summaryrefslogtreecommitdiff
path: root/usr/src/lib/libntfs/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libntfs/common')
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/attrib.h382
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/attrlist.h51
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/bitmap.h134
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/bootsect.h47
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/collate.h38
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/compat.h58
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/compress.h33
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/config.h313
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/crypto.h46
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/debug.h63
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/device.h128
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/device_io.h77
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/dir.h112
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/endians.h248
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/index.h131
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/inode.h215
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/layout.h3063
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/lcnalloc.h50
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/list.h192
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/logfile.h441
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/logging.h143
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/mft.h116
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/mst.h34
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/ntfstime.h69
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/runlist.h90
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/security.h55
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/support.h121
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/types.h142
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/unistr.h69
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/version.h29
-rw-r--r--usr/src/lib/libntfs/common/include/ntfs/volume.h247
-rw-r--r--usr/src/lib/libntfs/common/libntfs/attrib.c5234
-rw-r--r--usr/src/lib/libntfs/common/libntfs/attrlist.c320
-rw-r--r--usr/src/lib/libntfs/common/libntfs/bitmap.c249
-rw-r--r--usr/src/lib/libntfs/common/libntfs/bootsect.c273
-rw-r--r--usr/src/lib/libntfs/common/libntfs/collate.c220
-rw-r--r--usr/src/lib/libntfs/common/libntfs/compat.c73
-rw-r--r--usr/src/lib/libntfs/common/libntfs/compress.c553
-rw-r--r--usr/src/lib/libntfs/common/libntfs/crypto.c1519
-rw-r--r--usr/src/lib/libntfs/common/libntfs/debug.c73
-rw-r--r--usr/src/lib/libntfs/common/libntfs/device.c796
-rw-r--r--usr/src/lib/libntfs/common/libntfs/device_io.c46
-rw-r--r--usr/src/lib/libntfs/common/libntfs/dir.c1773
-rw-r--r--usr/src/lib/libntfs/common/libntfs/index.c1862
-rw-r--r--usr/src/lib/libntfs/common/libntfs/inode.c1200
-rw-r--r--usr/src/lib/libntfs/common/libntfs/lcnalloc.c858
-rw-r--r--usr/src/lib/libntfs/common/libntfs/logfile.c769
-rw-r--r--usr/src/lib/libntfs/common/libntfs/logging.c644
-rw-r--r--usr/src/lib/libntfs/common/libntfs/mft.c1583
-rw-r--r--usr/src/lib/libntfs/common/libntfs/misc.c64
-rw-r--r--usr/src/lib/libntfs/common/libntfs/mst.c216
-rw-r--r--usr/src/lib/libntfs/common/libntfs/runlist.c2154
-rw-r--r--usr/src/lib/libntfs/common/libntfs/security.c272
-rw-r--r--usr/src/lib/libntfs/common/libntfs/unistr.c776
-rw-r--r--usr/src/lib/libntfs/common/libntfs/unix_io.c321
-rw-r--r--usr/src/lib/libntfs/common/libntfs/version.c45
-rw-r--r--usr/src/lib/libntfs/common/libntfs/volume.c1689
-rw-r--r--usr/src/lib/libntfs/common/mapfile-vers134
58 files changed, 0 insertions, 30653 deletions
diff --git a/usr/src/lib/libntfs/common/include/ntfs/attrib.h b/usr/src/lib/libntfs/common/include/ntfs/attrib.h
deleted file mode 100644
index dcca5427ea..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/attrib.h
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * attrib.h - Exports for attribute handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_ATTRIB_H
-#define _NTFS_ATTRIB_H
-
-/* Forward declarations */
-typedef struct _ntfs_attr ntfs_attr;
-typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx;
-
-#include "list.h"
-#include "types.h"
-#include "inode.h"
-#include "unistr.h"
-#include "runlist.h"
-#include "volume.h"
-#include "debug.h"
-#include "logging.h"
-#include "crypto.h"
-
-extern ntfschar AT_UNNAMED[];
-
-/**
- * enum ntfs_lcn_special_values - special return values for ntfs_*_vcn_to_lcn()
- *
- * Special return values for ntfs_rl_vcn_to_lcn() and ntfs_attr_vcn_to_lcn().
- *
- * TODO: Describe them.
- */
-typedef enum {
- LCN_HOLE = -1, /* Keep this as highest value or die! */
- LCN_RL_NOT_MAPPED = -2,
- LCN_ENOENT = -3,
- LCN_EINVAL = -4,
- LCN_EIO = -5,
-} ntfs_lcn_special_values;
-
-/**
- * struct ntfs_attr_search_ctx - search context used in attribute search functions
- * @mrec: buffer containing mft record to search
- * @attr: attribute record in @mrec where to begin/continue search
- * @is_first: if true lookup_attr() begins search with @attr, else after @attr
- *
- * Structure must be initialized to zero before the first call to one of the
- * attribute search functions. Initialize @mrec to point to the mft record to
- * search, and @attr to point to the first attribute within @mrec (not necessary
- * if calling the _first() functions), and set @is_first to TRUE (not necessary
- * if calling the _first() functions).
- *
- * If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE,
- * the search begins after @attr. This is so that, after the first call to one
- * of the search attribute functions, we can call the function again, without
- * any modification of the search context, to automagically get the next
- * matching attribute.
- */
-struct _ntfs_attr_search_ctx {
- MFT_RECORD *mrec;
- ATTR_RECORD *attr;
- BOOL is_first;
- ntfs_inode *ntfs_ino;
- ATTR_LIST_ENTRY *al_entry;
- ntfs_inode *base_ntfs_ino;
- MFT_RECORD *base_mrec;
- ATTR_RECORD *base_attr;
-};
-
-extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
-extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
- MFT_RECORD *mrec);
-extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
-
-extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
- const u32 name_len, const IGNORE_CASE_BOOL ic,
- const VCN lowest_vcn, const u8 *val, const u32 val_len,
- ntfs_attr_search_ctx *ctx);
-
-extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
- const ATTR_TYPES type);
-
-/**
- * ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
- * @ctx: initialised attribute search context
- *
- * Syntactic sugar for walking attributes in an inode.
- *
- * Return 0 on success and -1 on error with errno set to the error code from
- * ntfs_attr_lookup().
- *
- * Example: When you want to enumerate all attributes in an open ntfs inode
- * @ni, you can simply do:
- *
- * int err;
- * ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL);
- * if (!ctx)
- * // Error code is in errno. Handle this case.
- * while (!(err = ntfs_attrs_walk(ctx))) {
- * ATTR_RECORD *attr = ctx->attr;
- * // attr now contains the next attribute. Do whatever you want
- * // with it and then just continue with the while loop.
- * }
- * if (err && errno != ENOENT)
- * // Ooops. An error occurred! You should handle this case.
- * // Now finished with all attributes in the inode.
- */
-static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
-{
- return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
- NULL, 0, ctx);
-}
-
-/**
- * struct ntfs_attr - ntfs in memory non-resident attribute structure
- * @rl: if not NULL, the decompressed runlist
- * @ni: base ntfs inode to which this attribute belongs
- * @type: attribute type
- * @name: Unicode name of the attribute
- * @name_len: length of @name in Unicode characters
- * @state: NTFS attribute specific flags describing this attribute
- * @allocated_size: copy from the attribute record
- * @data_size: copy from the attribute record
- * @initialized_size: copy from the attribute record
- * @compressed_size: copy from the attribute record
- * @compression_block_size: size of a compression block (cb)
- * @compression_block_size_bits: log2 of the size of a cb
- * @compression_block_clusters: number of clusters per cb
- * @crypto: (valid only for encrypted) see description below
- *
- * This structure exists purely to provide a mechanism of caching the runlist
- * of an attribute. If you want to operate on a particular attribute extent,
- * you should not be using this structure at all. If you want to work with a
- * resident attribute, you should not be using this structure at all. As a
- * fail-safe check make sure to test NAttrNonResident() and if it is false, you
- * know you shouldn't be using this structure.
- *
- * If you want to work on a resident attribute or on a specific attribute
- * extent, you should use ntfs_lookup_attr() to retrieve the attribute (extent)
- * record, edit that, and then write back the mft record (or set the
- * corresponding ntfs inode dirty for delayed write back).
- *
- * @rl is the decompressed runlist of the attribute described by this
- * structure. Obviously this only makes sense if the attribute is not resident,
- * i.e. NAttrNonResident() is true. If the runlist hasn't been decompressed yet
- * @rl is NULL, so be prepared to cope with @rl == NULL.
- *
- * @ni is the base ntfs inode of the attribute described by this structure.
- *
- * @type is the attribute type (see layout.h for the definition of ATTR_TYPES),
- * @name and @name_len are the little endian Unicode name and the name length
- * in Unicode characters of the attribute, respectively.
- *
- * @state contains NTFS attribute specific flags describing this attribute
- * structure. See ntfs_attr_state_bits above.
- *
- * @crypto points to private structure of crypto code. You should not access
- * fields of this structure, but you can check whether it is NULL or not. If it
- * is not NULL, then we successfully obtained FEK (File Encryption Key) and
- * ntfs_attr_p{read,write} calls probably would succeed. If it is NULL, then we
- * failed to obtain FEK (do not have corresponding PFX file, wrong password,
- * etc..) or library was compiled without crypto support. Attribute size can be
- * changed without knowledge of FEK, so you can use ntfs_attr_truncate in any
- * case.
- * NOTE: This field valid only if attribute encrypted (eg., NAttrEncrypted
- * returns non-zero).
- */
-struct _ntfs_attr {
- runlist_element *rl;
- ntfs_inode *ni;
- ATTR_TYPES type;
- ntfschar *name;
- u32 name_len;
- unsigned long state;
- s64 allocated_size;
- s64 data_size;
- s64 initialized_size;
- s64 compressed_size;
- u32 compression_block_size;
- u8 compression_block_size_bits;
- u8 compression_block_clusters;
- ntfs_crypto_attr *crypto;
- struct list_head list_entry;
- int nr_references;
-};
-
-/**
- * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
- * structure
- */
-typedef enum {
- NA_Initialized, /* 1: structure is initialized. */
- NA_NonResident, /* 1: Attribute is not resident. */
-} ntfs_attr_state_bits;
-
-#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
-#define set_nattr_flag(na, flag) set_bit(NA_##flag, (na)->state)
-#define clear_nattr_flag(na, flag) clear_bit(NA_##flag, (na)->state)
-
-#define NAttrInitialized(na) test_nattr_flag(na, Initialized)
-#define NAttrSetInitialized(na) set_nattr_flag(na, Initialized)
-#define NAttrClearInitialized(na) clear_nattr_flag(na, Initialized)
-
-#define NAttrNonResident(na) test_nattr_flag(na, NonResident)
-#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
-#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
-
-#define GenNAttrIno(func_name,flag) \
-static inline int NAttr##func_name(ntfs_attr *na) \
-{ \
- if (na->type == AT_DATA && na->name == AT_UNNAMED) \
- return (na->ni->flags & FILE_ATTR_##flag) ? 1 : 0; \
- return 0; \
-} \
-static inline void NAttrSet##func_name(ntfs_attr *na) \
-{ \
- if (na->type == AT_DATA && na->name == AT_UNNAMED) \
- na->ni->flags |= FILE_ATTR_##flag; \
- else \
- ntfs_log_trace("BUG! Should be called only for " \
- "unnamed data attribute.\n"); \
-} \
-static inline void NAttrClear##func_name(ntfs_attr *na) \
-{ \
- if (na->type == AT_DATA && na->name == AT_UNNAMED) \
- na->ni->flags &= ~FILE_ATTR_##flag; \
-}
-
-GenNAttrIno(Compressed, COMPRESSED)
-GenNAttrIno(Encrypted, ENCRYPTED)
-GenNAttrIno(Sparse, SPARSE_FILE)
-
-#ifndef __sun
-/**
- * union attr_val - Union of all known attribute values
- *
- * For convenience. Used in the attr structure.
- */
-typedef union {
- u8 _default; /* Unnamed u8 to serve as default when just using
- a_val without specifying any of the below. */
- STANDARD_INFORMATION std_inf;
- ATTR_LIST_ENTRY al_entry;
- FILE_NAME_ATTR filename;
- OBJECT_ID_ATTR obj_id;
- SECURITY_DESCRIPTOR_ATTR sec_desc;
- VOLUME_NAME vol_name;
- VOLUME_INFORMATION vol_inf;
- DATA_ATTR data;
- INDEX_ROOT index_root;
- INDEX_BLOCK index_blk;
- BITMAP_ATTR bmp;
- REPARSE_POINT reparse;
- EA_INFORMATION ea_inf;
- EA_ATTR ea;
- PROPERTY_SET property_set;
- LOGGED_UTILITY_STREAM logged_util_stream;
- EFS_ATTR_HEADER efs;
-} attr_val;
-#endif /* __sun */
-
-extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
- const BOOL compressed, const BOOL encrypted, const BOOL sparse,
- const s64 allocated_size, const s64 data_size,
- const s64 initialized_size, const s64 compressed_size,
- const u8 compression_unit);
-
-extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
- ntfschar *name, u32 name_len);
-extern void ntfs_attr_close(ntfs_attr *na);
-
-extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
- void *b);
-extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count,
- const void *b);
-
-extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
- ntfschar *name, u32 name_len, s64 *data_size);
-
-extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
- const s64 bk_cnt, const u32 bk_size, void *dst);
-extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
- s64 bk_cnt, const u32 bk_size, void *src);
-
-extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
-extern int ntfs_attr_map_runlist_range(ntfs_attr *na, VCN from_vcn, VCN to_vcn);
-extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
-
-extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn);
-extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
-
-extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
- const ATTR_TYPES type, const s64 size);
-extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
- const ATTR_TYPES type);
-extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
- const ATTR_TYPES type);
-
-extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
-
-extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, u8 *val, u32 size,
- ATTR_FLAGS flags);
-extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
- ATTR_FLAGS flags);
-extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
-
-extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, u8 *val, s64 size);
-extern int ntfs_attr_rm(ntfs_attr *na);
-
-extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
-
-extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
- const u32 new_size);
-
-extern int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni);
-extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra);
-
-extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
-
-extern int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse);
-extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
-
-extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
- ntfschar *name, u32 name_len);
-
-static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr)
-{
- return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset));
-}
-
-// FIXME / TODO: Above here the file is cleaned up. (AIA)
-/**
- * get_attribute_value_length - return the length of the value of an attribute
- * @a: pointer to a buffer containing the attribute record
- *
- * Return the byte size of the attribute value of the attribute @a (as it
- * would be after eventual decompression and filling in of holes if sparse).
- * If we return 0, check errno. If errno is 0 the actual length was 0,
- * otherwise errno describes the error.
- *
- * FIXME: Describe possible errnos.
- */
-s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a);
-
-/**
- * get_attribute_value - return the attribute value of an attribute
- * @vol: volume on which the attribute is present
- * @a: attribute to get the value of
- * @b: destination buffer for the attribute value
- *
- * Make a copy of the attribute value of the attribute @a into the destination
- * buffer @b. Note, that the size of @b has to be at least equal to the value
- * returned by get_attribute_value_length(@a).
- *
- * Return number of bytes copied. If this is zero check errno. If errno is 0
- * then nothing was read due to a zero-length attribute value, otherwise
- * errno describes the error.
- */
-s64 ntfs_get_attribute_value(const ntfs_volume *vol, const ATTR_RECORD *a,
- u8 *b);
-
-#endif /* defined _NTFS_ATTRIB_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/attrlist.h b/usr/src/lib/libntfs/common/include/ntfs/attrlist.h
deleted file mode 100644
index ff450d09bf..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/attrlist.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * attrlist.h - Exports for attribute list attribute handling. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- * Copyright (c) 2004 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_ATTRLIST_H
-#define _NTFS_ATTRLIST_H
-
-#include "attrib.h"
-
-extern int ntfs_attrlist_need(ntfs_inode *ni);
-
-extern int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr);
-extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx);
-
-/**
- * ntfs_attrlist_mark_dirty - set the attribute list dirty
- * @ni: ntfs inode which base inode contain dirty attribute list
- *
- * Set the attribute list dirty so it is written out later (at the latest at
- * ntfs_inode_close() time).
- *
- * This function cannot fail.
- */
-static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
-{
- if (ni->nr_extents == -1)
- NInoAttrListSetDirty(ni->u.base_ni);
- else
- NInoAttrListSetDirty(ni);
-}
-
-#endif /* defined _NTFS_ATTRLIST_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/bitmap.h b/usr/src/lib/libntfs/common/include/ntfs/bitmap.h
deleted file mode 100644
index f6d16f1923..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/bitmap.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * bitmap.h - Exports for bitmap handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_BITMAP_H
-#define _NTFS_BITMAP_H
-
-#include "types.h"
-#include "attrib.h"
-
-/*
- * NOTES:
- *
- * - Operations are 8-bit only to ensure the functions work both on little
- * and big endian machines! So don't make them 32-bit ops!
- * - bitmap starts at bit = 0 and ends at bit = bitmap size - 1.
- * - _Caller_ has to make sure that the bit to operate on is less than the
- * size of the bitmap.
- */
-
-/**
- * ntfs_bit_set - set a bit in a field of bits
- * @bitmap: field of bits
- * @bit: bit to set
- * @new_value: value to set bit to (0 or 1)
- *
- * Set the bit @bit in the @bitmap to @new_value. Ignore all errors.
- */
-static __inline__ void ntfs_bit_set(u8 *bitmap, const u64 bit,
- const u8 new_value)
-{
- if (!bitmap || new_value > 1)
- return;
- if (!new_value)
- bitmap[bit >> 3] &= ~(1 << (bit & 7));
- else
- bitmap[bit >> 3] |= (1 << (bit & 7));
-}
-
-/**
- * ntfs_bit_get - get value of a bit in a field of bits
- * @bitmap: field of bits
- * @bit: bit to get
- *
- * Get and return the value of the bit @bit in @bitmap (0 or 1).
- * Return -1 on error.
- */
-static __inline__ char ntfs_bit_get(const u8 *bitmap, const u64 bit)
-{
- if (!bitmap)
- return -1;
- return (bitmap[bit >> 3] >> (bit & 7)) & 1;
-}
-
-static __inline__ void ntfs_bit_change(u8 *bitmap, const u64 bit)
-{
- if (!bitmap)
- return;
- bitmap[bit >> 3] ^= 1 << (bit & 7);
-}
-
-/**
- * ntfs_bit_get_and_set - get value of a bit in a field of bits and set it
- * @bitmap: field of bits
- * @bit: bit to get/set
- * @new_value: value to set bit to (0 or 1)
- *
- * Return the value of the bit @bit and set it to @new_value (0 or 1).
- * Return -1 on error.
- */
-static __inline__ char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit,
- const u8 new_value)
-{
- register u8 old_bit, shift;
-
- if (!bitmap || new_value > 1)
- return -1;
- shift = bit & 7;
- old_bit = (bitmap[bit >> 3] >> shift) & 1;
- if (new_value != old_bit)
- bitmap[bit >> 3] ^= 1 << shift;
- return old_bit;
-}
-
-extern int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count);
-extern int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count);
-
-/**
- * ntfs_bitmap_set_bit - set a bit in a bitmap
- * @na: attribute containing the bitmap
- * @bit: bit to set
- *
- * Set the @bit in the bitmap described by the attribute @na.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit)
-{
- return ntfs_bitmap_set_run(na, bit, 1);
-}
-
-/**
- * ntfs_bitmap_clear_bit - clear a bit in a bitmap
- * @na: attribute containing the bitmap
- * @bit: bit to clear
- *
- * Clear @bit in the bitmap described by the attribute @na.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
-{
- return ntfs_bitmap_clear_run(na, bit, 1);
-}
-
-#endif /* defined _NTFS_BITMAP_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/bootsect.h b/usr/src/lib/libntfs/common/include/ntfs/bootsect.h
deleted file mode 100644
index af0da7a945..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/bootsect.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * bootsect.h - Exports for bootsector record handling. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2000-2002 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_BOOTSECT_H
-#define _NTFS_BOOTSECT_H
-
-#include "types.h"
-#include "volume.h"
-#include "layout.h"
-
-/**
- * is_boot_sector_ntfs - check a boot sector for describing an ntfs volume
- * @b: buffer containing the boot sector
- * @silent: if 1 don't display progress information
- *
- * This function checks the boot sector in @b for describing a valid ntfs
- * volume. Return TRUE if @b is a valid NTFS boot sector or FALSE otherwise.
- * If silent is FALSE, progress output will be output to stdout. If silent is
- * TRUE no output to stdout will occur. Errors/warnings to stderr will occur
- * disregarding the value of silent (but only if configure was run with
- * --enable-debug).
- */
-extern BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, BOOL silent);
-extern int ntfs_boot_sector_parse(ntfs_volume *vol,
- const NTFS_BOOT_SECTOR *bs);
-
-#endif /* defined _NTFS_BOOTSECT_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/collate.h b/usr/src/lib/libntfs/common/include/ntfs/collate.h
deleted file mode 100644
index 1c00ebd77e..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/collate.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * collate.h - Defines for NTFS collation handling. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- * Copyright (c) 2005 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_COLLATE_H
-#define _NTFS_COLLATE_H
-
-#include "types.h"
-#include "volume.h"
-
-#define NTFS_COLLATION_ERROR (-2)
-
-extern BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr);
-
-extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
- const void *data1, size_t data1_len,
- const void *data2, size_t data2_len);
-
-#endif /* _NTFS_COLLATE_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/compat.h b/usr/src/lib/libntfs/common/include/ntfs/compat.h
deleted file mode 100644
index 7c1f5f11fe..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/compat.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * compat.h - Tweaks for Windows compatibility.
- *
- * Copyright (c) 2002 Richard Russon
- * Copyright (c) 2002-2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_COMPAT_H
-#define _NTFS_COMPAT_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef WINDOWS
-
-#ifndef HAVE_FFS
-#define HAVE_FFS
-extern int ffs(int i);
-#endif /* HAVE_FFS */
-
-#define HAVE_STDIO_H /* mimic config.h */
-#define HAVE_STDARG_H
-
-#define atoll _atoi64
-#define fdatasync commit
-#define __inline__ inline
-#define __attribute__(X) /*nothing*/
-
-#else /* !defined WINDOWS */
-
-#ifndef O_BINARY
-#define O_BINARY 0 /* unix is binary by default */
-#endif
-
-#endif /* defined WINDOWS */
-
-#ifdef __sun
-#define __attribute__(X) /*nothing*/
-#endif /* __sun */
-
-#endif /* defined _NTFS_COMPAT_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/compress.h b/usr/src/lib/libntfs/common/include/ntfs/compress.h
deleted file mode 100644
index 93df37afc8..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/compress.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * compress.h - Exports for compressed attribute handling. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_COMPRESS_H
-#define _NTFS_COMPRESS_H
-
-#include "types.h"
-#include "attrib.h"
-
-extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
- void *b);
-
-#endif /* defined _NTFS_COMPRESS_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/config.h b/usr/src/lib/libntfs/common/include/ntfs/config.h
deleted file mode 100644
index 4c6c18efff..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/config.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/* config.h. Generated from config.h.in by configure. */
-/* config.h.in. Generated from configure.ac by autoheader. */
-
-/* Define this to 1 if you want to enable support of encrypted files in
- libntfs and utilities. */
-/* #undef ENABLE_CRYPTO */
-
-/* Define this to 1 if you want to enable generation of DCE compliant UUIDs.
- */
-#define ENABLE_UUID 1
-
-/* Define to 1 if you have the `atexit' function. */
-#define HAVE_ATEXIT 1
-
-/* Define to 1 if you have the `basename' function. */
-#define HAVE_BASENAME 1
-
-/* Define to 1 if you have the <byteswap.h> header file. */
-/* #undef HAVE_BYTESWAP_H */
-
-/* Define to 1 if you have the <ctype.h> header file. */
-#define HAVE_CTYPE_H 1
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
-/* #undef HAVE_DOPRNT */
-
-/* Define to 1 if you have the `dup2' function. */
-#define HAVE_DUP2 1
-
-/* Define to 1 if you have the <endian.h> header file. */
-/* #undef HAVE_ENDIAN_H */
-
-/* Define to 1 if you have the <errno.h> header file. */
-#define HAVE_ERRNO_H 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `fdatasync' function. */
-#define HAVE_FDATASYNC 1
-
-/* Define to 1 if you have the <features.h> header file. */
-/* #undef HAVE_FEATURES_H */
-
-/* Define to 1 if you have the `getmntent' function. */
-#define HAVE_GETMNTENT
-
-/* Define to 1 if you have the <getopt.h> header file. */
-#define HAVE_GETOPT_H 1
-
-/* Define to 1 if you have the `getopt_long' function. */
-#define HAVE_GETOPT_LONG 1
-
-/* Define to 1 if you have the `hasmntopt' function. */
-#define HAVE_HASMNTOPT 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the <libgen.h> header file. */
-#define HAVE_LIBGEN_H 1
-
-/* Define to 1 if you have the <libintl.h> header file. */
-#define HAVE_LIBINTL_H 1
-
-/* Define to 1 if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define to 1 if you have the <linux/fd.h> header file. */
-/* #undef HAVE_LINUX_FD_H */
-
-/* Define to 1 if you have the <linux/hdreg.h> header file. */
-/* #undef HAVE_LINUX_HDREG_H */
-
-/* Define to 1 if you have the <linux/major.h> header file. */
-/* #undef HAVE_LINUX_MAJOR_H */
-
-/* Define to 1 if you have the <locale.h> header file. */
-#define HAVE_LOCALE_H 1
-
-/* Define to 1 if you have the <machine/endian.h> header file. */
-/* #undef HAVE_MACHINE_ENDIAN_H */
-
-/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
-#define HAVE_MBRTOWC 1
-
-/* Define to 1 if you have the `mbsinit' function. */
-#define HAVE_MBSINIT 1
-
-/* Define to 1 if you have the `memmove' function. */
-/* #undef HAVE_MEMMOVE */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the `memset' function. */
-/* #undef HAVE_MEMSET */
-
-/* Define to 1 if you have the <mntent.h> header file. */
-/* #undef HAVE_MNTENT_H */
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define to 1 if you have the `realpath' function. */
-#define HAVE_REALPATH 1
-
-/* Define to 1 if you have the `regcomp' function. */
-#define HAVE_REGCOMP 1
-
-/* Define to 1 if you have the `setlocale' function. */
-#define HAVE_SETLOCALE 1
-
-/* Define to 1 if you have the `setxattr' function. */
-/* #undef HAVE_SETXATTR */
-
-/* Define to 1 if `stat' has the bug that it succeeds when given the
- zero-length file name argument. */
-/* #undef HAVE_STAT_EMPTY_STRING_BUG */
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if stdbool.h conforms to C99. */
-#define HAVE_STDBOOL_H 1
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#define HAVE_STDDEF_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdio.h> header file. */
-#define HAVE_STDIO_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the `strcasecmp' function. */
-#define HAVE_STRCASECMP 1
-
-/* Define to 1 if you have the `strchr' function. */
-/* #undef HAVE_STRCHR */
-
-/* Define to 1 if you have the `strdup' function. */
-/* #undef HAVE_STRDUP */
-
-/* Define to 1 if you have the `strerror' function. */
-#define HAVE_STRERROR 1
-
-/* Define to 1 if you have the `strftime' function. */
-/* #undef HAVE_STRFTIME */
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strnlen' function. */
-#define HAVE_STRNLEN 1
-
-/* Define to 1 if you have the `strtol' function. */
-#define HAVE_STRTOL 1
-
-/* Define to 1 if you have the `strtoul' function. */
-#define HAVE_STRTOUL 1
-
-/* Define to 1 if `st_blocks' is member of `struct stat'. */
-#define HAVE_STRUCT_STAT_ST_BLOCKS 1
-
-/* Define to 1 if `st_rdev' is member of `struct stat'. */
-#define HAVE_STRUCT_STAT_ST_RDEV 1
-
-/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
- `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
-#define HAVE_ST_BLOCKS 1
-
-/* Define to 1 if you have the `sysconf' function. */
-#define HAVE_SYSCONF 1
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#define HAVE_SYSLOG_H 1
-
-/* Define to 1 if you have the <sys/byteorder.h> header file. */
-#define HAVE_SYS_BYTEORDER_H 1
-
-/* Define to 1 if you have the <sys/endian.h> header file. */
-/* #undef HAVE_SYS_ENDIAN_H */
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#define HAVE_SYS_IOCTL_H 1
-
-/* Define to 1 if you have the <sys/mount.h> header file. */
-#define HAVE_SYS_MOUNT_H 1
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/statvfs.h> header file. */
-#define HAVE_SYS_STATVFS_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/sysmacros.h> header file. */
-#define HAVE_SYS_SYSMACROS_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/vfs.h> header file. */
-#define HAVE_SYS_VFS_H 1
-
-/* Define to 1 if you have the <time.h> header file. */
-#define HAVE_TIME_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define to 1 if you have the `utime' function. */
-#define HAVE_UTIME 1
-
-/* Define to 1 if you have the <utime.h> header file. */
-#define HAVE_UTIME_H 1
-
-/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
-#define HAVE_UTIME_NULL 1
-
-/* Define to 1 if you have the `vprintf' function. */
-/* #undef HAVE_VPRINTF */
-
-/* Define to 1 if you have the <wchar.h> header file. */
-#define HAVE_WCHAR_H 1
-
-/* Define to 1 if you have the <windows.h> header file. */
-/* #undef HAVE_WINDOWS_H */
-
-/* Define to 1 if the system has the type `_Bool'. */
-#define HAVE__BOOL 1
-
-/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
- slash. */
-#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
-
-/* Define to 1 if your C compiler doesn't accept -c and -o together. */
-/* #undef NO_MINUS_C_MINUS_O */
-
-/* Define this if you do not want the NTFS library to provide default device
- io operations. This means that you cannot use ntfs_mount() but have to use
- ntfs_device_mount() and provide your own device operations. */
-/* #undef NO_NTFS_DEVICE_DEFAULT_IO_OPS */
-
-/* Name of package */
-#define PACKAGE "ntfsprogs"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "linux-ntfs-dev@lists.sourceforge.net"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "ntfsprogs"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ntfsprogs 2.0.0"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "ntfsprogs"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.0.0"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "2.0.0"
-
-/* Define to 1 if your processor stores words with the most significant byte
- first (like Motorola and SPARC, unlike Intel and VAX). */
-/* #undef WORDS_BIGENDIAN */
-
-/* Define to 1 if your processor stores words with the least significant byte
- first (like Intel and VAX, unlike Motorola and SPARC). */
-#define WORDS_LITTLEENDIAN 1
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#define _FILE_OFFSET_BITS 64
-
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-/* Define for large files, on AIX-style hosts. */
-/* #undef _LARGE_FILES */
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
-#ifndef __cplusplus
-/* #undef inline */
-#endif
-
-/* Define to `long int' if <sys/types.h> does not define. */
-/* #undef off_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/crypto.h b/usr/src/lib/libntfs/common/include/ntfs/crypto.h
deleted file mode 100644
index a4b72435c1..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/crypto.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * crypto.h - Exports for dealing with encrypted files. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2007 Yura Pakhuchiy
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_CRYPTO_H
-#define _NTFS_CRYPTO_H
-
-extern ntfschar NTFS_EFS[5];
-
-/*
- * This is our Big Secret (TM) structure, so do not allow anyone even read it
- * values. ;-) In fact, it is private because exist only in libntfs version
- * compiled with cryptography support, so users can not depend on it.
- */
-typedef struct _ntfs_crypto_attr ntfs_crypto_attr;
-
-/*
- * These functions should not be used directly. They are called for encrypted
- * attributes from corresponding functions without _crypto_ part.
- */
-
-extern int ntfs_crypto_attr_open(ntfs_attr *na);
-extern void ntfs_crypto_attr_close(ntfs_attr *na);
-
-extern s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
- void *b);
-
-#endif /* _NTFS_CRYPTO_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/debug.h b/usr/src/lib/libntfs/common/include/ntfs/debug.h
deleted file mode 100644
index 0dd411420b..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/debug.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * debug.h - Debugging output functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_DEBUG_H
-#define _NTFS_DEBUG_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "logging.h"
-
-struct _runlist_element;
-
-#ifndef DEBUG
-static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
-#define NTFS_ON_DEBUG(x)
-#else
-extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
-#define NTFS_ON_DEBUG(x) (x)
-#endif
-
-#if defined(__GNUC__)
-
-#define NTFS_BUG(msg) \
-{ \
- int ___i; \
- ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
- ntfs_log_debug("Forcing segmentation fault!"); \
- ___i = ((int*)NULL)[1]; \
-}
-
-#else /* not __GNUC__ */
-
-#define NTFS_BUG(msg) \
-{ \
- int ___i; \
- ntfs_log_critical("Bug in %s(): %s\n", "unknown", msg); \
- ntfs_log_debug("Forcing segmentation fault!"); \
- ___i = ((int*)NULL)[1]; \
-}
-
-#endif /* __GNUC__ */
-
-#endif /* defined _NTFS_DEBUG_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/device.h b/usr/src/lib/libntfs/common/include/ntfs/device.h
deleted file mode 100644
index eeadf13e7a..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/device.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * device.h - Exports for low level device io. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_DEVICE_H
-#define _NTFS_DEVICE_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "device_io.h"
-#include "types.h"
-#include "support.h"
-#include "volume.h"
-
-/**
- * enum ntfs_device_state_bits -
- *
- * Defined bits for the state field in the ntfs_device structure.
- */
-typedef enum {
- ND_Open, /* 1: Device is open. */
- ND_ReadOnly, /* 1: Device is read-only. */
- ND_Dirty, /* 1: Device is dirty, needs sync. */
- ND_Block, /* 1: Device is a block device. */
-} ntfs_device_state_bits;
-
-#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
-#define set_ndev_flag(nd, flag) set_bit(ND_##flag, (nd)->d_state)
-#define clear_ndev_flag(nd, flag) clear_bit(ND_##flag, (nd)->d_state)
-
-#define NDevOpen(nd) test_ndev_flag(nd, Open)
-#define NDevSetOpen(nd) set_ndev_flag(nd, Open)
-#define NDevClearOpen(nd) clear_ndev_flag(nd, Open)
-
-#define NDevReadOnly(nd) test_ndev_flag(nd, ReadOnly)
-#define NDevSetReadOnly(nd) set_ndev_flag(nd, ReadOnly)
-#define NDevClearReadOnly(nd) clear_ndev_flag(nd, ReadOnly)
-
-#define NDevDirty(nd) test_ndev_flag(nd, Dirty)
-#define NDevSetDirty(nd) set_ndev_flag(nd, Dirty)
-#define NDevClearDirty(nd) clear_ndev_flag(nd, Dirty)
-
-#define NDevBlock(nd) test_ndev_flag(nd, Block)
-#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
-#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
-
-/**
- * struct ntfs_device -
- *
- * The ntfs device structure defining all operations needed to access the low
- * level device underlying the ntfs volume.
- */
-struct ntfs_device {
- struct ntfs_device_operations *d_ops; /* Device operations. */
- unsigned long d_state; /* State of the device. */
- char *d_name; /* Name of device. */
- void *d_private; /* Private data used by the
- device operations. */
-};
-
-struct stat;
-
-/**
- * struct ntfs_device_operations -
- *
- * The ntfs device operations defining all operations that can be performed on
- * the low level device described by an ntfs device structure.
- */
-struct ntfs_device_operations {
- int (*open)(struct ntfs_device *dev, int flags);
- int (*close)(struct ntfs_device *dev);
- s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
- s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
- s64 (*write)(struct ntfs_device *dev, const void *buf, s64 count);
- s64 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset);
- s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
- s64 offset);
- int (*sync)(struct ntfs_device *dev);
- int (*stat)(struct ntfs_device *dev, struct stat *buf);
- int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
-};
-
-extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
- struct ntfs_device_operations *dops, void *priv_data);
-extern int ntfs_device_free(struct ntfs_device *dev);
-
-extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
- void *b);
-extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
- const void *b);
-
-extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
- const u32 bksize, void *b);
-extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
- const u32 bksize, void *b);
-
-extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
- const s64 count, void *b);
-extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
- const s64 count, const void *b);
-
-extern s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size);
-extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
-extern int ntfs_device_heads_get(struct ntfs_device *dev);
-extern int ntfs_device_sectors_per_track_get(struct ntfs_device *dev);
-extern int ntfs_device_sector_size_get(struct ntfs_device *dev);
-extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size);
-
-#endif /* defined _NTFS_DEVICE_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/device_io.h b/usr/src/lib/libntfs/common/include/ntfs/device_io.h
deleted file mode 100644
index 6665b68050..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/device_io.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * device_io.h - Exports for default device io. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_DEVICE_IO_H
-#define _NTFS_DEVICE_IO_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
-
-#ifndef __CYGWIN32__
-
-/* Not on Cygwin; use standard Unix style low level device operations. */
-#define ntfs_device_default_io_ops ntfs_device_unix_io_ops
-
-#else /* __CYGWIN32__ */
-
-#ifndef HDIO_GETGEO
-# define HDIO_GETGEO 0x301
-/**
- * struct hd_geometry -
- */
-struct hd_geometry {
- unsigned char heads;
- unsigned char sectors;
- unsigned short cylinders;
- unsigned long start;
-};
-#endif
-#ifndef BLKGETSIZE
-# define BLKGETSIZE 0x1260
-#endif
-#ifndef BLKSSZGET
-# define BLKSSZGET 0x1268
-#endif
-#ifndef BLKGETSIZE64
-# define BLKGETSIZE64 0x80041272
-#endif
-#ifndef BLKBSZSET
-# define BLKBSZSET 0x40041271
-#endif
-
-/* On Cygwin; use Win32 low level device operations. */
-#define ntfs_device_default_io_ops ntfs_device_win32_io_ops
-
-#endif /* __CYGWIN32__ */
-
-
-/* Forward declaration. */
-struct ntfs_device_operations;
-
-extern struct ntfs_device_operations ntfs_device_default_io_ops;
-
-#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */
-
-#endif /* defined _NTFS_DEVICE_IO_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/dir.h b/usr/src/lib/libntfs/common/include/ntfs/dir.h
deleted file mode 100644
index 5299861b81..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/dir.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * dir.h - Exports for directory handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002 Anton Altaparmakov
- * Copyright (c) 2005-2006 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_DIR_H
-#define _NTFS_DIR_H
-
-#include "types.h"
-
-#define PATH_SEP '/'
-
-#ifndef MAX_PATH
-#define MAX_PATH 1024
-#endif
-
-/*
- * We do not have these under DJGPP, so define our version that do not conflict
- * with other S_IFs defined under DJGPP.
- */
-#ifdef DJGPP
-#ifndef S_IFLNK
-#define S_IFLNK 0120000
-#endif
-#ifndef S_ISLNK
-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#ifndef S_IFSOCK
-#define S_IFSOCK 0140000
-#endif
-#ifndef S_ISSOCK
-#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#endif
-
-/*
- * The little endian Unicode strings $I30, $SII, $SDH, $O, $Q, $R
- * as a global constant.
- */
-extern ntfschar NTFS_INDEX_I30[5];
-extern ntfschar NTFS_INDEX_SII[5];
-extern ntfschar NTFS_INDEX_SDH[5];
-extern ntfschar NTFS_INDEX_O[3];
-extern ntfschar NTFS_INDEX_Q[3];
-extern ntfschar NTFS_INDEX_R[3];
-
-extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
- const ntfschar *uname, const int uname_len);
-
-extern u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent,
- const char *pathname);
-extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
- const char *pathname);
-
-extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
- dev_t type);
-extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni,
- ntfschar *name, u8 name_len, dev_t type, dev_t dev);
-extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni,
- ntfschar *name, u8 name_len, ntfschar *target, u8 target_len);
-
-extern int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name,
- u8 name_len);
-
-extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
- u8 name_len);
-
-/*
- * File types (adapted from include <linux/fs.h>)
- */
-#define NTFS_DT_UNKNOWN 0
-#define NTFS_DT_FIFO 1
-#define NTFS_DT_CHR 2
-#define NTFS_DT_DIR 4
-#define NTFS_DT_BLK 6
-#define NTFS_DT_REG 8
-#define NTFS_DT_LNK 10
-#define NTFS_DT_SOCK 12
-#define NTFS_DT_WHT 14
-
-/*
- * This is the "ntfs_filldir" function type, used by ntfs_readdir() to let
- * the caller specify what kind of dirent layout it wants to have.
- * This allows the caller to read directories into their application or
- * to have different dirent layouts depending on the binary type.
- */
-typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
- const int name_len, const int name_type, const s64 pos,
- const MFT_REF mref, const unsigned dt_type);
-
-extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
- void *dirent, ntfs_filldir_t filldir);
-
-#endif /* defined _NTFS_DIR_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/endians.h b/usr/src/lib/libntfs/common/include/ntfs/endians.h
deleted file mode 100644
index b3426df30e..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/endians.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * endians.h - Definitions related to handling of byte ordering. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2000-2005 Anton Altaparmakov
- * Copyright (c) 2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_ENDIANS_H
-#define _NTFS_ENDIANS_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/*
- * Notes:
- * We define the conversion functions including typecasts since the
- * defaults don't necessarily perform appropriate typecasts.
- * Also, using our own functions means that we can change them if it
- * turns out that we do need to use the unaligned access macros on
- * architectures requiring aligned memory accesses...
- */
-
-#ifdef HAVE_ENDIAN_H
-#include <endian.h>
-#endif
-#ifdef HAVE_SYS_ENDIAN_H
-#include <sys/endian.h>
-#endif
-#ifdef HAVE_MACHINE_ENDIAN_H
-#include <machine/endian.h>
-#endif
-#ifdef HAVE_SYS_BYTEORDER_H
-#include <sys/byteorder.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifndef __BYTE_ORDER
-# if defined(_BYTE_ORDER)
-# define __BYTE_ORDER _BYTE_ORDER
-# define __LITTLE_ENDIAN _LITTLE_ENDIAN
-# define __BIG_ENDIAN _BIG_ENDIAN
-# elif defined(BYTE_ORDER)
-# define __BYTE_ORDER BYTE_ORDER
-# define __LITTLE_ENDIAN LITTLE_ENDIAN
-# define __BIG_ENDIAN BIG_ENDIAN
-# elif defined(__BYTE_ORDER__)
-# define __BYTE_ORDER __BYTE_ORDER__
-# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
-# define __BIG_ENDIAN __BIG_ENDIAN__
-# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
- defined(WORDS_LITTLEENDIAN)
-# define __BYTE_ORDER 1
-# define __LITTLE_ENDIAN 1
-# define __BIG_ENDIAN 0
-# elif (!defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) || \
- defined(WORDS_BIGENDIAN)
-# define __BYTE_ORDER 0
-# define __LITTLE_ENDIAN 1
-# define __BIG_ENDIAN 0
-# else
-# error "__BYTE_ORDER is not defined."
-# endif
-#endif
-
-#define __ntfs_bswap_constant_16(x) \
- (u16)((((u16)(x) & 0xff00) >> 8) | \
- (((u16)(x) & 0x00ff) << 8))
-
-#define __ntfs_bswap_constant_32(x) \
- (u32)((((u32)(x) & 0xff000000u) >> 24) | \
- (((u32)(x) & 0x00ff0000u) >> 8) | \
- (((u32)(x) & 0x0000ff00u) << 8) | \
- (((u32)(x) & 0x000000ffu) << 24))
-
-#define __ntfs_bswap_constant_64(x) \
- (u64)((((u64)(x) & 0xff00000000000000ull) >> 56) | \
- (((u64)(x) & 0x00ff000000000000ull) >> 40) | \
- (((u64)(x) & 0x0000ff0000000000ull) >> 24) | \
- (((u64)(x) & 0x000000ff00000000ull) >> 8) | \
- (((u64)(x) & 0x00000000ff000000ull) << 8) | \
- (((u64)(x) & 0x0000000000ff0000ull) << 24) | \
- (((u64)(x) & 0x000000000000ff00ull) << 40) | \
- (((u64)(x) & 0x00000000000000ffull) << 56))
-
-#ifdef HAVE_BYTESWAP_H
-# include <byteswap.h>
-#else
-# define bswap_16(x) __ntfs_bswap_constant_16(x)
-# define bswap_32(x) __ntfs_bswap_constant_32(x)
-# define bswap_64(x) __ntfs_bswap_constant_64(x)
-#endif
-
-#if defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
-
-#define __le16_to_cpu(x) ((__force u16)(x))
-#define __le32_to_cpu(x) ((__force u32)(x))
-#define __le64_to_cpu(x) ((__force u64)(x))
-
-#define __cpu_to_le16(x) ((__force le16)(x))
-#define __cpu_to_le32(x) ((__force le32)(x))
-#define __cpu_to_le64(x) ((__force le64)(x))
-
-#define __constant_le16_to_cpu(x) ((__force u16)(x))
-#define __constant_le32_to_cpu(x) ((__force u32)(x))
-#define __constant_le64_to_cpu(x) ((__force u64)(x))
-
-#define __constant_cpu_to_le16(x) ((__force le16)(x))
-#define __constant_cpu_to_le32(x) ((__force le32)(x))
-#define __constant_cpu_to_le64(x) ((__force le64)(x))
-
-#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
-
-#define __le16_to_cpu(x) bswap_16((__force u16)(x))
-#define __le32_to_cpu(x) bswap_32((__force u16)(x))
-#define __le64_to_cpu(x) bswap_64((__force u16)(x))
-
-#define __cpu_to_le16(x) (__force le16)bswap_16((__force u16)(x))
-#define __cpu_to_le32(x) (__force le32)bswap_32((__force u32)(x))
-#define __cpu_to_le64(x) (__force le64)bswap_64((__force u64)(x))
-
-#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((__force u16)(x))
-#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((__force u32)(x))
-#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((__force u64)(x))
-
-#define __constant_cpu_to_le16(x) \
- (__force le16)__ntfs_bswap_constant_16((__force u16)(x))
-#define __constant_cpu_to_le32(x) \
- (__force le32)__ntfs_bswap_constant_32((__force u32)(x))
-#define __constant_cpu_to_le64(x) \
- (__force le64)__ntfs_bswap_constant_64((__force u64)(x))
-
-#else
-
-#error "You must define __BYTE_ORDER to be __LITTLE_ENDIAN or __BIG_ENDIAN."
-
-#endif
-
-/* Unsigned from LE to CPU conversion. */
-
-#define le16_to_cpu(x) (u16)__le16_to_cpu((le16)(x))
-#define le32_to_cpu(x) (u32)__le32_to_cpu((le32)(x))
-#define le64_to_cpu(x) (u64)__le64_to_cpu((le64)(x))
-
-#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const le16*)(x))
-#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const le32*)(x))
-#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const le64*)(x))
-
-/* Signed from LE to CPU conversion. */
-
-#define sle16_to_cpu(x) (s16)__le16_to_cpu((sle16)(x))
-#define sle32_to_cpu(x) (s32)__le32_to_cpu((sle32)(x))
-#define sle64_to_cpu(x) (s64)__le64_to_cpu((sle64)(x))
-
-#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(const sle16*)(x))
-#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(const sle32*)(x))
-#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(const sle64*)(x))
-
-/* Unsigned from CPU to LE conversion. */
-
-#define cpu_to_le16(x) (le16)__cpu_to_le16((u16)(x))
-#define cpu_to_le32(x) (le32)__cpu_to_le32((u32)(x))
-#define cpu_to_le64(x) (le64)__cpu_to_le64((u64)(x))
-
-#define cpu_to_le16p(x) (le16)__cpu_to_le16(*(const u16*)(x))
-#define cpu_to_le32p(x) (le32)__cpu_to_le32(*(const u32*)(x))
-#define cpu_to_le64p(x) (le64)__cpu_to_le64(*(const u64*)(x))
-
-/* Signed from CPU to LE conversion. */
-
-#define cpu_to_sle16(x) (__force sle16)__cpu_to_le16((s16)(x))
-#define cpu_to_sle32(x) (__force sle32)__cpu_to_le32((s32)(x))
-#define cpu_to_sle64(x) (__force sle64)__cpu_to_le64((s64)(x))
-
-#define cpu_to_sle16p(x) (__force sle16)__cpu_to_le16(*(const s16*)(x))
-#define cpu_to_sle32p(x) (__force sle32)__cpu_to_le32(*(const s32*)(x))
-#define cpu_to_sle64p(x) (__force sle64)__cpu_to_le64(*(const s64*)(x))
-
-/* Constant endianness conversion defines. */
-
-#define const_le16_to_cpu(x) (u16)__constant_le16_to_cpu((le16)(x))
-#define const_le32_to_cpu(x) (u32)__constant_le32_to_cpu((le32)(x))
-#define const_le64_to_cpu(x) (u64)__constant_le64_to_cpu((le64)(x))
-
-#define const_cpu_to_le16(x) (le16)__constant_cpu_to_le16((u16)(x))
-#define const_cpu_to_le32(x) (le32)__constant_cpu_to_le32((u32)(x))
-#define const_cpu_to_le64(x) (le64)__constant_cpu_to_le64((u64)(x))
-
-#ifdef __CHECKER__
-static void ntfs_endian_self_test(void)
-{
- /* Should not generate warnings. */
- (le16)cpu_to_le16((u16)1);
- (le32)cpu_to_le32((u32)1);
- (le64)cpu_to_le64((u64)1);
- (sle16)cpu_to_sle16((s16)1);
- (sle32)cpu_to_sle32((s32)1);
- (sle64)cpu_to_sle64((s64)1);
- (u16)le16_to_cpu((__force le16)1);
- (u32)le32_to_cpu((__force le32)1);
- (u64)le64_to_cpu((__force le64)1);
- (s16)sle16_to_cpu((__force sle16)1);
- (s32)sle32_to_cpu((__force sle32)1);
- (s64)sle64_to_cpu((__force sle64)1);
- (le16)const_cpu_to_le16((u16)1);
- (le32)const_cpu_to_le32((u32)1);
- (le64)const_cpu_to_le64((u64)1);
- (u16)const_le16_to_cpu((__force le16)1);
- (u32)const_le32_to_cpu((__force le32)1);
- (u64)const_le64_to_cpu((__force le64)1);
-
- /*
- * TODO: Need some how to test that warnings are actually generated,
- * but without flooding output with them and vice-versa print warning
- * in case if some one warning is not triggered, but should. (Yura)
- *
- * I think it can only be done in a ./configure like script / shell
- * script that will compile known good and known bad code and pipe the
- * output from sparse to a file, then grep the file for the wanted
- * warnings/lack thereof and then it would say "Tests: PASS " or
- * "Tests: FAILED" or whatever. And you can then hook that into a
- * "make test" make target or similar so it is only done when one
- * wants to do it... (Anton)
- *
- * Also we can look on sparse self test script. (Yura)
- */
-}
-#endif
-
-#endif /* defined _NTFS_ENDIANS_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/index.h b/usr/src/lib/libntfs/common/include/ntfs/index.h
deleted file mode 100644
index 75e23e2a4e..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/index.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * index.h - Defines for NTFS index handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- * Copyright (c) 2004-2005 Richard Russon
- * Copyright (c) 2005-2006 Yura Pakhuchiy
- * Copyright (c) 2006 Szabolcs Szakacsits
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_INDEX_H
-#define _NTFS_INDEX_H
-
-#include "attrib.h"
-#include "types.h"
-#include "layout.h"
-#include "inode.h"
-#include "mft.h"
-
-#define VCN_INDEX_ROOT_PARENT ((VCN)-2)
-
-#define MAX_PARENT_VCN 32
-
-/**
- * struct ntfs_index_context -
- * @ni: inode containing the @entry described by this context
- * @name: name of the index described by this context
- * @name_len: length of the index name
- * @entry: index entry (points into @ir or @ib)
- * @data: index entry data (points into @entry)
- * @data_len: length in bytes of @data
- * @cr:
- * @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ib
- * @ir: index root if @is_in_root or NULL otherwise
- * @actx: attribute search context if in root or NULL otherwise
- * @ia_na: opened INDEX_ALLOCATION attribute
- * @ib: index block if @is_in_root is FALSE or NULL otherwise
- * @ib_vcn: VCN from which @ib where read from
- * @ib_dirty: TRUE if index block was changed
- * @parent_pos: parent entries' positions in the index block
- * @parent_vcn: entry's parent nodes or VCN_INDEX_ROOT_PARENT for root
- * @max_depth: number of the parent nodes
- * @pindex: maximum it's the number of the parent nodes
- * @block_size: index block size
- * @vcn_size_bits: VCN size bits for this index block
- *
- * @ni is the inode this context belongs to.
- *
- * @entry is the index entry described by this context. @data and @data_len
- * are the index entry data and its length in bytes, respectively. @data
- * simply points into @entry. This is probably what the user is interested in.
- *
- * If @is_in_root is TRUE, @entry is in the index root attribute @ir described
- * by the attribute search context @actx and inode @ni. @ib, @ib_vcn and
- * @ib_dirty are undefined in this case.
- *
- * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ib
- * and @ib_vcn point to the index allocation block and VCN where it's placed,
- * respectively. @ir and @actx are NULL in this case. @ia_na is opened
- * INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and
- * FALSE otherwise.
- *
- * To obtain a context call ntfs_index_ctx_get().
- *
- * When finished with the @entry and its @data, call ntfs_index_ctx_put() to
- * free the context and other associated resources.
- *
- * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
- * the call to ntfs_index_ctx_put() to ensure that the changes are written
- * to disk.
- */
-typedef struct {
- ntfs_inode *ni;
- ntfschar *name;
- u32 name_len;
- INDEX_ENTRY *entry;
- void *data;
- u16 data_len;
- COLLATION_RULES cr;
- BOOL is_in_root;
- INDEX_ROOT *ir;
- ntfs_attr_search_ctx *actx;
- ntfs_attr *ia_na;
- INDEX_BLOCK *ib;
- VCN ib_vcn;
- BOOL ib_dirty;
- int parent_pos[MAX_PARENT_VCN];
- VCN parent_vcn[MAX_PARENT_VCN];
- int max_depth;
- int pindex;
- u32 block_size;
- u8 vcn_size_bits;
-} ntfs_index_context;
-
-extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
- ntfschar *name, u32 name_len);
-extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
-extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
-
-extern int ntfs_index_lookup(const void *key, const int key_len,
- ntfs_index_context *ictx);
-
-extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
- MFT_REF mref);
-extern int ntfs_index_rm(ntfs_index_context *ictx);
-
-extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
-
-extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie);
-
-extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie);
-extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie);
-extern void ntfs_ih_filename_dump(INDEX_HEADER *ih);
-
-extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
-
-#endif /* _NTFS_INDEX_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/inode.h b/usr/src/lib/libntfs/common/include/ntfs/inode.h
deleted file mode 100644
index 90c2113116..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/inode.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * inode.h - Defines for NTFS inode handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2001,2002 Anton Altaparmakov
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_INODE_H
-#define _NTFS_INODE_H
-
-/* Forward declaration */
-typedef struct _ntfs_inode ntfs_inode;
-
-#include "list.h"
-#include "types.h"
-#include "layout.h"
-#include "support.h"
-#include "volume.h"
-
-/**
- * enum ntfs_inode_state_bits -
- *
- * Defined bits for the state field in the ntfs_inode structure.
- * (f) = files only, (d) = directories only
- */
-typedef enum {
- NI_Dirty, /* 1: Mft record needs to be written to disk. */
-
- /* Below fields only make sense for base inodes. */
- NI_AttrList, /* 1: Mft record contains an attribute list. */
- NI_AttrListDirty, /* 1: Attribute list needs to be written to the
- mft record and then to disk. */
- NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated
- in the index. */
-} ntfs_inode_state_bits;
-
-#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
-#define set_nino_flag(ni, flag) set_bit(NI_##flag, (ni)->state)
-#define clear_nino_flag(ni, flag) clear_bit(NI_##flag, (ni)->state)
-
-#define test_and_set_nino_flag(ni, flag) \
- test_and_set_bit(NI_##flag, (ni)->state)
-#define test_and_clear_nino_flag(ni, flag) \
- test_and_clear_bit(NI_##flag, (ni)->state)
-
-#define NInoDirty(ni) test_nino_flag(ni, Dirty)
-#define NInoSetDirty(ni) set_nino_flag(ni, Dirty)
-#define NInoClearDirty(ni) clear_nino_flag(ni, Dirty)
-#define NInoTestAndSetDirty(ni) test_and_set_nino_flag(ni, Dirty)
-#define NInoTestAndClearDirty(ni) test_and_clear_nino_flag(ni, Dirty)
-
-#define NInoAttrList(ni) test_nino_flag(ni, AttrList)
-#define NInoSetAttrList(ni) set_nino_flag(ni, AttrList)
-#define NInoClearAttrList(ni) clear_nino_flag(ni, AttrList)
-
-
-#define test_nino_al_flag(ni, flag) test_nino_flag(ni, AttrList##flag)
-#define set_nino_al_flag(ni, flag) set_nino_flag(ni, AttrList##flag)
-#define clear_nino_al_flag(ni, flag) clear_nino_flag(ni, AttrList##flag)
-
-#define test_and_set_nino_al_flag(ni, flag) \
- test_and_set_nino_flag(ni, AttrList##flag)
-#define test_and_clear_nino_al_flag(ni, flag) \
- test_and_clear_nino_flag(ni, AttrList##flag)
-
-#define NInoAttrListDirty(ni) test_nino_al_flag(ni, Dirty)
-#define NInoAttrListSetDirty(ni) set_nino_al_flag(ni, Dirty)
-#define NInoAttrListClearDirty(ni) clear_nino_al_flag(ni, Dirty)
-#define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty)
-#define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty)
-
-#define NInoFileNameDirty(ni) \
- test_nino_flag(ni, FileNameDirty)
-#define NInoFileNameSetDirty(ni) \
- set_nino_flag(ni, FileNameDirty)
-#define NInoFileNameClearDirty(ni) \
- clear_nino_flag(ni, FileNameDirty)
-#define NInoFileNameTestAndSetDirty(ni) \
- test_and_set_nino_flag(ni, FileNameDirty)
-#define NInoFileNameTestAndClearDirty(ni) \
- test_and_clear_nino_flag(ni, FileNameDirty)
-
-/**
- * struct _ntfs_inode - The NTFS in-memory inode structure.
- *
- * It is just used as an extension to the fields already provided in the VFS
- * inode.
- */
-struct _ntfs_inode {
- u64 mft_no; /* Inode / mft record number. */
- MFT_RECORD *mrec; /* The actual mft record of the inode. */
- ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
- unsigned long state; /* NTFS specific flags describing this inode.
- See ntfs_inode_state_bits above. */
- FILE_ATTR_FLAGS flags; /* Flags describing the file.
- (Copy from STANDARD_INFORMATION) */
- /*
- * Attribute list support (for use by the attribute lookup functions).
- * Setup during ntfs_open_inode() for all inodes with attribute lists.
- * Only valid if NI_AttrList is set in state.
- */
- u32 attr_list_size; /* Length of attribute list value in bytes. */
- u8 *attr_list; /* Attribute list value itself. */
- /* Below fields are always valid. */
- s32 nr_extents; /* For a base mft record, the number of
- attached extent inodes (0 if none), for
- extent records this is -1. */
- union { /* This union is only used if nr_extents != 0. */
- ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
- ntfs inodes of the extent mft
- records belonging to this base
- inode which have been loaded. */
- ntfs_inode *base_ni; /* For nr_extents == -1, the ntfs
- inode of the base mft record. */
- } u;
-
- /* Below fields are valid only for base inode. */
-
- /*
- * These two fields are used to sync filename index and guaranteed to be
- * correct, however value in index itself maybe wrong (windows itself
- * do not update them properly).
- */
- s64 data_size; /* Data size of unnamed DATA attribute. */
- s64 allocated_size; /* Allocated size stored in the filename
- index. (NOTE: Equal to allocated size of
- the unnamed data attribute for normal or
- encrypted files and to compressed size
- of the unnamed data attribute for sparse or
- compressed files.) */
-
- /*
- * These four fields are copy of relevant fields from
- * STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
- * attribute in the index.
- */
- time_t creation_time;
- time_t last_data_change_time;
- time_t last_mft_change_time;
- time_t last_access_time;
-
- /* These 2 fields are used to keep track of opened inodes. */
- struct list_head list_entry; /* Keep pointers to the next/prev list
- entry. */
- int nr_references; /* How many times this inode was
- opened. We really close inode only
- when this reaches zero. */
-
- struct list_head attr_cache; /* List of opened attributes. */
-};
-
-extern void __ntfs_inode_add_to_cache(ntfs_inode *ni);
-
-extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);
-
-extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);
-
-extern int ntfs_inode_close(ntfs_inode *ni);
-
-extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
- const leMFT_REF mref);
-
-extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
-
-/**
- * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty
- * @ni: ntfs inode to set dirty
- *
- * Set the inode @ni dirty so it is written out later (at the latest at
- * ntfs_inode_close() time). If @ni is an extent inode, set the base inode
- * dirty, too.
- *
- * This function cannot fail.
- */
-static __inline__ void ntfs_inode_mark_dirty(ntfs_inode *ni)
-{
- NInoSetDirty(ni);
- if (ni->nr_extents == -1)
- NInoSetDirty(ni->u.base_ni);
-}
-
-typedef enum {
- NTFS_UPDATE_ATIME = 1 << 0,
- NTFS_UPDATE_MTIME = 1 << 1,
- NTFS_UPDATE_CTIME = 1 << 2,
-} ntfs_time_update_flags;
-
-extern void ntfs_inode_update_times(ntfs_inode *ni,
- ntfs_time_update_flags mask);
-
-extern int ntfs_inode_sync(ntfs_inode *ni);
-
-extern int ntfs_inode_add_attrlist(ntfs_inode *ni);
-
-extern int ntfs_inode_free_space(ntfs_inode *ni, int size);
-
-extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
-
-#endif /* defined _NTFS_INODE_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/layout.h b/usr/src/lib/libntfs/common/include/ntfs/layout.h
deleted file mode 100644
index 7ae239cccd..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/layout.h
+++ /dev/null
@@ -1,3063 +0,0 @@
-/*
- * layout.h - Ntfs on-disk layout structures. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2005 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_LAYOUT_H
-#define _NTFS_LAYOUT_H
-
-#include "types.h"
-#include "endians.h"
-#include "support.h"
-
-/* The NTFS oem_id "NTFS " */
-#define NTFS_SB_MAGIC const_cpu_to_le64(0x202020205346544eULL)
-
-/*
- * Location of boot sector on partition:
- * The standard NTFS_BOOT_SECTOR is on sector 0 of the partition.
- * On NT4 and above there is one backup copy of the boot sector to
- * be found on the last sector of the partition (not normally accessible
- * from within Windows as the boot sector contained number of sectors
- * value is one less than the actual value!).
- * On versions of NT 3.51 and earlier, the backup copy was located at
- * number of sectors/2 (integer divide), i.e. in the middle of the volume.
- */
-
-/**
- * struct BIOS_PARAMETER_BLOCK - BIOS parameter block (BPB) structure.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le16 bytes_per_sector; /* Size of a sector in bytes. */
- u8 sectors_per_cluster; /* Size of a cluster in sectors. */
- le16 reserved_sectors; /* zero */
- u8 fats; /* zero */
- le16 root_entries; /* zero */
- le16 sectors; /* zero */
- u8 media_type; /* 0xf8 = hard disk */
- le16 sectors_per_fat; /* zero */
-/*0x0d*/le16 sectors_per_track; /* Required to boot Windows. */
-/*0x0f*/le16 heads; /* Required to boot Windows. */
-/*0x11*/le32 hidden_sectors; /* Offset to the start of the partition
- relative to the disk in sectors.
- Required to boot Windows. */
-/*0x15*/le32 large_sectors; /* zero */
-/* sizeof() = 25 (0x19) bytes */
-} __attribute__((__packed__)) BIOS_PARAMETER_BLOCK;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct NTFS_BOOT_SECTOR - NTFS boot sector structure.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u8 jump[3]; /* Irrelevant (jump to boot up code).*/
- le64 oem_id; /* Magic "NTFS ". */
-/*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */
- u8 physical_drive; /* 0x00 floppy, 0x80 hard disk */
- u8 current_head; /* zero */
- u8 extended_boot_signature; /* 0x80 */
- u8 reserved2; /* zero */
-/*0x28*/sle64 number_of_sectors; /* Number of sectors in volume. Gives
- maximum volume size of 2^63 sectors.
- Assuming standard sector size of 512
- bytes, the maximum byte size is
- approx. 4.7x10^21 bytes. (-; */
- sle64 mft_lcn; /* Cluster location of mft data. */
- sle64 mftmirr_lcn; /* Cluster location of copy of mft. */
- s8 clusters_per_mft_record; /* Mft record size in clusters. */
- u8 reserved0[3]; /* zero */
- s8 clusters_per_index_record; /* Index block size in clusters. */
- u8 reserved1[3]; /* zero */
- le64 volume_serial_number; /* Irrelevant (serial number). */
- le32 checksum; /* Boot sector checksum. */
-/*0x54*/u8 bootstrap[426]; /* Irrelevant (boot up code). */
- le16 end_of_sector_marker; /* End of boot sector magic. Always is
- 0xaa55 in little endian. */
-/* sizeof() = 512 (0x200) bytes */
-} __attribute__((__packed__)) NTFS_BOOT_SECTOR;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum NTFS_RECORD_TYPES -
- *
- * Magic identifiers present at the beginning of all ntfs record containing
- * records (like mft records for example).
- */
-typedef enum {
- /* Found in $MFT/$DATA. */
- magic_FILE = const_cpu_to_le32(0x454c4946), /* Mft entry. */
- magic_INDX = const_cpu_to_le32(0x58444e49), /* Index buffer. */
- magic_HOLE = const_cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
-
- /* Found in $LogFile/$DATA. */
- magic_RSTR = const_cpu_to_le32(0x52545352), /* Restart page. */
- magic_RCRD = const_cpu_to_le32(0x44524352), /* Log record page. */
-
- /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */
- magic_CHKD = const_cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
-
- /* Found in all ntfs record containing records. */
- magic_BAAD = const_cpu_to_le32(0x44414142), /* Failed multi sector
- transfer was detected. */
-
- /*
- * Found in $LogFile/$DATA when a page is full or 0xff bytes and is
- * thus not initialized. User has to initialize the page before using
- * it.
- */
- magic_empty = const_cpu_to_le32(0xffffffff),/* Record is empty and has
- to be initialized before
- it can be used. */
-} NTFS_RECORD_TYPES;
-
-/*
- * Generic magic comparison macros. Finally found a use for the ## preprocessor
- * operator! (-8
- */
-
-static inline BOOL __ntfs_is_magic(le32 x, NTFS_RECORD_TYPES r)
-{
- return (x == (__force le32)r);
-}
-#define ntfs_is_magic(x, m) __ntfs_is_magic(x, magic_##m)
-
-static inline BOOL __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPES r)
-{
- return (*p == (__force le32)r);
-}
-#define ntfs_is_magicp(p, m) __ntfs_is_magicp(p, magic_##m)
-
-/*
- * Specialised magic comparison macros for the NTFS_RECORD_TYPES defined above.
- */
-#define ntfs_is_file_record(x) ( ntfs_is_magic (x, FILE) )
-#define ntfs_is_file_recordp(p) ( ntfs_is_magicp(p, FILE) )
-#define ntfs_is_mft_record(x) ( ntfs_is_file_record(x) )
-#define ntfs_is_mft_recordp(p) ( ntfs_is_file_recordp(p) )
-#define ntfs_is_indx_record(x) ( ntfs_is_magic (x, INDX) )
-#define ntfs_is_indx_recordp(p) ( ntfs_is_magicp(p, INDX) )
-#define ntfs_is_hole_record(x) ( ntfs_is_magic (x, HOLE) )
-#define ntfs_is_hole_recordp(p) ( ntfs_is_magicp(p, HOLE) )
-
-#define ntfs_is_rstr_record(x) ( ntfs_is_magic (x, RSTR) )
-#define ntfs_is_rstr_recordp(p) ( ntfs_is_magicp(p, RSTR) )
-#define ntfs_is_rcrd_record(x) ( ntfs_is_magic (x, RCRD) )
-#define ntfs_is_rcrd_recordp(p) ( ntfs_is_magicp(p, RCRD) )
-
-#define ntfs_is_chkd_record(x) ( ntfs_is_magic (x, CHKD) )
-#define ntfs_is_chkd_recordp(p) ( ntfs_is_magicp(p, CHKD) )
-
-#define ntfs_is_baad_record(x) ( ntfs_is_magic (x, BAAD) )
-#define ntfs_is_baad_recordp(p) ( ntfs_is_magicp(p, BAAD) )
-
-#define ntfs_is_empty_record(x) ( ntfs_is_magic (x, empty) )
-#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
-
-
-#define NTFS_BLOCK_SIZE 512
-#define NTFS_BLOCK_SIZE_BITS 9
-
-/**
- * struct NTFS_RECORD -
- *
- * The Update Sequence Array (USA) is an array of the le16 values which belong
- * to the end of each sector protected by the update sequence record in which
- * this array is contained. Note that the first entry is the Update Sequence
- * Number (USN), a cyclic counter of how many times the protected record has
- * been written to disk. The values 0 and -1 (ie. 0xffff) are not used. All
- * last le16's of each sector have to be equal to the USN (during reading) or
- * are set to it (during writing). If they are not, an incomplete multi sector
- * transfer has occurred when the data was written.
- * The maximum size for the update sequence array is fixed to:
- * maximum size = usa_ofs + (usa_count * 2) = 510 bytes
- * The 510 bytes comes from the fact that the last le16 in the array has to
- * (obviously) finish before the last le16 of the first 512-byte sector.
- * This formula can be used as a consistency check in that usa_ofs +
- * (usa_count * 2) has to be less than or equal to 510.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the
- record type and/or status. */
- le16 usa_ofs; /* Offset to the Update Sequence Array (USA)
- from the start of the ntfs record. */
- le16 usa_count; /* Number of u16 sized entries in the USA
- including the Update Sequence Number (USN),
- thus the number of fixups is the usa_count
- minus 1. */
-} __attribute__((__packed__)) NTFS_RECORD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum NTFS_SYSTEM_FILES - System files mft record numbers.
- *
- * All these files are always marked as used in the bitmap attribute of the
- * mft; presumably in order to avoid accidental allocation for random other
- * mft records. Also, the sequence number for each of the system files is
- * always equal to their mft record number and it is never modified.
- */
-typedef enum {
- FILE_MFT = 0, /* Master file table (mft). Data attribute
- contains the entries and bitmap attribute
- records which ones are in use (bit==1). */
- FILE_MFTMirr = 1, /* Mft mirror: copy of first four mft records
- in data attribute. If cluster size > 4kiB,
- copy of first N mft records, with
- N = cluster_size / mft_record_size. */
- FILE_LogFile = 2, /* Journalling log in data attribute. */
- FILE_Volume = 3, /* Volume name attribute and volume information
- attribute (flags and ntfs version). Windows
- refers to this file as volume DASD (Direct
- Access Storage Device). */
- FILE_AttrDef = 4, /* Array of attribute definitions in data
- attribute. */
- FILE_root = 5, /* Root directory. */
- FILE_Bitmap = 6, /* Allocation bitmap of all clusters (LCNs) in
- data attribute. */
- FILE_Boot = 7, /* Boot sector (always at cluster 0) in data
- attribute. */
- FILE_BadClus = 8, /* Contains all bad clusters in the non-resident
- data attribute. */
- FILE_Secure = 9, /* Shared security descriptors in data attribute
- and two indexes into the descriptors.
- Appeared in Windows 2000. Before that, this
- file was named $Quota but was unused. */
- FILE_UpCase = 10, /* Uppercase equivalents of all 65536 Unicode
- characters in data attribute. */
- FILE_Extend = 11, /* Directory containing other system files (eg.
- $ObjId, $Quota, $Reparse and $UsnJrnl). This
- is new to NTFS 3.0. */
- FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */
- FILE_reserved13 = 13,
- FILE_reserved14 = 14,
- FILE_reserved15 = 15,
- FILE_first_user = 16, /* First user file, used as test limit for
- whether to allow opening a file or not. */
-} NTFS_SYSTEM_FILES;
-
-/**
- * enum MFT_RECORD_FLAGS -
- *
- * These are the so far known MFT_RECORD_* flags (16-bit) which contain
- * information about the mft record in which they are present.
- *
- * MFT_RECORD_IS_4 exists on all $Extend sub-files.
- * It seems that it marks it is a metadata file with MFT record >24, however,
- * it is unknown if it is limited to metadata files only.
- *
- * MFT_RECORD_IS_VIEW_INDEX exists on every metafile with a non directory
- * index, that means an INDEX_ROOT and an INDEX_ALLOCATION with a name other
- * than "$I30". It is unknown if it is limited to metadata files only.
- */
-#ifdef __sun
-typedef uint16_t MFT_RECORD_FLAGS;
-#define MFT_RECORD_IN_USE (const_cpu_to_le16(0x0001))
-#define MFT_RECORD_IS_DIRECTORY (const_cpu_to_le16(0x0002))
-#define MFT_RECORD_IS_4 (const_cpu_to_le16(0x0004))
-#define MFT_RECORD_IS_VIEW_INDEX (const_cpu_to_le16(0x0008))
-#else /* not __sun */
-typedef enum {
- MFT_RECORD_IN_USE = const_cpu_to_le16(0x0001),
- MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002),
- MFT_RECORD_IS_4 = const_cpu_to_le16(0x0004),
- MFT_RECORD_IS_VIEW_INDEX = const_cpu_to_le16(0x0008),
- MFT_REC_SPACE_FILLER = const_cpu_to_le16(0xffff),
- /* Just to make flags 16-bit. */
-} __attribute__((__packed__)) MFT_RECORD_FLAGS;
-#endif /* __sun */
-
-/*
- * mft references (aka file references or file record segment references) are
- * used whenever a structure needs to refer to a record in the mft.
- *
- * A reference consists of a 48-bit index into the mft and a 16-bit sequence
- * number used to detect stale references.
- *
- * For error reporting purposes we treat the 48-bit index as a signed quantity.
- *
- * The sequence number is a circular counter (skipping 0) describing how many
- * times the referenced mft record has been (re)used. This has to match the
- * sequence number of the mft record being referenced, otherwise the reference
- * is considered stale and removed (FIXME: only ntfsck or the driver itself?).
- *
- * If the sequence number is zero it is assumed that no sequence number
- * consistency checking should be performed.
- *
- * FIXME: Since inodes are 32-bit as of now, the driver needs to always check
- * for high_part being 0 and if not either BUG(), cause a panic() or handle
- * the situation in some other way. This shouldn't be a problem as a volume has
- * to become HUGE in order to need more than 32-bits worth of mft records.
- * Assuming the standard mft record size of 1kb only the records (never mind
- * the non-resident attributes, etc.) would require 4Tb of space on their own
- * for the first 32 bits worth of records. This is only if some strange person
- * doesn't decide to foul play and make the mft sparse which would be a really
- * horrible thing to do as it would trash our current driver implementation. )-:
- * Do I hear screams "we want 64-bit inodes!" ?!? (-;
- *
- * FIXME: The mft zone is defined as the first 12% of the volume. This space is
- * reserved so that the mft can grow contiguously and hence doesn't become
- * fragmented. Volume free space includes the empty part of the mft zone and
- * when the volume's free 88% are used up, the mft zone is shrunk by a factor
- * of 2, thus making more space available for more files/data. This process is
- * repeated every time there is no more free space except for the mft zone until
- * there really is no more free space.
- */
-
-/*
- * Typedef the MFT_REF as a 64-bit value for easier handling.
- * Also define two unpacking macros to get to the reference (MREF) and
- * sequence number (MSEQNO) respectively.
- * The _LE versions are to be applied on little endian MFT_REFs.
- * Note: The _LE versions will return a CPU endian formatted value!
- */
-#define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
-#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU)
-
-typedef u64 MFT_REF;
-typedef le64 leMFT_REF;
-
-#define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \
- ((MFT_REF)(m) & MFT_REF_MASK_CPU)))
-#define MK_LE_MREF(m, s) const_cpu_to_le64(((MFT_REF)(((MFT_REF)(s) << 48) | \
- ((MFT_REF)(m) & MFT_REF_MASK_CPU))))
-
-#define MREF(x) ((u64)((x) & MFT_REF_MASK_CPU))
-#define MSEQNO(x) ((u16)(((x) >> 48) & 0xffff))
-#define MREF_LE(x) ((u64)(const_le64_to_cpu(x) & MFT_REF_MASK_CPU))
-#define MSEQNO_LE(x) ((u16)((const_le64_to_cpu(x) >> 48) & 0xffff))
-
-#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0)
-#define ERR_MREF(x) ((u64)((s64)(x)))
-#define MREF_ERR(x) ((int)((s64)(x)))
-
-/**
- * struct MFT_RECORD - An MFT record layout (NTFS 3.1+)
- *
- * The mft record header present at the beginning of every record in the mft.
- * This is followed by a sequence of variable length attribute records which
- * is terminated by an attribute of type AT_END which is a truncated attribute
- * in that it only consists of the attribute type code AT_END and none of the
- * other members of the attribute structure are present.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
- le16 usa_ofs; /* See NTFS_RECORD definition above. */
- le16 usa_count; /* See NTFS_RECORD definition above. */
-
-/* 8*/ leLSN lsn; /* $LogFile sequence number for this record.
- Changed every time the record is modified. */
-/* 16*/ le16 sequence_number; /* Number of times this mft record has been
- reused. (See description for MFT_REF
- above.) NOTE: The increment (skipping zero)
- is done when the file is deleted. NOTE: If
- this is zero it is left zero. */
-/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of
- directory entries referencing this record.
- NOTE: Only used in mft base records.
- NOTE: When deleting a directory entry we
- check the link_count and if it is 1 we
- delete the file. Otherwise we delete the
- FILE_NAME_ATTR being referenced by the
- directory entry from the mft record and
- decrement the link_count.
- FIXME: Careful with Win32 + DOS names! */
-/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this
- mft record from the start of the mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
- is deleted, the MFT_RECORD_IN_USE flag is
- set to zero. */
-/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft
- record. This should be equal to the mft
- record size. */
-/* 32*/ leMFT_REF base_mft_record;/* This is zero for base mft records.
- When it is not zero it is a mft reference
- pointing to the base mft record to which
- this record belongs (this is then used to
- locate the attribute list attribute present
- in the base record which describes this
- extension record and hence might need
- modification when the extension record
- itself is modified, also locating the
- attribute list also means finding the other
- potential extents, belonging to the non-base
- mft record). */
-/* 40*/ le16 next_attr_instance; /* The instance number that will be
- assigned to the next attribute added to this
- mft record. NOTE: Incremented each time
- after it is used. NOTE: Every time the mft
- record is reused this number is set to zero.
- NOTE: The first instance number is always 0.
- */
-/* The below fields are specific to NTFS 3.1+ (Windows XP and above): */
-/* 42*/ le16 reserved; /* Reserved/alignment. */
-/* 44*/ le32 mft_record_number; /* Number of this mft record. */
-/* sizeof() = 48 bytes */
-/*
- * When (re)using the mft record, we place the update sequence array at this
- * offset, i.e. before we start with the attributes. This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work. As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading we obviously use the data from the ntfs record header.
- */
-} __attribute__((__packed__)) MFT_RECORD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct MFT_RECORD_OLD - An MFT record layout (NTFS <=3.0)
- *
- * This is the version without the NTFS 3.1+ specific fields.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
- le16 usa_ofs; /* See NTFS_RECORD definition above. */
- le16 usa_count; /* See NTFS_RECORD definition above. */
-
-/* 8*/ leLSN lsn; /* $LogFile sequence number for this record.
- Changed every time the record is modified. */
-/* 16*/ le16 sequence_number; /* Number of times this mft record has been
- reused. (See description for MFT_REF
- above.) NOTE: The increment (skipping zero)
- is done when the file is deleted. NOTE: If
- this is zero it is left zero. */
-/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of
- directory entries referencing this record.
- NOTE: Only used in mft base records.
- NOTE: When deleting a directory entry we
- check the link_count and if it is 1 we
- delete the file. Otherwise we delete the
- FILE_NAME_ATTR being referenced by the
- directory entry from the mft record and
- decrement the link_count.
- FIXME: Careful with Win32 + DOS names! */
-/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this
- mft record from the start of the mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
- is deleted, the MFT_RECORD_IN_USE flag is
- set to zero. */
-/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft
- record. This should be equal to the mft
- record size. */
-/* 32*/ MFT_REF base_mft_record; /* This is zero for base mft records.
- When it is not zero it is a mft reference
- pointing to the base mft record to which
- this record belongs (this is then used to
- locate the attribute list attribute present
- in the base record which describes this
- extension record and hence might need
- modification when the extension record
- itself is modified, also locating the
- attribute list also means finding the other
- potential extents, belonging to the non-base
- mft record). */
-/* 40*/ le16 next_attr_instance; /* The instance number that will be
- assigned to the next attribute added to this
- mft record. NOTE: Incremented each time
- after it is used. NOTE: Every time the mft
- record is reused this number is set to zero.
- NOTE: The first instance number is always 0.
- */
-/* sizeof() = 42 bytes */
-/*
- * When (re)using the mft record, we place the update sequence array at this
- * offset, i.e. before we start with the attributes. This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work. As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading we obviously use the data from the ntfs record header.
- */
-} __attribute__((__packed__)) MFT_RECORD_OLD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum ATTR_TYPES - System defined attributes (32-bit).
- *
- * Each attribute type has a corresponding attribute name (Unicode string of
- * maximum 64 character length) as described by the attribute definitions
- * present in the data attribute of the $AttrDef system file.
- *
- * On NTFS 3.0 volumes the names are just as the types are named in the below
- * enum exchanging AT_ for the dollar sign ($). If that isn't a revealing
- * choice of symbol... (-;
- */
-typedef enum {
- AT_UNUSED = const_cpu_to_le32( 0),
- AT_STANDARD_INFORMATION = const_cpu_to_le32( 0x10),
- AT_ATTRIBUTE_LIST = const_cpu_to_le32( 0x20),
- AT_FILE_NAME = const_cpu_to_le32( 0x30),
- AT_OBJECT_ID = const_cpu_to_le32( 0x40),
- AT_SECURITY_DESCRIPTOR = const_cpu_to_le32( 0x50),
- AT_VOLUME_NAME = const_cpu_to_le32( 0x60),
- AT_VOLUME_INFORMATION = const_cpu_to_le32( 0x70),
- AT_DATA = const_cpu_to_le32( 0x80),
- AT_INDEX_ROOT = const_cpu_to_le32( 0x90),
- AT_INDEX_ALLOCATION = const_cpu_to_le32( 0xa0),
- AT_BITMAP = const_cpu_to_le32( 0xb0),
- AT_REPARSE_POINT = const_cpu_to_le32( 0xc0),
- AT_EA_INFORMATION = const_cpu_to_le32( 0xd0),
- AT_EA = const_cpu_to_le32( 0xe0),
- AT_PROPERTY_SET = const_cpu_to_le32( 0xf0),
- AT_LOGGED_UTILITY_STREAM = const_cpu_to_le32( 0x100),
- AT_FIRST_USER_DEFINED_ATTRIBUTE = const_cpu_to_le32( 0x1000),
- AT_END = const_cpu_to_le32(0xffffffff),
-} ATTR_TYPES;
-
-/**
- * enum COLLATION_RULES - The collation rules for sorting views/indexes/etc
- * (32-bit).
- *
- * COLLATION_UNICODE_STRING - Collate Unicode strings by comparing their binary
- * Unicode values, except that when a character can be uppercased, the
- * upper case value collates before the lower case one.
- * COLLATION_FILE_NAME - Collate file names as Unicode strings. The collation
- * is done very much like COLLATION_UNICODE_STRING. In fact I have no idea
- * what the difference is. Perhaps the difference is that file names
- * would treat some special characters in an odd way (see
- * unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[]
- * for what I mean but COLLATION_UNICODE_STRING would not give any special
- * treatment to any characters at all, but this is speculation.
- * COLLATION_NTOFS_ULONG - Sorting is done according to ascending le32 key
- * values. E.g. used for $SII index in FILE_Secure, which sorts by
- * security_id (le32).
- * COLLATION_NTOFS_SID - Sorting is done according to ascending SID values.
- * E.g. used for $O index in FILE_Extend/$Quota.
- * COLLATION_NTOFS_SECURITY_HASH - Sorting is done first by ascending hash
- * values and second by ascending security_id values. E.g. used for $SDH
- * index in FILE_Secure.
- * COLLATION_NTOFS_ULONGS - Sorting is done according to a sequence of ascending
- * le32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which
- * sorts by object_id (16-byte), by splitting up the object_id in four
- * le32 values and using them as individual keys. E.g. take the following
- * two security_ids, stored as follows on disk:
- * 1st: a1 61 65 b7 65 7b d4 11 9e 3d 00 e0 81 10 42 59
- * 2nd: 38 14 37 d2 d2 f3 d4 11 a5 21 c8 6b 79 b1 97 45
- * To compare them, they are split into four le32 values each, like so:
- * 1st: 0xb76561a1 0x11d47b65 0xe0003d9e 0x59421081
- * 2nd: 0xd2371438 0x11d4f3d2 0x6bc821a5 0x4597b179
- * Now, it is apparent why the 2nd object_id collates after the 1st: the
- * first le32 value of the 1st object_id is less than the first le32 of
- * the 2nd object_id. If the first le32 values of both object_ids were
- * equal then the second le32 values would be compared, etc.
- */
-typedef enum {
- COLLATION_BINARY = const_cpu_to_le32(0), /* Collate by binary
- compare where the first byte is most
- significant. */
- COLLATION_FILE_NAME = const_cpu_to_le32(1), /* Collate file names
- as Unicode strings. */
- COLLATION_UNICODE_STRING = const_cpu_to_le32(2), /* Collate Unicode
- strings by comparing their binary
- Unicode values, except that when a
- character can be uppercased, the upper
- case value collates before the lower
- case one. */
- COLLATION_NTOFS_ULONG = const_cpu_to_le32(16),
- COLLATION_NTOFS_SID = const_cpu_to_le32(17),
- COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(18),
- COLLATION_NTOFS_ULONGS = const_cpu_to_le32(19),
-} COLLATION_RULES;
-
-/**
- * enum ATTR_DEF_FLAGS -
- *
- * The flags (32-bit) describing attribute properties in the attribute
- * definition structure. FIXME: This information is based on Regis's
- * information and, according to him, it is not certain and probably
- * incomplete. The INDEXABLE flag is fairly certainly correct as only the file
- * name attribute has this flag set and this is the only attribute indexed in
- * NT4.
- */
-typedef enum {
- ATTR_DEF_INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be
- indexed. */
- ATTR_DEF_MULTIPLE = const_cpu_to_le32(0x04), /* Attribute type
- can be present multiple times in the
- mft records of an inode. */
- ATTR_DEF_NOT_ZERO = const_cpu_to_le32(0x08), /* Attribute value
- must contain at least one non-zero
- byte. */
- ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be
- indexed and the attribute value must be
- unique for the attribute type in all of
- the mft records of an inode. */
- ATTR_DEF_NAMED_UNIQUE = const_cpu_to_le32(0x20), /* Attribute must be
- named and the name must be unique for
- the attribute type in all of the mft
- records of an inode. */
- ATTR_DEF_RESIDENT = const_cpu_to_le32(0x40), /* Attribute must be
- resident. */
- ATTR_DEF_ALWAYS_LOG = const_cpu_to_le32(0x80), /* Always log
- modifications to this attribute,
- regardless of whether it is resident or
- non-resident. Without this, only log
- modifications if the attribute is
- resident. */
-} ATTR_DEF_FLAGS;
-
-/**
- * struct ATTR_DEF -
- *
- * The data attribute of FILE_AttrDef contains a sequence of attribute
- * definitions for the NTFS volume. With this, it is supposed to be safe for an
- * older NTFS driver to mount a volume containing a newer NTFS version without
- * damaging it (that's the theory. In practice it's: not damaging it too much).
- * Entries are sorted by attribute type. The flags describe whether the
- * attribute can be resident/non-resident and possibly other things, but the
- * actual bits are unknown.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*hex ofs*/
-/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero
- terminated. */
-/* 80*/ ATTR_TYPES type; /* Type of the attribute. */
-/* 84*/ le32 display_rule; /* Default display rule.
- FIXME: What does it mean? (AIA) */
-/* 88*/ COLLATION_RULES collation_rule; /* Default collation rule. */
-/* 8c*/ ATTR_DEF_FLAGS flags; /* Flags describing the attribute. */
-/* 90*/ sle64 min_size; /* Optional minimum attribute size. */
-/* 98*/ sle64 max_size; /* Maximum size of attribute. */
-/* sizeof() = 0xa0 or 160 bytes */
-} __attribute__((__packed__)) ATTR_DEF;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum ATTR_FLAGS - Attribute flags (16-bit).
- */
-#ifdef __sun
-typedef uint16_t ATTR_FLAGS;
-#define ATTR_IS_COMPRESSED (const_cpu_to_le16(0x0001))
-#define ATTR_COMPRESSION_MASK (const_cpu_to_le16(0x00ff))
-#define ATTR_IS_ENCRYPTED (const_cpu_to_le16(0x4000))
-#define ATTR_IS_SPARSE (const_cpu_to_le16(0x8000))
-#else /* not __sun */
-typedef enum {
- ATTR_IS_COMPRESSED = const_cpu_to_le16(0x0001),
- ATTR_COMPRESSION_MASK = const_cpu_to_le16(0x00ff), /* Compression
- method mask. Also, first
- illegal value. */
- ATTR_IS_ENCRYPTED = const_cpu_to_le16(0x4000),
- ATTR_IS_SPARSE = const_cpu_to_le16(0x8000),
-} __attribute__((__packed__)) ATTR_FLAGS;
-#endif /* __sun */
-
-/*
- * Attribute compression.
- *
- * Only the data attribute is ever compressed in the current ntfs driver in
- * Windows. Further, compression is only applied when the data attribute is
- * non-resident. Finally, to use compression, the maximum allowed cluster size
- * on a volume is 4kib.
- *
- * The compression method is based on independently compressing blocks of X
- * clusters, where X is determined from the compression_unit value found in the
- * non-resident attribute record header (more precisely: X = 2^compression_unit
- * clusters). On Windows NT/2k, X always is 16 clusters (compression_unit = 4).
- *
- * There are three different cases of how a compression block of X clusters
- * can be stored:
- *
- * 1) The data in the block is all zero (a sparse block):
- * This is stored as a sparse block in the runlist, i.e. the runlist
- * entry has length = X and lcn = -1. The mapping pairs array actually
- * uses a delta_lcn value length of 0, i.e. delta_lcn is not present at
- * all, which is then interpreted by the driver as lcn = -1.
- * NOTE: Even uncompressed files can be sparse on NTFS 3.0 volumes, then
- * the same principles apply as above, except that the length is not
- * restricted to being any particular value.
- *
- * 2) The data in the block is not compressed:
- * This happens when compression doesn't reduce the size of the block
- * in clusters. I.e. if compression has a small effect so that the
- * compressed data still occupies X clusters, then the uncompressed data
- * is stored in the block.
- * This case is recognised by the fact that the runlist entry has
- * length = X and lcn >= 0. The mapping pairs array stores this as
- * normal with a run length of X and some specific delta_lcn, i.e.
- * delta_lcn has to be present.
- *
- * 3) The data in the block is compressed:
- * The common case. This case is recognised by the fact that the run
- * list entry has length L < X and lcn >= 0. The mapping pairs array
- * stores this as normal with a run length of X and some specific
- * delta_lcn, i.e. delta_lcn has to be present. This runlist entry is
- * immediately followed by a sparse entry with length = X - L and
- * lcn = -1. The latter entry is to make up the vcn counting to the
- * full compression block size X.
- *
- * In fact, life is more complicated because adjacent entries of the same type
- * can be coalesced. This means that one has to keep track of the number of
- * clusters handled and work on a basis of X clusters at a time being one
- * block. An example: if length L > X this means that this particular runlist
- * entry contains a block of length X and part of one or more blocks of length
- * L - X. Another example: if length L < X, this does not necessarily mean that
- * the block is compressed as it might be that the lcn changes inside the block
- * and hence the following runlist entry describes the continuation of the
- * potentially compressed block. The block would be compressed if the
- * following runlist entry describes at least X - L sparse clusters, thus
- * making up the compression block length as described in point 3 above. (Of
- * course, there can be several runlist entries with small lengths so that the
- * sparse entry does not follow the first data containing entry with
- * length < X.)
- *
- * NOTE: At the end of the compressed attribute value, there most likely is not
- * just the right amount of data to make up a compression block, thus this data
- * is not even attempted to be compressed. It is just stored as is, unless
- * the number of clusters it occupies is reduced when compressed in which case
- * it is stored as a compressed compression block, complete with sparse
- * clusters at the end.
- */
-
-/**
- * enum RESIDENT_ATTR_FLAGS - Flags of resident attributes (8-bit).
- */
-#ifdef __sun
-typedef uint8_t RESIDENT_ATTR_FLAGS;
-#define RESIDENT_ATTR_IS_INDEXED (0x01)
-#else /* not __sun */
-typedef enum {
- RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
- (has implications for deleting and
- modifying the attribute). */
-} __attribute__((__packed__)) RESIDENT_ATTR_FLAGS;
-#endif /* __sun */
-
-/**
- * struct ATTR_RECORD - Attribute record header.
- *
- * Always aligned to 8-byte boundary.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0*/ ATTR_TYPES type; /* The (32-bit) type of the attribute. */
-/* 4*/ le32 length; /* Byte size of the resident part of the
- attribute (aligned to 8-byte boundary).
- Used to get to the next attribute. */
-/* 8*/ u8 non_resident; /* If 0, attribute is resident.
- If 1, attribute is non-resident. */
-/* 9*/ u8 name_length; /* Unicode character size of name of attribute.
- 0 if unnamed. */
-/* 10*/ le16 name_offset; /* If name_length != 0, the byte offset to the
- beginning of the name from the attribute
- record. Note that the name is stored as a
- Unicode string. When creating, place offset
- just at the end of the record header. Then,
- follow with attribute value or mapping pairs
- array, resident and non-resident attributes
- respectively, aligning to an 8-byte
- boundary. */
-/* 12*/ ATTR_FLAGS flags; /* Flags describing the attribute. */
-/* 14*/ le16 instance; /* The instance of this attribute record. This
- number is unique within this mft record (see
- MFT_RECORD/next_attribute_instance notes
- above for more details). */
-/* 16*/ union {
- /* Resident attributes. */
- struct {
-/* 16 */ le32 value_length; /* Byte size of attribute value. */
-/* 20 */ le16 value_offset; /* Byte offset of the attribute
- value from the start of the
- attribute record. When creating,
- align to 8-byte boundary if we
- have a name present as this might
- not have a length of a multiple
- of 8-bytes. */
-/* 22 */ RESIDENT_ATTR_FLAGS resident_flags; /* See above. */
-/* 23 */ s8 reservedR; /* Reserved/alignment to 8-byte
- boundary. */
-/* 24 */ void *resident_end[]; /* Use offsetof(ATTR_RECORD,
- resident_end) to get size of
- a resident attribute. */
- } __attribute__((__packed__)) res;
-
- /* Non-resident attributes. */
- struct {
-/* 16*/ leVCN lowest_vcn;/* Lowest valid virtual cluster number
- for this portion of the attribute value or
- 0 if this is the only extent (usually the
- case). - Only when an attribute list is used
- does lowest_vcn != 0 ever occur. */
-/* 24*/ leVCN highest_vcn;/* Highest valid vcn of this extent of
- the attribute value. - Usually there is only one
- portion, so this usually equals the attribute
- value size in clusters minus 1. Can be -1 for
- zero length files. Can be 0 for "single extent"
- attributes. */
-/* 32*/ le16 mapping_pairs_offset; /* Byte offset from the
- beginning of the structure to the mapping pairs
- array which contains the mappings between the
- VCNs and the logical cluster numbers (LCNs).
- When creating, place this at the end of this
- record header aligned to 8-byte boundary. */
-/* 34*/ u8 compression_unit; /* The compression unit expressed
- as the log to the base 2 of the number of
- clusters in a compression unit. 0 means not
- compressed. (This effectively limits the
- compression unit size to be a power of two
- clusters.) WinNT4 only uses a value of 4. */
-/* 35*/ u8 reserved1[5]; /* Align to 8-byte boundary. */
-/* The sizes below are only used when lowest_vcn is zero, as otherwise it would
- be difficult to keep them up-to-date.*/
-/* 40*/ sle64 allocated_size; /* Byte size of disk space
- allocated to hold the attribute value. Always
- is a multiple of the cluster size. When a file
- is compressed, this field is a multiple of the
- compression block size (2^compression_unit) and
- it represents the logically allocated space
- rather than the actual on disk usage. For this
- use the compressed_size (see below). */
-/* 48*/ sle64 data_size; /* Byte size of the attribute
- value. Can be larger than allocated_size if
- attribute value is compressed or sparse. */
-/* 56*/ sle64 initialized_size; /* Byte size of initialized
- portion of the attribute value. Usually equals
- data_size. */
-#ifdef __sun
-/* 64 */
-#define non_resident_end compressed_size
-#else /* not __sun */
-/* 64 */ void *non_resident_end[0]; /* Use offsetof(ATTR_RECORD,
- non_resident_end) to get
- size of a non resident
- attribute. */
-#endif /* __sun */
-/* sizeof(uncompressed attr) = 64*/
-/* 64*/ sle64 compressed_size; /* Byte size of the attribute
- value after compression. Only present when
- compressed. Always is a multiple of the
- cluster size. Represents the actual amount of
- disk space being used on the disk. */
-/* 72 */ void *compressed_end[];
- /* Use offsetof(ATTR_RECORD, compressed_end) to
- get size of a compressed attribute. */
-/* sizeof(compressed attr) = 72*/
- } __attribute__((__packed__)) nonres;
- } __attribute__((__packed__)) u;
-} __attribute__((__packed__)) ATTR_RECORD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-typedef ATTR_RECORD ATTR_REC;
-
-/**
- * enum FILE_ATTR_FLAGS - File attribute flags (32-bit).
- */
-typedef enum {
- /*
- * These flags are only present in the STANDARD_INFORMATION attribute
- * (in the field file_attributes).
- */
- FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001),
- FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002),
- FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004),
- /* Old DOS valid. Unused in NT. = cpu_to_le32(0x00000008), */
-
- FILE_ATTR_DIRECTORY = const_cpu_to_le32(0x00000010),
- /* FILE_ATTR_DIRECTORY is not considered valid in NT. It is reserved
- for the DOS SUBDIRECTORY flag. */
- FILE_ATTR_ARCHIVE = const_cpu_to_le32(0x00000020),
- FILE_ATTR_DEVICE = const_cpu_to_le32(0x00000040),
- FILE_ATTR_NORMAL = const_cpu_to_le32(0x00000080),
-
- FILE_ATTR_TEMPORARY = const_cpu_to_le32(0x00000100),
- FILE_ATTR_SPARSE_FILE = const_cpu_to_le32(0x00000200),
- FILE_ATTR_REPARSE_POINT = const_cpu_to_le32(0x00000400),
- FILE_ATTR_COMPRESSED = const_cpu_to_le32(0x00000800),
-
- FILE_ATTR_OFFLINE = const_cpu_to_le32(0x00001000),
- FILE_ATTR_NOT_CONTENT_INDEXED = const_cpu_to_le32(0x00002000),
- FILE_ATTR_ENCRYPTED = const_cpu_to_le32(0x00004000),
-
- FILE_ATTR_VALID_FLAGS = const_cpu_to_le32(0x00007fb7),
- /* FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
- FILE_ATTR_DEVICE and preserves everything else. This mask
- is used to obtain all flags that are valid for reading. */
- FILE_ATTR_VALID_SET_FLAGS = const_cpu_to_le32(0x000031a7),
- /* FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
- FILE_ATTR_DEVICE, FILE_ATTR_DIRECTORY, FILE_ATTR_SPARSE_FILE,
- FILE_ATTR_REPARSE_POINT, FILE_ATRE_COMPRESSED and FILE_ATTR_ENCRYPTED
- and preserves the rest. This mask is used to to obtain all flags that
- are valid for setting. */
-
- /**
- * FILE_ATTR_I30_INDEX_PRESENT - Is it a directory?
- *
- * This is a copy of the MFT_RECORD_IS_DIRECTORY bit from the mft
- * record, telling us whether this is a directory or not, i.e. whether
- * it has an index root attribute named "$I30" or not.
- *
- * This flag is only present in the FILE_NAME attribute (in the
- * file_attributes field).
- */
- FILE_ATTR_I30_INDEX_PRESENT = const_cpu_to_le32(0x10000000),
-
- /**
- * FILE_ATTR_VIEW_INDEX_PRESENT - Does have a non-directory index?
- *
- * This is a copy of the MFT_RECORD_IS_VIEW_INDEX bit from the mft
- * record, telling us whether this file has a view index present (eg.
- * object id index, quota index, one of the security indexes and the
- * reparse points index).
- *
- * This flag is only present in the $STANDARD_INFORMATION and
- * $FILE_NAME attributes.
- */
- FILE_ATTR_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000),
-} __attribute__((__packed__)) FILE_ATTR_FLAGS;
-
-/*
- * NOTE on times in NTFS: All times are in MS standard time format, i.e. they
- * are the number of 100-nanosecond intervals since 1st January 1601, 00:00:00
- * universal coordinated time (UTC). (In Linux time starts 1st January 1970,
- * 00:00:00 UTC and is stored as the number of 1-second intervals since then.)
- */
-
-/**
- * struct STANDARD_INFORMATION - Attribute: Standard information (0x10).
- *
- * NOTE: Always resident.
- * NOTE: Present in all base file records on a volume.
- * NOTE: There is conflicting information about the meaning of each of the time
- * fields but the meaning as defined below has been verified to be
- * correct by practical experimentation on Windows NT4 SP6a and is hence
- * assumed to be the one and only correct interpretation.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0*/ sle64 creation_time; /* Time file was created. Updated when
- a filename is changed(?). */
-/* 8*/ sle64 last_data_change_time; /* Time the data attribute was last
- modified. */
-/* 16*/ sle64 last_mft_change_time; /* Time this mft record was last
- modified. */
-/* 24*/ sle64 last_access_time; /* Approximate time when the file was
- last accessed (obviously this is not
- updated on read-only volumes). In
- Windows this is only updated when
- accessed if some time delta has
- passed since the last update. Also,
- last access times updates can be
- disabled altogether for speed. */
-/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
-/* 36*/ union {
- /* NTFS 1.2 (and previous, presumably) */
- struct {
- /* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte
- boundary. */
- /* 48 */ void *v1_end[]; /* Marker for offsetof(). */
- } __attribute__((__packed__)) v12;
-/* sizeof() = 48 bytes */
- /* NTFS 3.0 */
- struct {
-/*
- * If a volume has been upgraded from a previous NTFS version, then these
- * fields are present only if the file has been accessed since the upgrade.
- * Recognize the difference by comparing the length of the resident attribute
- * value. If it is 48, then the following fields are missing. If it is 72 then
- * the fields are present. Maybe just check like this:
- * if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) {
- * Assume NTFS 1.2- format.
- * If (volume version is 3.0+)
- * Upgrade attribute to NTFS 3.0 format.
- * else
- * Use NTFS 1.2- format for access.
- * } else
- * Use NTFS 3.0 format for access.
- * Only problem is that it might be legal to set the length of the value to
- * arbitrarily large values thus spoiling this check. - But chkdsk probably
- * views that as a corruption, assuming that it behaves like this for all
- * attributes.
- */
- /* 36*/ le32 maximum_versions; /* Maximum allowed versions for
- file. Zero if version numbering is disabled. */
- /* 40*/ le32 version_number; /* This file's version (if any).
- Set to zero if maximum_versions is zero. */
- /* 44*/ le32 class_id; /* Class id from bidirectional
- class id index (?). */
- /* 48*/ le32 owner_id; /* Owner_id of the user owning
- the file. Translate via $Q index in FILE_Extend
- /$Quota to the quota control entry for the user
- owning the file. Zero if quotas are disabled. */
- /* 52*/ le32 security_id; /* Security_id for the file.
- Translate via $SII index and $SDS data stream
- in FILE_Secure to the security descriptor. */
- /* 56*/ le64 quota_charged; /* Byte size of the charge to
- the quota for all streams of the file. Note: Is
- zero if quotas are disabled. */
- /* 64*/ le64 usn; /* Last update sequence number
- of the file. This is a direct index into the
- change (aka USN) journal file. It is zero if
- the USN journal is disabled.
- NOTE: To disable the journal need to delete
- the journal file itself and to then walk the
- whole mft and set all USN entries in all mft
- records to zero! (This can take a while!)
- The journal is FILE_Extend/$UsnJrnl. Win2k
- will recreate the journal and initiate
- logging if necessary when mounting the
- partition. This, in contrast to disabling the
- journal is a very fast process, so the user
- won't even notice it. */
- /* 72*/ void *v3_end[]; /* Marker for offsetof(). */
- } __attribute__((__packed__)) v30;
- } __attribute__((__packed__)) u;
-/* sizeof() = 72 bytes (NTFS 3.0) */
-} __attribute__((__packed__)) STANDARD_INFORMATION;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct ATTR_LIST_ENTRY - Attribute: Attribute list (0x20).
- *
- * - Can be either resident or non-resident.
- * - Value consists of a sequence of variable length, 8-byte aligned,
- * ATTR_LIST_ENTRY records.
- * - The attribute list attribute contains one entry for each attribute of
- * the file in which the list is located, except for the list attribute
- * itself. The list is sorted: first by attribute type, second by attribute
- * name (if present), third by instance number. The extents of one
- * non-resident attribute (if present) immediately follow after the initial
- * extent. They are ordered by lowest_vcn and have their instance set to zero.
- * It is not allowed to have two attributes with all sorting keys equal.
- * - Further restrictions:
- * - If not resident, the vcn to lcn mapping array has to fit inside the
- * base mft record.
- * - The attribute list attribute value has a maximum size of 256kb. This
- * is imposed by the Windows cache manager.
- * - Attribute lists are only used when the attributes of mft record do not
- * fit inside the mft record despite all attributes (that can be made
- * non-resident) having been made non-resident. This can happen e.g. when:
- * - File has a large number of hard links (lots of file name
- * attributes present).
- * - The mapping pairs array of some non-resident attribute becomes so
- * large due to fragmentation that it overflows the mft record.
- * - The security descriptor is very complex (not applicable to
- * NTFS 3.0 volumes).
- * - There are many named streams.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0*/ ATTR_TYPES type; /* Type of referenced attribute. */
-/* 4*/ le16 length; /* Byte size of this entry. */
-/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
- attribute or 0 if unnamed. */
-/* 7*/ u8 name_offset; /* Byte offset to beginning of attribute name
- (always set this to where the name would
- start even if unnamed). */
-/* 8*/ leVCN lowest_vcn; /* Lowest virtual cluster number of this portion
- of the attribute value. This is usually 0. It
- is non-zero for the case where one attribute
- does not fit into one mft record and thus
- several mft records are allocated to hold
- this attribute. In the latter case, each mft
- record holds one extent of the attribute and
- there is one attribute list entry for each
- extent. NOTE: This is DEFINITELY a signed
- value! The windows driver uses cmp, followed
- by jg when comparing this, thus it treats it
- as signed. */
-/* 16*/ leMFT_REF mft_reference;/* The reference of the mft record holding
- the ATTR_RECORD for this portion of the
- attribute value. */
-/* 24*/ le16 instance; /* If lowest_vcn = 0, the instance of the
- attribute being referenced; otherwise 0. */
-/* 26*/ ntfschar name[]; /* Use when creating only. When reading use
- name_offset to determine the location of the
- name. */
-/* sizeof() = 26 + (attribute_name_length * 2) bytes */
-} __attribute__((__packed__)) ATTR_LIST_ENTRY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/*
- * The maximum allowed length for a file name.
- */
-#define NTFS_MAX_NAME_LEN 255
-
-/**
- * enum FILE_NAME_TYPE_FLAGS - Possible namespaces for filenames in ntfs.
- * (8-bit).
- */
-#ifdef __sun
-typedef uint8_t FILE_NAME_TYPE_FLAGS;
-#define FILE_NAME_POSIX (0x00)
-#define FILE_NAME_WIN32 (0x01)
-#define FILE_NAME_DOS (0x02)
-#define FILE_NAME_WIN32_AND_DOS (0x03)
-#else /* not __sun */
-typedef enum {
- FILE_NAME_POSIX = 0x00,
- /* This is the largest namespace. It is case sensitive and
- allows all Unicode characters except for: '\0' and '/'.
- Beware that in WinNT/2k files which eg have the same name
- except for their case will not be distinguished by the
- standard utilities and thus a "del filename" will delete
- both "filename" and "fileName" without warning. */
- FILE_NAME_WIN32 = 0x01,
- /* The standard WinNT/2k NTFS long filenames. Case insensitive.
- All Unicode chars except: '\0', '"', '*', '/', ':', '<',
- '>', '?', '\' and '|'. Further, names cannot end with a '.'
- or a space. */
- FILE_NAME_DOS = 0x02,
- /* The standard DOS filenames (8.3 format). Uppercase only.
- All 8-bit characters greater space, except: '"', '*', '+',
- ',', '/', ':', ';', '<', '=', '>', '?' and '\'. */
- FILE_NAME_WIN32_AND_DOS = 0x03,
- /* 3 means that both the Win32 and the DOS filenames are
- identical and hence have been saved in this single filename
- record. */
-} __attribute__((__packed__)) FILE_NAME_TYPE_FLAGS;
-#endif /* __sun */
-
-/**
- * struct FILE_NAME_ATTR - Attribute: Filename (0x30).
- *
- * NOTE: Always resident.
- * NOTE: All fields, except the parent_directory, are only updated when the
- * filename is changed. Until then, they just become out of sync with
- * reality and the more up to date values are present in the standard
- * information attribute.
- * NOTE: There is conflicting information about the meaning of each of the time
- * fields but the meaning as defined below has been verified to be
- * correct by practical experimentation on Windows NT4 SP6a and is hence
- * assumed to be the one and only correct interpretation.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*hex ofs*/
-/* 0*/ leMFT_REF parent_directory; /* Directory this filename is
- referenced from. */
-/* 8*/ sle64 creation_time; /* Time file was created. */
-/* 10*/ sle64 last_data_change_time; /* Time the data attribute was last
- modified. */
-/* 18*/ sle64 last_mft_change_time; /* Time this mft record was last
- modified. */
-/* 20*/ sle64 last_access_time; /* Last time this mft record was
- accessed. */
-/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
- for the data attribute. So for
- normal $DATA, this is the
- allocated_size from the unnamed
- $DATA attribute and for compressed
- and/or sparse $DATA, this is the
- compressed_size from the unnamed
- $DATA attribute. NOTE: This is a
- multiple of the cluster size. */
-/* 30*/ sle64 data_size; /* Byte size of actual data in data
- attribute. */
-/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
-/* 3c*/ union {
- /* 3c*/ struct {
- /* 3c*/ le16 packed_ea_size; /* Size of the buffer needed to
- pack the extended attributes
- (EAs), if such are present.*/
- /* 3e*/ le16 reserved; /* Reserved for alignment. */
- } __attribute__((__packed__)) s;
- /* 3c*/ le32 reparse_point_tag; /* Type of reparse point,
- present only in reparse
- points and only if there are
- no EAs. */
- } __attribute__((__packed__)) u;
-/* 40*/ u8 file_name_length; /* Length of file name in
- (Unicode) characters. */
-/* 41*/ FILE_NAME_TYPE_FLAGS file_name_type; /* Namespace of the file name.*/
-/* 42*/ ntfschar file_name[]; /* File name in Unicode. */
-} __attribute__((__packed__)) FILE_NAME_ATTR;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct GUID - GUID structures store globally unique identifiers (GUID).
- *
- * A GUID is a 128-bit value consisting of one group of eight hexadecimal
- * digits, followed by three groups of four hexadecimal digits each, followed
- * by one group of twelve hexadecimal digits. GUIDs are Microsoft's
- * implementation of the distributed computing environment (DCE) universally
- * unique identifier (UUID).
- *
- * Example of a GUID in string format:
- * 1F010768-5A73-BC91-0010-A52216A7227B
- * And the same in binary:
- * 1F0107685A73BC910010A52216A7227B
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef union {
- struct {
- le32 data1; /* The first eight hexadecimal digits of the
- GUID. */
- le16 data2; /* The first group of four hexadecimal
- digits. */
- le16 data3; /* The second group of four hexadecimal
- digits. */
- u8 data4[8]; /* The first two bytes are the third group of
- four hexadecimal digits. The remaining six
- bytes are the final 12 hexadecimal digits. */
- } __attribute__((__packed__)) s;
- u8 raw[16]; /* Raw binary for ease of access. */
-} __attribute__((__packed__)) GUID;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct OBJ_ID_INDEX_DATA - FILE_Extend/$ObjId contains an index named $O.
- *
- * This index contains all object_ids present on the volume as the index keys
- * and the corresponding mft_record numbers as the index entry data parts.
- *
- * The data part (defined below) also contains three other object_ids:
- * birth_volume_id - object_id of FILE_Volume on which the file was first
- * created. Optional (i.e. can be zero).
- * birth_object_id - object_id of file when it was first created. Usually
- * equals the object_id. Optional (i.e. can be zero).
- * domain_id - Reserved (always zero).
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- leMFT_REF mft_reference;/* Mft record containing the object_id in
- the index entry key. */
- union {
- struct {
- GUID birth_volume_id;
- GUID birth_object_id;
- GUID domain_id;
- } __attribute__((__packed__)) s;
- u8 extended_info[48];
- } __attribute__((__packed__)) u;
-} __attribute__((__packed__)) OBJ_ID_INDEX_DATA;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct OBJECT_ID_ATTR - Attribute: Object id (NTFS 3.0+) (0x40).
- *
- * NOTE: Always resident.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- GUID object_id; /* Unique id assigned to the
- file.*/
- /* The following fields are optional. The attribute value size is 16
- bytes, i.e. sizeof(GUID), if these are not present at all. Note,
- the entries can be present but one or more (or all) can be zero
- meaning that that particular value(s) is(are) not defined. Note,
- when the fields are missing here, it is well possible that they are
- to be found within the $Extend/$ObjId system file indexed under the
- above object_id. */
- union {
- struct {
- GUID birth_volume_id; /* Unique id of volume on which
- the file was first created.*/
- GUID birth_object_id; /* Unique id of file when it was
- first created. */
- GUID domain_id; /* Reserved, zero. */
- } __attribute__((__packed__)) s;
- u8 extended_info[48];
- } __attribute__((__packed__)) u;
-} __attribute__((__packed__)) OBJECT_ID_ATTR;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#if 0
-/**
- * enum IDENTIFIER_AUTHORITIES -
- *
- * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
- * the SID structure (see below).
- */
-typedef enum { /* SID string prefix. */
- SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */
- SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */
- SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */
- SECURITY_CREATOR_SID_AUTHORITY = {0, 0, 0, 0, 0, 3}, /* S-1-3 */
- SECURITY_NON_UNIQUE_AUTHORITY = {0, 0, 0, 0, 0, 4}, /* S-1-4 */
- SECURITY_NT_SID_AUTHORITY = {0, 0, 0, 0, 0, 5}, /* S-1-5 */
-} IDENTIFIER_AUTHORITIES;
-#endif
-
-/**
- * enum RELATIVE_IDENTIFIERS -
- *
- * These relative identifiers (RIDs) are used with the above identifier
- * authorities to make up universal well-known SIDs.
- *
- * Note: The relative identifier (RID) refers to the portion of a SID, which
- * identifies a user or group in relation to the authority that issued the SID.
- * For example, the universal well-known SID Creator Owner ID (S-1-3-0) is
- * made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
- * the relative identifier SECURITY_CREATOR_OWNER_RID (0).
- */
-typedef enum { /* Identifier authority. */
- SECURITY_NULL_RID = 0, /* S-1-0 */
- SECURITY_WORLD_RID = 0, /* S-1-1 */
- SECURITY_LOCAL_RID = 0, /* S-1-2 */
-
- SECURITY_CREATOR_OWNER_RID = 0, /* S-1-3 */
- SECURITY_CREATOR_GROUP_RID = 1, /* S-1-3 */
-
- SECURITY_CREATOR_OWNER_SERVER_RID = 2, /* S-1-3 */
- SECURITY_CREATOR_GROUP_SERVER_RID = 3, /* S-1-3 */
-
- SECURITY_DIALUP_RID = 1,
- SECURITY_NETWORK_RID = 2,
- SECURITY_BATCH_RID = 3,
- SECURITY_INTERACTIVE_RID = 4,
- SECURITY_SERVICE_RID = 6,
- SECURITY_ANONYMOUS_LOGON_RID = 7,
- SECURITY_PROXY_RID = 8,
- SECURITY_ENTERPRISE_CONTROLLERS_RID=9,
- SECURITY_SERVER_LOGON_RID = 9,
- SECURITY_PRINCIPAL_SELF_RID = 0xa,
- SECURITY_AUTHENTICATED_USER_RID = 0xb,
- SECURITY_RESTRICTED_CODE_RID = 0xc,
- SECURITY_TERMINAL_SERVER_RID = 0xd,
-
- SECURITY_LOGON_IDS_RID = 5,
- SECURITY_LOGON_IDS_RID_COUNT = 3,
-
- SECURITY_LOCAL_SYSTEM_RID = 0x12,
-
- SECURITY_NT_NON_UNIQUE = 0x15,
-
- SECURITY_BUILTIN_DOMAIN_RID = 0x20,
-
- /*
- * Well-known domain relative sub-authority values (RIDs).
- */
-
- /* Users. */
- DOMAIN_USER_RID_ADMIN = 0x1f4,
- DOMAIN_USER_RID_GUEST = 0x1f5,
- DOMAIN_USER_RID_KRBTGT = 0x1f6,
-
- /* Groups. */
- DOMAIN_GROUP_RID_ADMINS = 0x200,
- DOMAIN_GROUP_RID_USERS = 0x201,
- DOMAIN_GROUP_RID_GUESTS = 0x202,
- DOMAIN_GROUP_RID_COMPUTERS = 0x203,
- DOMAIN_GROUP_RID_CONTROLLERS = 0x204,
- DOMAIN_GROUP_RID_CERT_ADMINS = 0x205,
- DOMAIN_GROUP_RID_SCHEMA_ADMINS = 0x206,
- DOMAIN_GROUP_RID_ENTERPRISE_ADMINS= 0x207,
- DOMAIN_GROUP_RID_POLICY_ADMINS = 0x208,
-
- /* Aliases. */
- DOMAIN_ALIAS_RID_ADMINS = 0x220,
- DOMAIN_ALIAS_RID_USERS = 0x221,
- DOMAIN_ALIAS_RID_GUESTS = 0x222,
- DOMAIN_ALIAS_RID_POWER_USERS = 0x223,
-
- DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224,
- DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225,
- DOMAIN_ALIAS_RID_PRINT_OPS = 0x226,
- DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227,
-
- DOMAIN_ALIAS_RID_REPLICATOR = 0x228,
- DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229,
- DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a,
-} RELATIVE_IDENTIFIERS;
-
-/*
- * The universal well-known SIDs:
- *
- * NULL_SID S-1-0-0
- * WORLD_SID S-1-1-0
- * LOCAL_SID S-1-2-0
- * CREATOR_OWNER_SID S-1-3-0
- * CREATOR_GROUP_SID S-1-3-1
- * CREATOR_OWNER_SERVER_SID S-1-3-2
- * CREATOR_GROUP_SERVER_SID S-1-3-3
- *
- * (Non-unique IDs) S-1-4
- *
- * NT well-known SIDs:
- *
- * NT_AUTHORITY_SID S-1-5
- * DIALUP_SID S-1-5-1
- *
- * NETWORK_SID S-1-5-2
- * BATCH_SID S-1-5-3
- * INTERACTIVE_SID S-1-5-4
- * SERVICE_SID S-1-5-6
- * ANONYMOUS_LOGON_SID S-1-5-7 (aka null logon session)
- * PROXY_SID S-1-5-8
- * SERVER_LOGON_SID S-1-5-9 (aka domain controller account)
- * SELF_SID S-1-5-10 (self RID)
- * AUTHENTICATED_USER_SID S-1-5-11
- * RESTRICTED_CODE_SID S-1-5-12 (running restricted code)
- * TERMINAL_SERVER_SID S-1-5-13 (running on terminal server)
- *
- * (Logon IDs) S-1-5-5-X-Y
- *
- * (NT non-unique IDs) S-1-5-0x15-...
- *
- * (Built-in domain) S-1-5-0x20
- */
-
-/**
- * union SID_IDENTIFIER_AUTHORITY - A 48-bit value used in the SID structure
- *
- * NOTE: This is stored as a big endian number.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef union {
- struct {
- be16 high_part; /* High 16-bits. */
- be32 low_part; /* Low 32-bits. */
- } __attribute__((__packed__)) s;
- u8 value[6]; /* Value as individual bytes. */
-} __attribute__((__packed__)) SID_IDENTIFIER_AUTHORITY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SID -
- *
- * The SID structure is a variable-length structure used to uniquely identify
- * users or groups. SID stands for security identifier.
- *
- * The standard textual representation of the SID is of the form:
- * S-R-I-S-S...
- * Where:
- * - The first "S" is the literal character 'S' identifying the following
- * digits as a SID.
- * - R is the revision level of the SID expressed as a sequence of digits
- * in decimal.
- * - I is the 48-bit identifier_authority, expressed as digits in decimal,
- * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
- * - S... is one or more sub_authority values, expressed as digits in
- * decimal.
- *
- * Example SID; the domain-relative SID of the local Administrators group on
- * Windows NT/2k:
- * S-1-5-32-544
- * This translates to a SID with:
- * revision = 1,
- * sub_authority_count = 2,
- * identifier_authority = {0,0,0,0,0,5}, // SECURITY_NT_AUTHORITY
- * sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
- * sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u8 revision;
- u8 sub_authority_count;
- SID_IDENTIFIER_AUTHORITY identifier_authority;
- le32 sub_authority[1]; /* At least one sub_authority. */
-} __attribute__((__packed__)) SID;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum SID_CONSTANTS - Current constants for SIDs.
- */
-typedef enum {
- SID_REVISION = 1, /* Current revision level. */
- SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
- SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in
- a future revision. */
-} SID_CONSTANTS;
-
-/**
- * enum ACE_TYPES - The predefined ACE types (8-bit, see below).
- */
-#ifdef __sun
-typedef uint8_t ACE_TYPES;
-#define ACCESS_ALLOWED_ACE_TYPE (0)
-#define ACCESS_DENIED_ACE_TYPE (1)
-#define SYSTEM_AUDIT_ACE_TYPE (2)
-#else /* not __sun */
-typedef enum {
- ACCESS_MIN_MS_ACE_TYPE = 0,
- ACCESS_ALLOWED_ACE_TYPE = 0,
- ACCESS_DENIED_ACE_TYPE = 1,
- SYSTEM_AUDIT_ACE_TYPE = 2,
- SYSTEM_ALARM_ACE_TYPE = 3, /* Not implemented as of Win2k. */
- ACCESS_MAX_MS_V2_ACE_TYPE = 3,
-
- ACCESS_ALLOWED_COMPOUND_ACE_TYPE= 4,
- ACCESS_MAX_MS_V3_ACE_TYPE = 4,
-
- /* The following are Win2k only. */
- ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5,
- ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5,
- ACCESS_DENIED_OBJECT_ACE_TYPE = 6,
- SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7,
- SYSTEM_ALARM_OBJECT_ACE_TYPE = 8,
- ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8,
-
- ACCESS_MAX_MS_V4_ACE_TYPE = 8,
-
- /* This one is for WinNT&2k. */
- ACCESS_MAX_MS_ACE_TYPE = 8,
-} __attribute__((__packed__)) ACE_TYPES;
-#endif /* __sun */
-
-/**
- * enum ACE_FLAGS - The ACE flags (8-bit) for audit and inheritance.
- *
- * SUCCESSFUL_ACCESS_ACE_FLAG is only used with system audit and alarm ACE
- * types to indicate that a message is generated (in Windows!) for successful
- * accesses.
- *
- * FAILED_ACCESS_ACE_FLAG is only used with system audit and alarm ACE types
- * to indicate that a message is generated (in Windows!) for failed accesses.
- */
-#ifdef __sun
-typedef uint8_t ACE_FLAGS;
-#define OBJECT_INHERIT_ACE (0x01)
-#define CONTAINER_INHERIT_ACE (0x02)
-#define INHERIT_ONLY_ACE (0x08)
-#else /* not __sun */
-typedef enum {
- /* The inheritance flags. */
- OBJECT_INHERIT_ACE = 0x01,
- CONTAINER_INHERIT_ACE = 0x02,
- NO_PROPAGATE_INHERIT_ACE = 0x04,
- INHERIT_ONLY_ACE = 0x08,
- INHERITED_ACE = 0x10, /* Win2k only. */
- VALID_INHERIT_FLAGS = 0x1f,
-
- /* The audit flags. */
- SUCCESSFUL_ACCESS_ACE_FLAG = 0x40,
- FAILED_ACCESS_ACE_FLAG = 0x80,
-} __attribute__((__packed__)) ACE_FLAGS;
-#endif /* __sun */
-
-/**
- * struct ACE_HEADER -
- *
- * An ACE is an access-control entry in an access-control list (ACL).
- * An ACE defines access to an object for a specific user or group or defines
- * the types of access that generate system-administration messages or alarms
- * for a specific user or group. The user or group is identified by a security
- * identifier (SID).
- *
- * Each ACE starts with an ACE_HEADER structure (aligned on 4-byte boundary),
- * which specifies the type and size of the ACE. The format of the subsequent
- * data depends on the ACE type.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- ACE_TYPES type; /* Type of the ACE. */
- ACE_FLAGS flags; /* Flags describing the ACE. */
- le16 size; /* Size in bytes of the ACE. */
-} __attribute__((__packed__)) ACE_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum ACCESS_MASK - The access mask (32-bit).
- *
- * Defines the access rights.
- */
-typedef enum {
- /*
- * The specific rights (bits 0 to 15). Depend on the type of the
- * object being secured by the ACE.
- */
-
- /* Specific rights for files and directories are as follows: */
-
- /* Right to read data from the file. (FILE) */
- FILE_READ_DATA = const_cpu_to_le32(0x00000001),
- /* Right to list contents of a directory. (DIRECTORY) */
- FILE_LIST_DIRECTORY = const_cpu_to_le32(0x00000001),
-
- /* Right to write data to the file. (FILE) */
- FILE_WRITE_DATA = const_cpu_to_le32(0x00000002),
- /* Right to create a file in the directory. (DIRECTORY) */
- FILE_ADD_FILE = const_cpu_to_le32(0x00000002),
-
- /* Right to append data to the file. (FILE) */
- FILE_APPEND_DATA = const_cpu_to_le32(0x00000004),
- /* Right to create a subdirectory. (DIRECTORY) */
- FILE_ADD_SUBDIRECTORY = const_cpu_to_le32(0x00000004),
-
- /* Right to read extended attributes. (FILE/DIRECTORY) */
- FILE_READ_EA = const_cpu_to_le32(0x00000008),
-
- /* Right to write extended attributes. (FILE/DIRECTORY) */
- FILE_WRITE_EA = const_cpu_to_le32(0x00000010),
-
- /* Right to execute a file. (FILE) */
- FILE_EXECUTE = const_cpu_to_le32(0x00000020),
- /* Right to traverse the directory. (DIRECTORY) */
- FILE_TRAVERSE = const_cpu_to_le32(0x00000020),
-
- /*
- * Right to delete a directory and all the files it contains (its
- * children), even if the files are read-only. (DIRECTORY)
- */
- FILE_DELETE_CHILD = const_cpu_to_le32(0x00000040),
-
- /* Right to read file attributes. (FILE/DIRECTORY) */
- FILE_READ_ATTRIBUTES = const_cpu_to_le32(0x00000080),
-
- /* Right to change file attributes. (FILE/DIRECTORY) */
- FILE_WRITE_ATTRIBUTES = const_cpu_to_le32(0x00000100),
-
- /*
- * The standard rights (bits 16 to 23). Are independent of the type of
- * object being secured.
- */
-
- /* Right to delete the object. */
- DELETE = const_cpu_to_le32(0x00010000),
-
- /*
- * Right to read the information in the object's security descriptor,
- * not including the information in the SACL. I.e. right to read the
- * security descriptor and owner.
- */
- READ_CONTROL = const_cpu_to_le32(0x00020000),
-
- /* Right to modify the DACL in the object's security descriptor. */
- WRITE_DAC = const_cpu_to_le32(0x00040000),
-
- /* Right to change the owner in the object's security descriptor. */
- WRITE_OWNER = const_cpu_to_le32(0x00080000),
-
- /*
- * Right to use the object for synchronization. Enables a process to
- * wait until the object is in the signalled state. Some object types
- * do not support this access right.
- */
- SYNCHRONIZE = const_cpu_to_le32(0x00100000),
-
- /*
- * The following STANDARD_RIGHTS_* are combinations of the above for
- * convenience and are defined by the Win32 API.
- */
-
- /* These are currently defined to READ_CONTROL. */
- STANDARD_RIGHTS_READ = const_cpu_to_le32(0x00020000),
- STANDARD_RIGHTS_WRITE = const_cpu_to_le32(0x00020000),
- STANDARD_RIGHTS_EXECUTE = const_cpu_to_le32(0x00020000),
-
- /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */
- STANDARD_RIGHTS_REQUIRED = const_cpu_to_le32(0x000f0000),
-
- /*
- * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and
- * SYNCHRONIZE access.
- */
- STANDARD_RIGHTS_ALL = const_cpu_to_le32(0x001f0000),
-
- /*
- * The access system ACL and maximum allowed access types (bits 24 to
- * 25, bits 26 to 27 are reserved).
- */
- ACCESS_SYSTEM_SECURITY = const_cpu_to_le32(0x01000000),
- MAXIMUM_ALLOWED = const_cpu_to_le32(0x02000000),
-
- /*
- * The generic rights (bits 28 to 31). These map onto the standard and
- * specific rights.
- */
-
- /* Read, write, and execute access. */
- GENERIC_ALL = const_cpu_to_le32(0x10000000),
-
- /* Execute access. */
- GENERIC_EXECUTE = const_cpu_to_le32(0x20000000),
-
- /*
- * Write access. For files, this maps onto:
- * FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA |
- * FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE
- * For directories, the mapping has the same numerical value. See
- * above for the descriptions of the rights granted.
- */
- GENERIC_WRITE = const_cpu_to_le32(0x40000000),
-
- /*
- * Read access. For files, this maps onto:
- * FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA |
- * STANDARD_RIGHTS_READ | SYNCHRONIZE
- * For directories, the mapping has the same numerical value. See
- * above for the descriptions of the rights granted.
- */
- GENERIC_READ = const_cpu_to_le32(0x80000000),
-} ACCESS_MASK;
-
-/**
- * struct GENERIC_MAPPING -
- *
- * The generic mapping array. Used to denote the mapping of each generic
- * access right to a specific access mask.
- *
- * FIXME: What exactly is this and what is it for? (AIA)
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- ACCESS_MASK generic_read;
- ACCESS_MASK generic_write;
- ACCESS_MASK generic_execute;
- ACCESS_MASK generic_all;
-} __attribute__((__packed__)) GENERIC_MAPPING;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/*
- * The predefined ACE type structures are as defined below.
- */
-
-/**
- * struct ACCESS_DENIED_ACE -
- *
- * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
- ACE_TYPES type; /* Type of the ACE. */
- ACE_FLAGS flags; /* Flags describing the ACE. */
- le16 size; /* Size in bytes of the ACE. */
-
-/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
-/* 8*/ SID sid; /* The SID associated with the ACE. */
-} __attribute__((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE,
- SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum OBJECT_ACE_FLAGS - The object ACE flags (32-bit).
- */
-typedef enum {
- ACE_OBJECT_TYPE_PRESENT = const_cpu_to_le32(1),
- ACE_INHERITED_OBJECT_TYPE_PRESENT = const_cpu_to_le32(2),
-} OBJECT_ACE_FLAGS;
-
-/**
- * struct ACCESS_ALLOWED_OBJECT_ACE -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
- ACE_TYPES type; /* Type of the ACE. */
- ACE_FLAGS flags; /* Flags describing the ACE. */
- le16 size; /* Size in bytes of the ACE. */
-
-/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
-/* 8*/ OBJECT_ACE_FLAGS object_flags; /* Flags describing the object ACE. */
-/* 12*/ GUID object_type;
-/* 28*/ GUID inherited_object_type;
-/* 44*/ SID sid; /* The SID associated with the ACE. */
-} __attribute__((__packed__)) ACCESS_ALLOWED_OBJECT_ACE,
- ACCESS_DENIED_OBJECT_ACE,
- SYSTEM_AUDIT_OBJECT_ACE,
- SYSTEM_ALARM_OBJECT_ACE;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct ACL - An ACL is an access-control list (ACL).
- *
- * An ACL starts with an ACL header structure, which specifies the size of
- * the ACL and the number of ACEs it contains. The ACL header is followed by
- * zero or more access control entries (ACEs). The ACL as well as each ACE
- * are aligned on 4-byte boundaries.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u8 revision; /* Revision of this ACL. */
- u8 alignment1;
- le16 size; /* Allocated space in bytes for ACL. Includes this
- header, the ACEs and the remaining free space. */
- le16 ace_count; /* Number of ACEs in the ACL. */
- le16 alignment2;
-/* sizeof() = 8 bytes */
-} __attribute__((__packed__)) ACL;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum ACL_CONSTANTS - Current constants for ACLs.
- */
-typedef enum {
- /* Current revision. */
- ACL_REVISION = 2,
- ACL_REVISION_DS = 4,
-
- /* History of revisions. */
- ACL_REVISION1 = 1,
- MIN_ACL_REVISION = 2,
- ACL_REVISION2 = 2,
- ACL_REVISION3 = 3,
- ACL_REVISION4 = 4,
- MAX_ACL_REVISION = 4,
-} ACL_CONSTANTS;
-
-/**
- * enum SECURITY_DESCRIPTOR_CONTROL -
- *
- * The security descriptor control flags (16-bit).
- *
- * SE_OWNER_DEFAULTED - This boolean flag, when set, indicates that the
- * SID pointed to by the Owner field was provided by a
- * defaulting mechanism rather than explicitly provided by the
- * original provider of the security descriptor. This may
- * affect the treatment of the SID with respect to inheritance
- * of an owner.
- *
- * SE_GROUP_DEFAULTED - This boolean flag, when set, indicates that the
- * SID in the Group field was provided by a defaulting mechanism
- * rather than explicitly provided by the original provider of
- * the security descriptor. This may affect the treatment of
- * the SID with respect to inheritance of a primary group.
- *
- * SE_DACL_PRESENT - This boolean flag, when set, indicates that the
- * security descriptor contains a discretionary ACL. If this
- * flag is set and the Dacl field of the SECURITY_DESCRIPTOR is
- * null, then a null ACL is explicitly being specified.
- *
- * SE_DACL_DEFAULTED - This boolean flag, when set, indicates that the
- * ACL pointed to by the Dacl field was provided by a defaulting
- * mechanism rather than explicitly provided by the original
- * provider of the security descriptor. This may affect the
- * treatment of the ACL with respect to inheritance of an ACL.
- * This flag is ignored if the DaclPresent flag is not set.
- *
- * SE_SACL_PRESENT - This boolean flag, when set, indicates that the
- * security descriptor contains a system ACL pointed to by the
- * Sacl field. If this flag is set and the Sacl field of the
- * SECURITY_DESCRIPTOR is null, then an empty (but present)
- * ACL is being specified.
- *
- * SE_SACL_DEFAULTED - This boolean flag, when set, indicates that the
- * ACL pointed to by the Sacl field was provided by a defaulting
- * mechanism rather than explicitly provided by the original
- * provider of the security descriptor. This may affect the
- * treatment of the ACL with respect to inheritance of an ACL.
- * This flag is ignored if the SaclPresent flag is not set.
- *
- * SE_SELF_RELATIVE - This boolean flag, when set, indicates that the
- * security descriptor is in self-relative form. In this form,
- * all fields of the security descriptor are contiguous in memory
- * and all pointer fields are expressed as offsets from the
- * beginning of the security descriptor.
- */
-#ifdef __sun
-typedef uint16_t SECURITY_DESCRIPTOR_CONTROL;
-#define SE_DACL_PRESENT (const_cpu_to_le16(0x0004))
-#define SE_DACL_DEFAULTED (const_cpu_to_le16(0x0008))
-#define SE_SACL_PRESENT (const_cpu_to_le16(0x0010))
-#define SE_SACL_DEFAULTED (const_cpu_to_le16(0x0020))
-#define SE_SELF_RELATIVE (const_cpu_to_le16(0x8000))
-#else /* not __sun */
-typedef enum {
- SE_OWNER_DEFAULTED = const_cpu_to_le16(0x0001),
- SE_GROUP_DEFAULTED = const_cpu_to_le16(0x0002),
- SE_DACL_PRESENT = const_cpu_to_le16(0x0004),
- SE_DACL_DEFAULTED = const_cpu_to_le16(0x0008),
- SE_SACL_PRESENT = const_cpu_to_le16(0x0010),
- SE_SACL_DEFAULTED = const_cpu_to_le16(0x0020),
- SE_DACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0100),
- SE_SACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0200),
- SE_DACL_AUTO_INHERITED = const_cpu_to_le16(0x0400),
- SE_SACL_AUTO_INHERITED = const_cpu_to_le16(0x0800),
- SE_DACL_PROTECTED = const_cpu_to_le16(0x1000),
- SE_SACL_PROTECTED = const_cpu_to_le16(0x2000),
- SE_RM_CONTROL_VALID = const_cpu_to_le16(0x4000),
- SE_SELF_RELATIVE = const_cpu_to_le16(0x8000),
-} __attribute__((__packed__)) SECURITY_DESCRIPTOR_CONTROL;
-#endif /* __sun */
-
-/**
- * struct SECURITY_DESCRIPTOR_RELATIVE -
- *
- * Self-relative security descriptor. Contains the owner and group SIDs as well
- * as the sacl and dacl ACLs inside the security descriptor itself.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u8 revision; /* Revision level of the security descriptor. */
- u8 alignment;
- SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
- the descriptor as well as the following fields. */
- le32 owner; /* Byte offset to a SID representing an object's
- owner. If this is NULL, no owner SID is present in
- the descriptor. */
- le32 group; /* Byte offset to a SID representing an object's
- primary group. If this is NULL, no primary group
- SID is present in the descriptor. */
- le32 sacl; /* Byte offset to a system ACL. Only valid, if
- SE_SACL_PRESENT is set in the control field. If
- SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
- is specified. */
- le32 dacl; /* Byte offset to a discretionary ACL. Only valid, if
- SE_DACL_PRESENT is set in the control field. If
- SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
- (unconditionally granting access) is specified. */
-/* sizeof() = 0x14 bytes */
-} __attribute__((__packed__)) SECURITY_DESCRIPTOR_RELATIVE;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SECURITY_DESCRIPTOR - Absolute security descriptor.
- *
- * Does not contain the owner and group SIDs, nor the sacl and dacl ACLs inside
- * the security descriptor. Instead, it contains pointers to these structures
- * in memory. Obviously, absolute security descriptors are only useful for in
- * memory representations of security descriptors.
- *
- * On disk, a self-relative security descriptor is used.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u8 revision; /* Revision level of the security descriptor. */
- u8 alignment;
- SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
- the descriptor as well as the following fields. */
- SID *owner; /* Points to a SID representing an object's owner. If
- this is NULL, no owner SID is present in the
- descriptor. */
- SID *group; /* Points to a SID representing an object's primary
- group. If this is NULL, no primary group SID is
- present in the descriptor. */
- ACL *sacl; /* Points to a system ACL. Only valid, if
- SE_SACL_PRESENT is set in the control field. If
- SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
- is specified. */
- ACL *dacl; /* Points to a discretionary ACL. Only valid, if
- SE_DACL_PRESENT is set in the control field. If
- SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
- (unconditionally granting access) is specified. */
-} __attribute__((__packed__)) SECURITY_DESCRIPTOR;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum SECURITY_DESCRIPTOR_CONSTANTS -
- *
- * Current constants for security descriptors.
- */
-typedef enum {
- /* Current revision. */
- SECURITY_DESCRIPTOR_REVISION = 1,
- SECURITY_DESCRIPTOR_REVISION1 = 1,
-
- /* The sizes of both the absolute and relative security descriptors is
- the same as pointers, at least on ia32 architecture are 32-bit. */
- SECURITY_DESCRIPTOR_MIN_LENGTH = sizeof(SECURITY_DESCRIPTOR),
-} SECURITY_DESCRIPTOR_CONSTANTS;
-
-/*
- * Attribute: Security descriptor (0x50).
- *
- * A standard self-relative security descriptor.
- *
- * NOTE: Can be resident or non-resident.
- * NOTE: Not used in NTFS 3.0+, as security descriptors are stored centrally
- * in FILE_Secure and the correct descriptor is found using the security_id
- * from the standard information attribute.
- */
-typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
-
-/*
- * On NTFS 3.0+, all security descriptors are stored in FILE_Secure. Only one
- * referenced instance of each unique security descriptor is stored.
- *
- * FILE_Secure contains no unnamed data attribute, i.e. it has zero length. It
- * does, however, contain two indexes ($SDH and $SII) as well as a named data
- * stream ($SDS).
- *
- * Every unique security descriptor is assigned a unique security identifier
- * (security_id, not to be confused with a SID). The security_id is unique for
- * the NTFS volume and is used as an index into the $SII index, which maps
- * security_ids to the security descriptor's storage location within the $SDS
- * data attribute. The $SII index is sorted by ascending security_id.
- *
- * A simple hash is computed from each security descriptor. This hash is used
- * as an index into the $SDH index, which maps security descriptor hashes to
- * the security descriptor's storage location within the $SDS data attribute.
- * The $SDH index is sorted by security descriptor hash and is stored in a B+
- * tree. When searching $SDH (with the intent of determining whether or not a
- * new security descriptor is already present in the $SDS data stream), if a
- * matching hash is found, but the security descriptors do not match, the
- * search in the $SDH index is continued, searching for a next matching hash.
- *
- * When a precise match is found, the security_id corresponding to the security
- * descriptor in the $SDS attribute is read from the found $SDH index entry and
- * is stored in the $STANDARD_INFORMATION attribute of the file/directory to
- * which the security descriptor is being applied. The $STANDARD_INFORMATION
- * attribute is present in all base mft records (i.e. in all files and
- * directories).
- *
- * If a match is not found, the security descriptor is assigned a new unique
- * security_id and is added to the $SDS data attribute. Then, entries
- * referencing the this security descriptor in the $SDS data attribute are
- * added to the $SDH and $SII indexes.
- *
- * Note: Entries are never deleted from FILE_Secure, even if nothing
- * references an entry any more.
- */
-
-/**
- * struct SECURITY_DESCRIPTOR_HEADER -
- *
- * This header precedes each security descriptor in the $SDS data stream.
- * This is also the index entry data part of both the $SII and $SDH indexes.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
- le64 offset; /* Byte offset of this entry in the $SDS stream. */
- le32 length; /* Size in bytes of this entry in $SDS stream. */
-} __attribute__((__packed__)) SECURITY_DESCRIPTOR_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SDH_INDEX_DATA -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
- le64 offset; /* Byte offset of this entry in the $SDS stream. */
- le32 length; /* Size in bytes of this entry in $SDS stream. */
- le32 reserved_II; /* Padding - always unicode "II" or zero. This field
- isn't counted in INDEX_ENTRY's data_length. */
-} __attribute__((__packed__)) SDH_INDEX_DATA;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SII_INDEX_DATA -
- */
-typedef SECURITY_DESCRIPTOR_HEADER SII_INDEX_DATA;
-
-/**
- * struct SDS_ENTRY -
- *
- * The $SDS data stream contains the security descriptors, aligned on 16-byte
- * boundaries, sorted by security_id in a B+ tree. Security descriptors cannot
- * cross 256kib boundaries (this restriction is imposed by the Windows cache
- * manager). Each security descriptor is contained in a SDS_ENTRY structure.
- * Also, each security descriptor is stored twice in the $SDS stream with a
- * fixed offset of 0x40000 bytes (256kib, the Windows cache manager's max size)
- * between them; i.e. if a SDS_ENTRY specifies an offset of 0x51d0, then the
- * the first copy of the security descriptor will be at offset 0x51d0 in the
- * $SDS data stream and the second copy will be at offset 0x451d0.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
- unnamed structs. */
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
- le64 offset; /* Byte offset of this entry in the $SDS stream. */
- le32 length; /* Size in bytes of this entry in $SDS stream. */
-/* 20*/ SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security
- descriptor. */
-} __attribute__((__packed__)) SDS_ENTRY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SII_INDEX_KEY - The index entry key used in the $SII index.
- *
- * The collation type is COLLATION_NTOFS_ULONG.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__((__packed__)) SII_INDEX_KEY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct SDH_INDEX_KEY - The index entry key used in the $SDH index.
- *
- * The keys are sorted first by hash and then by security_id.
- * The collation rule is COLLATION_NTOFS_SECURITY_HASH.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__((__packed__)) SDH_INDEX_KEY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#ifndef __sun
-/**
- * struct VOLUME_NAME - Attribute: Volume name (0x60).
- *
- * NOTE: Always resident.
- * NOTE: Present only in FILE_Volume.
- */
-typedef struct {
- ntfschar name[]; /* The name of the volume in Unicode. */
-} __attribute__((__packed__)) VOLUME_NAME;
-#endif
-
-/**
- * enum VOLUME_FLAGS - Possible flags for the volume (16-bit).
- *
- * WARNING: Setting VOLUME_MOUNTED_ON_NT4 on a Volume causes Windows Vista to
- * fail to boot (it hangs on a black screen).
- */
-#ifdef __sun
-typedef uint16_t VOLUME_FLAGS;
-#define VOLUME_IS_DIRTY (const_cpu_to_le16(0x0001))
-#define VOLUME_RESIZE_LOG_FILE (const_cpu_to_le16(0x0002))
-#define VOLUME_UPGRADE_ON_MOUNT (const_cpu_to_le16(0x0004))
-#define VOLUME_MOUNTED_ON_NT4 (const_cpu_to_le16(0x0008))
-#define VOLUME_DELETE_USN_UNDERWAY (const_cpu_to_le16(0x0010))
-#define VOLUME_REPAIR_OBJECT_ID (const_cpu_to_le16(0x0020))
-#define VOLUME_CHKDSK_UNDERWAY (const_cpu_to_le16(0x4000))
-#define VOLUME_MODIFIED_BY_CHKDSK (const_cpu_to_le16(0x8000))
-#define VOLUME_FLAGS_MASK (const_cpu_to_le16(0xc03f))
-#else /* not __sun */
-typedef enum {
- VOLUME_IS_DIRTY = const_cpu_to_le16(0x0001),
- VOLUME_RESIZE_LOG_FILE = const_cpu_to_le16(0x0002),
- VOLUME_UPGRADE_ON_MOUNT = const_cpu_to_le16(0x0004),
- VOLUME_MOUNTED_ON_NT4 = const_cpu_to_le16(0x0008),
- VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010),
- VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020),
- VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000),
- VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000),
- VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f),
-} __attribute__((__packed__)) VOLUME_FLAGS;
-#endif /* __sun */
-
-/**
- * struct VOLUME_INFORMATION - Attribute: Volume information (0x70).
- *
- * NOTE: Always resident.
- * NOTE: Present only in FILE_Volume.
- * NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
- * NTFS 1.2. I haven't personally seen other values yet.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le64 reserved; /* Not used (yet?). */
- u8 major_ver; /* Major version of the ntfs format. */
- u8 minor_ver; /* Minor version of the ntfs format. */
- VOLUME_FLAGS flags; /* Bit array of VOLUME_* flags. */
-} __attribute__((__packed__)) VOLUME_INFORMATION;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#ifndef __sun
-/**
- * struct DATA_ATTR - Attribute: Data attribute (0x80).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Data contents of a file (i.e. the unnamed stream) or of a named stream.
- */
-typedef struct {
- u8 data[]; /* The file's data contents. */
-} __attribute__((__packed__)) DATA_ATTR;
-#endif
-
-/**
- * enum INDEX_HEADER_FLAGS - Index header flags (8-bit).
- */
-#ifdef __sun
-typedef uint8_t INDEX_HEADER_FLAGS;
-#define SMALL_INDEX (0)
-#define LARGE_INDEX (1)
-#define LEAF_NODE (0)
-#define INDEX_NODE (1)
-#define NODE_MASK (1)
-#else /* not __sun */
-typedef enum {
- /* When index header is in an index root attribute: */
- SMALL_INDEX = 0, /* The index is small enough to fit inside the
- index root attribute and there is no index
- allocation attribute present. */
- LARGE_INDEX = 1, /* The index is too large to fit in the index
- root attribute and/or an index allocation
- attribute is present. */
- /*
- * When index header is in an index block, i.e. is part of index
- * allocation attribute:
- */
- LEAF_NODE = 0, /* This is a leaf node, i.e. there are no more
- nodes branching off it. */
- INDEX_NODE = 1, /* This node indexes other nodes, i.e. is not a
- leaf node. */
- NODE_MASK = 1, /* Mask for accessing the *_NODE bits. */
-} __attribute__((__packed__)) INDEX_HEADER_FLAGS;
-#endif /* __sun */
-
-/**
- * struct INDEX_HEADER -
- *
- * This is the header for indexes, describing the INDEX_ENTRY records, which
- * follow the INDEX_HEADER. Together the index header and the index entries
- * make up a complete index.
- *
- * IMPORTANT NOTE: The offset, length and size structure members are counted
- * relative to the start of the index header structure and not relative to the
- * start of the index root or index allocation structures themselves.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 entries_offset; /* Byte offset to first INDEX_ENTRY
- aligned to 8-byte boundary. */
- le32 index_length; /* Data size of the index in bytes,
- i.e. bytes used from allocated
- size, aligned to 8-byte boundary. */
- le32 allocated_size; /* Byte size of this index (block),
- multiple of 8 bytes. */
- /* NOTE: For the index root attribute, the above two numbers are always
- equal, as the attribute is resident and it is resized as needed. In
- the case of the index allocation attribute the attribute is not
- resident and hence the allocated_size is a fixed value and must
- equal the index_block_size specified by the INDEX_ROOT attribute
- corresponding to the INDEX_ALLOCATION attribute this INDEX_BLOCK
- belongs to. */
- INDEX_HEADER_FLAGS flags; /* Bit field of INDEX_HEADER_FLAGS. */
- u8 reserved[3]; /* Reserved/align to 8-byte boundary. */
-} __attribute__((__packed__)) INDEX_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct INDEX_ROOT - Attribute: Index root (0x90).
- *
- * NOTE: Always resident.
- *
- * This is followed by a sequence of index entries (INDEX_ENTRY structures)
- * as described by the index header.
- *
- * When a directory is small enough to fit inside the index root then this
- * is the only attribute describing the directory. When the directory is too
- * large to fit in the index root, on the other hand, two additional attributes
- * are present: an index allocation attribute, containing sub-nodes of the B+
- * directory tree (see below), and a bitmap attribute, describing which virtual
- * cluster numbers (VCNs) in the index allocation attribute are in use by an
- * index block.
- *
- * NOTE: The root directory (FILE_root) contains an entry for itself. Other
- * directories do not contain entries for themselves, though.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- ATTR_TYPES type; /* Type of the indexed attribute. Is
- $FILE_NAME for directories, zero
- for view indexes. No other values
- allowed. */
- COLLATION_RULES collation_rule; /* Collation rule used to sort the
- index entries. If type is $FILE_NAME,
- this must be COLLATION_FILE_NAME. */
- le32 index_block_size; /* Size of each index block in bytes (in
- the index allocation attribute). */
- u8 clusters_per_index_block; /* Cluster size of each index block (in
- the index allocation attribute), when
- an index block is >= than a cluster,
- otherwise sectors per index block. */
- u8 reserved[3]; /* Reserved/align to 8-byte boundary. */
- INDEX_HEADER index; /* Index header describing the
- following index entries. */
-} __attribute__((__packed__)) INDEX_ROOT;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct INDEX_BLOCK - Attribute: Index allocation (0xa0).
- *
- * NOTE: Always non-resident (doesn't make sense to be resident anyway!).
- *
- * This is an array of index blocks. Each index block starts with an
- * INDEX_BLOCK structure containing an index header, followed by a sequence of
- * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
- le16 usa_ofs; /* See NTFS_RECORD definition. */
- le16 usa_count; /* See NTFS_RECORD definition. */
-
-/* 8*/ leLSN lsn; /* $LogFile sequence number of the last
- modification of this index block. */
-/* 16*/ leVCN index_block_vcn; /* Virtual cluster number of the index block. */
-/* 24*/ INDEX_HEADER index; /* Describes the following index entries. */
-/* sizeof()= 40 (0x28) bytes */
-/*
- * When creating the index block, we place the update sequence array at this
- * offset, i.e. before we start with the index entries. This also makes sense,
- * otherwise we could run into problems with the update sequence array
- * containing in itself the last two bytes of a sector which would mean that
- * multi sector transfer protection wouldn't work. As you can't protect data
- * by overwriting it since you then can't get it back...
- * When reading use the data from the ntfs record header.
- */
-} __attribute__((__packed__)) INDEX_BLOCK;
-#ifdef __sun
-#pragma pack()
-#endif
-
-typedef INDEX_BLOCK INDEX_ALLOCATION;
-
-/**
- * struct REPARSE_INDEX_KEY -
- *
- * The system file FILE_Extend/$Reparse contains an index named $R listing
- * all reparse points on the volume. The index entry keys are as defined
- * below. Note, that there is no index data associated with the index entries.
- *
- * The index entries are sorted by the index key file_id. The collation rule is
- * COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
- * primary key / is not a key at all. (AIA)
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 reparse_tag; /* Reparse point type (inc. flags). */
- leMFT_REF file_id; /* Mft record of the file containing the
- reparse point attribute. */
-} __attribute__((__packed__)) REPARSE_INDEX_KEY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum QUOTA_FLAGS - Quota flags (32-bit).
- */
-typedef enum {
- /* The user quota flags. Names explain meaning. */
- QUOTA_FLAG_DEFAULT_LIMITS = const_cpu_to_le32(0x00000001),
- QUOTA_FLAG_LIMIT_REACHED = const_cpu_to_le32(0x00000002),
- QUOTA_FLAG_ID_DELETED = const_cpu_to_le32(0x00000004),
-
- QUOTA_FLAG_USER_MASK = const_cpu_to_le32(0x00000007),
- /* Bit mask for user quota flags. */
-
- /* These flags are only present in the quota defaults index entry,
- i.e. in the entry where owner_id = QUOTA_DEFAULTS_ID. */
- QUOTA_FLAG_TRACKING_ENABLED = const_cpu_to_le32(0x00000010),
- QUOTA_FLAG_ENFORCEMENT_ENABLED = const_cpu_to_le32(0x00000020),
- QUOTA_FLAG_TRACKING_REQUESTED = const_cpu_to_le32(0x00000040),
- QUOTA_FLAG_LOG_THRESHOLD = const_cpu_to_le32(0x00000080),
- QUOTA_FLAG_LOG_LIMIT = const_cpu_to_le32(0x00000100),
- QUOTA_FLAG_OUT_OF_DATE = const_cpu_to_le32(0x00000200),
- QUOTA_FLAG_CORRUPT = const_cpu_to_le32(0x00000400),
- QUOTA_FLAG_PENDING_DELETES = const_cpu_to_le32(0x00000800),
-} QUOTA_FLAGS;
-
-/**
- * struct QUOTA_CONTROL_ENTRY -
- *
- * The system file FILE_Extend/$Quota contains two indexes $O and $Q. Quotas
- * are on a per volume and per user basis.
- *
- * The $Q index contains one entry for each existing user_id on the volume. The
- * index key is the user_id of the user/group owning this quota control entry,
- * i.e. the key is the owner_id. The user_id of the owner of a file, i.e. the
- * owner_id, is found in the standard information attribute. The collation rule
- * for $Q is COLLATION_NTOFS_ULONG.
- *
- * The $O index contains one entry for each user/group who has been assigned
- * a quota on that volume. The index key holds the SID of the user_id the
- * entry belongs to, i.e. the owner_id. The collation rule for $O is
- * COLLATION_NTOFS_SID.
- *
- * The $O index entry data is the user_id of the user corresponding to the SID.
- * This user_id is used as an index into $Q to find the quota control entry
- * associated with the SID.
- *
- * The $Q index entry data is the quota control entry and is defined below.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 version; /* Currently equals 2. */
- QUOTA_FLAGS flags; /* Flags describing this quota entry. */
- le64 bytes_used; /* How many bytes of the quota are in use. */
- sle64 change_time; /* Last time this quota entry was changed. */
- sle64 threshold; /* Soft quota (-1 if not limited). */
- sle64 limit; /* Hard quota (-1 if not limited). */
- sle64 exceeded_time; /* How long the soft quota has been exceeded. */
-/* The below field is NOT present for the quota defaults entry. */
- SID sid; /* The SID of the user/object associated with
- this quota entry. If this field is missing
- then the INDEX_ENTRY is padded with zeros
- to multiply of 8 which are not counted in
- the data_length field. If the SID is present
- then this structure is padded with zeros to
- multiply of 8 and the padding is counted in
- the INDEX_ENTRY's data_length. */
-} __attribute__((__packed__)) QUOTA_CONTROL_ENTRY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct QUOTA_O_INDEX_DATA -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 owner_id;
- le32 unknown; /* Always 32. Seems to be padding and it's not
- counted in the INDEX_ENTRY's data_length.
- This field shouldn't be really here. */
-} __attribute__((__packed__)) QUOTA_O_INDEX_DATA;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum PREDEFINED_OWNER_IDS - Predefined owner_id values (32-bit).
- */
-typedef enum {
- QUOTA_INVALID_ID = const_cpu_to_le32(0x00000000),
- QUOTA_DEFAULTS_ID = const_cpu_to_le32(0x00000001),
- QUOTA_FIRST_USER_ID = const_cpu_to_le32(0x00000100),
-} PREDEFINED_OWNER_IDS;
-
-/**
- * enum INDEX_ENTRY_FLAGS - Index entry flags (16-bit).
- */
-#ifdef __sun
-typedef uint16_t INDEX_ENTRY_FLAGS;
-#define INDEX_ENTRY_NODE (const_cpu_to_le16(1))
-#define INDEX_ENTRY_END (const_cpu_to_le16(2))
-#else /* not __sun */
-typedef enum {
- INDEX_ENTRY_NODE = const_cpu_to_le16(1), /* This entry contains a
- sub-node, i.e. a reference to an index
- block in form of a virtual cluster
- number (see below). */
- INDEX_ENTRY_END = const_cpu_to_le16(2), /* This signifies the last
- entry in an index block. The index
- entry does not represent a file but it
- can point to a sub-node. */
- INDEX_ENTRY_SPACE_FILLER = const_cpu_to_le16(0xffff),
- /* Just to force 16-bit width. */
-} __attribute__((__packed__)) INDEX_ENTRY_FLAGS;
-#endif /* __sun */
-
-/**
- * struct INDEX_ENTRY_HEADER - This the index entry header (see below).
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0*/ union { /* Only valid when INDEX_ENTRY_END is not set. */
- leMFT_REF indexed_file; /* The mft reference of the file
- described by this index
- entry. Used for directory
- indexes. */
- struct { /* Used for views/indexes to find the entry's data. */
- le16 data_offset; /* Data byte offset from this
- INDEX_ENTRY. Follows the
- index key. */
- le16 data_length; /* Data length in bytes. */
- le32 reservedV; /* Reserved (zero). */
- } __attribute__((__packed__)) s;
- } __attribute__((__packed__)) u;
-/* 8*/ le16 length; /* Byte size of this index entry, multiple of
- 8-bytes. */
-/* 10*/ le16 key_length; /* Byte size of the key value, which is in the
- index entry. It follows field reserved. Not
- multiple of 8-bytes. */
-/* 12*/ INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
-/* 14*/ le16 reserved; /* Reserved/align to 8-byte boundary. */
-/* sizeof() = 16 bytes */
-} __attribute__((__packed__)) INDEX_ENTRY_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct INDEX_ENTRY - This is an index entry.
- *
- * A sequence of such entries follows each INDEX_HEADER structure. Together
- * they make up a complete index. The index follows either an index root
- * attribute or an index allocation attribute.
- *
- * NOTE: Before NTFS 3.0 only filename attributes were indexed.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
- union { /* Only valid when INDEX_ENTRY_END is not set. */
- leMFT_REF indexed_file; /* The mft reference of the file
- described by this index
- entry. Used for directory
- indexes. */
- struct { /* Used for views/indexes to find the entry's data. */
- le16 data_offset; /* Data byte offset from this
- INDEX_ENTRY. Follows the
- index key. */
- le16 data_length; /* Data length in bytes. */
- le32 reservedV; /* Reserved (zero). */
- } __attribute__((__packed__)) s;
- } __attribute__((__packed__)) u;
- le16 length; /* Byte size of this index entry, multiple of
- 8-bytes. */
- le16 key_length; /* Byte size of the key value, which is in the
- index entry. It follows field reserved. Not
- multiple of 8-bytes. */
- INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
- le16 reserved; /* Reserved/align to 8-byte boundary. */
-
-/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present
- if INDEX_ENTRY_END bit in flags is not set. NOTE: On
- NTFS versions before 3.0 the only valid key is the
- FILE_NAME_ATTR. On NTFS 3.0+ the following
- additional index keys are defined: */
- FILE_NAME_ATTR file_name;/* $I30 index in directories. */
- SII_INDEX_KEY sii; /* $SII index in $Secure. */
- SDH_INDEX_KEY sdh; /* $SDH index in $Secure. */
- GUID object_id; /* $O index in FILE_Extend/$ObjId: The
- object_id of the mft record found in
- the data part of the index. */
- REPARSE_INDEX_KEY reparse; /* $R index in
- FILE_Extend/$Reparse. */
- SID sid; /* $O index in FILE_Extend/$Quota:
- SID of the owner of the user_id. */
- le32 owner_id; /* $Q index in FILE_Extend/$Quota:
- user_id of the owner of the quota
- control entry in the data part of
- the index. */
- } __attribute__((__packed__)) key;
- /* The (optional) index data is inserted here when creating. */
- /* VCN vcn; */ /* If INDEX_ENTRY_NODE bit in flags is set, the last
- eight bytes of this index entry contain the virtual
- cluster number of the index block that holds the
- entries immediately preceding the current entry (the
- vcn references the corresponding cluster in the data
- of the non-resident index allocation attribute). If
- the key_length is zero, then the vcn immediately
- follows the INDEX_ENTRY_HEADER. Regardless of
- key_length, the address of the 8-byte boundary
- aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by
- (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN),
- where sizeof(VCN) can be hardcoded as 8 if wanted. */
-} __attribute__((__packed__)) INDEX_ENTRY;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#ifndef __sun
-/**
- * struct BITMAP_ATTR - Attribute: Bitmap (0xb0).
- *
- * Contains an array of bits (aka a bitfield).
- *
- * When used in conjunction with the index allocation attribute, each bit
- * corresponds to one index block within the index allocation attribute. Thus
- * the number of bits in the bitmap * index block size / cluster size is the
- * number of clusters in the index allocation attribute.
- */
-typedef struct {
- u8 bitmap[]; /* Array of bits. */
-} __attribute__((__packed__)) BITMAP_ATTR;
-#endif
-
-/**
- * enum PREDEFINED_REPARSE_TAGS -
- *
- * The reparse point tag defines the type of the reparse point. It also
- * includes several flags, which further describe the reparse point.
- *
- * The reparse point tag is an unsigned 32-bit value divided in three parts:
- *
- * 1. The least significant 16 bits (i.e. bits 0 to 15) specify the type of
- * the reparse point.
- * 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use.
- * 3. The most significant three bits are flags describing the reparse point.
- * They are defined as follows:
- * bit 29: Name surrogate bit. If set, the filename is an alias for
- * another object in the system.
- * bit 30: High-latency bit. If set, accessing the first byte of data will
- * be slow. (E.g. the data is stored on a tape drive.)
- * bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
- * defined tags have to use zero here.
- */
-typedef enum {
- IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32(0x20000000),
- IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32(0x40000000),
- IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32(0x80000000),
-
- IO_REPARSE_TAG_RESERVED_ZERO = const_cpu_to_le32(0x00000000),
- IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001),
- IO_REPARSE_TAG_RESERVED_RANGE = const_cpu_to_le32(0x00000001),
-
- IO_REPARSE_TAG_NSS = const_cpu_to_le32(0x68000005),
- IO_REPARSE_TAG_NSS_RECOVER = const_cpu_to_le32(0x68000006),
- IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x68000007),
- IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x68000008),
-
- IO_REPARSE_TAG_MOUNT_POINT = const_cpu_to_le32(0x88000003),
-
- IO_REPARSE_TAG_HSM = const_cpu_to_le32(0xa8000004),
-
- IO_REPARSE_TAG_SYMBOLIC_LINK = const_cpu_to_le32(0xe8000000),
-
- IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xe000ffff),
-} PREDEFINED_REPARSE_TAGS;
-
-/**
- * struct REPARSE_POINT - Attribute: Reparse point (0xc0).
- *
- * NOTE: Can be resident or non-resident.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 reparse_tag; /* Reparse point type (inc. flags). */
- le16 reparse_data_length; /* Byte size of reparse data. */
- le16 reserved; /* Align to 8-byte boundary. */
- u8 reparse_data[]; /* Meaning depends on reparse_tag. */
-} __attribute__((__packed__)) REPARSE_POINT;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct EA_INFORMATION - Attribute: Extended attribute information (0xd0).
- *
- * NOTE: Always resident.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le16 ea_length; /* Byte size of the packed extended
- attributes. */
- le16 need_ea_count; /* The number of extended attributes which have
- the NEED_EA bit set. */
- le32 ea_query_length; /* Byte size of the buffer required to query
- the extended attributes when calling
- ZwQueryEaFile() in Windows NT/2k. I.e. the
- byte size of the unpacked extended
- attributes. */
-} __attribute__((__packed__)) EA_INFORMATION;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#ifdef __sun
-typedef uint8_t EA_FLAGS;
-#define NEED_EA (0x80)
-#else /* not __sun */
-/**
- * enum EA_FLAGS - Extended attribute flags (8-bit).
- */
-typedef enum {
- NEED_EA = 0x80, /* Indicate that the file to which the EA
- belongs cannot be interpreted without
- understanding the associated extended
- attributes. */
-} __attribute__((__packed__)) EA_FLAGS;
-#endif /* __sun */
-
-/**
- * struct EA_ATTR - Attribute: Extended attribute (EA) (0xe0).
- *
- * Like the attribute list and the index buffer list, the EA attribute value is
- * a sequence of EA_ATTR variable length records.
- *
- * FIXME: It appears weird that the EA name is not Unicode. Is it true?
- * FIXME: It seems that name is always uppercased. Is it true?
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 next_entry_offset; /* Offset to the next EA_ATTR. */
- EA_FLAGS flags; /* Flags describing the EA. */
- u8 name_length; /* Length of the name of the extended
- attribute in bytes. */
- le16 value_length; /* Byte size of the EA's value. */
- u8 name[]; /* Name of the EA. */
-#ifndef __sun
- u8 value[]; /* The value of the EA. Immediately
- follows the name. */
-#endif
-} __attribute__((__packed__)) EA_ATTR;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#ifndef __sun
-/**
- * struct PROPERTY_SET - Attribute: Property set (0xf0).
- *
- * Intended to support Native Structure Storage (NSS) - a feature removed from
- * NTFS 3.0 during beta testing.
- */
-typedef struct {
- /* Irrelevant as feature unused. */
-} __attribute__((__packed__)) PROPERTY_SET;
-#endif
-
-#ifndef __sun
-/**
- * struct LOGGED_UTILITY_STREAM - Attribute: Logged utility stream (0x100).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Operations on this attribute are logged to the journal ($LogFile) like
- * normal metadata changes.
- *
- * Used by the Encrypting File System (EFS). All encrypted files have this
- * attribute with the name $EFS. See below for the relevant structures.
- */
-typedef struct {
- /* Can be anything the creator chooses. */
-} __attribute__((__packed__)) LOGGED_UTILITY_STREAM;
-#endif
-
-/*
- * $EFS Data Structure:
- *
- * The following information is about the data structures that are contained
- * inside a logged utility stream (0x100) with a name of "$EFS".
- *
- * The stream starts with an instance of EFS_ATTR_HEADER.
- *
- * Next, at offsets offset_to_ddf_array and offset_to_drf_array (unless any of
- * them is 0) there is a EFS_DF_ARRAY_HEADER immediately followed by a sequence
- * of multiple data decryption/recovery fields.
- *
- * Each data decryption/recovery field starts with a EFS_DF_HEADER and the next
- * one (if it exists) can be found by adding EFS_DF_HEADER->df_length bytes to
- * the offset of the beginning of the current EFS_DF_HEADER.
- *
- * The data decryption/recovery field contains an EFS_DF_CERTIFICATE_HEADER, a
- * SID, an optional GUID, an optional container name, a non-optional user name,
- * and the encrypted FEK.
- *
- * Note all the below are best guesses so may have mistakes/inaccuracies.
- * Corrections/clarifications/additions are always welcome!
- *
- * Ntfs.sys takes an EFS value length of <= 0x54 or > 0x40000 to BSOD, i.e. it
- * is invalid.
- */
-
-/**
- * struct EFS_ATTR_HEADER - "$EFS" header.
- *
- * The header of the Logged utility stream (0x100) attribute named "$EFS".
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0*/ le32 length; /* Length of EFS attribute in bytes. */
- le32 state; /* Always 0? */
- le32 version; /* Efs version. Always 2? */
- le32 crypto_api_version; /* Always 0? */
-/* 16*/ u8 unknown4[16]; /* MD5 hash of decrypted FEK? This field is
- created with a call to UuidCreate() so is
- unlikely to be an MD5 hash and is more
- likely to be GUID of this encrytped file
- or something like that. */
-/* 32*/ u8 unknown5[16]; /* MD5 hash of DDFs? */
-/* 48*/ u8 unknown6[16]; /* MD5 hash of DRFs? */
-/* 64*/ le32 offset_to_ddf_array;/* Offset in bytes to the array of data
- decryption fields (DDF), see below. Zero if
- no DDFs are present. */
- le32 offset_to_drf_array;/* Offset in bytes to the array of data
- recovery fields (DRF), see below. Zero if
- no DRFs are present. */
- le32 reserved; /* Reserved. */
-} __attribute__((__packed__)) EFS_ATTR_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct EFS_DF_ARRAY_HEADER -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- le32 df_count; /* Number of data decryption/recovery fields in
- the array. */
-} __attribute__((__packed__)) EFS_DF_ARRAY_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct EFS_DF_HEADER -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0*/ le32 df_length; /* Length of this data decryption/recovery
- field in bytes. */
- le32 cred_header_offset;/* Offset in bytes to the credential header. */
- le32 fek_size; /* Size in bytes of the encrypted file
- encryption key (FEK). */
- le32 fek_offset; /* Offset in bytes to the FEK from the start of
- the data decryption/recovery field. */
-/* 16*/ le32 unknown1; /* always 0? Might be just padding. */
-} __attribute__((__packed__)) EFS_DF_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct EFS_DF_CREDENTIAL_HEADER -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0*/ le32 cred_length; /* Length of this credential in bytes. */
- le32 sid_offset; /* Offset in bytes to the user's sid from start
- of this structure. Zero if no sid is
- present. */
-/* 8*/ le32 type; /* Type of this credential:
- 1 = CryptoAPI container.
- 2 = Unexpected type.
- 3 = Certificate thumbprint.
- other = Unknown type. */
- union {
- /* CryptoAPI container. */
- struct {
-/* 12*/ le32 container_name_offset; /* Offset in bytes to
- the name of the container from start of this
- structure (may not be zero). */
-/* 16*/ le32 provider_name_offset; /* Offset in bytes to
- the name of the provider from start of this
- structure (may not be zero). */
- le32 public_key_blob_offset; /* Offset in bytes to
- the public key blob from start of this
- structure. */
-/* 24*/ le32 public_key_blob_size; /* Size in bytes of
- public key blob. */
- } __attribute__((__packed__)) crypt;
- /* Certificate thumbprint. */
- struct {
-/* 12*/ le32 cert_thumbprint_header_size; /* Size in
- bytes of the header of the certificate
- thumbprint. */
-/* 16*/ le32 cert_thumbprint_header_offset; /* Offset in
- bytes to the header of the certificate
- thumbprint from start of this structure. */
- le32 unknown1; /* Always 0? Might be padding... */
- le32 unknown2; /* Always 0? Might be padding... */
- } __attribute__((__packed__)) cert;
- } __attribute__((__packed__)) u;
-} __attribute__((__packed__)) EFS_DF_CREDENTIAL_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER;
-
-/**
- * struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER -
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0*/ le32 thumbprint_offset; /* Offset in bytes to the thumbprint. */
- le32 thumbprint_size; /* Size of thumbprint in bytes. */
-/* 8*/ le32 container_name_offset; /* Offset in bytes to the name of the
- container from start of this
- structure or 0 if no name present. */
- le32 provider_name_offset; /* Offset in bytes to the name of the
- cryptographic provider from start of
- this structure or 0 if no name
- present. */
-/* 16*/ le32 user_name_offset; /* Offset in bytes to the user name
- from start of this structure or 0 if
- no user name present. (This is also
- known as lpDisplayInformation.) */
-} __attribute__((__packed__)) EFS_DF_CERTIFICATE_THUMBPRINT_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-typedef EFS_DF_CERTIFICATE_THUMBPRINT_HEADER EFS_DF_CERT_THUMBPRINT_HEADER;
-
-#ifdef __sun
-typedef uint64_t INTX_FILE_TYPES;
-#define INTX_SYMBOLIC_LINK (const_cpu_to_le64(0x014B4E4C78746E49ULL))
-#define INTX_CHARACTER_DEVICE (const_cpu_to_le64(0x0052484378746E49ULL))
-#define INTX_BLOCK_DEVICE (const_cpu_to_le64(0x004B4C4278746E49ULL))
-#else /* not __sun */
-typedef enum {
- INTX_SYMBOLIC_LINK =
- const_cpu_to_le64(0x014B4E4C78746E49ULL), /* "IntxLNK\1" */
- INTX_CHARACTER_DEVICE =
- const_cpu_to_le64(0x0052484378746E49ULL), /* "IntxCHR\0" */
- INTX_BLOCK_DEVICE =
- const_cpu_to_le64(0x004B4C4278746E49ULL), /* "IntxBLK\0" */
-} INTX_FILE_TYPES;
-#endif /* __sun */
-
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- INTX_FILE_TYPES magic; /* Intx file magic. */
- union {
- /* For character and block devices. */
- struct {
- le64 major; /* Major device number. */
- le64 minor; /* Minor device number. */
- char device_end; /* Marker for offsetof(). */
- } __attribute__((__packed__)) s;
- /* For symbolic links. */
- ntfschar target[1];
- } __attribute__((__packed__)) u;
-} __attribute__((__packed__)) INTX_FILE;
-#ifdef __sun
-#pragma pack()
-#endif
-
-#endif /* defined _NTFS_LAYOUT_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/lcnalloc.h b/usr/src/lib/libntfs/common/include/ntfs/lcnalloc.h
deleted file mode 100644
index 07ab020d2d..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/lcnalloc.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * lcnalloc.h - Exports for cluster (de)allocation. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2002 Anton Altaparmakov
- * Copyright (c) 2004 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_LCNALLOC_H
-#define _NTFS_LCNALLOC_H
-
-#include "types.h"
-#include "runlist.h"
-#include "volume.h"
-
-/**
- * enum NTFS_CLUSTER_ALLOCATION_ZONES -
- */
-typedef enum {
- FIRST_ZONE = 0, /* For sanity checking. */
- MFT_ZONE = 0, /* Allocate from $MFT zone. */
- DATA_ZONE = 1, /* Allocate from $DATA zone. */
- LAST_ZONE = 1, /* For sanity checking. */
-} NTFS_CLUSTER_ALLOCATION_ZONES;
-
-extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
- LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone);
-
-extern int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl);
-
-extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
- s64 count);
-
-#endif /* defined _NTFS_LCNALLOC_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/list.h b/usr/src/lib/libntfs/common/include/ntfs/list.h
deleted file mode 100644
index e3c774423d..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/list.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * list.h - Linked list implementation. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2002 Anton Altaparmakov and others
- *
- * 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 _NTFS_LIST_H
-#define _NTFS_LIST_H
-
-/**
- * struct list_head - Simple doubly linked list implementation.
- *
- * Copied from Linux kernel 2.4.2-ac18 into Linux-NTFS (with minor
- * modifications). - AIA
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-struct list_head {
- struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-#define INIT_LIST_HEAD(ptr) do { \
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/**
- * __list_add - Insert a new entry between two known consecutive entries.
- * @new:
- * @prev:
- * @next:
- *
- * This is only for internal list manipulation where we know the prev/next
- * entries already!
- */
-static __inline__ void __list_add(struct list_head * new,
- struct list_head * prev, struct list_head * next)
-{
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static __inline__ void list_add(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/**
- * __list_del -
- * @prev:
- * @next:
- *
- * Delete a list entry by making the prev/next entries point to each other.
- *
- * This is only for internal list manipulation where we know the prev/next
- * entries already!
- */
-static __inline__ void __list_del(struct list_head * prev,
- struct list_head * next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- *
- * Note: list_empty on entry does not return true after this, the entry is in
- * an undefined state.
- */
-static __inline__ void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static __inline__ void list_del_init(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static __inline__ int list_empty(struct list_head *head)
-{
- return head->next == head;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static __inline__ void list_splice(struct list_head *list,
- struct list_head *head)
-{
- struct list_head *first = list->next;
-
- if (first != list) {
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
- }
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-/**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
-#endif /* defined _NTFS_LIST_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/logfile.h b/usr/src/lib/libntfs/common/include/ntfs/logfile.h
deleted file mode 100644
index 9c597ecb4d..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/logfile.h
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * logfile.h - Exports for $LogFile handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2005 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_LOGFILE_H
-#define _NTFS_LOGFILE_H
-
-#include "types.h"
-#include "endians.h"
-#include "layout.h"
-
-/*
- * Journal ($LogFile) organization:
- *
- * Two restart areas present in the first two pages (restart pages, one restart
- * area in each page). When the volume is dismounted they should be identical,
- * except for the update sequence array which usually has a different update
- * sequence number.
- *
- * These are followed by log records organized in pages headed by a log record
- * header going up to log file size. Not all pages contain log records when a
- * volume is first formatted, but as the volume ages, all records will be used.
- * When the log file fills up, the records at the beginning are purged (by
- * modifying the oldest_lsn to a higher value presumably) and writing begins
- * at the beginning of the file. Effectively, the log file is viewed as a
- * circular entity.
- *
- * NOTE: Windows NT, 2000, and XP all use log file version 1.1 but they accept
- * versions <= 1.x, including 0.-1. (Yes, that is a minus one in there!) We
- * probably only want to support 1.1 as this seems to be the current version
- * and we don't know how that differs from the older versions. The only
- * exception is if the journal is clean as marked by the two restart pages
- * then it doesn't matter whether we are on an earlier version. We can just
- * reinitialize the logfile and start again with version 1.1.
- */
-
-/* Some $LogFile related constants. */
-#define MaxLogFileSize 0x100000000ULL
-#define DefaultLogPageSize 4096
-#define MinLogRecordPages 48
-
-/**
- * struct RESTART_PAGE_HEADER - Log file restart page header.
- *
- * Begins the restart area.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
-/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
-/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
- When creating, set this to be immediately
- after this header structure (without any
- alignment). */
-/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
-
-/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
- chkdsk. Only used when the magic is changed
- to "CHKD". Otherwise this is zero. */
-/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
- was created, has to be >= 512 and a power of
- 2. Use this to calculate the required size
- of the usa (usa_count) and add it to usa_ofs.
- Then verify that the result is less than the
- value of the restart_area_offset. */
-/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
- 512 and a power of 2. The default is 4096
- and is used when the system page size is
- between 4096 and 8192. Otherwise this is
- set to the system page size instead. */
-/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
- the RESTART_AREA. Value has to be aligned
- to 8-byte boundary. When creating, set this
- to be after the usa. */
-/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
- version is 1. */
-/* 28*/ sle16 major_ver; /* Log file major version. We only support
- version 1.1. */
-/* sizeof() = 30 (0x1e) bytes */
-} __attribute__((__packed__)) RESTART_PAGE_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/*
- * Constant for the log client indices meaning that there are no client records
- * in this particular client array. Also inside the client records themselves,
- * this means that there are no client records preceding or following this one.
- */
-#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff)
-#define LOGFILE_NO_CLIENT_CPU 0xffff
-
-#ifdef __sun
-#define RESTART_VOLUME_IS_CLEAN (const_cpu_to_le16(0x0002))
-#else /* not __sun */
-/*
- * These are the so far known RESTART_AREA_* flags (16-bit) which contain
- * information about the log file in which they are present.
- */
-enum {
- RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
- RESTART_SPACE_FILLER = const_cpu_to_le16(0xffff),
- /* gcc: Force enum bit width to 16. */
-} __attribute__((__packed__));
-#endif /* __sun */
-
-typedef le16 RESTART_AREA_FLAGS;
-
-/**
- * struct RESTART_AREA - Log file restart area record.
- *
- * The offset of this record is found by adding the offset of the
- * RESTART_PAGE_HEADER to the restart_area_offset value found in it.
- * See notes at restart_area_offset above.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
- when the restart area was last written.
- This happens often but what is the interval?
- Is it just fixed time or is it every time a
- check point is written or something else?
- On create set to 0. */
-/* 8*/ le16 log_clients; /* Number of log client records in the array of
- log client records which follows this
- restart area. Must be 1. */
-/* 10*/ le16 client_free_list; /* The index of the first free log client record
- in the array of log client records.
- LOGFILE_NO_CLIENT means that there are no
- free log client records in the array.
- If != LOGFILE_NO_CLIENT, check that
- log_clients > client_free_list. On Win2k
- and presumably earlier, on a clean volume
- this is != LOGFILE_NO_CLIENT, and it should
- be 0, i.e. the first (and only) client
- record is free and thus the logfile is
- closed and hence clean. A dirty volume
- would have left the logfile open and hence
- this would be LOGFILE_NO_CLIENT. On WinXP
- and presumably later, the logfile is always
- open, even on clean shutdown so this should
- always be LOGFILE_NO_CLIENT. */
-/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
- record in the array of log client records.
- LOGFILE_NO_CLIENT means that there are no
- in-use log client records in the array. If
- != LOGFILE_NO_CLIENT check that log_clients
- > client_in_use_list. On Win2k and
- presumably earlier, on a clean volume this
- is LOGFILE_NO_CLIENT, i.e. there are no
- client records in use and thus the logfile
- is closed and hence clean. A dirty volume
- would have left the logfile open and hence
- this would be != LOGFILE_NO_CLIENT, and it
- should be 0, i.e. the first (and only)
- client record is in use. On WinXP and
- presumably later, the logfile is always
- open, even on clean shutdown so this should
- always be 0. */
-/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
- and presumably earlier this is always 0. On
- WinXP and presumably later, if the logfile
- was shutdown cleanly, the second bit,
- RESTART_VOLUME_IS_CLEAN, is set. This bit
- is cleared when the volume is mounted by
- WinXP and set when the volume is dismounted,
- thus if the logfile is dirty, this bit is
- clear. Thus we don't need to check the
- Windows version to determine if the logfile
- is clean. Instead if the logfile is closed,
- we know it must be clean. If it is open and
- this bit is set, we also know it must be
- clean. If on the other hand the logfile is
- open and this bit is clear, we can be almost
- certain that the logfile is dirty. */
-/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
- number. This is calculated as 67 - the
- number of bits required to store the logfile
- size in bytes and this can be used in with
- the specified file_size as a consistency
- check. */
-/* 20*/ le16 restart_area_length;/* Length of the restart area including the
- client array. Following checks required if
- version matches. Otherwise, skip them.
- restart_area_offset + restart_area_length
- has to be <= system_page_size. Also,
- restart_area_length has to be >=
- client_array_offset + (log_clients *
- sizeof(log client record)). */
-/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
- the first log client record if versions are
- matched. When creating, set this to be
- after this restart area structure, aligned
- to 8-bytes boundary. If the versions do not
- match, this is ignored and the offset is
- assumed to be (sizeof(RESTART_AREA) + 7) &
- ~7, i.e. rounded up to first 8-byte
- boundary. Either way, client_array_offset
- has to be aligned to an 8-byte boundary.
- Also, restart_area_offset +
- client_array_offset has to be <= 510.
- Finally, client_array_offset + (log_clients
- * sizeof(log client record)) has to be <=
- system_page_size. On Win2k and presumably
- earlier, this is 0x30, i.e. immediately
- following this record. On WinXP and
- presumably later, this is 0x40, i.e. there
- are 16 extra bytes between this record and
- the client array. This probably means that
- the RESTART_AREA record is actually bigger
- in WinXP and later. */
-/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
- restart_area_offset + the offset of the
- file_size are > 510 then corruption has
- occurred. This is the very first check when
- starting with the restart_area as if it
- fails it means that some of the above values
- will be corrupted by the multi sector
- transfer protection. The file_size has to
- be rounded down to be a multiple of the
- log_page_size in the RESTART_PAGE_HEADER and
- then it has to be at least big enough to
- store the two restart pages and 48 (0x30)
- log record pages. */
-/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
- the log record header. On create set to
- 0. */
-/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
- If the version matches then check that the
- value of log_record_header_length is a
- multiple of 8, i.e.
- (log_record_header_length + 7) & ~7 ==
- log_record_header_length. When creating set
- it to sizeof(LOG_RECORD_HEADER), aligned to
- 8 bytes. */
-/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record
- page. Must be a multiple of 8. On create
- set it to immediately after the update
- sequence array of the log record page. */
-/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
- time the logfile is restarted which happens
- at mount time when the logfile is opened.
- When creating set to a random value. Win2k
- sets it to the low 32 bits of the current
- system time in NTFS format (see time.h). */
-/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
-/* sizeof() = 48 (0x30) bytes */
-} __attribute__((__packed__)) RESTART_AREA;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct LOG_CLIENT_RECORD - Log client record.
- *
- * The offset of this record is found by adding the offset of the
- * RESTART_AREA to the client_array_offset value found in it.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/*Ofs*/
-/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
- set to 0. */
-/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
- the volume, i.e. the current position within
- the log file. At present, if clean this
- should = current_lsn in restart area but it
- probably also = current_lsn when dirty most
- of the time. At create set to 0. */
-/* 16*/ le16 prev_client; /* The offset to the previous log client record
- in the array of log client records.
- LOGFILE_NO_CLIENT means there is no previous
- client record, i.e. this is the first one.
- This is always LOGFILE_NO_CLIENT. */
-/* 18*/ le16 next_client; /* The offset to the next log client record in
- the array of log client records.
- LOGFILE_NO_CLIENT means there are no next
- client records, i.e. this is the last one.
- This is always LOGFILE_NO_CLIENT. */
-/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
- to zero every time the logfile is restarted
- and it is incremented when the logfile is
- closed at dismount time. Thus it is 0 when
- dirty and 1 when clean. On WinXP and
- presumably later, this is always 0. */
-/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
-/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
- always be 8. */
-/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
- always be "NTFS" with the remaining bytes
- set to 0. */
-/* sizeof() = 160 (0xa0) bytes */
-} __attribute__((__packed__)) LOG_CLIENT_RECORD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct RECORD_PAGE_HEADER - Log page record page header.
- *
- * Each log page begins with this header and is followed by several LOG_RECORD
- * structures, starting at offset 0x40 (the size of this structure and the
- * following update sequence array and then aligned to 8 byte boundary, but is
- * this specified anywhere?).
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
- u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
- When creating, set this to be immediately
- after this header structure (without any
- alignment). */
- u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
-
- union {
- LSN last_lsn;
- s64 file_offset;
- } __attribute__((__packed__)) copy;
- u32 flags;
- u16 page_count;
- u16 page_position;
- union {
- struct {
- u16 next_record_offset;
- u8 reserved[6];
- LSN last_end_lsn;
- } __attribute__((__packed__)) packed;
- } __attribute__((__packed__)) header;
-} __attribute__((__packed__)) RECORD_PAGE_HEADER;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
- *
- * (Or is it log record pages?)
- */
-#ifdef __sun
-typedef const uint16_t LOG_RECORD_FLAGS;
-#define LOG_RECORD_MULTI_PAGE (const_cpu_to_le16(0x0001))
-#else /* not __sun */
-typedef enum {
- LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
- LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
- /* This has nothing to do with the log record. It is only so
- gcc knows to make the flags 16-bit. */
-} __attribute__((__packed__)) LOG_RECORD_FLAGS;
-#endif /* __sun */
-
-/**
- * struct LOG_CLIENT_ID - The log client id structure identifying a log client.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- u16 seq_number;
- u16 client_index;
-} __attribute__((__packed__)) LOG_CLIENT_ID;
-#ifdef __sun
-#pragma pack()
-#endif
-
-/**
- * struct LOG_RECORD - Log record header.
- *
- * Each log record seems to have a constant size of 0x70 bytes.
- */
-#ifdef __sun
-#pragma pack(1)
-#endif
-typedef struct {
- LSN this_lsn;
- LSN client_previous_lsn;
- LSN client_undo_next_lsn;
- u32 client_data_length;
- LOG_CLIENT_ID client_id;
- u32 record_type;
- u32 transaction_id;
- u16 flags;
- u16 reserved_or_alignment[3];
-/* Now are at ofs 0x30 into struct. */
- u16 redo_operation;
- u16 undo_operation;
- u16 redo_offset;
- u16 redo_length;
- u16 undo_offset;
- u16 undo_length;
- u16 target_attribute;
- u16 lcns_to_follow; /* Number of lcn_list entries
- following this entry. */
-/* Now at ofs 0x40. */
- u16 record_offset;
- u16 attribute_offset;
- u32 alignment_or_reserved;
- VCN target_vcn;
-/* Now at ofs 0x50. */
- struct { /* Only present if lcns_to_follow
- is not 0. */
- LCN lcn;
- } __attribute__((__packed__)) lcn_list[];
-} __attribute__((__packed__)) LOG_RECORD;
-#ifdef __sun
-#pragma pack()
-#endif
-
-extern BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp);
-extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp);
-extern int ntfs_empty_logfile(ntfs_attr *na);
-
-#endif /* defined _NTFS_LOGFILE_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/logging.h b/usr/src/lib/libntfs/common/include/ntfs/logging.h
deleted file mode 100644
index 524643a149..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/logging.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * logging.h - Centralised logging. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the 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 _LOGGING_H_
-#define _LOGGING_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-
-#include "types.h"
-
-/* Function prototype for the logging handlers */
-typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
- u32 level, void *data, const char *format, va_list args);
-
-/* Set the logging handler from one of the functions, below. */
-void ntfs_log_set_handler(ntfs_log_handler *handler);
-
-/* Logging handlers */
-ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0)));
-ntfs_log_handler ntfs_log_handler_fprintf __attribute__((format(printf, 6, 0)));
-ntfs_log_handler ntfs_log_handler_null __attribute__((format(printf, 6, 0)));
-ntfs_log_handler ntfs_log_handler_stdout __attribute__((format(printf, 6, 0)));
-ntfs_log_handler ntfs_log_handler_outerr __attribute__((format(printf, 6, 0)));
-ntfs_log_handler ntfs_log_handler_stderr __attribute__((format(printf, 6, 0)));
-
-/* Enable/disable certain log levels */
-u32 ntfs_log_set_levels(u32 levels);
-u32 ntfs_log_clear_levels(u32 levels);
-u32 ntfs_log_get_levels(void);
-
-/* Enable/disable certain log flags */
-u32 ntfs_log_set_flags(u32 flags);
-u32 ntfs_log_clear_flags(u32 flags);
-u32 ntfs_log_get_flags(void);
-
-/* Turn command-line options into logging flags */
-BOOL ntfs_log_parse_option(const char *option);
-
-int ntfs_log_redirect(const char *function, const char *file, int line,
- u32 level, void *data, const char *format, ...)
- __attribute__((format(printf, 6, 7)));
-
-/* Logging levels - Determine what gets logged */
-#define NTFS_LOG_LEVEL_DEBUG ((u32)1 << 0) /* x = 42 */
-#define NTFS_LOG_LEVEL_TRACE ((u32)1 << 1) /* Entering function x() */
-#define NTFS_LOG_LEVEL_QUIET ((u32)1 << 2) /* Quietable output */
-#define NTFS_LOG_LEVEL_INFO ((u32)1 << 3) /* Volume needs defragmenting */
-#define NTFS_LOG_LEVEL_VERBOSE ((u32)1 << 4) /* Forced to continue */
-#define NTFS_LOG_LEVEL_PROGRESS ((u32)1 << 5) /* 54% complete */
-#define NTFS_LOG_LEVEL_WARNING ((u32)1 << 6) /* You should backup before starting */
-#define NTFS_LOG_LEVEL_ERROR ((u32)1 << 7) /* Operation failed, no damage done */
-#define NTFS_LOG_LEVEL_PERROR ((u32)1 << 8) /* Message : standard error description */
-#define NTFS_LOG_LEVEL_CRITICAL ((u32)1 << 9) /* Operation failed,damage may have occurred */
-
-/* Logging style flags - Manage the style of the output */
-#define NTFS_LOG_FLAG_PREFIX ((u32)1 << 0) /* Prefix messages with "ERROR: ", etc */
-#define NTFS_LOG_FLAG_FILENAME ((u32)1 << 1) /* Show the file origin of the message */
-#define NTFS_LOG_FLAG_LINE ((u32)1 << 2) /* Show the line number of the message */
-#define NTFS_LOG_FLAG_FUNCTION ((u32)1 << 3) /* Show the function name containing the message */
-#define NTFS_LOG_FLAG_ONLYNAME ((u32)1 << 4) /* Only display the filename, not the pathname */
-#define NTFS_LOG_FLAG_COLOUR ((u32)1 << 5) /* Colour highlight some messages */
-
-/* Macros to simplify logging. One for each level defined above.
- * Note, if DEBUG is not defined, then ntfs_log_debug/trace have no effect.
- */
-#if defined(__GNUC__)
-
-#define ntfs_log_critical(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_CRITICAL,NULL,FORMAT,##ARGS)
-#define ntfs_log_error(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS)
-#define ntfs_log_info(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_INFO,NULL,FORMAT,##ARGS)
-#define ntfs_log_perror(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PERROR,NULL,FORMAT,##ARGS)
-#define ntfs_log_progress(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PROGRESS,NULL,FORMAT,##ARGS)
-#define ntfs_log_quiet(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_QUIET,NULL,FORMAT,##ARGS)
-#define ntfs_log_verbose(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,FORMAT,##ARGS)
-#define ntfs_log_warning(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,FORMAT,##ARGS)
-
-#else /* not __GNUC__ */
-
-#define PRINT(...) printf(__VA_ARGS__)
-
-#define ntfs_log_critical(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_CRITICAL,NULL,__VA_ARGS__)
-#define ntfs_log_error(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_ERROR,NULL,__VA_ARGS__)
-#define ntfs_log_info(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_INFO,NULL,__VA_ARGS__)
-#define ntfs_log_perror(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_PERROR,NULL,__VA_ARGS__)
-#define ntfs_log_progress(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_PROGRESS,NULL,__VA_ARGS__)
-#define ntfs_log_quiet(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_QUIET,NULL,__VA_ARGS__)
-#define ntfs_log_verbose(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,__VA_ARGS__)
-#define ntfs_log_warning(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,__VA_ARGS__)
-
-#endif /* __GNUC__ */
-
-/*
- * By default debug and trace messages are compiled into the program,
- * but not displayed.
- */
-#if defined(__GNUC__)
-
-#ifndef DEBUG
-#define ntfs_log_debug(FORMAT, ARGS...)do {} while (0)
-#define ntfs_log_trace(FORMAT, ARGS...)do {} while (0)
-#else /* !DEBUG */
-#define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS)
-#define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS)
-#endif /* DEBUG */
-
-#else /* not __GNUC__ */
-
-#ifndef DEBUG
-#define ntfs_log_debug(...) do {} while (0)
-#define ntfs_log_trace(...) do {} while (0)
-#else /* !DEBUG */
-#define ntfs_log_debug(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,__VA_ARGS__)
-#define ntfs_log_trace(...) ntfs_log_redirect("unknown",__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,__VA_ARGS__)
-#endif /* DEBUG */
-
-#endif /* __GNUC__ */
-
-#endif /* _LOGGING_H_ */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/mft.h b/usr/src/lib/libntfs/common/include/ntfs/mft.h
deleted file mode 100644
index 180f61531d..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/mft.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * mft.h - Exports for MFT record handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2002 Anton Altaparmakov
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_MFT_H
-#define _NTFS_MFT_H
-
-#include "volume.h"
-#include "inode.h"
-#include "layout.h"
-
-extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
- const s64 count, MFT_RECORD *b);
-
-/**
- * ntfs_mft_record_read - read a record from the mft
- * @vol: volume to read from
- * @mref: mft record number to read
- * @b: output data buffer
- *
- * Read the mft record specified by @mref from volume @vol into buffer @b.
- * Return 0 on success or -1 on error, with errno set to the error code.
- *
- * The read mft record is mst deprotected and is hence ready to use. The caller
- * should check the record with is_baad_record() in case mst deprotection
- * failed.
- *
- * NOTE: @b has to be at least of size vol->mft_record_size.
- */
-static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
- const MFT_REF mref, MFT_RECORD *b)
-{
- return ntfs_mft_records_read(vol, mref, 1, b);
-}
-
-extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
- MFT_RECORD **mrec, ATTR_RECORD **attr);
-
-extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
- const s64 count, MFT_RECORD *b);
-
-/**
- * ntfs_mft_record_write - write an mft record to disk
- * @vol: volume to write to
- * @mref: mft record number to write
- * @b: data buffer containing the mft record to write
- *
- * Write the mft record specified by @mref from buffer @b to volume @vol.
- * Return 0 on success or -1 on error, with errno set to the error code.
- *
- * Before the mft record is written, it is mst protected. After the write, it
- * is deprotected again, thus resulting in an increase in the update sequence
- * number inside the buffer @b.
- *
- * NOTE: @b has to be at least of size vol->mft_record_size.
- */
-static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
- const MFT_REF mref, MFT_RECORD *b)
-{
- return ntfs_mft_records_write(vol, mref, 1, b);
-}
-
-/**
- * ntfs_mft_record_get_data_size - return number of bytes used in mft record @b
- * @m: mft record to get the data size of
- *
- * Takes the mft record @m and returns the number of bytes used in the record
- * or 0 on error (i.e. @m is not a valid mft record). Zero is not a valid size
- * for an mft record as it at least has to have the MFT_RECORD itself and a
- * zero length attribute of type AT_END, thus making the minimum size 56 bytes.
- *
- * Aside: The size is independent of NTFS versions 1.x/3.x because the 8-byte
- * alignment of the first attribute mask the difference in MFT_RECORD size
- * between NTFS 1.x and 3.x. Also, you would expect every mft record to
- * contain an update sequence array as well but that could in theory be
- * non-existent (don't know if Windows' NTFS driver/chkdsk wouldn't view this
- * as corruption in itself though).
- */
-static __inline__ u32 ntfs_mft_record_get_data_size(const MFT_RECORD *m)
-{
- if (!m || !ntfs_is_mft_record(m->magic))
- return 0;
- /* Get the number of used bytes and return it. */
- return le32_to_cpu(m->bytes_in_use);
-}
-
-extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
- MFT_RECORD *mrec);
-
-extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
-
-extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni);
-
-extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
-
-extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);
-
-#endif /* defined _NTFS_MFT_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/mst.h b/usr/src/lib/libntfs/common/include/ntfs/mst.h
deleted file mode 100644
index 0808b3c115..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/mst.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * mst.h - Exports for multi sector transfer fixup functions. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2000-2002 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_MST_H
-#define _NTFS_MST_H
-
-#include "types.h"
-#include "layout.h"
-
-extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size);
-extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size);
-extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b);
-
-#endif /* defined _NTFS_MST_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/ntfstime.h b/usr/src/lib/libntfs/common/include/ntfs/ntfstime.h
deleted file mode 100644
index 2fb85a5413..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/ntfstime.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * ntfstime.h - NTFS time related functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_NTFSTIME_H
-#define _NTFS_NTFSTIME_H
-
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-
-#include "types.h"
-
-#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
-
-/**
- * ntfs2utc - Convert an NTFS time to Unix time
- * @ntfs_time: An NTFS time in 100ns units since 1601
- *
- * NTFS stores times as the number of 100ns intervals since January 1st 1601 at
- * 00:00 UTC. This system will not suffer from Y2K problems until ~57000AD.
- *
- * Return: n A Unix time (number of seconds since 1970)
- */
-static __inline__ time_t ntfs2utc(sle64 ntfs_time)
-{
- return (sle64_to_cpu(ntfs_time) - (NTFS_TIME_OFFSET)) / 10000000;
-}
-
-/**
- * utc2ntfs - Convert Linux time to NTFS time
- * @utc_time: Linux time to convert to NTFS
- *
- * Convert the Linux time @utc_time to its corresponding NTFS time.
- *
- * Linux stores time in a long at present and measures it as the number of
- * 1-second intervals since 1st January 1970, 00:00:00 UTC.
- *
- * NTFS uses Microsoft's standard time format which is stored in a s64 and is
- * measured as the number of 100 nano-second intervals since 1st January 1601,
- * 00:00:00 UTC.
- *
- * Return: n An NTFS time (100ns units since Jan 1601)
- */
-static __inline__ sle64 utc2ntfs(time_t utc_time)
-{
- /* Convert to 100ns intervals and then add the NTFS time offset. */
- return cpu_to_sle64((s64)utc_time * 10000000 + NTFS_TIME_OFFSET);
-}
-
-#endif /* _NTFS_NTFSTIME_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/runlist.h b/usr/src/lib/libntfs/common/include/ntfs/runlist.h
deleted file mode 100644
index f35202971f..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/runlist.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * runlist.h - Exports for runlist handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002 Anton Altaparmakov
- * Copyright (c) 2002 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_RUNLIST_H
-#define _NTFS_RUNLIST_H
-
-#include "types.h"
-
-/* Forward declarations */
-typedef struct _runlist_element runlist_element;
-typedef runlist_element runlist;
-
-#include "attrib.h"
-#include "volume.h"
-
-/**
- * struct _runlist_element - in memory vcn to lcn mapping array element.
- * @vcn: starting vcn of the current array element
- * @lcn: starting lcn of the current array element
- * @length: length in clusters of the current array element
- *
- * The last vcn (in fact the last vcn + 1) is reached when length == 0.
- *
- * When lcn == -1 this means that the count vcns starting at vcn are not
- * physically allocated (i.e. this is a hole / data is sparse).
- */
-struct _runlist_element {/* In memory vcn to lcn mapping structure element. */
- VCN vcn; /* vcn = Starting virtual cluster number. */
- LCN lcn; /* lcn = Starting logical cluster number. */
- s64 length; /* Run length in clusters. */
-};
-
-extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
-
-extern s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
- const s64 pos, s64 count, void *b);
-extern s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
- const s64 pos, s64 count, void *b);
-
-extern int ntfs_rl_fill_zero(const ntfs_volume *vol, const runlist *rl,
- s64 pos, const s64 count);
-
-extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
- runlist_element *srl);
-
-extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
- const ATTR_RECORD *attr, runlist_element *old_rl);
-
-extern int ntfs_get_nr_significant_bytes(const s64 n);
-
-extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
- const runlist_element *rl, const VCN start_vcn);
-
-extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max,
- const s64 n);
-
-extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
- const int dst_len, const runlist_element *rl,
- const VCN start_vcn, VCN *const stop_vcn);
-
-extern int ntfs_rl_truncate(runlist **arl, const VCN start_vcn);
-
-extern int ntfs_rl_sparse(runlist *rl);
-extern s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl);
-
-#ifdef NTFS_TEST
-int test_rl_main(int argc, char *argv[]);
-#endif
-
-#endif /* defined _NTFS_RUNLIST_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/security.h b/usr/src/lib/libntfs/common/include/ntfs/security.h
deleted file mode 100644
index a61aabd754..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/security.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * security.h - Exports for handling security/ACLs in NTFS. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_SECURITY_H
-#define _NTFS_SECURITY_H
-
-#include "types.h"
-#include "layout.h"
-
-extern const GUID *const zero_guid;
-
-extern BOOL ntfs_guid_is_zero(const GUID *guid);
-extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);
-
-/**
- * ntfs_sid_is_valid - determine if a SID is valid
- * @sid: SID for which to determine if it is valid
- *
- * Determine if the SID pointed to by @sid is valid.
- *
- * Return TRUE if it is valid and FALSE otherwise.
- */
-static __inline__ BOOL ntfs_sid_is_valid(const SID *sid)
-{
- if (!sid || sid->revision != SID_REVISION ||
- sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
- return FALSE;
- return TRUE;
-}
-
-extern int ntfs_sid_to_mbs_size(const SID *sid);
-extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
- size_t sid_str_size);
-extern void ntfs_generate_guid(GUID *guid);
-
-#endif /* defined _NTFS_SECURITY_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/support.h b/usr/src/lib/libntfs/common/include/ntfs/support.h
deleted file mode 100644
index 7c1eed632a..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/support.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * support.h - Various useful things. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2006 Szabolcs Szakacsits
- * Copyright (c) 2006 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_SUPPORT_H
-#define _NTFS_SUPPORT_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDDEF_H
-#include <stddef.h>
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "logging.h"
-
-/*
- * Our mailing list. Use this define to prevent typos in email address.
- */
-#define NTFS_DEV_LIST "linux-ntfs-dev@lists.sf.net"
-
-/*
- * Generic macro to convert pointers to values for comparison purposes.
- */
-#ifndef p2n
-#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
-#endif
-
-/*
- * The classic min and max macros.
- */
-#ifndef min
-#define min(a,b) ((a) <= (b) ? (a) : (b))
-#endif
-
-#ifndef max
-#define max(a,b) ((a) >= (b) ? (a) : (b))
-#endif
-
-/*
- * Useful macro for determining the offset of a struct member.
- */
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
-
-/*
- * Round up and down @num to 2 in power of @order.
- */
-#define ROUND_UP(num,order) (((num) + ((1 << (order)) - 1)) & \
- ~((1 << (order)) - 1))
-#define ROUND_DOWN(num,order) ((num) & ~((1 << (order)) - 1))
-
-/*
- * Simple bit operation macros. NOTE: These are NOT atomic.
- */
-#define test_bit(bit, var) ((var) & (1 << (bit)))
-#define set_bit(bit, var) (var) |= 1 << (bit)
-#define clear_bit(bit, var) (var) &= ~(1 << (bit))
-
-#ifdef __sun
-#define test_and_set_bit(bit, var) _test_and_set_bit(bit, &var)
-static __inline__ BOOL _test_and_set_bit(unsigned long bit, unsigned long *var)
-{
- const BOOL old_state = test_bit(bit, *var);
- set_bit(bit, *var);
- return old_state;
-}
-
-#define test_and_clear_bit(bit, var) _test_and_clear_bit(bit, &var)
-static __inline__ BOOL _test_and_clear_bit(unsigned long bit, unsigned long *var)
-{
- const BOOL old_state = test_bit(bit, *var);
- clear_bit(bit, *var);
- return old_state;
-}
-#else /* !__sun */
-#define test_and_set_bit(bit, var) \
-({ \
- const BOOL old_state = test_bit(bit, var); \
- set_bit(bit, var); \
- old_state; \
-})
-
-#define test_and_clear_bit(bit, var) \
-({ \
- const BOOL old_state = test_bit(bit, var); \
- clear_bit(bit, var); \
- old_state; \
-})
-#endif /* __sun */
-
-/* Memory allocation with logging. */
-extern void *ntfs_calloc(size_t size);
-extern void *ntfs_malloc(size_t size);
-
-#endif /* defined _NTFS_SUPPORT_H */
diff --git a/usr/src/lib/libntfs/common/include/ntfs/types.h b/usr/src/lib/libntfs/common/include/ntfs/types.h
deleted file mode 100644
index cd9a9a998d..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/types.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * types.h - Misc type definitions not related to on-disk structure. Part of
- * the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2006 Szabolcs Szakacsits
- * Copyright (c) 2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_TYPES_H
-#define _NTFS_TYPES_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#if HAVE_STDINT_H || !HAVE_CONFIG_H
-#include <stdint.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-typedef uint8_t u8; /* Unsigned types of an exact size */
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-
-typedef int8_t s8; /* Signed types of an exact size */
-typedef int16_t s16;
-typedef int32_t s32;
-typedef int64_t s64;
-
-#if defined(__CHECKER__) && !defined(NTFS_DO_NOT_CHECK_ENDIANS)
- #undef __bitwise
- #undef __force
- #define __bitwise __attribute__((bitwise))
- #define __force __attribute__((force))
-#else
- #undef __bitwise
- #undef __force
- #define __bitwise
- #define __force
-#endif
-
-typedef u16 __bitwise le16;
-typedef u32 __bitwise le32;
-typedef u64 __bitwise le64;
-
-/*
- * Declare sle{16,32,64} to be unsigned because we do not want sign extension
- * on BE architectures.
- */
-typedef u16 __bitwise sle16;
-typedef u32 __bitwise sle32;
-typedef u64 __bitwise sle64;
-
-typedef u16 __bitwise be16;
-typedef u32 __bitwise be32;
-typedef u64 __bitwise be64;
-
-typedef le16 ntfschar; /* 2-byte Unicode character type. */
-#define UCHAR_T_SIZE_BITS 1
-
-/*
- * Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
- * and VCN, to allow for type checking and better code readability.
- */
-typedef s64 VCN;
-typedef sle64 leVCN;
-typedef s64 LCN;
-typedef sle64 leLCN;
-
-/*
- * The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit
- * values. We define our own type LSN, to allow for type checking and better
- * code readability.
- */
-typedef s64 LSN;
-typedef sle64 leLSN;
-
-/*
- * Cygwin has a collision between our BOOL and <windef.h>'s
- * As long as this file will be included after <windows.h> we're fine.
- */
-#ifndef _WINDEF_H
-/**
- * enum BOOL - These are just to make the code more readable...
- */
-typedef enum {
-#ifndef FALSE
- FALSE = 0,
-#endif
-#ifndef NO
- NO = 0,
-#endif
-#ifndef ZERO
- ZERO = 0,
-#endif
-#ifndef TRUE
- TRUE = 1,
-#endif
-#ifndef YES
- YES = 1,
-#endif
-#ifndef ONE
- ONE = 1,
-#endif
-} BOOL;
-#endif /* defined _WINDEF_H */
-
-/**
- * enum IGNORE_CASE_BOOL -
- */
-typedef enum {
- CASE_SENSITIVE = 0,
- IGNORE_CASE = 1,
-} IGNORE_CASE_BOOL;
-
-#define STATUS_OK (0)
-#define STATUS_ERROR (-1)
-#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2)
-#define STATUS_KEEP_SEARCHING (-3)
-#define STATUS_NOT_FOUND (-4)
-
-#endif /* defined _NTFS_TYPES_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/unistr.h b/usr/src/lib/libntfs/common/include/ntfs/unistr.h
deleted file mode 100644
index 2c5fd5548c..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/unistr.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * unistr.h - Exports for Unicode string handling. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_UNISTR_H
-#define _NTFS_UNISTR_H
-
-#include "types.h"
-#include "layout.h"
-
-extern BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
- const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_size);
-
-extern int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
- const ntfschar *name2, const u32 name2_len,
- const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len);
-
-extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n);
-
-extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
- const ntfschar *upcase, const u32 upcase_size);
-
-extern u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen);
-
-extern ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen);
-
-extern void ntfs_name_upcase(ntfschar *name, u32 name_len,
- const ntfschar *upcase, const u32 upcase_len);
-
-extern void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
- const ntfschar *upcase, const u32 upcase_len);
-
-extern int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
- const FILE_NAME_ATTR *file_name_attr2,
- const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len);
-
-extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
- int outs_len);
-extern int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len);
-
-extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
-
-extern ntfschar *ntfs_str2ucs(const char *s, int *len);
-
-extern void ntfs_ucsfree(ntfschar *ucs);
-
-#endif /* defined _NTFS_UNISTR_H */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/version.h b/usr/src/lib/libntfs/common/include/ntfs/version.h
deleted file mode 100644
index ec6dbdca32..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/version.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * version.h - Info about the NTFS library. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- * Copyright (c) 2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_VERSION_H_
-#define _NTFS_VERSION_H_
-
-extern const char *ntfs_libntfs_version(void);
-
-#endif /* _NTFS_VERSION_H_ */
-
diff --git a/usr/src/lib/libntfs/common/include/ntfs/volume.h b/usr/src/lib/libntfs/common/include/ntfs/volume.h
deleted file mode 100644
index 3183d69b13..0000000000
--- a/usr/src/lib/libntfs/common/include/ntfs/volume.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * volume.h - Exports for NTFS volume handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _NTFS_VOLUME_H
-#define _NTFS_VOLUME_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif
-#ifdef HAVE_MNTENT_H
-#include <mntent.h>
-#endif
-
-/* Forward declaration */
-typedef struct _ntfs_volume ntfs_volume;
-
-#include "list.h"
-#include "types.h"
-#include "support.h"
-#include "device.h"
-#include "inode.h"
-#include "attrib.h"
-
-/**
- * enum ntfs_mount_flags -
- *
- * Flags for the ntfs_mount() function.
- */
-typedef enum {
- NTFS_MNT_RDONLY = 1,
- NTFS_MNT_FORENSIC = 2,
- NTFS_MNT_CASE_SENSITIVE = 4,
- NTFS_MNT_NOT_EXCLUSIVE = 8,
- NTFS_MNT_FORCE = 16,
- NTFS_MNT_INTERIX = 32,
-} ntfs_mount_flags;
-
-/**
- * enum ntfs_mounted_flags -
- *
- * Flags returned by the ntfs_check_if_mounted() function.
- */
-typedef enum {
- NTFS_MF_MOUNTED = 1, /* Device is mounted. */
- NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
- NTFS_MF_READONLY = 4, /* Device is mounted read-only. */
-} ntfs_mounted_flags;
-
-extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
-
-/**
- * enum ntfs_volume_state_bits -
- *
- * Defined bits for the state field in the ntfs_volume structure.
- */
-typedef enum {
- NV_ReadOnly, /* 1: Volume is read-only. */
- NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
- NV_LogFileEmpty, /* 1: $logFile journal is empty. */
- NV_NoATime, /* 1: Do not update access time. */
- NV_WasDirty, /* 1: Volume was marked dirty before we mounted
- it. */
- NV_ForensicMount, /* 1: Mount is forensic, i.e. no modifications
- are to be done by mount/umount. */
- NV_Interix, /* 1: Make libntfs recognize Interix special
- files. */
-} ntfs_volume_state_bits;
-
-#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state)
-#define set_nvol_flag(nv, flag) set_bit(NV_##flag, (nv)->state)
-#define clear_nvol_flag(nv, flag) clear_bit(NV_##flag, (nv)->state)
-
-#define NVolReadOnly(nv) test_nvol_flag(nv, ReadOnly)
-#define NVolSetReadOnly(nv) set_nvol_flag(nv, ReadOnly)
-#define NVolClearReadOnly(nv) clear_nvol_flag(nv, ReadOnly)
-
-#define NVolCaseSensitive(nv) test_nvol_flag(nv, CaseSensitive)
-#define NVolSetCaseSensitive(nv) set_nvol_flag(nv, CaseSensitive)
-#define NVolClearCaseSensitive(nv) clear_nvol_flag(nv, CaseSensitive)
-
-#define NVolLogFileEmpty(nv) test_nvol_flag(nv, LogFileEmpty)
-#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
-#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
-
-#define NVolWasDirty(nv) test_nvol_flag(nv, WasDirty)
-#define NVolSetWasDirty(nv) set_nvol_flag(nv, WasDirty)
-#define NVolClearWasDirty(nv) clear_nvol_flag(nv, WasDirty)
-
-#define NVolForensicMount(nv) test_nvol_flag(nv, ForensicMount)
-#define NVolSetForensicMount(nv) set_nvol_flag(nv, ForensicMount)
-#define NVolClearForensicMount(nv) clear_nvol_flag(nv, ForensicMount)
-
-#define NVolInterix(nv) test_nvol_flag(nv, Interix)
-#define NVolSetInterix(nv) set_nvol_flag(nv, Interix)
-#define NVolClearInterix(nv) clear_nvol_flag(nv, Interix)
-
-/*
- * NTFS version 1.1 and 1.2 are used by Windows NT4.
- * NTFS version 2.x is used by Windows 2000 Beta
- * NTFS version 3.0 is used by Windows 2000.
- * NTFS version 3.1 is used by Windows XP, 2003 and Vista.
- */
-
-#define NTFS_V1_1(major, minor) ((major) == 1 && (minor) == 1)
-#define NTFS_V1_2(major, minor) ((major) == 1 && (minor) == 2)
-#define NTFS_V2_X(major, minor) ((major) == 2)
-#define NTFS_V3_0(major, minor) ((major) == 3 && (minor) == 0)
-#define NTFS_V3_1(major, minor) ((major) == 3 && (minor) == 1)
-
-#define NTFS_BUF_SIZE 8192
-
-#define NTFS_INODE_CACHE_SIZE 512 /* WARNING: This should be power of 2. */
-#define NTFS_INODE_CACHE_SIZE_BITS (NTFS_INODE_CACHE_SIZE - 1)
-
-/**
- * struct _ntfs_volume - structure describing an open volume in memory.
- */
-struct _ntfs_volume {
- union {
- struct ntfs_device *dev; /* NTFS device associated with
- the volume. */
- void *sb; /* For kernel porting compatibility. */
- } u;
- char *vol_name; /* Name of the volume. */
- unsigned long state; /* NTFS specific flags describing this volume.
- See ntfs_volume_state_bits above. */
-
- ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */
- u8 major_ver; /* Ntfs major version of volume. */
- u8 minor_ver; /* Ntfs minor version of volume. */
- le16 flags; /* Bit array of VOLUME_* flags. */
- GUID guid; /* The volume guid if present (otherwise it is
- a NULL guid). */
-
- u16 sector_size; /* Byte size of a sector. */
- u8 sector_size_bits; /* Log(2) of the byte size of a sector. */
- u32 cluster_size; /* Byte size of a cluster. */
- u32 mft_record_size; /* Byte size of a mft record. */
- u32 indx_record_size; /* Byte size of a INDX record. */
- u8 cluster_size_bits; /* Log(2) of the byte size of a cluster. */
- u8 mft_record_size_bits;/* Log(2) of the byte size of a mft record. */
- u8 indx_record_size_bits;/* Log(2) of the byte size of a INDX record. */
-
- /* Variables used by the cluster and mft allocators. */
- u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
- s64 mft_data_pos; /* Mft record number at which to allocate the
- next mft record. */
- LCN mft_zone_start; /* First cluster of the mft zone. */
- LCN mft_zone_end; /* First cluster beyond the mft zone. */
- LCN mft_zone_pos; /* Current position in the mft zone. */
- LCN data1_zone_pos; /* Current position in the first data zone. */
- LCN data2_zone_pos; /* Current position in the second data zone. */
-
- s64 nr_clusters; /* Volume size in clusters, hence also the
- number of bits in lcn_bitmap. */
- ntfs_inode *lcnbmp_ni; /* ntfs_inode structure for FILE_Bitmap. */
- ntfs_attr *lcnbmp_na; /* ntfs_attr structure for the data attribute
- of FILE_Bitmap. Each bit represents a
- cluster on the volume, bit 0 representing
- lcn 0 and so on. A set bit means that the
- cluster and vice versa. */
-
- LCN mft_lcn; /* Logical cluster number of the data attribute
- for FILE_MFT. */
- ntfs_inode *mft_ni; /* ntfs_inode structure for FILE_MFT. */
- ntfs_attr *mft_na; /* ntfs_attr structure for the data attribute
- of FILE_MFT. */
- ntfs_attr *mftbmp_na; /* ntfs_attr structure for the bitmap attribute
- of FILE_MFT. Each bit represents an mft
- record in the $DATA attribute, bit 0
- representing mft record 0 and so on. A set
- bit means that the mft record is in use and
- vice versa. */
-
- int mftmirr_size; /* Size of the FILE_MFTMirr in mft records. */
- LCN mftmirr_lcn; /* Logical cluster number of the data attribute
- for FILE_MFTMirr. */
- ntfs_inode *mftmirr_ni; /* ntfs_inode structure for FILE_MFTMirr. */
- ntfs_attr *mftmirr_na; /* ntfs_attr structure for the data attribute
- of FILE_MFTMirr. */
-
- ntfschar *upcase; /* Upper case equivalents of all 65536 2-byte
- Unicode characters. Obtained from
- FILE_UpCase. */
- u32 upcase_len; /* Length in Unicode characters of the upcase
- table. */
-
- ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
- FILE_AttrDef. */
- s32 attrdef_len; /* Size of the attribute definition table in
- bytes. */
-
- long nr_free_clusters; /* This two are self explaining. */
- long nr_free_mft_records;
-
- struct list_head inode_cache[NTFS_INODE_CACHE_SIZE]; /* List of opened
- inodes. */
-};
-
-extern ntfs_volume *ntfs_volume_alloc(void);
-
-extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
- ntfs_mount_flags flags);
-
-extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
- ntfs_mount_flags flags);
-extern int ntfs_device_umount(ntfs_volume *vol, const BOOL force);
-
-extern ntfs_volume *ntfs_mount(const char *name, ntfs_mount_flags flags);
-extern int ntfs_umount(ntfs_volume *vol, const BOOL force);
-
-extern int ntfs_version_is_supported(ntfs_volume *vol);
-extern int ntfs_logfile_reset(ntfs_volume *vol);
-
-extern int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags);
-
-#endif /* defined _NTFS_VOLUME_H */
diff --git a/usr/src/lib/libntfs/common/libntfs/attrib.c b/usr/src/lib/libntfs/common/libntfs/attrib.c
deleted file mode 100644
index 3c239bdaa3..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/attrib.c
+++ /dev/null
@@ -1,5234 +0,0 @@
-/**
- * attrib.c - Attribute handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- * Copyright (c) 2002-2005 Richard Russon
- * Copyright (c) 2002-2006 Szabolcs Szakacsits
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "attrlist.h"
-#include "device.h"
-#include "mft.h"
-#include "debug.h"
-#include "mst.h"
-#include "volume.h"
-#include "types.h"
-#include "layout.h"
-#include "inode.h"
-#include "runlist.h"
-#include "lcnalloc.h"
-#include "dir.h"
-#include "compress.h"
-#include "bitmap.h"
-#include "logging.h"
-#include "support.h"
-#include "crypto.h"
-
-ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') };
-
-/**
- * ntfs_get_attribute_value_length - Find the length of an attribute
- * @a:
- *
- * Description...
- *
- * Returns:
- */
-s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a)
-{
- if (!a) {
- errno = EINVAL;
- return 0;
- }
- errno = 0;
- if (a->non_resident)
- return sle64_to_cpu(a->u.nonres.data_size);
- return (s64)le32_to_cpu(a->u.res.value_length);
-}
-
-/**
- * ntfs_get_attribute_value - Get a copy of an attribute
- * @vol:
- * @a:
- * @b:
- *
- * Description...
- *
- * Returns:
- */
-s64 ntfs_get_attribute_value(const ntfs_volume *vol,
- const ATTR_RECORD *a, u8 *b)
-{
- runlist *rl;
- s64 total, r;
- int i;
-
- /* Sanity checks. */
- if (!vol || !a || !b) {
- errno = EINVAL;
- return 0;
- }
- /* Complex attribute? */
- /*
- * Ignore the flags in case they are not zero for an attribute list
- * attribute. Windows does not complain about invalid flags and chkdsk
- * does not detect or fix them so we need to cope with it, too.
- */
- if (a->type != AT_ATTRIBUTE_LIST && a->flags) {
- ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle "
- "this yet.\n", le16_to_cpu(a->flags));
- errno = EOPNOTSUPP;
- return 0;
- }
- if (!a->non_resident) {
- /* Attribute is resident. */
-
- /* Sanity check. */
- if (le32_to_cpu(a->u.res.value_length) + le16_to_cpu(a->u.res.value_offset)
- > le32_to_cpu(a->length)) {
- return 0;
- }
-
- memcpy(b, (const char*)a + le16_to_cpu(a->u.res.value_offset),
- le32_to_cpu(a->u.res.value_length));
- errno = 0;
- return (s64)le32_to_cpu(a->u.res.value_length);
- }
-
- /* Attribute is not resident. */
-
- /* If no data, return 0. */
- if (!(a->u.nonres.data_size)) {
- errno = 0;
- return 0;
- }
- /*
- * FIXME: What about attribute lists?!? (AIA)
- */
- /* Decompress the mapping pairs array into a runlist. */
- rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
- if (!rl) {
- errno = EINVAL;
- return 0;
- }
- /*
- * FIXED: We were overflowing here in a nasty fashion when we
- * reach the last cluster in the runlist as the buffer will
- * only be big enough to hold data_size bytes while we are
- * reading in allocated_size bytes which is usually larger
- * than data_size, since the actual data is unlikely to have a
- * size equal to a multiple of the cluster size!
- * FIXED2: We were also overflowing here in the same fashion
- * when the data_size was more than one run smaller than the
- * allocated size which happens with Windows XP sometimes.
- */
- /* Now load all clusters in the runlist into b. */
- for (i = 0, total = 0; rl[i].length; i++) {
- if (total + (rl[i].length << vol->cluster_size_bits) >=
- sle64_to_cpu(a->u.nonres.data_size)) {
- unsigned char *intbuf = NULL;
- /*
- * We have reached the last run so we were going to
- * overflow when executing the ntfs_pread() which is
- * BAAAAAAAD!
- * Temporary fix:
- * Allocate a new buffer with size:
- * rl[i].length << vol->cluster_size_bits, do the
- * read into our buffer, then memcpy the correct
- * amount of data into the caller supplied buffer,
- * free our buffer, and continue.
- * We have reached the end of data size so we were
- * going to overflow in the same fashion.
- * Temporary fix: same as above.
- */
- intbuf = ntfs_malloc(rl[i].length <<
- vol->cluster_size_bits);
- if (!intbuf) {
- int eo = errno;
- free(rl);
- errno = eo;
- return 0;
- }
- /*
- * FIXME: If compressed file: Only read if lcn != -1.
- * Otherwise, we are dealing with a sparse run and we
- * just memset the user buffer to 0 for the length of
- * the run, which should be 16 (= compression unit
- * size).
- * FIXME: Really only when file is compressed, or can
- * we have sparse runs in uncompressed files as well?
- * - Yes we can, in sparse files! But not necessarily
- * size of 16, just run length.
- */
- r = ntfs_pread(vol->u.dev, rl[i].lcn <<
- vol->cluster_size_bits, rl[i].length <<
- vol->cluster_size_bits, intbuf);
- if (r != rl[i].length << vol->cluster_size_bits) {
-#define ESTR "Error reading attribute value"
- if (r == -1) {
- int eo = errno;
- ntfs_log_perror(ESTR);
- errno = eo;
- } else if (r < rl[i].length <<
- vol->cluster_size_bits) {
- ntfs_log_debug(ESTR": Ran out of "
- "input data.\n");
- errno = EIO;
- } else {
- ntfs_log_debug(ESTR": unknown error\n");
- errno = EIO;
- }
-#undef ESTR
- free(rl);
- free(intbuf);
- return 0;
- }
- memcpy(b + total, intbuf, sle64_to_cpu(a->u.nonres.data_size) -
- total);
- free(intbuf);
- total = sle64_to_cpu(a->u.nonres.data_size);
- break;
- }
- /*
- * FIXME: If compressed file: Only read if lcn != -1.
- * Otherwise, we are dealing with a sparse run and we just
- * memset the user buffer to 0 for the length of the run, which
- * should be 16 (= compression unit size).
- * FIXME: Really only when file is compressed, or can
- * we have sparse runs in uncompressed files as well?
- * - Yes we can, in sparse files! But not necessarily size of
- * 16, just run length.
- */
- r = ntfs_pread(vol->u.dev, rl[i].lcn << vol->cluster_size_bits,
- rl[i].length << vol->cluster_size_bits,
- b + total);
- if (r != rl[i].length << vol->cluster_size_bits) {
-#define ESTR "Error reading attribute value"
- if (r == -1) {
- int eo = errno;
- ntfs_log_perror(ESTR);
- errno = eo;
- } else if (r < rl[i].length << vol->cluster_size_bits) {
- ntfs_log_debug(ESTR ": Ran out of "
- "input data.\n");
- errno = EIO;
- } else {
- ntfs_log_debug(ESTR ": unknown error\n");
- errno = EIO;
- }
-#undef ESTR
- free(rl);
- return 0;
- }
- total += r;
- }
- free(rl);
- return total;
-}
-
-/* Already cleaned up code below, but still look for FIXME:... */
-
-/**
- * __ntfs_attr_init - primary initialization of an ntfs attribute structure
- * @na: ntfs attribute to initialize
- * @ni: ntfs inode with which to initialize the ntfs attribute
- * @type: attribute type
- * @name: attribute name in little endian Unicode or NULL
- * @name_len: length of attribute @name in Unicode characters (if @name given)
- *
- * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len.
- */
-static void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni,
- const ATTR_TYPES type, ntfschar *name, const u32 name_len)
-{
- na->rl = NULL;
- na->ni = ni;
- na->type = type;
- na->name = name;
- if (name)
- na->name_len = name_len;
- else
- na->name_len = 0;
-}
-
-/**
- * ntfs_attr_init - initialize an ntfs_attr with data sizes and status
- * @na:
- * @non_resident:
- * @compressed:
- * @encrypted:
- * @sparse:
- * @allocated_size:
- * @data_size:
- * @initialized_size:
- * @compressed_size:
- * @compression_unit:
- *
- * Final initialization for an ntfs attribute.
- */
-void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
- const BOOL compressed, const BOOL encrypted, const BOOL sparse,
- const s64 allocated_size, const s64 data_size,
- const s64 initialized_size, const s64 compressed_size,
- const u8 compression_unit)
-{
- if (!NAttrInitialized(na)) {
- if (non_resident)
- NAttrSetNonResident(na);
- if (compressed)
- NAttrSetCompressed(na);
- if (encrypted)
- NAttrSetEncrypted(na);
- if (sparse)
- NAttrSetSparse(na);
- na->allocated_size = allocated_size;
- na->data_size = data_size;
- na->initialized_size = initialized_size;
- if (compressed || sparse) {
- ntfs_volume *vol = na->ni->vol;
-
- na->compressed_size = compressed_size;
- na->compression_block_clusters = 1 << compression_unit;
- na->compression_block_size = 1 << (compression_unit +
- vol->cluster_size_bits);
- na->compression_block_size_bits = ffs(
- na->compression_block_size) - 1;
- }
- NAttrSetInitialized(na);
- }
-}
-
-/**
- * ntfs_attr_open - open an ntfs attribute for access
- * @ni: open ntfs inode in which the ntfs attribute resides
- * @type: attribute type
- * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL
- * @name_len: length of attribute @name in Unicode characters (if @name given)
- *
- * Allocate a new ntfs attribute structure, initialize it with @ni, @type,
- * @name, and @name_len, then return it. Return NULL on error with
- * errno set to the error code.
- *
- * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you
- * do not care whether the attribute is named or not set @name to NULL. In
- * both those cases @name_len is not used at all.
- */
-ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
- ntfschar *name, u32 name_len)
-{
- ntfs_attr_search_ctx *ctx;
- ntfs_attr *na;
- ATTR_RECORD *a;
- struct list_head *pos;
- int err;
- BOOL cs;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
- (unsigned long long)ni->mft_no, type);
- if (!ni || !ni->vol || !ni->mrec) {
- errno = EINVAL;
- return NULL;
- }
- /* Check cache, maybe this attribute already opened? */
- list_for_each(pos, &ni->attr_cache) {
- ntfs_attr *tmp_na;
-
- tmp_na = list_entry(pos, ntfs_attr, list_entry);
- if (tmp_na->type == type && tmp_na->name_len == name_len &&
- !ntfs_ucsncmp(tmp_na->name, name, name_len)) {
- ntfs_log_trace("Found this attribute in cache, "
- "increment reference count and "
- "return it.\n");
- tmp_na->nr_references++;
- return tmp_na;
- }
- }
- /* Search failed. Properly open attrbute. */
- na = calloc(sizeof(ntfs_attr), 1);
- if (!na)
- return NULL;
- if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) {
- name = ntfs_ucsndup(name, name_len);
- if (!name) {
- err = errno;
- free(na);
- errno = err;
- return NULL;
- }
- }
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx) {
- err = errno;
- goto err_out;
- }
- if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) {
- err = errno;
- goto put_err_out;
- }
-
- a = ctx->attr;
- /*
- * Wipe the flags in case they are not zero for an attribute list
- * attribute. Windows does not complain about invalid flags and chkdsk
- * does not detect or fix them so we need to cope with it, too.
- */
- if (type == AT_ATTRIBUTE_LIST)
- a->flags = 0;
- cs = (a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? 1 : 0;
- if (!name) {
- if (a->name_length) {
- name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu(
- a->name_offset)), a->name_length);
- if (!name) {
- err = errno;
- goto put_err_out;
- }
- name_len = a->name_length;
- } else {
- name = AT_UNNAMED;
- name_len = 0;
- }
- }
- __ntfs_attr_init(na, ni, type, name, name_len);
- if (a->non_resident) {
- ntfs_attr_init(na, TRUE, (a->flags & ATTR_IS_COMPRESSED)? 1 : 0,
- (a->flags & ATTR_IS_ENCRYPTED) ? 1 : 0,
- (a->flags & ATTR_IS_SPARSE) ? 1 : 0,
- sle64_to_cpu(a->u.nonres.allocated_size),
- sle64_to_cpu(a->u.nonres.data_size),
- sle64_to_cpu(a->u.nonres.initialized_size),
- cs ? sle64_to_cpu(a->u.nonres.compressed_size) : 0,
- cs ? a->u.nonres.compression_unit : 0);
- } else {
- s64 l = le32_to_cpu(a->u.res.value_length);
- ntfs_attr_init(na, FALSE, (a->flags & ATTR_IS_COMPRESSED) ? 1:0,
- (a->flags & ATTR_IS_ENCRYPTED) ? 1 : 0,
- (a->flags & ATTR_IS_SPARSE) ? 1 : 0,
- (l + 7) & ~7, l, l, cs ? (l + 7) & ~7 : 0, 0);
- }
- ntfs_attr_put_search_ctx(ctx);
- if (NAttrEncrypted(na))
- ntfs_crypto_attr_open(na);
- list_add_tail(&na->list_entry, &ni->attr_cache);
- na->nr_references = 1;
- return na;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
-err_out:
- free(na);
- errno = err;
- return NULL;
-}
-
-/**
- * ntfs_attr_close - free an ntfs attribute structure
- * @na: ntfs attribute structure to free
- *
- * Release all memory associated with the ntfs attribute @na and then release
- * @na itself.
- */
-void ntfs_attr_close(ntfs_attr *na)
-{
- if (!na)
- return;
- na->nr_references--;
- if (na->nr_references) {
- ntfs_log_trace("There are %d more references left to "
- "this attribute.\n", na->nr_references);
- return;
- }
- ntfs_log_trace("There are no more references left to this attribute\n");
- list_del(&na->list_entry);
- if (NAttrEncrypted(na))
- ntfs_crypto_attr_close(na);
- if (NAttrNonResident(na) && na->rl)
- free(na->rl);
- /* Don't release if using an internal constant. */
- if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30)
- free(na->name);
- free(na);
-}
-
-/**
- * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute
- * @na: ntfs attribute for which to map (part of) a runlist
- * @vcn: map runlist part containing this vcn
- *
- * Map the part of a runlist containing the @vcn of the ntfs attribute @na.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
-{
- LCN lcn;
- ntfs_attr_search_ctx *ctx;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n",
- (unsigned long long)na->ni->mft_no, na->type, (long long)vcn);
-
- lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
- if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
- return 0;
-
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- return -1;
-
- /* Find the attribute in the mft record. */
- if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
- vcn, NULL, 0, ctx)) {
- runlist_element *rl;
-
- /* Decode the runlist. */
- rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr,
- na->rl);
- if (rl) {
- na->rl = rl;
- ntfs_attr_put_search_ctx(ctx);
- return 0;
- }
- }
- ntfs_attr_put_search_ctx(ctx);
- return -1;
-}
-
-/**
- * ntfs_attr_map_runlist_range - map (a part of) a runlist of an ntfs attribute
- * @na: ntfs attribute for which to map (part of) a runlist
- * @from_vcn: map runlist part starting this vcn
- * @to_vcn: map runlist part ending this vcn
- *
- * Map the part of a runlist from containing the @from_vcn to containing the
- * @to_vcn of an ntfs attribute @na. It is OK for @to_vcn to be beyond last run.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attr_map_runlist_range(ntfs_attr *na, VCN from_vcn, VCN to_vcn)
-{
- ntfs_attr_search_ctx *ctx = NULL;
- runlist *rl;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, "
- "from_vcn 0x%llx, to_vcn 0x%llx.\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)from_vcn, (long long)to_vcn);
-
- /* Map extent with @from_vcn. */
- if (ntfs_attr_map_runlist(na, from_vcn))
- goto err_out;
-
- for (rl = na->rl; rl->vcn <= to_vcn;) {
- /* Skip not interesting to us runs. */
- if (rl->lcn >= 0 || rl->lcn == LCN_HOLE || (rl->vcn +
- rl->length < from_vcn &&
- rl->lcn == LCN_RL_NOT_MAPPED)) {
- rl++;
- continue;
- }
-
- /* We reached the end of runlist, just exit. */
- if (rl->lcn == LCN_ENOENT)
- break;
-
- /* Check for errors. */
- if (rl->lcn < 0 && rl->lcn != LCN_RL_NOT_MAPPED) {
- errno = EIO;
- goto err_out;
- }
-
- /* Runlist is not mapped here. */
- if (!ctx) {
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- goto err_out;
- }
- /* Find the attribute in the mft record. */
- if (ntfs_attr_lookup(na->type, na->name, na->name_len,
- CASE_SENSITIVE, rl->vcn, NULL, 0,
- ctx))
- goto err_out;
-
- /* Decode the runlist. */
- rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr,
- na->rl);
- if (!rl)
- goto err_out;
- na->rl = rl;
- }
-
- ntfs_attr_put_search_ctx(ctx);
- ntfs_log_trace("Done.\n");
- return 0;
-err_out:
- ntfs_attr_put_search_ctx(ctx);
- ntfs_log_trace("Failed.\n");
- return -1;
-}
-
-/**
- * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute
- * @na: ntfs attribute for which to map the runlist
- *
- * Map the whole runlist of the ntfs attribute @na. For an attribute made up
- * of only one attribute extent this is the same as calling
- * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this
- * will map the runlist fragments from each of the extents thus giving access
- * to the entirety of the disk allocation of an attribute.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attr_map_whole_runlist(ntfs_attr *na)
-{
- VCN next_vcn, last_vcn, highest_vcn;
- ntfs_attr_search_ctx *ctx;
- ntfs_volume *vol = na->ni->vol;
- ATTR_RECORD *a;
- int err;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
- (unsigned long long)na->ni->mft_no, na->type);
-
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- return -1;
-
- /* Map all attribute extents one by one. */
- next_vcn = last_vcn = highest_vcn = 0;
- a = NULL;
- while (1) {
- runlist_element *rl;
-
- int not_mapped = 0;
- if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED)
- not_mapped = 1;
-
- if (ntfs_attr_lookup(na->type, na->name, na->name_len,
- CASE_SENSITIVE, next_vcn, NULL, 0, ctx))
- break;
-
- a = ctx->attr;
-
- if (not_mapped) {
- /* Decode the runlist. */
- rl = ntfs_mapping_pairs_decompress(na->ni->vol,
- a, na->rl);
- if (!rl)
- goto err_out;
- na->rl = rl;
- }
-
- /* Are we in the first extent? */
- if (!next_vcn) {
- if (a->u.nonres.lowest_vcn) {
- ntfs_log_trace("First extent of attribute has "
- "non zero lowest_vcn. "
- "Inode is corrupt.\n");
- errno = EIO;
- goto err_out;
- }
- /* Get the last vcn in the attribute. */
- last_vcn = sle64_to_cpu(a->u.nonres.allocated_size) >>
- vol->cluster_size_bits;
- }
-
- /* Get the lowest vcn for the next extent. */
- highest_vcn = sle64_to_cpu(a->u.nonres.highest_vcn);
- next_vcn = highest_vcn + 1;
-
- /* Only one extent or error, which we catch below. */
- if (next_vcn <= 0) {
- errno = ENOENT;
- break;
- }
-
- /* Avoid endless loops due to corruption. */
- if (next_vcn < sle64_to_cpu(a->u.nonres.lowest_vcn)) {
- ntfs_log_trace("Inode has corrupt attribute list "
- "attribute.\n");
- errno = EIO;
- goto err_out;
- }
- }
- if (!a) {
- if (errno == ENOENT)
- ntfs_log_trace("Attribute not found. "
- "Inode is corrupt.\n");
- else
- ntfs_log_trace("Inode is corrupt.\n");
- goto err_out;
- }
- if (highest_vcn && highest_vcn != last_vcn - 1) {
- ntfs_log_trace("Failed to load the complete run list for the "
- "attribute. Bug or corrupt inode.\n");
- ntfs_log_trace("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n",
- (long long)highest_vcn,
- (long long)last_vcn - 1);
- errno = EIO;
- goto err_out;
- }
- err = errno;
- ntfs_attr_put_search_ctx(ctx);
- if (err == ENOENT)
- return 0;
-out_now:
- errno = err;
- return -1;
-err_out:
- err = errno;
- ntfs_attr_put_search_ctx(ctx);
- goto out_now;
-}
-
-/**
- * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute
- * @na: ntfs attribute whose runlist to use for conversion
- * @vcn: vcn to convert
- *
- * Convert the virtual cluster number @vcn of an attribute into a logical
- * cluster number (lcn) of a device using the runlist @na->rl to map vcns to
- * their corresponding lcns.
- *
- * If the @vcn is not mapped yet, attempt to map the attribute extent
- * containing the @vcn and retry the vcn to lcn conversion.
- *
- * Since lcns must be >= 0, we use negative return values with special meaning:
- *
- * Return value Meaning / Description
- * ==========================================
- * -1 = LCN_HOLE Hole / not allocated on disk.
- * -3 = LCN_ENOENT There is no such vcn in the attribute.
- * -4 = LCN_EINVAL Input parameter error.
- * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory.
- */
-LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn)
-{
- LCN lcn;
- BOOL is_retry = FALSE;
-
- if (!na || !NAttrNonResident(na) || vcn < 0)
- return (LCN)LCN_EINVAL;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
- long)na->ni->mft_no, na->type);
-retry:
- /* Convert vcn to lcn. If that fails map the runlist and retry once. */
- lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
- if (lcn >= 0)
- return lcn;
- if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
- is_retry = TRUE;
- goto retry;
- }
- /*
- * If the attempt to map the runlist failed, or we are getting
- * LCN_RL_NOT_MAPPED despite having mapped the attribute extent
- * successfully, something is really badly wrong...
- */
- if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED)
- return (LCN)LCN_EIO;
- /* lcn contains the appropriate error code. */
- return lcn;
-}
-
-/**
- * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute
- * @na: ntfs attribute whose runlist to search
- * @vcn: vcn to find
- *
- * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
- * @na and return the the address of the runlist element containing the @vcn.
- *
- * Note you need to distinguish between the lcn of the returned runlist
- * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes
- * on read and allocate clusters on write. You need to update the runlist, the
- * attribute itself as well as write the modified mft record to disk.
- *
- * If there is an error return NULL with errno set to the error code. The
- * following error codes are defined:
- * EINVAL Input parameter error.
- * ENOENT There is no such vcn in the runlist.
- * ENOMEM Not enough memory.
- * EIO I/O error or corrupt metadata.
- */
-runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn)
-{
- runlist_element *rl;
- BOOL is_retry = FALSE;
-
- if (!na || !NAttrNonResident(na) || vcn < 0) {
- errno = EINVAL;
- return NULL;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)vcn);
-retry:
- rl = na->rl;
- if (!rl)
- goto map_rl;
- if (vcn < rl[0].vcn)
- goto map_rl;
- while (rl->length) {
- if (vcn < rl[1].vcn) {
- if (rl->lcn >= (LCN)LCN_HOLE)
- return rl;
- break;
- }
- rl++;
- }
- switch (rl->lcn) {
- case (LCN)LCN_RL_NOT_MAPPED:
- goto map_rl;
- case (LCN)LCN_ENOENT:
- errno = ENOENT;
- break;
- case (LCN)LCN_EINVAL:
- errno = EINVAL;
- break;
- default:
- errno = EIO;
- break;
- }
- return NULL;
-map_rl:
- /* The @vcn is in an unmapped region, map the runlist and retry. */
- if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
- is_retry = TRUE;
- goto retry;
- }
- /*
- * If we already retried or the mapping attempt failed something has
- * gone badly wrong. EINVAL and ENOENT coming from a failed mapping
- * attempt are equivalent to errors for us as they should not happen
- * in our code paths.
- */
- if (is_retry || errno == EINVAL || errno == ENOENT)
- errno = EIO;
- return NULL;
-}
-
-/**
- * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
- * @na: ntfs attribute to read from
- * @pos: byte position in the attribute to begin reading from
- * @count: number of bytes to read
- * @b: output data buffer
- *
- * This function will read @count bytes starting at offset @pos from the ntfs
- * attribute @na into the data buffer @b.
- *
- * On success, return the number of successfully read bytes. If this number is
- * lower than @count this means that the read reached end of file or that an
- * error was encountered during the read so that the read is partial. 0 means
- * end of file or nothing was read (also return 0 when @count is 0).
- *
- * On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of ntfs_pread(), or to EINVAL in case of invalid
- * arguments.
- */
-s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
-{
- s64 br, to_read, ofs, total, total2;
- ntfs_volume *vol;
- runlist_element *rl;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, "
- "count 0x%llx.\n", (unsigned long long)na->ni->mft_no,
- na->type, (long long)pos, (long long)count);
- if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- /*
- * If this is a compressed attribute it needs special treatment, but
- * only if it is non-resident.
- */
- if (NAttrCompressed(na) && NAttrNonResident(na))
- return ntfs_compressed_attr_pread(na, pos, count, b);
- /*
- * Encrypted non-resident attributes are not supported. We return
- * access denied, which is what Windows NT4 does, too.
- */
- if (NAttrEncrypted(na) && NAttrNonResident(na))
- return ntfs_crypto_attr_pread(na, pos, count, b);
-
- vol = na->ni->vol;
- if (!count)
- return 0;
- /* Truncate reads beyond end of attribute. */
- if (pos + count > na->data_size) {
- if (pos >= na->data_size)
- return 0;
- count = na->data_size - pos;
- }
- /* If it is a resident attribute, get the value from the mft record. */
- if (!NAttrNonResident(na)) {
- ntfs_attr_search_ctx *ctx;
- char *val;
-
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- return -1;
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
- 0, NULL, 0, ctx)) {
- int eo;
-res_err_out:
- eo = errno;
- ntfs_attr_put_search_ctx(ctx);
- errno = eo;
- return -1;
- }
- val = (char*)ctx->attr + le16_to_cpu(ctx->attr->u.res.value_offset);
- if (val < (char*)ctx->attr || val +
- le32_to_cpu(ctx->attr->u.res.value_length) >
- (char*)ctx->mrec + vol->mft_record_size) {
- errno = EIO;
- goto res_err_out;
- }
- memcpy(b, val + pos, count);
- ntfs_attr_put_search_ctx(ctx);
- return count;
- }
- total = total2 = 0;
- /* Zero out reads beyond initialized size. */
- if (pos + count > na->initialized_size) {
- if (pos >= na->initialized_size) {
- memset(b, 0, count);
- return count;
- }
- total2 = pos + count - na->initialized_size;
- count -= total2;
- memset((u8*)b + count, 0, total2);
- }
- /* Find the runlist element containing the vcn. */
- rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
- if (!rl) {
- /*
- * If the vcn is not present it is an out of bounds read.
- * However, we already truncated the read to the data_size,
- * so getting this here is an error.
- */
- if (errno == ENOENT)
- errno = EIO;
- return -1;
- }
- /*
- * Gather the requested data into the linear destination buffer. Note,
- * a partial final vcn is taken care of by the @count capping of read
- * length.
- */
- ofs = pos - (rl->vcn << vol->cluster_size_bits);
- for (; count; rl++, ofs = 0) {
- if (rl->lcn == LCN_RL_NOT_MAPPED) {
- rl = ntfs_attr_find_vcn(na, rl->vcn);
- if (!rl) {
- if (errno == ENOENT)
- errno = EIO;
- goto rl_err_out;
- }
- /* Needed for case when runs merged. */
- ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
- }
- if (!rl->length)
- goto rl_err_out;
- if (rl->lcn < (LCN)0) {
- if (rl->lcn != (LCN)LCN_HOLE)
- goto rl_err_out;
- /* It is a hole, just zero the matching @b range. */
- to_read = min(count, (rl->length <<
- vol->cluster_size_bits) - ofs);
- memset(b, 0, to_read);
- /* Update progress counters. */
- total += to_read;
- count -= to_read;
- b = (u8*)b + to_read;
- continue;
- }
- /* It is a real lcn, read it into @dst. */
- to_read = min(count, (rl->length << vol->cluster_size_bits) -
- ofs);
-retry:
- ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, "
- "lcn 0x%llx, ofs 0x%llx.\n", to_read, rl->vcn,
- rl->lcn, ofs);
- br = ntfs_pread(vol->u.dev, (rl->lcn << vol->cluster_size_bits) +
- ofs, to_read, b);
- /* If everything ok, update progress counters and continue. */
- if (br > 0) {
- total += br;
- count -= br;
- b = (u8*)b + br;
- continue;
- }
- /* If the syscall was interrupted, try again. */
- if (br == (s64)-1 && errno == EINTR)
- goto retry;
- if (total)
- return total;
- if (!br)
- errno = EIO;
- return -1;
- }
- /* Finally, return the number of bytes read. */
- return total + total2;
-rl_err_out:
- if (total)
- return total;
- errno = EIO;
- return -1;
-}
-
-/**
- * ntfs_attr_pwrite - positioned write to an ntfs attribute
- * @na: ntfs attribute to write to
- * @pos: position in the attribute to write to
- * @count: number of bytes to write
- * @b: data buffer to write to disk
- *
- * This function will write @count bytes from data buffer @b to ntfs attribute
- * @na at position @pos.
- *
- * On success, return the number of successfully written bytes. If this number
- * is lower than @count this means that an error was encountered during the
- * write so that the write is partial. 0 means nothing was written (also return
- * 0 when @count is 0).
- *
- * On error and nothing has been written, return -1 with errno set
- * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
- * invalid arguments.
- */
-s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
-{
- s64 written, to_write, ofs, total, old_initialized_size, old_data_size;
- VCN update_from = -1;
- ntfs_volume *vol;
- ntfs_attr_search_ctx *ctx = NULL;
- runlist_element *rl;
- int eo;
- struct {
- unsigned int undo_initialized_size : 1;
- unsigned int undo_data_size : 1;
- unsigned int update_mapping_pairs : 1;
- } need_to = { 0, 0, 0 };
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, "
- "count 0x%llx.\n", na->ni->mft_no, na->type,
- (long long)pos, (long long)count);
- if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- vol = na->ni->vol;
- /*
- * Encrypted non-resident attributes are not supported. We return
- * access denied, which is what Windows NT4 does, too.
- */
- if (NAttrEncrypted(na) && NAttrNonResident(na)) {
- errno = EACCES;
- return -1;
- }
- /* If this is a compressed attribute it needs special treatment. */
- if (NAttrCompressed(na)) {
- // TODO: Implement writing compressed attributes! (AIA)
- // return ntfs_attr_pwrite_compressed(ntfs_attr *na,
- // const s64 pos, s64 count, void *b);
- errno = EOPNOTSUPP;
- return -1;
- }
- if (!count)
- return 0;
- /* If the write reaches beyond the end, extend the attribute. */
- old_data_size = na->data_size;
- if (pos + count > na->data_size) {
- if (__ntfs_attr_truncate(na, pos + count, FALSE)) {
- eo = errno;
- ntfs_log_trace("Attribute extend failed.\n");
- errno = eo;
- return -1;
- }
- need_to.undo_data_size = 1;
- }
- old_initialized_size = na->initialized_size;
- /* If it is a resident attribute, write the data to the mft record. */
- if (!NAttrNonResident(na)) {
- char *val;
-
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- goto err_out;
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
- 0, NULL, 0, ctx))
- goto err_out;
- val = (char*)ctx->attr + le16_to_cpu(ctx->attr->u.res.value_offset);
- if (val < (char*)ctx->attr || val +
- le32_to_cpu(ctx->attr->u.res.value_length) >
- (char*)ctx->mrec + vol->mft_record_size) {
- errno = EIO;
- goto err_out;
- }
- memcpy(val + pos, b, count);
- if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
- ctx->mrec)) {
- /*
- * NOTE: We are in a bad state at this moment. We have
- * dirtied the mft record but we failed to commit it to
- * disk. Since we have read the mft record ok before,
- * it is unlikely to fail writing it, so is ok to just
- * return error here... (AIA)
- */
- goto err_out;
- }
- ntfs_attr_put_search_ctx(ctx);
- return count;
- }
- total = 0;
- /* Handle writes beyond initialized_size. */
- if (pos + count > na->initialized_size) {
- /*
- * Map runlist between initialized size and place we start
- * writing at.
- */
- if (ntfs_attr_map_runlist_range(na, na->initialized_size >>
- vol->cluster_size_bits,
- pos >> vol->cluster_size_bits))
- goto err_out;
- /* Set initialized_size to @pos + @count. */
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- goto err_out;
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
- 0, NULL, 0, ctx))
- goto err_out;
- /* If write starts beyond initialized_size, zero the gap. */
- if (pos > na->initialized_size && ntfs_rl_fill_zero(vol,
- na->rl, na->initialized_size,
- pos - na->initialized_size))
- goto err_out;
-
- ctx->attr->u.nonres.initialized_size = cpu_to_sle64(pos + count);
- if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
- ctx->mrec)) {
- /*
- * Undo the change in the in-memory copy and send it
- * back for writing.
- */
- ctx->attr->u.nonres.initialized_size =
- cpu_to_sle64(old_initialized_size);
- ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
- ctx->mrec);
- goto err_out;
- }
- na->initialized_size = pos + count;
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
- /*
- * NOTE: At this point the initialized_size in the mft record
- * has been updated BUT there is random data on disk thus if
- * we decide to abort, we MUST change the initialized_size
- * again.
- */
- need_to.undo_initialized_size = 1;
- }
- /* Find the runlist element containing the vcn. */
- rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
- if (!rl) {
- /*
- * If the vcn is not present it is an out of bounds write.
- * However, we already extended the size of the attribute,
- * so getting this here must be an error of some kind.
- */
- if (errno == ENOENT)
- errno = EIO;
- goto err_out;
- }
- /*
- * Scatter the data from the linear data buffer to the volume. Note, a
- * partial final vcn is taken care of by the @count capping of write
- * length.
- */
- ofs = pos - (rl->vcn << vol->cluster_size_bits);
- for (; count; rl++, ofs = 0) {
- if (rl->lcn == LCN_RL_NOT_MAPPED) {
- rl = ntfs_attr_find_vcn(na, rl->vcn);
- if (!rl) {
- if (errno == ENOENT)
- errno = EIO;
- goto rl_err_out;
- }
- /* Needed for case when runs merged. */
- ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
- }
- if (!rl->length) {
- errno = EIO;
- goto rl_err_out;
- }
- if (rl->lcn < (LCN)0) {
- LCN lcn_seek_from = -1;
- runlist *rlc;
- VCN cur_vcn, from_vcn;
-
- if (rl->lcn != (LCN)LCN_HOLE) {
- errno = EIO;
- goto rl_err_out;
- }
-
- to_write = min(count, (rl->length <<
- vol->cluster_size_bits) - ofs);
-
- /* Instantiate the hole. */
- cur_vcn = rl->vcn;
- from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits);
- ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n",
- cur_vcn);
- /*
- * Map whole runlist to be able update mapping pairs
- * later.
- */
- if (ntfs_attr_map_whole_runlist(na))
- goto err_out;
- /*
- * Restore @rl, it probably get lost during runlist
- * mapping.
- */
- rl = ntfs_attr_find_vcn(na, cur_vcn);
- if (!rl) {
- ntfs_log_error("BUG! Failed to find run after "
- "mapping whole runlist. Please "
- "report to the %s.\n",
- NTFS_DEV_LIST);
- errno = EIO;
- goto err_out;
- }
- /*
- * Search backwards to find the best lcn to start
- * seek from.
- */
- rlc = rl;
- while (rlc->vcn) {
- rlc--;
- if (rlc->lcn >= 0) {
- lcn_seek_from = rlc->lcn +
- (from_vcn - rlc->vcn);
- break;
- }
- }
- if (lcn_seek_from == -1) {
- /* Backwards search failed, search forwards. */
- rlc = rl;
- while (rlc->length) {
- rlc++;
- if (rlc->lcn >= 0) {
- lcn_seek_from = rlc->lcn -
- (rlc->vcn - from_vcn);
- if (lcn_seek_from < -1)
- lcn_seek_from = -1;
- break;
- }
- }
- }
- /* Allocate clusters to instantiate the hole. */
- rlc = ntfs_cluster_alloc(vol, from_vcn,
- ((ofs + to_write - 1) >>
- vol->cluster_size_bits) + 1 +
- rl->vcn - from_vcn,
- lcn_seek_from, DATA_ZONE);
- if (!rlc) {
- eo = errno;
- ntfs_log_trace("Failed to allocate clusters "
- "for hole instantiating.\n");
- errno = eo;
- goto err_out;
- }
- /* Merge runlists. */
- rl = ntfs_runlists_merge(na->rl, rlc);
- if (!rl) {
- eo = errno;
- ntfs_log_trace("Failed to merge runlists.\n");
- if (ntfs_cluster_free_from_rl(vol, rlc)) {
- ntfs_log_trace("Failed to free just "
- "allocated clusters. Leaving "
- "inconsistent metadata. "
- "Run chkdsk\n");
- }
- errno = eo;
- goto err_out;
- }
- na->rl = rl;
- need_to.update_mapping_pairs = 1;
- if (update_from == -1)
- update_from = from_vcn;
- rl = ntfs_attr_find_vcn(na, cur_vcn);
- if (!rl) {
- /*
- * It's definitely a BUG, if we failed to find
- * @cur_vcn, because we missed it during
- * instantiating of the hole.
- */
- ntfs_log_error("BUG! Failed to find run after "
- "instantiating. Please report "
- "to the %s.\n", NTFS_DEV_LIST);
- errno = EIO;
- goto err_out;
- }
- /* If leaved part of the hole go to the next run. */
- if (rl->lcn < 0)
- rl++;
- /* Now LCN shoudn't be less than 0. */
- if (rl->lcn < 0) {
- ntfs_log_error("BUG! LCN is lesser than 0. "
- "Please report to the %s.\n",
- NTFS_DEV_LIST);
- errno = EIO;
- goto err_out;
- }
- if (rl->vcn < cur_vcn) {
- /*
- * Clusters that replaced hole are merged with
- * previous run, so we need to update offset.
- */
- ofs += (cur_vcn - rl->vcn) <<
- vol->cluster_size_bits;
- }
- if (rl->vcn > cur_vcn) {
- /*
- * We left part of the hole, so update we need
- * to update offset
- */
- ofs -= (rl->vcn - cur_vcn) <<
- vol->cluster_size_bits;
- }
- /*
- * Clear region between start of @rl->vcn cluster and
- * @ofs if necessary.
- */
- if (ofs && ntfs_rl_fill_zero(vol, na->rl, rl->vcn <<
- vol->cluster_size_bits, ofs))
- goto err_out;
- }
- /* It is a real lcn, write it to the volume. */
- to_write = min(count, (rl->length << vol->cluster_size_bits) -
- ofs);
-retry:
- ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx,"
- " ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn,
- ofs);
- if (!NVolReadOnly(vol)) {
- s64 pos = (rl->lcn << vol->cluster_size_bits) + ofs;
- int bsize = 4096; /* FIXME: Test whether we need
- PAGE_SIZE here. Eg., on IA64. */
- /*
- * Write 4096 size blocks if it's possible. This will
- * cause the kernel not to seek and read disk blocks for
- * filling the end of the buffer which increases write
- * speed.
- */
- if (vol->cluster_size >= bsize && !(ofs % bsize) &&
- (to_write % bsize) && ofs + to_write ==
- na->initialized_size) {
- char *cb;
- s64 rounded = (to_write + bsize - 1) &
- ~(bsize - 1);
-
- cb = ntfs_malloc(rounded);
- if (!cb)
- goto err_out;
- memcpy(cb, b, to_write);
- memset(cb + to_write, 0, rounded - to_write);
- written = ntfs_pwrite(vol->u.dev, pos, rounded,
- cb);
- if (written > to_write)
- written = to_write;
- free(cb);
- } else
- written = ntfs_pwrite(vol->u.dev, pos, to_write,
- b);
- } else
- written = to_write;
- /* If everything ok, update progress counters and continue. */
- if (written > 0) {
- total += written;
- count -= written;
- b = (const u8*)b + written;
- continue;
- }
- /* If the syscall was interrupted, try again. */
- if (written == (s64)-1 && errno == EINTR)
- goto retry;
- if (!written)
- errno = EIO;
- goto rl_err_out;
- }
-done:
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- /* Update mapping pairs if needed. */
- if (need_to.update_mapping_pairs) {
- if (ntfs_attr_update_mapping_pairs(na, update_from)) {
- /* FIXME: We want rollback here. */
- ntfs_log_perror("%s(): Failed to update mapping pairs. "
- "Leaving inconsistent metadata. "
- "Run chkdsk!", "ntfs_attr_pwrite");
- errno = EIO;
- return -1;
- }
- }
- /* Finally, return the number of bytes written. */
- return total;
-rl_err_out:
- eo = errno;
- if (total) {
- if (need_to.undo_initialized_size) {
- if (pos + total > na->initialized_size)
- goto done;
- /*
- * TODO: Need to try to change initialized_size. If it
- * succeeds goto done, otherwise goto err_out. (AIA)
- */
- errno = EOPNOTSUPP;
- goto err_out;
- }
- goto done;
- }
- errno = eo;
-err_out:
- eo = errno;
- if (need_to.undo_initialized_size) {
- int err;
-
- err = 0;
- if (!ctx) {
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- err = 1;
- } else
- ntfs_attr_reinit_search_ctx(ctx);
- if (ctx) {
- err = ntfs_attr_lookup(na->type, na->name,
- na->name_len, 0, 0, NULL, 0, ctx);
- if (!err) {
- na->initialized_size = old_initialized_size;
- ctx->attr->u.nonres.initialized_size = cpu_to_sle64(
- old_initialized_size);
- err = ntfs_mft_record_write(vol,
- ctx->ntfs_ino->mft_no,
- ctx->mrec);
- }
- }
- if (err) {
- /*
- * FIXME: At this stage could try to recover by filling
- * old_initialized_size -> new_initialized_size with
- * data or at least zeroes. (AIA)
- */
- ntfs_log_error("Eeek! Failed to recover from error. "
- "Leaving metadata in inconsistent "
- "state! Run chkdsk!\n");
- }
- }
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- /* Update mapping pairs if needed. */
- if (need_to.update_mapping_pairs)
- ntfs_attr_update_mapping_pairs(na, update_from);
- /* Restore original data_size if needed. */
- if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))
- ntfs_log_trace("Failed to restore data_size.\n");
- errno = eo;
- return -1;
-}
-
-/**
- * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read
- * @na: multi sector transfer protected ntfs attribute to read from
- * @pos: byte position in the attribute to begin reading from
- * @bk_cnt: number of mst protected blocks to read
- * @bk_size: size of each mst protected block in bytes
- * @dst: output data buffer
- *
- * This function will read @bk_cnt blocks of size @bk_size bytes each starting
- * at offset @pos from the ntfs attribute @na into the data buffer @b.
- *
- * On success, the multi sector transfer fixups are applied and the number of
- * read blocks is returned. If this number is lower than @bk_cnt this means
- * that the read has either reached end of attribute or that an error was
- * encountered during the read so that the read is partial. 0 means end of
- * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0).
- *
- * On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid
- * arguments.
- *
- * NOTE: If an incomplete multi sector transfer is detected the magic is
- * changed to BAAD but no error is returned, i.e. it is possible that any of
- * the returned blocks have multi sector transfer errors. This should be
- * detected by the caller by checking each block with is_baad_recordp(&block).
- * The reasoning is that we want to fixup as many blocks as possible and we
- * want to return even bad ones to the caller so, e.g. in case of ntfsck, the
- * errors can be repaired.
- */
-s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
- const u32 bk_size, void *dst)
-{
- s64 br;
- u8 *end;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, "
- "pos 0x%llx.\n", (unsigned long long)na->ni->mft_no,
- na->type, (long long)pos);
- if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
- errno = EINVAL;
- return -1;
- }
- br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst);
- if (br <= 0)
- return br;
- br /= bk_size;
- for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst +
- bk_size)
- ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size);
- /* Finally, return the number of blocks read. */
- return br;
-}
-
-/**
- * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write
- * @na: multi sector transfer protected ntfs attribute to write to
- * @pos: position in the attribute to write to
- * @bk_cnt: number of mst protected blocks to write
- * @bk_size: size of each mst protected block in bytes
- * @src: data buffer to write to disk
- *
- * This function will write @bk_cnt blocks of size @bk_size bytes each from
- * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na
- * at position @pos.
- *
- * On success, return the number of successfully written blocks. If this number
- * is lower than @bk_cnt this means that an error was encountered during the
- * write so that the write is partial. 0 means nothing was written (also
- * return 0 when @bk_cnt or @bk_size are 0).
- *
- * On error and nothing has been written, return -1 with errno set
- * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case
- * of invalid arguments.
- *
- * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
- * deprotect algorithm (no checking). This saves us from making a copy before
- * the write and at the same time causes the usn to be incremented in the
- * buffer. This conceptually fits in better with the idea that cached data is
- * always deprotected and protection is performed when the data is actually
- * going to hit the disk and the cache is immediately deprotected again
- * simulating an mst read on the written data. This way cache coherency is
- * achieved.
- */
-s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt,
- const u32 bk_size, void *src)
-{
- s64 written, i;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, "
- "pos 0x%llx.\n", (unsigned long long)na->ni->mft_no,
- na->type, (long long)pos);
- if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
- errno = EINVAL;
- return -1;
- }
- if (!bk_cnt)
- return 0;
- /* Prepare data for writing. */
- for (i = 0; i < bk_cnt; ++i) {
- int err;
-
- err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
- ((u8*)src + i * bk_size), bk_size);
- if (err < 0) {
- /* Abort write at this position. */
- if (!i)
- return err;
- bk_cnt = i;
- break;
- }
- }
- /* Write the prepared data. */
- written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src);
- /* Quickly deprotect the data again. */
- for (i = 0; i < bk_cnt; ++i)
- ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i *
- bk_size));
- if (written <= 0)
- return written;
- /* Finally, return the number of complete blocks written. */
- return written / bk_size;
-}
-
-/**
- * ntfs_attr_find - find (next) attribute in mft record
- * @type: attribute type to find
- * @name: attribute name to find (optional, i.e. NULL means don't care)
- * @name_len: attribute name length (only needed if @name present)
- * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @val: attribute value to find (optional, resident attributes only)
- * @val_len: attribute value length
- * @ctx: search context with mft record and attribute to search from
- *
- * You shouldn't need to call this function directly. Use lookup_attr() instead.
- *
- * ntfs_attr_find() takes a search context @ctx as parameter and searches the
- * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
- * attribute of @type, optionally @name and @val. If found, ntfs_attr_find()
- * returns 0 and @ctx->attr will point to the found attribute.
- *
- * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and
- * @ctx->attr will point to the attribute before which the attribute being
- * searched for would need to be inserted if such an action were to be desired.
- *
- * On actual error, ntfs_attr_find() returns -1 with errno set to the error
- * code but not to ENOENT. In this case @ctx->attr is undefined and in
- * particular do not rely on it not changing.
- *
- * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
- * is FALSE, the search begins after @ctx->attr.
- *
- * If @type is AT_UNUSED, return the first found attribute, i.e. one can
- * enumerate all attributes by setting @type to AT_UNUSED and then calling
- * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to
- * indicate that there are no more entries. During the enumeration, each
- * successful call of ntfs_attr_find() will return the next attribute in the
- * mft record @ctx->mrec.
- *
- * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT.
- * AT_END is not a valid attribute, its length is zero for example, thus it is
- * safer to return error instead of success in this case. This also allows us
- * to interoperate cleanly with ntfs_external_attr_find().
- *
- * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
- * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
- * match both named and unnamed attributes.
- *
- * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and
- * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
- * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at
- * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case
- * sensitive. When @name is present, @name_len is the @name length in Unicode
- * characters.
- *
- * If @name is not present (NULL), we assume that the unnamed attribute is
- * being searched for.
- *
- * Finally, the resident attribute value @val is looked for, if present.
- * If @val is not present (NULL), @val_len is ignored.
- *
- * ntfs_attr_find() only searches the specified mft record and it ignores the
- * presence of an attribute list attribute (unless it is the one being searched
- * for, obviously). If you need to take attribute lists into consideration, use
- * ntfs_attr_lookup() instead (see below). This also means that you cannot use
- * ntfs_attr_find() to search for extent records of non-resident attributes, as
- * extents with lowest_vcn != 0 are usually described by the attribute list
- * attribute only. - Note that it is possible that the first extent is only in
- * the attribute list while the last extent is in the base mft record, so don't
- * rely on being able to find the first extent in the base mft record.
- *
- * Warning: Never use @val when looking for attribute types which can be
- * non-resident as this most likely will result in a crash!
- */
-static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
- const u32 name_len, const IGNORE_CASE_BOOL ic,
- const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
-{
- ATTR_RECORD *a;
- ntfs_volume *vol;
- ntfschar *upcase;
- u32 upcase_len;
-
- ntfs_log_trace("Entering for attribute type 0x%x.\n", type);
-
- if (ctx->ntfs_ino) {
- vol = ctx->ntfs_ino->vol;
- upcase = vol->upcase;
- upcase_len = vol->upcase_len;
- } else {
- if (name && name != AT_UNNAMED) {
- errno = EINVAL;
- return -1;
- }
- vol = NULL;
- upcase = NULL;
- upcase_len = 0;
- }
- /*
- * Iterate over attributes in mft record starting at @ctx->attr, or the
- * attribute following that, if @ctx->is_first is TRUE.
- */
- if (ctx->is_first) {
- a = ctx->attr;
- ctx->is_first = FALSE;
- } else
- a = (ATTR_RECORD*)((char*)ctx->attr +
- le32_to_cpu(ctx->attr->length));
- for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
- if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
- le32_to_cpu(ctx->mrec->bytes_allocated))
- break;
- ctx->attr = a;
- if (((type != AT_UNUSED) && (le32_to_cpu(a->type) >
- le32_to_cpu(type))) ||
- (a->type == AT_END)) {
- errno = ENOENT;
- return -1;
- }
- if (!a->length)
- break;
- /* If this is an enumeration return this attribute. */
- if (type == AT_UNUSED)
- return 0;
- if (a->type != type)
- continue;
- /*
- * If @name is AT_UNNAMED we want an unnamed attribute.
- * If @name is present, compare the two names.
- * Otherwise, match any attribute.
- */
- if (name == AT_UNNAMED) {
- /* The search failed if the found attribute is named. */
- if (a->name_length) {
- errno = ENOENT;
- return -1;
- }
- } else if (name && !ntfs_names_are_equal(name, name_len,
- (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, ic, upcase, upcase_len)) {
- register int rc;
-
- rc = ntfs_names_collate(name, name_len,
- (ntfschar*)((char*)a +
- le16_to_cpu(a->name_offset)),
- a->name_length, 1, IGNORE_CASE,
- upcase, upcase_len);
- /*
- * If @name collates before a->name, there is no
- * matching attribute.
- */
- if (rc == -1) {
- errno = ENOENT;
- return -1;
- }
- /* If the strings are not equal, continue search. */
- if (rc)
- continue;
- rc = ntfs_names_collate(name, name_len,
- (ntfschar*)((char*)a +
- le16_to_cpu(a->name_offset)),
- a->name_length, 1, CASE_SENSITIVE,
- upcase, upcase_len);
- if (rc == -1) {
- errno = ENOENT;
- return -1;
- }
- if (rc)
- continue;
- }
- /*
- * The names match or @name not present and attribute is
- * unnamed. If no @val specified, we have found the attribute
- * and are done.
- */
- if (!val)
- return 0;
- /* @val is present; compare values. */
- else {
- register int rc;
-
- rc = memcmp(val, (char*)a +le16_to_cpu(a->u.res.value_offset),
- min(val_len,
- le32_to_cpu(a->u.res.value_length)));
- /*
- * If @val collates before the current attribute's
- * value, there is no matching attribute.
- */
- if (!rc) {
- register u32 avl;
- avl = le32_to_cpu(a->u.res.value_length);
- if (val_len == avl)
- return 0;
- if (val_len < avl) {
- errno = ENOENT;
- return -1;
- }
- } else if (rc < 0) {
- errno = ENOENT;
- return -1;
- }
- }
- }
- ntfs_log_debug("ntfs_attr_find(): File is corrupt. Run chkdsk.\n");
- errno = EIO;
- return -1;
-}
-
-/**
- * ntfs_external_attr_find - find an attribute in the attribute list of an inode
- * @type: attribute type to find
- * @name: attribute name to find (optional, i.e. NULL means don't care)
- * @name_len: attribute name length (only needed if @name present)
- * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
- * @val: attribute value to find (optional, resident attributes only)
- * @val_len: attribute value length
- * @ctx: search context with mft record and attribute to search from
- *
- * You shouldn't need to call this function directly. Use ntfs_attr_lookup()
- * instead.
- *
- * Find an attribute by searching the attribute list for the corresponding
- * attribute list entry. Having found the entry, map the mft record for read
- * if the attribute is in a different mft record/inode, find the attribute in
- * there and return it.
- *
- * If @type is AT_UNUSED, return the first found attribute, i.e. one can
- * enumerate all attributes by setting @type to AT_UNUSED and then calling
- * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to
- * ENOENT to indicate that there are no more entries. During the enumeration,
- * each successful call of ntfs_external_attr_find() will return the next
- * attribute described by the attribute list of the base mft record described
- * by the search context @ctx.
- *
- * If @type is AT_END, seek to the end of the base mft record ignoring the
- * attribute list completely and return -1 with errno set to ENOENT. AT_END is
- * not a valid attribute, its length is zero for example, thus it is safer to
- * return error instead of success in this case.
- *
- * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
- * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
- * match both named and unnamed attributes.
- *
- * On first search @ctx->ntfs_ino must be the inode of the base mft record and
- * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx().
- * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too
- * (@ctx->base_ntfs_ino is then the base inode).
- *
- * After finishing with the attribute/mft record you need to call
- * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
- * mapped extent inodes, etc).
- *
- * Return 0 if the search was successful and -1 if not, with errno set to the
- * error code.
- *
- * On success, @ctx->attr is the found attribute, it is in mft record
- * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this
- * attribute with @ctx->base_* being the base mft record to which @ctx->attr
- * belongs.
- *
- * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the
- * attribute which collates just after the attribute being searched for in the
- * base ntfs inode, i.e. if one wants to add the attribute to the mft record
- * this is the correct place to insert it into, and if there is not enough
- * space, the attribute should be placed in an extent mft record.
- * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list
- * at which the new attribute's attribute list entry should be inserted. The
- * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL.
- * The only exception to this is when @type is AT_END, in which case
- * @ctx->al_entry is set to NULL also (see above).
- *
- * The following error codes are defined:
- * ENOENT Attribute not found, not an error as such.
- * EINVAL Invalid arguments.
- * EIO I/O error or corrupt data structures found.
- * ENOMEM Not enough memory to allocate necessary buffers.
- */
-static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name,
- const u32 name_len, const IGNORE_CASE_BOOL ic,
- const VCN lowest_vcn, const u8 *val, const u32 val_len,
- ntfs_attr_search_ctx *ctx)
-{
- ntfs_inode *base_ni, *ni;
- ntfs_volume *vol;
- ATTR_LIST_ENTRY *al_entry, *next_al_entry;
- u8 *al_start, *al_end;
- ATTR_RECORD *a;
- ntfschar *al_name;
- u32 al_name_len;
- BOOL is_first_search = FALSE;
-
- ni = ctx->ntfs_ino;
- base_ni = ctx->base_ntfs_ino;
- ntfs_log_trace("Entering for inode 0x%llx, attribute type 0x%x.\n",
- (unsigned long long)ni->mft_no, type);
- if (!base_ni) {
- /* First call happens with the base mft record. */
- base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
- ctx->base_mrec = ctx->mrec;
- }
- if (ni == base_ni)
- ctx->base_attr = ctx->attr;
- if (type == AT_END)
- goto not_found;
- vol = base_ni->vol;
- al_start = base_ni->attr_list;
- al_end = al_start + base_ni->attr_list_size;
- if (!ctx->al_entry) {
- ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
- is_first_search = TRUE;
- }
- /*
- * Iterate over entries in attribute list starting at @ctx->al_entry,
- * or the entry following that, if @ctx->is_first is TRUE.
- */
- if (ctx->is_first) {
- al_entry = ctx->al_entry;
- ctx->is_first = FALSE;
- /*
- * If an enumeration and the first attribute is higher than
- * the attribute list itself, need to return the attribute list
- * attribute.
- */
- if ((type == AT_UNUSED) && is_first_search &&
- le32_to_cpu(al_entry->type) >
- le32_to_cpu(AT_ATTRIBUTE_LIST))
- goto find_attr_list_attr;
- } else {
- al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +
- le16_to_cpu(ctx->al_entry->length));
- /*
- * If this is an enumeration and the attribute list attribute
- * is the next one in the enumeration sequence, just return the
- * attribute list attribute from the base mft record as it is
- * not listed in the attribute list itself.
- */
- if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) <
- le32_to_cpu(AT_ATTRIBUTE_LIST) &&
- le32_to_cpu(al_entry->type) >
- le32_to_cpu(AT_ATTRIBUTE_LIST)) {
- int rc;
-find_attr_list_attr:
-
- /* Check for bogus calls. */
- if (name || name_len || val || val_len || lowest_vcn) {
- errno = EINVAL;
- return -1;
- }
-
- /* We want the base record. */
- ctx->ntfs_ino = base_ni;
- ctx->mrec = ctx->base_mrec;
- ctx->is_first = TRUE;
- /* Sanity checks are performed elsewhere. */
- ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
- le16_to_cpu(ctx->mrec->attrs_offset));
-
- /* Find the attribute list attribute. */
- rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0,
- IGNORE_CASE, NULL, 0, ctx);
-
- /*
- * Setup the search context so the correct
- * attribute is returned next time round.
- */
- ctx->al_entry = al_entry;
- ctx->is_first = TRUE;
-
- /* Got it. Done. */
- if (!rc)
- return 0;
-
- /* Error! If other than not found return it. */
- if (errno != ENOENT)
- return rc;
-
- /* Not found?!? Absurd! Must be a bug... )-: */
- ntfs_log_trace("BUG! Attribute list attribute not "
- "found but it exists! "
- "Returning error (EINVAL).\n");
- errno = EINVAL;
- return -1;
- }
- }
- for (;; al_entry = next_al_entry) {
- /* Out of bounds check. */
- if ((u8*)al_entry < base_ni->attr_list ||
- (u8*)al_entry > al_end)
- break; /* Inode is corrupt. */
- ctx->al_entry = al_entry;
- /* Catch the end of the attribute list. */
- if ((u8*)al_entry == al_end)
- goto not_found;
- if (!al_entry->length)
- break;
- if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
- le16_to_cpu(al_entry->length) > al_end)
- break;
- next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
- le16_to_cpu(al_entry->length));
- if (type != AT_UNUSED) {
- if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
- goto not_found;
- if (type != al_entry->type)
- continue;
- }
- al_name_len = al_entry->name_length;
- al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);
- /*
- * If !@type we want the attribute represented by this
- * attribute list entry.
- */
- if (type == AT_UNUSED)
- goto is_enumeration;
- /*
- * If @name is AT_UNNAMED we want an unnamed attribute.
- * If @name is present, compare the two names.
- * Otherwise, match any attribute.
- */
- if (name == AT_UNNAMED) {
- if (al_name_len)
- goto not_found;
- } else if (name && !ntfs_names_are_equal(al_name, al_name_len,
- name, name_len, ic, vol->upcase,
- vol->upcase_len)) {
- register int rc;
-
- rc = ntfs_names_collate(name, name_len, al_name,
- al_name_len, 1, IGNORE_CASE,
- vol->upcase, vol->upcase_len);
- /*
- * If @name collates before al_name, there is no
- * matching attribute.
- */
- if (rc == -1)
- goto not_found;
- /* If the strings are not equal, continue search. */
- if (rc)
- continue;
- /*
- * FIXME: Reverse engineering showed 0, IGNORE_CASE but
- * that is inconsistent with ntfs_attr_find(). The
- * subsequent rc checks were also different. Perhaps I
- * made a mistake in one of the two. Need to recheck
- * which is correct or at least see what is going
- * on... (AIA)
- */
- rc = ntfs_names_collate(name, name_len, al_name,
- al_name_len, 1, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len);
- if (rc == -1)
- goto not_found;
- if (rc)
- continue;
- }
- /*
- * The names match or @name not present and attribute is
- * unnamed. Now check @lowest_vcn. Continue search if the
- * next attribute list entry still fits @lowest_vcn. Otherwise
- * we have reached the right one or the search has failed.
- */
- if (lowest_vcn && (u8*)next_al_entry >= al_start &&
- (u8*)next_al_entry + 6 < al_end &&
- (u8*)next_al_entry + le16_to_cpu(
- next_al_entry->length) <= al_end &&
- sle64_to_cpu(next_al_entry->lowest_vcn) <=
- lowest_vcn &&
- next_al_entry->type == al_entry->type &&
- next_al_entry->name_length == al_name_len &&
- ntfs_names_are_equal((ntfschar*)((char*)
- next_al_entry +
- next_al_entry->name_offset),
- next_al_entry->name_length,
- al_name, al_name_len, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len))
- continue;
-is_enumeration:
- if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
- if (MSEQNO_LE(al_entry->mft_reference) !=
- le16_to_cpu(
- ni->mrec->sequence_number)) {
- ntfs_log_debug("Found stale mft reference in "
- "attribute list!\n");
- break;
- }
- } else { /* Mft references do not match. */
- /* Do we want the base record back? */
- if (MREF_LE(al_entry->mft_reference) ==
- base_ni->mft_no) {
- ni = ctx->ntfs_ino = base_ni;
- ctx->mrec = ctx->base_mrec;
- } else {
- /* We want an extent record. */
- ni = ntfs_extent_inode_open(base_ni,
- al_entry->mft_reference);
- if (!ni) {
- ntfs_log_perror("Failed to map extent "
- "inode");
- break;
- }
- ctx->ntfs_ino = ni;
- ctx->mrec = ni->mrec;
- }
- }
- a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +
- le16_to_cpu(ctx->mrec->attrs_offset));
- /*
- * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the
- * mft record containing the attribute represented by the
- * current al_entry.
- *
- * We could call into ntfs_attr_find() to find the right
- * attribute in this mft record but this would be less
- * efficient and not quite accurate as ntfs_attr_find() ignores
- * the attribute instance numbers for example which become
- * important when one plays with attribute lists. Also, because
- * a proper match has been found in the attribute list entry
- * above, the comparison can now be optimized. So it is worth
- * re-implementing a simplified ntfs_attr_find() here.
- *
- * Use a manual loop so we can still use break and continue
- * with the same meanings as above.
- */
-do_next_attr_loop:
- if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec +
- le32_to_cpu(ctx->mrec->bytes_allocated))
- break;
- if (a->type == AT_END)
- continue;
- if (!a->length)
- break;
- if (al_entry->instance != a->instance)
- goto do_next_attr;
- /*
- * If the type and/or the name are/is mismatched between the
- * attribute list entry and the attribute record, there is
- * corruption so we break and return error EIO.
- */
- if (al_entry->type != a->type)
- break;
- if (!ntfs_names_are_equal((ntfschar*)((char*)a +
- le16_to_cpu(a->name_offset)),
- a->name_length, al_name,
- al_name_len, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len))
- break;
- ctx->attr = a;
- /*
- * If no @val specified or @val specified and it matches, we
- * have found it! Also, if !@type, it is an enumeration, so we
- * want the current attribute.
- */
- if ((type == AT_UNUSED) || !val || (!a->non_resident &&
- le32_to_cpu(a->u.res.value_length) == val_len &&
- !memcmp((char*)a + le16_to_cpu(a->u.res.value_offset),
- val, val_len))) {
- return 0;
- }
-do_next_attr:
- /* Proceed to the next attribute in the current mft record. */
- a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
- goto do_next_attr_loop;
- }
- if (ni != base_ni) {
- ctx->ntfs_ino = base_ni;
- ctx->mrec = ctx->base_mrec;
- ctx->attr = ctx->base_attr;
- }
- ntfs_log_debug("Inode is corrupt.\n");
- errno = EIO;
- return -1;
-not_found:
- /*
- * If we were looking for AT_END or we were enumerating and reached the
- * end, we reset the search context @ctx and use ntfs_attr_find() to
- * seek to the end of the base mft record.
- */
- if (type == AT_UNUSED || type == AT_END) {
- ntfs_attr_reinit_search_ctx(ctx);
- return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,
- ctx);
- }
- /*
- * The attribute wasn't found. Before we return, we want to ensure
- * @ctx->mrec and @ctx->attr indicate the position at which the
- * attribute should be inserted in the base mft record. Since we also
- * want to preserve @ctx->al_entry we cannot reinitialize the search
- * context using ntfs_attr_reinit_search_ctx() as this would set
- * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see
- * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve
- * @ctx->al_entry as the remaining fields (base_*) are identical to
- * their non base_ counterparts and we cannot set @ctx->base_attr
- * correctly yet as we do not know what @ctx->attr will be set to by
- * the call to ntfs_attr_find() below.
- */
- ctx->mrec = ctx->base_mrec;
- ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
- le16_to_cpu(ctx->mrec->attrs_offset));
- ctx->is_first = TRUE;
- ctx->ntfs_ino = ctx->base_ntfs_ino;
- ctx->base_ntfs_ino = NULL;
- ctx->base_mrec = NULL;
- ctx->base_attr = NULL;
- /*
- * In case there are multiple matches in the base mft record, need to
- * keep enumerating until we get an attribute not found response (or
- * another error), otherwise we would keep returning the same attribute
- * over and over again and all programs using us for enumeration would
- * lock up in a tight loop.
- */
- {
- int ret;
-
- do {
- ret = ntfs_attr_find(type, name, name_len, ic, val,
- val_len, ctx);
- } while (!ret);
- return ret;
- }
-}
-
-/**
- * ntfs_attr_lookup - find an attribute in an ntfs inode
- * @type: attribute type to find
- * @name: attribute name to find (optional, i.e. NULL means don't care)
- * @name_len: attribute name length (only needed if @name present)
- * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
- * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
- * @val: attribute value to find (optional, resident attributes only)
- * @val_len: attribute value length
- * @ctx: search context with mft record and attribute to search from
- *
- * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must
- * be the base mft record and @ctx must have been obtained from a call to
- * ntfs_attr_get_search_ctx().
- *
- * This function transparently handles attribute lists and @ctx is used to
- * continue searches where they were left off at.
- *
- * If @type is AT_UNUSED, return the first found attribute, i.e. one can
- * enumerate all attributes by setting @type to AT_UNUSED and then calling
- * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT
- * to indicate that there are no more entries. During the enumeration, each
- * successful call of ntfs_attr_lookup() will return the next attribute, with
- * the current attribute being described by the search context @ctx.
- *
- * If @type is AT_END, seek to the end of the base mft record ignoring the
- * attribute list completely and return -1 with errno set to ENOENT. AT_END is
- * not a valid attribute, its length is zero for example, thus it is safer to
- * return error instead of success in this case. It should never be needed to
- * do this, but we implement the functionality because it allows for simpler
- * code inside ntfs_external_attr_find().
- *
- * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
- * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
- * match both named and unnamed attributes.
- *
- * After finishing with the attribute/mft record you need to call
- * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
- * mapped extent inodes, etc).
- *
- * Return 0 if the search was successful and -1 if not, with errno set to the
- * error code.
- *
- * On success, @ctx->attr is the found attribute, it is in mft record
- * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this
- * attribute with @ctx->base_* being the base mft record to which @ctx->attr
- * belongs. If no attribute list attribute is present @ctx->al_entry and
- * @ctx->base_* are NULL.
- *
- * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the
- * attribute which collates just after the attribute being searched for in the
- * base ntfs inode, i.e. if one wants to add the attribute to the mft record
- * this is the correct place to insert it into, and if there is not enough
- * space, the attribute should be placed in an extent mft record.
- * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list
- * at which the new attribute's attribute list entry should be inserted. The
- * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL.
- * The only exception to this is when @type is AT_END, in which case
- * @ctx->al_entry is set to NULL also (see above).
- *
- *
- * The following error codes are defined:
- * ENOENT Attribute not found, not an error as such.
- * EINVAL Invalid arguments.
- * EIO I/O error or corrupt data structures found.
- * ENOMEM Not enough memory to allocate necessary buffers.
- */
-int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
- const u32 name_len, const IGNORE_CASE_BOOL ic,
- const VCN lowest_vcn, const u8 *val, const u32 val_len,
- ntfs_attr_search_ctx *ctx)
-{
- ntfs_volume *vol;
- ntfs_inode *base_ni;
-
- if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED &&
- (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) ||
- !vol->upcase || !vol->upcase_len))) {
- errno = EINVAL;
- return -1;
- }
- if (ctx->base_ntfs_ino)
- base_ni = ctx->base_ntfs_ino;
- else
- base_ni = ctx->ntfs_ino;
- if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
- return ntfs_attr_find(type, name, name_len, ic, val, val_len,
- ctx);
- return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn,
- val, val_len, ctx);
-}
-
-/**
- * ntfs_attr_init_search_ctx - initialize an attribute search context
- * @ctx: attribute search context to initialize
- * @ni: ntfs inode with which to initialize the search context
- * @mrec: mft record with which to initialize the search context
- *
- * Initialize the attribute search context @ctx with @ni and @mrec.
- */
-static void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
- ntfs_inode *ni, MFT_RECORD *mrec)
-{
- if (!mrec)
- mrec = ni->mrec;
- ctx->mrec = mrec;
- /* Sanity checks are performed elsewhere. */
- ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
- ctx->is_first = TRUE;
- ctx->ntfs_ino = ni;
- ctx->al_entry = NULL;
- ctx->base_ntfs_ino = NULL;
- ctx->base_mrec = NULL;
- ctx->base_attr = NULL;
-}
-
-/**
- * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
- * @ctx: attribute search context to reinitialize
- *
- * Reinitialize the attribute search context @ctx.
- *
- * This is used when a search for a new attribute is being started to reset
- * the search context to the beginning.
- */
-void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
-{
- if (!ctx->base_ntfs_ino) {
- /* No attribute list. */
- ctx->is_first = TRUE;
- /* Sanity checks are performed elsewhere. */
- ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
- le16_to_cpu(ctx->mrec->attrs_offset));
- /*
- * This needs resetting due to ntfs_external_attr_find() which
- * can leave it set despite having zeroed ctx->base_ntfs_ino.
- */
- ctx->al_entry = NULL;
- return;
- } /* Attribute list. */
- ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
- return;
-}
-
-/**
- * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
- * @ni: ntfs inode with which to initialize the search context
- * @mrec: mft record with which to initialize the search context
- *
- * Allocate a new attribute search context, initialize it with @ni and @mrec,
- * and return it. Return NULL on error with errno set to ENOMEM.
- *
- * @mrec can be NULL, in which case the mft record is taken from @ni.
- *
- * Note: For low level utilities which know what they are doing we allow @ni to
- * be NULL and @mrec to be set. Do NOT do this unless you understand the
- * implications!!! For example it is no longer safe to call ntfs_attr_lookup()
- * if you
- */
-ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
-{
- ntfs_attr_search_ctx *ctx;
-
- if (!ni && !mrec) {
- errno = EINVAL;
- return NULL;
- }
- ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx));
- if (ctx)
- ntfs_attr_init_search_ctx(ctx, ni, mrec);
- return ctx;
-}
-
-/**
- * ntfs_attr_put_search_ctx - release an attribute search context
- * @ctx: attribute search context to free
- *
- * Release the attribute search context @ctx. This function does not change
- * errno and doing nothing if NULL passed to it.
- */
-void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
-{
- free(ctx);
-}
-
-/**
- * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
- * @vol: ntfs volume to which the attribute belongs
- * @type: attribute type which to find
- *
- * Search for the attribute definition record corresponding to the attribute
- * @type in the $AttrDef system file.
- *
- * Return the attribute type definition record if found and NULL if not found
- * or an error occurred. On error the error code is stored in errno. The
- * following error codes are defined:
- * ENOENT - The attribute @type is not specified in $AttrDef.
- * EINVAL - Invalid parameters (e.g. @vol is not valid).
- */
-ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
- const ATTR_TYPES type)
-{
- ATTR_DEF *ad;
-
- if (!vol || !vol->attrdef || !type) {
- errno = EINVAL;
- return NULL;
- }
- for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
- vol->attrdef_len && ad->type; ++ad) {
- /* We haven't found it yet, carry on searching. */
- if (le32_to_cpu(ad->type) < le32_to_cpu(type))
- continue;
- /* We found the attribute; return it. */
- if (ad->type == type)
- return ad;
- /* We have gone too far already. No point in continuing. */
- break;
- }
- /* Attribute not found?!? */
- errno = ENOENT;
- return NULL;
-}
-
-/**
- * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
- * @vol: ntfs volume to which the attribute belongs
- * @type: attribute type which to check
- * @size: size which to check
- *
- * Check whether the @size in bytes is valid for an attribute of @type on the
- * ntfs volume @vol. This information is obtained from $AttrDef system file.
- *
- * Return 0 if valid and -1 if not valid or an error occurred. On error the
- * error code is stored in errno. The following error codes are defined:
- * ERANGE - @size is not valid for the attribute @type.
- * ENOENT - The attribute @type is not specified in $AttrDef.
- * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid).
- */
-int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
- const s64 size)
-{
- ATTR_DEF *ad;
-
- if (size < 0) {
- errno = EINVAL;
- return -1;
- }
-
- /*
- * $ATTRIBUTE_LIST should be not greater than 0x40000, but this is not
- * listed in the AttrDef.
- */
- if (type == AT_ATTRIBUTE_LIST && size > 0x40000) {
- errno = ERANGE;
- return -1;
- }
-
- ad = ntfs_attr_find_in_attrdef(vol, type);
- if (!ad)
- return -1;
- /* We found the attribute. - Do the bounds check. */
- if ((sle64_to_cpu(ad->min_size) && size <
- sle64_to_cpu(ad->min_size)) ||
- ((sle64_to_cpu(ad->max_size) > 0) && size >
- sle64_to_cpu(ad->max_size))) {
- /* @size is out of range! */
- errno = ERANGE;
- return -1;
- }
- return 0;
-}
-
-/**
- * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
- * @vol: ntfs volume to which the attribute belongs
- * @type: attribute type which to check
- *
- * Check whether the attribute of @type on the ntfs volume @vol is allowed to
- * be non-resident. This information is obtained from $AttrDef system file.
- *
- * Return 0 if the attribute is allowed to be non-resident and -1 if not or an
- * error occurred. On error the error code is stored in errno. The following
- * error codes are defined:
- * EPERM - The attribute is not allowed to be non-resident.
- * ENOENT - The attribute @type is not specified in $AttrDef.
- * EINVAL - Invalid parameters (e.g. @vol is not valid).
- */
-int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type)
-{
- ATTR_DEF *ad;
-
- /* Find the attribute definition record in $AttrDef. */
- ad = ntfs_attr_find_in_attrdef(vol, type);
- if (!ad)
- return -1;
- /* Check the flags and return the result. */
- if (ad->flags & ATTR_DEF_RESIDENT) {
- ntfs_log_trace("Attribute can't be non-resident\n");
- errno = EPERM;
- return -1;
- }
- return 0;
-}
-
-/**
- * ntfs_attr_can_be_resident - check if an attribute can be resident
- * @vol: ntfs volume to which the attribute belongs
- * @type: attribute type which to check
- *
- * Check whether the attribute of @type on the ntfs volume @vol is allowed to
- * be resident. This information is derived from our ntfs knowledge and may
- * not be completely accurate, especially when user defined attributes are
- * present. Basically we allow everything to be resident except for index
- * allocation and extended attribute attributes.
- *
- * Return 0 if the attribute is allowed to be resident and -1 if not or an
- * error occurred. On error the error code is stored in errno. The following
- * error codes are defined:
- * EPERM - The attribute is not allowed to be resident.
- * EINVAL - Invalid parameters (e.g. @vol is not valid).
- *
- * Warning: In the system file $MFT the attribute $Bitmap must be non-resident
- * otherwise windows will not boot (blue screen of death)! We cannot
- * check for this here as we don't know which inode's $Bitmap is being
- * asked about so the caller needs to special case this.
- */
-int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type)
-{
- if (!vol || !vol->attrdef || !type) {
- errno = EINVAL;
- return -1;
- }
- if (type != AT_INDEX_ALLOCATION)
- return 0;
-
- ntfs_log_trace("Attribute can't be resident\n");
- errno = EPERM;
- return -1;
-}
-
-/**
- * ntfs_make_room_for_attr - make room for an attribute inside an mft record
- * @m: mft record
- * @pos: position at which to make space
- * @size: byte size to make available at this position
- *
- * @pos points to the attribute in front of which we want to make space.
- *
- * Return 0 on success or -1 on error. On error the error code is stored in
- * errno. Possible error codes are:
- * ENOSPC - There is not enough space available to complete operation. The
- * caller has to make space before calling this.
- * EINVAL - Input parameters were faulty.
- */
-int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size)
-{
- u32 biu;
-
- ntfs_log_trace("Entering for pos 0x%d, size %u.\n",
- (int)(pos - (u8*)m), (unsigned) size);
-
- /* Make size 8-byte alignment. */
- size = (size + 7) & ~7;
-
- /* Rigorous consistency checks. */
- if (!m || !pos || pos < (u8*)m || pos + size >
- (u8*)m + le32_to_cpu(m->bytes_allocated)) {
- errno = EINVAL;
- return -1;
- }
- /* The -8 is for the attribute terminator. */
- if (pos - (u8*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) {
- errno = EINVAL;
- return -1;
- }
- /* Nothing to do. */
- if (!size)
- return 0;
-
- biu = le32_to_cpu(m->bytes_in_use);
- /* Do we have enough space? */
- if (biu + size > le32_to_cpu(m->bytes_allocated)) {
- ntfs_log_trace("Not enough space in the MFT record\n");
- errno = ENOSPC;
- return -1;
- }
- /* Move everything after pos to pos + size. */
- memmove(pos + size, pos, biu - (pos - (u8*)m));
- /* Update mft record. */
- m->bytes_in_use = cpu_to_le32(biu + size);
- return 0;
-}
-
-/**
- * ntfs_resident_attr_record_add - add resident attribute to inode
- * @ni: opened ntfs inode to which MFT record add attribute
- * @type: type of the new attribute
- * @name: name of the new attribute
- * @name_len: name length of the new attribute
- * @val: value of the new attribute
- * @size: size of new attribute (length of @val, if @val != NULL)
- * @flags: flags of the new attribute
- *
- * Return offset to attribute from the beginning of the mft record on success
- * and -1 on error. On error the error code is stored in errno.
- * Possible error codes are:
- * EINVAL - Invalid arguments passed to function.
- * EEXIST - Attribute of such type and with same name already exists.
- * EIO - I/O error occurred or damaged filesystem.
- */
-int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, u8 *val, u32 size,
- ATTR_FLAGS flags)
-{
- ntfs_attr_search_ctx *ctx;
- u32 length;
- ATTR_RECORD *a;
- MFT_RECORD *m;
- int err, offset;
- ntfs_inode *base_ni;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n",
- (long long) ni->mft_no, le32_to_cpu(type), le16_to_cpu(flags));
-
- if (!ni || (!name && name_len)) {
- errno = EINVAL;
- return -1;
- }
-
- if (ntfs_attr_can_be_resident(ni->vol, type)) {
- if (errno == EPERM)
- ntfs_log_trace("Attribute can't be resident.\n");
- else
- ntfs_log_trace("ntfs_attr_can_be_resident failed.\n");
- return -1;
- }
-
- /* Locate place where record should be. */
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- return -1;
- /*
- * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
- * attribute in @ni->mrec, not any extent inode in case if @ni is base
- * file record.
- */
- if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size,
- ctx)) {
- err = EEXIST;
- ntfs_log_trace("Attribute already present.\n");
- goto put_err_out;
- }
- if (errno != ENOENT) {
- err = EIO;
- goto put_err_out;
- }
- a = ctx->attr;
- m = ctx->mrec;
-
- /* Make room for attribute. */
- length = offsetof(ATTR_RECORD, u.res.resident_end) +
- ((name_len * sizeof(ntfschar) + 7) & ~7) +
- ((size + 7) & ~7);
- if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) {
- err = errno;
- ntfs_log_trace("Failed to make room for attribute.\n");
- goto put_err_out;
- }
-
- /* Setup record fields. */
- offset = ((u8*)a - (u8*)m);
- a->type = type;
- a->length = cpu_to_le32(length);
- a->non_resident = 0;
- a->name_length = name_len;
- a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, u.res.resident_end));
- a->flags = flags;
- a->instance = m->next_attr_instance;
- a->u.res.value_length = cpu_to_le32(size);
- a->u.res.value_offset = cpu_to_le16(length - ((size + 7) & ~7));
- if (val)
- memcpy((u8*)a + le16_to_cpu(a->u.res.value_offset), val, size);
- else
- memset((u8*)a + le16_to_cpu(a->u.res.value_offset), 0, size);
- if (type == AT_FILE_NAME)
- a->u.res.resident_flags = RESIDENT_ATTR_IS_INDEXED;
- else
- a->u.res.resident_flags = 0;
- if (name_len)
- memcpy((u8*)a + le16_to_cpu(a->name_offset),
- name, sizeof(ntfschar) * name_len);
- m->next_attr_instance =
- cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff);
- if (ni->nr_extents == -1)
- base_ni = ni->u.base_ni;
- else
- base_ni = ni;
- if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) {
- if (ntfs_attrlist_entry_add(ni, a)) {
- err = errno;
- ntfs_attr_record_resize(m, a, 0);
- ntfs_log_trace("Failed add attribute entry to "
- "ATTRIBUTE_LIST.\n");
- goto put_err_out;
- }
- }
- ntfs_inode_mark_dirty(ni);
- ntfs_attr_put_search_ctx(ctx);
- return offset;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_non_resident_attr_record_add - add extent of non-resident attribute
- * @ni: opened ntfs inode to which MFT record add attribute
- * @type: type of the new attribute extent
- * @name: name of the new attribute extent
- * @name_len: name length of the new attribute extent
- * @lowest_vcn: lowest vcn of the new attribute extent
- * @dataruns_size: dataruns size of the new attribute extent
- * @flags: flags of the new attribute extent
- *
- * Return offset to attribute from the beginning of the mft record on success
- * and -1 on error. On error the error code is stored in errno.
- * Possible error codes are:
- * EINVAL - Invalid arguments passed to function.
- * EEXIST - Attribute of such type, with same lowest vcn and with same
- * name already exists.
- * EIO - I/O error occurred or damaged filesystem.
- */
-int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
- ATTR_FLAGS flags)
-{
- ntfs_attr_search_ctx *ctx;
- u32 length;
- ATTR_RECORD *a;
- MFT_RECORD *m;
- ntfs_inode *base_ni;
- int err, offset;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, "
- "dataruns_size %d, flags 0x%x.\n",
- (long long) ni->mft_no, le32_to_cpu(type),
- (long long) lowest_vcn, dataruns_size,
- le16_to_cpu(flags));
-
- if (!ni || dataruns_size <= 0 || (!name && name_len)) {
- errno = EINVAL;
- return -1;
- }
-
- if (ntfs_attr_can_be_non_resident(ni->vol, type)) {
- if (errno == EPERM)
- ntfs_log_trace("Attribute can't be non resident.\n");
- else
- ntfs_log_trace("ntfs_attr_can_be_non_resident() "
- "failed.\n");
- return -1;
- }
-
- /* Locate place where record should be. */
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- return -1;
- /*
- * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
- * attribute in @ni->mrec, not any extent inode in case if @ni is base
- * file record.
- */
- if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0,
- ctx)) {
- err = EEXIST;
- ntfs_log_trace("Attribute already present.\n");
- goto put_err_out;
- }
- if (errno != ENOENT) {
- err = EIO;
- goto put_err_out;
- }
- a = ctx->attr;
- m = ctx->mrec;
-
- /* Make room for attribute. */
- dataruns_size = (dataruns_size + 7) & ~7;
- length = offsetof(ATTR_RECORD, u.nonres.compressed_size) + ((sizeof(ntfschar) *
- name_len + 7) & ~7) + dataruns_size +
- ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ?
- sizeof(a->u.nonres.compressed_size) : 0);
- if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) {
- err = errno;
- ntfs_log_trace("Failed to make room for attribute.\n");
- goto put_err_out;
- }
-
- /* Setup record fields. */
- a->type = type;
- a->length = cpu_to_le32(length);
- a->non_resident = 1;
- a->name_length = name_len;
- a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, u.nonres.compressed_size) +
- ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ?
- sizeof(a->u.nonres.compressed_size) : 0));
- a->flags = flags;
- a->instance = m->next_attr_instance;
- a->u.nonres.lowest_vcn = cpu_to_sle64(lowest_vcn);
- a->u.nonres.mapping_pairs_offset = cpu_to_le16(length - dataruns_size);
- a->u.nonres.compression_unit = (flags & ATTR_IS_COMPRESSED) ? 4 : 0;
- /* If @lowest_vcn == 0, than setup empty attribute. */
- if (!lowest_vcn) {
- a->u.nonres.highest_vcn = cpu_to_sle64(-1);
- a->u.nonres.allocated_size = 0;
- a->u.nonres.data_size = 0;
- a->u.nonres.initialized_size = 0;
- /* Set empty mapping pairs. */
- *((u8*)a + le16_to_cpu(a->u.nonres.mapping_pairs_offset)) = 0;
- }
- if (name_len)
- memcpy((u8*)a + le16_to_cpu(a->name_offset),
- name, sizeof(ntfschar) * name_len);
- m->next_attr_instance =
- cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff);
- if (ni->nr_extents == -1)
- base_ni = ni->u.base_ni;
- else
- base_ni = ni;
- if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) {
- if (ntfs_attrlist_entry_add(ni, a)) {
- err = errno;
- ntfs_attr_record_resize(m, a, 0);
- ntfs_log_trace("Failed add attribute entry to "
- "ATTRIBUTE_LIST.\n");
- goto put_err_out;
- }
- }
- ntfs_inode_mark_dirty(ni);
- /*
- * Locate offset from start of the MFT record where new attribute is
- * placed. We need relookup it, because record maybe moved during
- * update of attribute list.
- */
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE,
- lowest_vcn, NULL, 0, ctx)) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed. Probably leaving "
- "inconsistent metadata.\n");
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
- }
- offset = (u8*)ctx->attr - (u8*)ctx->mrec;
- ntfs_attr_put_search_ctx(ctx);
- return offset;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_attr_record_rm - remove attribute extent
- * @ctx: search context describing the attribute which should be removed
- *
- * If this function succeed, user should reinit search context if he/she wants
- * use it anymore.
- *
- * Return 0 on success and -1 on error. On error the error code is stored in
- * errno. Possible error codes are:
- * EINVAL - Invalid arguments passed to function.
- * EIO - I/O error occurred or damaged filesystem.
- */
-int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx)
-{
- ntfs_inode *base_ni, *ni;
- ATTR_TYPES type;
- int err;
-
- if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) {
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
- (long long) ctx->ntfs_ino->mft_no,
- (unsigned) le32_to_cpu(ctx->attr->type));
- type = ctx->attr->type;
- ni = ctx->ntfs_ino;
- if (ctx->base_ntfs_ino)
- base_ni = ctx->base_ntfs_ino;
- else
- base_ni = ctx->ntfs_ino;
-
- /* Remove attribute itself. */
- if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) {
- ntfs_log_trace("Couldn't remove attribute record. "
- "Bug or damaged MFT record.\n");
- if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST)
- if (ntfs_attrlist_entry_add(ni, ctx->attr))
- ntfs_log_trace("Rollback failed. Leaving "
- "inconsistent metadata.\n");
- err = EIO;
- return -1;
- }
- ntfs_inode_mark_dirty(ni);
-
- /*
- * Remove record from $ATTRIBUTE_LIST if present and we don't want
- * delete $ATTRIBUTE_LIST itself.
- */
- if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) {
- if (ntfs_attrlist_entry_rm(ctx)) {
- ntfs_log_trace("Couldn't delete record from "
- "$ATTRIBUTE_LIST.\n");
- return -1;
- }
- }
-
- /* Post $ATTRIBUTE_LIST delete setup. */
- if (type == AT_ATTRIBUTE_LIST) {
- if (NInoAttrList(base_ni) && base_ni->attr_list)
- free(base_ni->attr_list);
- base_ni->attr_list = NULL;
- NInoClearAttrList(base_ni);
- NInoAttrListClearDirty(base_ni);
- }
-
- /* Free MFT record, if it isn't contain attributes. */
- if (le32_to_cpu(ctx->mrec->bytes_in_use) -
- le16_to_cpu(ctx->mrec->attrs_offset) == 8) {
- if (ntfs_mft_record_free(ni->vol, ni)) {
- // FIXME: We need rollback here.
- ntfs_log_trace("Couldn't free MFT record.\n");
- errno = EIO;
- return -1;
- }
- /* Remove done if we freed base inode. */
- if (ni == base_ni)
- return 0;
- }
-
- if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni))
- return 0;
-
- /* Remove attribute list if we don't need it any more. */
- if (!ntfs_attrlist_need(base_ni)) {
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- /*
- * FIXME: Should we succeed here? Definitely something
- * goes wrong because NInoAttrList(base_ni) returned
- * that we have got attribute list.
- */
- ntfs_log_trace("Couldn't find attribute list. Succeed "
- "anyway.\n");
- return 0;
- }
- /* Deallocate clusters. */
- if (ctx->attr->non_resident) {
- runlist *al_rl;
-
- al_rl = ntfs_mapping_pairs_decompress(base_ni->vol,
- ctx->attr, NULL);
- if (!al_rl) {
- ntfs_log_trace("Couldn't decompress attribute "
- "list runlist. Succeed "
- "anyway.\n");
- return 0;
- }
- if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) {
- ntfs_log_trace("Leaking clusters! Run chkdsk. "
- "Couldn't free clusters from "
- "attribute list runlist.\n");
- }
- free(al_rl);
- }
- /* Remove attribute record itself. */
- if (ntfs_attr_record_rm(ctx)) {
- /*
- * FIXME: Should we succeed here? BTW, chkdsk doesn't
- * complain if it find MFT record with attribute list,
- * but without extents.
- */
- ntfs_log_trace("Couldn't remove attribute list. "
- "Succeed anyway.\n");
- return 0;
- }
- }
- return 0;
-}
-
-/**
- * ntfs_attr_add - add attribute to inode
- * @ni: opened ntfs inode to which add attribute
- * @type: type of the new attribute
- * @name: name in unicode of the new attribute
- * @name_len: name length in unicode characters of the new attribute
- * @val: value of new attribute
- * @size: size of the new attribute / length of @val (if specified)
- *
- * @val should always be specified for always resident attributes (eg. FILE_NAME
- * attribute), for attributes that can become non-resident @val can be NULL
- * (eg. DATA attribute). @size can be specified even if @val is NULL, in this
- * case data size will be equal to @size and initialized size will be equal
- * to 0.
- *
- * If inode haven't got enough space to add attribute, add attribute to one of
- * it extents, if no extents present or no one of them have enough space, than
- * allocate new extent and add attribute to it.
- *
- * If on one of this steps attribute list is needed but not present, than it is
- * added transparently to caller. So, this function should not be called with
- * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call
- * ntfs_inode_add_attrlist instead.
- *
- * On success return 0. On error return -1 with errno set to the error code.
- */
-int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, u8 *val, s64 size)
-{
- u32 attr_rec_size;
- int err, i, offset;
- BOOL is_resident = TRUE;
- BOOL always_non_resident = FALSE, always_resident = FALSE;
- ntfs_inode *attr_ni;
- ntfs_attr *na;
-
- if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) {
- ntfs_log_trace("Invalid arguments passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr %x, size %lld.\n",
- (long long) ni->mft_no, type, size);
-
- if (ni->nr_extents == -1)
- ni = ni->u.base_ni;
-
- /* Check the attribute type and the size. */
- if (ntfs_attr_size_bounds_check(ni->vol, type, size)) {
- if (errno == ERANGE) {
- ntfs_log_trace("Size bounds check failed.\n");
- } else if (errno == ENOENT) {
- ntfs_log_trace("Invalid attribute type. Aborting...\n");
- errno = EIO;
- }
- return -1;
- }
-
- /* Sanity checks for always resident attributes. */
- if (ntfs_attr_can_be_non_resident(ni->vol, type)) {
- if (errno != EPERM) {
- err = errno;
- ntfs_log_trace("ntfs_attr_can_be_non_resident() "
- "failed.\n");
- goto err_out;
- }
- /* @val is mandatory. */
- if (!val) {
- ntfs_log_trace("@val is mandatory for always resident "
- "attributes.\n");
- errno = EINVAL;
- return -1;
- }
- if (size > ni->vol->mft_record_size) {
- ntfs_log_trace("Attribute is too big.\n");
- errno = ERANGE;
- return -1;
- }
- always_resident = TRUE;
- }
-
- /* Check whether attribute can be resident. */
- if (ntfs_attr_can_be_resident(ni->vol, type)) {
- if (errno != EPERM) {
- err = errno;
- ntfs_log_trace("ntfs_attr_can_be_resident() failed.\n");
- goto err_out;
- }
- is_resident = FALSE;
- always_non_resident = TRUE;
- }
-
-retry:
- /* Calculate attribute record size. */
- if (is_resident)
- attr_rec_size = offsetof(ATTR_RECORD, u.res.resident_end) +
- ROUND_UP(name_len * sizeof(ntfschar), 3) +
- ROUND_UP(size, 3);
- else /* We add 8 for space for mapping pairs. */
- attr_rec_size = offsetof(ATTR_RECORD, u.nonres.non_resident_end) +
- ROUND_UP(name_len * sizeof(ntfschar), 3) + 8;
-
- /*
- * If we have enough free space for the new attribute in the base MFT
- * record, then add attribute to it.
- */
- if (le32_to_cpu(ni->mrec->bytes_allocated) -
- le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) {
- attr_ni = ni;
- goto add_attr_record;
- }
-
- /* Try to add to extent inodes. */
- if (ntfs_inode_attach_all_extents(ni)) {
- err = errno;
- ntfs_log_trace("Failed to attach all extents to inode.\n");
- goto err_out;
- }
- for (i = 0; i < ni->nr_extents; i++) {
- attr_ni = ni->u.extent_nis[i];
- if (le32_to_cpu(attr_ni->mrec->bytes_allocated) -
- le32_to_cpu(attr_ni->mrec->bytes_in_use) >=
- attr_rec_size)
- goto add_attr_record;
- }
-
- /*
- * If failed to find space for resident attribute, then try to find
- * space for non resident one.
- */
- if (is_resident && !always_resident) {
- is_resident = FALSE;
- goto retry;
- }
-
- /*
- * FIXME: Try to make other attributes non-resident here. Factor out
- * code from ntfs_resident_attr_resize.
- */
-
- /* There is no extent that contain enough space for new attribute. */
- if (!NInoAttrList(ni)) {
- /* Add attribute list not present, add it and retry. */
- if (ntfs_inode_add_attrlist(ni)) {
- err = errno;
- ntfs_log_trace("Failed to add attribute list.\n");
- goto err_out;
- }
- return ntfs_attr_add(ni, type, name, name_len, val, size);
- }
- /* Allocate new extent for attribute. */
- attr_ni = ntfs_mft_record_alloc(ni->vol, ni);
- if (!attr_ni) {
- err = errno;
- ntfs_log_trace("Failed to allocate extent record.\n");
- goto err_out;
- }
-
- /*
- * Determine resident or not will be attribute using heuristics and
- * calculate attribute record size. FIXME: small code duplication here.
- */
- if (always_resident || (!always_non_resident && size < 256)) {
- is_resident = TRUE;
- attr_rec_size = offsetof(ATTR_RECORD, u.res.resident_end) +
- ROUND_UP(name_len * sizeof(ntfschar), 3) +
- ROUND_UP(size, 3);
- } else { /* We add 8 for space for mapping pairs. */
- is_resident = FALSE;
- attr_rec_size = offsetof(ATTR_RECORD, u.nonres.non_resident_end) +
- ROUND_UP(name_len * sizeof(ntfschar), 3) + 8;
- }
-
-add_attr_record:
- if (is_resident) {
- /* Add resident attribute. */
- offset = ntfs_resident_attr_record_add(attr_ni, type, name,
- name_len, val, size, 0);
- if (offset < 0) {
- err = errno;
- ntfs_log_trace("Failed to add resident attribute.\n");
- goto free_err_out;
- }
- return 0;
- }
-
- /* Add non resident attribute. */
- offset = ntfs_non_resident_attr_record_add(attr_ni, type, name,
- name_len, 0, 8, 0);
- if (offset < 0) {
- err = errno;
- ntfs_log_trace("Failed to add non resident attribute.\n");
- goto free_err_out;
- }
-
- /* If @size == 0, we are done. */
- if (!size)
- return 0;
-
- /* Open new attribute and resize it. */
- na = ntfs_attr_open(ni, type, name, name_len);
- if (!na) {
- err = errno;
- ntfs_log_trace("Failed to open just added attribute.\n");
- goto rm_attr_err_out;
- }
- /* Resize and set attribute value. */
- if (ntfs_attr_truncate(na, size) ||
- (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) {
- err = errno;
- ntfs_log_trace("Failed to initialize just added attribute.\n");
- if (ntfs_attr_rm(na))
- ntfs_log_trace("Failed to remove just added attribute. "
- "Probably leaving inconsistent "
- "metadata.\n");
- goto err_out;
- }
- ntfs_attr_close(na);
- /* Done !*/
- return 0;
-
-rm_attr_err_out:
- /* Remove just added attribute. */
- if (ntfs_attr_record_resize(attr_ni->mrec,
- (ATTR_RECORD*)((u8*)attr_ni->mrec + offset), 0)) {
- ntfs_log_trace("Failed to remove just added attribute.\n");
- }
-free_err_out:
- /* Free MFT record, if it isn't contain attributes. */
- if (le32_to_cpu(attr_ni->mrec->bytes_in_use) -
- le16_to_cpu(attr_ni->mrec->attrs_offset) == 8) {
- if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) {
- ntfs_log_trace("Failed to free MFT record. Leaving "
- "inconsistent metadata.\n");
- }
- }
-err_out:
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_attr_rm - remove attribute from ntfs inode
- * @na: opened ntfs attribute to delete
- *
- * Remove attribute and all it's extents from ntfs inode. If attribute was non
- * resident also free all clusters allocated by attribute. This function always
- * closes @na upon exit (both on success and failure).
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_attr_rm(ntfs_attr *na)
-{
- ntfs_attr_search_ctx *ctx;
- int ret = 0;
-
- if (!na) {
- ntfs_log_trace("Invalid arguments passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
- (long long) na->ni->mft_no, na->type);
-
- /* Free cluster allocation. */
- if (NAttrNonResident(na)) {
- if (ntfs_attr_map_whole_runlist(na)) {
- ntfs_attr_close(na);
- return -1;
- }
- if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) {
- ntfs_log_trace("Failed to free cluster allocation. "
- "Leaving inconsistent metadata.\n");
- ret = -1;
- }
- }
-
- /* Search for attribute extents and remove them all. */
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx) {
- ntfs_attr_close(na);
- return -1;
- }
- while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
- CASE_SENSITIVE, 0, NULL, 0, ctx)) {
- if (ntfs_attr_record_rm(ctx)) {
- ntfs_log_trace("Failed to remove attribute extent. "
- "Leaving inconsistent metadata.\n");
- ret = -1;
- }
- ntfs_attr_reinit_search_ctx(ctx);
- }
- if (errno != ENOENT) {
- ntfs_log_trace("Attribute lookup failed. "
- "Probably leaving inconsistent metadata.\n");
- ret = -1;
- }
-
- /* Throw away now non-exist attribute. */
- ntfs_attr_close(na);
- /* Done. */
- return ret;
-}
-
-/**
- * ntfs_attr_record_resize - resize an attribute record
- * @m: mft record containing attribute record
- * @a: attribute record to resize
- * @new_size: new size in bytes to which to resize the attribute record @a
- *
- * Resize the attribute record @a, i.e. the resident part of the attribute, in
- * the mft record @m to @new_size bytes.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- * The following error codes are defined:
- * ENOSPC - Not enough space in the mft record @m to perform the resize.
- * Note that on error no modifications have been performed whatsoever.
- *
- * Warning: If you make a record smaller without having copied all the data you
- * are interested in the data may be overwritten!
- */
-int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
-{
- ntfs_log_trace("Entering for new_size %u.\n", (unsigned) new_size);
- /* Align to 8 bytes, just in case the caller hasn't. */
- new_size = (new_size + 7) & ~7;
- /* If the actual attribute length has changed, move things around. */
- if (new_size != le32_to_cpu(a->length)) {
- u32 new_muse = le32_to_cpu(m->bytes_in_use) -
- le32_to_cpu(a->length) + new_size;
- /* Not enough space in this mft record. */
- if (new_muse > le32_to_cpu(m->bytes_allocated)) {
- errno = ENOSPC;
- return -1;
- }
- /* Move attributes following @a to their new location. */
- memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length),
- le32_to_cpu(m->bytes_in_use) - ((u8*)a -
- (u8*)m) - le32_to_cpu(a->length));
- /* Adjust @m to reflect the change in used space. */
- m->bytes_in_use = cpu_to_le32(new_muse);
- /* Adjust @a to reflect the new size. */
- if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
- a->length = cpu_to_le32(new_size);
- }
- return 0;
-}
-
-/**
- * ntfs_resident_attr_value_resize - resize the value of a resident attribute
- * @m: mft record containing attribute record
- * @a: attribute record whose value to resize
- * @new_size: new size in bytes to which to resize the attribute value of @a
- *
- * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
- * If the value is made bigger, the newly "allocated" space is cleared.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- * The following error codes are defined:
- * ENOSPC - Not enough space in the mft record @m to perform the resize.
- * Note that on error no modifications have been performed whatsoever.
- */
-int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
- const u32 new_size)
-{
- ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size);
-
- /*
- * Check that the attribute name hasn't been placed after the
- * attribute value. Chkdsk treat this as corruption.
- */
- if (a->name_length && le16_to_cpu(a->name_offset) >=
- le16_to_cpu(a->u.res.value_offset)) {
- ntfs_log_trace("Name is placed after the attribute value. "
- "Corrupted inode. Run chkdsk. Aborting...\n");
- errno = EIO;
- return -1;
- }
- /* Resize the resident part of the attribute record. */
- if (ntfs_attr_record_resize(m, a, (le16_to_cpu(a->u.res.value_offset) +
- new_size + 7) & ~7) < 0) {
- if (errno != ENOSPC) {
- int eo = errno;
- ntfs_log_trace("Attribute record resize failed. "
- "Aborting...\n");
- errno = eo;
- }
- return -1;
- }
- /*
- * If we made the attribute value bigger, clear the area between the
- * old size and @new_size.
- */
- if (new_size > le32_to_cpu(a->u.res.value_length))
- memset((u8*)a + le16_to_cpu(a->u.res.value_offset) +
- le32_to_cpu(a->u.res.value_length), 0, new_size -
- le32_to_cpu(a->u.res.value_length));
- /* Finally update the length of the attribute value. */
- a->u.res.value_length = cpu_to_le32(new_size);
- return 0;
-}
-
-/**
- * ntfs_attr_record_move_to - move attribute record to target inode
- * @ctx: attribute search context describing the attribute record
- * @ni: opened ntfs inode to which move attribute record
- *
- * If this function succeed, user should reinit search context if he/she wants
- * use it anymore.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni)
-{
- ntfs_attr_search_ctx *nctx;
- ATTR_RECORD *a;
- int err;
-
- if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) {
- ntfs_log_trace("Invalid arguments passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for ctx->attr->type 0x%x, "
- "ctx->ntfs_ino->mft_no 0x%llx, ni->mft_no 0x%llx.\n",
- (unsigned) le32_to_cpu(ctx->attr->type),
- (long long) ctx->ntfs_ino->mft_no,
- (long long) ni->mft_no);
-
- if (ctx->ntfs_ino == ni)
- return 0;
-
- if (!ctx->al_entry) {
- ntfs_log_trace("Inode should contain attribute list to use "
- "this function.\n");
- errno = EINVAL;
- return -1;
- }
-
- /* Find place in MFT record where attribute will be moved. */
- a = ctx->attr;
- nctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!nctx) {
- ntfs_log_trace("Couldn't obtain search context.\n");
- return -1;
- }
- /*
- * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
- * attribute in @ni->mrec, not any extent inode in case if @ni is base
- * file record.
- */
- if (!ntfs_attr_find(a->type, (ntfschar*)((u8*)a + le16_to_cpu(
- a->name_offset)), a->name_length, CASE_SENSITIVE, NULL,
- 0, nctx)) {
- ntfs_log_trace("Attribute of such type, with same name already "
- "present in this MFT record.\n");
- err = EEXIST;
- goto put_err_out;
- }
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_debug("Attribute lookup failed.\n");
- goto put_err_out;
- }
-
- /* Make space and move attribute. */
- if (ntfs_make_room_for_attr(ni->mrec, (u8*) nctx->attr,
- le32_to_cpu(a->length))) {
- err = errno;
- ntfs_log_trace("Couldn't make space for attribute.\n");
- goto put_err_out;
- }
- memcpy(nctx->attr, a, le32_to_cpu(a->length));
- nctx->attr->instance = nctx->mrec->next_attr_instance;
- nctx->mrec->next_attr_instance = cpu_to_le16(
- (le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff);
- ntfs_attr_record_resize(ctx->mrec, a, 0);
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_inode_mark_dirty(ni);
-
- /* Update attribute list. */
- ctx->al_entry->mft_reference =
- MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
- ctx->al_entry->instance = nctx->attr->instance;
- ntfs_attrlist_mark_dirty(ni);
-
- ntfs_attr_put_search_ctx(nctx);
- return 0;
-put_err_out:
- ntfs_attr_put_search_ctx(nctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_attr_record_move_away - move away attribute record from it's mft record
- * @ctx: attribute search context describing the attribute record
- * @extra: minimum amount of free space in the new holder of record
- *
- * New attribute record holder must have free @extra bytes after moving
- * attribute record to it.
- *
- * If this function succeed, user should reinit search context if he/she wants
- * use it anymore.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra)
-{
- ntfs_inode *base_ni, *ni;
- MFT_RECORD *m;
- int i;
-
- if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) {
- ntfs_log_trace("Invalid arguments passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for attr 0x%x, inode 0x%llx.\n",
- (unsigned) le32_to_cpu(ctx->attr->type),
- (long long) ctx->ntfs_ino->mft_no);
-
- if (ctx->ntfs_ino->nr_extents == -1)
- base_ni = ctx->base_ntfs_ino;
- else
- base_ni = ctx->ntfs_ino;
-
- if (!NInoAttrList(base_ni)) {
- ntfs_log_trace("Inode should contain attribute list to use "
- "this function.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) {
- ntfs_log_trace("Couldn't attach extent inode.\n");
- return -1;
- }
-
- /* Walk through all extents and try to move attribute to them. */
- for (i = 0; i < base_ni->nr_extents; i++) {
- ni = base_ni->u.extent_nis[i];
- m = ni->mrec;
-
- if (ctx->ntfs_ino->mft_no == ni->mft_no)
- continue;
-
- if (le32_to_cpu(m->bytes_allocated) -
- le32_to_cpu(m->bytes_in_use) <
- le32_to_cpu(ctx->attr->length) + extra)
- continue;
-
- /*
- * ntfs_attr_record_move_to can fail if extent with other lowest
- * VCN already present in inode we trying move record to. So,
- * do not return error.
- */
- if (!ntfs_attr_record_move_to(ctx, ni))
- return 0;
- }
-
- /*
- * Failed to move attribute to one of the current extents, so allocate
- * new extent and move attribute to it.
- */
- ni = ntfs_mft_record_alloc(base_ni->vol, base_ni);
- if (!ni) {
- ntfs_log_trace("Couldn't allocate new MFT record.\n");
- return -1;
- }
- if (ntfs_attr_record_move_to(ctx, ni)) {
- ntfs_log_trace("Couldn't move attribute to new MFT record.\n");
- return -1;
- }
- return 0;
-}
-
-/**
- * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
- * @na: open ntfs attribute to make non-resident
- * @ctx: ntfs search context describing the attribute
- *
- * Convert a resident ntfs attribute to a non-resident one.
- *
- * Return 0 on success and -1 on error with errno set to the error code. The
- * following error codes are defined:
- * EPERM - The attribute is not allowed to be non-resident.
- * TODO: others...
- *
- * NOTE to self: No changes in the attribute list are required to move from
- * a resident to a non-resident attribute.
- *
- * Warning: We do not set the inode dirty and we do not write out anything!
- * We expect the caller to do this as this is a fairly low level
- * function and it is likely there will be further changes made.
- */
-static int ntfs_attr_make_non_resident(ntfs_attr *na,
- ntfs_attr_search_ctx *ctx)
-{
- s64 new_allocated_size, bw;
- ntfs_volume *vol = na->ni->vol;
- ATTR_REC *a = ctx->attr;
- runlist *rl;
- int mp_size, mp_ofs, name_ofs, arec_size;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
- long)na->ni->mft_no, na->type);
-
- /* Some preliminary sanity checking. */
- if (NAttrNonResident(na)) {
- ntfs_log_trace("Eeek! Trying to make non-resident attribute "
- "non-resident. Aborting...\n");
- errno = EINVAL;
- return -1;
- }
-
- /* Check that the attribute is allowed to be non-resident. */
- if (ntfs_attr_can_be_non_resident(vol, na->type))
- return -1;
-
- /*
- * Check that the attribute name hasn't been placed after the
- * attribute value. Chkdsk treat this as corruption.
- */
- if (a->name_length && le16_to_cpu(a->name_offset) >=
- le16_to_cpu(a->u.res.value_offset)) {
- ntfs_log_trace("Name is placed after the attribute value. "
- "Corrupted inode. Run chkdsk. Aborting...\n");
- errno = EIO;
- return -1;
- }
-
- new_allocated_size = (le32_to_cpu(a->u.res.value_length) + vol->cluster_size
- - 1) & ~(vol->cluster_size - 1);
-
- if (new_allocated_size > 0) {
- /* Start by allocating clusters to hold the attribute value. */
- rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >>
- vol->cluster_size_bits, -1, DATA_ZONE);
- if (!rl) {
- if (errno != ENOSPC) {
- ntfs_log_trace("Eeek! Failed to allocate "
- "cluster(s). Aborting...\n");
- }
- return -1;
- }
- } else
- rl = NULL;
- /*
- * Setup the in-memory attribute structure to be non-resident so that
- * we can use ntfs_attr_pwrite().
- */
- NAttrSetNonResident(na);
- na->rl = rl;
- na->allocated_size = new_allocated_size;
- na->data_size = na->initialized_size = le32_to_cpu(a->u.res.value_length);
- /*
- * FIXME: For now just clear all of these as we don't support them when
- * writing.
- */
- NAttrClearCompressed(na);
- NAttrClearSparse(na);
- NAttrClearEncrypted(na);
-
- if (rl) {
- /* Now copy the attribute value to the allocated cluster(s). */
- bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->u.res.value_length),
- (u8*)a + le16_to_cpu(a->u.res.value_offset));
- if (bw != le32_to_cpu(a->u.res.value_length)) {
- ntfs_log_debug("Failed to write out attribute value "
- "(bw = %lli, errno = %i). "
- "Aborting...\n", (long long)bw, errno);
- if (bw >= 0)
- errno = EIO;
- goto cluster_free_err_out;
- }
- }
- /* Determine the size of the mapping pairs array. */
- mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0);
- if (mp_size < 0) {
- ntfs_log_debug("Failed to get size for mapping pairs array. "
- "Aborting...\n");
- goto cluster_free_err_out;
- }
- /* Calculate new offsets for the name and the mapping pairs array. */
- name_ofs = (sizeof(ATTR_REC) - sizeof(a->u.nonres.compressed_size) + 7) & ~7;
- mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
- /*
- * Determine the size of the resident part of the non-resident
- * attribute record. (Not compressed thus no compressed_size element
- * present.)
- */
- arec_size = (mp_ofs + mp_size + 7) & ~7;
-
- /* Resize the resident part of the attribute record. */
- if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) {
- if (errno != ENOSPC) {
- ntfs_log_trace("Failed to resize attribute record. "
- "Aborting...\n");
- }
- goto cluster_free_err_out;
- }
-
- /*
- * Convert the resident part of the attribute record to describe a
- * non-resident attribute.
- */
- a->non_resident = 1;
-
- /* Move the attribute name if it exists and update the offset. */
- if (a->name_length)
- memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
- a->name_length * sizeof(ntfschar));
- a->name_offset = cpu_to_le16(name_ofs);
-
- /* Update the flags to match the in-memory ones. */
- a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED |
- ATTR_COMPRESSION_MASK);
-
- /* Setup the fields specific to non-resident attributes. */
- a->u.nonres.lowest_vcn = cpu_to_sle64(0);
- a->u.nonres.highest_vcn = cpu_to_sle64((new_allocated_size - 1) >>
- vol->cluster_size_bits);
-
- a->u.nonres.mapping_pairs_offset = cpu_to_le16(mp_ofs);
-
- a->u.nonres.compression_unit = 0;
-
- memset(&a->u.nonres.reserved1, 0, sizeof(a->u.nonres.reserved1));
-
- a->u.nonres.allocated_size = cpu_to_sle64(new_allocated_size);
- a->u.nonres.data_size = a->u.nonres.initialized_size = cpu_to_sle64(na->data_size);
-
- /* Generate the mapping pairs array in the attribute record. */
- if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs,
- rl, 0, NULL) < 0) {
- // FIXME: Eeek! We need rollback! (AIA)
- ntfs_log_trace("Eeek! Failed to build mapping pairs. Leaving "
- "corrupt attribute record on disk. In memory "
- "runlist is still intact! Error code is %i. "
- "FIXME: Need to rollback instead!\n", errno);
- return -1;
- }
-
- /* Done! */
- return 0;
-
-cluster_free_err_out:
- if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0)
- ntfs_log_trace("Failed to release allocated clusters in error "
- "code path. Leaving inconsistent metadata...\n");
- NAttrClearNonResident(na);
- na->allocated_size = na->data_size;
- na->rl = NULL;
- free(rl);
- return -1;
-}
-
-/**
- * ntfs_resident_attr_resize - resize a resident, open ntfs attribute
- * @na: resident ntfs attribute to resize
- * @newsize: new size (in bytes) to which to resize the attribute
- *
- * Change the size of a resident, open ntfs attribute @na to @newsize bytes.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- * The following error codes are defined:
- * ENOMEM - Not enough memory to complete operation.
- * ERANGE - @newsize is not valid for the attribute type of @na.
- * ENOSPC - There is no enough space on the volume to allocate
- * new clusters or in base mft to resize $ATTRIBUTE_LIST.
- * EOVERFLOW - Resident attribute can not become non resident and
- * already filled whole MFT record, but had not reached
- * @newsize bytes length.
- */
-static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
-{
- ntfs_attr_search_ctx *ctx;
- ntfs_volume *vol;
- ntfs_inode *ni;
- int err;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, new size %lld.\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)newsize);
-
- /* Get the attribute record that needs modification. */
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx)
- return -1;
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0,
- ctx)) {
- err = errno;
- goto put_err_out;
- }
- vol = na->ni->vol;
- /*
- * Check the attribute type and the corresponding minimum and maximum
- * sizes against @newsize and fail if @newsize is out of bounds.
- */
- if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
- err = errno;
- if (err == ERANGE) {
- ntfs_log_trace("Size bounds check failed. "
- "Aborting...\n");
- } else if (err == ENOENT)
- err = EIO;
- goto put_err_out;
- }
- /*
- * If @newsize is bigger than the MFT record we need to make the
- * attribute non-resident if the attribute type supports it. If it is
- * smaller we can go ahead and attempt the resize.
- */
- if (newsize < vol->mft_record_size) {
- /* Perform the resize of the attribute record. */
- if (!ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
- newsize)) {
- /* Update attribute size everywhere. */
- na->data_size = na->initialized_size = newsize;
- na->allocated_size = ROUND_UP(newsize, 3);
- if (NAttrCompressed(na) || NAttrSparse(na))
- na->compressed_size = na->allocated_size;
- if (na->type == AT_DATA && na->name == AT_UNNAMED) {
- na->ni->data_size = na->data_size;
- na->ni->allocated_size = na->allocated_size;
- NInoFileNameSetDirty(na->ni);
- }
- goto resize_done;
- }
- /* Error! If not enough space, just continue. */
- if (errno != ENOSPC) {
- err = errno;
- ntfs_log_trace("Failed to resize resident part "
- "of attribute. Aborting...\n");
- goto put_err_out;
- }
- }
- /* There is not enough space in the MFT record to perform the resize. */
-
- /* Make the attribute non-resident if possible. */
- if (!ntfs_attr_make_non_resident(na, ctx)) {
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- /* Resize non-resident attribute */
- return ntfs_attr_truncate(na, newsize);
- } else if (errno != ENOSPC && errno != EPERM) {
- err = errno;
- ntfs_log_trace("Failed to make attribute non-resident. "
- "Aborting...\n");
- goto put_err_out;
- }
-
- /* Try to make other attributes non-resident and retry each time. */
- ntfs_attr_init_search_ctx(ctx, NULL, na->ni->mrec);
- while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {
- ntfs_attr *tna;
- ATTR_RECORD *a;
-
- a = ctx->attr;
- if (a->non_resident)
- continue;
-
- /*
- * Check out whether convert is reasonable. Assume that mapping
- * pairs will take 8 bytes.
- */
- if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD,
- u.nonres.compressed_size) + ROUND_UP(a->name_length *
- sizeof(ntfschar), 3) + 8)
- continue;
-
- tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a +
- le16_to_cpu(a->name_offset)), a->name_length);
- if (!tna) {
- err = errno;
- ntfs_log_trace("Couldn't open attribute.\n");
- goto put_err_out;
- }
- if (ntfs_attr_make_non_resident(tna, ctx)) {
- ntfs_attr_close(tna);
- continue;
- }
- ntfs_inode_mark_dirty(tna->ni);
- ntfs_attr_close(tna);
- ntfs_attr_put_search_ctx(ctx);
- return ntfs_resident_attr_resize(na, newsize);
- }
- /* Check whether error occurred. */
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto put_err_out;
- }
-
- /* We can't move out attribute list, thus move out others. */
- if (na->type == AT_ATTRIBUTE_LIST) {
- ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD,
- u.nonres.non_resident_end) + 8)) {
- ntfs_log_trace("Couldn't free space in the MFT record "
- "to make attribute list non "
- "resident.\n");
- return -1;
- }
- return ntfs_resident_attr_resize(na, newsize);
- }
-
- /*
- * Move the attribute to a new MFT record, creating an attribute list
- * attribute or modifying it if it is already present.
- */
-
- /* Point search context back to attribute which we need resize. */
- ntfs_attr_init_search_ctx(ctx, na->ni, NULL);
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- ntfs_log_trace("Attribute lookup failed.\n");
- err = errno;
- goto put_err_out;
- }
-
- /*
- * Force index allocation creation instead of moving out index root
- * from the base MFT record.
- */
- if (na->type == AT_INDEX_ROOT && na->data_size > sizeof(INDEX_ROOT) +
- sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)) {
- INDEX_ROOT *ir;
-
- ir = (INDEX_ROOT*)((u8*)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- if (!(ir->index.flags & LARGE_INDEX)) {
- err = EOVERFLOW;
- goto put_err_out;
- }
- }
-
- /*
- * Check whether attribute is already single in the this MFT record.
- * 8 added for the attribute terminator.
- */
- if (le32_to_cpu(ctx->mrec->bytes_in_use) ==
- le16_to_cpu(ctx->mrec->attrs_offset) +
- le32_to_cpu(ctx->attr->length) + 8) {
- err = EOVERFLOW;
- goto put_err_out;
- }
-
- /* Add attribute list if not present. */
- if (na->ni->nr_extents == -1)
- ni = na->ni->u.base_ni;
- else
- ni = na->ni;
- if (!NInoAttrList(ni)) {
- ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_add_attrlist(ni))
- return -1;
- return ntfs_resident_attr_resize(na, newsize);
- }
- /* Allocate new MFT record. */
- ni = ntfs_mft_record_alloc(vol, ni);
- if (!ni) {
- err = errno;
- ntfs_log_trace("Couldn't allocate new MFT record.\n");
- goto put_err_out;
- }
- /* Move attribute to it. */
- if (ntfs_attr_record_move_to(ctx, ni)) {
- err = errno;
- ntfs_log_trace("Couldn't move attribute to new MFT record.\n");
- goto put_err_out;
- }
- /* Update ntfs attribute. */
- if (na->ni->nr_extents == -1)
- na->ni = ni;
-
- ntfs_attr_put_search_ctx(ctx);
- /* Try to perform resize once again. */
- return ntfs_resident_attr_resize(na, newsize);
-
-resize_done:
- /*
- * Set the inode (and its base inode if it exists) dirty so it is
- * written out later.
- */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- /* Done! */
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_attr_make_resident - convert a non-resident to a resident attribute
- * @na: open ntfs attribute to make resident
- * @ctx: ntfs search context describing the attribute
- *
- * Convert a non-resident ntfs attribute to a resident one.
- *
- * Return 0 on success and -1 on error with errno set to the error code. The
- * following error codes are defined:
- * EINVAL - Invalid arguments passed.
- * EPERM - The attribute is not allowed to be resident.
- * EIO - I/O error, damaged inode or bug.
- * ENOSPC - There is no enough space to perform conversion.
- * EOPNOTSUPP - Requested conversion is not supported yet.
- *
- * Warning: We do not set the inode dirty and we do not write out anything!
- * We expect the caller to do this as this is a fairly low level
- * function and it is likely there will be further changes made.
- */
-static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
-{
- ntfs_volume *vol = na->ni->vol;
- ATTR_REC *a = ctx->attr;
- int name_ofs, val_ofs;
- s64 arec_size, bytes_read;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
- long)na->ni->mft_no, na->type);
-
- /* Should be called for the first extent of the attribute. */
- if (sle64_to_cpu(a->u.nonres.lowest_vcn)) {
- ntfs_log_trace("Should be called for the first extent of the "
- "attribute. Aborting...\n");
- errno = EINVAL;
- return -1;
- }
-
- /* Some preliminary sanity checking. */
- if (!NAttrNonResident(na)) {
- ntfs_log_trace("Trying to make resident attribute resident. "
- "Aborting...\n");
- errno = EINVAL;
- return -1;
- }
-
- /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */
- if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) {
- errno = EPERM;
- return -1;
- }
-
- /* Check that the attribute is allowed to be resident. */
- if (ntfs_attr_can_be_resident(vol, na->type))
- return -1;
-
- /*
- * Check that the attribute name hasn't been placed after the
- * mapping pairs array. Chkdsk treat this as corruption.
- */
- if (a->name_length && le16_to_cpu(a->name_offset) >=
- le16_to_cpu(a->u.nonres.mapping_pairs_offset)) {
- ntfs_log_trace("Damaged attribute. Name is placed after the "
- "mapping pairs array. Run chkdsk. Aborting.\n");
- errno = EIO;
- return -1;
- }
-
- if (NAttrCompressed(na) || NAttrEncrypted(na)) {
- ntfs_log_trace("Making compressed or encrypted files resident "
- "is not implemented yet.\n");
- errno = EOPNOTSUPP;
- return -1;
- }
-
- /* Work out offsets into and size of the resident attribute. */
- name_ofs = 24; /* = sizeof(resident_ATTR_REC); */
- val_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
- arec_size = (val_ofs + na->data_size + 7) & ~7;
-
- /* Sanity check the size before we start modifying the attribute. */
- if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) +
- arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) {
- ntfs_log_trace("Not enough space to make attribute resident\n");
- errno = ENOSPC;
- return -1;
- }
-
- /* Read and cache the whole runlist if not already done. */
- if (ntfs_attr_map_whole_runlist(na))
- return -1;
-
- /* Move the attribute name if it exists and update the offset. */
- if (a->name_length) {
- memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
- a->name_length * sizeof(ntfschar));
- }
- a->name_offset = cpu_to_le16(name_ofs);
-
- /* Resize the resident part of the attribute record. */
- if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) {
- /*
- * Bug, because ntfs_attr_record_resize should not fail (we
- * already checked that attribute fits MFT record).
- */
- ntfs_log_error("BUG! Failed to resize attribute record. "
- "Please report to the %s. Aborting...\n",
- NTFS_DEV_LIST);
- errno = EIO;
- return -1;
- }
-
- /* Convert the attribute record to describe a resident attribute. */
- a->non_resident = 0;
- a->flags = 0;
- a->u.res.value_length = cpu_to_le32(na->data_size);
- a->u.res.value_offset = cpu_to_le16(val_ofs);
- /*
- * File names cannot be non-resident so we would never see this here
- * but at least it serves as a reminder that there may be attributes
- * for which we do need to set this flag. (AIA)
- */
- if (a->type == AT_FILE_NAME)
- a->u.res.resident_flags = RESIDENT_ATTR_IS_INDEXED;
- else
- a->u.res.resident_flags = 0;
- a->u.res.reservedR = 0;
-
- /* Sanity fixup... Shouldn't really happen. (AIA) */
- if (na->initialized_size > na->data_size)
- na->initialized_size = na->data_size;
-
- /* Copy data from run list to resident attribute value. */
- bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size,
- (u8*)a + val_ofs);
- if (bytes_read != na->initialized_size) {
- if (bytes_read >= 0)
- errno = EIO;
- ntfs_log_trace("Eeek! Failed to read attribute data. Leaving "
- "inconsistent metadata. Run chkdsk. "
- "Aborting...\n");
- return -1;
- }
-
- /* Clear memory in gap between initialized_size and data_size. */
- if (na->initialized_size < na->data_size)
- memset((u8*)a + val_ofs + na->initialized_size, 0,
- na->data_size - na->initialized_size);
-
- /*
- * Deallocate clusters from the runlist.
- *
- * NOTE: We can use ntfs_cluster_free() because we have already mapped
- * the whole run list and thus it doesn't matter that the attribute
- * record is in a transiently corrupted state at this moment in time.
- */
- if (ntfs_cluster_free(vol, na, 0, -1) < 0) {
- ntfs_log_perror("Eeek! Failed to release allocated clusters");
- ntfs_log_trace("Ignoring error and leaving behind wasted "
- "clusters.\n");
- }
-
- /* Throw away the now unused runlist. */
- free(na->rl);
- na->rl = NULL;
-
- /* Update in-memory struct ntfs_attr. */
- NAttrClearNonResident(na);
- NAttrClearCompressed(na);
- NAttrClearSparse(na);
- NAttrClearEncrypted(na);
- na->initialized_size = na->data_size;
- na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7;
- na->compression_block_size = 0;
- na->compression_block_size_bits = na->compression_block_clusters = 0;
- return 0;
-}
-
-#define NTFS_VCN_DELETE_MARK -2
-/**
- * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute
- * @na: non-resident ntfs open attribute for which we need update
- * @from_vcn: update runlist starting this VCN
- *
- * Build mapping pairs from @na->rl and write them to the disk. Also, this
- * function updates sparse bit, allocated and compressed size (allocates/frees
- * space for this field if required).
- *
- * @na->allocated_size should be set to correct value for the new runlist before
- * call to this function. Vice-versa @na->compressed_size will be calculated and
- * set to correct value during this function.
- *
- * New runlist should be fully formed starting @from_vcn. Runs before @from_vcn
- * can be mapped or not, but on-disk structures should not be modified before
- * call to this function so they can be mapped if necessary.
- *
- * FIXME: Make it O(1) for sparse files too, not only for normal.
- *
- * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define.
- *
- * NOTE: Be careful in the future with updating bits on compressed files (at
- * present assumed that on-disk flag is already set/cleared before call to
- * this function).
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- * The following error codes are defined:
- * EINVAL - Invalid arguments passed.
- * ENOMEM - Not enough memory to complete operation.
- * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST
- * or there is no free MFT records left to allocate.
- */
-int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn)
-{
- ntfs_attr_search_ctx *ctx;
- ntfs_inode *ni, *base_ni;
- MFT_RECORD *m;
- ATTR_RECORD *a;
- VCN stop_vcn;
- int err, mp_size, cur_max_mp_size, exp_max_mp_size;
- BOOL finished_build;
-
-retry:
- if (!na || !na->rl) {
- ntfs_log_trace("Invalid parameters passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (!NAttrNonResident(na)) {
- ntfs_log_trace("Attribute should be non resident.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, from vcn 0x%lld."
- "\n", (unsigned long long)na->ni->mft_no, na->type,
- from_vcn);
-
- if (na->ni->nr_extents == -1)
- base_ni = na->ni->u.base_ni;
- else
- base_ni = na->ni;
-
- ctx = ntfs_attr_get_search_ctx(base_ni, NULL);
- if (!ctx) {
- ntfs_log_trace("Couldn't get search context.\n");
- return -1;
- }
-
- /* Fill attribute records with new mapping pairs. */
- stop_vcn = 0;
- finished_build = FALSE;
- while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
- CASE_SENSITIVE, ctx->is_first ? 0 : from_vcn,
- NULL, 0, ctx)) {
- a = ctx->attr;
- m = ctx->mrec;
- /*
- * If runlist is updating not from the beginning, then set
- * @stop_vcn properly, i.e. to the lowest vcn of record that
- * contain @from_vcn. Also we do not need @from_vcn anymore,
- * set it to 0 to make ntfs_attr_lookup enumerate attributes.
- */
- if (from_vcn && a->u.nonres.lowest_vcn) {
- LCN first_lcn;
-
- stop_vcn = sle64_to_cpu(a->u.nonres.lowest_vcn);
- from_vcn = 0;
- /*
- * Check whether the first run we need to update is
- * the last run in runlist, if so, then deallocate
- * all attribute extents starting this one.
- */
- first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn);
- if (first_lcn == LCN_EINVAL) {
- ntfs_log_trace("BUG! Incorrect runlist.\n");
- err = EIO;
- goto put_err_out;
- }
- if (first_lcn == LCN_ENOENT ||
- first_lcn == LCN_RL_NOT_MAPPED)
- finished_build = TRUE;
- }
-
- /*
- * Check whether we finished mapping pairs build, if so mark
- * extent as need to delete (by setting highest vcn to
- * NTFS_VCN_DELETE_MARK (-2), we shall check it later and
- * delete extent) and continue search.
- */
- if (finished_build) {
- ntfs_log_trace("Mark attr 0x%x for delete in inode "
- "0x%llx.\n", (unsigned)le32_to_cpu(
- a->type), ctx->ntfs_ino->mft_no);
- a->u.nonres.highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK);
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- continue;
- }
-
- /*
- * Check that the attribute name hasn't been placed after the
- * mapping pairs array. Windows treat this as a corruption.
- */
- if (a->name_length) {
- if (le16_to_cpu(a->name_offset) >=
- le16_to_cpu(a->u.nonres.mapping_pairs_offset)) {
- ntfs_log_error("Damaged attribute. Name is "
- "placed after the mapping "
- "pairs array. Run chkdsk.\n");
- err = EIO;
- goto put_err_out;
- }
- }
- /*
- * If we in the first extent, then set/clean sparse bit,
- * update allocated and compressed size.
- */
- if (!a->u.nonres.lowest_vcn) {
- int sparse;
-
- /* Update allocated size. */
- a->u.nonres.allocated_size = cpu_to_sle64(na->allocated_size);
- /*
- * Check whether part of runlist we are updating is
- * sparse.
- */
- sparse = ntfs_rl_sparse(na->rl);
- if (sparse == -1) {
- ntfs_log_trace("Bad runlist.\n");
- err = errno;
- goto put_err_out;
- }
- /*
- * If new part or on-disk attribute is not sparse, then
- * we should fully map runlist to make final decision.
- */
- if (sparse || (a->flags & ATTR_IS_SPARSE)) {
- if (from_vcn && ntfs_attr_map_runlist_range(na,
- 0, from_vcn - 1)) {
- ntfs_log_trace("Failed to map runlist "
- "before @from_vcn.\n");
- err = errno;
- goto put_err_out;
- }
- /*
- * Reconsider whether whole runlist is sparse
- * if new part is not.
- */
- if (!sparse) {
- sparse = ntfs_rl_sparse(na->rl);
- if (sparse == -1) {
- ntfs_log_trace("Bad "
- "runlist.\n");
- err = errno;
- goto put_err_out;
- }
- }
- }
- /* Attribute becomes sparse/compressed. */
- if (sparse && !(a->flags & (ATTR_IS_SPARSE |
- ATTR_IS_COMPRESSED))) {
- /*
- * We need to move attribute to another mft
- * record, if attribute is to small to add
- * compressed_size field to it and we have no
- * free space in the current mft record.
- */
- if ((le32_to_cpu(a->length) - le16_to_cpu(
- a->u.nonres.mapping_pairs_offset)
- == 8) && !(le32_to_cpu(
- m->bytes_allocated) -
- le32_to_cpu(m->bytes_in_use))) {
- if (!NInoAttrList(na->ni)) {
- ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_add_attrlist(
- na->ni))
- return -1;
- goto retry;
- }
- if (ntfs_attr_record_move_away(ctx,
- 8)) {
- ntfs_log_trace("Failed to move "
- "attribute to another "
- "extent. Aborting..\n");
- err = errno;
- goto put_err_out;
- }
- ntfs_attr_put_search_ctx(ctx);
- goto retry;
- }
- if (!(le32_to_cpu(a->length) - le16_to_cpu(
- a->u.nonres.mapping_pairs_offset))) {
- ntfs_log_trace("Size of the space "
- "allocated for mapping "
- "pairs should not be 0."
- " Aborting ...\n");
- err = EIO;
- goto put_err_out;
- }
- NAttrSetSparse(na);
- a->flags |= ATTR_IS_SPARSE;
- a->u.nonres.compression_unit = 4; /* Windows set it so,
- even if attribute
- is not actually
- compressed. */
- memmove((u8*)a + le16_to_cpu(a->name_offset) +
- 8, (u8*)a + le16_to_cpu(a->name_offset),
- a->name_length * sizeof(ntfschar));
- a->name_offset = cpu_to_le16(le16_to_cpu(
- a->name_offset) + 8);
- a->u.nonres.mapping_pairs_offset =
- cpu_to_le16(le16_to_cpu(
- a->u.nonres.mapping_pairs_offset) + 8);
- /*
- * We should update all mapping pairs, because
- * we shifted their starting position.
- */
- from_vcn = 0;
- }
- /* Attribute becomes normal. */
- if (!sparse && (a->flags & ATTR_IS_SPARSE) &&
- !(a->flags & ATTR_IS_COMPRESSED)) {
- NAttrClearSparse(na);
- a->flags &= ~ATTR_IS_SPARSE;
- a->u.nonres.compression_unit = 0;
- memmove((u8*)a + le16_to_cpu(a->name_offset) -
- 8, (u8*)a + le16_to_cpu(a->name_offset),
- a->name_length * sizeof(ntfschar));
- /*
- * Windows defragmentation tool do not update
- * name offset correctly for unnamed
- * attributes, but chkdsk do not like when it
- * negative, so do not change it at all if it
- * would become negative.
- */
- if (le16_to_cpu(a->name_offset) >= 8)
- a->name_offset = cpu_to_le16(
- le16_to_cpu(
- a->name_offset) - 8);
- a->u.nonres.mapping_pairs_offset =
- cpu_to_le16(le16_to_cpu(
- a->u.nonres.mapping_pairs_offset) - 8);
- /*
- * We should update all mapping pairs, because
- * we shifted their starting position.
- */
- from_vcn = 0;
- }
- /* Update compressed size if required. */
- if (sparse || (a->flags & ATTR_IS_COMPRESSED)) {
- s64 new_compr_size;
-
- new_compr_size = ntfs_rl_get_compressed_size(
- na->ni->vol, na->rl);
- if (new_compr_size == -1) {
- err = errno;
- ntfs_log_trace("BUG! Leaving "
- "inconsistent "
- "metadata.\n");
- goto put_err_out;
- }
- na->compressed_size = new_compr_size;
- a->u.nonres.compressed_size = cpu_to_sle64(
- new_compr_size);
- }
- /*
- * Set FILE_NAME dirty flag, to update sparse bit and
- * allocated size in the index.
- */
- if (na->type == AT_DATA && na->name == AT_UNNAMED) {
- if (sparse)
- na->ni->allocated_size =
- na->compressed_size;
- else
- na->ni->allocated_size =
- na->allocated_size;
- NInoFileNameSetDirty(na->ni);
- }
-
- /*
- * We do want to do anything for the first extent in
- * case we are updating mapping pairs not from the
- * begging.
- */
- if (!a->u.nonres.highest_vcn || from_vcn <=
- sle64_to_cpu(a->u.nonres.highest_vcn) + 1)
- from_vcn = 0;
- else {
- if (from_vcn)
- continue;
- }
- }
-
- /* Get the size for the rest of mapping pairs array. */
- mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl,
- stop_vcn);
- if (mp_size <= 0) {
- err = errno;
- ntfs_log_trace("Get size for mapping pairs failed.\n");
- goto put_err_out;
- }
- /*
- * Determine maximum possible length of mapping pairs,
- * if we shall *not* expand space for mapping pairs.
- */
- cur_max_mp_size = le32_to_cpu(a->length) -
- le16_to_cpu(a->u.nonres.mapping_pairs_offset);
- /*
- * Determine maximum possible length of mapping pairs in the
- * current mft record, if we shall expand space for mapping
- * pairs.
- */
- exp_max_mp_size = le32_to_cpu(m->bytes_allocated) -
- le32_to_cpu(m->bytes_in_use) + cur_max_mp_size;
- /* Test mapping pairs for fitting in the current mft record. */
- if (mp_size > exp_max_mp_size) {
- /*
- * Mapping pairs of $ATTRIBUTE_LIST attribute must fit
- * in the base mft record. Try to move out other
- * attributes and try again.
- */
- if (na->type == AT_ATTRIBUTE_LIST) {
- ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_free_space(na->ni, mp_size -
- cur_max_mp_size)) {
- if (errno != ENOSPC)
- return -1;
- ntfs_log_error("Attribute list mapping "
- "pairs size to big, "
- "can't fit them in the "
- "base MFT record. "
- "Defragment volume and "
- "try once again.\n");
- errno = ENOSPC;
- return -1;
- }
- goto retry;
- }
-
- /* Add attribute list if it isn't present, and retry. */
- if (!NInoAttrList(base_ni)) {
- ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_add_attrlist(base_ni)) {
- ntfs_log_trace("Couldn't add attribute "
- "list.\n");
- return -1;
- }
- goto retry;
- }
-
- /*
- * Set mapping pairs size to maximum possible for this
- * mft record. We shall write the rest of mapping pairs
- * to another MFT records.
- */
- mp_size = exp_max_mp_size;
- }
-
- /* Change space for mapping pairs if we need it. */
- if (((mp_size + 7) & ~7) != cur_max_mp_size) {
- if (ntfs_attr_record_resize(m, a,
- le16_to_cpu(a->u.nonres.mapping_pairs_offset) +
- mp_size)) {
- ntfs_log_error("BUG! Ran out of space in mft "
- "record. Please run chkdsk and "
- "if that doesn't find any "
- "errors please report you saw "
- "this message to %s.\n",
- NTFS_DEV_LIST);
- err = EIO;
- goto put_err_out;
- }
- }
-
- /* Update lowest vcn. */
- a->u.nonres.lowest_vcn = cpu_to_sle64(stop_vcn);
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- if ((ctx->ntfs_ino->nr_extents == -1 ||
- NInoAttrList(ctx->ntfs_ino)) &&
- ctx->attr->type != AT_ATTRIBUTE_LIST) {
- ctx->al_entry->lowest_vcn = cpu_to_sle64(stop_vcn);
- ntfs_attrlist_mark_dirty(ctx->ntfs_ino);
- }
-
- /*
- * Generate the new mapping pairs array directly into the
- * correct destination, i.e. the attribute record itself.
- */
- if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu(
- a->u.nonres.mapping_pairs_offset), mp_size, na->rl,
- stop_vcn, &stop_vcn))
- finished_build = TRUE;
- if (!finished_build && errno != ENOSPC) {
- err = errno;
- ntfs_log_error("BUG! Mapping pairs build failed. "
- "Please run chkdsk and if that doesn't "
- "find any errors please report you saw "
- "this message to %s.\n", NTFS_DEV_LIST);
- goto put_err_out;
- }
- a->u.nonres.highest_vcn = cpu_to_sle64(stop_vcn - 1);
- }
- /* Check whether error occurred. */
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto put_err_out;
- }
- /* Sanity check. */
- if (from_vcn) {
- err = ENOMSG;
- ntfs_log_error("Library BUG! @from_vcn is nonzero, please "
- "report to %s.\n", NTFS_DEV_LIST);
- goto put_err_out;
- }
-
- /* Deallocate not used attribute extents and return with success. */
- if (finished_build) {
- ntfs_attr_reinit_search_ctx(ctx);
- ntfs_log_trace("Deallocate marked extents.\n");
- while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
- CASE_SENSITIVE, 0, NULL, 0, ctx)) {
- if (sle64_to_cpu(ctx->attr->u.nonres.highest_vcn) !=
- NTFS_VCN_DELETE_MARK)
- continue;
- /* Remove unused attribute record. */
- if (ntfs_attr_record_rm(ctx)) {
- err = errno;
- ntfs_log_trace("Couldn't remove unused "
- "attribute record.\n");
- goto put_err_out;
- }
- ntfs_attr_reinit_search_ctx(ctx);
- }
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto put_err_out;
- }
- ntfs_log_trace("Deallocate done.\n");
- ntfs_attr_put_search_ctx(ctx);
- ntfs_log_trace("Done!");
- return 0;
- }
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
-
- /* Allocate new MFT records for the rest of mapping pairs. */
- while (1) {
- /* Calculate size of rest mapping pairs. */
- mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol,
- na->rl, stop_vcn);
- if (mp_size <= 0) {
- err = errno;
- ntfs_log_trace("Get size for mapping pairs failed.\n");
- goto put_err_out;
- }
- /* Allocate new mft record. */
- ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
- if (!ni) {
- err = errno;
- ntfs_log_trace("Couldn't allocate new MFT record.\n");
- goto put_err_out;
- }
- m = ni->mrec;
- /*
- * If mapping size exceed available space, set them to
- * possible maximum.
- */
- cur_max_mp_size = le32_to_cpu(m->bytes_allocated) -
- le32_to_cpu(m->bytes_in_use) -
- (offsetof(ATTR_RECORD, u.nonres.compressed_size) +
- ((NAttrCompressed(na) || NAttrSparse(na)) ?
- sizeof(a->u.nonres.compressed_size) : 0)) -
- ((sizeof(ntfschar) * na->name_len + 7) & ~7);
- if (mp_size > cur_max_mp_size)
- mp_size = cur_max_mp_size;
- /* Add attribute extent to new record. */
- err = ntfs_non_resident_attr_record_add(ni, na->type,
- na->name, na->name_len, stop_vcn, mp_size, 0);
- if (err == -1) {
- err = errno;
- ntfs_log_trace("Couldn't add attribute extent into the "
- "MFT record.\n");
- if (ntfs_mft_record_free(na->ni->vol, ni)) {
- ntfs_log_trace("Couldn't free MFT record.\n");
- }
- goto put_err_out;
- }
- a = (ATTR_RECORD*)((u8*)m + err);
-
- err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a +
- le16_to_cpu(a->u.nonres.mapping_pairs_offset), mp_size, na->rl,
- stop_vcn, &stop_vcn);
- if (err < 0 && errno != ENOSPC) {
- err = errno;
- ntfs_log_error("BUG! Mapping pairs build failed. "
- "Please run chkdsk and if that doesn't "
- "find any errors please report you saw "
- "this message to %s.\n", NTFS_DEV_LIST);
- if (ntfs_mft_record_free(na->ni->vol, ni))
- ntfs_log_trace("Couldn't free MFT record.\n");
- goto put_err_out;
- }
- a->u.nonres.highest_vcn = cpu_to_sle64(stop_vcn - 1);
- ntfs_inode_mark_dirty(ni);
- /* All mapping pairs has been written. */
- if (!err)
- break;
- }
- ntfs_log_trace("Done!\n");
- return 0;
-put_err_out:
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-#undef NTFS_VCN_DELETE_MARK
-
-/**
- * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute
- * @na: non-resident ntfs attribute to shrink
- * @newsize: new size (in bytes) to which to shrink the attribute
- *
- * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- * The following error codes are defined:
- * ENOMEM - Not enough memory to complete operation.
- * ERANGE - @newsize is not valid for the attribute type of @na.
- */
-static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
-{
- ntfs_volume *vol;
- ntfs_attr_search_ctx *ctx;
- VCN first_free_vcn;
- s64 nr_freed_clusters;
- int err;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, newsize %lld.\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)newsize);
-
- vol = na->ni->vol;
-
- /*
- * Check the attribute type and the corresponding minimum size
- * against @newsize and fail if @newsize is too small.
- */
- if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
- if (errno == ERANGE) {
- ntfs_log_trace("Eeek! Size bounds check failed. "
- "Aborting...\n");
- } else if (errno == ENOENT)
- errno = EIO;
- return -1;
- }
-
- /* The first cluster outside the new allocation. */
- first_free_vcn = (newsize + vol->cluster_size - 1) >>
- vol->cluster_size_bits;
- /*
- * Compare the new allocation with the old one and only deallocate
- * clusters if there is a change.
- */
- if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) {
- if (ntfs_attr_map_whole_runlist(na)) {
- ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist "
- "failed.\n");
- return -1;
- }
- /* Deallocate all clusters starting with the first free one. */
- nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn,
- -1);
- if (nr_freed_clusters < 0) {
- ntfs_log_trace("Eeek! Freeing of clusters failed. "
- "Aborting...\n");
- return -1;
- }
-
- /* Truncate the runlist itself. */
- if (ntfs_rl_truncate(&na->rl, first_free_vcn)) {
- err = errno;
- /*
- * Failed to truncate the runlist, so just throw it
- * away, it will be mapped afresh on next use.
- */
- free(na->rl);
- na->rl = NULL;
- ntfs_log_trace("Eeek! Run list truncation failed.\n");
- errno = err;
- return -1;
- }
-
- /* Prepare to mapping pairs update. */
- na->allocated_size = first_free_vcn << vol->cluster_size_bits;
- /* Write mapping pairs for new runlist. */
- if (ntfs_attr_update_mapping_pairs(na, first_free_vcn)) {
- ntfs_log_trace("Eeek! Mapping pairs update failed. "
- "Leaving inconsistent metadata. "
- "Run chkdsk.\n");
- return -1;
- }
- }
-
- /* Get the first attribute record. */
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx) {
- ntfs_log_trace("Couldn't get attribute search context.\n");
- return -1;
- }
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- err = errno;
- if (err == ENOENT)
- err = EIO;
- ntfs_log_trace("Eeek! Lookup of first attribute extent failed. "
- "Leaving inconsistent metadata.\n");
- goto put_err_out;
- }
-
- /* Update data and initialized size. */
- na->data_size = newsize;
- ctx->attr->u.nonres.data_size = cpu_to_sle64(newsize);
- if (newsize < na->initialized_size) {
- na->initialized_size = newsize;
- ctx->attr->u.nonres.initialized_size = cpu_to_sle64(newsize);
- }
- /* Update data size in the index. */
- if (na->type == AT_DATA && na->name == AT_UNNAMED) {
- na->ni->data_size = na->data_size;
- NInoFileNameSetDirty(na->ni);
- }
-
- /* If the attribute now has zero size, make it resident. */
- if (!newsize) {
- if (ntfs_attr_make_resident(na, ctx)) {
- /* If couldn't make resident, just continue. */
- if (errno != EPERM)
- ntfs_log_error("Failed to make attribute "
- "resident. Leaving as is...\n");
- }
- }
-
- /* Set the inode dirty so it is written out later. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- /* Done! */
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute
- * @na: non-resident ntfs attribute to expand
- * @newsize: new size (in bytes) to which to expand the attribute
- * @sparse: if TRUE then will create hole if possible
- *
- * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes,
- * by allocating new clusters.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- * The following error codes are defined:
- * ENOMEM - Not enough memory to complete operation.
- * ERANGE - @newsize is not valid for the attribute type of @na.
- * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
- */
-static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
- BOOL sparse)
-{
- VCN first_free_vcn;
- ntfs_volume *vol;
- ntfs_attr_search_ctx *ctx;
- runlist *rl, *rln;
- s64 org_alloc_size;
- int err;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, new size %lld, "
- "current size %lld.\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)newsize, (long long)na->data_size);
-
- vol = na->ni->vol;
-
- /*
- * Check the attribute type and the corresponding maximum size
- * against @newsize and fail if @newsize is too big.
- */
- if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
- if (errno == ERANGE) {
- ntfs_log_trace("Eeek! Size bounds check failed. "
- "Aborting...\n");
- } else if (errno == ENOENT)
- errno = EIO;
- return -1;
- }
-
- /* Save for future use. */
- org_alloc_size = na->allocated_size;
- /* The first cluster outside the new allocation. */
- first_free_vcn = (newsize + vol->cluster_size - 1) >>
- vol->cluster_size_bits;
- /*
- * Compare the new allocation with the old one and only allocate
- * clusters if there is a change.
- */
- if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) {
- /* Map required part of runlist. */
- if (ntfs_attr_map_runlist(na, na->allocated_size >>
- vol->cluster_size_bits)) {
- ntfs_log_error("Failed to map runlist.\n");
- return -1;
- }
-
- /*
- * If we extend $DATA attribute on NTFS 3+ volume, we can add
- * sparse runs instead of real allocation of clusters.
- */
- if (na->type == AT_DATA && vol->major_ver >= 3 && sparse) {
- rl = ntfs_malloc(0x1000);
- if (!rl)
- return -1;
-
- rl[0].vcn = (na->allocated_size >>
- vol->cluster_size_bits);
- rl[0].lcn = LCN_HOLE;
- rl[0].length = first_free_vcn -
- (na->allocated_size >> vol->cluster_size_bits);
- rl[1].vcn = first_free_vcn;
- rl[1].lcn = LCN_ENOENT;
- rl[1].length = 0;
- } else {
- /*
- * Determine first after last LCN of attribute.
- * We will start seek clusters from this LCN to avoid
- * fragmentation. If there are no valid LCNs in the
- * attribute let the cluster allocator choose the
- * starting LCN.
- */
- LCN lcn_seek_from;
-
- lcn_seek_from = -1;
- if (na->rl->length) {
- /* Seek to the last run list element. */
- for (rl = na->rl; (rl + 1)->length; rl++)
- ;
- /*
- * If the last LCN is a hole or similar seek
- * back to last valid LCN.
- */
- while (rl->lcn < 0 && rl != na->rl)
- rl--;
- /*
- * Only set lcn_seek_from it the LCN is valid.
- */
- if (rl->lcn >= 0)
- lcn_seek_from = rl->lcn + rl->length;
- }
-
- rl = ntfs_cluster_alloc(vol, na->allocated_size >>
- vol->cluster_size_bits, first_free_vcn -
- (na->allocated_size >>
- vol->cluster_size_bits), lcn_seek_from,
- DATA_ZONE);
- if (!rl) {
- ntfs_log_trace("Cluster allocation failed.\n");
- return -1;
- }
- }
-
- /* Append new clusters to attribute runlist. */
- rln = ntfs_runlists_merge(na->rl, rl);
- if (!rln) {
- /* Failed, free just allocated clusters. */
- err = errno;
- ntfs_log_trace("Run list merge failed.\n");
- ntfs_cluster_free_from_rl(vol, rl);
- free(rl);
- errno = err;
- return -1;
- }
- na->rl = rln;
-
- /* Prepare to mapping pairs update. */
- na->allocated_size = first_free_vcn << vol->cluster_size_bits;
- /* Write mapping pairs for new runlist. */
- if (ntfs_attr_update_mapping_pairs(na, org_alloc_size >>
- vol->cluster_size_bits)) {
- err = errno;
- ntfs_log_trace("Mapping pairs update failed.\n");
- goto rollback;
- }
- }
-
- ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
- if (!ctx) {
- ntfs_log_trace("Failed to get search context.\n");
- if (na->allocated_size == org_alloc_size) {
- return -1;
- }
- err = errno;
- goto rollback;
- }
-
- if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- err = errno;
- ntfs_log_trace("Lookup of first attribute extent failed.\n");
- if (err == ENOENT)
- err = EIO;
- if (na->allocated_size != org_alloc_size) {
- ntfs_attr_put_search_ctx(ctx);
- goto rollback;
- } else
- goto put_err_out;
- }
-
- /* Update data size. */
- na->data_size = newsize;
- ctx->attr->u.nonres.data_size = cpu_to_sle64(newsize);
- /* Update data size in the index. */
- if (na->type == AT_DATA && na->name == AT_UNNAMED) {
- na->ni->data_size = na->data_size;
- NInoFileNameSetDirty(na->ni);
- }
- /* Set the inode dirty so it is written out later. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- /* Done! */
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-rollback:
- /* Free allocated clusters. */
- if (ntfs_cluster_free(vol, na, org_alloc_size >>
- vol->cluster_size_bits, -1) < 0) {
- ntfs_log_trace("Eeek! Leaking clusters. Run chkdsk!\n");
- err = EIO;
- }
- /* Now, truncate the runlist itself. */
- if (ntfs_rl_truncate(&na->rl, org_alloc_size >>
- vol->cluster_size_bits)) {
- /*
- * Failed to truncate the runlist, so just throw it away, it
- * will be mapped afresh on next use.
- */
- free(na->rl);
- na->rl = NULL;
- ntfs_log_trace("Couldn't truncate runlist. Rollback failed.\n");
- } else {
- /* Prepare to mapping pairs update. */
- na->allocated_size = org_alloc_size;
- /* Restore mapping pairs. */
- if (ntfs_attr_update_mapping_pairs(na, na->allocated_size >>
- vol->cluster_size_bits)) {
- ntfs_log_trace("Failed to restore old mapping pairs. "
- "Rollback failed.\n");
- }
- }
- errno = err;
- return -1;
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-
-/**
- * __ntfs_attr_truncate - resize an ntfs attribute
- * @na: open ntfs attribute to resize
- * @newsize: new size (in bytes) to which to resize the attribute
- * @sparse: if TRUE then will create hole if possible
- *
- * Change the size of an open ntfs attribute @na to @newsize bytes. If the
- * attribute is made bigger and the attribute is resident the newly
- * "allocated" space is cleared and if the attribute is non-resident the
- * newly allocated space is marked as not initialised and no real allocation
- * on disk is performed.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- * The following error codes are defined:
- * EINVAL - Invalid arguments were passed to the function.
- * EACCES - Attribute is encrypted.
- * ERANGE - @newsize is not valid for the attribute type of @na.
- * ENOSPC - There is no enough space on the volume to allocate
- * new clusters or in base mft to resize $ATTRIBUTE_LIST.
- * EOVERFLOW - Resident attribute can not become non resident and
- * already filled whole MFT record, but had not reached
- * @newsize bytes length.
- * EOPNOTSUPP - The desired resize is not implemented yet.
- */
-int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse)
-{
- int ret;
-
- if (!na || newsize < 0 ||
- (na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) {
- ntfs_log_trace("Invalid arguments passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
- long)na->ni->mft_no, na->type);
-
- if (na->data_size == newsize)
- return 0;
- /*
- * Encrypted attributes are not supported. We return access denied,
- * which is what Windows NT4 does, too.
- */
- if (NAttrEncrypted(na)) {
- errno = EACCES;
- ntfs_log_trace("Failed (encrypted).\n");
- return -1;
- }
- /*
- * TODO: Implement making handling of compressed attributes.
- */
- if (NAttrCompressed(na)) {
- errno = EOPNOTSUPP;
- ntfs_log_trace("Failed (compressed).\n");
- return -1;
- }
- if (NAttrNonResident(na)) {
- if (newsize > na->data_size)
- ret = ntfs_non_resident_attr_expand(na, newsize,
- sparse);
- else
- ret = ntfs_non_resident_attr_shrink(na, newsize);
- } else
- ret = ntfs_resident_attr_resize(na, newsize);
- if (!ret)
- ntfs_log_trace("Done!\n");
- else
- ntfs_log_trace("Failed.\n");
- return ret;
-}
-
-
-/**
- * Wrapper around __ntfs_attr_truncate that always tries to creates hole
- */
-int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
-{
- return __ntfs_attr_truncate(na, newsize, TRUE);
-}
-
-
-/**
- * ntfs_attr_readall - read the entire data from an ntfs attribute
- * @ni: open ntfs inode in which the ntfs attribute resides
- * @type: attribute type
- * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL
- * @name_len: length of attribute @name in Unicode characters (if @name given)
- * @data_size: if non-NULL then store here the data size
- *
- * This function will read the entire content of an ntfs attribute.
- * If @name is AT_UNNAMED then look specifically for an unnamed attribute.
- * If @name is NULL then the attribute could be either named or not.
- * In both those cases @name_len is not used at all.
- *
- * On success a buffer is allocated with the content of the attribute
- * and which needs to be freed when it's not needed anymore. If the
- * @data_size parameter is non-NULL then the data size is set there.
- *
- * On error NULL is returned with errno set to the error code.
- */
-void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
- ntfschar *name, u32 name_len, s64 *data_size)
-{
- ntfs_attr *na;
- void *data, *ret = NULL;
- s64 size;
-
- na = ntfs_attr_open(ni, type, name, name_len);
- if (!na) {
- ntfs_log_perror("ntfs_attr_open failed");
- return NULL;
- }
- data = ntfs_malloc(na->data_size);
- if (!data)
- goto out;
-
- size = ntfs_attr_pread(na, 0, na->data_size, data);
- if (size != na->data_size) {
- ntfs_log_perror("ntfs_attr_pread failed");
- free(data);
- goto out;
- }
- ret = data;
- if (data_size)
- *data_size = size;
-out:
- ntfs_attr_close(na);
- return ret;
-}
-
-/**
- * ntfs_attr_exist - FIXME: description
- */
-int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
- u32 name_len)
-{
- ntfs_attr_search_ctx *ctx;
- int ret;
-
- ntfs_log_trace("Entering.\n");
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- return 0;
-
- ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0,
- ctx);
-
- ntfs_attr_put_search_ctx(ctx);
- return !ret;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/attrlist.c b/usr/src/lib/libntfs/common/libntfs/attrlist.c
deleted file mode 100644
index 3bbc6a3ca8..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/attrlist.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/**
- * attrlist.c - Attribute list attribute handling code. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "layout.h"
-#include "attrib.h"
-#include "attrlist.h"
-#include "debug.h"
-#include "unistr.h"
-#include "logging.h"
-
-/**
- * ntfs_attrlist_need - check whether inode need attribute list
- * @ni: opened ntfs inode for which perform check
- *
- * Check whether all are attributes belong to one MFT record, in that case
- * attribute list is not needed.
- *
- * Return 1 if inode need attribute list, 0 if not, -1 on error with errno set
- * to the error code. If function succeed errno set to 0. The following error
- * codes are defined:
- * EINVAL - Invalid arguments passed to function or attribute haven't got
- * attribute list.
- */
-int ntfs_attrlist_need(ntfs_inode *ni)
-{
- ATTR_LIST_ENTRY *ale;
-
- if (!ni) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- if (!NInoAttrList(ni)) {
- ntfs_log_trace("Inode haven't got attribute list.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (!ni->attr_list) {
- ntfs_log_trace("Corrupt in-memory struct.\n");
- errno = EINVAL;
- return -1;
- }
-
- errno = 0;
- ale = (ATTR_LIST_ENTRY *)ni->attr_list;
- while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
- if (MREF_LE(ale->mft_reference) != ni->mft_no)
- return 1;
- ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
- }
- return 0;
-}
-
-/**
- * ntfs_attrlist_entry_add - add an attribute list attribute entry
- * @ni: opened ntfs inode, which contains that attribute
- * @attr: attribute record to add to attribute list
- *
- * Return 0 on success and -1 on error with errno set to the error code. The
- * following error codes are defined:
- * EINVAL - Invalid arguments passed to function.
- * ENOMEM - Not enough memory to allocate necessary buffers.
- * EIO - I/O error occurred or damaged filesystem.
- * EEXIST - Such attribute already present in attribute list.
- */
-int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
-{
- ATTR_LIST_ENTRY *ale;
- leMFT_REF mref;
- ntfs_attr *na = NULL;
- ntfs_attr_search_ctx *ctx;
- u8 *new_al;
- int entry_len, entry_offset, err;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
- (long long) ni->mft_no,
- (unsigned) le32_to_cpu(attr->type));
-
- if (!ni || !attr) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
-
- if (ni->nr_extents == -1)
- ni = ni->u.base_ni;
-
- if (!NInoAttrList(ni)) {
- ntfs_log_trace("Attribute list isn't present.\n");
- errno = ENOENT;
- return -1;
- }
-
- /* Determine size and allocate memory for new attribute list. */
- entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
- attr->name_length + 7) & ~7;
- new_al = malloc(ni->attr_list_size + entry_len);
- if (!new_al) {
- ntfs_log_trace("Not enough memory.\n");
- err = ENOMEM;
- return -1;
- }
-
- /* Find place for the new entry. */
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx) {
- err = errno;
- ntfs_log_trace("Failed to obtain attribute search context.\n");
- goto err_out;
- }
- if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
- ((u8*)attr + le16_to_cpu(attr->name_offset)) :
- AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
- (attr->non_resident) ? sle64_to_cpu(attr->u.nonres.lowest_vcn) :
- 0, (attr->non_resident) ? NULL : ((u8*)attr +
- le16_to_cpu(attr->u.res.value_offset)), (attr->non_resident) ?
- 0 : le32_to_cpu(attr->u.res.value_length), ctx)) {
- /* Found some extent, check it to be before new extent. */
- if (ctx->al_entry->lowest_vcn == attr->u.nonres.lowest_vcn) {
- err = EEXIST;
- ntfs_log_trace("Such attribute already present in the "
- "attribute list.\n");
- ntfs_attr_put_search_ctx(ctx);
- goto err_out;
- }
- /* Add new entry after this extent. */
- ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
- le16_to_cpu(ctx->al_entry->length));
- } else {
- /* Check for real errors. */
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- ntfs_attr_put_search_ctx(ctx);
- goto err_out;
- }
- /* No previous extents found. */
- ale = ctx->al_entry;
- }
- /* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
- ntfs_attr_put_search_ctx(ctx);
-
- /* Determine new entry offset. */
- entry_offset = ((u8 *)ale - ni->attr_list);
- /* Set pointer to new entry. */
- ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
- /* Form new entry. */
- ale->type = attr->type;
- ale->length = cpu_to_le16(entry_len);
- ale->name_length = attr->name_length;
- ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
- if (attr->non_resident)
- ale->lowest_vcn = attr->u.nonres.lowest_vcn;
- else
- ale->lowest_vcn = 0;
- ale->mft_reference = mref;
- ale->instance = attr->instance;
- NTFS_ON_DEBUG(memset(ale->name, 0, ((u8*)((u8*)ale + entry_len)) -
- ((u8*)ale->name))); /* Shut up, valgrind. */
- memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
- attr->name_length * sizeof(ntfschar));
-
- /* Resize $ATTRIBUTE_LIST to new length. */
- na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
- if (!na) {
- err = errno;
- ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
- goto err_out;
- }
- if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
- err = errno;
- ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
- goto err_out;
- }
-
- /* Copy entries from old attribute list to new. */
- memcpy(new_al, ni->attr_list, entry_offset);
- memcpy(new_al + entry_offset + entry_len, ni->attr_list +
- entry_offset, ni->attr_list_size - entry_offset);
-
- /* Set new runlist. */
- free(ni->attr_list);
- ni->attr_list = new_al;
- ni->attr_list_size = ni->attr_list_size + entry_len;
- NInoAttrListSetDirty(ni);
- /* Done! */
- ntfs_attr_close(na);
- return 0;
-err_out:
- if (na)
- ntfs_attr_close(na);
- free(new_al);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_attrlist_entry_rm - remove an attribute list attribute entry
- * @ctx: attribute search context describing the attribute list entry
- *
- * Remove the attribute list entry @ctx->al_entry from the attribute list.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
-{
- u8 *new_al;
- int new_al_len;
- ntfs_inode *base_ni;
- ntfs_attr *na;
- ATTR_LIST_ENTRY *ale;
- int err;
-
- if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (ctx->base_ntfs_ino)
- base_ni = ctx->base_ntfs_ino;
- else
- base_ni = ctx->ntfs_ino;
- ale = ctx->al_entry;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld."
- "\n", (long long) ctx->ntfs_ino->mft_no,
- (unsigned) le32_to_cpu(ctx->al_entry->type),
- (long long) sle64_to_cpu(ctx->al_entry->lowest_vcn));
-
- if (!NInoAttrList(base_ni)) {
- ntfs_log_trace("Attribute list isn't present.\n");
- errno = ENOENT;
- return -1;
- }
-
- /* Allocate memory for new attribute list. */
- new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
- new_al = malloc(new_al_len);
- if (!new_al) {
- ntfs_log_trace("Not enough memory.\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* Reisze $ATTRIBUTE_LIST to new length. */
- na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
- if (!na) {
- err = errno;
- ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
- goto err_out;
- }
- if (ntfs_attr_truncate(na, new_al_len)) {
- err = errno;
- ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
- goto err_out;
- }
-
- /* Copy entries from old attribute list to new. */
- memcpy(new_al, base_ni->attr_list, (u8*)ale - base_ni->attr_list);
- memcpy(new_al + ((u8*)ale - base_ni->attr_list), (u8*)ale + le16_to_cpu(
- ale->length), new_al_len - ((u8*)ale - base_ni->attr_list));
-
- /* Set new runlist. */
- free(base_ni->attr_list);
- base_ni->attr_list = new_al;
- base_ni->attr_list_size = new_al_len;
- NInoAttrListSetDirty(base_ni);
- /* Done! */
- ntfs_attr_close(na);
- return 0;
-err_out:
- if (na)
- ntfs_attr_close(na);
- free(new_al);
- errno = err;
- return -1;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/bitmap.c b/usr/src/lib/libntfs/common/libntfs/bitmap.c
deleted file mode 100644
index 2f7d6bb84a..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/bitmap.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * bitmap.c - Bitmap handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2006 Anton Altaparmakov
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "attrib.h"
-#include "bitmap.h"
-#include "debug.h"
-#include "logging.h"
-
-/**
- * ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
- * @na: attribute containing the bitmap
- * @start_bit: first bit to set
- * @count: number of bits to set
- * @value: value to set the bits to (i.e. 0 or 1)
- *
- * Set @count bits starting at bit @start_bit in the bitmap described by the
- * attribute @na to @value, where @value is either 0 or 1.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
- s64 count, int value)
-{
- ntfs_volume *vol = na->ni->vol;
- s64 bufsize, br, left = count;
- u8 *buf, *lastbyte_buf;
- int bit, firstbyte, lastbyte, lastbyte_pos, tmp, err;
-
- if (!na || start_bit < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
-
- bit = start_bit & 7;
- if (bit)
- firstbyte = 1;
- else
- firstbyte = 0;
-
- /* Calculate the required buffer size in bytes, capping it at 8kiB. */
- bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
- if (bufsize > 8192)
- bufsize = 8192;
-
- buf = (u8*)ntfs_malloc(bufsize);
- if (!buf)
- return -1;
-
- /* Depending on @value, zero or set all bits in the allocated buffer. */
- memset(buf, value ? 0xff : 0, bufsize);
-
- /* If there is a first partial byte... */
- if (bit) {
- /* read it in... */
- br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
- if (br != 1) {
- free(buf);
- errno = EIO;
- return -1;
- }
- /* and set or clear the appropriate bits in it. */
- while ((bit & 7) && left--) {
- if (value)
- *buf |= 1 << bit++;
- else
- *buf &= ~(1 << bit++);
- }
- /* Update @start_bit to the new position. */
- start_bit = (start_bit + 7) & ~7;
- }
-
- /* Loop until @left reaches zero. */
- lastbyte = 0;
- lastbyte_buf = NULL;
- bit = left & 7;
- do {
- /* If there is a last partial byte... */
- if (left > 0 && bit) {
- lastbyte_pos = ((left + 7) >> 3) + firstbyte;
- if (!lastbyte_pos) {
- // FIXME: Eeek! BUG!
- ntfs_log_trace("lastbyte is zero. Leaving "
- "inconsistent metadata.\n");
- err = EIO;
- goto free_err_out;
- }
- /* and it is in the currently loaded bitmap window... */
- if (lastbyte_pos <= bufsize) {
- lastbyte_buf = buf + lastbyte_pos - 1;
-
- /* read the byte in... */
- br = ntfs_attr_pread(na, (start_bit + left) >>
- 3, 1, lastbyte_buf);
- if (br != 1) {
- // FIXME: Eeek! We need rollback! (AIA)
- ntfs_log_trace("Read of last byte "
- "failed. Leaving "
- "inconsistent "
- "metadata.\n");
- err = EIO;
- goto free_err_out;
- }
- /* and set/clear the appropriate bits in it. */
- while (bit && left--) {
- if (value)
- *lastbyte_buf |= 1 << --bit;
- else
- *lastbyte_buf &= ~(1 << --bit);
- }
- /* We don't want to come back here... */
- bit = 0;
- /* We have a last byte that we have handled. */
- lastbyte = 1;
- }
- }
-
- /* Write the prepared buffer to disk. */
- tmp = (start_bit >> 3) - firstbyte;
- br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
- if (br != bufsize) {
- // FIXME: Eeek! We need rollback! (AIA)
- ntfs_log_trace("Failed to write buffer to bitmap. "
- "Leaving inconsistent metadata.\n");
- err = EIO;
- goto free_err_out;
- }
-
- /* Update counters. */
- tmp = (bufsize - firstbyte - lastbyte) << 3;
- if (firstbyte) {
- firstbyte = 0;
- /*
- * Re-set the partial first byte so a subsequent write
- * of the buffer does not have stale, incorrect bits.
- */
- *buf = value ? 0xff : 0;
- }
- start_bit += tmp;
- left -= tmp;
- if (bufsize > (tmp = (left + 7) >> 3))
- bufsize = tmp;
-
- if (lastbyte && left != 0) {
- // FIXME: Eeek! BUG!
- ntfs_log_trace("Last buffer but count is not zero (= "
- "%lli). Leaving inconsistent metadata."
- "\n", (long long)left);
- err = EIO;
- goto free_err_out;
- }
- } while (left > 0);
-
- /* Update free clusters and MFT records. */
- if (na == vol->mftbmp_na) {
- if (value)
- vol->nr_free_mft_records -= count;
- else
- vol->nr_free_mft_records += count;
- }
- if (na == vol->lcnbmp_na) {
- if (value)
- vol->nr_free_clusters -= count;
- else
- vol->nr_free_clusters += count;
- }
-
- /* Done! */
- free(buf);
- return 0;
-
-free_err_out:
- free(buf);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_bitmap_set_run - set a run of bits in a bitmap
- * @na: attribute containing the bitmap
- * @start_bit: first bit to set
- * @count: number of bits to set
- *
- * Set @count bits starting at bit @start_bit in the bitmap described by the
- * attribute @na.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
-{
- return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
-}
-
-/**
- * ntfs_bitmap_clear_run - clear a run of bits in a bitmap
- * @na: attribute containing the bitmap
- * @start_bit: first bit to clear
- * @count: number of bits to clear
- *
- * Clear @count bits starting at bit @start_bit in the bitmap described by the
- * attribute @na.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count)
-{
- ntfs_log_trace("Dealloc from bit 0x%llx, count 0x%llx.\n",
- (long long)start_bit, (long long)count);
-
- return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/bootsect.c b/usr/src/lib/libntfs/common/libntfs/bootsect.c
deleted file mode 100644
index 3c4e9ca9b2..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/bootsect.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/**
- * bootsect.c - Boot sector handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- * Copyright (c) 2005 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "bootsect.h"
-#include "debug.h"
-#include "logging.h"
-
-/**
- * ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
- * @b: buffer containing putative boot sector to analyze
- * @silent: if zero, output progress messages to stderr
- *
- * Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
- * must be at least 512 bytes in size.
- *
- * If @silent is zero, output progress messages to stderr. Otherwise, do not
- * output any messages (except when configured with --enable-debug in which
- * case warning/debug messages may be displayed).
- *
- * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
- */
-BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b,
- const BOOL silent __attribute__((unused)))
-{
- u32 i;
-
- ntfs_log_debug("\nBeginning bootsector check...\n");
-
- /*
- * Check that checksum == sum of u32 values from b to the checksum
- * field. If checksum is zero, no checking is done. We will work when
- * the checksum test fails, since some utilities update the boot sector
- * ignoring the checksum which leaves the checksum out-of-date. We
- * report a warning if this is the case.
- */
- if ((void*)b < (void*)&b->checksum && b->checksum) {
- u32 *u = (u32 *)b;
- u32 *bi = (u32 *)(&b->checksum);
-
- ntfs_log_debug("Calculating bootsector checksum... ");
- for (i = 0; u < bi; ++u)
- i += le32_to_cpup(u);
- if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i) {
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("The NTFS bootsector contains an "
- "incorrect checksum.");
- } else
- ntfs_log_debug("OK\n");
- }
-
- /* Check OEMidentifier is "NTFS " */
- ntfs_log_debug("Checking OEMid... ");
- if (b->oem_id != NTFS_SB_MAGIC) /* "NTFS " */
- goto not_ntfs;
- ntfs_log_debug("OK\n");
-
- /* Check bytes per sector value is between 256 and 4096. */
- ntfs_log_debug("Checking bytes per sector... ");
- if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 ||
- le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000)
- goto not_ntfs;
- ntfs_log_debug("OK\n");
-
- /* Check sectors per cluster value is valid. */
- ntfs_log_debug("Checking sectors per cluster... ");
- switch (b->bpb.sectors_per_cluster) {
- case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
- break;
- default:
- goto not_ntfs;
- }
- ntfs_log_debug("OK\n");
-
- /* Check the cluster size is not above 65536 bytes. */
- ntfs_log_debug("Checking cluster size... ");
- if ((u32)le16_to_cpu(b->bpb.bytes_per_sector) *
- b->bpb.sectors_per_cluster > 0x10000)
- goto not_ntfs;
- ntfs_log_debug("OK\n");
-
- /* Check reserved/unused fields are really zero. */
- ntfs_log_debug("Checking reserved fields are zero... ");
- if (le16_to_cpu(b->bpb.reserved_sectors) ||
- le16_to_cpu(b->bpb.root_entries) ||
- le16_to_cpu(b->bpb.sectors) ||
- le16_to_cpu(b->bpb.sectors_per_fat) ||
- le32_to_cpu(b->bpb.large_sectors) ||
- b->bpb.fats)
- goto not_ntfs;
- ntfs_log_debug("OK\n");
-
- /* Check clusters per file mft record value is valid. */
- ntfs_log_debug("Checking clusters per mft record... ");
- if ((u8)b->clusters_per_mft_record < 0xe1 ||
- (u8)b->clusters_per_mft_record > 0xf7) {
- switch (b->clusters_per_mft_record) {
- case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
- break;
- default:
- goto not_ntfs;
- }
- }
- ntfs_log_debug("OK\n");
-
- /* Check clusters per index block value is valid. */
- ntfs_log_debug("Checking clusters per index block... ");
- if ((u8)b->clusters_per_index_record < 0xe1 ||
- (u8)b->clusters_per_index_record > 0xf7) {
- switch (b->clusters_per_index_record) {
- case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
- break;
- default:
- goto not_ntfs;
- }
- }
- ntfs_log_debug("OK\n");
-
- if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
- ntfs_log_debug("Warning: Bootsector has invalid end of sector "
- "marker.\n");
-
- ntfs_log_debug("Bootsector check completed successfully.\n");
- return TRUE;
-not_ntfs:
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("Bootsector check failed. Aborting...\n");
- return FALSE;
-}
-
-/**
- * ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
- * @vol: ntfs_volume to setup
- * @bs: buffer containing ntfs boot sector to parse
- *
- * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
- * obtained values.
- *
- * Return 0 on success or -1 on error with errno set to the error code EINVAL.
- */
-int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
-{
- u8 sectors_per_cluster;
- s8 c;
-
- /* We return -1 with errno = EINVAL on error. */
- errno = EINVAL;
-
- vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
- vol->sector_size_bits = ffs(vol->sector_size) - 1;
- ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
- ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
- /*
- * The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
- * below or equal the number_of_clusters) really belong in the
- * ntfs_boot_sector_is_ntfs but in this way we can just do this once.
- */
- sectors_per_cluster = bs->bpb.sectors_per_cluster;
- ntfs_log_debug("NumberOfSectors = %lli\n",
- sle64_to_cpu(bs->number_of_sectors));
- ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
- if (sectors_per_cluster & (sectors_per_cluster - 1)) {
- ntfs_log_debug("Error: %s is not a valid NTFS partition! "
- "sectors_per_cluster is not a power of 2.\n",
- vol->u.dev->d_name);
- return -1;
- }
- vol->nr_clusters = sle64_to_cpu(bs->number_of_sectors) >>
- (ffs(sectors_per_cluster) - 1);
-
- vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
- vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
- ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn);
- ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn);
- if (vol->mft_lcn > vol->nr_clusters ||
- vol->mftmirr_lcn > vol->nr_clusters) {
- ntfs_log_debug("Error: %s is not a valid NTFS partition!\n",
- vol->u.dev->d_name);
- ntfs_log_debug("($Mft LCN or $MftMirr LCN is greater than the "
- "number of clusters!)\n");
- return -1;
- }
- vol->cluster_size = sectors_per_cluster * vol->sector_size;
- if (vol->cluster_size & (vol->cluster_size - 1)) {
- ntfs_log_debug("Error: %s is not a valid NTFS partition! "
- "cluster_size is not a power of 2.\n",
- vol->u.dev->d_name);
- return -1;
- }
- vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
- /*
- * Need to get the clusters per mft record and handle it if it is
- * negative. Then calculate the mft_record_size. A value of 0x80 is
- * illegal, thus signed char is actually ok!
- */
- c = bs->clusters_per_mft_record;
- ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
- ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
- ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
- /*
- * When clusters_per_mft_record is negative, it means that it is to
- * be taken to be the negative base 2 logarithm of the mft_record_size
- * min bytes. Then:
- * mft_record_size = 2^(-clusters_per_mft_record) bytes.
- */
- if (c < 0)
- vol->mft_record_size = 1 << -c;
- else
- vol->mft_record_size = c << vol->cluster_size_bits;
- if (vol->mft_record_size & (vol->mft_record_size - 1)) {
- ntfs_log_debug("Error: %s is not a valid NTFS partition! "
- "mft_record_size is not a power of 2.\n",
- vol->u.dev->d_name);
- return -1;
- }
- vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
- ntfs_log_debug("MftRecordSize = 0x%x\n",
- (unsigned)vol->mft_record_size);
- ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
- /* Same as above for INDX record. */
- c = bs->clusters_per_index_record;
- ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
- if (c < 0)
- vol->indx_record_size = 1 << -c;
- else
- vol->indx_record_size = c << vol->cluster_size_bits;
- vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
- ntfs_log_debug("INDXRecordSize = 0x%x\n",
- (unsigned)vol->indx_record_size);
- ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
- /*
- * Windows cares only about first 4 records in $MFTMirr and inores
- * everything beyend them.
- */
- vol->mftmirr_size = 4;
- return 0;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/collate.c b/usr/src/lib/libntfs/common/libntfs/collate.c
deleted file mode 100644
index 566ceef475..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/collate.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * collate.c - NTFS collation handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- * Copyright (c) 2005 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "compat.h"
-#include "collate.h"
-#include "debug.h"
-#include "unistr.h"
-#include "logging.h"
-
-/**
- * ntfs_collate_binary - Which of two binary objects should be listed first
- * @vol: unused
- * @data1:
- * @data1_len:
- * @data2:
- * @data2_len:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
- const void *data1, size_t data1_len,
- const void *data2, size_t data2_len)
-{
- int rc;
-
- ntfs_log_trace("Entering.\n");
- rc = memcmp(data1, data2, min(data1_len, data2_len));
- if (!rc && (data1_len != data2_len)) {
- if (data1_len < data2_len)
- rc = -1;
- else
- rc = 1;
- }
- ntfs_log_trace("Done, returning %i.\n", rc);
- return rc;
-}
-
-/**
- * ntfs_collate_ntofs_ulong - Which of two long ints should be listed first
- * @vol: unused
- * @data1:
- * @data1_len:
- * @data2:
- * @data2_len:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
- const void *data1, size_t data1_len,
- const void *data2, size_t data2_len)
-{
- int rc;
- u32 d1, d2;
-
- ntfs_log_trace("Entering.\n");
- if (data1_len != data2_len || data1_len != 4) {
- ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
- return NTFS_COLLATION_ERROR;
- }
- d1 = le32_to_cpup(data1);
- d2 = le32_to_cpup(data2);
- if (d1 < d2)
- rc = -1;
- else {
- if (d1 == d2)
- rc = 0;
- else
- rc = 1;
- }
- ntfs_log_trace("Done, returning %i.\n", rc);
- return rc;
-}
-
-/**
- * ntfs_collate_file_name - Which of two filenames should be listed first
- * @vol:
- * @data1:
- * @data1_len: unused
- * @data2:
- * @data2_len: unused
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_collate_file_name(ntfs_volume *vol,
- const void *data1, size_t data1_len __attribute__((unused)),
- const void *data2, size_t data2_len __attribute__((unused)))
-{
- int rc;
-
- ntfs_log_trace("Entering.\n");
- rc = ntfs_file_values_compare(data1, data2, NTFS_COLLATION_ERROR,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
- if (!rc)
- rc = ntfs_file_values_compare(data1, data2,
- NTFS_COLLATION_ERROR, CASE_SENSITIVE,
- vol->upcase, vol->upcase_len);
- ntfs_log_trace("Done, returning %i.\n", rc);
- return rc;
-}
-
-typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, size_t,
- const void *, size_t);
-
-static ntfs_collate_func_t ntfs_do_collate0x0[3] = {
- ntfs_collate_binary,
- ntfs_collate_file_name,
- NULL/*ntfs_collate_unicode_string*/,
-};
-
-static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
- ntfs_collate_ntofs_ulong,
- NULL/*ntfs_collate_ntofs_sid*/,
- NULL/*ntfs_collate_ntofs_security_hash*/,
- NULL/*ntfs_collate_ntofs_ulongs*/,
-};
-
-/**
- * ntfs_is_collation_rule_supported - Check if a collation rule is implemented.
- * @cr: The to-be-checked collation rule
- *
- * Use this function to know if @cr is supported by libntfs.
- *
- * 7 collation rules are known to be supported by NTFS as defined
- * in layout.h. However, libntfs only support 3 of them ATM.
- *
- * Return TRUE if @cr is supported. FALSE otherwise.
- */
-BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr)
-{
- return (cr == COLLATION_BINARY || cr == COLLATION_NTOFS_ULONG ||
- cr == COLLATION_FILE_NAME);
- /*
- * FIXME: At the moment we only support COLLATION_BINARY,
- * COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME.
- * The correct future implementation of this function should be:
- *
- * u32 i = le32_to_cpu(cr);
- * return ((i <= 0x02) || ((i >= 0x10) && (i <= 0x13)));
- */
-}
-
-/**
- * ntfs_collate - collate two data items using a specified collation rule
- * @vol: ntfs volume to which the data items belong
- * @cr: collation rule to use when comparing the items
- * @data1: first data item to collate
- * @data1_len: length in bytes of @data1
- * @data2: second data item to collate
- * @data2_len: length in bytes of @data2
- *
- * Collate the two data items @data1 and @data2 using the collation rule @cr
- * and return -1, 0, or 1 if @data1 is found, respectively, to collate before,
- * to match, or to collate after @data2.
- *
- * For speed we use the collation rule @cr as an index into two tables of
- * function pointers to call the appropriate collation function.
- *
- * Return NTFS_COLLATION_ERROR if error occurred.
- */
-int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
- const void *data1, size_t data1_len,
- const void *data2, size_t data2_len)
-{
- u32 i;
-
- ntfs_log_trace("Entering.\n");
- if (!vol || !data1 || !data2) {
- ntfs_log_error("Invalid arguments passed.\n");
- return NTFS_COLLATION_ERROR;
- }
-
- if (!ntfs_is_collation_rule_supported(cr))
- goto err;
- i = le32_to_cpu(cr);
- if (i <= 0x02)
- return ntfs_do_collate0x0[i](vol, data1, data1_len,
- data2, data2_len);
- if (i < 0x10)
- goto err;
- i -= 0x10;
- if (i <= 3)
- return ntfs_do_collate0x1[i](vol, data1, data1_len,
- data2, data2_len);
-err:
- ntfs_log_debug("Unknown collation rule.\n");
- return NTFS_COLLATION_ERROR;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/compat.c b/usr/src/lib/libntfs/common/libntfs/compat.c
deleted file mode 100644
index acdf4db7ce..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/compat.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * compat.c - Tweaks for Windows compatibility
- *
- * Copyright (c) 2002 Richard Russon
- * Copyright (c) 2002-2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef WINDOWS
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "compat.h"
-
-/* TODO: Add check for FFS in the configure script... (AIA) */
-
-#ifndef HAVE_FFS
-/**
- * ffs - Find the first set bit in an int
- * @x:
- *
- * Description...
- *
- * Returns:
- */
-int ffs(int x)
-{
- int r = 1;
-
- if (!x)
- return 0;
- if (!(x & 0xffff)) {
- x >>= 16;
- r += 16;
- }
- if (!(x & 0xff)) {
- x >>= 8;
- r += 8;
- }
- if (!(x & 0xf)) {
- x >>= 4;
- r += 4;
- }
- if (!(x & 3)) {
- x >>= 2;
- r += 2;
- }
- if (!(x & 1)) {
- x >>= 1;
- r += 1;
- }
- return r;
-}
-#endif /* HAVE_FFS */
-
-#endif /* WINDOWS */
-
diff --git a/usr/src/lib/libntfs/common/libntfs/compress.c b/usr/src/lib/libntfs/common/libntfs/compress.c
deleted file mode 100644
index def04e46eb..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/compress.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/**
- * compress.c - Compressed attribute handling code. Part of the Linux-NTFS
- * project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- * Copyright (c) 2005 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "debug.h"
-#include "volume.h"
-#include "types.h"
-#include "layout.h"
-#include "runlist.h"
-#include "compress.h"
-#include "logging.h"
-
-/**
- * enum ntfs_compression_constants - constants used in the compression code
- */
-typedef enum {
- /* Token types and access mask. */
- NTFS_SYMBOL_TOKEN = 0,
- NTFS_PHRASE_TOKEN = 1,
- NTFS_TOKEN_MASK = 1,
-
- /* Compression sub-block constants. */
- NTFS_SB_SIZE_MASK = 0x0fff,
- NTFS_SB_SIZE = 0x1000,
- NTFS_SB_IS_COMPRESSED = 0x8000,
-} ntfs_compression_constants;
-
-/**
- * ntfs_decompress - decompress a compression block into an array of pages
- * @dest: buffer to which to write the decompressed data
- * @dest_size: size of buffer @dest in bytes
- * @cb_start: compression block to decompress
- * @cb_size: size of compression block @cb_start in bytes
- *
- * This decompresses the compression block @cb_start into the destination
- * buffer @dest.
- *
- * @cb_start is a pointer to the compression block which needs decompressing
- * and @cb_size is the size of @cb_start in bytes (8-64kiB).
- *
- * Return 0 if success or -EOVERFLOW on error in the compressed stream.
- */
-static int ntfs_decompress(u8 *dest, const u32 dest_size,
- u8 *const cb_start, const u32 cb_size)
-{
- /*
- * Pointers into the compressed data, i.e. the compression block (cb),
- * and the therein contained sub-blocks (sb).
- */
- u8 *cb_end = cb_start + cb_size; /* End of cb. */
- u8 *cb = cb_start; /* Current position in cb. */
- u8 *cb_sb_start = cb; /* Beginning of the current sb in the cb. */
- u8 *cb_sb_end; /* End of current sb / beginning of next sb. */
- /* Variables for uncompressed data / destination. */
- u8 *dest_end = dest + dest_size; /* End of dest buffer. */
- u8 *dest_sb_start; /* Start of current sub-block in dest. */
- u8 *dest_sb_end; /* End of current sb in dest. */
- /* Variables for tag and token parsing. */
- u8 tag; /* Current tag. */
- int token; /* Loop counter for the eight tokens in tag. */
-
- ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size);
-do_next_sb:
- ntfs_log_debug("Beginning sub-block at offset = 0x%x in the cb.\n",
- cb - cb_start);
- /*
- * Have we reached the end of the compression block or the end of the
- * decompressed data? The latter can happen for example if the current
- * position in the compression block is one byte before its end so the
- * first two checks do not detect it.
- */
- if (cb == cb_end || !le16_to_cpup((u16*)cb) || dest == dest_end) {
- ntfs_log_debug("Completed. Returning success (0).\n");
- return 0;
- }
- /* Setup offset for the current sub-block destination. */
- dest_sb_start = dest;
- dest_sb_end = dest + NTFS_SB_SIZE;
- /* Check that we are still within allowed boundaries. */
- if (dest_sb_end > dest_end)
- goto return_overflow;
- /* Does the minimum size of a compressed sb overflow valid range? */
- if (cb + 6 > cb_end)
- goto return_overflow;
- /* Setup the current sub-block source pointers and validate range. */
- cb_sb_start = cb;
- cb_sb_end = cb_sb_start + (le16_to_cpup((u16*)cb) & NTFS_SB_SIZE_MASK)
- + 3;
- if (cb_sb_end > cb_end)
- goto return_overflow;
- /* Now, we are ready to process the current sub-block (sb). */
- if (!(le16_to_cpup((u16*)cb) & NTFS_SB_IS_COMPRESSED)) {
- ntfs_log_debug("Found uncompressed sub-block.\n");
- /* This sb is not compressed, just copy it into destination. */
- /* Advance source position to first data byte. */
- cb += 2;
- /* An uncompressed sb must be full size. */
- if (cb_sb_end - cb != NTFS_SB_SIZE)
- goto return_overflow;
- /* Copy the block and advance the source position. */
- memcpy(dest, cb, NTFS_SB_SIZE);
- cb += NTFS_SB_SIZE;
- /* Advance destination position to next sub-block. */
- dest += NTFS_SB_SIZE;
- goto do_next_sb;
- }
- ntfs_log_debug("Found compressed sub-block.\n");
- /* This sb is compressed, decompress it into destination. */
- /* Forward to the first tag in the sub-block. */
- cb += 2;
-do_next_tag:
- if (cb == cb_sb_end) {
- /* Check if the decompressed sub-block was not full-length. */
- if (dest < dest_sb_end) {
- int nr_bytes = dest_sb_end - dest;
-
- ntfs_log_debug("Filling incomplete sub-block with zeroes.\n");
- /* Zero remainder and update destination position. */
- memset(dest, 0, nr_bytes);
- dest += nr_bytes;
- }
- /* We have finished the current sub-block. */
- goto do_next_sb;
- }
- /* Check we are still in range. */
- if (cb > cb_sb_end || dest > dest_sb_end)
- goto return_overflow;
- /* Get the next tag and advance to first token. */
- tag = *cb++;
- /* Parse the eight tokens described by the tag. */
- for (token = 0; token < 8; token++, tag >>= 1) {
- u16 lg, pt, length, max_non_overlap;
- register u16 i;
- u8 *dest_back_addr;
-
- /* Check if we are done / still in range. */
- if (cb >= cb_sb_end || dest > dest_sb_end)
- break;
- /* Determine token type and parse appropriately.*/
- if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) {
- /*
- * We have a symbol token, copy the symbol across, and
- * advance the source and destination positions.
- */
- *dest++ = *cb++;
- /* Continue with the next token. */
- continue;
- }
- /*
- * We have a phrase token. Make sure it is not the first tag in
- * the sb as this is illegal and would confuse the code below.
- */
- if (dest == dest_sb_start)
- goto return_overflow;
- /*
- * Determine the number of bytes to go back (p) and the number
- * of bytes to copy (l). We use an optimized algorithm in which
- * we first calculate log2(current destination position in sb),
- * which allows determination of l and p in O(1) rather than
- * O(n). We just need an arch-optimized log2() function now.
- */
- lg = 0;
- for (i = dest - dest_sb_start - 1; i >= 0x10; i >>= 1)
- lg++;
- /* Get the phrase token into i. */
- pt = le16_to_cpup((u16*)cb);
- /*
- * Calculate starting position of the byte sequence in
- * the destination using the fact that p = (pt >> (12 - lg)) + 1
- * and make sure we don't go too far back.
- */
- dest_back_addr = dest - (pt >> (12 - lg)) - 1;
- if (dest_back_addr < dest_sb_start)
- goto return_overflow;
- /* Now calculate the length of the byte sequence. */
- length = (pt & (0xfff >> lg)) + 3;
- /* Verify destination is in range. */
- if (dest + length > dest_sb_end)
- goto return_overflow;
- /* The number of non-overlapping bytes. */
- max_non_overlap = dest - dest_back_addr;
- if (length <= max_non_overlap) {
- /* The byte sequence doesn't overlap, just copy it. */
- memcpy(dest, dest_back_addr, length);
- /* Advance destination pointer. */
- dest += length;
- } else {
- /*
- * The byte sequence does overlap, copy non-overlapping
- * part and then do a slow byte by byte copy for the
- * overlapping part. Also, advance the destination
- * pointer.
- */
- memcpy(dest, dest_back_addr, max_non_overlap);
- dest += max_non_overlap;
- dest_back_addr += max_non_overlap;
- length -= max_non_overlap;
- while (length--)
- *dest++ = *dest_back_addr++;
- }
- /* Advance source position and continue with the next token. */
- cb += 2;
- }
- /* No tokens left in the current tag. Continue with the next tag. */
- goto do_next_tag;
-return_overflow:
- ntfs_log_debug("Failed. Returning -EOVERFLOW.\n");
- errno = EOVERFLOW;
- return -1;
-}
-
-/**
- * ntfs_is_cb_compressed - internal function, do not use
- *
- * This is a very specialised function determining if a cb is compressed or
- * uncompressed. It is assumed that checking for a sparse cb has already been
- * performed and that the cb is not sparse. It makes all sorts of other
- * assumptions as well and hence it is not useful anywhere other than where it
- * is used at the moment. Please, do not make this function available for use
- * outside of compress.c as it is bound to confuse people and not do what they
- * want.
- *
- * Return TRUE on errors so that the error will be detected later on in the
- * code. Might be a bit confusing to debug but there really should never be
- * errors coming from here.
- */
-static BOOL ntfs_is_cb_compressed(ntfs_attr *na,
- runlist_element *rl, VCN cb_start_vcn, int cb_clusters)
-{
- /*
- * The simplest case: the run starting at @cb_start_vcn contains
- * @cb_clusters clusters which are all not sparse, thus the cb is not
- * compressed.
- */
-restart:
- cb_clusters -= rl->length - (cb_start_vcn - rl->vcn);
- while (cb_clusters > 0) {
- /* Go to the next run. */
- rl++;
- /* Map the next runlist fragment if it is not mapped. */
- if (rl->lcn < LCN_HOLE || !rl->length) {
- cb_start_vcn = rl->vcn;
- rl = ntfs_attr_find_vcn(na, rl->vcn);
- if (!rl || rl->lcn < LCN_HOLE || !rl->length)
- return TRUE;
- /*
- * If the runs were merged need to deal with the
- * resulting partial run so simply restart.
- */
- if (rl->vcn < cb_start_vcn)
- goto restart;
- }
- /* If the current run is sparse, the cb is compressed. */
- if (rl->lcn == LCN_HOLE)
- return TRUE;
- /* If the whole cb is not sparse, it is not compressed. */
- if (rl->length >= cb_clusters)
- return FALSE;
- cb_clusters -= rl->length;
- };
- /* All cb_clusters were not sparse thus the cb is not compressed. */
- return FALSE;
-}
-
-/**
- * ntfs_compressed_attr_pread - read from a compressed attribute
- * @na: ntfs attribute to read from
- * @pos: byte position in the attribute to begin reading from
- * @count: number of bytes to read
- * @b: output data buffer
- *
- * NOTE: You probably want to be using attrib.c::ntfs_attr_pread() instead.
- *
- * This function will read @count bytes starting at offset @pos from the
- * compressed ntfs attribute @na into the data buffer @b.
- *
- * On success, return the number of successfully read bytes. If this number
- * is lower than @count this means that the read reached end of file or that
- * an error was encountered during the read so that the read is partial.
- * 0 means end of file or nothing was read (also return 0 when @count is 0).
- *
- * On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of ntfs_pread(), or to EINVAL in case of invalid
- * arguments.
- */
-s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b)
-{
- s64 br, to_read, ofs, total, total2;
- u64 cb_size_mask;
- VCN start_vcn, vcn, end_vcn;
- ntfs_volume *vol;
- runlist_element *rl;
- u8 *dest, *cb, *cb_pos, *cb_end;
- u32 cb_size;
- int err;
- unsigned int nr_cbs, cb_clusters;
-
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count 0x%llx.\n",
- (unsigned long long)na->ni->mft_no, na->type,
- (long long)pos, (long long)count);
- if (!na || !NAttrCompressed(na) || !na->ni || !na->ni->vol || !b ||
- pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- /*
- * Encrypted attributes are not supported. We return access denied,
- * which is what Windows NT4 does, too.
- */
- if (NAttrEncrypted(na)) {
- errno = EACCES;
- return -1;
- }
- if (!count)
- return 0;
- /* Truncate reads beyond end of attribute. */
- if (pos + count > na->data_size) {
- if (pos >= na->data_size) {
- return 0;
- }
- count = na->data_size - pos;
- }
- /* If it is a resident attribute, simply use ntfs_attr_pread(). */
- if (!NAttrNonResident(na))
- return ntfs_attr_pread(na, pos, count, b);
- total = total2 = 0;
- /* Zero out reads beyond initialized size. */
- if (pos + count > na->initialized_size) {
- if (pos >= na->initialized_size) {
- memset(b, 0, count);
- return count;
- }
- total2 = pos + count - na->initialized_size;
- count -= total2;
- memset((u8*)b + count, 0, total2);
- }
- vol = na->ni->vol;
- cb_size = na->compression_block_size;
- cb_size_mask = cb_size - 1UL;
- cb_clusters = na->compression_block_clusters;
-
- /* Need a temporary buffer for each loaded compression block. */
- cb = ntfs_malloc(cb_size);
- if (!cb)
- return -1;
-
- /* Need a temporary buffer for each uncompressed block. */
- dest = ntfs_malloc(cb_size);
- if (!dest) {
- err = errno;
- free(cb);
- errno = err;
- return -1;
- }
- /*
- * The first vcn in the first compression block (cb) which we need to
- * decompress.
- */
- start_vcn = (pos & ~cb_size_mask) >> vol->cluster_size_bits;
- /* Offset in the uncompressed cb at which to start reading data. */
- ofs = pos & cb_size_mask;
- /*
- * The first vcn in the cb after the last cb which we need to
- * decompress.
- */
- end_vcn = ((pos + count + cb_size - 1) & ~cb_size_mask) >>
- vol->cluster_size_bits;
- /* Number of compression blocks (cbs) in the wanted vcn range. */
- nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits >>
- na->compression_block_size_bits;
- cb_end = cb + cb_size;
-do_next_cb:
- nr_cbs--;
- cb_pos = cb;
- vcn = start_vcn;
- start_vcn += cb_clusters;
-
- /* Check whether the compression block is sparse. */
- rl = ntfs_attr_find_vcn(na, vcn);
- if (!rl || rl->lcn < LCN_HOLE) {
- free(cb);
- free(dest);
- if (total)
- return total;
- /* FIXME: Do we want EIO or the error code? (AIA) */
- errno = EIO;
- return -1;
- }
- if (rl->lcn == LCN_HOLE) {
- /* Sparse cb, zero out destination range overlapping the cb. */
- ntfs_log_debug("Found sparse compression block.\n");
- to_read = min(count, cb_size - ofs);
- memset(b, 0, to_read);
- ofs = 0;
- total += to_read;
- count -= to_read;
- b = (u8*)b + to_read;
- } else if (!ntfs_is_cb_compressed(na, rl, vcn, cb_clusters)) {
- s64 tdata_size, tinitialized_size;
- /*
- * Uncompressed cb, read it straight into the destination range
- * overlapping the cb.
- */
- ntfs_log_debug("Found uncompressed compression block.\n");
- /*
- * Read the uncompressed data into the destination buffer.
- * NOTE: We cheat a little bit here by marking the attribute as
- * not compressed in the ntfs_attr structure so that we can
- * read the data by simply using ntfs_attr_pread(). (-8
- * NOTE: we have to modify data_size and initialized_size
- * temporarily as well...
- */
- to_read = min(count, cb_size - ofs);
- ofs += vcn << vol->cluster_size_bits;
- NAttrClearCompressed(na);
- tdata_size = na->data_size;
- tinitialized_size = na->initialized_size;
- na->data_size = na->initialized_size = na->allocated_size;
- do {
- br = ntfs_attr_pread(na, ofs, to_read, b);
- if (br < 0) {
- err = errno;
- na->data_size = tdata_size;
- na->initialized_size = tinitialized_size;
- NAttrSetCompressed(na);
- free(cb);
- free(dest);
- if (total)
- return total;
- errno = err;
- return br;
- }
- total += br;
- count -= br;
- b = (u8*)b + br;
- to_read -= br;
- ofs += br;
- } while (to_read > 0);
- na->data_size = tdata_size;
- na->initialized_size = tinitialized_size;
- NAttrSetCompressed(na);
- ofs = 0;
- } else {
- s64 tdata_size, tinitialized_size;
-
- /*
- * Compressed cb, decompress it into the temporary buffer, then
- * copy the data to the destination range overlapping the cb.
- */
- ntfs_log_debug("Found compressed compression block.\n");
- /*
- * Read the compressed data into the temporary buffer.
- * NOTE: We cheat a little bit here by marking the attribute as
- * not compressed in the ntfs_attr structure so that we can
- * read the raw, compressed data by simply using
- * ntfs_attr_pread(). (-8
- * NOTE: We have to modify data_size and initialized_size
- * temporarily as well...
- */
- to_read = cb_size;
- NAttrClearCompressed(na);
- tdata_size = na->data_size;
- tinitialized_size = na->initialized_size;
- na->data_size = na->initialized_size = na->allocated_size;
- do {
- br = ntfs_attr_pread(na,
- (vcn << vol->cluster_size_bits) +
- (cb_pos - cb), to_read, cb_pos);
- if (br < 0) {
- err = errno;
- na->data_size = tdata_size;
- na->initialized_size = tinitialized_size;
- NAttrSetCompressed(na);
- free(cb);
- free(dest);
- if (total)
- return total;
- errno = err;
- return br;
- }
- cb_pos += br;
- to_read -= br;
- } while (to_read > 0);
- na->data_size = tdata_size;
- na->initialized_size = tinitialized_size;
- NAttrSetCompressed(na);
- /* Just a precaution. */
- if (cb_pos + 2 <= cb_end)
- *(u16*)cb_pos = 0;
- ntfs_log_debug("Successfully read the compression block.\n");
- if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) {
- err = errno;
- free(cb);
- free(dest);
- if (total)
- return total;
- errno = err;
- return -1;
- }
- to_read = min(count, cb_size - ofs);
- memcpy(b, dest + ofs, to_read);
- total += to_read;
- count -= to_read;
- b = (u8*)b + to_read;
- ofs = 0;
- }
- /* Do we have more work to do? */
- if (nr_cbs)
- goto do_next_cb;
- /* We no longer need the buffers. */
- free(cb);
- free(dest);
- /* Return number of bytes read. */
- return total + total2;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/crypto.c b/usr/src/lib/libntfs/common/libntfs/crypto.c
deleted file mode 100644
index 850e0705c6..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/crypto.c
+++ /dev/null
@@ -1,1519 +0,0 @@
-/**
- * crypto.c - Routines for dealing with encrypted files. Part of the
- * Linux-NTFS project.
- *
- * Copyright (c) 2005 Yuval Fledel
- * Copyright (c) 2005-2007 Anton Altaparmakov
- * Copyright (c) 2007 Yura Pakhuchiy
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * TODO: Cleanup this file. Write nice descriptions for non-exported functions
- * and maybe clean up namespace (not necessary for all functions to belong to
- * ntfs_crypto, we can have ntfs_fek, ntfs_rsa, etc.., but there should be
- * maximum 2-3 namespaces, not every function begins with it own namespace
- * like now).
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "types.h"
-#include "volume.h"
-#include "debug.h"
-#include "dir.h"
-#include "layout.h"
-#include "crypto.h"
-
-#ifdef ENABLE_CRYPTO
-
-#include <gcrypt.h>
-#include <gnutls/pkcs12.h>
-#include <gnutls/x509.h>
-
-#include <libconfig.h>
-
-#define NTFS_CONFIG_PATH_SYSTEM "/etc/libntfs/config"
-#define NTFS_CONFIG_PATH_USER ".libntfs/config"
-
-#define NTFS_SHA1_THUMBPRINT_SIZE 0x14
-
-#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3)
-
-#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4"
-#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1"
-
-#define NTFS_EFS_SECTOR_SIZE 512
-
-typedef enum {
- DF_TYPE_UNKNOWN,
- DF_TYPE_DDF,
- DF_TYPE_DRF,
-} NTFS_DF_TYPES;
-
-/**
- * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit)
- *
- * To choose which one is used in Windows, create or set the REG_DWORD registry
- * key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\
- * AlgorithmID to the value of your chosen crypto algorithm, e.g. to use DesX,
- * set AlgorithmID to 0x6604.
- *
- * Note that the Windows versions I have tried so far (all are high crypto
- * enabled) ignore the AlgorithmID value if it is not one of CALG_3DES,
- * CALG_DESX, or CALG_AES_256, i.e. you cannot select CALG_DES at all using
- * this registry key. It would be interesting to check out encryption on one
- * of the "crippled" crypto Windows versions...
- */
-typedef enum {
- CALG_DES = const_cpu_to_le32(0x6601),
- /* If not one of the below three, fall back to standard Des. */
- CALG_3DES = const_cpu_to_le32(0x6603),
- CALG_DESX = const_cpu_to_le32(0x6604),
- CALG_AES_256 = const_cpu_to_le32(0x6610),
-} NTFS_CRYPTO_ALGORITHMS;
-
-/**
- * struct ntfs_fek - Decrypted, in-memory file encryption key.
- */
-struct _ntfs_fek {
- gcry_cipher_hd_t gcry_cipher_hd;
- le32 alg_id;
- u8 *key_data;
- gcry_cipher_hd_t *des_gcry_cipher_hd_ptr;
-};
-
-typedef struct _ntfs_fek ntfs_fek;
-
-struct _ntfs_crypto_attr {
- ntfs_fek *fek;
-};
-
-typedef struct {
- u64 in_whitening, out_whitening;
- gcry_cipher_hd_t gcry_cipher_hd;
-} ntfs_desx_ctx;
-
-ntfschar NTFS_EFS[5] = {
- const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'),
- const_cpu_to_le16('S'), const_cpu_to_le16(0)
-};
-
-typedef struct {
- gcry_sexp_t key;
- NTFS_DF_TYPES df_type;
- char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE];
-} ntfs_rsa_private_key_t;
-
-/*
- * Yes, global variables sucks, but we need to keep whether we performed
- * gcrypt/gnutls global initialization and keep user's RSA keys.
- */
-typedef struct {
- int initialized;
- int desx_alg_id;
- gcry_module_t desx_module;
- ntfs_rsa_private_key_t **rsa_key;
- int nr_rsa_keys;
-} ntfs_crypto_ctx_t;
-
-static ntfs_crypto_ctx_t ntfs_crypto_ctx = {
- .desx_alg_id = -1,
- .desx_module = NULL,
-};
-
-/**
- * ntfs_pkcs12_load_pfxfile
- */
-static int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx,
- unsigned *pfx_size)
-{
- int f, to_read, total, attempts, br;
- struct stat key_stat;
-
- if (!keyfile || !pfx || !pfx_size) {
- ntfs_log_error("You have to specify the key file, a pointer "
- "to hold the key file contents, and a pointer "
- "to hold the size of the key file contents.\n");
- return -1;
- }
- f = open(keyfile, O_RDONLY);
- if (f == -1) {
- ntfs_log_perror("Failed to open key file");
- return -1;
- }
- if (fstat(f, &key_stat) == -1) {
- ntfs_log_perror("Failed to stat key file");
- goto file_out;
- }
- if (!S_ISREG(key_stat.st_mode)) {
- ntfs_log_error("Key file is not a regular file, cannot read "
- "it.\n");
- goto file_out;
- }
- if (!key_stat.st_size) {
- ntfs_log_error("Key file has zero size.\n");
- goto file_out;
- }
- *pfx = malloc(key_stat.st_size + 1);
- if (!*pfx) {
- ntfs_log_perror("Failed to allocate buffer for key file "
- "contents");
- goto file_out;
- }
- to_read = key_stat.st_size;
- total = attempts = 0;
- do {
- br = read(f, *pfx + total, to_read);
- if (br == -1) {
- ntfs_log_perror("Failed to read from key file");
- goto free_out;
- }
- if (!br)
- attempts++;
- to_read -= br;
- total += br;
- } while (to_read > 0 && attempts < 3);
- close(f);
- /* Make sure it is zero terminated. */
- (*pfx)[key_stat.st_size] = 0;
- *pfx_size = key_stat.st_size;
- return 0;
-free_out:
- free(*pfx);
-file_out:
- close(f);
- return -1;
-}
-
-/**
- * ntfs_rsa_private_key_import_from_gnutls
- */
-static gcry_sexp_t ntfs_rsa_private_key_import_from_gnutls(
- gnutls_x509_privkey_t priv_key)
-{
- int i, j;
- size_t tmp_size;
- gnutls_datum_t rd[6];
- gcry_mpi_t rm[6];
- gcry_sexp_t rsa_key;
-
- /* Extract the RSA parameters from the GNU TLS private key. */
- if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1],
- &rd[2], &rd[3], &rd[4], &rd[5])) {
- ntfs_log_error("Failed to export rsa parameters. (Is the "
- "key an RSA private key?)\n");
- return NULL;
- }
- /* Convert each RSA parameter to MPI format. */
- for (i = 0; i < 6; i++) {
- if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data,
- rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to convert RSA parameter %i "
- "to mpi format (size %d)\n", i,
- rd[i].size);
- rsa_key = NULL;
- break;
- }
- }
- /* Release the no longer needed datum values. */
- for (j = 0; j < 6; j++) {
- if (rd[j].data && rd[j].size)
- gnutls_free(rd[j].data);
- }
- /*
- * Build the gcrypt private key, note libgcrypt uses p and q inversed
- * to what gnutls uses.
- */
- if (i == 6 && gcry_sexp_build(&rsa_key, NULL,
- "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
- rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) !=
- GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to build RSA private key s-exp.\n");
- rsa_key = NULL;
- }
- /* Release the no longer needed MPI values. */
- for (j = 0; j < i; j++)
- gcry_mpi_release(rm[j]);
- return rsa_key;
-}
-
-/**
- * ntfs_rsa_private_key_release
- */
-static void ntfs_rsa_private_key_release(ntfs_rsa_private_key_t *rsa_key)
-{
- if (rsa_key) {
- if (rsa_key->key)
- gcry_sexp_release(rsa_key->key);
- free(rsa_key);
- }
-}
-
-/**
- * ntfs_pkcs12_extract_rsa_key
- */
-static ntfs_rsa_private_key_t *ntfs_pkcs12_extract_rsa_key(u8 *pfx,
- int pfx_size, const char *password)
-{
- int err, bag_index, flags;
- gnutls_datum_t dpfx, dkey;
- gnutls_pkcs12_t pkcs12 = NULL;
- gnutls_pkcs12_bag_t bag = NULL;
- gnutls_x509_privkey_t pkey = NULL;
- gnutls_x509_crt_t crt = NULL;
- ntfs_rsa_private_key_t *rsa_key = NULL;
- char purpose_oid[100];
- size_t purpose_oid_size = sizeof(purpose_oid);
- size_t tp_size;
- BOOL have_thumbprint = FALSE;
-
- rsa_key = malloc(sizeof(ntfs_rsa_private_key_t));
- if (!rsa_key) {
- ntfs_log_perror("%s", "ntfs_pkcs12_extract_rsa_key");
- return NULL;
- }
- rsa_key->df_type = DF_TYPE_UNKNOWN;
- rsa_key->key = NULL;
- tp_size = sizeof(rsa_key->thumbprint);
- /* Create a pkcs12 structure. */
- err = gnutls_pkcs12_init(&pkcs12);
- if (err) {
- ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- /* Convert the PFX file (DER format) to native pkcs12 format. */
- dpfx.data = pfx;
- dpfx.size = pfx_size;
- err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0);
- if (err) {
- ntfs_log_error("Failed to convert the PFX file from DER to "
- "native PKCS#12 format: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- /*
- * Verify that the password is correct and that the key file has not
- * been tampered with. Note if the password has zero length and the
- * verification fails, retry with password set to NULL. This is needed
- * to get password less .pfx files generated with Windows XP SP1 (and
- * probably earlier versions of Windows) to work.
- */
-retry_verify:
- err = gnutls_pkcs12_verify_mac(pkcs12, password);
- if (err) {
- if (err == GNUTLS_E_MAC_VERIFY_FAILED &&
- password && !strlen(password)) {
- password = NULL;
- goto retry_verify;
- }
- ntfs_log_error("You are probably misspelled password to PFX "
- "file.\n");
- goto err;
- }
- for (bag_index = 0; ; bag_index++) {
- err = gnutls_pkcs12_bag_init(&bag);
- if (err) {
- ntfs_log_error("Failed to initialize PKCS#12 Bag "
- "structure: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag);
- if (err) {
- if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
- err = 0;
- break;
- }
- ntfs_log_error("Failed to obtain Bag from PKCS#12 "
- "structure: %s\n",
- gnutls_strerror(err));
- goto err;
- }
-check_again:
- err = gnutls_pkcs12_bag_get_count(bag);
- if (err < 0) {
- ntfs_log_error("Failed to obtain Bag count: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- err = gnutls_pkcs12_bag_get_type(bag, 0);
- if (err < 0) {
- ntfs_log_error("Failed to determine Bag type: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- flags = 0;
- switch (err) {
- case GNUTLS_BAG_PKCS8_KEY:
- flags = GNUTLS_PKCS_PLAIN;
- case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
- err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
- if (err < 0) {
- ntfs_log_error("Failed to obtain Bag data: "
- "%s\n", gnutls_strerror(err));
- goto err;
- }
- err = gnutls_x509_privkey_init(&pkey);
- if (err) {
- ntfs_log_error("Failed to initialized "
- "private key structure: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- /* Decrypt the private key into GNU TLS format. */
- err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey,
- GNUTLS_X509_FMT_DER, password, flags);
- if (err) {
- ntfs_log_error("Failed to convert private "
- "key from DER to GNU TLS "
- "format: %s\n",
- gnutls_strerror(err));
- goto err;
- }
-#if 0
- /*
- * Export the key again, but unencrypted, and output it
- * to stderr. Note the output has an RSA header so to
- * compare to openssl pkcs12 -nodes -in myfile.pfx
- * output need to ignore the part of the key between
- * the first "MII..." up to the second "MII...". The
- * actual RSA private key begins at the second "MII..."
- * and in my testing at least was identical to openssl
- * output and was also identical both on big and little
- * endian so gnutls should be endianness safe.
- */
- char *buf = malloc(8192);
- size_t bufsize = 8192;
- err = gnutls_x509_privkey_export_pkcs8(pkey,
- GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf,
- &bufsize);
- if (err) {
- ntfs_log_error("eek1\n");
- exit(1);
- }
- ntfs_log_error("%s\n", buf);
- free(buf);
-#endif
- /* Convert the private key to our internal format. */
- rsa_key->key =
- ntfs_rsa_private_key_import_from_gnutls(pkey);
- if (!rsa_key->key)
- goto err;
- break;
- case GNUTLS_BAG_ENCRYPTED:
- err = gnutls_pkcs12_bag_decrypt(bag, password);
- if (err) {
- ntfs_log_error("Failed to decrypt Bag: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- goto check_again;
- case GNUTLS_BAG_CERTIFICATE:
- err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
- if (err < 0) {
- ntfs_log_error("Failed to obtain Bag data: "
- "%s\n", gnutls_strerror(err));
- goto err;
- }
- err = gnutls_x509_crt_init(&crt);
- if (err) {
- ntfs_log_error("Failed to initialize "
- "certificate structure: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- err = gnutls_x509_crt_import(crt, &dkey,
- GNUTLS_X509_FMT_DER);
- if (err) {
- ntfs_log_error("Failed to convert certificate "
- "from DER to GNU TLS format: "
- "%s\n", gnutls_strerror(err));
- goto err;
- }
- err = gnutls_x509_crt_get_key_purpose_oid(crt, 0,
- purpose_oid, &purpose_oid_size, NULL);
- if (err) {
- ntfs_log_error("Failed to get key purpose "
- "OID: %s\n",
- gnutls_strerror(err));
- goto err;
- }
- purpose_oid[purpose_oid_size - 1] = 0;
- if (!strcmp(purpose_oid,
- NTFS_EFS_CERT_PURPOSE_OID_DRF))
- rsa_key->df_type = DF_TYPE_DRF;
- else if (!strcmp(purpose_oid,
- NTFS_EFS_CERT_PURPOSE_OID_DDF))
- rsa_key->df_type = DF_TYPE_DDF;
- else {
- ntfs_log_error("Certificate has unknown "
- "purpose OID %s.\n",
- purpose_oid);
- err = EINVAL;
- goto err;
- }
- /* Return the thumbprint to the caller. */
- err = gnutls_x509_crt_get_fingerprint(crt,
- GNUTLS_DIG_SHA1, rsa_key->thumbprint,
- &tp_size);
- if (err) {
- ntfs_log_error("Failed to get thumbprint: "
- "%s\n", gnutls_strerror(err));
- goto err;
- }
- if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) {
- ntfs_log_error("Invalid thumbprint size %zd. "
- "Should be %d.\n", tp_size,
- sizeof(rsa_key->thumbprint));
- err = EINVAL;
- goto err;
- }
- have_thumbprint = TRUE;
- gnutls_x509_crt_deinit(crt);
- crt = NULL;
- break;
- default:
- /* We do not care about other types. */
- break;
- }
- gnutls_pkcs12_bag_deinit(bag);
- }
-err:
- if (err || !rsa_key->key || rsa_key->df_type == DF_TYPE_UNKNOWN ||
- !have_thumbprint) {
- if (!err)
- ntfs_log_error("Key type or thumbprint not found, "
- "aborting.\n");
- ntfs_rsa_private_key_release(rsa_key);
- rsa_key = NULL;
- }
- if (crt)
- gnutls_x509_crt_deinit(crt);
- if (pkey)
- gnutls_x509_privkey_deinit(pkey);
- if (bag)
- gnutls_pkcs12_bag_deinit(bag);
- if (pkcs12)
- gnutls_pkcs12_deinit(pkcs12);
- return rsa_key;
-}
-
-/**
- * ntfs_buffer_reverse -
- *
- * This is a utility function for reversing the order of a buffer in place.
- * Users of this function should be very careful not to sweep byte order
- * problems under the rug.
- */
-static inline void ntfs_buffer_reverse(u8 *buf, unsigned buf_size)
-{
- unsigned i;
- u8 t;
-
- for (i = 0; i < buf_size / 2; i++) {
- t = buf[i];
- buf[i] = buf[buf_size - i - 1];
- buf[buf_size - i - 1] = t;
- }
-}
-
-#ifndef HAVE_STRNLEN
-/**
- * strnlen - strnlen is a gnu extension so emulate it if not present
- */
-static size_t strnlen(const char *s, size_t maxlen)
-{
- const char *p, *end;
-
- /* Look for a '\0' character. */
- for (p = s, end = s + maxlen; p < end && *p; p++)
- ;
- return p - s;
-}
-#endif /* ! HAVE_STRNLEN */
-
-/**
- * ntfs_raw_fek_decrypt -
- *
- * Note: decrypting into the input buffer.
- */
-static unsigned ntfs_raw_fek_decrypt(u8 *fek, u32 fek_size,
- ntfs_rsa_private_key_t *rsa_key)
-{
- gcry_mpi_t fek_mpi;
- gcry_sexp_t fek_sexp, fek_sexp2;
- gcry_error_t err;
- size_t size, padding;
-
- /* Reverse the raw FEK. */
- ntfs_buffer_reverse(fek, fek_size);
- /* Convert the FEK to internal MPI format. */
- err = gcry_mpi_scan(&fek_mpi, GCRYMPI_FMT_USG, fek, fek_size, NULL);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to convert file encryption key to "
- "internal MPI format: %s\n",
- gcry_strerror(err));
- return 0;
- }
- /* Create an internal S-expression from the FEK. */
- err = gcry_sexp_build(&fek_sexp, NULL,
- "(enc-val (flags) (rsa (a %m)))", fek_mpi);
- gcry_mpi_release(fek_mpi);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to create internal S-expression of "
- "the file encryption key: %s\n",
- gcry_strerror(err));
- return 0;
- }
- /* Decrypt the FEK. */
- err = gcry_pk_decrypt(&fek_sexp2, fek_sexp, rsa_key->key);
- gcry_sexp_release(fek_sexp);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to decrypt the file encryption key: "
- "%s\n", gcry_strerror(err));
- return 0;
- }
- /* Extract the actual FEK from the decrypted raw S-expression. */
- fek_sexp = gcry_sexp_find_token(fek_sexp2, "value", 0);
- gcry_sexp_release(fek_sexp2);
- if (!fek_sexp) {
- ntfs_log_error("Failed to find the decrypted file encryption "
- "key in the internal S-expression.\n");
- return 0;
- }
- /* Convert the decrypted FEK S-expression into MPI format. */
- fek_mpi = gcry_sexp_nth_mpi(fek_sexp, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release(fek_sexp);
- if (!fek_mpi) {
- ntfs_log_error("Failed to convert the decrypted file "
- "encryption key S-expression to internal MPI "
- "format.\n");
- return 0;
- }
- /* Convert the decrypted FEK from MPI format to binary data. */
- err = gcry_mpi_print(GCRYMPI_FMT_USG, fek, fek_size, &size, fek_mpi);
- gcry_mpi_release(fek_mpi);
- if (err != GPG_ERR_NO_ERROR || !size) {
- ntfs_log_error("Failed to convert decrypted file encryption "
- "key from internal MPI format to binary data: "
- "%s\n", gcry_strerror(err));
- return 0;
- }
- /*
- * Finally, remove the PKCS#1 padding and return the size of the
- * decrypted FEK.
- */
- padding = strnlen((char *)fek, size) + 1;
- if (padding > size) {
- ntfs_log_error("Failed to remove PKCS#1 padding from "
- "decrypted file encryption key.\n");
- return 0;
- }
- size -= padding;
- memmove(fek, fek + padding, size);
- return size;
-}
-
-/**
- * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key
- * @src: source buffer containing 128-bit key
- *
- * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the
- * out-whitening keys required to perform desx {de,en}cryption.
- */
-static gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key,
- u64 *out_whitening, u64 *in_whitening)
-{
- static const u8 *salt1 = (const u8*)"Dan Simon ";
- static const u8 *salt2 = (const u8*)"Scott Field";
- static const int salt_len = 12;
- gcry_md_hd_t hd1, hd2;
- u32 *md;
- gcry_error_t err;
-
- err = gcry_md_open(&hd1, GCRY_MD_MD5, 0);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to open MD5 digest.\n");
- return err;
- }
- /* Hash the on-disk key. */
- gcry_md_write(hd1, src, 128 / 8);
- /* Copy the current hash for efficiency. */
- err = gcry_md_copy(&hd2, hd1);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to copy MD5 digest object.\n");
- goto out;
- }
- /* Hash with the first salt and store the result. */
- gcry_md_write(hd1, salt1, salt_len);
- md = (u32*)gcry_md_read(hd1, 0);
- des_key[0] = md[0] ^ md[1];
- des_key[1] = md[2] ^ md[3];
- /* Hash with the second salt and store the result. */
- gcry_md_write(hd2, salt2, salt_len);
- md = (u32*)gcry_md_read(hd2, 0);
- *out_whitening = *(u64*)md;
- *in_whitening = *(u64*)(md + 2);
- gcry_md_close(hd2);
-out:
- gcry_md_close(hd1);
- return err;
-}
-
-/**
- * ntfs_desx_setkey - libgcrypt set_key implementation for DES-X-MS128
- * @context: pointer to a variable of type ntfs_desx_ctx
- * @key: the 128 bit DES-X-MS128 key, concated with the DES handle
- * @keylen: must always be 16
- *
- * This is the libgcrypt set_key implementation for DES-X-MS128.
- */
-static gcry_err_code_t ntfs_desx_setkey(void *context, const u8 *key,
- unsigned keylen)
-{
- ntfs_desx_ctx *ctx = context;
- gcry_error_t err;
- u8 des_key[8];
-
- if (keylen != 16) {
- ntfs_log_error("Key length for desx must be 16.\n");
- return GPG_ERR_INV_KEYLEN;
- }
- err = gcry_cipher_open(&ctx->gcry_cipher_hd, GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_ECB, 0);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to open des cipher (error 0x%x).\n",
- err);
- return err;
- }
- err = ntfs_desx_key_expand(key, (u32*)des_key, &ctx->out_whitening,
- &ctx->in_whitening);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to expand desx key (error 0x%x).\n",
- err);
- gcry_cipher_close(ctx->gcry_cipher_hd);
- return err;
- }
- err = gcry_cipher_setkey(ctx->gcry_cipher_hd, des_key, sizeof(des_key));
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to set des key (error 0x%x).\n", err);
- gcry_cipher_close(ctx->gcry_cipher_hd);
- return err;
- }
- /*
- * Take a note of the ctx->gcry_cipher_hd since we need to close it at
- * ntfs_decrypt_data_key_close() time.
- */
- **(gcry_cipher_hd_t***)(key + ((keylen + 7) & ~7)) =
- &ctx->gcry_cipher_hd;
- return GPG_ERR_NO_ERROR;
-}
-
-/**
- * ntfs_desx_decrypt
- */
-static void ntfs_desx_decrypt(void *context, u8 *outbuf, const u8 *inbuf)
-{
- ntfs_desx_ctx *ctx = context;
- gcry_error_t err;
-
- err = gcry_cipher_reset(ctx->gcry_cipher_hd);
- if (err != GPG_ERR_NO_ERROR)
- ntfs_log_error("Failed to reset des cipher (error 0x%x).\n",
- err);
- *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening;
- err = gcry_cipher_encrypt(ctx->gcry_cipher_hd, outbuf, 8, NULL, 0);
- if (err != GPG_ERR_NO_ERROR)
- ntfs_log_error("Des decryption failed (error 0x%x).\n", err);
- *(u64*)outbuf ^= ctx->in_whitening;
-}
-
-static gcry_cipher_spec_t ntfs_desx_cipher = {
- .name = "DES-X-MS128",
- .blocksize = 8,
- .keylen = 128,
- .contextsize = sizeof(ntfs_desx_ctx),
- .setkey = ntfs_desx_setkey,
- .decrypt = ntfs_desx_decrypt,
-};
-
-#ifdef NTFS_TEST
-/*
- * Do not remove this test code from this file! (AIA)
- * It would be nice to move all tests (these and runlist) out of the library
- * (at least, into the separate file{,s}), so they would not annoy eyes. (Yura)
- */
-
-/**
- * ntfs_desx_key_expand_test
- */
-static BOOL ntfs_desx_key_expand_test(void)
-{
- const u8 known_desx_on_disk_key[16] = {
- 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f,
- 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30
- };
- const u8 known_des_key[8] = {
- 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f,
- };
- const u8 known_out_whitening[8] = {
- 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d,
- };
- const u8 known_in_whitening[8] = {
- 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e
- };
- u64 test_out_whitening, test_in_whitening;
- union {
- u64 u64;
- u32 u32[2];
- } test_des_key;
- gcry_error_t err;
- BOOL res;
-
- err = ntfs_desx_key_expand(known_desx_on_disk_key, test_des_key.u32,
- &test_out_whitening, &test_in_whitening);
- if (err != GPG_ERR_NO_ERROR)
- res = FALSE;
- else
- res = test_des_key.u64 == *(u64*)known_des_key &&
- test_out_whitening ==
- *(u64*)known_out_whitening &&
- test_in_whitening ==
- *(u64*)known_in_whitening;
- ntfs_log_error("Testing whether ntfs_desx_key_expand() works: %s\n",
- res ? "SUCCESS" : "FAILED");
- return res;
-}
-
-/**
- * ntfs_des_test
- */
-static BOOL ntfs_des_test(void)
-{
- const u8 known_des_key[8] = {
- 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f
- };
- const u8 known_des_encrypted_data[8] = {
- 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f
- };
- const u8 known_decrypted_data[8] = {
- 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09
- };
- u8 test_decrypted_data[8];
- int res;
- gcry_error_t err;
- gcry_cipher_hd_t gcry_cipher_hd;
-
- err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_ECB, 0);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to open des cipher (error 0x%x).\n",
- err);
- return FALSE;
- }
- err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key,
- sizeof(known_des_key));
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to set des key (error 0x%x.\n", err);
- gcry_cipher_close(gcry_cipher_hd);
- return FALSE;
- }
- /*
- * Apply DES decryption (ntfs actually uses encryption when decrypting).
- */
- err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data,
- sizeof(test_decrypted_data), known_des_encrypted_data,
- sizeof(known_des_encrypted_data));
- gcry_cipher_close(gcry_cipher_hd);
- if (err) {
- ntfs_log_error("Failed to des decrypt test data (error "
- "0x%x).\n", err);
- return FALSE;
- }
- res = !memcmp(test_decrypted_data, known_decrypted_data,
- sizeof(known_decrypted_data));
- ntfs_log_error("Testing whether des decryption works: %s\n",
- res ? "SUCCESS" : "FAILED");
- return res;
-}
-
-#else /* !defined(NTFS_TEST) */
-
-/**
- * ntfs_desx_key_expand_test
- */
-static inline BOOL ntfs_desx_key_expand_test(void)
-{
- return TRUE;
-}
-
-/**
- * ntfs_des_test
- */
-static inline BOOL ntfs_des_test(void)
-{
- return TRUE;
-}
-
-#endif /* !defined(NTFS_TEST) */
-
-/**
- * ntfs_fek_import_from_raw
- */
-static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf,
- unsigned fek_size)
-{
- ntfs_fek *fek;
- u32 key_size, wanted_key_size, gcry_algo;
- gcry_error_t err;
-
- key_size = le32_to_cpup(fek_buf);
- ntfs_log_debug("key_size 0x%x\n", key_size);
- if (key_size + 16 > fek_size) {
- ntfs_log_debug("Invalid FEK. It was probably decrypted with "
- "the incorrect RSA key.");
- errno = EINVAL;
- return NULL;
- }
- fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) +
- sizeof(gcry_cipher_hd_t));
- if (!fek) {
- errno = ENOMEM;
- return NULL;
- }
- fek->alg_id = *(le32*)(fek_buf + 8);
- ntfs_log_debug("algorithm_id 0x%x\n", le32_to_cpu(fek->alg_id));
- fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7);
- memcpy(fek->key_data, fek_buf + 16, key_size);
- fek->des_gcry_cipher_hd_ptr = NULL;
- *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) =
- &fek->des_gcry_cipher_hd_ptr;
- switch (fek->alg_id) {
- case CALG_DESX:
- if (!ntfs_crypto_ctx.desx_module) {
- if (!ntfs_desx_key_expand_test() || !ntfs_des_test()) {
- err = EINVAL;
- goto out;
- }
- err = gcry_cipher_register(&ntfs_desx_cipher,
- &ntfs_crypto_ctx.desx_alg_id,
- &ntfs_crypto_ctx.desx_module);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to register desx "
- "cipher: %s\n",
- gcry_strerror(err));
- err = EINVAL;
- goto out;
- }
- }
- wanted_key_size = 16;
- gcry_algo = ntfs_crypto_ctx.desx_alg_id;
- break;
- case CALG_3DES:
- wanted_key_size = 24;
- gcry_algo = GCRY_CIPHER_3DES;
- break;
- case CALG_AES_256:
- wanted_key_size = 32;
- gcry_algo = GCRY_CIPHER_AES256;
- break;
- default:
- wanted_key_size = 8;
- gcry_algo = GCRY_CIPHER_DES;
- if (fek->alg_id == CALG_DES)
- ntfs_log_error("DES is not supported at present\n");
- else
- ntfs_log_error("Unknown crypto algorithm 0x%x\n",
- le32_to_cpu(fek->alg_id));
- ntfs_log_error(". Please email %s and say that you saw this "
- "message. We will then try to implement "
- "support for this algorithm.\n", NTFS_DEV_LIST);
- err = EOPNOTSUPP;
- goto out;
- }
- if (key_size != wanted_key_size) {
- ntfs_log_error("%s key of %u bytes but needed size is %u "
- "bytes, assuming corrupt or incorrect key. "
- "Aborting.\n",
- gcry_cipher_algo_name(gcry_algo),
- (unsigned)key_size, (unsigned)wanted_key_size);
- err = EIO;
- goto out;
- }
- err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo,
- GCRY_CIPHER_MODE_CBC, 0);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("gcry_cipher_open() failed: %s\n",
- gcry_strerror(err));
- err = EINVAL;
- goto out;
- }
- err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data, key_size);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("gcry_cipher_setkey() failed: %s\n",
- gcry_strerror(err));
- gcry_cipher_close(fek->gcry_cipher_hd);
- err = EINVAL;
- goto out;
- }
- return fek;
-out:
- free(fek);
- errno = err;
- return NULL;
-}
-
-/**
- * ntfs_fek_release
- */
-static void ntfs_fek_release(ntfs_fek *fek)
-{
- if (fek->des_gcry_cipher_hd_ptr)
- gcry_cipher_close(*fek->des_gcry_cipher_hd_ptr);
- gcry_cipher_close(fek->gcry_cipher_hd);
- free(fek);
-}
-
-/**
- * ntfs_df_array_fek_get
- */
-static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
- ntfs_rsa_private_key_t *rsa_key)
-{
- EFS_DF_HEADER *df_header;
- EFS_DF_CREDENTIAL_HEADER *df_cred;
- EFS_DF_CERT_THUMBPRINT_HEADER *df_cert;
- u8 *fek_buf;
- ntfs_fek *fek;
- u32 df_count, fek_size;
- unsigned i, thumbprint_size = sizeof(rsa_key->thumbprint);
-
- df_count = le32_to_cpu(df_array->df_count);
- if (!df_count)
- ntfs_log_error("There are no elements in the DF array.\n");
- df_header = (EFS_DF_HEADER*)(df_array + 1);
- for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)(
- (u8*)df_header + le32_to_cpu(df_header->df_length))) {
- df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header +
- le32_to_cpu(df_header->cred_header_offset));
- if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) {
- ntfs_log_debug("Credential type is not certificate "
- "thumbprint, skipping DF entry.\n");
- continue;
- }
- df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred +
- le32_to_cpu(
- df_cred->cert_thumbprint_header_offset));
- if (le32_to_cpu(df_cert->thumbprint_size) != thumbprint_size) {
- ntfs_log_error("Thumbprint size %d is not valid "
- "(should be %d), skipping this DF "
- "entry.\n",
- le32_to_cpu(df_cert->thumbprint_size),
- thumbprint_size);
- continue;
- }
- if (memcmp((u8*)df_cert +
- le32_to_cpu(df_cert->thumbprint_offset),
- rsa_key->thumbprint, thumbprint_size)) {
- ntfs_log_debug("Thumbprints do not match, skipping "
- "this DF entry.\n");
- continue;
- }
- /*
- * The thumbprints match so this is probably the DF entry
- * matching the RSA key. Try to decrypt the FEK with it.
- */
- fek_size = le32_to_cpu(df_header->fek_size);
- fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset);
- /* Decrypt the FEK. Note: This is done in place. */
- fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key);
- if (fek_size) {
- /* Convert the FEK to our internal format. */
- fek = ntfs_fek_import_from_raw(fek_buf, fek_size);
- if (fek)
- return fek;
- ntfs_log_error("Failed to convert the decrypted file "
- "encryption key to internal format.\n");
- } else
- ntfs_log_error("Failed to decrypt the file "
- "encryption key.\n");
- }
- return NULL;
-}
-
-/**
- * ntfs_inode_fek_get -
- */
-static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode,
- ntfs_rsa_private_key_t *rsa_key)
-{
- EFS_ATTR_HEADER *efs;
- EFS_DF_ARRAY_HEADER *df_array = NULL;
- ntfs_fek *fek = NULL;
-
- /* Obtain the $EFS contents. */
- efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, NTFS_EFS, 4,
- NULL);
- if (!efs) {
- ntfs_log_perror("Failed to read $EFS attribute");
- return NULL;
- }
- /*
- * Depending on whether the key is a normal key or a data recovery key,
- * iterate through the DDF or DRF array, respectively.
- */
- if (rsa_key->df_type == DF_TYPE_DDF) {
- if (efs->offset_to_ddf_array)
- df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
- le32_to_cpu(efs->offset_to_ddf_array));
- else
- ntfs_log_error("There are no entries in the DDF "
- "array.\n");
- } else if (rsa_key->df_type == DF_TYPE_DRF) {
- if (efs->offset_to_drf_array)
- df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
- le32_to_cpu(efs->offset_to_drf_array));
- else
- ntfs_log_error("There are no entries in the DRF "
- "array.\n");
- } else
- ntfs_log_error("Invalid DF type.\n");
- if (df_array)
- fek = ntfs_df_array_fek_get(df_array, rsa_key);
- free(efs);
- return fek;
-}
-
-/**
- * ntfs_fek_decrypt_sector
- */
-static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
-{
- gcry_error_t err;
-
- err = gcry_cipher_reset(fek->gcry_cipher_hd);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to reset cipher: %s\n",
- gcry_strerror(err));
- return -1;
- }
- /*
- * Note: You may wonder why we are not calling gcry_cipher_setiv() here
- * instead of doing it by hand after the decryption. The answer is
- * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give
- * it a length of 16 for AES256 so it does not like it.
- */
- err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0);
- if (err != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err));
- return -1;
- }
- /* Apply the IV. */
- if (fek->alg_id == CALG_AES_256) {
- ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset);
- ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset);
- } else {
- /* All other algorithms (Des, 3Des, DesX) use the same IV. */
- ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset);
- }
- return 512;
-}
-
-/**
- * ntfs_crypto_deinit - perform library-wide crypto deinitialization
- */
-static void ntfs_crypto_deinit(void)
-{
- int i;
-
- if (!ntfs_crypto_ctx.initialized)
- return;
-
- for (i = 0; i < ntfs_crypto_ctx.nr_rsa_keys; i++)
- ntfs_rsa_private_key_release(ntfs_crypto_ctx.rsa_key[i]);
- free(ntfs_crypto_ctx.rsa_key);
- ntfs_crypto_ctx.rsa_key = NULL;
- ntfs_crypto_ctx.nr_rsa_keys = 0;
- gnutls_global_deinit();
- if (ntfs_crypto_ctx.desx_module) {
- gcry_cipher_unregister(ntfs_crypto_ctx.desx_module);
- ntfs_crypto_ctx.desx_module = NULL;
- ntfs_crypto_ctx.desx_alg_id = -1;
- }
- ntfs_crypto_ctx.initialized = 0;
-}
-
-
-static void ntfs_crypto_parse_config(struct config_t *cfg)
-{
- ntfs_crypto_ctx_t *ctx = &ntfs_crypto_ctx;
- config_setting_t *cfg_keys, *cfg_key;
- const char *pfx_file, *pfx_pwd;
- ntfs_rsa_private_key_t *key;
- u8 *pfx_buf;
- unsigned pfx_size;
- int i;
-
- /* Search for crypto.keys list. */
- cfg_keys = config_lookup(cfg, "crypto.keys");
- if (!cfg_keys) {
- ntfs_log_error("Unable to find crypto.keys in config file.\n");
- return;
- }
- /* Iterate trough list of records about keys. */
- for (i = 0; (cfg_key = config_setting_get_elem(cfg_keys, i)); i++) {
- /* Get path and password to key. */
- pfx_file = config_setting_get_string_elem(cfg_key, 0);
- pfx_pwd = config_setting_get_string_elem(cfg_key, 1);
- if (!pfx_file) {
- ntfs_log_error("Entry number %d in section crypto.keys "
- "of configuration file formed "
- "incorrectly.\n", i + 1);
- continue;
- }
- if (!pfx_pwd)
- pfx_pwd = "";
- /* Load the PKCS#12 file containing the user's private key. */
- if (ntfs_pkcs12_load_pfxfile(pfx_file, &pfx_buf, &pfx_size)) {
- ntfs_log_error("Failed to load key file %s.\n",
- pfx_file);
- continue;
- }
- /*
- * Check whether we need to allocate memory for new key pointer.
- * If yes, allocate memory for it and for 3 more pointers.
- */
- if (!(ctx->nr_rsa_keys % 4)) {
- ntfs_rsa_private_key_t **new;
-
- new = realloc(ctx->rsa_key,
- sizeof(ntfs_rsa_private_key_t *) *
- (ctx->nr_rsa_keys + 4));
- if (!new) {
- ntfs_log_perror("Unable to store all keys");
- break;
- }
- ctx->rsa_key = new;
- }
- /* Obtain the user's private RSA key from the key file. */
- key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, pfx_pwd);
- if (key)
- ctx->rsa_key[ctx->nr_rsa_keys++] = key;
- else
- ntfs_log_error("Failed to obtain RSA key from %s\n",
- pfx_file);
- /* No longer need the pfx file contents. */
- free(pfx_buf);
- }
-}
-
-
-static void ntfs_crypto_read_configs(void)
-{
- struct config_t cfg;
- char *home;
- int fd = -1;
-
- config_init(&cfg);
- /* Load system configuration file. */
- if (config_read_file(&cfg, NTFS_CONFIG_PATH_SYSTEM))
- ntfs_crypto_parse_config(&cfg);
- else
- if (config_error_line(&cfg)) /* Do not cry if file absent. */
- ntfs_log_error("Failed to read system configuration "
- "file: %s (line %d).\n",
- config_error_text(&cfg),
- config_error_line(&cfg));
- /* Load user configuration file. */
- fd = open(".", O_RDONLY); /* Save current working directory. */
- if (fd == -1) {
- ntfs_log_error("Failed to open working directory.\n");
- goto out;
- }
- home = getenv("HOME");
- if (!home) {
- ntfs_log_error("Environment variable HOME is not set.\n");
- goto out;
- }
- if (chdir(home) == -1) {
- ntfs_log_perror("chdir() to home directory failed");
- goto out;
- }
- if (config_read_file(&cfg, NTFS_CONFIG_PATH_USER))
- ntfs_crypto_parse_config(&cfg);
- else
- if (config_error_line(&cfg)) /* Do not cry if file absent. */
- ntfs_log_error("Failed to read user configuration "
- "file: %s (line %d).\n",
- config_error_text(&cfg),
- config_error_line(&cfg));
- if (fchdir(fd) == -1)
- ntfs_log_error("Failed to restore original working "
- "directory.\n");
-out:
- if (fd != -1)
- close(fd);
- config_destroy(&cfg);
-}
-
-/**
- * ntfs_crypto_init - perform library-wide crypto initializations
- *
- * This function is called during first call of ntfs_crypto_attr_open and
- * performs gcrypt and GNU TLS initializations, then read list of PFX files
- * from configuration files and load RSA keys from them.
- */
-static int ntfs_crypto_init(void)
-{
- int err;
-
- if (ntfs_crypto_ctx.initialized)
- return 0;
-
- /* Initialize gcrypt library. Note: Must come before GNU TLS init. */
- if (gcry_control(GCRYCTL_DISABLE_SECMEM, 0) != GPG_ERR_NO_ERROR) {
- ntfs_log_error("Failed to initialize the gcrypt library.\n");
- return -1;
- }
- /* Initialize GNU TLS library. Note: Must come after libgcrypt init. */
- err = gnutls_global_init();
- if (err < 0) {
- ntfs_log_error("Failed to initialize GNU TLS library: %s\n",
- gnutls_strerror(err));
- return -1;
- }
- /* Read crypto related sections of libntfs configuration files. */
- ntfs_crypto_read_configs();
-
- ntfs_crypto_ctx.initialized = 1;
- atexit(ntfs_crypto_deinit);
- return 0;
-}
-
-
-/**
- * ntfs_crypto_attr_open - perform crypto related initialization for attribute
- * @na: ntfs attribute to perform initialization for
- *
- * This function is called from ntfs_attr_open for encrypted attributes and
- * tries to decrypt FEK enumerating all user submitted RSA keys. If we
- * successfully obtained FEK, then @na->crypto is allocated and FEK stored
- * inside. In the other case @na->crypto is set to NULL.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_crypto_attr_open(ntfs_attr *na)
-{
- ntfs_fek *fek;
- int i;
-
- na->crypto = NULL;
- if (!na || !NAttrEncrypted(na)) {
- errno = EINVAL;
- return -1;
- }
- if (ntfs_crypto_init()) {
- errno = EACCES;
- return -1;
- }
-
- for (i = 0; i < ntfs_crypto_ctx.nr_rsa_keys; i++) {
- fek = ntfs_inode_fek_get(na->ni, ntfs_crypto_ctx.rsa_key[i]);
- if (fek) {
- na->crypto = ntfs_malloc(sizeof(ntfs_crypto_attr));
- if (!na->crypto)
- return -1;
- na->crypto->fek = fek;
- return 0;
- }
- }
-
- errno = EACCES;
- return -1;
-}
-
-
-/**
- * ntfs_crypto_attr_close - perform crypto related deinit for attribute
- * @na: ntfs attribute to perform deinitialization for
- *
- * This function is called from ntfs_attr_close for encrypted attributes and
- * frees memory that were allocated for it handling.
- */
-void ntfs_crypto_attr_close(ntfs_attr *na)
-{
- if (!na || !NAttrEncrypted(na))
- return;
-
- if (na->crypto) {
- ntfs_fek_release(na->crypto->fek);
- free(na->crypto);
- }
-}
-
-
-/**
- * ntfs_crypto_attr_pread - read from an encrypted attribute
- * @na: ntfs attribute to read from
- * @pos: byte position in the attribute to begin reading from
- * @count: number of bytes to read
- * @b: output data buffer
- *
- * This function is called from ntfs_attr_pread for encrypted attributes and
- * should behave as described in ntfs_attr_pread description.
- */
-s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
-{
- unsigned char *buffer;
- s64 bytes_read, offset, total, length;
- int i;
-
- if (!na || pos < 0 || count < 0 || !b || !NAttrEncrypted(na)) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return 0;
-
- if (!na->crypto) {
- errno = EACCES;
- return -1;
- }
-
- buffer = malloc(NTFS_EFS_SECTOR_SIZE);
- if (!buffer)
- return -1;
-
- ntfs_attr_map_runlist_range(na, pos >> na->ni->vol->cluster_size_bits,
- (pos + count - 1) >> na->ni->vol->cluster_size_bits);
-
- total = 0;
- offset = ROUND_DOWN(pos, 9);
- while (total < count && offset < na->data_size) {
- /* Calculate number of bytes we actually want. */
- length = NTFS_EFS_SECTOR_SIZE;
- if (offset + length > pos + count)
- length = pos + count - offset;
- if (offset + length > na->data_size)
- length = na->data_size - offset;
-
- if (length < 0) {
- total = -1;
- errno = EIO;
- ntfs_log_error("LIBRARY BUG!!! Please report that you "
- "saw this message to %s. Thanks!",
- NTFS_DEV_LIST);
- break;
- }
-
- /* Just write zeros if @offset fully beyond initialized size. */
- if (offset >= na->initialized_size) {
- memset(b + total, 0, length);
- total += length;
- continue;
- }
-
- bytes_read = ntfs_rl_pread(na->ni->vol, na->rl, offset,
- NTFS_EFS_SECTOR_SIZE, buffer);
- if (!bytes_read)
- break;
- if (bytes_read != NTFS_EFS_SECTOR_SIZE) {
- ntfs_log_perror("%s(): ntfs_rl_pread returned %lld "
- "bytes", "ntfs_crypto_attr_pread", bytes_read);
- break;
- }
- if ((i = ntfs_fek_decrypt_sector(na->crypto->fek, buffer,
- offset)) < bytes_read) {
- ntfs_log_error("%s(): Couldn't decrypt all data "
- "(%u/%lld/%lld/%lld)!", "ntfs_crypto_attr_pread",
- i, (long long)bytes_read,
- (long long)offset, (long long)total);
- break;
- }
-
- /* Handle partially in initialized size situation. */
- if (offset + length > na->initialized_size)
- memset(buffer + (na->initialized_size - offset), 0,
- offset + length - na->initialized_size);
-
- if (offset >= pos)
- memcpy(b + total, buffer, length);
- else {
- length -= (pos - offset);
- memcpy(b + total, buffer + (pos - offset), length);
- }
- total += length;
- offset += bytes_read;
- }
-
- free(buffer);
- return total;
-}
-
-#else /* !ENABLE_CRYPTO */
-
-/* Stubs for crypto-disabled version of libntfs. */
-
-int ntfs_crypto_attr_open(ntfs_attr *na)
-{
- na->crypto = NULL;
- errno = EACCES;
- return -1;
-}
-
-void ntfs_crypto_attr_close(ntfs_attr *na)
-{
-}
-
-s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
- void *b)
-{
- errno = EACCES;
- return -1;
-}
-
-#endif /* !ENABLE_CRYPTO */
-
diff --git a/usr/src/lib/libntfs/common/libntfs/debug.c b/usr/src/lib/libntfs/common/libntfs/debug.c
deleted file mode 100644
index 8962051006..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/debug.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * debug.c - Debugging output functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "runlist.h"
-#include "debug.h"
-#include "logging.h"
-
-#ifdef DEBUG
-/**
- * ntfs_debug_runlist_dump - Dump a runlist.
- * @rl:
- *
- * Description...
- *
- * Returns:
- */
-void ntfs_debug_runlist_dump(const runlist_element *rl)
-{
- int i = 0;
- const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
- "LCN_ENOENT ", "LCN_EINVAL ",
- "LCN_unknown " };
-
- ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
- if (!rl) {
- ntfs_log_debug("Run list not present.\n");
- return;
- }
- ntfs_log_debug("VCN LCN Run length\n");
- do {
- LCN lcn = (rl + i)->lcn;
-
- if (lcn < (LCN)0) {
- int idx = -lcn - 1;
-
- if (idx > -LCN_EINVAL - 1)
- idx = 4;
- ntfs_log_debug("%-16llx %s %-16llx%s\n", rl[i].vcn, lcn_str[idx], rl[i].length, rl[i].length ? "" : " (runlist end)");
- } else
- ntfs_log_debug("%-16llx %-16llx %-16llx%s\n", rl[i].vcn, rl[i].lcn, rl[i].length, rl[i].length ? "" : " (runlist end)");
- } while (rl[i++].length);
-}
-
-#endif
-
diff --git a/usr/src/lib/libntfs/common/libntfs/device.c b/usr/src/lib/libntfs/common/libntfs/device.c
deleted file mode 100644
index 89c2b1b2dc..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/device.c
+++ /dev/null
@@ -1,796 +0,0 @@
-/**
- * device.c - Low level device io functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif
-#ifdef HAVE_LINUX_FD_H
-#include <linux/fd.h>
-#endif
-#ifdef HAVE_LINUX_HDREG_H
-#include <linux/hdreg.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "mst.h"
-#include "debug.h"
-#include "device.h"
-#include "logging.h"
-
-#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
-#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */
-#endif
-#if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
-#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */
-#endif
-#if defined(linux) && !defined(HDIO_GETGEO)
-#define HDIO_GETGEO 0x0301 /* Get device geometry. */
-#endif
-#if defined(linux) && defined(_IO) && !defined(BLKSSZGET)
-# define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */
-#endif
-#if defined(linux) && defined(_IO) && !defined(BLKBSZSET)
-# define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */
-#endif
-
-/**
- * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
- * @name: name of the device (must be present)
- * @state: initial device state (usually zero)
- * @dops: ntfs device operations to use with the device (must be present)
- * @priv_data: pointer to private data (optional)
- *
- * Allocate an ntfs device structure and pre-initialize it with the user-
- * specified device operations @dops, device state @state, device name @name,
- * and optional private data @priv_data.
- *
- * Note, @name is copied and can hence be freed after this functions returns.
- *
- * On success return a pointer to the allocated ntfs device structure and on
- * error return NULL with errno set to the error code returned by malloc().
- */
-struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
- struct ntfs_device_operations *dops, void *priv_data)
-{
- struct ntfs_device *dev;
-
- if (!name) {
- errno = EINVAL;
- return NULL;
- }
-
- dev = (struct ntfs_device *)ntfs_malloc(sizeof(struct ntfs_device));
- if (dev) {
- if (!(dev->d_name = strdup(name))) {
- int eo = errno;
- free(dev);
- errno = eo;
- return NULL;
- }
- dev->d_ops = dops;
- dev->d_state = state;
- dev->d_private = priv_data;
- }
- return dev;
-}
-
-/**
- * ntfs_device_free - free an ntfs device structure
- * @dev: ntfs device structure to free
- *
- * Free the ntfs device structure @dev.
- *
- * Return 0 on success or -1 on error with errno set to the error code. The
- * following error codes are defined:
- * EINVAL Invalid pointer @dev.
- * EBUSY Device is still open. Close it before freeing it!
- */
-int ntfs_device_free(struct ntfs_device *dev)
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
- if (NDevOpen(dev)) {
- errno = EBUSY;
- return -1;
- }
- free(dev->d_name);
- free(dev);
- return 0;
-}
-
-/**
- * fake_pread - read operation disguised as pread
- * @dev: device to read from
- * @b: output data buffer
- * @count: number of bytes to read
- * @pos: position in device to read from
- *
- * Auxiliary function, used when we emulate pread by seek() + a sequence of
- * read()s.
- */
-static s64 fake_pread(struct ntfs_device *dev, void *b, s64 count,
- s64 pos __attribute__((unused)))
-{
- return dev->d_ops->read(dev, b, count);
-}
-
-/**
- * ntfs_pread - positioned read from disk
- * @dev: device to read from
- * @pos: position in device to read from
- * @count: number of bytes to read
- * @b: output data buffer
- *
- * This function will read @count bytes from device @dev at position @pos into
- * the data buffer @b.
- *
- * On success, return the number of successfully read bytes. If this number is
- * lower than @count this means that we have either reached end of file or
- * encountered an error during the read so that the read is partial. 0 means
- * end of file or nothing to read (@count is 0).
- *
- * On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of either seek, read, or set to EINVAL in case of
- * invalid arguments.
- */
-s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
-{
- s64 br, total;
- struct ntfs_device_operations *dops;
- s64 (*_pread)(struct ntfs_device *, void *, s64, s64);
-
- ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
- if (!b || count < 0 || pos < 0) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return 0;
- dops = dev->d_ops;
- _pread = dops->pread;
- if (!_pread)
- _pread = fake_pread;
-seek:
- /* Locate to position if pread is to be emulated by seek() + read(). */
- if (_pread == fake_pread &&
- dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
- ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned "
- "error", pos);
- return -1;
- }
- /* Read the data. */
- for (total = 0; count; count -= br, total += br) {
- br = _pread(dev, (char*)b + total, count, pos + total);
- /* If everything ok, continue. */
- if (br > 0)
- continue;
- /* If EOF or error return number of bytes read. */
- if (!br || total)
- return total;
- /*
- * If pread is not supported by the OS, fall back to emulating
- * it by seek() + read() and set the device pread() pointer to
- * NULL so we automatically use seek() + read() from now on.
- */
- if (errno == ENOSYS && _pread != fake_pread) {
- _pread = fake_pread;
- dops->pread = NULL;
- goto seek;
- }
- /* Nothing read and error, return error status. */
- return br;
- }
- /* Finally, return the number of bytes read. */
- return total;
-}
-
-/**
- * fake_pwrite - write operation disguised as pwrite
- * @dev: device to write to
- * @b: input data buffer
- * @count: number of bytes to write
- * @pos: position in device to write to
- *
- * Auxiliary function, used when we emulate pwrite by seek() + a sequence of
- * write()s.
- */
-static s64 fake_pwrite(struct ntfs_device *dev, const void *b, s64 count,
- s64 pos __attribute__((unused)))
-{
- return dev->d_ops->write(dev, b, count);
-}
-
-/**
- * ntfs_pwrite - positioned write to disk
- * @dev: device to write to
- * @pos: position in file descriptor to write to
- * @count: number of bytes to write
- * @b: data buffer to write to disk
- *
- * This function will write @count bytes from data buffer @b to the device @dev
- * at position @pos.
- *
- * On success, return the number of successfully written bytes. If this number
- * is lower than @count this means that the write has been interrupted in
- * flight or that an error was encountered during the write so that the write
- * is partial. 0 means nothing was written (also return 0 when @count is 0).
- *
- * On error and nothing has been written, return -1 with errno set
- * appropriately to the return code of either seek, write, or set
- * to EINVAL in case of invalid arguments.
- */
-s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
- const void *b)
-{
- s64 written, total;
- struct ntfs_device_operations *dops;
- s64 (*_pwrite)(struct ntfs_device *, const void *, s64, s64);
-
- ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
- if (!b || count < 0 || pos < 0) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return 0;
- if (NDevReadOnly(dev)) {
- errno = EROFS;
- return -1;
- }
- dops = dev->d_ops;
- _pwrite = dops->pwrite;
- if (!_pwrite)
- _pwrite = fake_pwrite;
-seek:
- /*
- * Locate to position if pwrite is to be emulated by seek() + write().
- */
- if (_pwrite == fake_pwrite &&
- dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
- ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error",
- pos);
- return -1;
- }
- NDevSetDirty(dev);
- /* Write the data. */
- for (total = 0; count; count -= written, total += written) {
- written = _pwrite(dev, (const char*)b + total, count,
- pos + total);
- /* If everything ok, continue. */
- if (written > 0)
- continue;
- /*
- * If nothing written or error return number of bytes written.
- */
- if (!written || total)
- break;
- /*
- * If pwrite is not supported by the OS, fall back to emulating
- * it by seek() + write() and set the device pwrite() pointer
- * to NULL so we automatically use seek() + write() from now
- * on.
- */
- if (errno == ENOSYS && _pwrite != fake_pwrite) {
- _pwrite = fake_pwrite;
- dops->pwrite = NULL;
- goto seek;
- }
- /* Nothing written and error, return error status. */
- return written;
- }
- /* Finally, return the number of bytes written. */
- return total;
-}
-
-/**
- * ntfs_mst_pread - multi sector transfer (mst) positioned read
- * @dev: device to read from
- * @pos: position in file descriptor to read from
- * @count: number of blocks to read
- * @bksize: size of each block that needs mst deprotecting
- * @b: output data buffer
- *
- * Multi sector transfer (mst) positioned read. This function will read @count
- * blocks of size @bksize bytes each from device @dev at position @pos into the
- * the data buffer @b.
- *
- * On success, return the number of successfully read blocks. If this number is
- * lower than @count this means that we have reached end of file, that the read
- * was interrupted, or that an error was encountered during the read so that
- * the read is partial. 0 means end of file or nothing was read (also return 0
- * when @count or @bksize are 0).
- *
- * On error and nothing was read, return -1 with errno set appropriately to the
- * return code of either seek, read, or set to EINVAL in case of invalid
- * arguments.
- *
- * NOTE: If an incomplete multi sector transfer has been detected the magic
- * will have been changed to magic_BAAD but no error will be returned. Thus it
- * is possible that we return count blocks as being read but that any number
- * (between zero and count!) of these blocks is actually subject to a multi
- * sector transfer error. This should be detected by the caller by checking for
- * the magic being "BAAD".
- */
-s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
- const u32 bksize, void *b)
-{
- s64 br, i;
-
- if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
- errno = EINVAL;
- return -1;
- }
- /* Do the read. */
- br = ntfs_pread(dev, pos, count * bksize, b);
- if (br < 0)
- return br;
- /*
- * Apply fixups to successfully read data, disregarding any errors
- * returned from the MST fixup function. This is because we want to
- * fixup everything possible and we rely on the fact that the "BAAD"
- * magic will be detected later on.
- */
- count = br / bksize;
- for (i = 0; i < count; ++i)
- ntfs_mst_post_read_fixup((NTFS_RECORD*)
- ((u8*)b + i * bksize), bksize);
- /* Finally, return the number of complete blocks read. */
- return count;
-}
-
-/**
- * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
- * @dev: device to write to
- * @pos: position in file descriptor to write to
- * @count: number of blocks to write
- * @bksize: size of each block that needs mst protecting
- * @b: data buffer to write to disk
- *
- * Multi sector transfer (mst) positioned write. This function will write
- * @count blocks of size @bksize bytes each from data buffer @b to the device
- * @dev at position @pos.
- *
- * On success, return the number of successfully written blocks. If this number
- * is lower than @count this means that the write has been interrupted or that
- * an error was encountered during the write so that the write is partial. 0
- * means nothing was written (also return 0 when @count or @bksize are 0).
- *
- * On error and nothing has been written, return -1 with errno set
- * appropriately to the return code of either seek, write, or set
- * to EINVAL in case of invalid arguments.
- *
- * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
- * deprotect algorithm (no checking). This saves us from making a copy before
- * the write and at the same time causes the usn to be incremented in the
- * buffer. This conceptually fits in better with the idea that cached data is
- * always deprotected and protection is performed when the data is actually
- * going to hit the disk and the cache is immediately deprotected again
- * simulating an mst read on the written data. This way cache coherency is
- * achieved.
- */
-s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
- const u32 bksize, void *b)
-{
- s64 written, i;
-
- if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return 0;
- /* Prepare data for writing. */
- for (i = 0; i < count; ++i) {
- int err;
-
- err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
- ((u8*)b + i * bksize), bksize);
- if (err < 0) {
- /* Abort write at this position. */
- if (!i)
- return err;
- count = i;
- break;
- }
- }
- /* Write the prepared data. */
- written = ntfs_pwrite(dev, pos, count * bksize, b);
- /* Quickly deprotect the data again. */
- for (i = 0; i < count; ++i)
- ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
- if (written <= 0)
- return written;
- /* Finally, return the number of complete blocks written. */
- return written / bksize;
-}
-
-/**
- * ntfs_cluster_read - read ntfs clusters
- * @vol: volume to read from
- * @lcn: starting logical cluster number
- * @count: number of clusters to read
- * @b: output data buffer
- *
- * Read @count ntfs clusters starting at logical cluster number @lcn from
- * volume @vol into buffer @b. Return number of clusters read or -1 on error,
- * with errno set to the error code.
- */
-s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
- void *b)
-{
- s64 br;
-
- if (!vol || lcn < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- if (vol->nr_clusters < lcn + count) {
- errno = ESPIPE;
- return -1;
- }
- br = ntfs_pread(vol->u.dev, lcn << vol->cluster_size_bits,
- count << vol->cluster_size_bits, b);
- if (br < 0) {
- ntfs_log_perror("Error reading cluster(s)");
- return br;
- }
- return br >> vol->cluster_size_bits;
-}
-
-/**
- * ntfs_cluster_write - write ntfs clusters
- * @vol: volume to write to
- * @lcn: starting logical cluster number
- * @count: number of clusters to write
- * @b: data buffer to write to disk
- *
- * Write @count ntfs clusters starting at logical cluster number @lcn from
- * buffer @b to volume @vol. Return the number of clusters written or -1 on
- * error, with errno set to the error code.
- */
-s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
- const s64 count, const void *b)
-{
- s64 bw;
-
- if (!vol || lcn < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- if (vol->nr_clusters < lcn + count) {
- errno = ESPIPE;
- return -1;
- }
- if (!NVolReadOnly(vol))
- bw = ntfs_pwrite(vol->u.dev, lcn << vol->cluster_size_bits,
- count << vol->cluster_size_bits, b);
- else
- bw = count << vol->cluster_size_bits;
- if (bw < 0) {
- ntfs_log_perror("Error writing cluster(s)");
- return bw;
- }
- return bw >> vol->cluster_size_bits;
-}
-
-/**
- * ntfs_device_offset_valid - test if a device offset is valid
- * @dev: open device
- * @ofs: offset to test for validity
- *
- * Test if the offset @ofs is an existing location on the device described
- * by the open device structure @dev.
- *
- * Return 0 if it is valid and -1 if it is not valid.
- */
-static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
-{
- char ch;
-
- if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
- dev->d_ops->read(dev, &ch, 1) == 1)
- return 0;
- return -1;
-}
-
-/**
- * ntfs_device_size_get - return the size of a device in blocks
- * @dev: open device
- * @block_size: block size in bytes in which to return the result
- *
- * Return the number of @block_size sized blocks in the device described by the
- * open device @dev.
- *
- * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
- *
- * On error return -1 with errno set to the error code.
- */
-s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
-{
- s64 high, low;
-
- if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
- errno = EINVAL;
- return -1;
- }
-#ifdef BLKGETSIZE64
- { u64 size;
-
- if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
- ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
- (unsigned long long)size,
- (unsigned long long)size);
- return (s64)size / block_size;
- }
- }
-#endif
-#ifdef BLKGETSIZE
- { unsigned long size;
-
- if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
- ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
- size, size);
- return (s64)size * 512 / block_size;
- }
- }
-#endif
-#ifdef FDGETPRM
- { struct floppy_struct this_floppy;
-
- if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
- ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
- (unsigned long)this_floppy.size,
- (unsigned long)this_floppy.size);
- return (s64)this_floppy.size * 512 / block_size;
- }
- }
-#endif
- /*
- * We couldn't figure it out by using a specialized ioctl,
- * so do binary search to find the size of the device.
- */
- low = 0LL;
- for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
- low = high;
- while (low < high - 1LL) {
- const s64 mid = (low + high) / 2;
-
- if (!ntfs_device_offset_valid(dev, mid))
- low = mid;
- else
- high = mid;
- }
- dev->d_ops->seek(dev, 0LL, SEEK_SET);
- return (low + 1LL) / block_size;
-}
-
-/**
- * ntfs_device_partition_start_sector_get - get starting sector of a partition
- * @dev: open device
- *
- * On success, return the starting sector of the partition @dev in the parent
- * block device of @dev. On error return -1 with errno set to the error code.
- *
- * The following error codes are defined:
- * EINVAL Input parameter error
- * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
- * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
- */
-s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
-#ifdef HDIO_GETGEO
- { struct hd_geometry geo;
-
- if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
- ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
- geo.start, geo.start);
- return geo.start;
- }
- }
-#else
- errno = EOPNOTSUPP;
-#endif
- return -1;
-}
-
-/**
- * ntfs_device_heads_get - get number of heads of device
- * @dev: open device
- *
- * On success, return the number of heads on the device @dev. On error return
- * -1 with errno set to the error code.
- *
- * The following error codes are defined:
- * EINVAL Input parameter error
- * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
- * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
- */
-int ntfs_device_heads_get(struct ntfs_device *dev)
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
-#ifdef HDIO_GETGEO
- { struct hd_geometry geo;
-
- if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
- ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
- (unsigned)geo.heads,
- (unsigned)geo.heads);
- return geo.heads;
- }
- }
-#else
- errno = EOPNOTSUPP;
-#endif
- return -1;
-}
-
-/**
- * ntfs_device_sectors_per_track_get - get number of sectors per track of device
- * @dev: open device
- *
- * On success, return the number of sectors per track on the device @dev. On
- * error return -1 with errno set to the error code.
- *
- * The following error codes are defined:
- * EINVAL Input parameter error
- * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
- * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
- */
-int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
-#ifdef HDIO_GETGEO
- { struct hd_geometry geo;
-
- if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
- ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
- (unsigned)geo.sectors,
- (unsigned)geo.sectors);
- return geo.sectors;
- }
- }
-#else
- errno = EOPNOTSUPP;
-#endif
- return -1;
-}
-
-/**
- * ntfs_device_sector_size_get - get sector size of a device
- * @dev: open device
- *
- * On success, return the sector size in bytes of the device @dev.
- * On error return -1 with errno set to the error code.
- *
- * The following error codes are defined:
- * EINVAL Input parameter error
- * EOPNOTSUPP System does not support BLKSSZGET ioctl
- * ENOTTY @dev is a file or a device not supporting BLKSSZGET
- */
-int ntfs_device_sector_size_get(struct ntfs_device *dev)
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
-#ifdef BLKSSZGET
- {
- int sect_size = 0;
-
- if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
- ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
- sect_size);
- return sect_size;
- }
- }
-#else
- errno = EOPNOTSUPP;
-#endif
- return -1;
-}
-
-/**
- * ntfs_device_block_size_set - set block size of a device
- * @dev: open device
- * @block_size: block size to set @dev to
- *
- * On success, return 0.
- * On error return -1 with errno set to the error code.
- *
- * The following error codes are defined:
- * EINVAL Input parameter error
- * EOPNOTSUPP System does not support BLKBSZSET ioctl
- * ENOTTY @dev is a file or a device not supporting BLKBSZSET
- */
-int ntfs_device_block_size_set(struct ntfs_device *dev,
- int block_size __attribute__((unused)))
-{
- if (!dev) {
- errno = EINVAL;
- return -1;
- }
-#ifdef BLKBSZSET
- {
- size_t s_block_size = block_size;
- if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
- ntfs_log_debug("Used BLKBSZSET to set block size to "
- "%d bytes.\n", block_size);
- return 0;
- }
- /* If not a block device, pretend it was successful. */
- if (!NDevBlock(dev))
- return 0;
- }
-#else
- /* If not a block device, pretend it was successful. */
- if (!NDevBlock(dev))
- return 0;
- errno = EOPNOTSUPP;
-#endif
- return -1;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/device_io.c b/usr/src/lib/libntfs/common/libntfs/device_io.c
deleted file mode 100644
index 706e935f34..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/device_io.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * device_io.c - Default device io operations. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2003-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "config.h"
-
-#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
-
-#if defined(__CYGWIN32__)
-
-/* On Cygwin; use Win32 low level device operations. */
-#include "win32_io.c"
-
-#elif defined(__FreeBSD__)
-
-/* On FreeBSD; need to use sector aligned i/o. */
-#include "freebsd_io.c"
-
-#else
-
-/*
- * Not on Cygwin or FreeBSD; use standard Unix style low level device
- * operations.
- */
-#include "unix_io.c"
-
-#endif
-
-#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */
diff --git a/usr/src/lib/libntfs/common/libntfs/dir.c b/usr/src/lib/libntfs/common/libntfs/dir.c
deleted file mode 100644
index b112c73205..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/dir.c
+++ /dev/null
@@ -1,1773 +0,0 @@
-/**
- * dir.c - Directory handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2005 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef HAVE_SYS_SYSMACROS_H
-#include <sys/sysmacros.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "debug.h"
-#include "attrib.h"
-#include "inode.h"
-#include "dir.h"
-#include "volume.h"
-#include "mft.h"
-#include "index.h"
-#include "ntfstime.h"
-#include "lcnalloc.h"
-#include "logging.h"
-
-/*
- * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O"
- * and "$Q" as global constants.
- */
-ntfschar NTFS_INDEX_I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
- const_cpu_to_le16('3'), const_cpu_to_le16('0'),
- const_cpu_to_le16('\0') };
-ntfschar NTFS_INDEX_SII[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'),
- const_cpu_to_le16('I'), const_cpu_to_le16('I'),
- const_cpu_to_le16('\0') };
-ntfschar NTFS_INDEX_SDH[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'),
- const_cpu_to_le16('D'), const_cpu_to_le16('H'),
- const_cpu_to_le16('\0') };
-ntfschar NTFS_INDEX_O[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('O'),
- const_cpu_to_le16('\0') };
-ntfschar NTFS_INDEX_Q[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'),
- const_cpu_to_le16('\0') };
-ntfschar NTFS_INDEX_R[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('R'),
- const_cpu_to_le16('\0') };
-
-/**
- * ntfs_inode_lookup_by_name - find an inode in a directory given its name
- * @dir_ni: ntfs inode of the directory in which to search for the name
- * @uname: Unicode name for which to search in the directory
- * @uname_len: length of the name @uname in Unicode characters
- *
- * Look for an inode with name @uname in the directory with inode @dir_ni.
- * ntfs_inode_lookup_by_name() walks the contents of the directory looking for
- * the Unicode name. If the name is found in the directory, the corresponding
- * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
- * is a 64-bit number containing the sequence number.
- *
- * On error, return -1 with errno set to the error code. If the inode is is not
- * found errno is ENOENT.
- *
- * Note, @uname_len does not include the (optional) terminating NULL character.
- *
- * Note, we look for a case sensitive match first but we also look for a case
- * insensitive match at the same time. If we find a case insensitive match, we
- * save that for the case that we don't find an exact match, where we return
- * the mft reference of the case insensitive match.
- *
- * If the volume is mounted with the case sensitive flag set, then we only
- * allow exact matches.
- */
-u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
- const int uname_len)
-{
- VCN vcn;
- u64 mref = 0;
- s64 br;
- ntfs_volume *vol = dir_ni->vol;
- ntfs_attr_search_ctx *ctx;
- INDEX_ROOT *ir;
- INDEX_ENTRY *ie;
- INDEX_ALLOCATION *ia;
- u8 *index_end;
- ntfs_attr *ia_na;
- int eo, rc;
- u32 index_block_size, index_vcn_size;
- u8 index_vcn_size_bits;
-
- if (!dir_ni || !dir_ni->mrec || !uname || uname_len <= 0) {
- errno = EINVAL;
- return -1;
- }
-
- ctx = ntfs_attr_get_search_ctx(dir_ni, NULL);
- if (!ctx)
- return -1;
-
- /* Find the index root attribute in the mft record. */
- if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- ntfs_log_perror("Index root attribute missing in directory "
- "inode 0x%llx", (unsigned long long)dir_ni->
- mft_no);
- goto put_err_out;
- }
- /* Get to the index root value. */
- ir = (INDEX_ROOT*)((u8*)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- index_block_size = le32_to_cpu(ir->index_block_size);
- if (index_block_size < NTFS_BLOCK_SIZE ||
- index_block_size & (index_block_size - 1)) {
- ntfs_log_debug("Index block size %u is invalid.\n",
- (unsigned)index_block_size);
- goto put_err_out;
- }
- index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
- /* The first index entry. */
- ie = (INDEX_ENTRY*)((u8*)&ir->index +
- le32_to_cpu(ir->index.entries_offset));
- /*
- * Loop until we exceed valid memory (corruption case) or until we
- * reach the last entry.
- */
- for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
- /* Bounds checks. */
- if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
- sizeof(INDEX_ENTRY_HEADER) > index_end ||
- (u8*)ie + le16_to_cpu(ie->key_length) >
- index_end)
- goto put_err_out;
- /*
- * The last entry cannot contain a name. It can however contain
- * a pointer to a child node in the B+tree so we just break out.
- */
- if (ie->flags & INDEX_ENTRY_END)
- break;
- /*
- * We perform a case sensitive comparison and if that matches
- * we are done and return the mft reference of the inode (i.e.
- * the inode number together with the sequence number for
- * consistency checking). We convert it to cpu format before
- * returning.
- */
- if (ntfs_names_are_equal(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
-found_it:
- /*
- * We have a perfect match, so we don't need to care
- * about having matched imperfectly before.
- */
- mref = le64_to_cpu(ie->u.indexed_file);
- ntfs_attr_put_search_ctx(ctx);
- return mref;
- }
- /*
- * For a case insensitive mount, we also perform a case
- * insensitive comparison. If the comparison matches, we cache
- * the mft reference in mref. Use first case insensitive match
- * in case if no name matches case sensitive, but several names
- * matches case insensitive.
- */
- if (!mref && !NVolCaseSensitive(vol) &&
- ntfs_names_are_equal(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length,
- IGNORE_CASE, vol->upcase, vol->upcase_len))
- mref = le64_to_cpu(ie->u.indexed_file);
- /*
- * Not a perfect match, need to do full blown collation so we
- * know which way in the B+tree we have to go.
- */
- rc = ntfs_names_collate(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length, 1,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
- /*
- * If uname collates before the name of the current entry, there
- * is definitely no such name in this index but we might need to
- * descend into the B+tree so we just break out of the loop.
- */
- if (rc == -1)
- break;
- /* The names are not equal, continue the search. */
- if (rc)
- continue;
- /*
- * Names match with case insensitive comparison, now try the
- * case sensitive comparison, which is required for proper
- * collation.
- */
- rc = ntfs_names_collate(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length, 1,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len);
- if (rc == -1)
- break;
- if (rc)
- continue;
- /*
- * Perfect match, this will never happen as the
- * ntfs_are_names_equal() call will have gotten a match but we
- * still treat it correctly.
- */
- goto found_it;
- }
- /*
- * We have finished with this index without success. Check for the
- * presence of a child node and if not present return error code
- * ENOENT, unless we have got the mft reference of a matching name
- * cached in mref in which case return mref.
- */
- if (!(ie->flags & INDEX_ENTRY_NODE)) {
- ntfs_attr_put_search_ctx(ctx);
- if (mref)
- return mref;
- ntfs_log_debug("Entry not found.\n");
- errno = ENOENT;
- return -1;
- } /* Child node present, descend into it. */
-
- /* Open the index allocation attribute. */
- ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
- if (!ia_na) {
- ntfs_log_perror("Failed to open index allocation attribute. "
- "Directory inode 0x%llx is corrupt or driver "
- "bug", (unsigned long long)dir_ni->mft_no);
- goto put_err_out;
- }
-
- /* Allocate a buffer for the current index block. */
- ia = (INDEX_ALLOCATION*)malloc(index_block_size);
- if (!ia) {
- ntfs_log_perror("Failed to allocate buffer for index block");
- ntfs_attr_close(ia_na);
- goto put_err_out;
- }
-
- /* Determine the size of a vcn in the directory index. */
- if (vol->cluster_size <= index_block_size) {
- index_vcn_size = vol->cluster_size;
- index_vcn_size_bits = vol->cluster_size_bits;
- } else {
- index_vcn_size = vol->sector_size;
- index_vcn_size_bits = vol->sector_size_bits;
- }
-
- /* Get the starting vcn of the index_block holding the child node. */
- vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
-
-descend_into_child_node:
-
- /* Read the index block starting at vcn. */
- br = ntfs_attr_mst_pread(ia_na, vcn << index_vcn_size_bits, 1,
- index_block_size, ia);
- if (br != 1) {
- if (br != -1)
- errno = EIO;
- ntfs_log_perror("Failed to read vcn 0x%llx",
- (unsigned long long)vcn);
- goto close_err_out;
- }
-
- if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
- ntfs_log_debug("Actual VCN (0x%llx) of index buffer is "
- "different from expected VCN (0x%llx).\n",
- (long long)sle64_to_cpu(ia->index_block_vcn),
- (long long)vcn);
- errno = EIO;
- goto close_err_out;
- }
- if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
- ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode "
- "0x%llx has a size (%u) differing from the "
- "directory specified size (%u).\n",
- (long long)vcn, (unsigned long long)dir_ni->
- mft_no, (unsigned)le32_to_cpu(ia->index.
- allocated_size) + 0x18, (unsigned)
- index_block_size);
- errno = EIO;
- goto close_err_out;
- }
- index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
- if (index_end > (u8*)ia + index_block_size) {
- ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory "
- "inode 0x%llx exceeds maximum size.\n",
- (long long)vcn, (unsigned long long)dir_ni->
- mft_no);
- errno = EIO;
- goto close_err_out;
- }
-
- /* The first index entry. */
- ie = (INDEX_ENTRY*)((u8*)&ia->index +
- le32_to_cpu(ia->index.entries_offset));
- /*
- * Iterate similar to above big loop but applied to index buffer, thus
- * loop until we exceed valid memory (corruption case) or until we
- * reach the last entry.
- */
- for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
- /* Bounds check. */
- if ((u8*)ie < (u8*)ia || (u8*)ie +
- sizeof(INDEX_ENTRY_HEADER) > index_end ||
- (u8*)ie + le16_to_cpu(ie->key_length) >
- index_end) {
- ntfs_log_debug("Index entry out of bounds in directory "
- "inode 0x%llx.\n",
- (unsigned long long)dir_ni->mft_no);
- errno = EIO;
- goto close_err_out;
- }
- /*
- * The last entry cannot contain a name. It can however contain
- * a pointer to a child node in the B+tree so we just break out.
- */
- if (ie->flags & INDEX_ENTRY_END)
- break;
- /*
- * We perform a case sensitive comparison and if that matches
- * we are done and return the mft reference of the inode (i.e.
- * the inode number together with the sequence number for
- * consistency checking). We convert it to cpu format before
- * returning.
- */
- if (ntfs_names_are_equal(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
-found_it2:
- /*
- * We have a perfect match, so we don't need to care
- * about having matched imperfectly before.
- */
- mref = le64_to_cpu(ie->u.indexed_file);
- free(ia);
- ntfs_attr_close(ia_na);
- ntfs_attr_put_search_ctx(ctx);
- return mref;
- }
- /*
- * For a case insensitive mount, we also perform a case
- * insensitive comparison. If the comparison matches, we cache
- * the mft reference in mref. Use first case insensitive match
- * in case if no name matches case sensitive, but several names
- * matches case insensitive.
- */
- if (!mref && !NVolCaseSensitive(vol) &&
- ntfs_names_are_equal(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length,
- IGNORE_CASE, vol->upcase, vol->upcase_len))
- mref = le64_to_cpu(ie->u.indexed_file);
- /*
- * Not a perfect match, need to do full blown collation so we
- * know which way in the B+tree we have to go.
- */
- rc = ntfs_names_collate(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length, 1,
- IGNORE_CASE, vol->upcase, vol->upcase_len);
- /*
- * If uname collates before the name of the current entry, there
- * is definitely no such name in this index but we might need to
- * descend into the B+tree so we just break out of the loop.
- */
- if (rc == -1)
- break;
- /* The names are not equal, continue the search. */
- if (rc)
- continue;
- /*
- * Names match with case insensitive comparison, now try the
- * case sensitive comparison, which is required for proper
- * collation.
- */
- rc = ntfs_names_collate(uname, uname_len,
- (ntfschar*)&ie->key.file_name.file_name,
- ie->key.file_name.file_name_length, 1,
- CASE_SENSITIVE, vol->upcase, vol->upcase_len);
- if (rc == -1)
- break;
- if (rc)
- continue;
- /*
- * Perfect match, this will never happen as the
- * ntfs_are_names_equal() call will have gotten a match but we
- * still treat it correctly.
- */
- goto found_it2;
- }
- /*
- * We have finished with this index buffer without success. Check for
- * the presence of a child node.
- */
- if (ie->flags & INDEX_ENTRY_NODE) {
- if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
- ntfs_log_debug("Index entry with child node found in a "
- "leaf node in directory inode "
- "0x%llx.\n",
- (unsigned long long)dir_ni->mft_no);
- errno = EIO;
- goto close_err_out;
- }
- /* Child node present, descend into it. */
- vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
- if (vcn >= 0)
- goto descend_into_child_node;
- ntfs_log_debug("Negative child node vcn in directory inode "
- "0x%llx.\n", (unsigned long long)dir_ni->
- mft_no);
- errno = EIO;
- goto close_err_out;
- }
- free(ia);
- ntfs_attr_close(ia_na);
- ntfs_attr_put_search_ctx(ctx);
- /*
- * No child node present, return error code ENOENT, unless we have got
- * the mft reference of a matching name cached in mref in which case
- * return mref.
- */
- if (mref)
- return mref;
- ntfs_log_debug("Entry not found.\n");
- errno = ENOENT;
- return -1;
-put_err_out:
- eo = EIO;
- ntfs_log_debug("Corrupt directory. Aborting lookup.\n");
-eo_put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- errno = eo;
- return -1;
-close_err_out:
- eo = errno;
- free(ia);
- ntfs_attr_close(ia_na);
- goto eo_put_err_out;
-}
-
-/**
- * ntfs_pathname_to_inode_num - find the inode number which represents the
- * given pathname
- * @vol: An ntfs volume obtained from ntfs_mount
- * @parent: A directory inode to begin the search (may be NULL)
- * @pathname: Pathname to be located
- *
- * Take an ASCII pathname and find the inode that represents it. The function
- * splits the path and then descends the directory tree. If @parent is NULL,
- * then the root directory '.' will be used as the base for the search.
- *
- * Return: -1 Error, the pathname was invalid, or some other error occurred
- * else Success, the pathname was valid
- */
-u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent,
- const char *pathname)
-{
- u64 inum, result;
- int len, err = 0;
- char *p, *q;
- ntfs_inode *ni = NULL;
- ntfschar *unicode = NULL;
- char *ascii = NULL;
-
- inum = result = (u64)-1;
- if (!vol || !pathname) {
- err = EINVAL;
- goto close;
- }
- ntfs_log_trace("Path: '%s'\n", pathname);
- if (parent) {
- ni = parent;
- } else
- inum = FILE_root;
- unicode = calloc(1, MAX_PATH);
- ascii = strdup(pathname);
- if (!unicode || !ascii) {
- ntfs_log_error("Out of memory.\n");
- err = ENOMEM;
- goto close;
- }
- p = ascii;
- /* Remove leading /'s. */
- while (p && *p == PATH_SEP)
- p++;
- while (p && *p) {
- if (!ni) {
- ni = ntfs_inode_open(vol, inum);
- if (!ni) {
- ntfs_log_debug("Cannot open inode %llu.\n",
- (unsigned long long)inum);
- err = EIO;
- goto close;
- }
- }
- /* Find the end of the first token. */
- q = strchr(p, PATH_SEP);
- if (q != NULL) {
- *q = 0;
- q++;
- }
- len = ntfs_mbstoucs(p, &unicode, MAX_PATH);
- if (len < 0) {
- ntfs_log_debug("Couldn't convert name to Unicode: "
- "%s.\n", p);
- err = EILSEQ;
- goto close;
- }
- inum = ntfs_inode_lookup_by_name(ni, unicode, len);
- if (inum == (u64)-1) {
- ntfs_log_debug("Couldn't find name '%s' in pathname "
- "'%s'.\n", p, pathname);
- err = ENOENT;
- goto close;
- }
- inum = MREF(inum);
- if (ni != parent)
- ntfs_inode_close(ni);
- ni = NULL;
- p = q;
- while (p && *p == PATH_SEP)
- p++;
- }
- result = inum;
-close:
- if (ni && (ni != parent))
- ntfs_inode_close(ni);
- free(ascii);
- free(unicode);
- if (err)
- errno = err;
- return result;
-}
-
-/**
- * ntfs_pathname_to_inode - Find the inode which represents the given pathname
- * @vol: An ntfs volume obtained from ntfs_mount
- * @parent: A directory inode to begin the search (may be NULL)
- * @pathname: Pathname to be located
- *
- * Take an ASCII pathname and find the inode that represents it. The function
- * splits the path and then descends the directory tree. If @parent is NULL,
- * then the root directory '.' will be used as the base for the search.
- *
- * Return: inode Success, the pathname was valid
- * NULL Error, the pathname was invalid, or some other error occurred
- */
-ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
- const char *pathname)
-{
- u64 inum;
-
- inum = ntfs_pathname_to_inode_num(vol, parent, pathname);
- if (inum == (u64)-1)
- return NULL;
- return ntfs_inode_open(vol, inum);
-}
-
-/*
- * The little endian Unicode string ".." for ntfs_readdir().
- */
-static const ntfschar dotdot[3] = { const_cpu_to_le16('.'),
- const_cpu_to_le16('.'),
- const_cpu_to_le16('\0') };
-
-/**
- * ntfs_filldir - ntfs specific filldir method
- * @vol: ntfs volume with wjich we are working
- * @pos: current position in directory
- * @ie: current index entry
- * @dirent: context for filldir callback supplied by the caller
- * @filldir: filldir callback supplied by the caller
- *
- * Pass information specifying the current directory entry @ie to the @filldir
- * callback.
- */
-static int ntfs_filldir(ntfs_volume *vol, s64 *pos, INDEX_ENTRY *ie,
- void *dirent, ntfs_filldir_t filldir)
-{
- FILE_NAME_ATTR *fn = &ie->key.file_name;
- unsigned dt_type;
-
- ntfs_log_trace("Entering.\n");
-
- /* Skip root directory self reference entry. */
- if (MREF_LE(ie->u.indexed_file) == FILE_root)
- return 0;
- if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT)
- dt_type = NTFS_DT_DIR;
- else {
- if (NVolInterix(vol) && fn->file_attributes & FILE_ATTR_SYSTEM)
- dt_type = NTFS_DT_UNKNOWN;
- else
- dt_type = NTFS_DT_REG;
- }
- return filldir(dirent, fn->file_name, fn->file_name_length,
- fn->file_name_type, *pos,
- le64_to_cpu(ie->u.indexed_file), dt_type);
-}
-
-/**
- * ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode
- * @ni: ntfs inode whose parent directory to find
- *
- * Find the parent directory of the ntfs inode @ni. To do this, find the first
- * file name attribute in the mft record of @ni and return the parent mft
- * reference from that.
- *
- * Note this only makes sense for directories, since files can be hard linked
- * from multiple directories and there is no way for us to tell which one is
- * being looked for.
- *
- * Technically directories can have hard links, too, but we consider that as
- * illegal as Linux/UNIX do not support directory hard links.
- *
- * Return the mft reference of the parent directory on success or -1 on error
- * with errno set to the error code.
- */
-static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
-{
- MFT_REF mref;
- ntfs_attr_search_ctx *ctx;
- FILE_NAME_ATTR *fn;
- int eo;
-
- ntfs_log_trace("Entering.\n");
-
- if (!ni) {
- errno = EINVAL;
- return ERR_MREF(-1);
- }
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- return ERR_MREF(-1);
- if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
- ntfs_log_debug("No file name found in inode 0x%llx. Corrupt "
- "inode.\n", (unsigned long long)ni->mft_no);
- goto err_out;
- }
- if (ctx->attr->non_resident) {
- ntfs_log_debug("File name attribute must be resident. "
- "Corrupt inode 0x%llx.\n",
- (unsigned long long)ni->mft_no);
- goto io_err_out;
- }
- fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- if ((u8*)fn + le32_to_cpu(ctx->attr->u.res.value_length) >
- (u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) {
- ntfs_log_debug("Corrupt file name attribute in inode 0x%llx.\n",
- (unsigned long long)ni->mft_no);
- goto io_err_out;
- }
- mref = le64_to_cpu(fn->parent_directory);
- ntfs_attr_put_search_ctx(ctx);
- return mref;
-io_err_out:
- errno = EIO;
-err_out:
- eo = errno;
- ntfs_attr_put_search_ctx(ctx);
- errno = eo;
- return ERR_MREF(-1);
-}
-
-/**
- * ntfs_readdir - read the contents of an ntfs directory
- * @dir_ni: ntfs inode of current directory
- * @pos: current position in directory
- * @dirent: context for filldir callback supplied by the caller
- * @filldir: filldir callback supplied by the caller
- *
- * Parse the index root and the index blocks that are marked in use in the
- * index bitmap and hand each found directory entry to the @filldir callback
- * supplied by the caller.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- *
- * Note: Index blocks are parsed in ascending vcn order, from which follows
- * that the directory entries are not returned sorted.
- */
-int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
- void *dirent, ntfs_filldir_t filldir)
-{
- s64 i_size, br, ia_pos, bmp_pos, ia_start;
- ntfs_volume *vol;
- ntfs_attr *ia_na, *bmp_na = NULL;
- ntfs_attr_search_ctx *ctx = NULL;
- u8 *index_end, *bmp = NULL;
- INDEX_ROOT *ir;
- INDEX_ENTRY *ie;
- INDEX_ALLOCATION *ia = NULL;
- int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo;
- u32 index_block_size, index_vcn_size;
- u8 index_block_size_bits, index_vcn_size_bits;
-
- ntfs_log_trace("Entering.\n");
-
- if (!dir_ni || !pos || !filldir) {
- errno = EINVAL;
- return -1;
- }
-
- if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
- errno = ENOTDIR;
- return -1;
- }
-
- vol = dir_ni->vol;
-
- ntfs_log_trace("Entering for inode 0x%llx, *pos 0x%llx.\n",
- (unsigned long long)dir_ni->mft_no, (long long)*pos);
-
- /* Open the index allocation attribute. */
- ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
- if (!ia_na) {
- if (errno != ENOENT) {
- ntfs_log_perror("Failed to open index allocation "
- "attribute. Directory inode 0x%llx is "
- "corrupt or bug", (unsigned long long)
- dir_ni->mft_no);
- return -1;
- }
- i_size = 0;
- } else
- i_size = ia_na->data_size;
-
- rc = 0;
-
- /* Are we at end of dir yet? */
- if (*pos >= i_size + vol->mft_record_size)
- goto done;
-
- /* Emulate . and .. for all directories. */
- if (!*pos) {
- rc = filldir(dirent, dotdot, 1, FILE_NAME_POSIX, *pos,
- MK_MREF(dir_ni->mft_no,
- le16_to_cpu(dir_ni->mrec->sequence_number)),
- NTFS_DT_DIR);
- if (rc)
- goto err_out;
- ++*pos;
- }
- if (*pos == 1) {
- MFT_REF parent_mref;
-
- parent_mref = ntfs_mft_get_parent_ref(dir_ni);
- if (parent_mref == ERR_MREF(-1)) {
- ntfs_log_perror("Parent directory not found");
- goto dir_err_out;
- }
-
- rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos,
- parent_mref, NTFS_DT_DIR);
- if (rc)
- goto err_out;
- ++*pos;
- }
-
- ctx = ntfs_attr_get_search_ctx(dir_ni, NULL);
- if (!ctx)
- goto err_out;
-
- /* Get the offset into the index root attribute. */
- ir_pos = (int)*pos;
- /* Find the index root attribute in the mft record. */
- if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- ntfs_log_debug("Index root attribute missing in directory "
- "inode 0x%llx.\n", (unsigned long long)dir_ni->
- mft_no);
- goto dir_err_out;
- }
- /* Get to the index root value. */
- ir = (INDEX_ROOT*)((u8*)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
-
- /* Determine the size of a vcn in the directory index. */
- index_block_size = le32_to_cpu(ir->index_block_size);
- if (index_block_size < NTFS_BLOCK_SIZE ||
- index_block_size & (index_block_size - 1)) {
- ntfs_log_debug("Index block size %u is invalid.\n",
- (unsigned)index_block_size);
- goto dir_err_out;
- }
- index_block_size_bits = ffs(index_block_size) - 1;
- if (vol->cluster_size <= index_block_size) {
- index_vcn_size = vol->cluster_size;
- index_vcn_size_bits = vol->cluster_size_bits;
- } else {
- index_vcn_size = vol->sector_size;
- index_vcn_size_bits = vol->sector_size_bits;
- }
-
- /* Are we jumping straight into the index allocation attribute? */
- if (*pos >= vol->mft_record_size) {
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
- goto skip_index_root;
- }
-
- index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
- /* The first index entry. */
- ie = (INDEX_ENTRY*)((u8*)&ir->index +
- le32_to_cpu(ir->index.entries_offset));
- /*
- * Loop until we exceed valid memory (corruption case) or until we
- * reach the last entry or until filldir tells us it has had enough
- * or signals an error (both covered by the rc test).
- */
- for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
- ntfs_log_debug("In index root, offset 0x%x.\n",
- (u8*)ie - (u8*)ir);
- /* Bounds checks. */
- if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
- sizeof(INDEX_ENTRY_HEADER) > index_end ||
- (u8*)ie + le16_to_cpu(ie->key_length) >
- index_end)
- goto dir_err_out;
- /* The last entry cannot contain a name. */
- if (ie->flags & INDEX_ENTRY_END)
- break;
- /* Skip index root entry if continuing previous readdir. */
- if (ir_pos > (u8*)ie - (u8*)ir)
- continue;
- /* Advance the position even if going to skip the entry. */
- *pos = (u8*)ie - (u8*)ir;
- /*
- * Submit the directory entry to ntfs_filldir(), which will
- * invoke the filldir() callback as appropriate.
- */
- rc = ntfs_filldir(vol, pos, ie, dirent, filldir);
- if (rc)
- goto err_out;
- }
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
-
- /* If there is no index allocation attribute we are finished. */
- if (!ia_na)
- goto EOD;
-
- /* Advance *pos to the beginning of the index allocation. */
- *pos = vol->mft_record_size;
-
-skip_index_root:
-
- if (!ia_na)
- goto done;
-
- /* Allocate a buffer for the current index block. */
- ia = (INDEX_ALLOCATION*)malloc(index_block_size);
- if (!ia) {
- ntfs_log_perror("Failed to allocate buffer for index block");
- goto err_out;
- }
-
- bmp_na = ntfs_attr_open(dir_ni, AT_BITMAP, NTFS_INDEX_I30, 4);
- if (!bmp_na) {
- ntfs_log_perror("Failed to open index bitmap attribute");
- goto dir_err_out;
- }
-
- /* Get the offset into the index allocation attribute. */
- ia_pos = *pos - vol->mft_record_size;
-
- bmp_pos = ia_pos >> index_block_size_bits;
- if (bmp_pos >> 3 >= bmp_na->data_size) {
- ntfs_log_debug("Current index position exceeds index bitmap "
- "size.\n");
- goto dir_err_out;
- }
-
- bmp_buf_size = min(bmp_na->data_size - (bmp_pos >> 3), 4096);
- bmp = (u8*)malloc(bmp_buf_size);
- if (!bmp) {
- ntfs_log_perror("Failed to allocate bitmap buffer");
- goto err_out;
- }
-
- br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp);
- if (br != bmp_buf_size) {
- if (br != -1)
- errno = EIO;
- ntfs_log_perror("Failed to read from index bitmap attribute");
- goto err_out;
- }
-
- bmp_buf_pos = 0;
- /* If the index block is not in use find the next one that is. */
- while (!(bmp[bmp_buf_pos >> 3] & (1 << (bmp_buf_pos & 7)))) {
-find_next_index_buffer:
- bmp_pos++;
- bmp_buf_pos++;
- /* If we have reached the end of the bitmap, we are done. */
- if (bmp_pos >> 3 >= bmp_na->data_size)
- goto EOD;
- ia_pos = bmp_pos << index_block_size_bits;
- if (bmp_buf_pos >> 3 < bmp_buf_size)
- continue;
- /* Read next chunk from the index bitmap. */
- if ((bmp_pos >> 3) + bmp_buf_size > bmp_na->data_size)
- bmp_buf_size = bmp_na->data_size - (bmp_pos >> 3);
- br = ntfs_attr_pread(bmp_na, bmp_pos >> 3, bmp_buf_size, bmp);
- if (br != bmp_buf_size) {
- if (br != -1)
- errno = EIO;
- ntfs_log_perror("Failed to read from index bitmap "
- "attribute");
- goto err_out;
- }
- }
-
- ntfs_log_debug("Handling index block 0x%llx.\n", (long long)bmp_pos);
-
- /* Read the index block starting at bmp_pos. */
- br = ntfs_attr_mst_pread(ia_na, bmp_pos << index_block_size_bits, 1,
- index_block_size, ia);
- if (br != 1) {
- if (br != -1)
- errno = EIO;
- ntfs_log_perror("Failed to read index block");
- goto err_out;
- }
-
- ia_start = ia_pos & ~(s64)(index_block_size - 1);
- if (sle64_to_cpu(ia->index_block_vcn) != ia_start >>
- index_vcn_size_bits) {
- ntfs_log_debug("Actual VCN (0x%llx) of index buffer is "
- "different from expected VCN (0x%llx) in "
- "inode 0x%llx.\n",
- (long long)sle64_to_cpu(ia->index_block_vcn),
- (long long)ia_start >> index_vcn_size_bits,
- (unsigned long long)dir_ni->mft_no);
- goto dir_err_out;
- }
- if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {
- ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode "
- "0x%llx has a size (%u) differing from the "
- "directory specified size (%u).\n",
- (long long)ia_start >> index_vcn_size_bits,
- (unsigned long long)dir_ni->mft_no,
- (unsigned) le32_to_cpu(ia->index.allocated_size)
- + 0x18, (unsigned)index_block_size);
- goto dir_err_out;
- }
- index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
- if (index_end > (u8*)ia + index_block_size) {
- ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory "
- "inode 0x%llx exceeds maximum size.\n",
- (long long)ia_start >> index_vcn_size_bits,
- (unsigned long long)dir_ni->mft_no);
- goto dir_err_out;
- }
- /* The first index entry. */
- ie = (INDEX_ENTRY*)((u8*)&ia->index +
- le32_to_cpu(ia->index.entries_offset));
- /*
- * Loop until we exceed valid memory (corruption case) or until we
- * reach the last entry or until ntfs_filldir tells us it has had
- * enough or signals an error (both covered by the rc test).
- */
- for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
- ntfs_log_debug("In index allocation, offset 0x%llx.\n",
- (long long)ia_start + ((u8*)ie - (u8*)ia));
- /* Bounds checks. */
- if ((u8*)ie < (u8*)ia || (u8*)ie +
- sizeof(INDEX_ENTRY_HEADER) > index_end ||
- (u8*)ie + le16_to_cpu(ie->key_length) >
- index_end) {
- ntfs_log_debug("Index entry out of bounds in directory "
- "inode 0x%llx.\n", (unsigned long long)
- dir_ni->mft_no);
- goto dir_err_out;
- }
- /* The last entry cannot contain a name. */
- if (ie->flags & INDEX_ENTRY_END)
- break;
- /* Skip index entry if continuing previous readdir. */
- if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
- continue;
- /* Advance the position even if going to skip the entry. */
- *pos = (u8*)ie - (u8*)ia + (sle64_to_cpu(
- ia->index_block_vcn) << index_vcn_size_bits) +
- dir_ni->vol->mft_record_size;
- /*
- * Submit the directory entry to ntfs_filldir(), which will
- * invoke the filldir() callback as appropriate.
- */
- rc = ntfs_filldir(vol, pos, ie, dirent, filldir);
- if (rc)
- goto err_out;
- }
- goto find_next_index_buffer;
-EOD:
- /* We are finished, set *pos to EOD. */
- *pos = i_size + vol->mft_record_size;
-done:
- free(ia);
- free(bmp);
- if (bmp_na)
- ntfs_attr_close(bmp_na);
- if (ia_na)
- ntfs_attr_close(ia_na);
- ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos);
- return 0;
-dir_err_out:
- errno = EIO;
-err_out:
- eo = errno;
- if (rc)
- ntfs_log_trace("filldir returned %i, *pos 0x%llx.", rc,
- (long long)*pos);
- ntfs_log_trace("Failed.\n");
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- free(ia);
- free(bmp);
- if (bmp_na)
- ntfs_attr_close(bmp_na);
- if (ia_na)
- ntfs_attr_close(ia_na);
- errno = eo;
- return -1;
-}
-
-/**
- * __ntfs_create - create object on ntfs volume
- * @dir_ni: ntfs inode for directory in which create new object
- * @name: unicode name of new object
- * @name_len: length of the name in unicode characters
- * @type: type of the object to create
- * @dev: major and minor device numbers (obtained from makedev())
- * @target: target in unicode (only for symlinks)
- * @target_len: length of target in unicode characters
- *
- * Internal, use ntfs_create{,_device,_symlink} wrappers instead.
- *
- * @type can be:
- * S_IFREG to create regular file
- * S_IFDIR to create directory
- * S_IFBLK to create block device
- * S_IFCHR to create character device
- * S_IFLNK to create symbolic link
- * S_IFIFO to create FIFO
- * S_IFSOCK to create socket
- * other values are invalid.
- *
- * @dev is used only if @type is S_IFBLK or S_IFCHR, in other cases its value
- * ignored.
- *
- * @target and @target_len are used only if @type is S_IFLNK, in other cases
- * their value ignored.
- *
- * Return opened ntfs inode that describes created object on success or NULL
- * on error with errno set to the error code.
- */
-static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
- ntfschar *name, u8 name_len, dev_t type, dev_t dev,
- ntfschar *target, u8 target_len)
-{
- ntfs_inode *ni;
- int rollback_data = 0, rollback_sd = 0;
- FILE_NAME_ATTR *fn = NULL;
- STANDARD_INFORMATION *si = NULL;
- SECURITY_DESCRIPTOR_ATTR *sd = NULL;
- ACL *acl;
- ACCESS_ALLOWED_ACE *ace;
- SID *sid;
- int err, fn_len, si_len, sd_len;
-
- ntfs_log_trace("Entering.\n");
-
- /* Sanity checks. */
- if (!dir_ni || !name || !name_len) {
- ntfs_log_error("Invalid arguments.\n");
- errno = EINVAL;
- return NULL;
- }
- /* FIXME: Reparse points requires special handling. */
- if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
- errno = EOPNOTSUPP;
- return NULL;
- }
- /* Allocate MFT record for new file. */
- ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
- if (!ni) {
- ntfs_log_error("Failed to allocate new MFT record: %s.\n",
- strerror(errno));
- return NULL;
- }
- /*
- * Create STANDARD_INFORMATION attribute. Write STANDARD_INFORMATION
- * version 1.2, windows will upgrade it to version 3 if needed.
- */
- si_len = offsetof(STANDARD_INFORMATION, u.v12.v1_end);
- si = calloc(1, si_len);
- if (!si) {
- err = errno;
- ntfs_log_error("Not enough memory.\n");
- goto err_out;
- }
- si->creation_time = utc2ntfs(ni->creation_time);
- si->last_data_change_time = utc2ntfs(ni->last_data_change_time);
- si->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
- si->last_access_time = utc2ntfs(ni->last_access_time);
- if (!S_ISREG(type) && !S_ISDIR(type)) {
- si->file_attributes = FILE_ATTR_SYSTEM;
- ni->flags = FILE_ATTR_SYSTEM;
- }
- /* Add STANDARD_INFORMATION to inode. */
- if (ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0,
- (u8*)si, si_len)) {
- err = errno;
- ntfs_log_error("Failed to add STANDARD_INFORMATION "
- "attribute.\n");
- goto err_out;
- }
- /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
- /*
- * Calculate security descriptor length. We have 2 sub-authorities in
- * owner and group SIDs, but structure SID contain only one, so add
- * 4 bytes to every SID.
- */
- sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
- sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
- sd = calloc(1, sd_len);
- if (!sd) {
- err = errno;
- ntfs_log_error("Not enough memory.\n");
- goto err_out;
- }
- sd->revision = 1;
- sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
- sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
- sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
- sid->revision = 1;
- sid->sub_authority_count = 2;
- sid->sub_authority[0] = cpu_to_le32(32);
- sid->sub_authority[1] = cpu_to_le32(544);
- sid->identifier_authority.value[5] = 5;
- sid = (SID*)((u8*)sid + sizeof(SID) + 4);
- sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
- sid->revision = 1;
- sid->sub_authority_count = 2;
- sid->sub_authority[0] = cpu_to_le32(32);
- sid->sub_authority[1] = cpu_to_le32(544);
- sid->identifier_authority.value[5] = 5;
- acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
- sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
- acl->revision = 2;
- acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
- acl->ace_count = cpu_to_le16(1);
- ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
- ace->type = ACCESS_ALLOWED_ACE_TYPE;
- ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
- ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
- ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
- ace->sid.revision = 1;
- ace->sid.sub_authority_count = 1;
- ace->sid.sub_authority[0] = 0;
- ace->sid.identifier_authority.value[5] = 1;
- /* Add SECURITY_DESCRIPTOR attribute to inode. */
- if (ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0,
- (u8*)sd, sd_len)) {
- err = errno;
- ntfs_log_error("Failed to add SECURITY_DESCRIPTOR "
- "attribute.\n");
- goto err_out;
- }
- rollback_sd = 1;
- /* Add DATA/INDEX_ROOT attribute. */
- if (S_ISDIR(type)) {
- INDEX_ROOT *ir = NULL;
- INDEX_ENTRY *ie;
- int ir_len, index_len;
-
- /* Create INDEX_ROOT attribute. */
- index_len = sizeof(INDEX_HEADER) + sizeof(INDEX_ENTRY_HEADER);
- ir_len = offsetof(INDEX_ROOT, index) + index_len;
- ir = calloc(1, ir_len);
- if (!ir) {
- err = errno;
- ntfs_log_error("Not enough memory.\n");
- goto err_out;
- }
- ir->type = AT_FILE_NAME;
- ir->collation_rule = COLLATION_FILE_NAME;
- ir->index_block_size = cpu_to_le32(ni->vol->indx_record_size);
- if (ni->vol->cluster_size <= ni->vol->indx_record_size)
- ir->clusters_per_index_block =
- ni->vol->indx_record_size >>
- ni->vol->cluster_size_bits;
- else
- ir->clusters_per_index_block =
- ni->vol->indx_record_size >>
- ni->vol->sector_size_bits;
- ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER));
- ir->index.index_length = cpu_to_le32(index_len);
- ir->index.allocated_size = cpu_to_le32(index_len);
- ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT));
- ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER));
- ie->key_length = 0;
- ie->flags = INDEX_ENTRY_END;
- /* Add INDEX_ROOT attribute to inode. */
- if (ntfs_attr_add(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4,
- (u8*)ir, ir_len)) {
- err = errno;
- free(ir);
- ntfs_log_error("Failed to add INDEX_ROOT attribute.\n");
- goto err_out;
- }
- free(ir);
- } else {
- INTX_FILE *data;
- int data_len;
-
- switch (type) {
- case S_IFBLK:
- case S_IFCHR:
- data_len = offsetof(INTX_FILE, u.s.device_end);
- data = ntfs_malloc(data_len);
- if (!data) {
- err = errno;
- goto err_out;
- }
- data->u.s.major = cpu_to_le64(major(dev));
- data->u.s.minor = cpu_to_le64(minor(dev));
- if (type == S_IFBLK)
- data->magic = INTX_BLOCK_DEVICE;
- if (type == S_IFCHR)
- data->magic = INTX_CHARACTER_DEVICE;
- break;
- case S_IFLNK:
- data_len = sizeof(INTX_FILE_TYPES) +
- target_len * sizeof(ntfschar);
- data = ntfs_malloc(data_len);
- if (!data) {
- err = errno;
- goto err_out;
- }
- data->magic = INTX_SYMBOLIC_LINK;
- memcpy(data->u.target, target,
- target_len * sizeof(ntfschar));
- break;
- case S_IFSOCK:
- data = NULL;
- data_len = 1;
- break;
- default: /* FIFO or regular file. */
- data = NULL;
- data_len = 0;
- break;
- }
- /* Add DATA attribute to inode. */
- if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, (u8*)data,
- data_len)) {
- err = errno;
- free(data);
- ntfs_log_error("Failed to add DATA attribute.\n");
- goto err_out;
- }
- rollback_data = 1;
- free(data);
- }
- /* Create FILE_NAME attribute. */
- fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
- fn = ntfs_calloc(fn_len);
- if (!fn) {
- err = errno;
- goto err_out;
- }
- fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
- le16_to_cpu(dir_ni->mrec->sequence_number));
- fn->file_name_length = name_len;
- fn->file_name_type = FILE_NAME_POSIX;
- if (S_ISDIR(type))
- fn->file_attributes = FILE_ATTR_I30_INDEX_PRESENT;
- if (!S_ISREG(type) && !S_ISDIR(type))
- fn->file_attributes = FILE_ATTR_SYSTEM;
- fn->creation_time = utc2ntfs(ni->creation_time);
- fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
- fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
- fn->last_access_time = utc2ntfs(ni->last_access_time);
- memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
- /* Add FILE_NAME attribute to inode. */
- if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
- err = errno;
- ntfs_log_error("Failed to add FILE_NAME attribute.\n");
- goto err_out;
- }
- /* Add FILE_NAME attribute to index. */
- if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
- le16_to_cpu(ni->mrec->sequence_number)))) {
- err = errno;
- ntfs_log_perror("Failed to add entry to the index");
- goto err_out;
- }
- /* Set hard links count and directory flag. */
- ni->mrec->link_count = cpu_to_le16(1);
- if (S_ISDIR(type))
- ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY;
- ntfs_inode_mark_dirty(ni);
- /* Done! */
- free(fn);
- free(si);
- free(sd);
- ntfs_log_trace("Done.\n");
- return ni;
-err_out:
- ntfs_log_trace("Failed.\n");
- if (rollback_sd) {
- ntfs_attr *na;
-
- na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
- if (!na)
- ntfs_log_perror("Failed to open SD (0x50) attribute of "
- " inode 0x%llx. Run chkdsk.\n",
- (unsigned long long)ni->mft_no);
- else if (ntfs_attr_rm(na))
- ntfs_log_perror("Failed to remove SD (0x50) attribute "
- "of inode 0x%llx. Run chkdsk.\n",
- (unsigned long long)ni->mft_no);
- }
- if (rollback_data) {
- ntfs_attr *na;
-
- na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
- if (!na)
- ntfs_log_perror("Failed to open data attribute of "
- " inode 0x%llx. Run chkdsk.\n",
- (unsigned long long)ni->mft_no);
- else if (ntfs_attr_rm(na))
- ntfs_log_perror("Failed to remove data attribute of "
- "inode 0x%llx. Run chkdsk.\n",
- (unsigned long long)ni->mft_no);
- }
- /*
- * Free extent MFT records (should not exist any with current
- * ntfs_create implementation, but for any case if something will be
- * changed in the future).
- */
- while (ni->nr_extents)
- if (ntfs_mft_record_free(ni->vol, *(ni->u.extent_nis))) {
- err = errno;
- ntfs_log_error("Failed to free extent MFT record. "
- "Leaving inconsistent metadata.\n");
- }
- if (ntfs_mft_record_free(ni->vol, ni))
- ntfs_log_error("Failed to free MFT record. "
- "Leaving inconsistent metadata. Run chkdsk.\n");
- free(fn);
- free(si);
- free(sd);
- errno = err;
- return NULL;
-}
-
-/**
- * Some wrappers around __ntfs_create() ...
- */
-
-ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
- dev_t type)
-{
- if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO &&
- type != S_IFSOCK) {
- ntfs_log_error("Invalid arguments.\n");
- return NULL;
- }
- return __ntfs_create(dir_ni, name, name_len, type, 0, NULL, 0);
-}
-
-ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
- dev_t type, dev_t dev)
-{
- if (type != S_IFCHR && type != S_IFBLK) {
- ntfs_log_error("Invalid arguments.\n");
- return NULL;
- }
- return __ntfs_create(dir_ni, name, name_len, type, dev, NULL, 0);
-}
-
-ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
- ntfschar *target, u8 target_len)
-{
- if (!target || !target_len) {
- ntfs_log_error("Invalid arguments.\n");
- return NULL;
- }
- return __ntfs_create(dir_ni, name, name_len, S_IFLNK, 0,
- target, target_len);
-}
-
-/**
- * ntfs_delete - delete file or directory from ntfs volume
- * @pni: ntfs inode for object to delete
- * @dir_ni: ntfs inode for directory in which delete object
- * @name: unicode name of the object to delete
- * @name_len: length of the name in unicode characters
- *
- * @pni is pointer to pointer to ntfs_inode structure. Upon successful
- * completion and if inode is really deleted (there are no more links left to
- * it) this function will close @*pni and set it to NULL, in the other cases
- * @*pni will stay opened.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name,
- u8 name_len)
-{
- ntfs_attr_search_ctx *actx = NULL;
- ntfs_index_context *ictx = NULL;
- ntfs_inode *ni;
- FILE_NAME_ATTR *fn = NULL;
- BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
- BOOL case_sensitive_match = TRUE;
- int err = 0;
-
- ntfs_log_trace("Entering.\n");
-
- if (!pni || !(ni = *pni) || !dir_ni || !name || !name_len ||
- ni->nr_extents == -1 || dir_ni->nr_extents == -1) {
- ntfs_log_error("Invalid arguments.\n");
- errno = EINVAL;
- goto err_out;
- }
- if (ni->nr_references > 1 && le16_to_cpu(ni->mrec->link_count) == 1) {
- ntfs_log_error("Trying to deleting inode with left "
- "references.\n");
- errno = EINVAL;
- goto err_out;
- }
- /*
- * Search for FILE_NAME attribute with such name. If it's in POSIX or
- * WIN32_AND_DOS namespace, then simply remove it from index and inode.
- * If filename in DOS or in WIN32 namespace, then remove DOS name first,
- * only then remove WIN32 name. Mark WIN32 name as POSIX name to prevent
- * chkdsk to complain about DOS name absence in case if DOS name had
- * been successfully deleted, but WIN32 name remove failed.
- */
- actx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!actx)
- goto err_out;
-search:
- while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
- 0, NULL, 0, actx)) {
- errno = 0;
- fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
- le16_to_cpu(actx->attr->u.res.value_offset));
- ntfs_log_trace("Found filename with instance number %d.\n",
- le16_to_cpu(actx->attr->instance));
- if (looking_for_dos_name) {
- if (fn->file_name_type == FILE_NAME_DOS)
- break;
- else
- continue;
- }
- if (looking_for_win32_name) {
- if (fn->file_name_type == FILE_NAME_WIN32)
- break;
- else
- continue;
- }
- if (dir_ni->mft_no == MREF_LE(fn->parent_directory) &&
- ntfs_names_are_equal(fn->file_name,
- fn->file_name_length, name,
- name_len, case_sensitive_match ?
- CASE_SENSITIVE : IGNORE_CASE, ni->vol->upcase,
- ni->vol->upcase_len)) {
- if (fn->file_name_type == FILE_NAME_WIN32) {
- looking_for_dos_name = TRUE;
- ntfs_attr_reinit_search_ctx(actx);
- ntfs_log_trace("Restart search. "
- "Looking for DOS name.\n");
- continue;
- }
- if (fn->file_name_type == FILE_NAME_DOS)
- looking_for_dos_name = TRUE;
- break;
- }
- }
- if (errno) {
- /*
- * If case sensitive search failed and volume mounted case
- * insensitive, then try once again ignoring case.
- */
- if (errno == ENOENT && !NVolCaseSensitive(ni->vol) &&
- case_sensitive_match) {
- case_sensitive_match = FALSE;
- ntfs_attr_reinit_search_ctx(actx);
- ntfs_log_trace("Restart search. Ignore case.");
- goto search;
- }
- ntfs_log_error("Failed to find requested filename in FILE_NAME "
- "attributes that belong to this inode.\n");
- goto err_out;
- }
- /* If deleting directory check it to be empty. */
- if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
- ntfs_attr *na;
-
- na = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4);
- if (!na) {
- ntfs_log_error("Corrupt directory or library bug.\n");
- errno = EIO;
- goto err_out;
- }
- /*
- * Do not allow non-empty directory deletion if hard links count
- * is 1 (always) or 2 (in case if filename in DOS namespace,
- * because we delete it first in file which have both WIN32 and
- * DOS names).
- */
- if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(
- INDEX_ENTRY_HEADER)) && (le16_to_cpu(
- ni->mrec->link_count) == 1 ||
- (le16_to_cpu(ni->mrec->link_count) == 2 &&
- fn->file_name_type == FILE_NAME_DOS))) {
- ntfs_attr_close(na);
- ntfs_log_error("Directory is not empty.\n");
- errno = ENOTEMPTY;
- goto err_out;
- }
- ntfs_attr_close(na);
- }
- /* One more sanity check. */
- if (ni->nr_references > 1 && looking_for_dos_name &&
- le16_to_cpu(ni->mrec->link_count) == 2) {
- ntfs_log_error("Trying to deleting inode with left "
- "references.\n");
- errno = EINVAL;
- goto err_out;
- }
- ntfs_log_trace("Found!\n");
- /* Search for such FILE_NAME in index. */
- ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4);
- if (!ictx)
- goto err_out;
- if (ntfs_index_lookup(fn, le32_to_cpu(actx->attr->u.res.value_length), ictx))
- goto err_out;
- /* Set namespace to POSIX for WIN32 name. */
- if (fn->file_name_type == FILE_NAME_WIN32) {
- fn->file_name_type = FILE_NAME_POSIX;
- ntfs_inode_mark_dirty(actx->ntfs_ino);
- ((FILE_NAME_ATTR*)ictx->data)->file_name_type = FILE_NAME_POSIX;
- ntfs_index_entry_mark_dirty(ictx);
- }
- /* Do not support reparse point deletion yet. */
- if (((FILE_NAME_ATTR*)ictx->data)->file_attributes &
- FILE_ATTR_REPARSE_POINT) {
- errno = EOPNOTSUPP;
- goto err_out;
- }
- /* Remove FILE_NAME from index. */
- if (ntfs_index_rm(ictx))
- goto err_out;
-
- /* Remove FILE_NAME from inode. */
- if (ntfs_attr_record_rm(actx))
- goto err_out;
- /* Decrement hard link count. */
- ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
- ni->mrec->link_count) - 1);
- ntfs_inode_mark_dirty(ni);
- if (looking_for_dos_name) {
- looking_for_dos_name = FALSE;
- looking_for_win32_name = TRUE;
- ntfs_attr_reinit_search_ctx(actx);
- ntfs_log_trace("DOS name deleted. "
- "Now search for WIN32 name.\n");
- goto search;
- } else
- ntfs_log_trace("Deleted.\n");
- /* TODO: Update object id, quota and security indexes if required. */
- /*
- * If hard link count is not equal to zero then we are done. In other
- * case there are no reference to this inode left, so we should free all
- * non-resident attributes and mark all MFT record as not in use.
- */
- if (ni->mrec->link_count)
- goto out;
- ntfs_attr_reinit_search_ctx(actx);
- while (!ntfs_attrs_walk(actx)) {
- if (actx->attr->non_resident) {
- runlist *rl;
-
- rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr,
- NULL);
- if (!rl) {
- err = errno;
- ntfs_log_error("Failed to decompress runlist. "
- "Leaving inconsistent "
- "metadata.\n");
- continue;
- }
- if (ntfs_cluster_free_from_rl(ni->vol, rl)) {
- err = errno;
- ntfs_log_error("Failed to free clusters. "
- "Leaving inconsistent "
- "metadata.\n");
- continue;
- }
- free(rl);
- }
- }
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_error("Attribute enumeration failed. "
- "Probably leaving inconsistent metadata.\n");
- }
- /* All extents should be attached after attribute walk. */
- while (ni->nr_extents)
- if (ntfs_mft_record_free(ni->vol, *(ni->u.extent_nis))) {
- err = errno;
- ntfs_log_error("Failed to free extent MFT record. "
- "Leaving inconsistent metadata.\n");
- }
- if (ntfs_mft_record_free(ni->vol, ni)) {
- err = errno;
- ntfs_log_error("Failed to free base MFT record. "
- "Leaving inconsistent metadata.\n");
- }
- *pni = NULL;
-out:
- if (actx)
- ntfs_attr_put_search_ctx(actx);
- if (ictx)
- ntfs_index_ctx_put(ictx);
- if (err) {
- ntfs_log_error("%s(): Failed.\n", "ntfs_delete");
- errno = err;
- return -1;
- }
- ntfs_log_trace("Done.\n");
- return 0;
-err_out:
- err = errno;
- goto out;
-}
-
-/**
- * ntfs_link - create hard link for file or directory
- * @ni: ntfs inode for object to create hard link
- * @dir_ni: ntfs inode for directory in which new link should be placed
- * @name: unicode name of the new link
- * @name_len: length of the name in unicode characters
- *
- * NOTE: At present we allow creating hard links to directories, we use them
- * in a temporary state during rename. But it's definitely bad idea to have
- * hard links to directories as a result of operation.
- * FIXME: Create internal __ntfs_link that allows hard links to a directories
- * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
-{
- FILE_NAME_ATTR *fn = NULL;
- int fn_len, err;
-
- ntfs_log_trace("Entering.\n");
-
- if (!ni || !dir_ni || !name || !name_len ||
- ni->mft_no == dir_ni->mft_no) {
- err = EINVAL;
- ntfs_log_error("Invalid arguments.");
- goto err_out;
- }
- /* FIXME: Reparse points requires special handling. */
- if (ni->flags & FILE_ATTR_REPARSE_POINT) {
- err = EOPNOTSUPP;
- goto err_out;
- }
- /* Create FILE_NAME attribute. */
- fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
- fn = ntfs_calloc(fn_len);
- if (!fn) {
- err = errno;
- goto err_out;
- }
- fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
- le16_to_cpu(dir_ni->mrec->sequence_number));
- fn->file_name_length = name_len;
- fn->file_name_type = FILE_NAME_POSIX;
- fn->file_attributes = ni->flags;
- if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
- fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT;
- fn->allocated_size = cpu_to_sle64(ni->allocated_size);
- fn->data_size = cpu_to_sle64(ni->data_size);
- fn->creation_time = utc2ntfs(ni->creation_time);
- fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
- fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
- fn->last_access_time = utc2ntfs(ni->last_access_time);
- memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
- /* Add FILE_NAME attribute to index. */
- if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
- le16_to_cpu(ni->mrec->sequence_number)))) {
- err = errno;
- ntfs_log_error("Failed to add entry to the index.\n");
- goto err_out;
- }
- /* Add FILE_NAME attribute to inode. */
- if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
- ntfs_index_context *ictx;
-
- err = errno;
- ntfs_log_error("Failed to add FILE_NAME attribute.\n");
- /* Try to remove just added attribute from index. */
- ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4);
- if (!ictx)
- goto rollback_failed;
- if (ntfs_index_lookup(fn, fn_len, ictx)) {
- ntfs_index_ctx_put(ictx);
- goto rollback_failed;
- }
- if (ntfs_index_rm(ictx)) {
- ntfs_index_ctx_put(ictx);
- goto rollback_failed;
- }
- goto err_out;
- }
- /* Increment hard links count. */
- ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
- ni->mrec->link_count) + 1);
- /* Done! */
- ntfs_inode_mark_dirty(ni);
- free(fn);
- ntfs_log_trace("Done.\n");
- return 0;
-rollback_failed:
- ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n");
-err_out:
- ntfs_log_error("%s(): Failed.\n", "ntfs_link");
- free(fn);
- errno = err;
- return -1;
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/index.c b/usr/src/lib/libntfs/common/libntfs/index.c
deleted file mode 100644
index efa4ae5913..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/index.c
+++ /dev/null
@@ -1,1862 +0,0 @@
-/**
- * index.c - NTFS index handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004-2005 Anton Altaparmakov
- * Copyright (c) 2004-2005 Richard Russon
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- * Copyright (c) 2005-2006 Szabolcs Szakacsits
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "collate.h"
-#include "debug.h"
-#include "index.h"
-#include "mst.h"
-#include "dir.h"
-#include "logging.h"
-#include "bitmap.h"
-#include "support.h"
-
-/**
- * ntfs_index_entry_mark_dirty - mark an index entry dirty
- * @ictx: ntfs index context describing the index entry
- *
- * Mark the index entry described by the index entry context @ictx dirty.
- *
- * If the index entry is in the index root attribute, simply mark the inode
- * containing the index root attribute dirty. This ensures the mftrecord, and
- * hence the index root attribute, will be written out to disk later.
- *
- * If the index entry is in an index block belonging to the index allocation
- * attribute, set ib_dirty to TRUE, thus index block will be updated during
- * ntfs_index_ctx_put.
- */
-void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
-{
- if (ictx->is_in_root)
- ntfs_inode_mark_dirty(ictx->actx->ntfs_ino);
- else
- ictx->ib_dirty = TRUE;
-}
-
-static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn)
-{
- return vcn << icx->vcn_size_bits;
-}
-
-static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos)
-{
- return pos >> icx->vcn_size_bits;
-}
-
-static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf)
-{
- s64 ret;
-
- ntfs_log_trace("vcn: %lld\n", vcn);
-
- ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn),
- 1, icx->block_size, buf);
- if (ret != 1) {
- ntfs_log_perror("Failed to write index block %lld of inode "
- "%llu", (long long)vcn,
- (unsigned long long)icx->ni->mft_no);
- return STATUS_ERROR;
- }
- return STATUS_OK;
-}
-
-static int ntfs_icx_ib_write(ntfs_index_context *icx)
-{
- if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib))
- return STATUS_ERROR;
-
- icx->ib_dirty = FALSE;
-
- return STATUS_OK;
-}
-
-/**
- * ntfs_index_ctx_get - allocate and initialize a new index context
- * @ni: ntfs inode with which to initialize the context
- * @name: name of the which context describes
- * @name_len: length of the index name
- *
- * Allocate a new index context, initialize it with @ni and return it.
- * Return NULL if allocation failed.
- */
-ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
- ntfschar *name, u32 name_len)
-{
- ntfs_index_context *icx;
-
- ntfs_log_trace("Entering.\n");
-
- if (!ni) {
- errno = EINVAL;
- return NULL;
- }
- if (ni->nr_extents == -1)
- ni = ni->u.base_ni;
- icx = ntfs_calloc(sizeof(ntfs_index_context));
- if (icx)
- *icx = (ntfs_index_context) {
- .ni = ni,
- .name = name,
- .name_len = name_len,
- };
- return icx;
-}
-
-static void ntfs_index_ctx_free(ntfs_index_context *icx)
-{
- ntfs_log_trace("Entering.\n");
-
- if (!icx->entry)
- return;
-
- if (icx->actx)
- ntfs_attr_put_search_ctx(icx->actx);
-
- if (icx->is_in_root) {
- if (icx->ia_na)
- ntfs_attr_close(icx->ia_na);
- return;
- }
-
- if (icx->ib_dirty) {
- /* FIXME: Error handling!!! */
- ntfs_ib_write(icx, icx->ib_vcn, icx->ib);
- }
-
- free(icx->ib);
- ntfs_attr_close(icx->ia_na);
-}
-
-/**
- * ntfs_index_ctx_put - release an index context
- * @icx: index context to free
- *
- * Release the index context @icx, releasing all associated resources.
- */
-void ntfs_index_ctx_put(ntfs_index_context *icx)
-{
- ntfs_index_ctx_free(icx);
- free(icx);
-}
-
-/**
- * ntfs_index_ctx_reinit - reinitialize an index context
- * @icx: index context to reinitialize
- *
- * Reinitialize the index context @icx so it can be used for ntfs_index_lookup.
- */
-void ntfs_index_ctx_reinit(ntfs_index_context *icx)
-{
- ntfs_log_trace("Entering.\n");
-
- ntfs_index_ctx_free(icx);
-
- *icx = (ntfs_index_context) {
- .ni = icx->ni,
- .name = icx->name,
- .name_len = icx->name_len,
- };
-}
-
-static leVCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
-{
- return (leVCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN));
-}
-
-/**
- * Get the subnode vcn to which the index entry refers.
- */
-VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie)
-{
- return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie));
-}
-
-static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
-{
- return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset));
-}
-
-static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie)
-{
- return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length));
-}
-
-static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
-{
- /* FIXME: check if it isn't overflowing the index block size */
- return (u8 *)ih + le32_to_cpu(ih->index_length);
-}
-
-static int ntfs_ie_end(INDEX_ENTRY *ie)
-{
- return (ie->flags & INDEX_ENTRY_END) ? 1 : 0;
-}
-
-/**
- * Find the last entry in the index block
- */
-static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end)
-{
- ntfs_log_trace("Entering.\n");
-
- while ((char *)ie < ies_end && !ntfs_ie_end(ie))
- ie = ntfs_ie_get_next(ie);
- return ie;
-}
-
-static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos)
-{
- INDEX_ENTRY *ie;
-
- ntfs_log_trace("pos: %d\n", pos);
-
- ie = ntfs_ie_get_first(ih);
-
- while (pos-- > 0)
- ie = ntfs_ie_get_next(ie);
- return ie;
-}
-
-static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie)
-{
- INDEX_ENTRY *ie_prev, *tmp;
-
- ntfs_log_trace("Entering.\n");
-
- ie_prev = NULL;
- tmp = ntfs_ie_get_first(ih);
-
- while (tmp != ie) {
- ie_prev = tmp;
- tmp = ntfs_ie_get_next(tmp);
- }
- return ie_prev;
-}
-
-char *ntfs_ie_filename_get(INDEX_ENTRY *ie)
-{
- FILE_NAME_ATTR *fn;
- char *name = NULL;
- int name_len;
-
- fn = (FILE_NAME_ATTR *)&ie->key;
- name_len = ntfs_ucstombs(fn->file_name, fn->file_name_length, &name, 0);
- if (name_len < 0) {
- ntfs_log_perror("ntfs_ucstombs");
- return NULL;
- } else if (name_len > 0)
- return name;
- free(name);
- return NULL;
-}
-
-void ntfs_ie_filename_dump(INDEX_ENTRY *ie)
-{
- char *s;
-
- s = ntfs_ie_filename_get(ie);
- ntfs_log_debug("'%s' ", s);
- free(s);
-}
-
-void ntfs_ih_filename_dump(INDEX_HEADER *ih)
-{
- INDEX_ENTRY *ie;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ntfs_ie_get_first(ih);
- while (!ntfs_ie_end(ie)) {
- ntfs_ie_filename_dump(ie);
- ie = ntfs_ie_get_next(ie);
- }
-}
-
-static int ntfs_ih_numof_entries(INDEX_HEADER *ih)
-{
- int n;
- INDEX_ENTRY *ie;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ntfs_ie_get_first(ih);
- for (n = 0; !ntfs_ie_end(ie); n++)
- ie = ntfs_ie_get_next(ie);
- return n;
-}
-
-static int ntfs_ih_one_entry(INDEX_HEADER *ih)
-{
- return (ntfs_ih_numof_entries(ih) == 1);
-}
-
-static int ntfs_ih_zero_entry(INDEX_HEADER *ih)
-{
- return (ntfs_ih_numof_entries(ih) == 0);
-}
-
-static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
-{
- u32 new_size;
-
- ntfs_log_trace("Entering.\n");
-
- new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length);
- ih->index_length = cpu_to_le32(new_size);
- memmove(ie, (u8 *)ie + le16_to_cpu(ie->length),
- new_size - ((u8 *)ie - (u8 *)ih));
-}
-
-static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn)
-{
- *ntfs_ie_get_vcn_addr(ie) = cpu_to_sle64(vcn);
-}
-
-/**
- * Insert @ie index entry at @pos entry. Used @ih values should be ok already.
- */
-static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos)
-{
- int ie_size = le16_to_cpu(ie->length);
-
- ntfs_log_trace("Entering.\n");
-
- ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size);
- memmove((u8 *)pos + ie_size, pos,
- le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) -
- ie_size);
- memcpy(pos, ie, ie_size);
-}
-
-static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie)
-{
- INDEX_ENTRY *dup;
-
- ntfs_log_trace("Entering.\n");
-
- dup = ntfs_malloc(le16_to_cpu(ie->length));
- if (dup)
- memcpy(dup, ie, le16_to_cpu(ie->length));
- return dup;
-}
-
-static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
-{
- INDEX_ENTRY *dup;
- int size = le16_to_cpu(ie->length);
-
- ntfs_log_trace("Entering.\n");
-
- if (ie->flags & INDEX_ENTRY_NODE)
- size -= sizeof(VCN);
-
- dup = ntfs_malloc(size);
- if (dup) {
- memcpy(dup, ie, size);
- dup->flags &= ~INDEX_ENTRY_NODE;
- dup->length = cpu_to_le16(size);
- }
- return dup;
-}
-
-static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
-{
- u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18;
-
- ntfs_log_trace("Entering.\n");
-
- if (!ntfs_is_indx_record(ib->magic)) {
-
- ntfs_log_error("Corrupt index block signature: vcn %lld inode "
- "%llu\n", (long long)vcn,
- (unsigned long long)icx->ni->mft_no);
- return -1;
- }
-
- if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
-
- ntfs_log_error("Corrupt index block: VCN (%lld) is different "
- "from expected VCN (%lld) in inode %llu\n",
- (long long)sle64_to_cpu(ib->index_block_vcn),
- (long long)vcn,
- (unsigned long long)icx->ni->mft_no);
- return -1;
- }
-
- if (ib_size != icx->block_size) {
-
- ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
- "has a size (%u) differing from the index "
- "specified size (%u)\n", (long long)vcn,
- icx->ni->mft_no, (unsigned)ib_size,
- (unsigned)icx->block_size);
- return -1;
- }
- return 0;
-}
-
-static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
- u32 name_len, ntfs_attr_search_ctx **ctx)
-{
- ATTR_RECORD *a;
- INDEX_ROOT *ir = NULL;
-
- ntfs_log_trace("Entering.\n");
-
- *ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!*ctx) {
- ntfs_log_perror("Failed to get $INDEX_ROOT search context");
- return NULL;
- }
-
- if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
- 0, NULL, 0, *ctx)) {
- ntfs_log_perror("Failed to lookup $INDEX_ROOT");
- goto err_out;
- }
-
- a = (*ctx)->attr;
- if (a->non_resident) {
- errno = EINVAL;
- ntfs_log_perror("Non-resident $INDEX_ROOT detected");
- goto err_out;
- }
-
- ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->u.res.value_offset));
-err_out:
- if (!ir)
- ntfs_attr_put_search_ctx(*ctx);
- return ir;
-}
-
-/**
- * Find a key in the index block.
- *
- * Return values:
- * STATUS_OK with errno set to ESUCCESS if we know for sure that the
- * entry exists and @ie_out points to this entry.
- * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the
- * entry doesn't exist and @ie_out is the insertion point.
- * STATUS_KEEP_SEARCHING if we can't answer the above question and
- * @vcn will contain the node index block.
- * STATUS_ERROR with errno set if on unexpected error during lookup.
- */
-static int ntfs_ie_lookup(const void *key, const int key_len,
- ntfs_index_context *icx, INDEX_HEADER *ih,
- VCN *vcn, INDEX_ENTRY **ie_out)
-{
- INDEX_ENTRY *ie;
- u8 *index_end;
- int rc, item = 0;
-
- ntfs_log_trace("Entering.\n");
-
- index_end = ntfs_ie_get_end(ih);
-
- /*
- * Loop until we exceed valid memory (corruption case) or until we
- * reach the last entry.
- */
- for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) {
- /* Bounds checks. */
- if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end ||
- (u8 *)ie + le16_to_cpu(ie->length) > index_end) {
- errno = ERANGE;
- ntfs_log_error("Index entry out of bounds in inode "
- "%llu.\n",
- (unsigned long long)icx->ni->mft_no);
- return STATUS_ERROR;
- }
- /*
- * The last entry cannot contain a key. It can however contain
- * a pointer to a child node in the B+tree so we just break out.
- */
- if (ntfs_ie_end(ie))
- break;
- /*
- * Not a perfect match, need to do full blown collation so we
- * know which way in the B+tree we have to go.
- */
- rc = ntfs_collate(icx->ni->vol, icx->cr, key, key_len, &ie->key,
- le16_to_cpu(ie->key_length));
- if (rc == NTFS_COLLATION_ERROR) {
- ntfs_log_error("Collation error. Perhaps a filename "
- "contains invalid characters?\n");
- errno = ERANGE;
- return STATUS_ERROR;
- }
- /*
- * If @key collates before the key of the current entry, there
- * is definitely no such key in this index but we might need to
- * descend into the B+tree so we just break out of the loop.
- */
- if (rc == -1)
- break;
-
- if (!rc) {
- *ie_out = ie;
- errno = 0;
- icx->parent_pos[icx->pindex] = item;
- return STATUS_OK;
- }
-
- item++;
- }
- /*
- * We have finished with this index block without success. Check for the
- * presence of a child node and if not present return with errno ENOENT,
- * otherwise we will keep searching in another index block.
- */
- if (!(ie->flags & INDEX_ENTRY_NODE)) {
- ntfs_log_debug("Index entry wasn't found.\n");
- *ie_out = ie;
- errno = ENOENT;
- return STATUS_NOT_FOUND;
- }
-
- /* Get the starting vcn of the index_block holding the child node. */
- *vcn = ntfs_ie_get_vcn(ie);
- if (*vcn < 0) {
- errno = EINVAL;
- ntfs_log_perror("Negative vcn in inode %llu\n",
- icx->ni->mft_no);
- return STATUS_ERROR;
- }
-
- ntfs_log_trace("Parent entry number %d\n", item);
- icx->parent_pos[icx->pindex] = item;
- return STATUS_KEEP_SEARCHING;
-}
-
-static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni)
-{
- ntfs_attr *na;
-
- na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len);
- if (!na) {
- ntfs_log_perror("Failed to open index allocation of inode "
- "%llu", (unsigned long long)ni->mft_no);
- return NULL;
- }
- return na;
-}
-
-static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
-{
- s64 pos, ret;
-
- ntfs_log_trace("vcn: %lld\n", vcn);
-
- pos = ntfs_ib_vcn_to_pos(icx, vcn);
-
- ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size,
- (u8 *)dst);
- if (ret != 1) {
- if (ret == -1)
- ntfs_log_perror("Failed to read index block");
- else
- ntfs_log_error("Failed to read full index block at "
- "%lld\n", (long long)pos);
- return -1;
- }
-
- if (ntfs_ia_check(icx, dst, vcn))
- return -1;
- return 0;
-}
-
-static int ntfs_icx_parent_inc(ntfs_index_context *icx)
-{
- icx->pindex++;
- if (icx->pindex >= MAX_PARENT_VCN) {
- errno = EOPNOTSUPP;
- ntfs_log_perror("Index is over %d level deep", MAX_PARENT_VCN);
- return STATUS_ERROR;
- }
- return STATUS_OK;
-}
-
-static int ntfs_icx_parent_dec(ntfs_index_context *icx)
-{
- icx->pindex--;
- if (icx->pindex < 0) {
- errno = EINVAL;
- ntfs_log_perror("Corrupt index pointer (%d)", icx->pindex);
- return STATUS_ERROR;
- }
- return STATUS_OK;
-}
-
-/**
- * ntfs_index_lookup - find a key in an index and return its index entry
- * @key: [IN] key for which to search in the index
- * @key_len: [IN] length of @key in bytes
- * @icx: [IN/OUT] context describing the index and the returned entry
- *
- * Before calling ntfs_index_lookup(), @icx must have been obtained from a
- * call to ntfs_index_ctx_get().
- *
- * Look for the @key in the index specified by the index lookup context @icx.
- * ntfs_index_lookup() walks the contents of the index looking for the @key.
- *
- * If the @key is found in the index, 0 is returned and @icx is setup to
- * describe the index entry containing the matching @key. @icx->entry is the
- * index entry and @icx->data and @icx->data_len are the index entry data and
- * its length in bytes, respectively.
- *
- * If the @key is not found in the index, -1 is returned, errno = ENOENT and
- * @icx is setup to describe the index entry whose key collates immediately
- * after the search @key, i.e. this is the position in the index at which
- * an index entry with a key of @key would need to be inserted.
- *
- * If an error occurs return -1, set errno to error code and @icx is left
- * untouched.
- *
- * When finished with the entry and its data, call ntfs_index_ctx_put() to free
- * the context and other associated resources.
- *
- * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
- * the call to ntfs_index_ctx_put() to ensure that the changes are written
- * to disk.
- */
-int ntfs_index_lookup(const void *key, const int key_len,
- ntfs_index_context *icx)
-{
- VCN old_vcn, vcn;
- ntfs_inode *ni = icx->ni;
- INDEX_ROOT *ir;
- INDEX_ENTRY *ie;
- INDEX_BLOCK *ib = NULL;
- ntfs_attr_search_ctx *actx;
- int ret, err = 0;
-
- ntfs_log_trace("Entering.\n");
-
- if (!key || key_len <= 0) {
- errno = EINVAL;
- ntfs_log_perror("key: %p key_len: %d", key, key_len);
- return -1;
- }
-
- ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &actx);
- if (!ir) {
- if (errno == ENOENT)
- errno = EIO;
- return -1;
- }
-
- icx->block_size = le32_to_cpu(ir->index_block_size);
- if (icx->block_size < NTFS_BLOCK_SIZE) {
- errno = EINVAL;
- ntfs_log_perror("Index block size (%u) is smaller than the "
- "sector size (%d)", (unsigned)icx->block_size,
- NTFS_BLOCK_SIZE);
- return -1;
- }
-
- if (ni->vol->cluster_size <= icx->block_size)
- icx->vcn_size_bits = ni->vol->cluster_size_bits;
- else
- icx->vcn_size_bits = ni->vol->sector_size_bits;
-
- icx->cr = ir->collation_rule;
- if (!ntfs_is_collation_rule_supported(icx->cr)) {
- err = errno = EOPNOTSUPP;
- ntfs_log_perror("Unknown collation rule 0x%x",
- (unsigned)le32_to_cpu(icx->cr));
- goto err_out;
- }
-
- old_vcn = VCN_INDEX_ROOT_PARENT;
- /*
- * FIXME: check for both ir and ib that the first index entry is
- * within the index block.
- */
- ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
- if (ret == STATUS_ERROR) {
- err = errno;
- goto err_out;
- }
-
- icx->actx = actx;
- icx->ir = ir;
-
- if (ret != STATUS_KEEP_SEARCHING) {
- /* STATUS_OK or STATUS_NOT_FOUND */
- err = errno;
- icx->is_in_root = TRUE;
- icx->parent_vcn[icx->pindex] = old_vcn;
- goto done;
- }
-
- /* Child node present, descend into it. */
- icx->ia_na = ntfs_ia_open(icx, ni);
- if (!icx->ia_na)
- goto err_out;
-
- ib = ntfs_malloc(icx->block_size);
- if (!ib) {
- err = errno;
- goto err_out;
- }
-
-descend_into_child_node:
- icx->parent_vcn[icx->pindex] = old_vcn;
- if (ntfs_icx_parent_inc(icx)) {
- err = errno;
- goto err_out;
- }
- old_vcn = vcn;
-
- ntfs_log_debug("Descend into node with VCN %lld.\n", vcn);
-
- if (ntfs_ib_read(icx, vcn, ib))
- goto err_out;
-
- ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie);
- if (ret != STATUS_KEEP_SEARCHING) {
- err = errno;
- if (ret == STATUS_ERROR)
- goto err_out;
-
- /* STATUS_OK or STATUS_NOT_FOUND */
- icx->is_in_root = FALSE;
- icx->ib = ib;
- icx->parent_vcn[icx->pindex] = icx->ib_vcn = vcn;
- goto done;
- }
-
- if ((ib->index.flags & NODE_MASK) == LEAF_NODE) {
- ntfs_log_error("Index entry with child node found in a leaf "
- "node in inode 0x%llx.\n",
- (unsigned long long)ni->mft_no);
- goto err_out;
- }
-
- goto descend_into_child_node;
-err_out:
- if (icx->ia_na) {
- ntfs_attr_close(icx->ia_na);
- icx->ia_na = NULL;
- }
- free(ib);
- if (!err)
- err = EIO;
- if (actx)
- ntfs_attr_put_search_ctx(actx);
- errno = err;
- return -1;
-done:
- icx->entry = ie;
- icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
- icx->data_len = le16_to_cpu(ie->key_length);
- icx->max_depth = icx->pindex;
- ntfs_log_trace("Done.\n");
- if (err) {
- errno = err;
- return -1;
- }
- return 0;
-}
-
-static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
- INDEX_HEADER_FLAGS node_type)
-{
- INDEX_BLOCK *ib;
- int ih_size = sizeof(INDEX_HEADER);
-
- ntfs_log_trace("Entering ib_vcn = %lld ib_size = %u\n", ib_vcn,
- ib_size);
-
- ib = ntfs_calloc(ib_size);
- if (!ib)
- return NULL;
-
- ib->magic = magic_INDX;
- ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK));
- ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1);
- /* Set USN to 1 */
- *(le16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1);
- ib->lsn = 0;
-
- ib->index_block_vcn = cpu_to_sle64(ib_vcn);
-
- ib->index.entries_offset = cpu_to_le32((ih_size +
- le16_to_cpu(ib->usa_count) * 2 + 7) & ~7);
- ib->index.index_length = 0;
- ib->index.allocated_size = cpu_to_le32(ib_size -
- (sizeof(INDEX_BLOCK) - ih_size));
- ib->index.flags = node_type;
- return ib;
-}
-
-/**
- * Find the median by going through all the entries
- */
-static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih)
-{
- INDEX_ENTRY *ie, *ie_start;
- u8 *ie_end;
- int i = 0, median;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ie_start = ntfs_ie_get_first(ih);
- ie_end = (u8 *)ntfs_ie_get_end(ih);
-
- while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) {
- ie = ntfs_ie_get_next(ie);
- i++;
- }
- /*
- * NOTE: this could be also the entry at the half of the index block.
- */
- median = i / 2 - 1;
-
- ntfs_log_trace("Entries: %d median: %d\n", i, median);
-
- for (i = 0, ie = ie_start; i <= median; i++)
- ie = ntfs_ie_get_next(ie);
-
- return ie;
-}
-
-static s64 ntfs_ibm_vcn_to_pos(ntfs_index_context *icx, VCN vcn)
-{
- return ntfs_ib_vcn_to_pos(icx, vcn) / icx->block_size;
-}
-
-static s64 ntfs_ibm_pos_to_vcn(ntfs_index_context *icx, s64 pos)
-{
- return ntfs_ib_pos_to_vcn(icx, pos * icx->block_size);
-}
-
-static int ntfs_ibm_add(ntfs_index_context *icx)
-{
- u8 bmp[8];
-
- ntfs_log_trace("Entering.\n");
-
- if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len))
- return STATUS_OK;
- /*
- * AT_BITMAP must be at least 8 bytes.
- */
- memset(bmp, 0, sizeof(bmp));
- if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len,
- bmp, sizeof(bmp))) {
- ntfs_log_perror("Failed to add AT_BITMAP");
- return STATUS_ERROR;
- }
- return STATUS_OK;
-}
-
-static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
-{
- u8 byte;
- s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn);
- u32 bpos = pos / 8;
- u32 bit = 1 << (pos % 8);
- ntfs_attr *na;
- int ret = STATUS_ERROR;
-
- ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn);
-
- na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len);
- if (!na) {
- ntfs_log_perror("Failed to open $BITMAP attribute");
- return -1;
- }
-
- if (set) {
- if (na->data_size < bpos + 1) {
- if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) {
- ntfs_log_perror("Failed to truncate AT_BITMAP");
- goto err_na;
- }
- }
- }
-
- if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) {
- ntfs_log_perror("Failed to read $BITMAP");
- goto err_na;
- }
-
- if (set)
- byte |= bit;
- else
- byte &= ~bit;
-
- if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) {
- ntfs_log_perror("Failed to write $Bitmap");
- goto err_na;
- }
-
- ret = STATUS_OK;
-err_na:
- ntfs_attr_close(na);
- return ret;
-}
-
-
-static int ntfs_ibm_set(ntfs_index_context *icx, VCN vcn)
-{
- return ntfs_ibm_modify(icx, vcn, 1);
-}
-
-static int ntfs_ibm_clear(ntfs_index_context *icx, VCN vcn)
-{
- return ntfs_ibm_modify(icx, vcn, 0);
-}
-
-static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
-{
- u8 *bm;
- int bit;
- s64 vcn, byte, size;
-
- ntfs_log_trace("Entering.\n");
-
- bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len,
- &size);
- if (!bm)
- return (VCN)-1;
-
- for (byte = 0; byte < size; byte++) {
-
- if (bm[byte] == 255)
- continue;
-
- for (bit = 0; bit < 8; bit++) {
- if (!(bm[byte] & (1 << bit))) {
- vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit);
- goto out;
- }
- }
- }
-
- vcn = ntfs_ibm_pos_to_vcn(icx, size * 8);
-out:
- ntfs_log_trace("allocated vcn: %lld\n", vcn);
-
- if (ntfs_ibm_set(icx, vcn))
- vcn = (VCN)-1;
-
- free(bm);
- return vcn;
-}
-
-static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn)
-{
- INDEX_BLOCK *ib;
- INDEX_ENTRY *ie_last;
- char *ies_start, *ies_end;
- int i;
-
- ntfs_log_trace("Entering.\n");
-
- if (!(ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size),
- LEAF_NODE)))
- return NULL;
-
- ies_start = (char *)ntfs_ie_get_first(&ir->index);
- ies_end = (char *)ntfs_ie_get_end(&ir->index);
-
- ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
- /*
- * Copy all entries, including the termination entry
- * as well, which can never have any data.
- */
- i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length);
- memcpy(ntfs_ie_get_first(&ib->index), ies_start, i);
-
- ib->index.flags = ir->index.flags;
- ib->index.index_length = cpu_to_le32(i +
- le32_to_cpu(ib->index.entries_offset));
- return ib;
-}
-
-static void ntfs_ir_nill(INDEX_ROOT *ir)
-{
- INDEX_ENTRY *ie_last;
- char *ies_start, *ies_end;
-
- ntfs_log_trace("Entering\n");
- /* TODO: This function could be much simpler. */
- ies_start = (char *)ntfs_ie_get_first(&ir->index);
- ies_end = (char *)ntfs_ie_get_end(&ir->index);
- ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
- /* Move the index root termination entry forward. */
- if ((char *)ie_last > ies_start) {
- memmove(ies_start, (char *)ie_last, le16_to_cpu(
- ie_last->length));
- ie_last = (INDEX_ENTRY *)ies_start;
- }
-}
-
-static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
- INDEX_ENTRY *median, VCN new_vcn)
-{
- u8 *ies_end;
- INDEX_ENTRY *ie_head; /* first entry after the median */
- int tail_size, ret;
- INDEX_BLOCK *dst;
-
- ntfs_log_trace("Entering.\n");
-
- dst = ntfs_ib_alloc(new_vcn, icx->block_size,
- src->index.flags & NODE_MASK);
- if (!dst)
- return STATUS_ERROR;
-
- ie_head = ntfs_ie_get_next(median);
-
- ies_end = (u8 *)ntfs_ie_get_end(&src->index);
- tail_size = ies_end - (u8 *)ie_head;
- memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size);
-
- dst->index.index_length = cpu_to_le32(tail_size +
- le32_to_cpu(dst->index.entries_offset));
-
- ret = ntfs_ib_write(icx, new_vcn, dst);
-
- free(dst);
- return ret;
-}
-
-static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
- INDEX_ENTRY *ie)
-{
- char *ies_start, *ies_end;
- INDEX_ENTRY *ie_last;
-
- ntfs_log_trace("Entering.\n");
-
- ies_start = (char *)ntfs_ie_get_first(&src->index);
- ies_end = (char *)ntfs_ie_get_end(&src->index);
-
- ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
- if (ie_last->flags & INDEX_ENTRY_NODE)
- ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie));
-
- memcpy(ie, ie_last, le16_to_cpu(ie_last->length));
-
- src->index.index_length = cpu_to_le32(((char *)ie - ies_start) +
- le16_to_cpu(ie->length) +
- le32_to_cpu(src->index.entries_offset));
-
- if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src))
- return STATUS_ERROR;
-
- return STATUS_OK;
-}
-
-static int ntfs_ia_add(ntfs_index_context *icx)
-{
- ntfs_log_trace("Entering.\n");
-
- if (ntfs_ibm_add(icx))
- return -1;
-
- if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name,
- icx->name_len)) {
- if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name,
- icx->name_len, NULL, 0)) {
- ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION");
- return -1;
- }
- }
-
- icx->ia_na = ntfs_ia_open(icx, icx->ni);
- if (!icx->ia_na)
- return -1;
- return 0;
-}
-
-static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len)
-{
- ntfs_attr_search_ctx *ctx;
- INDEX_ROOT *ir;
-
- ir = ntfs_ir_lookup(ni, name, len, &ctx);
- if (ir)
- ntfs_attr_put_search_ctx(ctx);
- return ir;
-}
-
-static int ntfs_ir_reparent(ntfs_index_context *icx)
-{
- ntfs_attr_search_ctx *ctx;
- INDEX_ROOT *ir;
- INDEX_ENTRY *ie;
- INDEX_BLOCK *ib = NULL;
- VCN new_ib_vcn;
- int ret = STATUS_ERROR;
-
- ntfs_log_trace("Entering.\n");
-
- if (!(icx->ia_na))
- if (ntfs_ia_add(icx))
- return -1;
-
- ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
- if (!ir)
- return -1;
-
- new_ib_vcn = ntfs_ibm_get_free(icx);
- if (new_ib_vcn == -1)
- goto err_out;
-
- ib = ntfs_ir_to_ib(ir, new_ib_vcn);
- if (ib == NULL) {
- ntfs_log_perror("Failed to move index root to index block");
- goto clear_bmp;
- }
-
- if (ntfs_ib_write(icx, new_ib_vcn, ib))
- goto clear_bmp;
-
- ntfs_ir_nill(ir);
-
- ie = ntfs_ie_get_first(&ir->index);
- ie->flags |= INDEX_ENTRY_NODE;
- ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
- ntfs_ie_set_vcn(ie, new_ib_vcn);
-
- ir->index.flags = LARGE_INDEX;
- ir->index.index_length = cpu_to_le32(le32_to_cpu(
- ir->index.entries_offset) + le16_to_cpu(ie->length));
- ir->index.allocated_size = ir->index.index_length;
-
- if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
- sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
- le32_to_cpu(ir->index.allocated_size)))
- /* FIXME: revert bitmap, index root */
- goto err_out;
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
-
- ret = STATUS_OK;
-err_out:
- ntfs_attr_put_search_ctx(ctx);
- free(ib);
- return ret;
-clear_bmp:
- ntfs_ibm_clear(icx, new_ib_vcn);
- goto err_out;
-}
-
-/**
- * ntfs_ir_truncate - Truncate index root attribute
- *
- * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR.
- */
-static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
-{
- ntfs_attr *na;
- int ret;
-
- ntfs_log_trace("Entering.\n");
-
- na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len);
- if (!na) {
- ntfs_log_perror("Failed to open INDEX_ROOT");
- return STATUS_ERROR;
- }
- /*
- * INDEX_ROOT must be resident and its entries can be moved to
- * INDEX_BLOCK, so ENOSPC isn't a real error.
- */
- ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
- if (ret == STATUS_OK) {
- icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
- if (!icx->ir)
- return STATUS_ERROR;
-
- icx->ir->index.allocated_size = cpu_to_le32(data_size);
- } else {
- if (errno != ENOSPC && errno != EOVERFLOW)
- ntfs_log_trace("Failed to truncate INDEX_ROOT");
- if (errno == EOVERFLOW)
- ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT;
- }
-
- ntfs_attr_close(na);
- return ret;
-}
-
-/**
- * ntfs_ir_make_space - Make more space for the index root attribute
- *
- * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
- * On error return STATUS_ERROR.
- */
-static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
-{
- int ret;
-
- ntfs_log_trace("Entering.\n");
-
- ret = ntfs_ir_truncate(icx, data_size);
- if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) {
- ret = ntfs_ir_reparent(icx);
- if (ret == STATUS_OK)
- ret = STATUS_KEEP_SEARCHING;
- else
- ntfs_log_perror("Failed to nodify INDEX_ROOT");
- }
- return ret;
-}
-
-/*
- * NOTE: 'ie' must be a copy of a real index entry.
- */
-static int ntfs_ie_add_vcn(INDEX_ENTRY **ie)
-{
- INDEX_ENTRY *p, *old = *ie;
-
- old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN));
- p = realloc(old, le16_to_cpu(old->length));
- if (!p)
- return STATUS_ERROR;
-
- p->flags |= INDEX_ENTRY_NODE;
- *ie = p;
- return STATUS_OK;
-}
-
-static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn,
- int pos)
-{
- INDEX_ENTRY *ie_node, *ie;
- int ret = STATUS_ERROR;
- VCN old_vcn;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ntfs_ie_dup(orig_ie);
- if (!ie)
- return STATUS_ERROR;
-
- if (!(ie->flags & INDEX_ENTRY_NODE))
- if (ntfs_ie_add_vcn(&ie))
- goto out;
-
- ie_node = ntfs_ie_get_by_pos(ih, pos);
- old_vcn = ntfs_ie_get_vcn(ie_node);
- ntfs_ie_set_vcn(ie_node, new_vcn);
-
- ntfs_ie_insert(ih, ie, ie_node);
- ntfs_ie_set_vcn(ie_node, old_vcn);
- ret = STATUS_OK;
-out:
- free(ie);
- return ret;
-}
-
-static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx)
-{
- return icx->parent_vcn[icx->pindex];
-}
-
-static VCN ntfs_icx_parent_pos(ntfs_index_context *icx)
-{
- return icx->parent_pos[icx->pindex];
-}
-
-static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median,
- VCN new_vcn)
-{
- u32 new_size;
- int ret;
-
- ntfs_log_trace("Entering.\n");
-
- icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
- if (!icx->ir)
- return STATUS_ERROR;
-
- new_size = le32_to_cpu(icx->ir->index.index_length) +
- le16_to_cpu(median->length);
- if (!(median->flags & INDEX_ENTRY_NODE))
- new_size += sizeof(VCN);
-
- ret = ntfs_ir_make_space(icx, new_size);
- if (ret != STATUS_OK)
- return ret;
-
- icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
- if (!icx->ir)
- return STATUS_ERROR;
-
- return ntfs_ih_insert(&icx->ir->index, median, new_vcn,
- ntfs_icx_parent_pos(icx));
-}
-
-static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib);
-
-/**
- * ntfs_ib_insert - insert an index block to an index context.
- *
- * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
- * On error return STATUS_ERROR.
- */
-static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
-{
- INDEX_BLOCK *ib;
- u32 idx_size, allocated_size;
- int err = STATUS_ERROR;
- VCN old_vcn;
-
- ntfs_log_trace("Entering.\n");
-
- ib = ntfs_malloc(icx->block_size);
- if (!ib)
- return -1;
-
- old_vcn = ntfs_icx_parent_vcn(icx);
-
- if (ntfs_ib_read(icx, old_vcn, ib))
- goto err_out;
-
- idx_size = le32_to_cpu(ib->index.index_length);
- allocated_size = le32_to_cpu(ib->index.allocated_size);
- /* FIXME: sizeof(VCN) should be included only if ie has no VCN */
- if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) {
- err = ntfs_ib_split(icx, ib);
- if (err == STATUS_OK)
- err = STATUS_KEEP_SEARCHING;
- goto err_out;
- }
-
- if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx)))
- goto err_out;
-
- if (ntfs_ib_write(icx, old_vcn, ib))
- goto err_out;
-
- err = STATUS_OK;
-err_out:
- free(ib);
- return err;
-}
-
-/**
- * ntfs_ib_split - Split index allocation attribute
- *
- * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
- * On error return is STATUS_ERROR.
- */
-static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
-{
- INDEX_ENTRY *median;
- VCN new_vcn;
- int ret;
-
- ntfs_log_trace("Entering.\n");
-
- if (ntfs_icx_parent_dec(icx))
- return STATUS_ERROR;
-
- median = ntfs_ie_get_median(&ib->index);
- new_vcn = ntfs_ibm_get_free(icx);
- if (new_vcn == -1)
- return STATUS_ERROR;
-
- if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) {
- ntfs_ibm_clear(icx, new_vcn);
- return STATUS_ERROR;
- }
-
- if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
- ret = ntfs_ir_insert_median(icx, median, new_vcn);
- else
- ret = ntfs_ib_insert(icx, median, new_vcn);
-
- ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
-
- if (ret != STATUS_OK) {
- ntfs_ibm_clear(icx, new_vcn);
- return ret;
- }
-
- ret = ntfs_ib_cut_tail(icx, ib, median);
- return ret;
-}
-
-static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
-{
- INDEX_HEADER *ih;
- int allocated_size, new_size;
- int ret = STATUS_ERROR;
-
-#ifdef DEBUG
- char *fn;
- fn = ntfs_ie_filename_get(ie);
- ntfs_log_trace("file: '%s'\n", fn);
- free(fn);
-#endif
-
- while (1) {
- if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length),
- icx)) {
- errno = EEXIST;
- ntfs_log_error("Index already have such entry.\n");
- goto err_out;
- }
- if (errno != ENOENT) {
- ntfs_log_perror("Failed to find place for new entry");
- goto err_out;
- }
-
- if (icx->is_in_root)
- ih = &icx->ir->index;
- else
- ih = &icx->ib->index;
-
- allocated_size = le32_to_cpu(ih->allocated_size);
- new_size = le32_to_cpu(ih->index_length) +
- le16_to_cpu(ie->length);
-
- if (new_size <= allocated_size)
- break;
-
- ntfs_log_trace("index block sizes: allocated: %d needed: %d\n",
- allocated_size, new_size);
-
- if (icx->is_in_root) {
- if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR)
- goto err_out;
- } else {
- if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR)
- goto err_out;
- }
- ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
- ntfs_index_ctx_reinit(icx);
- }
-
- ntfs_ie_insert(ih, ie, icx->entry);
- ntfs_index_entry_mark_dirty(icx);
-
- ret = STATUS_OK;
-err_out:
- ntfs_log_trace("%s\n", ret ? "Failed" : "Done");
- return ret;
-}
-
-/**
- * ntfs_index_add_filename - add filename to directory index
- * @ni: ntfs inode describing directory to which index add filename
- * @fn: FILE_NAME attribute to add
- * @mref: reference of the inode which @fn describes
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
-{
- INDEX_ENTRY *ie;
- ntfs_index_context *icx;
- int fn_size, ie_size, ret = -1, err;
-
- ntfs_log_trace("Entering.\n");
-
- if (!ni || !fn) {
- ntfs_log_error("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- fn_size = (fn->file_name_length * sizeof(ntfschar)) +
- sizeof(FILE_NAME_ATTR);
- ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
-
- ie = ntfs_calloc(ie_size);
- if (!ie)
- return -1;
-
- ie->u.indexed_file = cpu_to_le64(mref);
- ie->length = cpu_to_le16(ie_size);
- ie->key_length = cpu_to_le16(fn_size);
- memcpy(&ie->key, fn, fn_size);
-
- icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
- if (!icx)
- goto out;
-
- err = errno;
- ret = ntfs_ie_add(icx, ie);
- errno = err;
-
- ntfs_index_ctx_put(icx);
-out:
- free(ie);
- return ret;
-}
-
-static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
- INDEX_ENTRY *ie, INDEX_BLOCK *ib)
-{
- INDEX_ENTRY *ie_roam;
- int ret = STATUS_ERROR;
-
- ntfs_log_trace("Entering.\n");
-
- ie_roam = ntfs_ie_dup_novcn(ie);
- if (!ie_roam)
- return STATUS_ERROR;
-
- ntfs_ie_delete(ih, ie);
-
- if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
- ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
- else
- if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib))
- goto out;
-
- ntfs_index_ctx_reinit(icx);
-
- ret = ntfs_ie_add(icx, ie_roam);
-out:
- free(ie_roam);
- return ret;
-}
-
-/**
- * ntfs_ir_leafify -
- *
- * Used if an empty index block to be deleted has END entry as the parent
- * in the INDEX_ROOT which is the only one there.
- */
-static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih)
-{
- INDEX_ENTRY *ie;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ntfs_ie_get_first(ih);
- ie->flags &= ~INDEX_ENTRY_NODE;
- ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN));
-
- ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) -
- sizeof(VCN));
- ih->flags &= ~LARGE_INDEX;
-
- /* Not fatal error */
- ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
-
- ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
- ntfs_index_ctx_reinit(icx);
-}
-
-/**
- * ntfs_ih_reparent_end -
- *
- * Used if an empty index block to be deleted has END entry as the parent
- * in the INDEX_ROOT which is not the only one there.
- */
-static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih,
- INDEX_BLOCK *ib)
-{
- INDEX_ENTRY *ie, *ie_prev;
-
- ntfs_log_trace("Entering.\n");
-
- ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx));
- ie_prev = ntfs_ie_prev(ih, ie);
-
- ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev));
- return ntfs_ih_takeout(icx, ih, ie_prev, ib);
-}
-
-static int ntfs_index_rm_leaf(ntfs_index_context *icx)
-{
- INDEX_BLOCK *ib = NULL;
- INDEX_HEADER *parent_ih;
- INDEX_ENTRY *ie;
- int ret = STATUS_ERROR;
-
- ntfs_log_trace("pindex: %d\n", icx->pindex);
-
- if (ntfs_icx_parent_dec(icx))
- return STATUS_ERROR;
-
- if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1]))
- return STATUS_ERROR;
-
- if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
- parent_ih = &icx->ir->index;
- else {
- ib = ntfs_malloc(icx->block_size);
- if (!ib)
- return STATUS_ERROR;
-
- if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib))
- goto out;
-
- parent_ih = &ib->index;
- }
-
- ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx));
- if (!ntfs_ie_end(ie)) {
- ret = ntfs_ih_takeout(icx, parent_ih, ie, ib);
- goto out;
- }
-
- if (ntfs_ih_zero_entry(parent_ih)) {
-
- if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) {
- ntfs_ir_leafify(icx, parent_ih);
- goto ok;
- }
-
- ret = ntfs_index_rm_leaf(icx);
- goto out;
- }
-
- if (ntfs_ih_reparent_end(icx, parent_ih, ib))
- goto out;
-ok:
- ret = STATUS_OK;
-out:
- free(ib);
- return ret;
-}
-
-static int ntfs_index_rm_node(ntfs_index_context *icx)
-{
- int entry_pos;
- VCN vcn;
- INDEX_BLOCK *ib = NULL;
- INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
- INDEX_HEADER *ih;
- u32 new_size;
- int delta, ret = STATUS_ERROR;
-
- ntfs_log_trace("Entering.\n");
-
- if (!icx->ia_na) {
- icx->ia_na = ntfs_ia_open(icx, icx->ni);
- if (!icx->ia_na)
- return STATUS_ERROR;
- }
-
- ib = ntfs_malloc(icx->block_size);
- if (!ib)
- return STATUS_ERROR;
-
- ie_succ = ntfs_ie_get_next(icx->entry);
- entry_pos = icx->parent_pos[icx->pindex]++;
-descend:
- vcn = ntfs_ie_get_vcn(ie_succ);
- if (ntfs_ib_read(icx, vcn, ib))
- goto out;
-
- ie_succ = ntfs_ie_get_first(&ib->index);
-
- if (ntfs_icx_parent_inc(icx))
- goto out;
-
- icx->parent_vcn[icx->pindex] = vcn;
- icx->parent_pos[icx->pindex] = 0;
-
- if ((ib->index.flags & NODE_MASK) == INDEX_NODE)
- goto descend;
-
- if (ntfs_ih_zero_entry(&ib->index)) {
- errno = EOPNOTSUPP;
- ntfs_log_perror("Failed to find any entry in an index block. "
- "Please run chkdsk.");
- goto out;
- }
-
- ie = ntfs_ie_dup(ie_succ);
- if (!ie)
- goto out;
-
- if (ntfs_ie_add_vcn(&ie))
- goto out2;
-
- ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry));
-
- if (icx->is_in_root)
- ih = &icx->ir->index;
- else
- ih = &icx->ib->index;
-
- delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length);
- new_size = le32_to_cpu(ih->index_length) + delta;
- if (delta > 0) {
- if (icx->is_in_root) {
- if (ntfs_ir_truncate(icx, new_size)) {
- errno = EOPNOTSUPP;
- ntfs_log_perror("Denied to truncate INDEX_ROOT"
- " during entry removal");
- goto out2;
- }
- ih = &icx->ir->index;
- entry = ntfs_ie_get_by_pos(ih, entry_pos);
- } else if (new_size > le32_to_cpu(ih->allocated_size)) {
- errno = EOPNOTSUPP;
- ntfs_log_perror("Denied to split INDEX_BLOCK during "
- "entry removal");
- goto out2;
- }
- }
-
- ntfs_ie_delete(ih, entry);
- ntfs_ie_insert(ih, ie, entry);
-
- if (icx->is_in_root) {
- if (ntfs_ir_truncate(icx, new_size))
- goto out2;
- ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
- } else
- if (ntfs_icx_ib_write(icx))
- goto out2;
-
- ntfs_ie_delete(&ib->index, ie_succ);
-
- if (ntfs_ih_zero_entry(&ib->index)) {
- if (ntfs_index_rm_leaf(icx))
- goto out2;
- } else
- if (ntfs_ib_write(icx, vcn, ib))
- goto out2;
-
- ret = STATUS_OK;
-out2:
- free(ie);
-out:
- free(ib);
- return ret;
-}
-
-/**
- * ntfs_index_rm - remove entry from the index
- * @icx: index context describing entry to delete
- *
- * Delete entry described by @icx from the index. Index context is always
- * reinitialized after use of this function, so it can be used for index
- * lookup once again.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_index_rm(ntfs_index_context *icx)
-{
- INDEX_HEADER *ih;
- int err;
-
- ntfs_log_trace("Entering.\n");
-
- if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) {
- ntfs_log_error("Invalid arguments.\n");
- errno = EINVAL;
- goto err_out;
- }
- if (icx->is_in_root)
- ih = &icx->ir->index;
- else
- ih = &icx->ib->index;
-
- if (icx->entry->flags & INDEX_ENTRY_NODE) {
-
- if (ntfs_index_rm_node(icx))
- goto err_out;
-
- } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) {
-
- ntfs_ie_delete(ih, icx->entry);
-
- if (icx->is_in_root) {
- err = ntfs_ir_truncate(icx,
- le32_to_cpu(ih->index_length));
- if (err != STATUS_OK)
- goto err_out;
- } else
- if (ntfs_icx_ib_write(icx))
- goto err_out;
- } else {
- if (ntfs_index_rm_leaf(icx))
- goto err_out;
- }
-
- ntfs_index_ctx_reinit(icx);
- ntfs_log_trace("Done.\n");
- return 0;
-err_out:
- err = errno;
- ntfs_index_ctx_reinit(icx);
- errno = err;
- ntfs_log_trace("Failed.\n");
- return -1;
-}
-
-/**
- * ntfs_index_root_get - read the index root of an attribute
- * @ni: open ntfs inode in which the ntfs attribute resides
- * @attr: attribute for which we want its index root
- *
- * This function will read the related index root an ntfs attribute.
- *
- * On success a buffer is allocated with the content of the index root
- * and which needs to be freed when it's not needed anymore.
- *
- * On error NULL is returned with errno set to the error code.
- */
-INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr)
-{
- ntfs_attr_search_ctx *ctx;
- ntfschar *name;
- INDEX_ROOT *root = NULL;
-
- name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset));
-
- if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx))
- return NULL;
-
- root = ntfs_malloc(sizeof(INDEX_ROOT));
- if (!root)
- goto out;
-
- *root = *((INDEX_ROOT *)((u8 *)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset)));
-out:
- ntfs_attr_put_search_ctx(ctx);
- return root;
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/inode.c b/usr/src/lib/libntfs/common/libntfs/inode.c
deleted file mode 100644
index 9ea1d34524..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/inode.c
+++ /dev/null
@@ -1,1200 +0,0 @@
-/**
- * inode.c - Inode handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2005 Anton Altaparmakov
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "attrib.h"
-#include "inode.h"
-#include "debug.h"
-#include "mft.h"
-#include "attrlist.h"
-#include "runlist.h"
-#include "lcnalloc.h"
-#include "index.h"
-#include "dir.h"
-#include "ntfstime.h"
-#include "logging.h"
-
-/**
- * __ntfs_inode_allocate - Create and initialise an NTFS inode object
- * @vol:
- *
- * Description...
- *
- * Returns:
- */
-static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol)
-{
- ntfs_inode *ni;
-
- ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode));
- if (ni) {
- ni->vol = vol;
- INIT_LIST_HEAD(&ni->attr_cache);
- }
- return ni;
-}
-
-/**
- * ntfs_inode_allocate - Create an NTFS inode object
- * @vol:
- *
- * Description...
- *
- * Returns:
- */
-ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol)
-{
- return __ntfs_inode_allocate(vol);
-}
-
-/**
- * __ntfs_inode_release - Destroy an NTFS inode object
- * @ni:
- *
- * Description...
- *
- * Returns:
- */
-static int __ntfs_inode_release(ntfs_inode *ni)
-{
- if (NInoDirty(ni))
- ntfs_log_debug("Eeek. Discarding dirty inode!\n");
- if (NInoAttrList(ni) && ni->attr_list)
- free(ni->attr_list);
- free(ni->mrec);
- free(ni);
- return 0;
-}
-
-/**
- * __ntfs_inode_add_to_cache - do not use me! Only for internal library use.
- */
-void __ntfs_inode_add_to_cache(ntfs_inode *ni)
-{
- list_add_tail(&ni->list_entry, &ni->vol->inode_cache[
- ni->mft_no & NTFS_INODE_CACHE_SIZE_BITS]);
- ni->nr_references = 1;
-}
-
-/**
- * ntfs_inode_open - open an inode ready for access
- * @vol: volume to get the inode from
- * @mref: inode number / mft record number to open
- *
- * Allocate an ntfs_inode structure and initialize it for the given inode
- * specified by @mref. @mref specifies the inode number / mft record to read,
- * including the sequence number, which can be 0 if no sequence number checking
- * is to be performed.
- *
- * Then, allocate a buffer for the mft record, read the mft record from the
- * volume @vol, and attach it to the ntfs_inode structure (->mrec). The
- * mft record is mst deprotected and sanity checked for validity and we abort
- * if deprotection or checks fail.
- *
- * Finally, search for an attribute list attribute in the mft record and if one
- * is found, load the attribute list attribute value and attach it to the
- * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate
- * this.
- *
- * Return a pointer to the ntfs_inode structure on success or NULL on error,
- * with errno set to the error code.
- */
-ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
-{
- s64 l;
- ntfs_inode *ni;
- ntfs_attr_search_ctx *ctx;
- int err = 0;
- STANDARD_INFORMATION *std_info;
- struct list_head *pos;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));
- if (!vol) {
- errno = EINVAL;
- return NULL;
- }
- /* Check cache, maybe this inode already opened? */
- list_for_each(pos, &vol->inode_cache[MREF(mref) &
- NTFS_INODE_CACHE_SIZE_BITS]) {
- ntfs_inode *tmp_ni;
-
- tmp_ni = list_entry(pos, ntfs_inode, list_entry);
- if (tmp_ni->mft_no == MREF(mref)) {
- ntfs_log_trace("Found this inode in cache, increment "
- "reference count and return it.\n");
- tmp_ni->nr_references++;
- return tmp_ni;
- }
- }
- /* Search failed. Properly open inode. */
- ni = __ntfs_inode_allocate(vol);
- if (!ni)
- return NULL;
- if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL))
- goto err_out;
- if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
- err = ENOENT;
- goto err_out;
- }
- ni->mft_no = MREF(mref);
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- goto err_out;
- /* Receive some basic information about inode. */
- if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
- 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
- err = errno;
- ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
- "attribute.\n");
- goto put_err_out;
- }
- std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- ni->flags = std_info->file_attributes;
- ni->creation_time = ntfs2utc(std_info->creation_time);
- ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time);
- ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time);
- ni->last_access_time = ntfs2utc(std_info->last_access_time);
- /* Set attribute list information. */
- if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
- ctx)) {
- if (errno != ENOENT)
- goto put_err_out;
- /* Attribute list attribute does not present. */
- goto get_size;
- }
- NInoSetAttrList(ni);
- l = ntfs_get_attribute_value_length(ctx->attr);
- if (!l)
- goto put_err_out;
- if (l > 0x40000) {
- err = EIO;
- goto put_err_out;
- }
- ni->attr_list_size = l;
- ni->attr_list = ntfs_malloc(ni->attr_list_size);
- if (!ni->attr_list)
- goto put_err_out;
- l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list);
- if (!l)
- goto put_err_out;
- if (l != ni->attr_list_size) {
- err = EIO;
- goto put_err_out;
- }
-get_size:
- if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
- if (errno != ENOENT)
- goto put_err_out;
- /* Directory or special file. */
- ni->data_size = ni->allocated_size = 0;
- } else {
- if (ctx->attr->non_resident) {
- ni->data_size = sle64_to_cpu(ctx->attr->u.nonres.data_size);
- if (ctx->attr->flags &
- (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE))
- ni->allocated_size = sle64_to_cpu(
- ctx->attr->u.nonres.compressed_size);
- else
- ni->allocated_size = sle64_to_cpu(
- ctx->attr->u.nonres.allocated_size);
- } else {
- ni->data_size = le32_to_cpu(ctx->attr->u.res.value_length);
- ni->allocated_size = (ni->data_size + 7) & ~7;
- }
- }
- ntfs_attr_put_search_ctx(ctx);
- __ntfs_inode_add_to_cache(ni);
- return ni;
-put_err_out:
- if (!err)
- err = errno;
- ntfs_attr_put_search_ctx(ctx);
-err_out:
- if (!err)
- err = errno;
- __ntfs_inode_release(ni);
- errno = err;
- return NULL;
-}
-
-/**
- * ntfs_inode_close - close an ntfs inode and free all associated memory
- * @ni: ntfs inode to close
- *
- * Make sure the ntfs inode @ni is clean.
- *
- * If the ntfs inode @ni is a base inode, close all associated extent inodes,
- * then deallocate all memory attached to it, and finally free the ntfs inode
- * structure itself.
- *
- * If it is an extent inode, we disconnect it from its base inode before we
- * destroy it.
- *
- * It is OK to pass NULL to this function, it is just noop in this case.
- *
- * Return 0 on success or -1 on error with errno set to the error code. On
- * error, @ni has not been freed. The user should attempt to handle the error
- * and call ntfs_inode_close() again. The following error codes are defined:
- *
- * EBUSY @ni and/or its attribute list runlist is/are dirty and the
- * attempt to write it/them to disk failed.
- * EINVAL @ni is invalid (probably it is an extent inode).
- * EIO I/O error while trying to write inode to disk.
- */
-int ntfs_inode_close(ntfs_inode *ni)
-{
- if (!ni)
- return 0;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- /* Decrement number of users. If there are left then just return. */
- if (ni->nr_extents != -1) {
- ni->nr_references--;
- if (ni->nr_references) {
- ntfs_log_trace("There are %d more references left to "
- "this inode.\n",
- ni->nr_references);
- return 0;
- } else
- ntfs_log_trace("There are no more references left to "
- "this inode.\n");
- }
- /* Check whether all attributes of this inode are closed. */
- if (!list_empty(&ni->attr_cache))
- ntfs_log_error("%s(): Not all attributes are closed. "
- "We definitely have memory leak. "
- "Continue anyway.\n", "ntfs_inode_close");
- /* If we have dirty metadata, write it out. */
- if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
- if (ntfs_inode_sync(ni)) {
- if (errno != EIO)
- errno = EBUSY;
- return -1;
- }
- }
- /* Is this a base inode with mapped extent inodes? */
- if (ni->nr_extents > 0) {
- while (ni->nr_extents > 0) {
- if (ntfs_inode_close(ni->u.extent_nis[0])) {
- if (errno != EIO)
- errno = EBUSY;
- return -1;
- }
- }
- } else if (ni->nr_extents == -1) {
- ntfs_inode **tmp_nis;
- ntfs_inode *base_ni;
- s32 i;
-
- /*
- * If the inode is an extent inode, disconnect it from the
- * base inode before destroying it.
- */
- base_ni = ni->u.base_ni;
- for (i = 0; i < base_ni->nr_extents; ++i) {
- tmp_nis = base_ni->u.extent_nis;
- if (tmp_nis[i] != ni)
- continue;
- /* Found it. Disconnect. */
- memmove(tmp_nis + i, tmp_nis + i + 1,
- (base_ni->nr_extents - i - 1) *
- sizeof(ntfs_inode *));
- /* Buffer should be for multiple of four extents. */
- if ((--base_ni->nr_extents) & 3) {
- i = -1;
- break;
- }
- /*
- * ElectricFence is unhappy with realloc(x,0) as free(x)
- * thus we explicitly separate these two cases.
- */
- if (base_ni->nr_extents) {
- /* Resize the memory buffer. */
- tmp_nis = realloc(tmp_nis, base_ni->nr_extents *
- sizeof(ntfs_inode *));
- /* Ignore errors, they don't really matter. */
- if (tmp_nis)
- base_ni->u.extent_nis = tmp_nis;
- } else if (tmp_nis)
- free(tmp_nis);
- /* Allow for error checking. */
- i = -1;
- break;
- }
- if (i != -1)
- ntfs_log_debug("Extent inode was not attached to base "
- "inode! Continuing regardless.\n");
- }
- /* Remove inode from the list of opened inodes. */
- if (ni->nr_extents != -1)
- list_del(&ni->list_entry);
- return __ntfs_inode_release(ni);
-}
-
-/**
- * ntfs_extent_inode_open - load an extent inode and attach it to its base
- * @base_ni: base ntfs inode
- * @mref: mft reference of the extent inode to load (in little endian)
- *
- * First check if the extent inode @mref is already attached to the base ntfs
- * inode @base_ni, and if so, return a pointer to the attached extent inode.
- *
- * If the extent inode is not already attached to the base inode, allocate an
- * ntfs_inode structure and initialize it for the given inode @mref. @mref
- * specifies the inode number / mft record to read, including the sequence
- * number, which can be 0 if no sequence number checking is to be performed.
- *
- * Then, allocate a buffer for the mft record, read the mft record from the
- * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec).
- * The mft record is mst deprotected and sanity checked for validity and we
- * abort if deprotection or checks fail.
- *
- * Finally attach the ntfs inode to its base inode @base_ni and return a
- * pointer to the ntfs_inode structure on success or NULL on error, with errno
- * set to the error code.
- *
- * Note, extent inodes are never closed directly. They are automatically
- * disposed off by the closing of the base inode.
- */
-ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const leMFT_REF mref)
-{
- u64 mft_no = MREF_LE(mref);
- ntfs_inode *ni;
- ntfs_inode **extent_nis;
- int i;
-
- if (!base_ni) {
- errno = EINVAL;
- return NULL;
- }
- ntfs_log_trace("Opening extent inode 0x%llx "
- "(base MFT record 0x%llx).\n",
- (unsigned long long)mft_no,
- (unsigned long long)base_ni->mft_no);
- /* Is the extent inode already open and attached to the base inode? */
- if (base_ni->nr_extents > 0) {
- extent_nis = base_ni->u.extent_nis;
- for (i = 0; i < base_ni->nr_extents; i++) {
- u16 seq_no;
-
- ni = extent_nis[i];
- if (mft_no != ni->mft_no)
- continue;
- /* Verify the sequence number if given. */
- seq_no = MSEQNO_LE(mref);
- if (seq_no && seq_no != le16_to_cpu(
- ni->mrec->sequence_number)) {
- ntfs_log_debug("Found stale extent mft "
- "reference! Corrupt file "
- "system. Run chkdsk.\n");
- errno = EIO;
- return NULL;
- }
- /* We are done, return the extent inode. */
- return ni;
- }
- }
- /* Wasn't there, we need to load the extent inode. */
- ni = __ntfs_inode_allocate(base_ni->vol);
- if (!ni)
- return NULL;
- if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec,
- NULL))
- goto err_out;
- ni->mft_no = mft_no;
- ni->nr_extents = -1;
- ni->u.base_ni = base_ni;
- /* Attach extent inode to base inode, reallocating memory if needed. */
- if (!(base_ni->nr_extents & 3)) {
- i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
-
- extent_nis = (ntfs_inode**)ntfs_malloc(i);
- if (!extent_nis)
- goto err_out;
- if (base_ni->nr_extents) {
- memcpy(extent_nis, base_ni->u.extent_nis,
- i - 4 * sizeof(ntfs_inode *));
- free(base_ni->u.extent_nis);
- }
- base_ni->u.extent_nis = extent_nis;
- }
- base_ni->u.extent_nis[base_ni->nr_extents++] = ni;
- return ni;
-err_out:
- i = errno;
- __ntfs_inode_release(ni);
- errno = i;
- ntfs_log_perror("Failed to open extent inode");
- return NULL;
-}
-
-/**
- * ntfs_inode_attach_all_extents - attach all extents for target inode
- * @ni: opened ntfs inode for which perform attach
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_inode_attach_all_extents(ntfs_inode *ni)
-{
- ATTR_LIST_ENTRY *ale;
- u64 prev_attached = 0;
-
- if (!ni) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (ni->nr_extents == -1)
- ni = ni->u.base_ni;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- /* Inode haven't got attribute list, thus nothing to attach. */
- if (!NInoAttrList(ni))
- return 0;
-
- if (!ni->attr_list) {
- ntfs_log_trace("Corrupted in-memory structure.\n");
- errno = EINVAL;
- return -1;
- }
-
- /* Walk through attribute list and attach all extents. */
- errno = 0;
- ale = (ATTR_LIST_ENTRY *)ni->attr_list;
- while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
- if (ni->mft_no != MREF_LE(ale->mft_reference) &&
- prev_attached != MREF_LE(ale->mft_reference)) {
- if (!ntfs_extent_inode_open(ni, ale->mft_reference)) {
- ntfs_log_trace("Couldn't attach extent "
- "inode (attr type 0x%x "
- "references to it).\n",
- le32_to_cpu(ale->type));
- return -1;
- }
- prev_attached = MREF_LE(ale->mft_reference);
- }
- ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
- }
- return 0;
-}
-
-/**
- * ntfs_inode_sync_standard_information - update standard information attribute
- * @ni: ntfs inode to update standard information
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
-{
- ntfs_attr_search_ctx *ctx;
- STANDARD_INFORMATION *std_info;
- int err;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx)
- return -1;
- if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
- 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
- err = errno;
- ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
- "attribute.\n");
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
- }
- std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- std_info->file_attributes = ni->flags;
- std_info->creation_time = utc2ntfs(ni->creation_time);
- std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time);
- std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
- std_info->last_access_time = utc2ntfs(ni->last_access_time);
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-}
-
-/**
- * ntfs_inode_sync_file_name - update FILE_NAME attributes
- * @ni: ntfs inode to update FILE_NAME attributes
- *
- * Update all FILE_NAME attributes for inode @ni in the index.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-static int ntfs_inode_sync_file_name(ntfs_inode *ni)
-{
- ntfs_attr_search_ctx *ctx = NULL;
- ntfs_index_context *ictx;
- ntfs_inode *index_ni;
- FILE_NAME_ATTR *fn;
- int err = 0;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx) {
- err = errno;
- ntfs_log_trace("Failed to get attribute search context.\n");
- goto err_out;
- }
- /* Walk through all FILE_NAME attributes and update them. */
- while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {
- fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr +
- le16_to_cpu(ctx->attr->u.res.value_offset));
- if (MREF_LE(fn->parent_directory) == ni->mft_no) {
- /*
- * WARNING: We cheater here and obtain 2 attribute
- * search contexts for one inode (first we obtained
- * above, second will be obtained inside
- * ntfs_index_lookup), it's acceptable for library,
- * but will lock kernel.
- */
- index_ni = ni;
- } else
- index_ni = ntfs_inode_open(ni->vol,
- le64_to_cpu(fn->parent_directory));
- if (!index_ni) {
- if (!err)
- err = errno;
- ntfs_log_trace("Failed to open inode with index.\n");
- continue;
- }
- ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);
- if (!ictx) {
- if (!err)
- err = errno;
- ntfs_log_trace("Failed to get index context.\n");
- ntfs_inode_close(index_ni);
- continue;
- }
- if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
- if (!err) {
- if (errno == ENOENT)
- err = EIO;
- else
- err = errno;
- }
- ntfs_log_trace("Index lookup failed.\n");
- ntfs_index_ctx_put(ictx);
- ntfs_inode_close(index_ni);
- continue;
- }
- /* Update flags and file size. */
- fn = (FILE_NAME_ATTR *)ictx->data;
- fn->file_attributes =
- (fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) |
- (ni->flags & FILE_ATTR_VALID_FLAGS);
- fn->allocated_size = cpu_to_sle64(ni->allocated_size);
- fn->data_size = cpu_to_sle64(ni->data_size);
- fn->creation_time = utc2ntfs(ni->creation_time);
- fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
- fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
- fn->last_access_time = utc2ntfs(ni->last_access_time);
- ntfs_index_entry_mark_dirty(ictx);
- ntfs_index_ctx_put(ictx);
- if (ni != index_ni)
- ntfs_inode_close(index_ni);
- }
- /* Check for real error occurred. */
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto err_out;
- }
- ntfs_attr_put_search_ctx(ctx);
- if (err) {
- errno = err;
- return -1;
- }
- return 0;
-err_out:
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_inode_sync - write the inode (and its dirty extents) to disk
- * @ni: ntfs inode to write
- *
- * Write the inode @ni to disk as well as its dirty extent inodes if such
- * exist and @ni is a base inode. If @ni is an extent inode, only @ni is
- * written completely disregarding its base inode and any other extent inodes.
- *
- * For a base inode with dirty extent inodes if any writes fail for whatever
- * reason, the failing inode is skipped and the sync process is continued. At
- * the end the error condition that brought about the failure is returned. Thus
- * the smallest amount of data loss possible occurs.
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- * The following error codes are defined:
- * EINVAL - Invalid arguments were passed to the function.
- * EBUSY - Inode and/or one of its extents is busy, try again later.
- * EIO - I/O error while writing the inode (or one of its extents).
- */
-int ntfs_inode_sync(ntfs_inode *ni)
-{
- int err = 0;
-
- if (!ni) {
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- /* Update FILE_NAME's in the index. */
- if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
- NInoFileNameTestAndClearDirty(ni) &&
- ntfs_inode_sync_file_name(ni)) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- }
- ntfs_log_trace("Failed to sync FILE_NAME attributes.\n");
- NInoFileNameSetDirty(ni);
- }
-
- /* Write out attribute list from cache to disk. */
- if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
- NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
- ntfs_attr *na;
-
- na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
- if (!na) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- ntfs_log_trace("Attribute list sync failed "
- "(open failed).\n");
- }
- NInoAttrListSetDirty(ni);
- } else {
- if (na->data_size == ni->attr_list_size) {
- if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,
- ni->attr_list) !=
- ni->attr_list_size) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- ntfs_log_trace("Attribute list "
- "sync failed "
- "(write).\n");
- }
- NInoAttrListSetDirty(ni);
- }
- } else {
- err = EIO;
- ntfs_log_trace("Attribute list sync failed "
- "(invalid size).\n");
- NInoAttrListSetDirty(ni);
- }
- ntfs_attr_close(na);
- }
- }
-
- /* Write this inode out to the $MFT (and $MFTMirr if applicable). */
- if (NInoTestAndClearDirty(ni)) {
- /* Update STANDARD_INFORMATION. */
- if ((ni->mrec->flags & MFT_RECORD_IN_USE) &&
- ni->nr_extents != -1 &&
- ntfs_inode_sync_standard_information(ni)) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- }
- ntfs_log_trace("Failed to sync standard "
- "information.\n");
- }
- /* Write MFT record. */
- if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- }
- NInoSetDirty(ni);
- ntfs_log_trace("Base MFT record sync failed.\n");
- }
- }
-
- /* If this is a base inode with extents write all dirty extents, too. */
- if (ni->nr_extents > 0) {
- s32 i;
-
- for (i = 0; i < ni->nr_extents; ++i) {
- ntfs_inode *eni;
-
- eni = ni->u.extent_nis[i];
- if (NInoTestAndClearDirty(eni)) {
- if (ntfs_mft_record_write(eni->vol, eni->mft_no,
- eni->mrec)) {
- if (!err || errno == EIO) {
- err = errno;
- if (err != EIO)
- err = EBUSY;
- }
- NInoSetDirty(eni);
- ntfs_log_trace("Extent MFT record sync "
- "failed.\n");
- }
- }
- }
- }
-
- if (!err)
- return 0;
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_inode_add_attrlist - add attribute list to inode and fill it
- * @ni: opened ntfs inode to which add attribute list
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- * The following error codes are defined:
- * EINVAL - Invalid arguments were passed to the function.
- * EEXIST - Attribute list already exist.
- * EIO - Input/Ouput error occurred.
- * ENOMEM - Not enough memory to perform add.
- */
-int ntfs_inode_add_attrlist(ntfs_inode *ni)
-{
- int err;
- ntfs_attr_search_ctx *ctx;
- u8 *al, *aln;
- int al_len, al_allocated;
- ATTR_LIST_ENTRY *ale;
- ntfs_attr *na;
-
- if (!ni) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- if (NInoAttrList(ni) || ni->nr_extents) {
- ntfs_log_trace("Inode already has got attribute list.\n");
- errno = EEXIST;
- return -1;
- }
-
- al_allocated = 0x40;
- al_len = 0;
- al = malloc(al_allocated);
- NTFS_ON_DEBUG(memset(al, 0, 0x40)); /* Valgrind. */
- ale = (ATTR_LIST_ENTRY *) al;
- if (!al) {
- ntfs_log_trace("Not enough memory.\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* Form attribute list. */
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx) {
- err = errno;
- ntfs_log_trace("Couldn't get search context.\n");
- goto err_out;
- }
- /* Walk through all attributes. */
- while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {
- if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
- err = EIO;
- ntfs_log_trace("Attribute list already present.\n");
- goto put_err_out;
- }
- /* Calculate new length of attribute list. */
- al_len += (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
- ctx->attr->name_length + 7) & ~7;
- /* Allocate more memory if needed. */
- while (al_len > al_allocated) {
- al_allocated += 0x40;
- aln = realloc(al, al_allocated);
- NTFS_ON_DEBUG(memset(aln + al_allocated - 0x40, 0,
- 0x40)); /* Valgrind. */
- if (!aln) {
- ntfs_log_trace("Not enough memory.\n");
- err = ENOMEM;
- goto put_err_out;
- }
- ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al));
- al = aln;
- }
- /* Add attribute to attribute list. */
- ale->type = ctx->attr->type;
- ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) +
- sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7);
- ale->name_length = ctx->attr->name_length;
- ale->name_offset = (u8 *)ale->name - (u8 *)ale;
- if (ctx->attr->non_resident)
- ale->lowest_vcn = ctx->attr->u.nonres.lowest_vcn;
- else
- ale->lowest_vcn = 0;
- ale->mft_reference = MK_LE_MREF(ni->mft_no,
- le16_to_cpu(ni->mrec->sequence_number));
- ale->instance = ctx->attr->instance;
- memcpy(ale->name, (u8 *)ctx->attr +
- le16_to_cpu(ctx->attr->name_offset),
- ctx->attr->name_length * sizeof(ntfschar));
- ale = (ATTR_LIST_ENTRY *)(al + al_len);
- }
- /* Check for real error occurred. */
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto put_err_out;
- }
- /* Deallocate trailing memory. */
- aln = realloc(al, al_len);
- if (!aln) {
- err = errno;
- ntfs_log_trace("realloc() failed.\n");
- goto put_err_out;
- }
- al = aln;
-
- /* Set in-memory attribute list. */
- ni->attr_list = al;
- ni->attr_list_size = al_len;
- NInoSetAttrList(ni);
- NInoAttrListSetDirty(ni);
-
- /* Free space if there is not enough it for $ATTRIBUTE_LIST. */
- if (le32_to_cpu(ni->mrec->bytes_allocated) -
- le32_to_cpu(ni->mrec->bytes_in_use) <
- offsetof(ATTR_RECORD, u.res.resident_end)) {
- if (ntfs_inode_free_space(ni,
- offsetof(ATTR_RECORD, u.res.resident_end))) {
- /* Failed to free space. */
- err = errno;
- ntfs_log_trace("Failed to free space for "
- "$ATTRIBUTE_LIST.\n");
- goto rollback;
- }
- }
-
- /* Add $ATTRIBUTE_LIST to mft record. */
- if (ntfs_resident_attr_record_add(ni,
- AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
- err = errno;
- ntfs_log_trace("Couldn't add $ATTRIBUTE_LIST to MFT record.\n");
- goto rollback;
- }
-
- /* Resize it. */
- na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
- if (!na) {
- err = errno;
- ntfs_log_trace("Failed to open just added $ATTRIBUTE_LIST.\n");
- goto remove_attrlist_record;
- }
- if (ntfs_attr_truncate(na, al_len)) {
- err = errno;
- ntfs_log_trace("Failed to resize just added $ATTRIBUTE_LIST.\n");
- ntfs_attr_close(na);
- goto remove_attrlist_record;;
- }
- /* Done! */
- ntfs_attr_put_search_ctx(ctx);
- ntfs_attr_close(na);
- return 0;
-remove_attrlist_record:
- /* Prevent ntfs_attr_recorm_rm from freeing attribute list. */
- ni->attr_list = NULL;
- NInoClearAttrList(ni);
- /* Remove $ATTRIBUTE_LIST record. */
- ntfs_attr_reinit_search_ctx(ctx);
- if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,
- CASE_SENSITIVE, 0, NULL, 0, ctx)) {
- if (ntfs_attr_record_rm(ctx))
- ntfs_log_trace("Rollback failed. Failed to remove attribute "
- "list record.\n");
- } else
- ntfs_log_trace("Rollback failed. Couldn't find attribute list "
- "record.\n");
- /* Setup back in-memory runlist. */
- ni->attr_list = al;
- ni->attr_list_size = al_len;
- NInoSetAttrList(ni);
-rollback:
- /*
- * Scan attribute list for attributes that placed not in the base MFT
- * record and move them to it.
- */
- ntfs_attr_reinit_search_ctx(ctx);
- ale = (ATTR_LIST_ENTRY*)al;
- while ((u8*)ale < al + al_len) {
- if (MREF_LE(ale->mft_reference) != ni->mft_no) {
- if (!ntfs_attr_lookup(ale->type, ale->name,
- ale->name_length,
- CASE_SENSITIVE,
- sle64_to_cpu(ale->lowest_vcn),
- NULL, 0, ctx)) {
- if (ntfs_attr_record_move_to(ctx, ni))
- ntfs_log_trace("Rollback failed. Couldn't "
- "back attribute to base MFT record.\n");
- } else
- ntfs_log_trace("Rollback failed. ntfs_attr_lookup "
- "failed.\n");
- ntfs_attr_reinit_search_ctx(ctx);
- }
- ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length));
- }
- /* Remove in-memory attribute list. */
- ni->attr_list = NULL;
- ni->attr_list_size = 0;
- NInoClearAttrList(ni);
- NInoAttrListClearDirty(ni);
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
-err_out:
- free(al);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_inode_free_space - free space in the MFT record of inode
- * @ni: ntfs inode in which MFT record free space
- * @size: amount of space needed to free
- *
- * Return 0 on success or -1 on error with errno set to the error code.
- */
-int ntfs_inode_free_space(ntfs_inode *ni, int size)
-{
- ntfs_attr_search_ctx *ctx;
- int freed, err;
-
- if (!ni || size < 0) {
- ntfs_log_trace("Invalid arguments.\n");
- errno = EINVAL;
- return -1;
- }
-
- ntfs_log_trace("Entering for inode 0x%llx, size %d.\n",
- (long long) ni->mft_no, size);
-
- freed = (le32_to_cpu(ni->mrec->bytes_allocated) -
- le32_to_cpu(ni->mrec->bytes_in_use));
-
- if (size <= freed)
- return 0;
-
- ctx = ntfs_attr_get_search_ctx(ni, NULL);
- if (!ctx) {
- ntfs_log_trace("Failed to get attribute search context.\n");
- return -1;
- }
-
- /*
- * Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT
- * record. FIXME: I'm not sure in this, need to recheck. For now simply
- * do not move $STANDARD_INFORMATION at all.
- *
- * Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position
- * search context on first attribute after $STANDARD_INFORMATION and
- * $ATTRIBUTE_LIST.
- *
- * Why we reposition instead of simply skip this attributes during
- * enumeration? Because in case we have got only in-memory attribute
- * list ntfs_attr_lookup will fail when it will try to find
- * $ATTRIBUTE_LIST.
- */
- if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
- 0, ctx)) {
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- goto put_err_out;
- }
- if (ctx->attr->type == AT_END) {
- err = ENOSPC;
- goto put_err_out;
- }
- }
-
- while (1) {
- int record_size;
-
- /*
- * Check whether attribute is from different MFT record. If so,
- * find next, because we don't need such.
- */
- while (ctx->ntfs_ino->mft_no != ni->mft_no) {
- if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE,
- 0, NULL, 0, ctx)) {
- err = errno;
- if (errno != ENOENT) {
- ntfs_log_trace("Attribute lookup failed.\n");
- } else
- err = ENOSPC;
- goto put_err_out;
- }
- }
-
- record_size = le32_to_cpu(ctx->attr->length);
-
- /* Move away attribute. */
- if (ntfs_attr_record_move_away(ctx, 0)) {
- err = errno;
- ntfs_log_trace("Failed to move out attribute.\n");
- break;
- }
- freed += record_size;
-
- /* Check whether we done. */
- if (size <= freed) {
- ntfs_attr_put_search_ctx(ctx);
- return 0;
- }
-
- /*
- * Reposition to first attribute after $STANDARD_INFORMATION and
- * $ATTRIBUTE_LIST (see comments upwards).
- */
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0,
- NULL, 0, ctx)) {
- if (errno != ENOENT) {
- err = errno;
- ntfs_log_trace("Attribute lookup failed.\n");
- break;
- }
- if (ctx->attr->type == AT_END) {
- err = ENOSPC;
- break;
- }
- }
- }
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- if (err == ENOSPC)
- ntfs_log_trace("No attributes left that can be moved out.\n");
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_inode_update_times - update selected time fields for ntfs inode
- * @ni: ntfs inode for which update time fields
- * @mask: select which time fields should be updated
- *
- * This function updates time fields to current time. Fields to update are
- * selected using @mask (see enum @ntfs_time_update_flags for posssible values).
- */
-void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
-{
- time_t now;
-
- if (!ni) {
- ntfs_log_error("%s(): Invalid arguments.\n", "ntfs_inode_update_times");
- return;
- }
- if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) ||
- NVolReadOnly(ni->vol) || !mask)
- return;
-
- now = time(NULL);
- if (mask & NTFS_UPDATE_ATIME)
- ni->last_access_time = now;
- if (mask & NTFS_UPDATE_MTIME)
- ni->last_data_change_time = now;
- if (mask & NTFS_UPDATE_CTIME)
- ni->last_mft_change_time = now;
- NInoFileNameSetDirty(ni);
- NInoSetDirty(ni);
-}
-
-/**
- * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute
- * @mft_no: mft record number where @attr is present
- * @attr: attribute record used to check for the $Bad attribute
- *
- * Check if the mft record given by @mft_no and @attr contains the bad sector
- * list. Please note that mft record numbers describing $Badclus extent inodes
- * will not match the current $Badclus:$Bad check.
- *
- * On success return 1 if the file is $Badclus:$Bad, otherwise return 0.
- * On error return -1 with errno set to the error code.
- */
-int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
-{
- int len, ret = 0;
- ntfschar *ustr;
-
- if (!attr) {
- ntfs_log_error("Invalid argument.\n");
- errno = EINVAL;
- return -1;
- }
-
- if (mft_no != FILE_BadClus)
- return 0;
-
- if (attr->type != AT_DATA)
- return 0;
-
- if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) {
- ntfs_log_perror("Couldn't convert '$Bad' to Unicode");
- return -1;
- }
-
- if (ustr && ntfs_names_are_equal(ustr, len,
- (ntfschar *)((u8 *)attr + le16_to_cpu(
- attr->name_offset)), attr->name_length, 0, NULL, 0))
- ret = 1;
-
- ntfs_ucsfree(ustr);
-
- return ret;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/lcnalloc.c b/usr/src/lib/libntfs/common/libntfs/lcnalloc.c
deleted file mode 100644
index 7f42f8a564..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/lcnalloc.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/**
- * lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2004 Anton Altaparmakov
- * Copyright (c) 2004 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "attrib.h"
-#include "bitmap.h"
-#include "debug.h"
-#include "runlist.h"
-#include "volume.h"
-#include "lcnalloc.h"
-#include "logging.h"
-
-/**
- * ntfs_cluster_alloc - allocate clusters on an ntfs volume
- * @vol: mounted ntfs volume on which to allocate the clusters
- * @start_vcn: vcn to use for the first allocated cluster
- * @count: number of clusters to allocate
- * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
- * @zone: zone from which to allocate the clusters
- *
- * Allocate @count clusters preferably starting at cluster @start_lcn or at the
- * current allocator position if @start_lcn is -1, on the mounted ntfs volume
- * @vol. @zone is either DATA_ZONE for allocation of normal clusters and
- * MFT_ZONE for allocation of clusters for the master file table, i.e. the
- * $MFT/$DATA attribute.
- *
- * On success return a runlist describing the allocated cluster(s).
- *
- * On error return NULL with errno set to the error code.
- *
- * Notes on the allocation algorithm
- * =================================
- *
- * There are two data zones. First is the area between the end of the mft zone
- * and the end of the volume, and second is the area between the start of the
- * volume and the start of the mft zone. On unmodified/standard NTFS 1.x
- * volumes, the second data zone doesn't exist due to the mft zone being
- * expanded to cover the start of the volume in order to reserve space for the
- * mft bitmap attribute.
- *
- * 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 up to 8192 bytes at a time, so we
- * need to cope with crossing over boundaries of two buffers. Further, the fact
- * that the allocator allows for caller supplied hints as to the location of
- * where allocation should begin and the fact that the allocator keeps track of
- * where in the data zones the next natural allocation should occur, contribute
- * to the complexity of the function. But it should all be worthwhile, because
- * this allocator 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: 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 it might even be correct not to do 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)
- */
-runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
- LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
-{
- LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
- LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
- s64 clusters, br;
- runlist *rl = NULL, *trl;
- u8 *buf, *byte;
- int err = 0, rlpos, rlsize, buf_size;
- u8 pass, done_zones, search_zone, need_writeback, bit;
-
- ntfs_log_trace("Entering with count = 0x%llx, start_lcn = 0x%llx, zone = "
- "%s_ZONE.\n", (long long)count, (long long)start_lcn,
- zone == MFT_ZONE ? "MFT" : "DATA");
- if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
- (s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
- ntfs_log_trace("Invalid arguments!\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* Return empty runlist if @count == 0 */
- if (!count) {
- rl = ntfs_malloc(0x1000);
- if (!rl)
- return NULL;
- rl[0].vcn = start_vcn;
- rl[0].lcn = LCN_RL_NOT_MAPPED;
- rl[0].length = 0;
- return rl;
- }
-
- /* Allocate memory. */
- buf = (u8*)ntfs_malloc(8192);
- if (!buf)
- return NULL;
- /*
- * If no specific @start_lcn was requested, use the current data zone
- * position, otherwise use the requested @start_lcn 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,
- * we either start at the current position within the mft zone or at
- * the specified position. 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 = start_lcn;
- 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 == DATA_ZONE && zone_start >= vol->mft_zone_start &&
- zone_start < vol->mft_zone_end) {
- zone_start = vol->mft_zone_end;
- /*
- * Starting at beginning of data1_zone which means a single
- * pass in this zone is sufficient.
- */
- pass = 2;
- } else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start ||
- zone_start >= vol->mft_zone_end)) {
- zone_start = vol->mft_lcn;
- if (!vol->mft_zone_end)
- zone_start = 0;
- /*
- * Starting at beginning of volume which means a single pass
- * is sufficient.
- */
- pass = 2;
- }
- if (zone == MFT_ZONE) {
- zone_end = vol->mft_zone_end;
- search_zone = 1;
- } else /* 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;
- }
- }
- /*
- * bmp_pos is the current bit position inside the bitmap. We use
- * bmp_initial_pos to determine whether or not to do a zone switch.
- */
- bmp_pos = bmp_initial_pos = zone_start;
-
- /* Loop until all clusters are allocated, i.e. clusters == 0. */
- clusters = count;
- rlpos = rlsize = 0;
- while (1) {
- ntfs_log_trace("Start of outer while loop: done_zones = 0x%x, "
- "search_zone = %i, pass = %i, zone_start = "
- "0x%llx, zone_end = 0x%llx, bmp_initial_pos = "
- "0x%llx, bmp_pos = 0x%llx, rlpos = %i, rlsize = "
- "%i.\n", done_zones, search_zone, pass,
- (long long)zone_start, (long long)zone_end,
- (long long)bmp_initial_pos, (long long)bmp_pos,
- rlpos, rlsize);
- /* Loop until we run out of free clusters. */
- last_read_pos = bmp_pos >> 3;
- ntfs_log_trace("last_read_pos = 0x%llx.\n", (long long)last_read_pos);
- br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, 8192, buf);
- if (br <= 0) {
- if (!br) {
- /* Reached end of attribute. */
- ntfs_log_trace("End of attribute reached. Skipping "
- "to zone_pass_done.\n");
- goto zone_pass_done;
- }
- err = errno;
- ntfs_log_trace("ntfs_attr_pread() failed. Aborting.\n");
- goto err_ret;
- }
- /*
- * We might have read less than 8192 bytes if we are close to
- * the end of the attribute.
- */
- buf_size = (int)br << 3;
- lcn = bmp_pos & 7;
- bmp_pos &= ~7;
- need_writeback = 0;
- ntfs_log_trace("Before inner while loop: buf_size = %i, lcn = "
- "0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
- buf_size, (long long)lcn, (long long)bmp_pos,
- need_writeback);
- while (lcn < buf_size && lcn + bmp_pos < zone_end) {
- byte = buf + (lcn >> 3);
- ntfs_log_trace("In inner while loop: buf_size = %i, lcn = "
- "0x%llx, bmp_pos = 0x%llx, "
- "need_writeback = %i, byte ofs = 0x%x, "
- "*byte = 0x%x.\n", buf_size,
- (long long)lcn, (long long)bmp_pos,
- need_writeback, (unsigned int)(lcn >> 3),
- (unsigned int)*byte);
- /* Skip full bytes. */
- if (*byte == 0xff) {
- lcn = (lcn + 8) & ~7;
- ntfs_log_trace("continuing while loop 1.\n");
- continue;
- }
- bit = 1 << (lcn & 7);
- ntfs_log_trace("bit = %i.\n", bit);
- /* If the bit is already set, go onto the next one. */
- if (*byte & bit) {
- lcn++;
- ntfs_log_trace("continuing while loop 2.\n");
- continue;
- }
- /* Reallocate memory if necessary. */
- if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
- ntfs_log_trace("Reallocating space.\n");
- if (!rl)
- ntfs_log_trace("First free bit is at LCN = "
- "0x%llx.\n", (long long)(lcn + bmp_pos));
- rlsize += 4096;
- trl = (runlist*)realloc(rl, rlsize);
- if (!trl) {
- err = ENOMEM;
- ntfs_log_trace("Failed to allocate memory, "
- "going to wb_err_ret.\n");
- goto wb_err_ret;
- }
- rl = trl;
- ntfs_log_trace("Reallocated memory, rlsize = "
- "0x%x.\n", rlsize);
- }
- /* Allocate the bitmap bit. */
- *byte |= bit;
- vol->nr_free_clusters--;
- /* We need to write this bitmap buffer back to disk! */
- need_writeback = 1;
- ntfs_log_trace("*byte = 0x%x, need_writeback is set.\n",
- (unsigned int)*byte);
- /*
- * Coalesce with previous run if adjacent LCNs.
- * Otherwise, append a new run.
- */
- ntfs_log_trace("Adding run (lcn 0x%llx, len 0x%llx), "
- "prev_lcn = 0x%llx, lcn = 0x%llx, "
- "bmp_pos = 0x%llx, prev_run_len = "
- "0x%llx, rlpos = %i.\n",
- (long long)(lcn + bmp_pos), 1LL,
- (long long)prev_lcn, (long long)lcn,
- (long long)bmp_pos,
- (long long)prev_run_len, rlpos);
- if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
- ntfs_log_trace("Coalescing to run (lcn 0x%llx, len "
- "0x%llx).\n",
- (long long)rl[rlpos - 1].lcn,
- (long long) rl[rlpos - 1].length);
- rl[rlpos - 1].length = ++prev_run_len;
- ntfs_log_trace("Run now (lcn 0x%llx, len 0x%llx), "
- "prev_run_len = 0x%llx.\n",
- (long long)rl[rlpos - 1].lcn,
- (long long)rl[rlpos - 1].length,
- (long long)prev_run_len);
- } else {
- if (rlpos) {
- ntfs_log_trace("Adding new run, (previous "
- "run lcn 0x%llx, len 0x%llx).\n",
- (long long) rl[rlpos - 1].lcn,
- (long long) rl[rlpos - 1].length);
- rl[rlpos].vcn = rl[rlpos - 1].vcn +
- prev_run_len;
- } else {
- ntfs_log_trace("Adding new run, is first run.\n");
- rl[rlpos].vcn = start_vcn;
- }
- rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
- rl[rlpos].length = prev_run_len = 1;
- rlpos++;
- }
- /* Done? */
- if (!--clusters) {
- LCN tc;
- /*
- * Update the current zone position. Positions
- * of already scanned zones have been updated
- * during the respective zone switches.
- */
- tc = lcn + bmp_pos + 1;
- ntfs_log_trace("Done. Updating current zone "
- "position, tc = 0x%llx, search_zone = %i.\n",
- (long long)tc, search_zone);
- switch (search_zone) {
- case 1:
- ntfs_log_trace("Before checks, vol->mft_zone_pos = 0x%llx.\n",
- (long long) 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 = 0;
- } else if ((bmp_initial_pos >=
- vol->mft_zone_pos ||
- tc > vol->mft_zone_pos)
- && tc >= vol->mft_lcn)
- vol->mft_zone_pos = tc;
- ntfs_log_trace("After checks, vol->mft_zone_pos = 0x%llx.\n",
- (long long) vol->mft_zone_pos);
- break;
- case 2:
- ntfs_log_trace("Before checks, vol->data1_zone_pos = 0x%llx.\n",
- (long long) vol->data1_zone_pos);
- if (tc >= vol->nr_clusters)
- vol->data1_zone_pos =
- vol->mft_zone_end;
- else if ((bmp_initial_pos >=
- vol->data1_zone_pos ||
- tc > vol->data1_zone_pos)
- && tc >= vol->mft_zone_end)
- vol->data1_zone_pos = tc;
- ntfs_log_trace("After checks, vol->data1_zone_pos = 0x%llx.\n",
- (long long) vol->data1_zone_pos);
- break;
- case 4:
- ntfs_log_trace("Before checks, vol->data2_zone_pos = 0x%llx.\n",
- (long long) vol->data2_zone_pos);
- if (tc >= vol->mft_zone_start)
- vol->data2_zone_pos = 0;
- else if (bmp_initial_pos >=
- vol->data2_zone_pos ||
- tc > vol->data2_zone_pos)
- vol->data2_zone_pos = tc;
- ntfs_log_trace("After checks, vol->data2_zone_pos = 0x%llx.\n",
- (long long) vol->data2_zone_pos);
- break;
- default:
- free(rl);
- free(buf);
- NTFS_BUG("switch (search_zone) 1");
- return NULL;
- }
- ntfs_log_trace("Going to done_ret.\n");
- goto done_ret;
- }
- lcn++;
- }
- bmp_pos += buf_size;
- ntfs_log_trace("After inner while loop: buf_size = 0x%x, lcn = "
- "0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
- buf_size, (long long)lcn,
- (long long)bmp_pos, need_writeback);
- if (need_writeback) {
- s64 bw;
- ntfs_log_trace("Writing back.\n");
- need_writeback = 0;
- bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos,
- br, buf);
- if (bw != br) {
- if (bw == -1)
- err = errno;
- else
- err = EIO;
- ntfs_log_trace("Bitmap writeback failed in read next "
- "buffer code path with error code %i.\n", err);
- goto err_ret;
- }
- }
- if (bmp_pos < zone_end) {
- ntfs_log_trace("Continuing outer while loop, bmp_pos = "
- "0x%llx, zone_end = 0x%llx.\n",
- (long long)bmp_pos,
- (long long)zone_end);
- continue;
- }
-zone_pass_done: /* Finished with the current zone pass. */
- ntfs_log_trace("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 = 0;
- break;
- default:
- NTFS_BUG("switch (search_zone) 2");
- }
- /* Sanity check. */
- if (zone_end < zone_start)
- zone_end = zone_start;
- bmp_pos = zone_start;
- ntfs_log_trace("Continuing outer while loop, pass = 2, "
- "zone_start = 0x%llx, zone_end = "
- "0x%llx, bmp_pos = 0x%llx.\n",
- zone_start, zone_end, bmp_pos);
- continue;
- } /* pass == 2 */
-done_zones_check:
- ntfs_log_trace("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_log_trace("Switching zone.\n");
- /* Now switch to the next zone we haven't done yet. */
- pass = 1;
- switch (search_zone) {
- case 1:
- ntfs_log_trace("Switching from mft zone to data1 "
- "zone.\n");
- /* Update mft zone position. */
- if (rlpos) {
- LCN tc;
- ntfs_log_trace("Before checks, vol->mft_zone_pos = 0x%llx.\n",
- (long long) vol->mft_zone_pos);
- tc = rl[rlpos - 1].lcn +
- rl[rlpos - 1].length;
- if (tc >= vol->mft_zone_end) {
- vol->mft_zone_pos =
- vol->mft_lcn;
- if (!vol->mft_zone_end)
- vol->mft_zone_pos = 0;
- } else if ((bmp_initial_pos >=
- vol->mft_zone_pos ||
- tc > vol->mft_zone_pos)
- && tc >= vol->mft_lcn)
- vol->mft_zone_pos = tc;
- ntfs_log_trace("After checks, vol->mft_zone_pos = 0x%llx.\n",
- (long long) vol->mft_zone_pos);
- }
- /* Switch from mft zone to data1 zone. */
-switch_to_data1_zone: search_zone = 2;
- zone_start = bmp_initial_pos =
- 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_log_trace("Switching from data1 zone to data2 "
- "zone.\n");
- /* Update data1 zone position. */
- if (rlpos) {
- LCN tc;
- ntfs_log_trace("Before checks, vol->data1_zone_pos = 0x%llx.\n",
- (long long) vol->data1_zone_pos);
- tc = rl[rlpos - 1].lcn +
- rl[rlpos - 1].length;
- if (tc >= vol->nr_clusters)
- vol->data1_zone_pos =
- vol->mft_zone_end;
- else if ((bmp_initial_pos >=
- vol->data1_zone_pos ||
- tc > vol->data1_zone_pos)
- && tc >= vol->mft_zone_end)
- vol->data1_zone_pos = tc;
- ntfs_log_trace("After checks, vol->data1_zone_pos = 0x%llx.\n",
- (long long) vol->data1_zone_pos);
- }
- /* Switch from data1 zone to data2 zone. */
- search_zone = 4;
- zone_start = bmp_initial_pos =
- 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 =
- bmp_initial_pos = 0;
- pass = 2;
- }
- break;
- case 4:
- ntfs_log_debug("Switching from data2 zone to data1 "
- "zone.\n");
- /* Update data2 zone position. */
- if (rlpos) {
- LCN tc;
- ntfs_log_trace("Before checks, vol->data2_zone_pos = 0x%llx.\n",
- (long long) vol->data2_zone_pos);
- tc = rl[rlpos - 1].lcn +
- rl[rlpos - 1].length;
- if (tc >= vol->mft_zone_start)
- vol->data2_zone_pos = 0;
- else if (bmp_initial_pos >=
- vol->data2_zone_pos ||
- tc > vol->data2_zone_pos)
- vol->data2_zone_pos = tc;
- ntfs_log_trace("After checks, vol->data2_zone_pos = 0x%llx.\n",
- (long long) vol->data2_zone_pos);
- }
- /* Switch from data2 zone to data1 zone. */
- goto switch_to_data1_zone; /* See above. */
- default:
- NTFS_BUG("switch (search_zone) 3");
- }
- ntfs_log_trace("After zone switch, search_zone = %i, pass = "
- "%i, bmp_initial_pos = 0x%llx, "
- "zone_start = 0x%llx, zone_end = "
- "0x%llx.\n", search_zone, pass,
- (long long)bmp_initial_pos,
- (long long)zone_start,
- (long long)zone_end);
- bmp_pos = zone_start;
- if (zone_start == zone_end) {
- ntfs_log_trace("Empty zone, going to "
- "done_zones_check.\n");
- /* Empty zone. Don't bother searching it. */
- goto done_zones_check;
- }
- ntfs_log_trace("Continuing outer while loop.\n");
- continue;
- } /* done_zones == 7 */
- ntfs_log_trace("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_log_trace("vol->mft_zone_start = 0x%llx, vol->mft_zone_end = "
- "0x%llx, mft_zone_size = 0x%llx.\n",
- (long long)vol->mft_zone_start,
- (long long)vol->mft_zone_end,
- (long long)mft_zone_size);
- if (zone == MFT_ZONE || mft_zone_size <= 0) {
- ntfs_log_trace("No free clusters left, going to err_ret.\n");
- /* Really no more space left on device. */
- err = ENOSPC;
- goto err_ret;
- } /* zone == DATA_ZONE && mft_zone_size > 0 */
- ntfs_log_trace("Shrinking mft zone.\n");
- zone_end = vol->mft_zone_end;
- mft_zone_size >>= 1;
- if (mft_zone_size > 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 = 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 = 0;
- }
- bmp_pos = zone_start = bmp_initial_pos =
- vol->data1_zone_pos = vol->mft_zone_end;
- search_zone = 2;
- pass = 2;
- done_zones &= ~2;
- ntfs_log_trace("After shrinking mft zone, mft_zone_size = 0x%llx, "
- "vol->mft_zone_start = 0x%llx, "
- "vol->mft_zone_end = 0x%llx, vol->mft_zone_pos "
- "= 0x%llx, search_zone = 2, pass = 2, "
- "dones_zones = 0x%x, zone_start = 0x%llx, "
- "zone_end = 0x%llx, vol->data1_zone_pos = "
- "0x%llx, continuing outer while loop.\n",
- (long long)mft_zone_size,
- (long long)vol->mft_zone_start,
- (long long)vol->mft_zone_end,
- (long long)vol->mft_zone_pos,
- done_zones,
- (long long)zone_start,
- (long long)zone_end,
- (long long)vol->data1_zone_pos);
- }
- ntfs_log_debug("After outer while loop.\n");
-done_ret:
- ntfs_log_debug("At done_ret.\n");
- /* Add runlist terminator element. */
- rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
- rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
- rl[rlpos].length = 0;
- if (need_writeback) {
- s64 bw;
- ntfs_log_trace("Writing back.\n");
- need_writeback = 0;
- bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
- if (bw != br) {
- if (bw < 0)
- err = errno;
- else
- err = EIO;
- ntfs_log_trace("Bitmap writeback failed in done code path "
- "with error code %i.\n", err);
- goto err_ret;
- }
- }
-done_err_ret:
- ntfs_log_debug("At done_err_ret (follows done_ret).\n");
- free(buf);
- /* Done! */
- if (!err)
- return rl;
- ntfs_log_trace("Failed to allocate clusters. Returning with error code "
- "%i.\n", err);
- errno = err;
- return NULL;
-wb_err_ret:
- ntfs_log_trace("At wb_err_ret.\n");
- if (need_writeback) {
- s64 bw;
- ntfs_log_trace("Writing back.\n");
- need_writeback = 0;
- bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
- if (bw != br) {
- if (bw < 0)
- err = errno;
- else
- err = EIO;
- ntfs_log_trace("Bitmap writeback failed in error code path "
- "with error code %i.\n", err);
- }
- }
-err_ret:
- ntfs_log_trace("At err_ret.\n");
- if (rl) {
- if (err == ENOSPC) {
- ntfs_log_trace("err = ENOSPC, first free lcn = 0x%llx, could "
- "allocate up to = 0x%llx clusters.\n",
- (long long)rl[0].lcn,
- (long long)count - clusters);
- }
- /* Add runlist terminator element. */
- rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
- rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
- rl[rlpos].length = 0;
- /* Deallocate all allocated clusters. */
- ntfs_log_trace("Deallocating allocated clusters.\n");
- ntfs_cluster_free_from_rl(vol, rl);
- /* Free the runlist. */
- free(rl);
- rl = NULL;
- } else {
- if (err == ENOSPC) {
- ntfs_log_trace("No space left at all, err = ENOSPC, first "
- "free lcn = 0x%llx.\n",
- (long long)vol->data1_zone_pos);
- }
- }
- ntfs_log_trace("rl = NULL, going to done_err_ret.\n");
- goto done_err_ret;
-}
-
-/**
- * ntfs_cluster_free_from_rl - free clusters from runlist
- * @vol: mounted ntfs volume on which to free the clusters
- * @rl: runlist from which deallocate clusters
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
-{
- ntfs_log_trace("Entering.\n");
-
- for (; rl->length; rl++) {
-
- ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
- (long long)rl->lcn, (long long)rl->length);
-
- if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na,
- rl->lcn, rl->length)) {
- int eo = errno;
- ntfs_log_trace("Eeek! Deallocation of clusters failed.\n");
- errno = eo;
- return -1;
- }
- }
- return 0;
-}
-
-/**
- * ntfs_cluster_free - free clusters on an ntfs volume
- * @vol: mounted ntfs volume on which to free the clusters
- * @na: attribute whose runlist describes the clusters to free
- * @start_vcn: vcn in @rl at which to start freeing clusters
- * @count: number of clusters to free or -1 for all clusters
- *
- * Free @count clusters starting at the cluster @start_vcn in the runlist
- * described by the attribute @na from the mounted ntfs volume @vol.
- *
- * If @count is -1, all clusters from @start_vcn to the end of the runlist
- * are deallocated.
- *
- * On success return the number of deallocated clusters (not counting sparse
- * clusters) and on error return -1 with errno set to the error code.
- */
-int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
-{
- runlist *rl;
- s64 nr_freed, delta, to_free;
-
- if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
- (count < 0 && count != -1)) {
- ntfs_log_trace("Invalid arguments!\n");
- errno = EINVAL;
- return -1;
- }
- ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
- "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
- na->type, (long long)count, (long long)start_vcn);
-
- rl = ntfs_attr_find_vcn(na, start_vcn);
- if (!rl) {
- if (errno == ENOENT)
- return 0;
- else
- return -1;
- }
-
- if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
- errno = EIO;
- return -1;
- }
-
- /* Find the starting cluster inside the run that needs freeing. */
- delta = start_vcn - rl->vcn;
-
- /* The number of clusters in this run that need freeing. */
- to_free = rl->length - delta;
- if (count >= 0 && to_free > count)
- to_free = count;
-
- if (rl->lcn != LCN_HOLE) {
- /* Do the actual freeing of the clusters in this run. */
- if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
- to_free))
- return -1;
- /* We have freed @to_free real clusters. */
- nr_freed = to_free;
- } else {
- /* No real clusters were freed. */
- nr_freed = 0;
- }
-
- /* Go to the next run and adjust the number of clusters left to free. */
- ++rl;
- if (count >= 0)
- count -= to_free;
-
- /*
- * Loop over the remaining runs, using @count as a capping value, and
- * free them.
- */
- for (; rl->length && count != 0; ++rl) {
- // FIXME: Need to try ntfs_attr_map_runlist() for attribute
- // list support! (AIA)
- if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
- // FIXME: Eeek! We need rollback! (AIA)
- ntfs_log_trace("Eeek! invalid lcn (= %lli). Should attempt "
- "to map runlist! Leaving inconsistent "
- "metadata!\n", (long long)rl->lcn);
- errno = EIO;
- return -1;
- }
-
- /* The number of clusters in this run that need freeing. */
- to_free = rl->length;
- if (count >= 0 && to_free > count)
- to_free = count;
-
- if (rl->lcn != LCN_HOLE) {
- /* Do the actual freeing of the clusters in the run. */
- if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
- to_free)) {
- int eo = errno;
-
- // FIXME: Eeek! We need rollback! (AIA)
- ntfs_log_trace("Eeek! bitmap clear run failed. "
- "Leaving inconsistent metadata!\n");
- errno = eo;
- return -1;
- }
- /* We have freed @to_free real clusters. */
- nr_freed += to_free;
- }
-
- if (count >= 0)
- count -= to_free;
- }
-
- if (count != -1 && count != 0) {
- // FIXME: Eeek! BUG()
- ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving "
- "inconsistent metadata!\n", (long long)count);
- errno = EIO;
- return -1;
- }
-
- /* Done. Return the number of actual clusters that were freed. */
- return nr_freed;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/logfile.c b/usr/src/lib/libntfs/common/libntfs/logfile.c
deleted file mode 100644
index 054bd2f088..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/logfile.c
+++ /dev/null
@@ -1,769 +0,0 @@
-/**
- * logfile.c - NTFS journal handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2005 Anton Altaparmakov
- * Copyright (c) 2005 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "debug.h"
-#include "logfile.h"
-#include "volume.h"
-#include "mst.h"
-#include "logging.h"
-
-/**
- * ntfs_check_restart_page_header - check the page header for consistency
- * @rp: restart page header to check
- * @pos: position in logfile at which the restart page header resides
- *
- * Check the restart page header @rp for consistency and return TRUE if it is
- * consistent and FALSE otherwise.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- */
-static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
-{
- u32 logfile_system_page_size, logfile_log_page_size;
- u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
- BOOL have_usa = TRUE;
-
- ntfs_log_trace("Entering.\n");
- /*
- * If the system or log page sizes are smaller than the ntfs block size
- * or either is not a power of 2 we cannot handle this log file.
- */
- logfile_system_page_size = le32_to_cpu(rp->system_page_size);
- logfile_log_page_size = le32_to_cpu(rp->log_page_size);
- if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
- logfile_log_page_size < NTFS_BLOCK_SIZE ||
- logfile_system_page_size &
- (logfile_system_page_size - 1) ||
- logfile_log_page_size & (logfile_log_page_size - 1)) {
- ntfs_log_error("$LogFile uses unsupported page size.\n");
- return FALSE;
- }
- /*
- * We must be either at !pos (1st restart page) or at pos = system page
- * size (2nd restart page).
- */
- if (pos && pos != logfile_system_page_size) {
- ntfs_log_error("Found restart area in incorrect "
- "position in $LogFile.\n");
- return FALSE;
- }
- /* We only know how to handle version 1.1. */
- if (sle16_to_cpu(rp->major_ver) != 1 ||
- sle16_to_cpu(rp->minor_ver) != 1) {
- ntfs_log_error("$LogFile version %i.%i is not "
- "supported. (This driver supports version "
- "1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
- (int)sle16_to_cpu(rp->minor_ver));
- return FALSE;
- }
- /*
- * If chkdsk has been run the restart page may not be protected by an
- * update sequence array.
- */
- if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
- have_usa = FALSE;
- goto skip_usa_checks;
- }
- /* Verify the size of the update sequence array. */
- usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
- if (usa_count != le16_to_cpu(rp->usa_count)) {
- ntfs_log_error("$LogFile restart page specifies "
- "inconsistent update sequence array count.\n");
- return FALSE;
- }
- /* Verify the position of the update sequence array. */
- usa_ofs = le16_to_cpu(rp->usa_ofs);
- usa_end = usa_ofs + usa_count * sizeof(u16);
- if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
- usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
- ntfs_log_error("$LogFile restart page specifies "
- "inconsistent update sequence array offset.\n");
- return FALSE;
- }
-skip_usa_checks:
- /*
- * Verify the position of the restart area. It must be:
- * - aligned to 8-byte boundary,
- * - after the update sequence array, and
- * - within the system page size.
- */
- ra_ofs = le16_to_cpu(rp->restart_area_offset);
- if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
- ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
- ra_ofs > logfile_system_page_size) {
- ntfs_log_error("$LogFile restart page specifies "
- "inconsistent restart area offset.\n");
- return FALSE;
- }
- /*
- * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
- * set.
- */
- if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
- ntfs_log_error("$LogFile restart page is not modified "
- "by chkdsk but a chkdsk LSN is specified.\n");
- return FALSE;
- }
- ntfs_log_trace("Done.\n");
- return TRUE;
-}
-
-/**
- * ntfs_check_restart_area - check the restart area for consistency
- * @rp: restart page whose restart area to check
- *
- * Check the restart area of the restart page @rp for consistency and return
- * TRUE if it is consistent and FALSE otherwise.
- *
- * This function assumes that the restart page header has already been
- * consistency checked.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- */
-static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
-{
- u64 file_size;
- RESTART_AREA *ra;
- u16 ra_ofs, ra_len, ca_ofs;
- u8 fs_bits;
-
- ntfs_log_trace("Entering.\n");
- ra_ofs = le16_to_cpu(rp->restart_area_offset);
- ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
- /*
- * Everything before ra->file_size must be before the first word
- * protected by an update sequence number. This ensures that it is
- * safe to access ra->client_array_offset.
- */
- if (ra_ofs + offsetof(RESTART_AREA, file_size) >
- NTFS_BLOCK_SIZE - sizeof(u16)) {
- ntfs_log_error("$LogFile restart area specifies "
- "inconsistent file offset.\n");
- return FALSE;
- }
- /*
- * Now that we can access ra->client_array_offset, make sure everything
- * up to the log client array is before the first word protected by an
- * update sequence number. This ensures we can access all of the
- * restart area elements safely. Also, the client array offset must be
- * aligned to an 8-byte boundary.
- */
- ca_ofs = le16_to_cpu(ra->client_array_offset);
- if (((ca_ofs + 7) & ~7) != ca_ofs ||
- ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE -
- sizeof(u16))) {
- ntfs_log_error("$LogFile restart area specifies "
- "inconsistent client array offset.\n");
- return FALSE;
- }
- /*
- * The restart area must end within the system page size both when
- * calculated manually and as specified by ra->restart_area_length.
- * Also, the calculated length must not exceed the specified length.
- */
- ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
- sizeof(LOG_CLIENT_RECORD);
- if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) ||
- (u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) >
- le32_to_cpu(rp->system_page_size) ||
- ra_len > le16_to_cpu(ra->restart_area_length)) {
- ntfs_log_error("$LogFile restart area is out of bounds "
- "of the system page size specified by the "
- "restart page header and/or the specified "
- "restart area length is inconsistent.\n");
- return FALSE;
- }
- /*
- * The ra->client_free_list and ra->client_in_use_list must be either
- * LOGFILE_NO_CLIENT or less than ra->log_clients or they are
- * overflowing the client array.
- */
- if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
- le16_to_cpu(ra->client_free_list) >=
- le16_to_cpu(ra->log_clients)) ||
- (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
- le16_to_cpu(ra->client_in_use_list) >=
- le16_to_cpu(ra->log_clients))) {
- ntfs_log_error("$LogFile restart area specifies "
- "overflowing client free and/or in use lists.\n");
- return FALSE;
- }
- /*
- * Check ra->seq_number_bits against ra->file_size for consistency.
- * We cannot just use ffs() because the file size is not a power of 2.
- */
- file_size = (u64)sle64_to_cpu(ra->file_size);
- fs_bits = 0;
- while (file_size) {
- file_size >>= 1;
- fs_bits++;
- }
- if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
- ntfs_log_error("$LogFile restart area specifies "
- "inconsistent sequence number bits.\n");
- return FALSE;
- }
- /* The log record header length must be a multiple of 8. */
- if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
- le16_to_cpu(ra->log_record_header_length)) {
- ntfs_log_error("$LogFile restart area specifies "
- "inconsistent log record header length.\n");
- return FALSE;
- }
- /* Ditto for the log page data offset. */
- if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
- le16_to_cpu(ra->log_page_data_offset)) {
- ntfs_log_error("$LogFile restart area specifies "
- "inconsistent log page data offset.\n");
- return FALSE;
- }
- ntfs_log_trace("Done.\n");
- return TRUE;
-}
-
-/**
- * ntfs_check_log_client_array - check the log client array for consistency
- * @rp: restart page whose log client array to check
- *
- * Check the log client array of the restart page @rp for consistency and
- * return TRUE if it is consistent and FALSE otherwise.
- *
- * This function assumes that the restart page header and the restart area have
- * already been consistency checked.
- *
- * Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
- * function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
- * restart page and the page must be multi sector transfer deprotected.
- */
-static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
-{
- RESTART_AREA *ra;
- LOG_CLIENT_RECORD *ca, *cr;
- u16 nr_clients, idx;
- BOOL in_free_list, idx_is_first;
-
- ntfs_log_trace("Entering.\n");
- ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
- ca = (LOG_CLIENT_RECORD*)((u8*)ra +
- le16_to_cpu(ra->client_array_offset));
- /*
- * Check the ra->client_free_list first and then check the
- * ra->client_in_use_list. Check each of the log client records in
- * each of the lists and check that the array does not overflow the
- * ra->log_clients value. Also keep track of the number of records
- * visited as there cannot be more than ra->log_clients records and
- * that way we detect eventual loops in within a list.
- */
- nr_clients = le16_to_cpu(ra->log_clients);
- idx = le16_to_cpu(ra->client_free_list);
- in_free_list = TRUE;
-check_list:
- for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
- idx = le16_to_cpu(cr->next_client)) {
- if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
- goto err_out;
- /* Set @cr to the current log client record. */
- cr = ca + idx;
- /* The first log client record must not have a prev_client. */
- if (idx_is_first) {
- if (cr->prev_client != LOGFILE_NO_CLIENT)
- goto err_out;
- idx_is_first = FALSE;
- }
- }
- /* Switch to and check the in use list if we just did the free list. */
- if (in_free_list) {
- in_free_list = FALSE;
- idx = le16_to_cpu(ra->client_in_use_list);
- goto check_list;
- }
- ntfs_log_trace("Done.\n");
- return TRUE;
-err_out:
- ntfs_log_error("$LogFile log client array is corrupt.\n");
- return FALSE;
-}
-
-/**
- * ntfs_check_and_load_restart_page - check the restart page for consistency
- * @log_na: opened ntfs attribute for journal $LogFile
- * @rp: restart page to check
- * @pos: position in @log_na at which the restart page resides
- * @wrp: [OUT] copy of the multi sector transfer deprotected restart page
- * @lsn: [OUT] set to the current logfile lsn on success
- *
- * Check the restart page @rp for consistency and return 0 if it is consistent
- * and errno otherwise. The restart page may have been modified by chkdsk in
- * which case its magic is CHKD instead of RSTR.
- *
- * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
- * require the full restart page.
- *
- * If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
- * copy of the complete multi sector transfer deprotected page. On failure,
- * *@wrp is undefined.
- *
- * Similarly, if @lsn is not NULL, on success *@lsn will be set to the current
- * logfile lsn according to this restart page. On failure, *@lsn is undefined.
- *
- * The following error codes are defined:
- * EINVAL - The restart page is inconsistent.
- * ENOMEM - Not enough memory to load the restart page.
- * EIO - Failed to reading from $LogFile.
- */
-static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
- RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
- LSN *lsn)
-{
- RESTART_AREA *ra;
- RESTART_PAGE_HEADER *trp;
- int err;
-
- ntfs_log_trace("Entering.\n");
- /* Check the restart page header for consistency. */
- if (!ntfs_check_restart_page_header(rp, pos)) {
- /* Error output already done inside the function. */
- return EINVAL;
- }
- /* Check the restart area for consistency. */
- if (!ntfs_check_restart_area(rp)) {
- /* Error output already done inside the function. */
- return EINVAL;
- }
- ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
- /*
- * Allocate a buffer to store the whole restart page so we can multi
- * sector transfer deprotect it.
- */
- trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
- if (!trp)
- return ENOMEM;
- /*
- * Read the whole of the restart page into the buffer. If it fits
- * completely inside @rp, just copy it from there. Otherwise read it
- * from disk.
- */
- if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE)
- memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
- else if (ntfs_attr_pread(log_na, pos,
- le32_to_cpu(rp->system_page_size), trp) !=
- le32_to_cpu(rp->system_page_size)) {
- err = errno;
- ntfs_log_error("Failed to read whole restart page into the "
- "buffer.\n");
- if (err != ENOMEM)
- err = EIO;
- goto err_out;
- }
- /*
- * Perform the multi sector transfer deprotection on the buffer if the
- * restart page is protected.
- */
- if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
- && ntfs_mst_post_read_fixup((NTFS_RECORD*)trp,
- le32_to_cpu(rp->system_page_size))) {
- /*
- * A multi sector tranfer error was detected. We only need to
- * abort if the restart page contents exceed the multi sector
- * transfer fixup of the first sector.
- */
- if (le16_to_cpu(rp->restart_area_offset) +
- le16_to_cpu(ra->restart_area_length) >
- NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
- ntfs_log_error("Multi sector transfer error "
- "detected in $LogFile restart page.\n");
- err = EINVAL;
- goto err_out;
- }
- }
- /*
- * If the restart page is modified by chkdsk or there are no active
- * logfile clients, the logfile is consistent. Otherwise, need to
- * check the log client records for consistency, too.
- */
- err = 0;
- if (ntfs_is_rstr_record(rp->magic) &&
- ra->client_in_use_list != LOGFILE_NO_CLIENT) {
- if (!ntfs_check_log_client_array(trp)) {
- err = EINVAL;
- goto err_out;
- }
- }
- if (lsn) {
- if (ntfs_is_rstr_record(rp->magic))
- *lsn = sle64_to_cpu(ra->current_lsn);
- else /* if (ntfs_is_chkd_record(rp->magic)) */
- *lsn = sle64_to_cpu(rp->chkdsk_lsn);
- }
- ntfs_log_trace("Done.\n");
- if (wrp)
- *wrp = trp;
- else {
-err_out:
- free(trp);
- }
- return err;
-}
-
-/**
- * ntfs_check_logfile - check in the journal if the volume is consistent
- * @log_na: ntfs attribute of loaded journal $LogFile to check
- * @rp: [OUT] on success this is a copy of the current restart page
- *
- * Check the $LogFile journal for consistency and return TRUE if it is
- * consistent and FALSE if not. On success, the current restart page is
- * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
- *
- * At present we only check the two restart pages and ignore the log record
- * pages.
- *
- * Note that the MstProtected flag is not set on the $LogFile inode and hence
- * when reading pages they are not deprotected. This is because we do not know
- * if the $LogFile was created on a system with a different page size to ours
- * yet and mst deprotection would fail if our page size is smaller.
- */
-BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
-{
- s64 size, pos;
- LSN rstr1_lsn, rstr2_lsn;
- ntfs_volume *vol = log_na->ni->vol;
- u8 *kaddr = NULL;
- RESTART_PAGE_HEADER *rstr1_ph = NULL;
- RESTART_PAGE_HEADER *rstr2_ph = NULL;
- int log_page_size, log_page_mask, err;
- BOOL logfile_is_empty = TRUE;
- u8 log_page_bits;
-
- ntfs_log_trace("Entering.\n");
- /* An empty $LogFile must have been clean before it got emptied. */
- if (NVolLogFileEmpty(vol))
- goto is_empty;
- size = log_na->data_size;
- /* Make sure the file doesn't exceed the maximum allowed size. */
- if (size > (s64)MaxLogFileSize)
- size = MaxLogFileSize;
- log_page_size = DefaultLogPageSize;
- log_page_mask = log_page_size - 1;
- /*
- * Use generic_ffs() instead of ffs() to enable the compiler to
- * optimize log_page_size and log_page_bits into constants.
- */
- log_page_bits = ffs(log_page_size) - 1;
- size &= ~(log_page_size - 1);
-
- /*
- * Ensure the log file is big enough to store at least the two restart
- * pages and the minimum number of log record pages.
- */
- if (size < log_page_size * 2 || (size - log_page_size * 2) >>
- log_page_bits < MinLogRecordPages) {
- ntfs_log_error("$LogFile is too small.\n");
- return FALSE;
- }
- /* Allocate memory for restart page. */
- kaddr = ntfs_malloc(NTFS_BLOCK_SIZE);
- if (!kaddr)
- return FALSE;
- /*
- * Read through the file looking for a restart page. Since the restart
- * page header is at the beginning of a page we only need to search at
- * what could be the beginning of a page (for each page size) rather
- * than scanning the whole file byte by byte. If all potential places
- * contain empty and uninitialized records, the log file can be assumed
- * to be empty.
- */
- for (pos = 0; pos < size; pos <<= 1) {
- /*
- * Read first NTFS_BLOCK_SIZE bytes of potential restart page.
- */
- if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) !=
- NTFS_BLOCK_SIZE) {
- ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE "
- "bytes of potential restart page.\n");
- goto err_out;
- }
-
- /*
- * A non-empty block means the logfile is not empty while an
- * empty block after a non-empty block has been encountered
- * means we are done.
- */
- if (!ntfs_is_empty_recordp((le32*)kaddr))
- logfile_is_empty = FALSE;
- else if (!logfile_is_empty)
- break;
- /*
- * A log record page means there cannot be a restart page after
- * this so no need to continue searching.
- */
- if (ntfs_is_rcrd_recordp((le32*)kaddr))
- break;
- /* If not a (modified by chkdsk) restart page, continue. */
- if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
- !ntfs_is_chkd_recordp((le32*)kaddr)) {
- if (!pos)
- pos = NTFS_BLOCK_SIZE >> 1;
- continue;
- }
- /*
- * Check the (modified by chkdsk) restart page for consistency
- * and get a copy of the complete multi sector transfer
- * deprotected restart page.
- */
- err = ntfs_check_and_load_restart_page(log_na,
- (RESTART_PAGE_HEADER*)kaddr, pos,
- !rstr1_ph ? &rstr1_ph : &rstr2_ph,
- !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
- if (!err) {
- /*
- * If we have now found the first (modified by chkdsk)
- * restart page, continue looking for the second one.
- */
- if (!pos) {
- pos = NTFS_BLOCK_SIZE >> 1;
- continue;
- }
- /*
- * We have now found the second (modified by chkdsk)
- * restart page, so we can stop looking.
- */
- break;
- }
- /*
- * Error output already done inside the function. Note, we do
- * not abort if the restart page was invalid as we might still
- * find a valid one further in the file.
- */
- if (err != EINVAL)
- goto err_out;
- /* Continue looking. */
- if (!pos)
- pos = NTFS_BLOCK_SIZE >> 1;
- }
- if (kaddr) {
- free(kaddr);
- kaddr = NULL;
- }
- if (logfile_is_empty) {
- NVolSetLogFileEmpty(vol);
-is_empty:
- ntfs_log_trace("Done. ($LogFile is empty.)\n");
- return TRUE;
- }
- if (!rstr1_ph) {
- if (rstr2_ph)
- ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
- ntfs_log_error("Did not find any restart pages in "
- "$LogFile and it was not empty.\n");
- return FALSE;
- }
- /* If both restart pages were found, use the more recent one. */
- if (rstr2_ph) {
- /*
- * If the second restart area is more recent, switch to it.
- * Otherwise just throw it away.
- */
- if (rstr2_lsn > rstr1_lsn) {
- ntfs_log_debug("Using second restart page as it is more "
- "recent.\n");
- free(rstr1_ph);
- rstr1_ph = rstr2_ph;
- /* rstr1_lsn = rstr2_lsn; */
- } else {
- ntfs_log_debug("Using first restart page as it is more "
- "recent.\n");
- free(rstr2_ph);
- }
- rstr2_ph = NULL;
- }
- /* All consistency checks passed. */
- if (rp)
- *rp = rstr1_ph;
- else
- free(rstr1_ph);
- ntfs_log_trace("Done.\n");
- return TRUE;
-err_out:
- free(kaddr);
- free(rstr1_ph);
- free(rstr2_ph);
- return FALSE;
-}
-
-/**
- * ntfs_is_logfile_clean - check in the journal if the volume is clean
- * @log_na: ntfs attribute of loaded journal $LogFile to check
- * @rp: copy of the current restart page
- *
- * Analyze the $LogFile journal and return TRUE if it indicates the volume was
- * shutdown cleanly and FALSE if not.
- *
- * At present we only look at the two restart pages and ignore the log record
- * pages. This is a little bit crude in that there will be a very small number
- * of cases where we think that a volume is dirty when in fact it is clean.
- * This should only affect volumes that have not been shutdown cleanly but did
- * not have any pending, non-check-pointed i/o, i.e. they were completely idle
- * at least for the five seconds preceding the unclean shutdown.
- *
- * This function assumes that the $LogFile journal has already been consistency
- * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
- * is empty this function requires that NVolLogFileEmpty() is true otherwise an
- * empty volume will be reported as dirty.
- */
-BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
-{
- RESTART_AREA *ra;
-
- ntfs_log_trace("Entering.\n");
- /* An empty $LogFile must have been clean before it got emptied. */
- if (NVolLogFileEmpty(log_na->ni->vol)) {
- ntfs_log_trace("Done. ($LogFile is empty.)\n");
- return TRUE;
- }
- if (!rp) {
- ntfs_log_error("Restart page header is NULL.\n");
- return FALSE;
- }
- if (!ntfs_is_rstr_record(rp->magic) &&
- !ntfs_is_chkd_record(rp->magic)) {
- ntfs_log_error("Restart page buffer is invalid. This is "
- "probably a bug in that the $LogFile should "
- "have been consistency checked before calling "
- "this function.\n");
- return FALSE;
- }
-
- ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
- /*
- * If the $LogFile has active clients, i.e. it is open, and we do not
- * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
- * we assume there was an unclean shutdown.
- */
- if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
- !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
- ntfs_log_debug("Done. $LogFile indicates a dirty shutdown.\n");
- return FALSE;
- }
- /* $LogFile indicates a clean shutdown. */
- ntfs_log_trace("Done. $LogFile indicates a clean shutdown.\n");
- return TRUE;
-}
-
-/**
- * ntfs_empty_logfile - empty the contents of the $LogFile journal
- * @na: ntfs attribute of journal $LogFile to empty
- *
- * Empty the contents of the $LogFile journal @na and return 0 on success and
- * -1 on error.
- *
- * This function assumes that the $LogFile journal has already been consistency
- * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
- * has been used to ensure that the $LogFile is clean.
- */
-int ntfs_empty_logfile(ntfs_attr *na)
-{
- s64 len, pos, count;
- char buf[NTFS_BUF_SIZE];
- int err;
-
- ntfs_log_trace("Entering.\n");
- if (NVolLogFileEmpty(na->ni->vol))
- goto done;
-
- /* The $DATA attribute of the $LogFile has to be non-resident. */
- if (!NAttrNonResident(na)) {
- err = EIO;
- ntfs_log_debug("$LogFile $DATA attribute is resident!?!\n");
- goto io_error_exit;
- }
-
- /* Get length of $LogFile contents. */
- len = na->data_size;
- if (!len) {
- ntfs_log_debug("$LogFile has zero length, no disk write "
- "needed.\n");
- return 0;
- }
-
- /* Read $LogFile until its end. We do this as a check for correct
- length thus making sure we are decompressing the mapping pairs
- array correctly and hence writing below is safe as well. */
- pos = 0;
- while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE, buf)) > 0)
- pos += count;
-
- if (count == -1 || pos != len) {
- err = errno;
- ntfs_log_debug("Amount of $LogFile data read does not "
- "correspond to expected length!\n");
- if (count != -1)
- err = EIO;
- goto io_error_exit;
- }
-
- /* Fill the buffer with 0xff's. */
- memset(buf, -1, NTFS_BUF_SIZE);
-
- /* Set the $DATA attribute. */
- pos = 0;
- while ((count = len - pos) > 0) {
- if (count > NTFS_BUF_SIZE)
- count = NTFS_BUF_SIZE;
-
- if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
- err = errno;
- ntfs_log_debug("Failed to set the $LogFile attribute "
- "value.\n");
- if (count != -1)
- err = EIO;
- goto io_error_exit;
- }
- pos += count;
- }
-
- /* Set the flag so we do not have to do it again on remount. */
- NVolSetLogFileEmpty(na->ni->vol);
-done:
- ntfs_log_trace("Done.\n");
- return 0;
-io_error_exit:
- errno = err;
- return -1;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/logging.c b/usr/src/lib/libntfs/common/libntfs/logging.c
deleted file mode 100644
index eb447e493f..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/logging.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/**
- * logging.c - Centralised logging. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#include "compat.h"
-#include "logging.h"
-
-#ifndef PATH_SEP
-#define PATH_SEP '/'
-#endif
-
-/* Colour prefixes and a suffix */
-#ifdef __sun
-static const char *col_green = "\033[32m";
-static const char *col_cyan = "\033[36m";
-static const char *col_yellow = "\033[01;33m";
-static const char *col_red = "\033[01;31m";
-static const char *col_redinv = "\033[01;07;31m";
-static const char *col_end = "\033[0m";
-#else /* ! __sun */
-static const char *col_green = "\e[32m";
-static const char *col_cyan = "\e[36m";
-static const char *col_yellow = "\e[01;33m";
-static const char *col_red = "\e[01;31m";
-static const char *col_redinv = "\e[01;07;31m";
-static const char *col_end = "\e[0m";
-#endif /* __sun */
-
-/**
- * struct ntfs_logging - Control info for the logging system
- * @levels: Bitfield of logging levels
- * @flags: Flags which affect the output style
- * @handler: Function to perform the actual logging
- */
-struct ntfs_logging {
- u32 levels;
- u32 flags;
- ntfs_log_handler *handler;
-};
-
-/**
- * ntfs_log - This struct controls all the logging in the library and tools.
- */
-static struct ntfs_logging ntfs_log = {
- .levels = NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET |
- NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR |
- NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
- NTFS_LOG_LEVEL_PROGRESS |
- 0,
- .flags = NTFS_LOG_FLAG_ONLYNAME,
- .handler = ntfs_log_handler_null,
-};
-
-
-/**
- * ntfs_log_get_levels - Get a list of the current logging levels
- *
- * Find out which logging levels are enabled.
- *
- * Returns: Log levels in a 32-bit field
- */
-u32 ntfs_log_get_levels(void)
-{
- return ntfs_log.levels;
-}
-
-/**
- * ntfs_log_set_levels - Enable extra logging levels
- * @levels: 32-bit field of log levels to set
- *
- * Enable one or more logging levels.
- * The logging levels are named: NTFS_LOG_LEVEL_*.
- *
- * Returns: Log levels that were enabled before the call
- */
-u32 ntfs_log_set_levels(u32 levels)
-{
- u32 old;
- old = ntfs_log.levels;
- ntfs_log.levels |= levels;
- return old;
-}
-
-/**
- * ntfs_log_clear_levels - Disable some logging levels
- * @levels: 32-bit field of log levels to clear
- *
- * Disable one or more logging levels.
- * The logging levels are named: NTFS_LOG_LEVEL_*.
- *
- * Returns: Log levels that were enabled before the call
- */
-u32 ntfs_log_clear_levels(u32 levels)
-{
- u32 old;
- old = ntfs_log.levels;
- ntfs_log.levels &= (~levels);
- return old;
-}
-
-
-/**
- * ntfs_log_get_flags - Get a list of logging style flags
- *
- * Find out which logging flags are enabled.
- *
- * Returns: Logging flags in a 32-bit field
- */
-u32 ntfs_log_get_flags(void)
-{
- return ntfs_log.flags;
-}
-
-/**
- * ntfs_log_set_flags - Enable extra logging style flags
- * @flags: 32-bit field of logging flags to set
- *
- * Enable one or more logging flags.
- * The log flags are named: NTFS_LOG_LEVEL_*.
- *
- * Returns: Logging flags that were enabled before the call
- */
-u32 ntfs_log_set_flags(u32 flags)
-{
- u32 old;
- old = ntfs_log.flags;
- ntfs_log.flags |= flags;
- return old;
-}
-
-/**
- * ntfs_log_clear_flags - Disable some logging styles
- * @flags: 32-bit field of logging flags to clear
- *
- * Disable one or more logging flags.
- * The log flags are named: NTFS_LOG_LEVEL_*.
- *
- * Returns: Logging flags that were enabled before the call
- */
-u32 ntfs_log_clear_flags(u32 flags)
-{
- u32 old;
- old = ntfs_log.flags;
- ntfs_log.flags &= (~flags);
- return old;
-}
-
-
-/**
- * ntfs_log_get_stream - Default output streams for logging levels
- * @level: Log level
- *
- * By default, urgent messages are sent to "stderr".
- * Other messages are sent to "stdout".
- *
- * Returns: "string" Prefix to be used
- */
-static FILE * ntfs_log_get_stream(u32 level)
-{
- FILE *stream;
-
- switch (level) {
- case NTFS_LOG_LEVEL_INFO:
- case NTFS_LOG_LEVEL_QUIET:
- case NTFS_LOG_LEVEL_PROGRESS:
- case NTFS_LOG_LEVEL_VERBOSE:
- stream = stdout;
- break;
-
- case NTFS_LOG_LEVEL_DEBUG:
- case NTFS_LOG_LEVEL_TRACE:
- case NTFS_LOG_LEVEL_WARNING:
- case NTFS_LOG_LEVEL_ERROR:
- case NTFS_LOG_LEVEL_CRITICAL:
- case NTFS_LOG_LEVEL_PERROR:
- default:
- stream = stderr;
- break;
- }
-
- return stream;
-}
-
-/**
- * ntfs_log_get_prefix - Default prefixes for logging levels
- * @level: Log level to be prefixed
- *
- * Prefixing the logging output can make it easier to parse.
- *
- * Returns: "string" Prefix to be used
- */
-static const char * ntfs_log_get_prefix(u32 level)
-{
- const char *prefix;
-
- switch (level) {
- case NTFS_LOG_LEVEL_DEBUG:
- prefix = "DEBUG: ";
- break;
- case NTFS_LOG_LEVEL_TRACE:
- prefix = "TRACE: ";
- break;
- case NTFS_LOG_LEVEL_QUIET:
- prefix = "QUIET: ";
- break;
- case NTFS_LOG_LEVEL_INFO:
- prefix = "INFO: ";
- break;
- case NTFS_LOG_LEVEL_VERBOSE:
- prefix = "VERBOSE: ";
- break;
- case NTFS_LOG_LEVEL_PROGRESS:
- prefix = "PROGRESS: ";
- break;
- case NTFS_LOG_LEVEL_WARNING:
- prefix = "WARNING: ";
- break;
- case NTFS_LOG_LEVEL_ERROR:
- prefix = "ERROR: ";
- break;
- case NTFS_LOG_LEVEL_PERROR:
- prefix = "ERROR: ";
- break;
- case NTFS_LOG_LEVEL_CRITICAL:
- prefix = "CRITICAL: ";
- break;
- default:
- prefix = "";
- break;
- }
-
- return prefix;
-}
-
-
-/**
- * ntfs_log_set_handler - Provide an alternate logging handler
- * @handler: function to perform the logging
- *
- * This alternate handler will be called for all future logging requests.
- * If no @handler is specified, logging will revert to the default handler.
- */
-void ntfs_log_set_handler(ntfs_log_handler *handler)
-{
- if (handler) {
- ntfs_log.handler = handler;
-#ifdef HAVE_SYSLOG_H
- if (handler == ntfs_log_handler_syslog)
- openlog("libntfs", LOG_PID, LOG_USER);
-#endif
- } else
- ntfs_log.handler = ntfs_log_handler_null;
-}
-
-/**
- * ntfs_log_redirect - Pass on the request to the real handler
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @...: Arguments to be formatted
- *
- * This is just a redirector function. The arguments are simply passed to the
- * main logging handler (as defined in the global logging struct @ntfs_log).
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_redirect(const char *function, const char *file,
- int line, u32 level, void *data, const char *format, ...)
-{
- int olderr = errno;
- int ret;
- va_list args;
-
- if (!(ntfs_log.levels & level)) /* Don't log this message */
- return 0;
-
- va_start(args, format);
- errno = olderr;
- ret = ntfs_log.handler(function, file, line, level, data, format, args);
- va_end(args);
-
- errno = olderr;
- return ret;
-}
-
-
-#ifdef HAVE_SYSLOG_H
-/**
- * ntfs_log_handler_syslog - syslog logging handler
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * A syslog logging handler. Ignores colors and truncates output after 512
- * bytes.
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_handler_syslog(const char *function, const char *file, int line,
- u32 level, void *data __attribute__((unused)),
- const char *format, va_list args)
-{
- char buffer[512];
- int ret = 0, olderr = errno;
-
- if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
- (strchr(file, PATH_SEP))) /* Abbreviate the filename */
- file = strrchr(file, PATH_SEP) + 1;
-
- /* Prefix the output */
- if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_PREFIX)
- ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s",
- ntfs_log_get_prefix(level));
-
- /* Source filename */
- if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_FILENAME)
- ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s ",
- file);
-
- /* Source line number */
- if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_LINE)
- ret += snprintf(buffer + ret, sizeof(buffer) - ret, "(%d) ",
- line);
-
- /* Source function */
- if (ret < sizeof(buffer) && ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION)
- || (level & NTFS_LOG_LEVEL_TRACE)))
- ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s(): ",
- function);
-
- /* Message itself */
- if (ret < sizeof(buffer))
- ret += vsnprintf(buffer + ret, sizeof(buffer) - ret, format,
- args);
-
- /* Append errno */
- if (ret < sizeof(buffer) && level & NTFS_LOG_LEVEL_PERROR)
- ret += snprintf(buffer + ret, sizeof(buffer) - ret, ": %s.\n",
- strerror(olderr));
-
- syslog(LOG_NOTICE, "%s", buffer);
-
- errno = olderr;
- return ret;
-}
-#endif
-
-/**
- * ntfs_log_handler_fprintf - Basic logging handler
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * A simple logging handler. This is where the log line is finally displayed.
- * It is more likely that you will want to set the handler to either
- * ntfs_log_handler_outerr or ntfs_log_handler_stderr.
- *
- * Note: For this handler, @data is a pointer to a FILE output stream.
- * If @data is NULL, nothing will be displayed.
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_handler_fprintf(const char *function, const char *file,
- int line, u32 level, void *data, const char *format, va_list args)
-{
- int ret = 0;
- int olderr = errno;
- FILE *stream;
- const char *col_prefix = NULL;
- const char *col_suffix = NULL;
-
- if (!data) /* Interpret data as a FILE stream. */
- return 0; /* If it's NULL, we can't do anything. */
- stream = (FILE*)data;
-
- if (ntfs_log.flags & NTFS_LOG_FLAG_COLOUR) {
- /* Pick a colour determined by the log level */
- switch (level) {
- case NTFS_LOG_LEVEL_DEBUG:
- col_prefix = col_green;
- col_suffix = col_end;
- break;
- case NTFS_LOG_LEVEL_TRACE:
- col_prefix = col_cyan;
- col_suffix = col_end;
- break;
- case NTFS_LOG_LEVEL_WARNING:
- col_prefix = col_yellow;
- col_suffix = col_end;
- break;
- case NTFS_LOG_LEVEL_ERROR:
- case NTFS_LOG_LEVEL_PERROR:
- col_prefix = col_red;
- col_suffix = col_end;
- break;
- case NTFS_LOG_LEVEL_CRITICAL:
- col_prefix = col_redinv;
- col_suffix = col_end;
- break;
- }
- }
-
- if (col_prefix)
- ret += fprintf(stream, col_prefix);
-
- if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
- (strchr(file, PATH_SEP))) /* Abbreviate the filename */
- file = strrchr(file, PATH_SEP) + 1;
-
- if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
- ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
-
- if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */
- ret += fprintf(stream, "%s ", file);
-
- if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */
- ret += fprintf(stream, "(%d) ", line);
-
- if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
- (level & NTFS_LOG_LEVEL_TRACE))
- ret += fprintf(stream, "%s(): ", function);
-
- ret += vfprintf(stream, format, args);
-
- if (level & NTFS_LOG_LEVEL_PERROR)
- ret += fprintf(stream, ": %s.\n", strerror(olderr));
-
- if (col_suffix)
- ret += fprintf(stream, col_suffix);
-
-
- fflush(stream);
- errno = olderr;
- return ret;
-}
-
-/**
- * ntfs_log_handler_null - Null logging handler (no output)
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * This handler produces no output. It provides a way to temporarily disable
- * logging, without having to change the levels and flags.
- *
- * Returns: 0 Message wasn't logged
- */
-int ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)),
- int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)),
- const char *format __attribute__((unused)), va_list args __attribute__((unused)))
-{
- return 0;
-}
-
-/**
- * ntfs_log_handler_stdout - All logs go to stdout
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * Display a log message to stdout.
- *
- * Note: For this handler, @data is a pointer to a FILE output stream.
- * If @data is NULL, then stdout will be used.
- *
- * Note: This function calls ntfs_log_handler_fprintf to do the main work.
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_handler_stdout(const char *function, const char *file,
- int line, u32 level, void *data, const char *format, va_list args)
-{
- if (!data)
- data = stdout;
-
- return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
-}
-
-/**
- * ntfs_log_handler_outerr - Logs go to stdout/stderr depending on level
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * Display a log message. The output stream will be determined by the log
- * level.
- *
- * Note: For this handler, @data is a pointer to a FILE output stream.
- * If @data is NULL, the function ntfs_log_get_stream will be called
- *
- * Note: This function calls ntfs_log_handler_fprintf to do the main work.
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_handler_outerr(const char *function, const char *file,
- int line, u32 level, void *data, const char *format, va_list args)
-{
- if (!data)
- data = ntfs_log_get_stream(level);
-
- return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
-}
-
-/**
- * ntfs_log_handler_stderr - All logs go to stderr
- * @function: Function in which the log line occurred
- * @file: File in which the log line occurred
- * @line: Line number on which the log line occurred
- * @level: Level at which the line is logged
- * @data: User specified data, possibly specific to a handler
- * @format: printf-style formatting string
- * @args: Arguments to be formatted
- *
- * Display a log message to stderr.
- *
- * Note: For this handler, @data is a pointer to a FILE output stream.
- * If @data is NULL, then stdout will be used.
- *
- * Note: This function calls ntfs_log_handler_fprintf to do the main work.
- *
- * Returns: -1 Error occurred
- * 0 Message wasn't logged
- * num Number of output characters
- */
-int ntfs_log_handler_stderr(const char *function, const char *file,
- int line, u32 level, void *data, const char *format, va_list args)
-{
- if (!data)
- data = stderr;
-
- return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
-}
-
-
-/**
- * ntfs_log_parse_option - Act upon command line options
- * @option: Option flag
- *
- * Delegate some of the work of parsing the command line. All the options begin
- * with "--log-". Options cause log levels to be enabled in @ntfs_log (the
- * global logging structure).
- *
- * Note: The "colour" option changes the logging handler.
- *
- * Returns: TRUE Option understood
- * FALSE Invalid log option
- */
-BOOL ntfs_log_parse_option(const char *option)
-{
- if (strcmp(option, "--log-debug") == 0) {
- ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
- return TRUE;
- } else if (strcmp(option, "--log-verbose") == 0) {
- ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
- return TRUE;
- } else if (strcmp(option, "--log-quiet") == 0) {
- ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
- return TRUE;
- } else if (strcmp(option, "--log-trace") == 0) {
- ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
- return TRUE;
- } else if ((strcmp(option, "--log-colour") == 0) ||
- (strcmp(option, "--log-color") == 0)) {
- ntfs_log_set_flags(NTFS_LOG_FLAG_COLOUR);
- return TRUE;
- }
-
- ntfs_log_debug("Unknown logging option '%s'\n", option);
- return FALSE;
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/mft.c b/usr/src/lib/libntfs/common/libntfs/mft.c
deleted file mode 100644
index 49034707ba..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/mft.c
+++ /dev/null
@@ -1,1583 +0,0 @@
-/**
- * mft.c - Mft record handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- * Copyright (c) 2004-2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include <time.h>
-
-#include "compat.h"
-#include "types.h"
-#include "device.h"
-#include "debug.h"
-#include "bitmap.h"
-#include "attrib.h"
-#include "inode.h"
-#include "volume.h"
-#include "layout.h"
-#include "lcnalloc.h"
-#include "mft.h"
-#include "logging.h"
-
-/**
- * ntfs_mft_records_read - read records from the mft from disk
- * @vol: volume to read from
- * @mref: starting mft record number to read
- * @count: number of mft records to read
- * @b: output data buffer
- *
- * Read @count mft records starting at @mref from volume @vol into buffer
- * @b. Return 0 on success or -1 on error, with errno set to the error
- * code.
- *
- * If any of the records exceed the initialized size of the $MFT/$DATA
- * attribute, i.e. they cannot possibly be allocated mft records, assume this
- * is a bug and return error code ESPIPE.
- *
- * The read mft records are mst deprotected and are hence ready to use. The
- * caller should check each record with is_baad_record() in case mst
- * deprotection failed.
- *
- * NOTE: @b has to be at least of size @count * vol->mft_record_size.
- */
-int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
- const s64 count, MFT_RECORD *b)
-{
- s64 br;
- VCN m;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));
- if (!vol || !vol->mft_na || !b || count < 0) {
- errno = EINVAL;
- return -1;
- }
- m = MREF(mref);
- /* Refuse to read non-allocated mft records. */
- if (m + count > vol->mft_na->initialized_size >>
- vol->mft_record_size_bits) {
- errno = ESPIPE;
- return -1;
- }
- br = ntfs_attr_mst_pread(vol->mft_na, m << vol->mft_record_size_bits,
- count, vol->mft_record_size, b);
- if (br != count) {
- if (br != -1)
- errno = EIO;
- if (br >= 0)
- ntfs_log_debug("Error: partition is smaller than it should "
- "be!\n");
- else
- ntfs_log_perror("Error reading $Mft record(s)");
- return -1;
- }
- return 0;
-}
-
-/**
- * ntfs_mft_records_write - write mft records to disk
- * @vol: volume to write to
- * @mref: starting mft record number to write
- * @count: number of mft records to write
- * @b: data buffer containing the mft records to write
- *
- * Write @count mft records starting at @mref from data buffer @b to volume
- * @vol. Return 0 on success or -1 on error, with errno set to the error code.
- *
- * If any of the records exceed the initialized size of the $MFT/$DATA
- * attribute, i.e. they cannot possibly be allocated mft records, assume this
- * is a bug and return error code ESPIPE.
- *
- * Before the mft records are written, they are mst protected. After the write,
- * they are deprotected again, thus resulting in an increase in the update
- * sequence number inside the data buffer @b.
- *
- * If any mft records are written which are also represented in the mft mirror
- * $MFTMirr, we make a copy of the relevant parts of the data buffer @b into a
- * temporary buffer before we do the actual write. Then if at least one mft
- * record was successfully written, we write the appropriate mft records from
- * the copied buffer to the mft mirror, too.
- */
-int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
- const s64 count, MFT_RECORD *b)
-{
- s64 bw;
- VCN m;
- void *bmirr = NULL;
- int cnt = 0, res = 0;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));
- if (!vol || !vol->mft_na || vol->mftmirr_size <= 0 || !b || count < 0) {
- errno = EINVAL;
- return -1;
- }
- m = MREF(mref);
- /* Refuse to write non-allocated mft records. */
- if (m + count > vol->mft_na->initialized_size >>
- vol->mft_record_size_bits) {
- errno = ESPIPE;
- return -1;
- }
- if (m < vol->mftmirr_size) {
- if (!vol->mftmirr_na) {
- errno = EINVAL;
- return -1;
- }
- cnt = vol->mftmirr_size - m;
- if (cnt > count)
- cnt = count;
- bmirr = ntfs_malloc(cnt * vol->mft_record_size);
- if (!bmirr)
- return -1;
- memcpy(bmirr, b, cnt * vol->mft_record_size);
- }
- bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits,
- count, vol->mft_record_size, b);
- if (bw != count) {
- if (bw != -1)
- errno = EIO;
- if (bw >= 0)
- ntfs_log_error("Partial write while writing $Mft "
- "record(s)!\n");
- else
- ntfs_log_perror("Error writing $Mft record(s)");
- res = errno;
- }
- if (bmirr && bw > 0) {
- if (bw < cnt)
- cnt = bw;
- bw = ntfs_attr_mst_pwrite(vol->mftmirr_na,
- m << vol->mft_record_size_bits, cnt,
- vol->mft_record_size, bmirr);
- if (bw != cnt) {
- if (bw != -1)
- errno = EIO;
- ntfs_log_debug("Error: failed to sync $MFTMirr! Run "
- "chkdsk.\n");
- res = errno;
- }
- }
- free(bmirr);
- if (!res)
- return res;
- errno = res;
- return -1;
-}
-
-/**
- * ntfs_file_record_read - read a FILE record from the mft from disk
- * @vol: volume to read from
- * @mref: mft reference specifying mft record to read
- * @mrec: address of pointer in which to return the mft record
- * @attr: address of pointer in which to return the first attribute
- *
- * Read a FILE record from the mft of @vol from the storage medium. @mref
- * specifies the mft record to read, including the sequence number, which can
- * be 0 if no sequence number checking is to be performed.
- *
- * The function allocates a buffer large enough to hold the mft record and
- * reads the record into the buffer (mst deprotecting it in the process).
- * *@mrec is then set to point to the buffer.
- *
- * If @attr is not NULL, *@attr is set to point to the first attribute in the
- * mft record, i.e. *@attr is a pointer into *@mrec.
- *
- * Return 0 on success, or -1 on error, with errno set to the error code.
- *
- * The read mft record is checked for having the magic FILE,
- * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
- * If either of these fails, -1 is returned and errno is set to EIO. If you get
- * this, but you still want to read the mft record (e.g. in order to correct
- * it), use ntfs_mft_record_read() directly.
- *
- * Note: Caller has to free *@mrec when finished.
- *
- * Note: We do not check if the mft record is flagged in use. The caller can
- * check if desired.
- */
-int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
- MFT_RECORD **mrec, ATTR_RECORD **attr)
-{
- MFT_RECORD *m;
- ATTR_RECORD *a;
- int err;
-
- if (!vol || !mrec) {
- errno = EINVAL;
- return -1;
- }
- m = *mrec;
- if (!m) {
- m = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size);
- if (!m)
- return -1;
- }
- if (ntfs_mft_record_read(vol, mref, m)) {
- err = errno;
- goto read_failed;
- }
- if (!ntfs_is_file_record(m->magic))
- goto file_corrupt;
- if (MSEQNO(mref) && MSEQNO(mref) != le16_to_cpu(m->sequence_number))
- goto file_corrupt;
- a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
- if (p2n(a) < p2n(m) || (char*)a > (char*)m + vol->mft_record_size)
- goto file_corrupt;
- *mrec = m;
- if (attr)
- *attr = a;
- return 0;
-file_corrupt:
- ntfs_log_debug("ntfs_file_record_read(): file is corrupt.\n");
- err = EIO;
-read_failed:
- if (m != *mrec)
- free(m);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_mft_record_layout - layout an mft record into a memory buffer
- * @vol: volume to which the mft record will belong
- * @mref: mft reference specifying the mft record number
- * @mrec: destination buffer of size >= @vol->mft_record_size bytes
- *
- * Layout an empty, unused mft record with the mft reference @mref into the
- * buffer @m. The volume @vol is needed because the mft record structure was
- * modified in NTFS 3.1 so we need to know which volume version this mft record
- * will be used on.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
- MFT_RECORD *mrec)
-{
- ATTR_RECORD *a;
-
- if (!vol || !mrec) {
- errno = EINVAL;
- return -1;
- }
- /* Aligned to 2-byte boundary. */
- if (vol->major_ver < 3 || (vol->major_ver == 3 && !vol->minor_ver))
- mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD_OLD) + 1) & ~1);
- else {
- /* Abort if mref is > 32 bits. */
- if (MREF(mref) & 0x0000ffff00000000ull) {
- ntfs_log_debug("Mft reference exceeds 32 bits!\n");
- errno = ERANGE;
- return -1;
- }
- mrec->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);
- /*
- * Set the NTFS 3.1+ specific fields while we know that the
- * volume version is 3.1+.
- */
- mrec->reserved = cpu_to_le16(0);
- mrec->mft_record_number = cpu_to_le32(MREF(mref));
- }
- mrec->magic = magic_FILE;
- if (vol->mft_record_size >= NTFS_BLOCK_SIZE)
- mrec->usa_count = cpu_to_le16(vol->mft_record_size /
- NTFS_BLOCK_SIZE + 1);
- else {
- mrec->usa_count = cpu_to_le16(1);
- ntfs_log_error("Sector size is bigger than MFT record size. "
- "Setting usa_count to 1. If Windows chkdsk "
- "reports this as corruption, please email %s "
- "stating that you saw this message and that "
- "the file system created was corrupt. "
- "Thank you.\n", NTFS_DEV_LIST);
- }
- /* Set the update sequence number to 1. */
- *(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1);
- mrec->lsn = 0;
- mrec->sequence_number = cpu_to_le16(1);
- mrec->link_count = cpu_to_le16(0);
- /* Aligned to 8-byte boundary. */
- mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) +
- (le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7);
- mrec->flags = cpu_to_le16(0);
- /*
- * Using attrs_offset plus eight bytes (for the termination attribute),
- * aligned to 8-byte boundary.
- */
- mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 +
- 7) & ~7);
- mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size);
- mrec->base_mft_record = cpu_to_le64((MFT_REF)0);
- mrec->next_attr_instance = cpu_to_le16(0);
- a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
- a->type = AT_END;
- a->length = cpu_to_le32(0);
- /* Finally, clear the unused part of the mft record. */
- memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec));
- return 0;
-}
-
-/**
- * ntfs_mft_record_format - format an mft record on an ntfs volume
- * @vol: volume on which to format the mft record
- * @mref: mft reference specifying mft record to format
- *
- * Format the mft record with the mft reference @mref in $MFT/$DATA, i.e. lay
- * out an empty, unused mft record in memory and write it to the volume @vol.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref)
-{
- MFT_RECORD *m;
- int err;
-
- if (!vol || !vol->mft_na) {
- errno = EINVAL;
- return -1;
- }
- m = ntfs_calloc(vol->mft_record_size);
- if (!m)
- return -1;
- if (ntfs_mft_record_layout(vol, mref, m)) {
- err = errno;
- free(m);
- errno = err;
- return -1;
- }
- if (ntfs_mft_record_write(vol, mref, m)) {
- err = errno;
- free(m);
- errno = err;
- return -1;
- }
- free(m);
- return 0;
-}
-
-static const char *es = " Leaving inconsistent metadata. Run chkdsk.";
-
-/**
- * ntfs_ffz - Find the first unset (zero) bit in a word
- * @word:
- *
- * Description...
- *
- * Returns:
- */
-static inline unsigned int ntfs_ffz(unsigned int word)
-{
- return ffs(~word) - 1;
-}
-
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
-/**
- * ntfs_mft_bitmap_find_free_rec - find a free mft record in the mft bitmap
- * @vol: volume on which to search for a free mft record
- * @base_ni: open base inode if allocating an extent mft record or NULL
- *
- * Search for a free mft record in the mft bitmap attribute on the ntfs volume
- * @vol.
- *
- * If @base_ni is NULL start the search at the default allocator position.
- *
- * If @base_ni is not NULL start the search at the mft record after the base
- * mft record @base_ni.
- *
- * Return the free mft record on success and -1 on error with errno set to the
- * error code. An error code of ENOSPC means that there are no free mft
- * records in the currently initialized mft bitmap.
- */
-static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
-{
- s64 pass_end, ll, data_pos, pass_start, ofs, bit;
- ntfs_attr *mftbmp_na;
- u8 *buf, *byte;
- unsigned int size;
- u8 pass, b;
-
- mftbmp_na = vol->mftbmp_na;
- /*
- * Set the end of the pass making sure we do not overflow the mft
- * bitmap.
- */
- size = PAGE_SIZE;
- pass_end = vol->mft_na->allocated_size >> vol->mft_record_size_bits;
- ll = mftbmp_na->initialized_size << 3;
- if (pass_end > ll)
- pass_end = ll;
- pass = 1;
- if (!base_ni)
- data_pos = vol->mft_data_pos;
- else
- data_pos = base_ni->mft_no + 1;
- if (data_pos < 24)
- data_pos = 24;
- if (data_pos >= pass_end) {
- data_pos = 24;
- pass = 2;
- /* This happens on a freshly formatted volume. */
- if (data_pos >= pass_end) {
- errno = ENOSPC;
- return -1;
- }
- }
- pass_start = data_pos;
- buf = (u8*)ntfs_malloc(PAGE_SIZE);
- if (!buf)
- return -1;
-
- ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, "
- "pass_end 0x%llx, data_pos 0x%llx.\n", pass,
- (long long)pass_start, (long long)pass_end,
- (long long)data_pos);
-#ifdef DEBUG
- byte = NULL;
- b = 0;
-#endif
- /* Loop until a free mft record is found. */
- for (; pass <= 2; size = PAGE_SIZE) {
- /* Cap size to pass_end. */
- ofs = data_pos >> 3;
- ll = ((pass_end + 7) >> 3) - ofs;
- if (size > ll)
- size = ll;
- ll = ntfs_attr_pread(mftbmp_na, ofs, size, buf);
- if (ll < 0) {
- ntfs_log_error("Failed to read mft bitmap "
- "attribute, aborting.\n");
- free(buf);
- return -1;
- }
- ntfs_log_debug("Read 0x%llx bytes.\n", (long long)ll);
- /* If we read at least one byte, search @buf for a zero bit. */
- if (ll) {
- size = ll << 3;
- bit = data_pos & 7;
- data_pos &= ~7ull;
- ntfs_log_debug("Before inner for loop: size 0x%x, "
- "data_pos 0x%llx, bit 0x%llx, "
- "*byte 0x%hhx, b %u.\n", size,
- (long long)data_pos, (long long)bit,
- byte ? *byte : -1, b);
- for (; bit < size && data_pos + bit < pass_end;
- bit &= ~7ull, bit += 8) {
- byte = buf + (bit >> 3);
- if (*byte == 0xff)
- continue;
- /* Note: ffz() result must be zero based. */
- b = ntfs_ffz((unsigned long)*byte);
- if (b < 8 && b >= (bit & 7)) {
- free(buf);
- return data_pos + (bit & ~7ull) + b;
- }
- }
- ntfs_log_debug("After inner for loop: size 0x%x, "
- "data_pos 0x%llx, bit 0x%llx, "
- "*byte 0x%hhx, b %u.\n", size,
- (long long)data_pos, (long long)bit,
- byte ? *byte : -1, b);
- data_pos += size;
- /*
- * If the end of the pass has not been reached yet,
- * continue searching the mft bitmap for a zero bit.
- */
- if (data_pos < pass_end)
- continue;
- }
- /* Do the next pass. */
- pass++;
- if (pass == 2) {
- /*
- * Starting the second pass, in which we scan the first
- * part of the zone which we omitted earlier.
- */
- pass_end = pass_start;
- data_pos = pass_start = 24;
- ntfs_log_debug("pass %i, pass_start 0x%llx, pass_end "
- "0x%llx.\n", pass, (long long)pass_start,
- (long long)pass_end);
- if (data_pos >= pass_end)
- break;
- }
- }
- /* No free mft records in currently initialized mft bitmap. */
- free(buf);
- errno = ENOSPC;
- return -1;
-}
-
-/**
- * ntfs_mft_bitmap_extend_allocation - extend mft bitmap attribute by a cluster
- * @vol: volume on which to extend the mft bitmap attribute
- *
- * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster.
- *
- * Note: Only changes allocated_size, i.e. does not touch initialized_size or
- * data_size.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol)
-{
- LCN lcn;
- s64 ll = 0; /* silence compiler warning */
- ntfs_attr *mftbmp_na, *lcnbmp_na;
- runlist_element *rl, *rl2 = NULL; /* silence compiler warning */
- ntfs_attr_search_ctx *ctx;
- MFT_RECORD *m = NULL; /* silence compiler warning */
- ATTR_RECORD *a = NULL; /* silence compiler warning */
- int ret, mp_size;
- u32 old_alen = 0; /* silence compiler warning */
- u8 b, tb;
- struct {
- u8 added_cluster:1;
- u8 added_run:1;
- u8 mp_rebuilt:1;
- } status = { 0, 0, 0 };
-
- mftbmp_na = vol->mftbmp_na;
- lcnbmp_na = vol->lcnbmp_na;
- /*
- * Determine the last lcn of the mft bitmap. The allocated size of the
- * mft bitmap cannot be zero so we are ok to do this.
- */
- rl = ntfs_attr_find_vcn(mftbmp_na, (mftbmp_na->allocated_size - 1) >>
- vol->cluster_size_bits);
- if (!rl || !rl->length || rl->lcn < 0) {
- ntfs_log_error("Failed to determine last allocated "
- "cluster of mft bitmap attribute.\n");
- if (rl)
- errno = EIO;
- return -1;
- }
- lcn = rl->lcn + rl->length;
- /*
- * Attempt to get the cluster following the last allocated cluster by
- * hand as it may be in the MFT zone so the allocator would not give it
- * to us.
- */
- ret = (int)ntfs_attr_pread(lcnbmp_na, lcn >> 3, 1, &b);
- if (ret < 0) {
- ntfs_log_error("Failed to read from lcn bitmap.\n");
- return -1;
- }
- ntfs_log_debug("Read %i byte%s.\n", ret, ret == 1 ? "" : "s");
- tb = 1 << (lcn & 7ull);
- if (ret == 1 && b != 0xff && !(b & tb)) {
- /* Next cluster is free, allocate it. */
- b |= tb;
- ret = (int)ntfs_attr_pwrite(lcnbmp_na, lcn >> 3, 1, &b);
- if (ret < 1) {
- ntfs_log_error("Failed to write to lcn "
- "bitmap.\n");
- if (!ret)
- errno = EIO;
- return -1;
- }
- vol->nr_free_clusters--;
- /* Update the mft bitmap runlist. */
- rl->length++;
- rl[1].vcn++;
- status.added_cluster = 1;
- ntfs_log_debug("Appending one cluster to mft bitmap.\n");
- } else {
- /* Allocate a cluster from the DATA_ZONE. */
- rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE);
- if (!rl2) {
- ntfs_log_error("Failed to allocate a cluster for "
- "the mft bitmap.\n");
- return -1;
- }
- rl = ntfs_runlists_merge(mftbmp_na->rl, rl2);
- if (!rl) {
- ret = errno;
- ntfs_log_error("Failed to merge runlists for mft "
- "bitmap.\n");
- if (ntfs_cluster_free_from_rl(vol, rl2))
- ntfs_log_error("Failed to deallocate "
- "cluster.%s\n", es);
- free(rl2);
- errno = ret;
- return -1;
- }
- mftbmp_na->rl = rl;
- status.added_run = 1;
- ntfs_log_debug("Adding one run to mft bitmap.\n");
- /* Find the last run in the new runlist. */
- for (; rl[1].length; rl++)
- ;
- }
- /*
- * Update the attribute record as well. Note: @rl is the last
- * (non-terminator) runlist element of mft bitmap.
- */
- ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL);
- if (!ctx) {
- ntfs_log_error("Failed to get search context.\n");
- goto undo_alloc;
- }
- if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,
- mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find last attribute extent of "
- "mft bitmap attribute.\n");
- goto undo_alloc;
- }
- m = ctx->mrec;
- a = ctx->attr;
- ll = sle64_to_cpu(a->u.nonres.lowest_vcn);
- rl2 = ntfs_attr_find_vcn(mftbmp_na, ll);
- if (!rl2 || !rl2->length) {
- ntfs_log_error("Failed to determine previous last "
- "allocated cluster of mft bitmap attribute.\n");
- if (rl2)
- errno = EIO;
- goto undo_alloc;
- }
- /* Get the size for the new mapping pairs array for this extent. */
- mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll);
- if (mp_size <= 0) {
- ntfs_log_error("Get size for mapping pairs failed for "
- "mft bitmap attribute extent.\n");
- goto undo_alloc;
- }
- /* Expand the attribute record if necessary. */
- old_alen = le32_to_cpu(a->length);
- if (ntfs_attr_record_resize(m, a, mp_size +
- le16_to_cpu(a->u.nonres.mapping_pairs_offset))) {
- if (errno != ENOSPC) {
- ntfs_log_error("Failed to resize attribute "
- "record for mft bitmap attribute.\n");
- goto undo_alloc;
- }
- // TODO: Deal with this by moving this extent to a new mft
- // record or by starting a new extent in a new mft record.
- ntfs_log_error("Not enough space in this mft record to "
- "accommodate extended mft bitmap attribute "
- "extent. Cannot handle this yet.\n");
- errno = EOPNOTSUPP;
- goto undo_alloc;
- }
- status.mp_rebuilt = 1;
- /* Generate the mapping pairs array directly into the attr record. */
- if (ntfs_mapping_pairs_build(vol, (u8*)a +
- le16_to_cpu(a->u.nonres.mapping_pairs_offset), mp_size, rl2, ll,
- NULL)) {
- ntfs_log_error("Failed to build mapping pairs array for "
- "mft bitmap attribute.\n");
- errno = EIO;
- goto undo_alloc;
- }
- /* Update the highest_vcn. */
- a->u.nonres.highest_vcn = cpu_to_sle64(rl[1].vcn - 1);
- /*
- * We now have extended the mft bitmap allocated_size by one cluster.
- * Reflect this in the ntfs_attr structure and the attribute record.
- */
- if (a->u.nonres.lowest_vcn) {
- /*
- * We are not in the first attribute extent, switch to it, but
- * first ensure the changes will make it to disk later.
- */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,
- mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find first attribute "
- "extent of mft bitmap attribute.\n");
- goto restore_undo_alloc;
- }
- a = ctx->attr;
- }
- mftbmp_na->allocated_size += vol->cluster_size;
- a->u.nonres.allocated_size = cpu_to_sle64(mftbmp_na->allocated_size);
- /* Ensure the changes make it to disk. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-restore_undo_alloc:
- ret = errno;
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,
- mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find last attribute extent of "
- "mft bitmap attribute.%s\n", es);
- ntfs_attr_put_search_ctx(ctx);
- mftbmp_na->allocated_size += vol->cluster_size;
- /*
- * The only thing that is now wrong is ->allocated_size of the
- * base attribute extent which chkdsk should be able to fix.
- */
- errno = ret;
- return -1;
- }
- m = ctx->mrec;
- a = ctx->attr;
- a->u.nonres.highest_vcn = cpu_to_sle64(rl[1].vcn - 2);
- errno = ret;
-undo_alloc:
- ret = errno;
- if (status.added_cluster) {
- /* Truncate the last run in the runlist by one cluster. */
- rl->length--;
- rl[1].vcn--;
- } else if (status.added_run) {
- lcn = rl->lcn;
- /* Remove the last run from the runlist. */
- rl->lcn = rl[1].lcn;
- rl->length = 0;
- }
- /* Deallocate the cluster. */
- if (ntfs_bitmap_clear_bit(lcnbmp_na, lcn))
- ntfs_log_error("Failed to free cluster.%s\n", es);
- if (status.mp_rebuilt) {
- if (ntfs_mapping_pairs_build(vol, (u8*)a +
- le16_to_cpu(a->u.nonres.mapping_pairs_offset),
- old_alen - le16_to_cpu(a->u.nonres.mapping_pairs_offset),
- rl2, ll, NULL))
- ntfs_log_error("Failed to restore mapping "
- "pairs array.%s\n", es);
- if (ntfs_attr_record_resize(m, a, old_alen))
- ntfs_log_error("Failed to restore attribute "
- "record.%s\n", es);
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- }
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- errno = ret;
- return -1;
-}
-
-/**
- * ntfs_mft_bitmap_extend_initialized - extend mft bitmap initialized data
- * @vol: volume on which to extend the mft bitmap attribute
- *
- * Extend the initialized portion of the mft bitmap attribute on the ntfs
- * volume @vol by 8 bytes.
- *
- * Note: Only changes initialized_size and data_size, i.e. requires that
- * allocated_size is big enough to fit the new initialized_size.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
-{
- s64 old_data_size, old_initialized_size, ll;
- ntfs_attr *mftbmp_na;
- ntfs_attr_search_ctx *ctx;
- ATTR_RECORD *a;
- int err;
-
- mftbmp_na = vol->mftbmp_na;
- ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL);
- if (!ctx) {
- ntfs_log_error("Failed to get search context.\n");
- return -1;
- }
- if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,
- mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find first attribute extent of "
- "mft bitmap attribute.\n");
- err = errno;
- goto put_err_out;
- }
- a = ctx->attr;
- old_data_size = mftbmp_na->data_size;
- old_initialized_size = mftbmp_na->initialized_size;
- mftbmp_na->initialized_size += 8;
- a->u.nonres.initialized_size = cpu_to_sle64(mftbmp_na->initialized_size);
- if (mftbmp_na->initialized_size > mftbmp_na->data_size) {
- mftbmp_na->data_size = mftbmp_na->initialized_size;
- a->u.nonres.data_size = cpu_to_sle64(mftbmp_na->data_size);
- }
- /* Ensure the changes make it to disk. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- /* Initialize the mft bitmap attribute value with zeroes. */
- ll = 0;
- ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll);
- if (ll == 8) {
- ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n");
- return 0;
- }
- vol->nr_free_mft_records += 64; /* 8 bytes x 8 bits each. */
- ntfs_log_error("Failed to write to mft bitmap.\n");
- err = errno;
- if (ll >= 0)
- err = EIO;
- /* Try to recover from the error. */
- ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL);
- if (!ctx) {
- ntfs_log_error("Failed to get search context.%s\n", es);
- goto err_out;
- }
- if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name,
- mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find first attribute extent of "
- "mft bitmap attribute.%s\n", es);
-put_err_out:
- ntfs_attr_put_search_ctx(ctx);
- goto err_out;
- }
- a = ctx->attr;
- mftbmp_na->initialized_size = old_initialized_size;
- a->u.nonres.initialized_size = cpu_to_sle64(old_initialized_size);
- if (mftbmp_na->data_size != old_data_size) {
- mftbmp_na->data_size = old_data_size;
- a->u.nonres.data_size = cpu_to_sle64(old_data_size);
- }
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- ntfs_log_debug("Restored status of mftbmp: allocated_size 0x%llx, "
- "data_size 0x%llx, initialized_size 0x%llx.\n",
- (long long)mftbmp_na->allocated_size,
- (long long)mftbmp_na->data_size,
- (long long)mftbmp_na->initialized_size);
-err_out:
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_mft_data_extend_allocation - extend mft data attribute
- * @vol: volume on which to extend the mft data attribute
- *
- * Extend the mft data attribute on the ntfs volume @vol by 16 mft records
- * worth of clusters or if not enough space for this by one mft record worth
- * of clusters.
- *
- * Note: Only changes allocated_size, i.e. does not touch initialized_size or
- * data_size.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
-{
- LCN lcn;
- VCN old_last_vcn;
- s64 min_nr, nr, ll = 0; /* silence compiler warning */
- ntfs_attr *mft_na;
- runlist_element *rl, *rl2;
- ntfs_attr_search_ctx *ctx;
- MFT_RECORD *m = NULL; /* silence compiler warning */
- ATTR_RECORD *a = NULL; /* silence compiler warning */
- int err, mp_size;
- u32 old_alen = 0; /* silence compiler warning */
- BOOL mp_rebuilt = FALSE;
-
- ntfs_log_debug("Extending mft data allocation.\n");
- mft_na = vol->mft_na;
- /*
- * Determine the preferred allocation location, i.e. the last lcn of
- * the mft data attribute. The allocated size of the mft data
- * attribute cannot be zero so we are ok to do this.
- */
- rl = ntfs_attr_find_vcn(mft_na,
- (mft_na->allocated_size - 1) >> vol->cluster_size_bits);
- if (!rl || !rl->length || rl->lcn < 0) {
- ntfs_log_error("Failed to determine last allocated "
- "cluster of mft data attribute.\n");
- if (rl)
- errno = EIO;
- return -1;
- }
- lcn = rl->lcn + rl->length;
- ntfs_log_debug("Last lcn of mft data attribute is 0x%llx.\n", (long long)lcn);
- /* Minimum allocation is one mft record worth of clusters. */
- min_nr = vol->mft_record_size >> vol->cluster_size_bits;
- if (!min_nr)
- min_nr = 1;
- /* Want to allocate 16 mft records worth of clusters. */
- nr = vol->mft_record_size << 4 >> vol->cluster_size_bits;
- if (!nr)
- nr = min_nr;
- ntfs_log_debug("Trying mft data allocation with default cluster count "
- "%lli.\n", (long long)nr);
- old_last_vcn = rl[1].vcn;
- do {
- rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE);
- if (rl2)
- break;
- if (errno != ENOSPC || nr == min_nr) {
- ntfs_log_error("Failed to allocate the minimal "
- "number of clusters (%lli) for the "
- "mft data attribute.\n", (long long)nr);
- return -1;
- }
- /*
- * There is not enough space to do the allocation, but there
- * might be enough space to do a minimal allocation so try that
- * before failing.
- */
- nr = min_nr;
- ntfs_log_debug("Retrying mft data allocation with minimal cluster "
- "count %lli.\n", (long long)nr);
- } while (1);
- rl = ntfs_runlists_merge(mft_na->rl, rl2);
- if (!rl) {
- err = errno;
- ntfs_log_error("Failed to merge runlists for mft data "
- "attribute.\n");
- if (ntfs_cluster_free_from_rl(vol, rl2))
- ntfs_log_error("Failed to deallocate clusters "
- "from the mft data attribute.%s\n", es);
- free(rl2);
- errno = err;
- return -1;
- }
- mft_na->rl = rl;
- ntfs_log_debug("Allocated %lli clusters.\n", nr);
- /* Find the last run in the new runlist. */
- for (; rl[1].length; rl++)
- ;
- /* Update the attribute record as well. */
- ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
- if (!ctx) {
- ntfs_log_error("Failed to get search context.\n");
- goto undo_alloc;
- }
- if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
- rl[1].vcn, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find last attribute extent of "
- "mft data attribute.\n");
- goto undo_alloc;
- }
- m = ctx->mrec;
- a = ctx->attr;
- ll = sle64_to_cpu(a->u.nonres.lowest_vcn);
- rl2 = ntfs_attr_find_vcn(mft_na, ll);
- if (!rl2 || !rl2->length) {
- ntfs_log_error("Failed to determine previous last "
- "allocated cluster of mft data attribute.\n");
- if (rl2)
- errno = EIO;
- goto undo_alloc;
- }
- /* Get the size for the new mapping pairs array for this extent. */
- mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll);
- if (mp_size <= 0) {
- ntfs_log_error("Get size for mapping pairs failed for "
- "mft data attribute extent.\n");
- goto undo_alloc;
- }
- /* Expand the attribute record if necessary. */
- old_alen = le32_to_cpu(a->length);
- if (ntfs_attr_record_resize(m, a,
- mp_size + le16_to_cpu(a->u.nonres.mapping_pairs_offset))) {
- if (errno != ENOSPC) {
- ntfs_log_error("Failed to resize attribute "
- "record for mft data attribute.\n");
- goto undo_alloc;
- }
- // TODO: Deal with this by moving this extent to a new mft
- // record or by starting a new extent in a new mft record.
- // Note: Use the special reserved mft records and ensure that
- // this extent is not required to find the mft record in
- // question.
- ntfs_log_error("Not enough space in this mft record to "
- "accommodate extended mft data attribute "
- "extent. Cannot handle this yet.\n");
- errno = EOPNOTSUPP;
- goto undo_alloc;
- }
- mp_rebuilt = TRUE;
- /*
- * Generate the mapping pairs array directly into the attribute record.
- */
- if (ntfs_mapping_pairs_build(vol,
- (u8*)a + le16_to_cpu(a->u.nonres.mapping_pairs_offset), mp_size,
- rl2, ll, NULL)) {
- ntfs_log_error("Failed to build mapping pairs array of "
- "mft data attribute.\n");
- errno = EIO;
- goto undo_alloc;
- }
- /* Update the highest_vcn. */
- a->u.nonres.highest_vcn = cpu_to_sle64(rl[1].vcn - 1);
- /*
- * We now have extended the mft data allocated_size by nr clusters.
- * Reflect this in the ntfs_attr structure and the attribute record.
- * @rl is the last (non-terminator) runlist element of mft data
- * attribute.
- */
- if (a->u.nonres.lowest_vcn) {
- /*
- * We are not in the first attribute extent, switch to it, but
- * first ensure the changes will make it to disk later.
- */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(mft_na->type, mft_na->name,
- mft_na->name_len, 0, 0, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find first attribute "
- "extent of mft data attribute.\n");
- goto restore_undo_alloc;
- }
- a = ctx->attr;
- }
- mft_na->allocated_size += nr << vol->cluster_size_bits;
- a->u.nonres.allocated_size = cpu_to_sle64(mft_na->allocated_size);
- /* Ensure the changes make it to disk. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- return 0;
-restore_undo_alloc:
- err = errno;
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
- rl[1].vcn, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find last attribute extent of "
- "mft data attribute.%s\n", es);
- ntfs_attr_put_search_ctx(ctx);
- mft_na->allocated_size += nr << vol->cluster_size_bits;
- /*
- * The only thing that is now wrong is ->allocated_size of the
- * base attribute extent which chkdsk should be able to fix.
- */
- errno = err;
- return -1;
- }
- m = ctx->mrec;
- a = ctx->attr;
- a->u.nonres.highest_vcn = cpu_to_sle64(old_last_vcn - 1);
- errno = err;
-undo_alloc:
- err = errno;
- if (ntfs_cluster_free(vol, mft_na, old_last_vcn, -1) < 0)
- ntfs_log_error("Failed to free clusters from mft data "
- "attribute.%s\n", es);
- if (ntfs_rl_truncate(&mft_na->rl, old_last_vcn))
- ntfs_log_error("Failed to truncate mft data attribute "
- "runlist.%s\n", es);
- if (mp_rebuilt) {
- if (ntfs_mapping_pairs_build(vol, (u8*)a +
- le16_to_cpu(a->u.nonres.mapping_pairs_offset),
- old_alen - le16_to_cpu(a->u.nonres.mapping_pairs_offset),
- rl2, ll, NULL))
- ntfs_log_error("Failed to restore mapping pairs "
- "array.%s\n", es);
- if (ntfs_attr_record_resize(m, a, old_alen))
- ntfs_log_error("Failed to restore attribute "
- "record.%s\n", es);
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- }
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
- * @vol: volume on which to allocate the mft record
- * @base_ni: open base inode if allocating an extent mft record or NULL
- *
- * Allocate an mft record in $MFT/$DATA of an open ntfs volume @vol.
- *
- * If @base_ni is NULL make the mft record a base mft record and allocate it at
- * the default allocator position.
- *
- * If @base_ni is not NULL make the allocated mft record an extent record,
- * allocate it starting at the mft record after the base mft record and attach
- * the allocated and opened ntfs inode to the base inode @base_ni.
- *
- * On success return the now opened ntfs (extent) inode of the mft record.
- *
- * On error return NULL with errno set to the error code.
- *
- * To find a free mft record, we scan the mft bitmap for a zero bit. To
- * optimize this we start scanning at the place specified by @base_ni or if
- * @base_ni is NULL we start where we last stopped and we perform wrap around
- * when we reach the end. Note, we do not try to allocate mft records below
- * number 24 because numbers 0 to 15 are the defined system files anyway and 16
- * to 24 are special in that they are used for storing extension mft records
- * for the $DATA attribute of $MFT. This is required to avoid the possibility
- * of creating a run list with a circular dependence which once written to disk
- * can never be read in again. Windows will only use records 16 to 24 for
- * normal files if the volume is completely out of space. We never use them
- * which means that when the volume is really out of space we cannot create any
- * more files while Windows can still create up to 8 small files. We can start
- * doing this at some later time, it does not matter much for now.
- *
- * When scanning the mft bitmap, we only search up to the last allocated mft
- * record. If there are no free records left in the range 24 to number of
- * allocated mft records, then we extend the $MFT/$DATA attribute in order to
- * create free mft records. We extend the allocated size of $MFT/$DATA by 16
- * records at a time or one cluster, if cluster size is above 16kiB. If there
- * is not sufficient space to do this, we try to extend by a single mft record
- * or one cluster, if cluster size is above the mft record size, but we only do
- * this if there is enough free space, which we know from the values returned
- * by the failed cluster allocation function when we tried to do the first
- * allocation.
- *
- * No matter how many mft records we allocate, we initialize only the first
- * allocated mft record, incrementing mft data size and initialized size
- * accordingly, open an ntfs_inode for it and return it to the caller, unless
- * there are less than 24 mft records, in which case we allocate and initialize
- * mft records until we reach record 24 which we consider as the first free mft
- * record for use by normal files.
- *
- * If during any stage we overflow the initialized data in the mft bitmap, we
- * extend the initialized size (and data size) by 8 bytes, allocating another
- * cluster if required. The bitmap data size has to be at least equal to the
- * number of mft records in the mft, but it can be bigger, in which case the
- * superfluous bits are padded with zeroes.
- *
- * Thus, when we return successfully (return value non-zero), we will have:
- * - initialized / extended the mft bitmap if necessary,
- * - initialized / extended the mft data if necessary,
- * - set the bit corresponding to the mft record being allocated in the
- * mft bitmap,
- * - open an ntfs_inode for the allocated mft record, and we will
- * - return the ntfs_inode.
- *
- * On error (return value zero), nothing will have changed. If we had changed
- * anything before the error occurred, we will have reverted back to the
- * starting state before returning to the caller. Thus, except for bugs, we
- * should always leave the volume in a consistent state when returning from
- * this function.
- *
- * Note, this function cannot make use of most of the normal functions, like
- * for example for attribute resizing, etc, because when the run list overflows
- * the base mft record and an attribute list is used, it is very important that
- * the extension mft records used to store the $DATA attribute of $MFT can be
- * reached without having to read the information contained inside them, as
- * this would make it impossible to find them in the first place after the
- * volume is dismounted. $MFT/$BITMAP probably does not need to follow this
- * rule because the bitmap is not essential for finding the mft records, but on
- * the other hand, handling the bitmap in this special way would make life
- * easier because otherwise there might be circular invocations of functions
- * when reading the bitmap but if we are careful, we should be able to avoid
- * all problems.
- */
-ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
-{
- s64 ll, bit, old_data_initialized, old_data_size;
- ntfs_attr *mft_na, *mftbmp_na;
- ntfs_attr_search_ctx *ctx;
- MFT_RECORD *m;
- ATTR_RECORD *a;
- ntfs_inode *ni;
- int err;
- le16 seq_no, usn;
-
- if (base_ni)
- ntfs_log_trace("Entering (allocating an extent mft record for "
- "base mft record 0x%llx).\n",
- (long long)base_ni->mft_no);
- else
- ntfs_log_trace("Entering (allocating a base mft record).\n");
- if (!vol || !vol->mft_na || !vol->mftbmp_na) {
- errno = EINVAL;
- return NULL;
- }
- mft_na = vol->mft_na;
- mftbmp_na = vol->mftbmp_na;
- bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
- if (bit >= 0) {
- ntfs_log_debug("Found free record (#1), bit 0x%llx.\n",
- (long long)bit);
- goto found_free_rec;
- }
- if (errno != ENOSPC)
- return NULL;
- /*
- * No free mft records left. If the mft bitmap already covers more
- * than the currently used mft records, the next records are all free,
- * so we can simply allocate the first unused mft record.
- * Note: We also have to make sure that the mft bitmap at least covers
- * the first 24 mft records as they are special and whilst they may not
- * be in use, we do not allocate from them.
- */
- ll = mft_na->initialized_size >> vol->mft_record_size_bits;
- if (mftbmp_na->initialized_size << 3 > ll &&
- mftbmp_na->initialized_size > 3) {
- bit = ll;
- if (bit < 24)
- bit = 24;
- ntfs_log_debug("Found free record (#2), bit 0x%llx.\n",
- (long long)bit);
- goto found_free_rec;
- }
- /*
- * The mft bitmap needs to be expanded until it covers the first unused
- * mft record that we can allocate.
- * Note: The smallest mft record we allocate is mft record 24.
- */
- ntfs_log_debug("Status of mftbmp before extension: allocated_size 0x%llx, "
- "data_size 0x%llx, initialized_size 0x%llx.\n",
- (long long)mftbmp_na->allocated_size,
- (long long)mftbmp_na->data_size,
- (long long)mftbmp_na->initialized_size);
- if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) {
- /* Need to extend bitmap by one more cluster. */
- ntfs_log_debug("mftbmp: initialized_size + 8 > allocated_size.\n");
- if (ntfs_mft_bitmap_extend_allocation(vol))
- goto err_out;
- ntfs_log_debug("Status of mftbmp after allocation extension: "
- "allocated_size 0x%llx, data_size 0x%llx, "
- "initialized_size 0x%llx.\n",
- (long long)mftbmp_na->allocated_size,
- (long long)mftbmp_na->data_size,
- (long long)mftbmp_na->initialized_size);
- }
- /*
- * We now have sufficient allocated space, extend the initialized_size
- * as well as the data_size if necessary and fill the new space with
- * zeroes.
- */
- bit = mftbmp_na->initialized_size << 3;
- if (ntfs_mft_bitmap_extend_initialized(vol))
- goto err_out;
- ntfs_log_debug("Status of mftbmp after initialized extension: "
- "allocated_size 0x%llx, data_size 0x%llx, "
- "initialized_size 0x%llx.\n",
- (long long)mftbmp_na->allocated_size,
- (long long)mftbmp_na->data_size,
- (long long)mftbmp_na->initialized_size);
- ntfs_log_debug("Found free record (#3), bit 0x%llx.\n", (long long)bit);
-found_free_rec:
- /* @bit is the found free mft record, allocate it in the mft bitmap. */
- ntfs_log_debug("At found_free_rec.\n");
- if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {
- ntfs_log_error("Failed to allocate bit in mft bitmap.\n");
- goto err_out;
- }
- ntfs_log_debug("Set bit 0x%llx in mft bitmap.\n", (long long)bit);
- /* The mft bitmap is now uptodate. Deal with mft data attribute now. */
- ll = (bit + 1) << vol->mft_record_size_bits;
- if (ll <= mft_na->initialized_size) {
- ntfs_log_debug("Allocated mft record already initialized.\n");
- goto mft_rec_already_initialized;
- }
- ntfs_log_debug("Initializing allocated mft record.\n");
- /*
- * The mft record is outside the initialized data. Extend the mft data
- * attribute until it covers the allocated record. The loop is only
- * actually traversed more than once when a freshly formatted volume is
- * first written to so it optimizes away nicely in the common case.
- */
- ntfs_log_debug("Status of mft data before extension: "
- "allocated_size 0x%llx, data_size 0x%llx, "
- "initialized_size 0x%llx.\n",
- (long long)mft_na->allocated_size,
- (long long)mft_na->data_size,
- (long long)mft_na->initialized_size);
- while (ll > mft_na->allocated_size) {
- if (ntfs_mft_data_extend_allocation(vol))
- goto undo_mftbmp_alloc;
- ntfs_log_debug("Status of mft data after allocation extension: "
- "allocated_size 0x%llx, data_size 0x%llx, "
- "initialized_size 0x%llx.\n",
- (long long)mft_na->allocated_size,
- (long long)mft_na->data_size,
- (long long)mft_na->initialized_size);
- }
- old_data_initialized = mft_na->initialized_size;
- old_data_size = mft_na->data_size;
- /*
- * Extend mft data initialized size (and data size of course) to reach
- * the allocated mft record, formatting the mft records along the way.
- * Note: We only modify the ntfs_attr structure as that is all that is
- * needed by ntfs_mft_record_format(). We will update the attribute
- * record itself in one fell swoop later on.
- */
- while (ll > mft_na->initialized_size) {
- s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
- mft_na->initialized_size += vol->mft_record_size;
- if (mft_na->initialized_size > mft_na->data_size)
- mft_na->data_size = mft_na->initialized_size;
- ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);
- err = ntfs_mft_record_format(vol, ll2);
- if (err) {
- ntfs_log_error("Failed to format mft record.\n");
- goto undo_data_init;
- }
- }
- /* Update the mft data attribute record to reflect the new sizes. */
- ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
- if (!ctx) {
- ntfs_log_error("Failed to get search context.\n");
- goto undo_data_init;
- }
- if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
- 0, NULL, 0, ctx)) {
- ntfs_log_error("Failed to find first attribute extent of "
- "mft data attribute.\n");
- ntfs_attr_put_search_ctx(ctx);
- goto undo_data_init;
- }
- a = ctx->attr;
- a->u.nonres.initialized_size = cpu_to_sle64(mft_na->initialized_size);
- a->u.nonres.data_size = cpu_to_sle64(mft_na->data_size);
- /* Ensure the changes make it to disk. */
- ntfs_inode_mark_dirty(ctx->ntfs_ino);
- ntfs_attr_put_search_ctx(ctx);
- ntfs_log_debug("Status of mft data after mft record initialization: "
- "allocated_size 0x%llx, data_size 0x%llx, "
- "initialized_size 0x%llx.\n",
- (long long)mft_na->allocated_size,
- (long long)mft_na->data_size,
- (long long)mft_na->initialized_size);
- /* Sanity checks. */
- if (mft_na->data_size > mft_na->allocated_size ||
- mft_na->initialized_size > mft_na->data_size)
- NTFS_BUG("mft_na sanity checks failed");
- /* Sync MFT to disk now in order to minimize data-loss. */
- if (ntfs_inode_sync(mft_na->ni)) {
- ntfs_log_debug("mft sync after extension failed. rolling back.");
- goto undo_data_init;
- }
-mft_rec_already_initialized:
- /*
- * We now have allocated and initialized the mft record. Need to read
- * it from disk and re-format it, preserving the sequence number if it
- * is not zero as well as the update sequence number if it is not zero
- * or -1 (0xffff).
- */
- m = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size);
- if (!m)
- goto undo_mftbmp_alloc;
-
- if (ntfs_mft_record_read(vol, bit, m)) {
- err = errno;
- ntfs_log_error("Failed to read mft record.\n");
- free(m);
- errno = err;
- goto undo_mftbmp_alloc;
- }
- /* Sanity check that the mft record is really not in use. */
- if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
- ntfs_log_error("Mft record 0x%llx was marked unused in "
- "mft bitmap but is marked used itself. "
- "Corrupt filesystem or library bug! "
- "Run chkdsk immediately!\n", (long long)bit);
- free(m);
- errno = EIO;
- goto undo_mftbmp_alloc;
- }
- seq_no = m->sequence_number;
- usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
- if (ntfs_mft_record_layout(vol, bit, m)) {
- err = errno;
- ntfs_log_error("Failed to re-format mft record.\n");
- free(m);
- errno = err;
- goto undo_mftbmp_alloc;
- }
- if (seq_no)
- m->sequence_number = seq_no;
- if (usn && le16_to_cpu(usn) != 0xffff)
- *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn;
- /* Set the mft record itself in use. */
- m->flags |= MFT_RECORD_IN_USE;
- /* Now need to open an ntfs inode for the mft record. */
- ni = ntfs_inode_allocate(vol);
- if (!ni) {
- err = errno;
- ntfs_log_error("Failed to allocate buffer for inode.\n");
- free(m);
- errno = err;
- goto undo_mftbmp_alloc;
- }
- ni->mft_no = bit;
- ni->mrec = m;
- /*
- * If we are allocating an extent mft record, make the opened inode an
- * extent inode and attach it to the base inode. Also, set the base
- * mft record reference in the extent inode.
- */
- if (base_ni) {
- ni->nr_extents = -1;
- ni->u.base_ni = base_ni;
- m->base_mft_record = MK_LE_MREF(base_ni->mft_no,
- le16_to_cpu(base_ni->mrec->sequence_number));
- /*
- * Attach the extent inode to the base inode, reallocating
- * memory if needed.
- */
- if (!(base_ni->nr_extents & 3)) {
- ntfs_inode **extent_nis;
- int i;
-
- i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
- extent_nis = (ntfs_inode**)ntfs_malloc(i);
- if (!extent_nis) {
- err = errno;
- free(m);
- free(ni);
- errno = err;
- goto undo_mftbmp_alloc;
- }
- if (base_ni->u.extent_nis) {
- memcpy(extent_nis, base_ni->u.extent_nis,
- i - 4 * sizeof(ntfs_inode *));
- free(base_ni->u.extent_nis);
- }
- base_ni->u.extent_nis = extent_nis;
- }
- base_ni->u.extent_nis[base_ni->nr_extents++] = ni;
- }
- /* Make sure the allocated inode is written out to disk later. */
- ntfs_inode_mark_dirty(ni);
- /* Initialize time, allocated and data size in ntfs_inode struct. */
- ni->data_size = ni->allocated_size = 0;
- ni->flags = 0;
- ni->creation_time = ni->last_data_change_time =
- ni->last_mft_change_time =
- ni->last_access_time = time(NULL);
- if (!base_ni) {
- /* Update the default mft allocation position if it was used. */
- vol->mft_data_pos = bit + 1;
- /* Add inode to cache. */
- __ntfs_inode_add_to_cache(ni);
- }
- /* Return the opened, allocated inode of the allocated mft record. */
- ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n",
- base_ni ? "extent " : "", (long long)bit);
- return ni;
-undo_data_init:
- mft_na->initialized_size = old_data_initialized;
- mft_na->data_size = old_data_size;
-undo_mftbmp_alloc:
- err = errno;
- if (ntfs_bitmap_clear_bit(mftbmp_na, bit))
- ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es);
- errno = err;
-err_out:
- if (!errno)
- errno = EIO;
- return NULL;
-}
-
-/**
- * ntfs_mft_record_free - free an mft record on an ntfs volume
- * @vol: volume on which to free the mft record
- * @ni: open ntfs inode of the mft record to free
- *
- * Free the mft record of the open inode @ni on the mounted ntfs volume @vol.
- * Note that this function calls ntfs_inode_close() internally and hence you
- * cannot use the pointer @ni any more after this function returns success.
- *
- * On success return 0 and on error return -1 with errno set to the error code.
- */
-int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
-{
- u64 mft_no;
- int err;
- u16 seq_no;
- le16 old_seq_no;
-
- ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
-
- if (!vol || !vol->mftbmp_na || !ni) {
- errno = EINVAL;
- return -1;
- }
-
- /* Cache the mft reference for later. */
- mft_no = ni->mft_no;
-
- /* Mark the mft record as not in use. */
- ni->mrec->flags &= ~MFT_RECORD_IN_USE;
-
- /* Increment the sequence number, skipping zero, if it is not zero. */
- old_seq_no = ni->mrec->sequence_number;
- seq_no = le16_to_cpu(old_seq_no);
- if (seq_no == 0xffff)
- seq_no = 1;
- else if (seq_no)
- seq_no++;
- ni->mrec->sequence_number = cpu_to_le16(seq_no);
-
- /* Set the inode dirty and write it out. */
- ntfs_inode_mark_dirty(ni);
- if (ntfs_inode_sync(ni)) {
- err = errno;
- goto sync_rollback;
- }
-
- /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
- if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) {
- err = errno;
- // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
- // error, this could be changed to goto sync_rollback;
- goto bitmap_rollback;
- }
-
- /* Throw away the now freed inode. */
- if (!ntfs_inode_close(ni))
- return 0;
- err = errno;
-
- /* Rollback what we did... */
-bitmap_rollback:
- if (ntfs_bitmap_set_bit(vol->mftbmp_na, mft_no))
- ntfs_log_debug("Eeek! Rollback failed in ntfs_mft_record_free(). "
- "Leaving inconsistent metadata!\n");
-sync_rollback:
- ni->mrec->flags |= MFT_RECORD_IN_USE;
- ni->mrec->sequence_number = old_seq_no;
- ntfs_inode_mark_dirty(ni);
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_mft_usn_dec - Decrement USN by one
- * @mrec: pointer to an mft record
- *
- * On success return 0 and on error return -1 with errno set.
- */
-int ntfs_mft_usn_dec(MFT_RECORD *mrec)
-{
- u16 usn;
- le16 *usnp;
-
- if (!mrec) {
- errno = EINVAL;
- return -1;
- }
- usnp = (le16 *)((char *)mrec + le16_to_cpu(mrec->usa_ofs));
- usn = le16_to_cpup(usnp);
- if (usn-- <= 1)
- usn = 0xfffe;
- *usnp = cpu_to_le16(usn);
-
- return 0;
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/misc.c b/usr/src/lib/libntfs/common/libntfs/misc.c
deleted file mode 100644
index 26a51c13c9..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/misc.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * misc.c - Miscellaneous functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2006 Szabolcs Szakacsits
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "compat.h"
-#include "support.h"
-#include "logging.h"
-
-/**
- * ntfs_calloc - A logging supported calloc(3)
- *
- * Return a pointer to the allocated memory or NULL if the request fails.
- * Memory is initialized with zeros.
- */
-void *ntfs_calloc(size_t size)
-{
- void *p;
-
- p = calloc(1, size);
- if (!p)
- ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
- return p;
-}
-
-/**
- * ntfs_malloc - A logging supported malloc(3)
- *
- * Return a pointer to the allocated memory or NULL if the request fails.
- * Memory is uninitialized.
- */
-void *ntfs_malloc(size_t size)
-{
- void *p;
-
- p = malloc(size);
- if (!p)
- ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
- return p;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/mst.c b/usr/src/lib/libntfs/common/libntfs/mst.c
deleted file mode 100644
index 2b48e992c0..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/mst.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/**
- * mst.c - Multi sector fixup handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2004 Anton Altaparmakov
- * Copyright (c) 2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "mst.h"
-
-/**
- * ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
- * @b: pointer to the data to deprotect
- * @size: size in bytes of @b
- *
- * Perform the necessary post read multi sector transfer fixups and detect the
- * presence of incomplete multi sector transfers. - In that case, overwrite the
- * magic of the ntfs record header being processed with "BAAD" (in memory only!)
- * and abort processing.
- *
- * Return 0 on success and -1 on error, with errno set to the error code. The
- * following error codes are defined:
- * EINVAL Invalid arguments or invalid NTFS record in buffer @b.
- * EIO Multi sector transfer error was detected. Magic of the NTFS
- * record in @b will have been set to "BAAD".
- */
-int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
-{
- u16 usa_ofs, usa_count, usn;
- u16 *usa_pos, *data_pos;
-
- /* Setup the variables. */
- usa_ofs = le16_to_cpu(b->usa_ofs);
- /* Decrement usa_count to get number of fixups. */
- usa_count = le16_to_cpu(b->usa_count) - 1;
- /* Size and alignment checks. */
- if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
- (u32)(usa_ofs + (usa_count * 2)) > size ||
- (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
- errno = EINVAL;
- return -1;
- }
- /* Position of usn in update sequence array. */
- usa_pos = (u16*)b + usa_ofs/sizeof(u16);
- /*
- * The update sequence number which has to be equal to each of the
- * u16 values before they are fixed up. Note no need to care for
- * endianness since we are comparing and moving data for on disk
- * structures which means the data is consistent. - If it is
- * consistency the wrong endianness it doesn't make any difference.
- */
- usn = *usa_pos;
- /*
- * Position in protected data of first u16 that needs fixing up.
- */
- data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
- /*
- * Check for incomplete multi sector transfer(s).
- */
- while (usa_count--) {
- if (*data_pos != usn) {
- /*
- * Incomplete multi sector transfer detected! )-:
- * Set the magic to "BAAD" and return failure.
- * Note that magic_BAAD is already converted to le32.
- */
- b->magic = magic_BAAD;
- errno = EIO;
- return -1;
- }
- data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
- }
- /* Re-setup the variables. */
- usa_count = le16_to_cpu(b->usa_count) - 1;
- data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
- /* Fixup all sectors. */
- while (usa_count--) {
- /*
- * Increment position in usa and restore original data from
- * the usa into the data buffer.
- */
- *data_pos = *(++usa_pos);
- /* Increment position in data as well. */
- data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
- }
- return 0;
-}
-
-/**
- * ntfs_mst_pre_write_fixup - apply multi sector transfer protection
- * @b: pointer to the data to protect
- * @size: size in bytes of @b
- *
- * Perform the necessary pre write multi sector transfer fixup on the data
- * pointer to by @b of @size.
- *
- * Return 0 if fixups applied successfully or -1 if no fixups were performed
- * due to errors. In that case errno i set to the error code (EINVAL).
- *
- * NOTE: We consider the absence / invalidity of an update sequence array to
- * mean error. This means that you have to create a valid update sequence
- * array header in the ntfs record before calling this function, otherwise it
- * will fail (the header needs to contain the position of the update sequence
- * array together with the number of elements in the array). You also need to
- * initialise the update sequence number before calling this function
- * otherwise a random word will be used (whatever was in the record at that
- * position at that time).
- */
-int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
-{
- u16 usa_ofs, usa_count, usn;
- le16 *usa_pos, *data_pos, usnle;
-
- /* Sanity check + only fixup if it makes sense. */
- if (!b || ntfs_is_baad_record(b->magic) ||
- ntfs_is_hole_record(b->magic)) {
- errno = EINVAL;
- return -1;
- }
- /* Setup the variables. */
- usa_ofs = le16_to_cpu(b->usa_ofs);
- /* Decrement usa_count to get number of fixups. */
- usa_count = le16_to_cpu(b->usa_count) - 1;
- /* Size and alignment checks. */
- if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
- (u32)(usa_ofs + (usa_count * 2)) > size ||
- (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
- errno = EINVAL;
- return -1;
- }
- /* Position of usn in update sequence array. */
- usa_pos = (le16*)((u8*)b + usa_ofs);
- /*
- * Cyclically increment the update sequence number
- * (skipping 0 and -1, i.e. 0xffff).
- */
- usn = le16_to_cpup(usa_pos) + 1;
- if (usn == 0xffff || !usn)
- usn = 1;
- usnle = cpu_to_le16(usn);
- *usa_pos = usnle;
- /* Position in data of first u16 that needs fixing up. */
- data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
- /* Fixup all sectors. */
- while (usa_count--) {
- /*
- * Increment the position in the usa and save the
- * original data from the data buffer into the usa.
- */
- *(++usa_pos) = *data_pos;
- /* Apply fixup to data. */
- *data_pos = usnle;
- /* Increment position in data as well. */
- data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
- }
- return 0;
-}
-
-/**
- * ntfs_mst_post_write_fixup - deprotect multi sector transfer protected data
- * @b: pointer to the data to deprotect
- *
- * Perform the necessary post write multi sector transfer fixup, not checking
- * for any errors, because we assume we have just used
- * ntfs_mst_pre_write_fixup(), thus the data will be fine or we would never
- * have gotten here.
- */
-void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
-{
- u16 *usa_pos, *data_pos;
-
- u16 usa_ofs = le16_to_cpu(b->usa_ofs);
- u16 usa_count = le16_to_cpu(b->usa_count) - 1;
-
- /* Position of usn in update sequence array. */
- usa_pos = (u16*)b + usa_ofs/sizeof(u16);
-
- /* Position in protected data of first u16 that needs fixing up. */
- data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
-
- /* Fixup all sectors. */
- while (usa_count--) {
- /*
- * Increment position in usa and restore original data from
- * the usa into the data buffer.
- */
- *data_pos = *(++usa_pos);
-
- /* Increment position in data as well. */
- data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
- }
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/runlist.c b/usr/src/lib/libntfs/common/libntfs/runlist.c
deleted file mode 100644
index d70b643a88..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/runlist.c
+++ /dev/null
@@ -1,2154 +0,0 @@
-/**
- * runlist.c - Run list handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2002-2005 Anton Altaparmakov
- * Copyright (c) 2002-2005 Richard Russon
- * Copyright (c) 2002-2006 Szabolcs Szakacsits
- * Copyright (c) 2004-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "volume.h"
-#include "layout.h"
-#include "debug.h"
-#include "device.h"
-#include "logging.h"
-
-/**
- * ntfs_rl_mm - runlist memmove
- * @base:
- * @dst:
- * @src:
- * @size:
- *
- * Description...
- *
- * Returns:
- */
-static __inline__ void ntfs_rl_mm(runlist_element *base, int dst, int src,
- int size)
-{
- if ((dst != src) && (size > 0))
- memmove(base + dst, base + src, size * sizeof(*base));
-}
-
-/**
- * ntfs_rl_mc - runlist memory copy
- * @dstbase:
- * @dst:
- * @srcbase:
- * @src:
- * @size:
- *
- * Description...
- *
- * Returns:
- */
-static __inline__ void ntfs_rl_mc(runlist_element *dstbase, int dst,
- runlist_element *srcbase, int src, int size)
-{
- if (size > 0)
- memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
-}
-
-/**
- * ntfs_rl_realloc - Reallocate memory for runlists
- * @rl: original runlist
- * @old_size: number of runlist elements in the original runlist @rl
- * @new_size: number of runlist elements we need space for
- *
- * As the runlists grow, more memory will be required. To prevent large
- * numbers of small reallocations of memory, this function returns a 4kiB block
- * of memory.
- *
- * N.B. If the new allocation doesn't require a different number of 4kiB
- * blocks in memory, the function will return the original pointer.
- *
- * On success, return a pointer to the newly allocated, or recycled, memory.
- * On error, return NULL with errno set to the error code.
- */
-static runlist_element *ntfs_rl_realloc(runlist_element *rl,
- int old_size, int new_size)
-{
- old_size = (old_size * sizeof(runlist_element) + 0xfff) & ~0xfff;
- new_size = (new_size * sizeof(runlist_element) + 0xfff) & ~0xfff;
- if (old_size == new_size)
- return rl;
- return realloc(rl, new_size);
-}
-
-/**
- * ntfs_rl_are_mergeable - test if two runlists can be joined together
- * @dst: original runlist
- * @src: new runlist to test for mergeability with @dst
- *
- * Test if two runlists can be joined together. For this, their VCNs and LCNs
- * must be adjacent.
- *
- * Return: TRUE Success, the runlists can be merged.
- * FALSE Failure, the runlists cannot be merged.
- */
-static BOOL ntfs_rl_are_mergeable(runlist_element *dst,
- runlist_element *src)
-{
- if (!dst || !src) {
- ntfs_log_debug("Eeek. ntfs_rl_are_mergeable() invoked with NULL "
- "pointer!\n");
- return FALSE;
- }
-
- /* We can merge unmapped regions even if they are misaligned. */
- if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED))
- return TRUE;
- /* If the runs are misaligned, we cannot merge them. */
- if ((dst->vcn + dst->length) != src->vcn)
- return FALSE;
- /* If both runs are non-sparse and contiguous, we can merge them. */
- if ((dst->lcn >= 0) && (src->lcn >= 0) &&
- ((dst->lcn + dst->length) == src->lcn))
- return TRUE;
- /* If we are merging two holes, we can merge them. */
- if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE))
- return TRUE;
- /* Cannot merge. */
- return FALSE;
-}
-
-/**
- * __ntfs_rl_merge - merge two runlists without testing if they can be merged
- * @dst: original, destination runlist
- * @src: new runlist to merge with @dst
- *
- * Merge the two runlists, writing into the destination runlist @dst. The
- * caller must make sure the runlists can be merged or this will corrupt the
- * destination runlist.
- */
-static __inline__ void __ntfs_rl_merge(runlist_element *dst,
- runlist_element *src)
-{
- dst->length += src->length;
-}
-
-/**
- * ntfs_rl_append - append a runlist after a given element
- * @dst: original runlist to be worked on
- * @dsize: number of elements in @dst (including end marker)
- * @src: runlist to be inserted into @dst
- * @ssize: number of elements in @src (excluding end marker)
- * @loc: append the new runlist @src after this element in @dst
- *
- * Append the runlist @src after element @loc in @dst. Merge the right end of
- * the new runlist, if necessary. Adjust the size of the hole before the
- * appended runlist.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return NULL, with errno set to the error code. Both runlists are
- * left unmodified.
- */
-static runlist_element *ntfs_rl_append(runlist_element *dst,
- int dsize, runlist_element *src, int ssize, int loc)
-{
- BOOL right = FALSE; /* Right end of @src needs merging */
- int marker; /* End of the inserted runs */
-
- if (!dst || !src) {
- ntfs_log_debug("Eeek. ntfs_rl_append() invoked with NULL "
- "pointer!\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* First, check if the right hand end needs merging. */
- if ((loc + 1) < dsize)
- right = ntfs_rl_are_mergeable(src + ssize - 1, dst + loc + 1);
-
- /* Space required: @dst size + @src size, less one if we merged. */
- dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
- if (!dst)
- return NULL;
- /*
- * We are guaranteed to succeed from here so can start modifying the
- * original runlists.
- */
-
- /* First, merge the right hand end, if necessary. */
- if (right)
- __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
-
- /* marker - First run after the @src runs that have been inserted */
- marker = loc + ssize + 1;
-
- /* Move the tail of @dst out of the way, then copy in @src. */
- ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - loc - 1 - right);
- ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
-
- /* Adjust the size of the preceding hole. */
- dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
-
- /* We may have changed the length of the file, so fix the end marker */
- if (dst[marker].lcn == LCN_ENOENT)
- dst[marker].vcn = dst[marker-1].vcn + dst[marker-1].length;
-
- return dst;
-}
-
-/**
- * ntfs_rl_insert - insert a runlist into another
- * @dst: original runlist to be worked on
- * @dsize: number of elements in @dst (including end marker)
- * @src: new runlist to be inserted
- * @ssize: number of elements in @src (excluding end marker)
- * @loc: insert the new runlist @src before this element in @dst
- *
- * Insert the runlist @src before element @loc in the runlist @dst. Merge the
- * left end of the new runlist, if necessary. Adjust the size of the hole
- * after the inserted runlist.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return NULL, with errno set to the error code. Both runlists are
- * left unmodified.
- */
-static runlist_element *ntfs_rl_insert(runlist_element *dst,
- int dsize, runlist_element *src, int ssize, int loc)
-{
- BOOL left = FALSE; /* Left end of @src needs merging */
- BOOL disc = FALSE; /* Discontinuity between @dst and @src */
- int marker; /* End of the inserted runs */
-
- if (!dst || !src) {
- ntfs_log_debug("Eeek. ntfs_rl_insert() invoked with NULL "
- "pointer!\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* disc => Discontinuity between the end of @dst and the start of @src.
- * This means we might need to insert a "notmapped" run.
- */
- if (loc == 0)
- disc = (src[0].vcn > 0);
- else {
- s64 merged_length;
-
- left = ntfs_rl_are_mergeable(dst + loc - 1, src);
-
- merged_length = dst[loc - 1].length;
- if (left)
- merged_length += src->length;
-
- disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
- }
-
- /* Space required: @dst size + @src size, less one if we merged, plus
- * one if there was a discontinuity.
- */
- dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc);
- if (!dst)
- return NULL;
- /*
- * We are guaranteed to succeed from here so can start modifying the
- * original runlist.
- */
-
- if (left)
- __ntfs_rl_merge(dst + loc - 1, src);
-
- /*
- * marker - First run after the @src runs that have been inserted
- * Nominally: marker = @loc + @ssize (location + number of runs in @src)
- * If "left", then the first run in @src has been merged with one in @dst.
- * If "disc", then @dst and @src don't meet and we need an extra run to fill the gap.
- */
- marker = loc + ssize - left + disc;
-
- /* Move the tail of @dst out of the way, then copy in @src. */
- ntfs_rl_mm(dst, marker, loc, dsize - loc);
- ntfs_rl_mc(dst, loc + disc, src, left, ssize - left);
-
- /* Adjust the VCN of the first run after the insertion ... */
- dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length;
- /* ... and the length. */
- if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED)
- dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn;
-
- /* Writing beyond the end of the file and there's a discontinuity. */
- if (disc) {
- if (loc > 0) {
- dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length;
- dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
- } else {
- dst[loc].vcn = 0;
- dst[loc].length = dst[loc + 1].vcn;
- }
- dst[loc].lcn = LCN_RL_NOT_MAPPED;
- }
- return dst;
-}
-
-/**
- * ntfs_rl_replace - overwrite a runlist element with another runlist
- * @dst: original runlist to be worked on
- * @dsize: number of elements in @dst (including end marker)
- * @src: new runlist to be inserted
- * @ssize: number of elements in @src (excluding end marker)
- * @loc: index in runlist @dst to overwrite with @src
- *
- * Replace the runlist element @dst at @loc with @src. Merge the left and
- * right ends of the inserted runlist, if necessary.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return NULL, with errno set to the error code. Both runlists are
- * left unmodified.
- */
-static runlist_element *ntfs_rl_replace(runlist_element *dst,
- int dsize, runlist_element *src, int ssize, int loc)
-{
- signed delta;
- BOOL left = FALSE; /* Left end of @src needs merging */
- BOOL right = FALSE; /* Right end of @src needs merging */
- int tail; /* Start of tail of @dst */
- int marker; /* End of the inserted runs */
-
- if (!dst || !src) {
- ntfs_log_debug("Eeek. ntfs_rl_replace() invoked with NULL "
- "pointer!\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* First, see if the left and right ends need merging. */
- if ((loc + 1) < dsize)
- right = ntfs_rl_are_mergeable(src + ssize - 1, dst + loc + 1);
- if (loc > 0)
- left = ntfs_rl_are_mergeable(dst + loc - 1, src);
-
- /* Allocate some space. We'll need less if the left, right, or both
- * ends get merged. The -1 accounts for the run being replaced.
- */
- delta = ssize - 1 - left - right;
- if (delta > 0) {
- dst = ntfs_rl_realloc(dst, dsize, dsize + delta);
- if (!dst)
- return NULL;
- }
- /*
- * We are guaranteed to succeed from here so can start modifying the
- * original runlists.
- */
-
- /* First, merge the left and right ends, if necessary. */
- if (right)
- __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
- if (left)
- __ntfs_rl_merge(dst + loc - 1, src);
-
- /*
- * tail - Offset of the tail of @dst
- * Nominally: @tail = @loc + 1 (location, skipping the replaced run)
- * If "right", then one of @dst's runs is already merged into @src.
- */
- tail = loc + right + 1;
-
- /*
- * marker - First run after the @src runs that have been inserted
- * Nominally: @marker = @loc + @ssize (location + number of runs in @src)
- * If "left", then the first run in @src has been merged with one in @dst.
- */
- marker = loc + ssize - left;
-
- /* Move the tail of @dst out of the way, then copy in @src. */
- ntfs_rl_mm(dst, marker, tail, dsize - tail);
- ntfs_rl_mc(dst, loc, src, left, ssize - left);
-
- /* We may have changed the length of the file, so fix the end marker */
- if (((dsize - tail) > 0) && (dst[marker].lcn == LCN_ENOENT))
- dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length;
-
- return dst;
-}
-
-/**
- * ntfs_rl_split - insert a runlist into the centre of a hole
- * @dst: original runlist to be worked on
- * @dsize: number of elements in @dst (including end marker)
- * @src: new runlist to be inserted
- * @ssize: number of elements in @src (excluding end marker)
- * @loc: index in runlist @dst at which to split and insert @src
- *
- * Split the runlist @dst at @loc into two and insert @new in between the two
- * fragments. No merging of runlists is necessary. Adjust the size of the
- * holes either side.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @dst and @src are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return NULL, with errno set to the error code. Both runlists are
- * left unmodified.
- */
-static runlist_element *ntfs_rl_split(runlist_element *dst,
- int dsize, runlist_element *src, int ssize, int loc)
-{
- if (!dst || !src) {
- ntfs_log_trace("Invoked with NULL pointer!\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* Space required: @dst size + @src size + one new hole. */
- dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
- if (!dst)
- return dst;
- /*
- * We are guaranteed to succeed from here so can start modifying the
- * original runlists.
- */
-
- /* Move the tail of @dst out of the way, then copy in @src. */
- ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc);
- ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
-
- /* Adjust the size of the holes either size of @src. */
- dst[loc].length = dst[loc+1].vcn - dst[loc].vcn;
- dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length;
- dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn;
-
- return dst;
-}
-
-
-/**
- * ntfs_runlists_merge - merge two runlists into one
- * @drl: original runlist to be worked on
- * @srl: new runlist to be merged into @drl
- *
- * First we sanity check the two runlists @srl and @drl to make sure that they
- * are sensible and can be merged. The runlist @srl must be either after the
- * runlist @drl or completely within a hole (or unmapped region) in @drl.
- *
- * Merging of runlists is necessary in two cases:
- * 1. When attribute lists are used and a further extent is being mapped.
- * 2. When new clusters are allocated to fill a hole or extend a file.
- *
- * There are four possible ways @srl can be merged. It can:
- * - be inserted at the beginning of a hole,
- * - split the hole in two and be inserted between the two fragments,
- * - be appended at the end of a hole, or it can
- * - replace the whole hole.
- * It can also be appended to the end of the runlist, which is just a variant
- * of the insert case.
- *
- * On success, return a pointer to the new, combined, runlist. Note, both
- * runlists @drl and @srl are deallocated before returning so you cannot use
- * the pointers for anything any more. (Strictly speaking the returned runlist
- * may be the same as @dst but this is irrelevant.)
- *
- * On error, return NULL, with errno set to the error code. Both runlists are
- * left unmodified. The following error codes are defined:
- * ENOMEM Not enough memory to allocate runlist array.
- * EINVAL Invalid parameters were passed in.
- * ERANGE The runlists overlap and cannot be merged.
- */
-runlist_element *ntfs_runlists_merge(runlist_element *drl,
- runlist_element *srl)
-{
- int di, si; /* Current index into @[ds]rl. */
- int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */
- int dins; /* Index into @drl at which to insert @srl. */
- int dend, send; /* Last index into @[ds]rl. */
- int dfinal, sfinal; /* The last index into @[ds]rl with
- lcn >= LCN_HOLE. */
- int marker = 0;
- VCN marker_vcn = 0;
-
- ntfs_log_debug("dst:\n");
- ntfs_debug_runlist_dump(drl);
- ntfs_log_debug("src:\n");
- ntfs_debug_runlist_dump(srl);
-
- /* Check for silly calling... */
- if (!srl)
- return drl;
-
- /* Check for the case where the first mapping is being done now. */
- if (!drl) {
- drl = srl;
- /* Complete the source runlist if necessary. */
- if (drl[0].vcn) {
- /* Scan to the end of the source runlist. */
- for (dend = 0; drl[dend].length; dend++)
- ;
- dend++;
- drl = ntfs_rl_realloc(drl, dend, dend + 1);
- if (!drl)
- return drl;
- /* Insert start element at the front of the runlist. */
- ntfs_rl_mm(drl, 1, 0, dend);
- drl[0].vcn = 0;
- drl[0].lcn = LCN_RL_NOT_MAPPED;
- drl[0].length = drl[1].vcn;
- }
- goto finished;
- }
-
- si = di = 0;
-
- /* Skip any unmapped start element(s) in the source runlist. */
- while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE)
- si++;
-
- /* Can't have an entirely unmapped source runlist. */
- if (!srl[si].length) {
- ntfs_log_debug("Eeek! ntfs_runlists_merge() received entirely "
- "unmapped source runlist.\n");
- errno = EINVAL;
- return NULL;
- }
-
- /* Record the starting points. */
- sstart = si;
-
- /*
- * Skip forward in @drl until we reach the position where @srl needs to
- * be inserted. If we reach the end of @drl, @srl just needs to be
- * appended to @drl.
- */
- for (; drl[di].length; di++) {
- if (drl[di].vcn + drl[di].length > srl[sstart].vcn)
- break;
- }
- dins = di;
-
- /* Sanity check for illegal overlaps. */
- if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
- (srl[si].lcn >= 0)) {
- ntfs_log_debug("Run lists overlap. Cannot merge!\n");
- errno = ERANGE;
- return NULL;
- }
-
- /* Scan to the end of both runlists in order to know their sizes. */
- for (send = si; srl[send].length; send++)
- ;
- for (dend = di; drl[dend].length; dend++)
- ;
-
- if (srl[send].lcn == (LCN)LCN_ENOENT)
- marker_vcn = srl[marker = send].vcn;
-
- /* Scan to the last element with lcn >= LCN_HOLE. */
- for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--)
- ;
- for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--)
- ;
-
- {
- BOOL start;
- BOOL finish;
- int ds = dend + 1; /* Number of elements in drl & srl */
- int ss = sfinal - sstart + 1;
-
- start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */
- (drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */
- finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */
- ((drl[dins].vcn + drl[dins].length) <= /* End of hole */
- (srl[send - 1].vcn + srl[send - 1].length)));
-
- /* Or we'll lose an end marker */
- if (finish && !drl[dins].length)
- ss++;
- if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
- finish = FALSE;
-
- ntfs_log_debug("dfinal = %i, dend = %i\n", dfinal, dend);
- ntfs_log_debug("sstart = %i, sfinal = %i, send = %i\n", sstart, sfinal, send);
- ntfs_log_debug("start = %i, finish = %i\n", start, finish);
- ntfs_log_debug("ds = %i, ss = %i, dins = %i\n", ds, ss, dins);
-
- if (start) {
- if (finish)
- drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins);
- else
- drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins);
- } else {
- if (finish)
- drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins);
- else
- drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins);
- }
- if (!drl) {
- ntfs_log_perror("Merge failed");
- return drl;
- }
- free(srl);
- if (marker) {
- ntfs_log_debug("Triggering marker code.\n");
- for (ds = dend; drl[ds].length; ds++)
- ;
- /* We only need to care if @srl ended after @drl. */
- if (drl[ds].vcn <= marker_vcn) {
- int slots = 0;
-
- if (drl[ds].vcn == marker_vcn) {
- ntfs_log_debug("Old marker = %lli, replacing with "
- "LCN_ENOENT.\n",
- (long long)drl[ds].lcn);
- drl[ds].lcn = (LCN)LCN_ENOENT;
- goto finished;
- }
- /*
- * We need to create an unmapped runlist element in
- * @drl or extend an existing one before adding the
- * ENOENT terminator.
- */
- if (drl[ds].lcn == (LCN)LCN_ENOENT) {
- ds--;
- slots = 1;
- }
- if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) {
- /* Add an unmapped runlist element. */
- if (!slots) {
- /* FIXME/TODO: We need to have the
- * extra memory already! (AIA)
- */
- drl = ntfs_rl_realloc(drl, ds, ds + 2);
- if (!drl)
- goto critical_error;
- slots = 2;
- }
- ds++;
- /* Need to set vcn if it isn't set already. */
- if (slots != 1)
- drl[ds].vcn = drl[ds - 1].vcn +
- drl[ds - 1].length;
- drl[ds].lcn = (LCN)LCN_RL_NOT_MAPPED;
- /* We now used up a slot. */
- slots--;
- }
- drl[ds].length = marker_vcn - drl[ds].vcn;
- /* Finally add the ENOENT terminator. */
- ds++;
- if (!slots) {
- /* FIXME/TODO: We need to have the extra
- * memory already! (AIA)
- */
- drl = ntfs_rl_realloc(drl, ds, ds + 1);
- if (!drl)
- goto critical_error;
- }
- drl[ds].vcn = marker_vcn;
- drl[ds].lcn = (LCN)LCN_ENOENT;
- drl[ds].length = (s64)0;
- }
- }
- }
-
-finished:
- /* The merge was completed successfully. */
- ntfs_log_debug("Merged runlist:\n");
- ntfs_debug_runlist_dump(drl);
- return drl;
-
-critical_error:
- /* Critical error! We cannot afford to fail here. */
- ntfs_log_perror("libntfs: Critical error");
- ntfs_log_debug("Forcing segmentation fault!\n");
- marker_vcn = ((runlist*)NULL)->lcn;
- return drl;
-}
-
-/**
- * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist
- * @vol: ntfs volume on which the attribute resides
- * @attr: attribute record whose mapping pairs array to decompress
- * @old_rl: optional runlist in which to insert @attr's runlist
- *
- * Decompress the attribute @attr's mapping pairs array into a runlist. On
- * success, return the decompressed runlist.
- *
- * If @old_rl is not NULL, decompressed runlist is inserted into the
- * appropriate place in @old_rl and the resultant, combined runlist is
- * returned. The original @old_rl is deallocated.
- *
- * On error, return NULL with errno set to the error code. @old_rl is left
- * unmodified in that case.
- *
- * The following error codes are defined:
- * ENOMEM Not enough memory to allocate runlist array.
- * EIO Corrupt runlist.
- * EINVAL Invalid parameters were passed in.
- * ERANGE The two runlists overlap.
- *
- * FIXME: For now we take the conceptionally simplest approach of creating the
- * new runlist disregarding the already existing one and then splicing the
- * two into one, if that is possible (we check for overlap and discard the new
- * runlist if overlap present before returning NULL, with errno = ERANGE).
- */
-runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
- const ATTR_RECORD *attr, runlist_element *old_rl)
-{
- VCN vcn; /* Current vcn. */
- LCN lcn; /* Current lcn. */
- s64 deltaxcn; /* Change in [vl]cn. */
- runlist_element *rl; /* The output runlist. */
- const u8 *buf; /* Current position in mapping pairs array. */
- const u8 *attr_end; /* End of attribute. */
- int err, rlsize; /* Size of runlist buffer. */
- u16 rlpos; /* Current runlist position in units of
- runlist_elements. */
- u8 b; /* Current byte offset in buf. */
-
- ntfs_log_trace("Entering for attr 0x%x.\n",
- (unsigned)le32_to_cpu(attr->type));
- /* Make sure attr exists and is non-resident. */
- if (!attr || !attr->non_resident ||
- sle64_to_cpu(attr->u.nonres.lowest_vcn) < (VCN)0) {
- errno = EINVAL;
- return NULL;
- }
- /* Start at vcn = lowest_vcn and lcn 0. */
- vcn = sle64_to_cpu(attr->u.nonres.lowest_vcn);
- lcn = 0;
- /* Get start of the mapping pairs array. */
- buf = (const u8*)attr + le16_to_cpu(attr->u.nonres.mapping_pairs_offset);
- attr_end = (const u8*)attr + le32_to_cpu(attr->length);
- if (buf < (const u8*)attr || buf > attr_end) {
- ntfs_log_debug("Corrupt attribute.\n");
- errno = EIO;
- return NULL;
- }
- /* Current position in runlist array. */
- rlpos = 0;
- /* Allocate first 4kiB block and set current runlist size to 4kiB. */
- rlsize = 0x1000;
- rl = ntfs_malloc(rlsize);
- if (!rl)
- return NULL;
- /* Insert unmapped starting element if necessary. */
- if (vcn) {
- rl->vcn = (VCN)0;
- rl->lcn = (LCN)LCN_RL_NOT_MAPPED;
- rl->length = vcn;
- rlpos++;
- }
- while (buf < attr_end && *buf) {
- /*
- * Allocate more memory if needed, including space for the
- * not-mapped and terminator elements.
- */
- if ((int)((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
- runlist_element *rl2;
-
- rlsize += 0x1000;
- rl2 = realloc(rl, rlsize);
- if (!rl2) {
- int eo = errno;
- free(rl);
- errno = eo;
- return NULL;
- }
- rl = rl2;
- }
- /* Enter the current vcn into the current runlist element. */
- rl[rlpos].vcn = vcn;
- /*
- * Get the change in vcn, i.e. the run length in clusters.
- * Doing it this way ensures that we signextend negative values.
- * A negative run length doesn't make any sense, but hey, I
- * didn't make up the NTFS specs and Windows NT4 treats the run
- * length as a signed value so that's how it is...
- */
- b = *buf & 0xf;
- if (b) {
- if (buf + b > attr_end)
- goto io_error;
- for (deltaxcn = (s8)buf[b--]; b; b--)
- deltaxcn = (deltaxcn << 8) + buf[b];
- } else { /* The length entry is compulsory. */
- ntfs_log_debug("Missing length entry in mapping pairs "
- "array.\n");
- deltaxcn = (s64)-1;
- }
- /*
- * Assume a negative length to indicate data corruption and
- * hence clean-up and return NULL.
- */
- if (deltaxcn < 0) {
- ntfs_log_debug("Invalid length in mapping pairs array.\n");
- goto err_out;
- }
- /*
- * Enter the current run length into the current runlist
- * element.
- */
- rl[rlpos].length = deltaxcn;
- /* Increment the current vcn by the current run length. */
- vcn += deltaxcn;
- /*
- * There might be no lcn change at all, as is the case for
- * sparse clusters on NTFS 3.0+, in which case we set the lcn
- * to LCN_HOLE.
- */
- if (!(*buf & 0xf0))
- rl[rlpos].lcn = (LCN)LCN_HOLE;
- else {
- /* Get the lcn change which really can be negative. */
- u8 b2 = *buf & 0xf;
- b = b2 + ((*buf >> 4) & 0xf);
- if (buf + b > attr_end)
- goto io_error;
- for (deltaxcn = (s8)buf[b--]; b > b2; b--)
- deltaxcn = (deltaxcn << 8) + buf[b];
- /* Change the current lcn to it's new value. */
- lcn += deltaxcn;
-#ifdef DEBUG
- /*
- * On NTFS 1.2-, apparently can have lcn == -1 to
- * indicate a hole. But we haven't verified ourselves
- * whether it is really the lcn or the deltaxcn that is
- * -1. So if either is found give us a message so we
- * can investigate it further!
- */
- if (vol->major_ver < 3) {
- if (deltaxcn == (LCN)-1)
- ntfs_log_debug("lcn delta == -1\n");
- if (lcn == (LCN)-1)
- ntfs_log_debug("lcn == -1\n");
- }
-#endif
- /* Check lcn is not below -1. */
- if (lcn < (LCN)-1) {
- ntfs_log_debug("Invalid LCN < -1 in mapping pairs "
- "array.\n");
- goto err_out;
- }
- /* Enter the current lcn into the runlist element. */
- rl[rlpos].lcn = lcn;
- }
- /* Get to the next runlist element. */
- rlpos++;
- /* Increment the buffer position to the next mapping pair. */
- buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1;
- }
- if (buf >= attr_end)
- goto io_error;
- /*
- * If there is a highest_vcn specified, it must be equal to the final
- * vcn in the runlist - 1, or something has gone badly wrong.
- */
- deltaxcn = sle64_to_cpu(attr->u.nonres.highest_vcn);
- if (deltaxcn && vcn - 1 != deltaxcn) {
-mpa_err:
- ntfs_log_debug("Corrupt mapping pairs array in non-resident "
- "attribute.\n");
- goto err_out;
- }
- /* Setup not mapped runlist element if this is the base extent. */
- if (!attr->u.nonres.lowest_vcn) {
- VCN max_cluster;
-
- max_cluster = ((sle64_to_cpu(attr->u.nonres.allocated_size) +
- vol->cluster_size - 1) >>
- vol->cluster_size_bits) - 1;
- /*
- * A highest_vcn of zero means this is a single extent
- * attribute so simply terminate the runlist with LCN_ENOENT).
- */
- if (deltaxcn) {
- /*
- * If there is a difference between the highest_vcn and
- * the highest cluster, the runlist is either corrupt
- * or, more likely, there are more extents following
- * this one.
- */
- if (deltaxcn < max_cluster) {
- ntfs_log_debug("More extents to follow; deltaxcn = "
- "0x%llx, max_cluster = 0x%llx\n",
- (long long)deltaxcn,
- (long long)max_cluster);
- rl[rlpos].vcn = vcn;
- vcn += rl[rlpos].length = max_cluster - deltaxcn;
- rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
- rlpos++;
- } else if (deltaxcn > max_cluster) {
- ntfs_log_debug("Corrupt attribute. deltaxcn = "
- "0x%llx, max_cluster = 0x%llx\n",
- (long long)deltaxcn,
- (long long)max_cluster);
- goto mpa_err;
- }
- }
- rl[rlpos].lcn = (LCN)LCN_ENOENT;
- } else /* Not the base extent. There may be more extents to follow. */
- rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
-
- /* Setup terminating runlist element. */
- rl[rlpos].vcn = vcn;
- rl[rlpos].length = (s64)0;
- /* If no existing runlist was specified, we are done. */
- if (!old_rl) {
- ntfs_log_debug("Mapping pairs array successfully decompressed:\n");
- ntfs_debug_runlist_dump(rl);
- return rl;
- }
- /* Now combine the new and old runlists checking for overlaps. */
- old_rl = ntfs_runlists_merge(old_rl, rl);
- if (old_rl)
- return old_rl;
- err = errno;
- free(rl);
- ntfs_log_debug("Failed to merge runlists.\n");
- errno = err;
- return NULL;
-io_error:
- ntfs_log_debug("Corrupt attribute.\n");
-err_out:
- free(rl);
- errno = EIO;
- return NULL;
-}
-
-/**
- * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist
- * @rl: runlist to use for conversion
- * @vcn: vcn to convert
- *
- * Convert the virtual cluster number @vcn of an attribute into a logical
- * cluster number (lcn) of a device using the runlist @rl to map vcns to their
- * corresponding lcns.
- *
- * Since lcns must be >= 0, we use negative return values with special meaning:
- *
- * Return value Meaning / Description
- * ==================================================
- * -1 = LCN_HOLE Hole / not allocated on disk.
- * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been
- * inserted into the runlist yet.
- * -3 = LCN_ENOENT There is no such vcn in the attribute.
- * -4 = LCN_EINVAL Input parameter error.
- */
-LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
-{
- int i;
-
- if (vcn < (VCN)0)
- return (LCN)LCN_EINVAL;
- /*
- * If rl is NULL, assume that we have found an unmapped runlist. The
- * caller can then attempt to map it and fail appropriately if
- * necessary.
- */
- if (!rl)
- return (LCN)LCN_RL_NOT_MAPPED;
-
- /* Catch out of lower bounds vcn. */
- if (vcn < rl[0].vcn)
- return (LCN)LCN_ENOENT;
-
- for (i = 0; rl[i].length; i++) {
- if (vcn < rl[i+1].vcn) {
- if (rl[i].lcn >= (LCN)0)
- return rl[i].lcn + (vcn - rl[i].vcn);
- return rl[i].lcn;
- }
- }
- /*
- * The terminator element is setup to the correct value, i.e. one of
- * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT.
- */
- if (rl[i].lcn < (LCN)0)
- return rl[i].lcn;
- /* Just in case... We could replace this with BUG() some day. */
- return (LCN)LCN_ENOENT;
-}
-
-/**
- * ntfs_rl_pread - gather read from disk
- * @vol: ntfs volume to read from
- * @rl: runlist specifying where to read the data from
- * @pos: byte position within runlist @rl at which to begin the read
- * @count: number of bytes to read
- * @b: data buffer into which to read from disk
- *
- * This function will read @count bytes from the volume @vol to the data buffer
- * @b gathering the data as specified by the runlist @rl. The read begins at
- * offset @pos into the runlist @rl.
- *
- * On success, return the number of successfully read bytes. If this number is
- * lower than @count this means that the read reached end of file or that an
- * error was encountered during the read so that the read is partial. 0 means
- * nothing was read (also return 0 when @count is 0).
- *
- * On error and nothing has been read, return -1 with errno set appropriately
- * to the return code of ntfs_pread(), or to EINVAL in case of invalid
- * arguments.
- *
- * NOTE: If we encounter EOF while reading we return EIO because we assume that
- * the run list must point to valid locations within the ntfs volume.
- */
-s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
- const s64 pos, s64 count, void *b)
-{
- s64 bytes_read, to_read, ofs, total;
- int err = EIO;
-
- if (!vol || !rl || pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return count;
- /* Seek in @rl to the run containing @pos. */
- for (ofs = 0; rl->length && (ofs + (rl->length <<
- vol->cluster_size_bits) <= pos); rl++)
- ofs += (rl->length << vol->cluster_size_bits);
- /* Offset in the run at which to begin reading. */
- ofs = pos - ofs;
- for (total = 0LL; count; rl++, ofs = 0) {
- if (!rl->length)
- goto rl_err_out;
- if (rl->lcn < (LCN)0) {
- if (rl->lcn != (LCN)LCN_HOLE)
- goto rl_err_out;
- /* It is a hole. Just fill buffer @b with zeroes. */
- to_read = min(count, (rl->length <<
- vol->cluster_size_bits) - ofs);
- memset(b, 0, to_read);
- /* Update counters and proceed with next run. */
- total += to_read;
- count -= to_read;
- b = (u8*)b + to_read;
- continue;
- }
- /* It is a real lcn, read it from the volume. */
- to_read = min(count, (rl->length << vol->cluster_size_bits) -
- ofs);
-retry:
- bytes_read = ntfs_pread(vol->u.dev, (rl->lcn <<
- vol->cluster_size_bits) + ofs, to_read, b);
- /* If everything ok, update progress counters and continue. */
- if (bytes_read > 0) {
- total += bytes_read;
- count -= bytes_read;
- b = (u8*)b + bytes_read;
- continue;
- }
- /* If the syscall was interrupted, try again. */
- if (bytes_read == (s64)-1 && errno == EINTR)
- goto retry;
- if (bytes_read == (s64)-1)
- err = errno;
- goto rl_err_out;
- }
- /* Finally, return the number of bytes read. */
- return total;
-rl_err_out:
- if (total)
- return total;
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_rl_pwrite - scatter write to disk
- * @vol: ntfs volume to write to
- * @rl: runlist specifying where to write the data to
- * @pos: byte position within runlist @rl at which to begin the write
- * @count: number of bytes to write
- * @b: data buffer to write to disk
- *
- * This function will write @count bytes from data buffer @b to the volume @vol
- * scattering the data as specified by the runlist @rl. The write begins at
- * offset @pos into the runlist @rl.
- *
- * On success, return the number of successfully written bytes. If this number
- * is lower than @count this means that the write has been interrupted in
- * flight or that an error was encountered during the write so that the write
- * is partial. 0 means nothing was written (also return 0 when @count is 0).
- *
- * On error and nothing has been written, return -1 with errno set
- * appropriately to the return code of ntfs_pwrite(), or to to EINVAL in case
- * of invalid arguments.
- */
-s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
- const s64 pos, s64 count, void *b)
-{
- s64 written, to_write, ofs, total;
- int err = EIO;
-
- if (!vol || !rl || pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
- if (!count)
- return count;
- /* Seek in @rl to the run containing @pos. */
- for (ofs = 0; rl->length && (ofs + (rl->length <<
- vol->cluster_size_bits) <= pos); rl++)
- ofs += (rl->length << vol->cluster_size_bits);
- /* Offset in the run at which to begin writing. */
- ofs = pos - ofs;
- for (total = 0LL; count; rl++, ofs = 0) {
- if (!rl->length)
- goto rl_err_out;
- if (rl->lcn < (LCN)0) {
- s64 t;
- int cnt;
-
- if (rl->lcn != (LCN)LCN_HOLE)
- goto rl_err_out;
- /*
- * It is a hole. Check if the buffer is zero in this
- * region and if not abort with error.
- */
- to_write = min(count, (rl->length <<
- vol->cluster_size_bits) - ofs);
- written = to_write / sizeof(unsigned long);
- for (t = 0; t < written; t++) {
- if (((unsigned long*)b)[t])
- goto rl_err_out;
- }
- cnt = to_write & (sizeof(unsigned long) - 1);
- if (cnt) {
- int i;
- u8 *b2;
-
- b2 = (u8*)b + (to_write &
- ~(sizeof(unsigned long) - 1));
- for (i = 0; i < cnt; i++) {
- if (b2[i])
- goto rl_err_out;
- }
- }
- /*
- * The buffer region is zero, update progress counters
- * and proceed with next run.
- */
- total += to_write;
- count -= to_write;
- b = (u8*)b + to_write;
- continue;
- }
- /* It is a real lcn, write it to the volume. */
- to_write = min(count, (rl->length << vol->cluster_size_bits) -
- ofs);
-retry:
- if (!NVolReadOnly(vol))
- written = ntfs_pwrite(vol->u.dev, (rl->lcn <<
- vol->cluster_size_bits) + ofs,
- to_write, b);
- else
- written = to_write;
- /* If everything ok, update progress counters and continue. */
- if (written > 0) {
- total += written;
- count -= written;
- b = (u8*)b + written;
- continue;
- }
- /* If the syscall was interrupted, try again. */
- if (written == (s64)-1 && errno == EINTR)
- goto retry;
- if (written == (s64)-1)
- err = errno;
- goto rl_err_out;
- }
- /* Finally, return the number of bytes written. */
- return total;
-rl_err_out:
- if (total)
- return total;
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_rl_fill_zero - fill given region with zeroes
- * @vol: ntfs volume to write to
- * @rl: runlist specifying where to write zeroes to
- * @pos: byte position within runlist @rl at which to begin the zeroing
- * @count: number of bytes to fill with zeros
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-int ntfs_rl_fill_zero(const ntfs_volume *vol, const runlist *rl, s64 pos,
- const s64 count)
-{
- char *buf;
- s64 written, size, end = pos + count;
- int ret = 0;
-
- ntfs_log_trace("pos %lld, count %lld\n", (long long)pos,
- (long long)count);
-
- if (!vol || !rl || pos < 0 || count < 0) {
- errno = EINVAL;
- return -1;
- }
-
- buf = ntfs_calloc(NTFS_BUF_SIZE);
- if (!buf)
- return -1;
-
- while (pos < end) {
- size = min(end - pos, NTFS_BUF_SIZE);
- written = ntfs_rl_pwrite(vol, rl, pos, size, buf);
- if (written <= 0) {
- ntfs_log_perror("Failed to zero space");
- ret = -1;
- break;
- }
- pos += written;
- }
- free(buf);
- return ret;
-}
-
-/**
- * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number
- * @n: number for which to get the number of bytes for
- *
- * Return the number of bytes required to store @n unambiguously as
- * a signed number.
- *
- * This is used in the context of the mapping pairs array to determine how
- * many bytes will be needed in the array to store a given logical cluster
- * number (lcn) or a specific run length.
- *
- * Return the number of bytes written. This function cannot fail.
- */
-int ntfs_get_nr_significant_bytes(const s64 n)
-{
- s64 l = n;
- int i;
- s8 j;
-
- i = 0;
- do {
- l >>= 8;
- i++;
- } while (l != 0LL && l != -1LL);
- j = (n >> 8 * (i - 1)) & 0xff;
- /* If the sign bit is wrong, we need an extra byte. */
- if ((n < 0LL && j >= 0) || (n > 0LL && j < 0))
- i++;
- return i;
-}
-
-/**
- * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array
- * @vol: ntfs volume (needed for the ntfs version)
- * @rl: runlist for which to determine the size of the mapping pairs
- * @start_vcn: vcn at which to start the mapping pairs array
- *
- * Walk the runlist @rl and calculate the size in bytes of the mapping pairs
- * array corresponding to the runlist @rl, starting at vcn @start_vcn. This
- * for example allows us to allocate a buffer of the right size when building
- * the mapping pairs array.
- *
- * If @rl is NULL, just return 1 (for the single terminator byte).
- *
- * Return the calculated size in bytes on success. On error, return -1 with
- * errno set to the error code. The following error codes are defined:
- * EINVAL - Run list contains unmapped elements. Make sure to only pass
- * fully mapped runlists to this function.
- * - @start_vcn is invalid.
- * EIO - The runlist is corrupt.
- */
-int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
- const runlist_element *rl, const VCN start_vcn)
-{
- LCN prev_lcn;
- int rls;
-
- if (start_vcn < 0) {
- ntfs_log_trace("start_vcn %lld (should be >= 0)\n",
- (long long) start_vcn);
- errno = EINVAL;
- return -1;
- }
- if (!rl) {
- if (start_vcn) {
- ntfs_log_trace("rl NULL, start_vcn %lld (should be > 0)\n",
- (long long) start_vcn);
- errno = EINVAL;
- return -1;
- }
- return 1;
- }
- /* Skip to runlist element containing @start_vcn. */
- while (rl->length && start_vcn >= rl[1].vcn)
- rl++;
- if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) {
- errno = EINVAL;
- return -1;
- }
- prev_lcn = 0;
- /* Always need the terminating zero byte. */
- rls = 1;
- /* Do the first partial run if present. */
- if (start_vcn > rl->vcn) {
- s64 delta;
-
- /* We know rl->length != 0 already. */
- if (rl->length < 0 || rl->lcn < LCN_HOLE)
- goto err_out;
- delta = start_vcn - rl->vcn;
- /* Header byte + length. */
- rls += 1 + ntfs_get_nr_significant_bytes(rl->length - delta);
- /*
- * If the logical cluster number (lcn) denotes a hole and we
- * are on NTFS 3.0+, we don't store it at all, i.e. we need
- * zero space. On earlier NTFS versions we just store the lcn.
- * Note: this assumes that on NTFS 1.2-, holes are stored with
- * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
- */
- if (rl->lcn >= 0 || vol->major_ver < 3) {
- prev_lcn = rl->lcn;
- if (rl->lcn >= 0)
- prev_lcn += delta;
- /* Change in lcn. */
- rls += ntfs_get_nr_significant_bytes(prev_lcn);
- }
- /* Go to next runlist element. */
- rl++;
- }
- /* Do the full runs. */
- for (; rl->length; rl++) {
- if (rl->length < 0 || rl->lcn < LCN_HOLE)
- goto err_out;
- /* Header byte + length. */
- rls += 1 + ntfs_get_nr_significant_bytes(rl->length);
- /*
- * If the logical cluster number (lcn) denotes a hole and we
- * are on NTFS 3.0+, we don't store it at all, i.e. we need
- * zero space. On earlier NTFS versions we just store the lcn.
- * Note: this assumes that on NTFS 1.2-, holes are stored with
- * an lcn of -1 and not a delta_lcn of -1 (unless both are -1).
- */
- if (rl->lcn >= 0 || vol->major_ver < 3) {
- /* Change in lcn. */
- rls += ntfs_get_nr_significant_bytes(rl->lcn -
- prev_lcn);
- prev_lcn = rl->lcn;
- }
- }
- return rls;
-err_out:
- if (rl->lcn == LCN_RL_NOT_MAPPED)
- errno = EINVAL;
- else
- errno = EIO;
- return -1;
-}
-
-/**
- * ntfs_write_significant_bytes - write the significant bytes of a number
- * @dst: destination buffer to write to
- * @dst_max: pointer to last byte of destination buffer for bounds checking
- * @n: number whose significant bytes to write
- *
- * Store in @dst, the minimum bytes of the number @n which are required to
- * identify @n unambiguously as a signed number, taking care not to exceed
- * @dest_max, the maximum position within @dst to which we are allowed to
- * write.
- *
- * This is used when building the mapping pairs array of a runlist to compress
- * a given logical cluster number (lcn) or a specific run length to the minimum
- * size possible.
- *
- * Return the number of bytes written on success. On error, i.e. the
- * destination buffer @dst is too small, return -1 with errno set ENOSPC.
- */
-int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
-{
- s64 l = n;
- int i;
- s8 j;
-
- i = 0;
- do {
- if (dst > dst_max)
- goto err_out;
- *dst++ = l & 0xffLL;
- l >>= 8;
- i++;
- } while (l != 0LL && l != -1LL);
- j = (n >> 8 * (i - 1)) & 0xff;
- /* If the sign bit is wrong, we need an extra byte. */
- if (n < 0LL && j >= 0) {
- if (dst > dst_max)
- goto err_out;
- i++;
- *dst = (u8)-1;
- } else if (n > 0LL && j < 0) {
- if (dst > dst_max)
- goto err_out;
- i++;
- *dst = 0;
- }
- return i;
-err_out:
- errno = ENOSPC;
- return -1;
-}
-
-/**
- * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist
- * @vol: ntfs volume (needed for the ntfs version)
- * @dst: destination buffer to which to write the mapping pairs array
- * @dst_len: size of destination buffer @dst in bytes
- * @rl: runlist for which to build the mapping pairs array
- * @start_vcn: vcn at which to start the mapping pairs array
- * @stop_vcn: first vcn outside destination buffer on success or ENOSPC error
- *
- * Create the mapping pairs array from the runlist @rl, starting at vcn
- * @start_vcn and save the array in @dst. @dst_len is the size of @dst in
- * bytes and it should be at least equal to the value obtained by calling
- * ntfs_get_size_for_mapping_pairs().
- *
- * If @rl is NULL, just write a single terminator byte to @dst.
- *
- * On success or ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to
- * the first vcn outside the destination buffer. Note that on error @dst has
- * been filled with all the mapping pairs that will fit, thus it can be treated
- * as partial success, in that a new attribute extent needs to be created or the
- * next extent has to be used and the mapping pairs build has to be continued
- * with @start_vcn set to *@stop_vcn.
- *
- * Return 0 on success. On error, return -1 with errno set to the error code.
- * The following error codes are defined:
- * EINVAL - Run list contains unmapped elements. Make sure to only pass
- * fully mapped runlists to this function.
- * - @start_vcn is invalid.
- * EIO - The runlist is corrupt.
- * ENOSPC - The destination buffer is too small.
- */
-int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
- const int dst_len, const runlist_element *rl,
- const VCN start_vcn, VCN *const stop_vcn)
-{
- LCN prev_lcn;
- u8 *dst_max, *dst_next;
- s8 len_len, lcn_len;
-
- if (start_vcn < 0)
- goto val_err;
- if (!rl) {
- if (start_vcn)
- goto val_err;
- if (stop_vcn)
- *stop_vcn = 0;
- if (dst_len < 1) {
- errno = ENOSPC;
- return -1;
- }
- /* Terminator byte. */
- *dst = 0;
- return 0;
- }
- /* Skip to runlist element containing @start_vcn. */
- while (rl->length && start_vcn >= rl[1].vcn)
- rl++;
- if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn)
- goto val_err;
- /*
- * @dst_max is used for bounds checking in
- * ntfs_write_significant_bytes().
- */
- dst_max = dst + dst_len - 1;
- prev_lcn = 0;
- /* Do the first partial run if present. */
- if (start_vcn > rl->vcn) {
- s64 delta;
-
- /* We know rl->length != 0 already. */
- if (rl->length < 0 || rl->lcn < LCN_HOLE)
- goto err_out;
- delta = start_vcn - rl->vcn;
- /* Write length. */
- len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
- rl->length - delta);
- if (len_len < 0)
- goto size_err;
- /*
- * If the logical cluster number (lcn) denotes a hole and we
- * are on NTFS 3.0+, we don't store it at all, i.e. we need
- * zero space. On earlier NTFS versions we just write the lcn
- * change. FIXME: Do we need to write the lcn change or just
- * the lcn in that case? Not sure as I have never seen this
- * case on NT4. - We assume that we just need to write the lcn
- * change until someone tells us otherwise... (AIA)
- */
- if (rl->lcn >= 0 || vol->major_ver < 3) {
- prev_lcn = rl->lcn;
- if (rl->lcn >= 0)
- prev_lcn += delta;
- /* Write change in lcn. */
- lcn_len = ntfs_write_significant_bytes(dst + 1 +
- len_len, dst_max, prev_lcn);
- if (lcn_len < 0)
- goto size_err;
- } else
- lcn_len = 0;
- dst_next = dst + len_len + lcn_len + 1;
- if (dst_next > dst_max)
- goto size_err;
- /* Update header byte. */
- *dst = lcn_len << 4 | len_len;
- /* Position at next mapping pairs array element. */
- dst = dst_next;
- /* Go to next runlist element. */
- rl++;
- }
- /* Do the full runs. */
- for (; rl->length; rl++) {
- if (rl->length < 0 || rl->lcn < LCN_HOLE)
- goto err_out;
- /* Write length. */
- len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
- rl->length);
- if (len_len < 0)
- goto size_err;
- /*
- * If the logical cluster number (lcn) denotes a hole and we
- * are on NTFS 3.0+, we don't store it at all, i.e. we need
- * zero space. On earlier NTFS versions we just write the lcn
- * change. FIXME: Do we need to write the lcn change or just
- * the lcn in that case? Not sure as I have never seen this
- * case on NT4. - We assume that we just need to write the lcn
- * change until someone tells us otherwise... (AIA)
- */
- if (rl->lcn >= 0 || vol->major_ver < 3) {
- /* Write change in lcn. */
- lcn_len = ntfs_write_significant_bytes(dst + 1 +
- len_len, dst_max, rl->lcn - prev_lcn);
- if (lcn_len < 0)
- goto size_err;
- prev_lcn = rl->lcn;
- } else
- lcn_len = 0;
- dst_next = dst + len_len + lcn_len + 1;
- if (dst_next > dst_max)
- goto size_err;
- /* Update header byte. */
- *dst = lcn_len << 4 | len_len;
- /* Position at next mapping pairs array element. */
- dst += 1 + len_len + lcn_len;
- }
- /* Set stop vcn. */
- if (stop_vcn)
- *stop_vcn = rl->vcn;
- /* Add terminator byte. */
- *dst = 0;
- return 0;
-size_err:
- /* Set stop vcn. */
- if (stop_vcn)
- *stop_vcn = rl->vcn;
- /* Add terminator byte. */
- *dst = 0;
- errno = ENOSPC;
- return -1;
-val_err:
- errno = EINVAL;
- return -1;
-err_out:
- if (rl->lcn == LCN_RL_NOT_MAPPED)
- errno = EINVAL;
- else
- errno = EIO;
- return -1;
-}
-
-/**
- * ntfs_rl_truncate - truncate a runlist starting at a specified vcn
- * @arl: address of runlist to truncate
- * @start_vcn: first vcn which should be cut off
- *
- * Truncate the runlist *@arl starting at vcn @start_vcn as well as the memory
- * buffer holding the runlist.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- *
- * NOTE: @arl is the address of the runlist. We need the address so we can
- * modify the pointer to the runlist with the new, reallocated memory buffer.
- */
-int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
-{
- runlist *rl;
-
- if (!arl || !*arl) {
- errno = EINVAL;
- ntfs_log_perror("rl_truncate error: arl: %p *arl: %p", arl, *arl);
- return -1;
- }
-
- rl = *arl;
-
- if (start_vcn < rl->vcn) {
- errno = EINVAL;
- ntfs_log_perror("Start_vcn lies outside front of runlist");
- return -1;
- }
-
- /* Find the starting vcn in the run list. */
- while (rl->length) {
- if (start_vcn < rl[1].vcn)
- break;
- rl++;
- }
-
- if (!rl->length) {
- errno = EIO;
- ntfs_log_trace("Truncating already truncated runlist?\n");
- return -1;
- }
-
- /* Truncate the run. */
- rl->length = start_vcn - rl->vcn;
-
- /*
- * If a run was partially truncated, make the following runlist
- * element a terminator instead of the truncated runlist
- * element itself.
- */
- if (rl->length) {
- ++rl;
- rl->vcn = start_vcn;
- rl->length = 0;
- }
- rl->lcn = (LCN)LCN_ENOENT;
- return 0;
-}
-
-/**
- * ntfs_rl_sparse - check whether runlist have sparse regions or not.
- * @rl: runlist to check
- *
- * This function just skips not mapped regions assuming they are not sparse,
- * so you need to ensure that runlist is fully mapped if you want perform full
- * check.
- *
- * Return 1 if have, 0 if not, -1 on error with errno set to the error code.
- */
-int ntfs_rl_sparse(runlist *rl)
-{
- runlist *rlc;
-
- if (!rl) {
- ntfs_log_trace("Invalid argument passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- for (rlc = rl; rlc->length; rlc++) {
- if (rlc->lcn < 0) {
- if (rlc->lcn == LCN_RL_NOT_MAPPED)
- continue;
- if (rlc->lcn != LCN_HOLE) {
- ntfs_log_trace("Bad runlist.\n");
- errno = EIO;
- return -1;
- }
- return 1;
- }
- }
- return 0;
-}
-
-/**
- * ntfs_rl_get_compressed_size - calculate length of non sparse regions
- * @vol: ntfs volume (need for cluster size)
- * @rl: runlist to calculate for
- *
- * Return compressed size or -1 on error with errno set to the error code.
- */
-s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl)
-{
- runlist *rlc;
- s64 ret = 0;
-
- if (!rl) {
- ntfs_log_trace("Invalid argument passed.\n");
- errno = EINVAL;
- return -1;
- }
-
- for (rlc = rl; rlc->length; rlc++) {
- if (rlc->lcn < 0) {
- if (rlc->lcn != LCN_HOLE) {
- ntfs_log_trace("Received unmapped runlist.\n");
- errno = EINVAL;
- return -1;
- }
- } else
- ret += rlc->length;
- }
- return ret << vol->cluster_size_bits;
-}
-
-
-#ifdef NTFS_TEST
-/**
- * test_rl_helper
- */
-#define MKRL(R,V,L,S) \
- (R)->vcn = V; \
- (R)->lcn = L; \
- (R)->length = S;
-/*
-}
-*/
-/**
- * test_rl_dump_runlist - Runlist test: Display the contents of a runlist
- * @rl:
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_dump_runlist(const runlist_element *rl)
-{
- int abbr = 0; /* abbreviate long lists */
- int len = 0;
- int i;
- const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "XXXX" };
-
- if (!rl) {
- printf(" Run list not present.\n");
- return;
- }
-
- if (abbr)
- for (len = 0; rl[len].length; len++) ;
-
- printf(" VCN LCN len\n");
- for (i = 0; ; i++, rl++) {
- LCN lcn = rl->lcn;
-
- if ((abbr) && (len > 20)) {
- if (i == 4)
- printf(" ...\n");
- if ((i > 3) && (i < (len - 3)))
- continue;
- }
-
- if (lcn < (LCN)0) {
- int ind = -lcn - 1;
-
- if (ind > -LCN_ENOENT - 1)
- ind = 3;
- printf("%8lld %8s %8lld\n",
- rl->vcn, lcn_str[ind], rl->length);
- } else
- printf("%8lld %8lld %8lld\n",
- rl->vcn, rl->lcn, rl->length);
- if (!rl->length)
- break;
- }
- if ((abbr) && (len > 20))
- printf(" (%d entries)\n", len+1);
- printf("\n");
-}
-
-/**
- * test_rl_runlists_merge - Runlist test: Merge two runlists
- * @drl:
- * @srl:
- *
- * Description...
- *
- * Returns:
- */
-static runlist_element * test_rl_runlists_merge(runlist_element *drl, runlist_element *srl)
-{
- runlist_element *res = NULL;
-
- printf("dst:\n");
- test_rl_dump_runlist(drl);
- printf("src:\n");
- test_rl_dump_runlist(srl);
-
- res = ntfs_runlists_merge(drl, srl);
-
- printf("res:\n");
- test_rl_dump_runlist(res);
-
- return res;
-}
-
-/**
- * test_rl_read_buffer - Runlist test: Read a file containing a runlist
- * @file:
- * @buf:
- * @bufsize:
- *
- * Description...
- *
- * Returns:
- */
-static int test_rl_read_buffer(const char *file, u8 *buf, int bufsize)
-{
- FILE *fptr;
-
- fptr = fopen(file, "r");
- if (!fptr) {
- printf("open %s\n", file);
- return 0;
- }
-
- if (fread(buf, bufsize, 1, fptr) == 99) {
- printf("read %s\n", file);
- return 0;
- }
-
- fclose(fptr);
- return 1;
-}
-
-/**
- * test_rl_pure_src - Runlist test: Complicate the simple tests a little
- * @contig:
- * @multi:
- * @vcn:
- * @len:
- *
- * Description...
- *
- * Returns:
- */
-static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int len)
-{
- runlist_element *result;
- int fudge;
-
- if (contig)
- fudge = 0;
- else
- fudge = 999;
-
- result = ntfs_malloc(4096);
- if (!result)
- return NULL;
-
- if (multi) {
- MKRL(result+0, vcn + (0*len/4), fudge + vcn + 1000 + (0*len/4), len / 4)
- MKRL(result+1, vcn + (1*len/4), fudge + vcn + 1000 + (1*len/4), len / 4)
- MKRL(result+2, vcn + (2*len/4), fudge + vcn + 1000 + (2*len/4), len / 4)
- MKRL(result+3, vcn + (3*len/4), fudge + vcn + 1000 + (3*len/4), len / 4)
- MKRL(result+4, vcn + (4*len/4), LCN_RL_NOT_MAPPED, 0)
- } else {
- MKRL(result+0, vcn, fudge + vcn + 1000, len)
- MKRL(result+1, vcn + len, LCN_RL_NOT_MAPPED, 0)
- }
- return result;
-}
-
-/**
- * test_rl_pure_test - Runlist test: Perform tests using simple runlists
- * @test:
- * @contig:
- * @multi:
- * @vcn:
- * @len:
- * @file:
- * @size:
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_pure_test(int test, BOOL contig, BOOL multi, int vcn, int len, runlist_element *file, int size)
-{
- runlist_element *src;
- runlist_element *dst;
- runlist_element *res;
-
- src = test_rl_pure_src(contig, multi, vcn, len);
- dst = malloc(4096);
-
- memcpy(dst, file, size);
-
- printf("Test %2d ----------\n", test);
- res = test_rl_runlists_merge(dst, src);
-
- free(res);
-}
-
-/**
- * test_rl_pure - Runlist test: Create tests using simple runlists
- * @contig:
- * @multi:
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_pure(char *contig, char *multi)
-{
- /* VCN, LCN, len */
- static runlist_element file1[] = {
- { 0, -1, 100 }, /* HOLE */
- { 100, 1100, 100 }, /* DATA */
- { 200, -1, 100 }, /* HOLE */
- { 300, 1300, 100 }, /* DATA */
- { 400, -1, 100 }, /* HOLE */
- { 500, -3, 0 } /* NOENT */
- };
- static runlist_element file2[] = {
- { 0, 1000, 100 }, /* DATA */
- { 100, -1, 100 }, /* HOLE */
- { 200, -3, 0 } /* NOENT */
- };
- static runlist_element file3[] = {
- { 0, 1000, 100 }, /* DATA */
- { 100, -3, 0 } /* NOENT */
- };
- static runlist_element file4[] = {
- { 0, -3, 0 } /* NOENT */
- };
- static runlist_element file5[] = {
- { 0, -2, 100 }, /* NOTMAP */
- { 100, 1100, 100 }, /* DATA */
- { 200, -2, 100 }, /* NOTMAP */
- { 300, 1300, 100 }, /* DATA */
- { 400, -2, 100 }, /* NOTMAP */
- { 500, -3, 0 } /* NOENT */
- };
- static runlist_element file6[] = {
- { 0, 1000, 100 }, /* DATA */
- { 100, -2, 100 }, /* NOTMAP */
- { 200, -3, 0 } /* NOENT */
- };
- BOOL c, m;
-
- if (strcmp(contig, "contig") == 0)
- c = TRUE;
- else if (strcmp(contig, "noncontig") == 0)
- c = FALSE;
- else {
- printf("rl pure [contig|noncontig] [single|multi]\n");
- return;
- }
- if (strcmp(multi, "multi") == 0)
- m = TRUE;
- else if (strcmp(multi, "single") == 0)
- m = FALSE;
- else {
- printf("rl pure [contig|noncontig] [single|multi]\n");
- return;
- }
-
- test_rl_pure_test(1, c, m, 0, 40, file1, sizeof(file1));
- test_rl_pure_test(2, c, m, 40, 40, file1, sizeof(file1));
- test_rl_pure_test(3, c, m, 60, 40, file1, sizeof(file1));
- test_rl_pure_test(4, c, m, 0, 100, file1, sizeof(file1));
- test_rl_pure_test(5, c, m, 200, 40, file1, sizeof(file1));
- test_rl_pure_test(6, c, m, 240, 40, file1, sizeof(file1));
- test_rl_pure_test(7, c, m, 260, 40, file1, sizeof(file1));
- test_rl_pure_test(8, c, m, 200, 100, file1, sizeof(file1));
- test_rl_pure_test(9, c, m, 400, 40, file1, sizeof(file1));
- test_rl_pure_test(10, c, m, 440, 40, file1, sizeof(file1));
- test_rl_pure_test(11, c, m, 460, 40, file1, sizeof(file1));
- test_rl_pure_test(12, c, m, 400, 100, file1, sizeof(file1));
- test_rl_pure_test(13, c, m, 160, 100, file2, sizeof(file2));
- test_rl_pure_test(14, c, m, 100, 140, file2, sizeof(file2));
- test_rl_pure_test(15, c, m, 200, 40, file2, sizeof(file2));
- test_rl_pure_test(16, c, m, 240, 40, file2, sizeof(file2));
- test_rl_pure_test(17, c, m, 100, 40, file3, sizeof(file3));
- test_rl_pure_test(18, c, m, 140, 40, file3, sizeof(file3));
- test_rl_pure_test(19, c, m, 0, 40, file4, sizeof(file4));
- test_rl_pure_test(20, c, m, 40, 40, file4, sizeof(file4));
- test_rl_pure_test(21, c, m, 0, 40, file5, sizeof(file5));
- test_rl_pure_test(22, c, m, 40, 40, file5, sizeof(file5));
- test_rl_pure_test(23, c, m, 60, 40, file5, sizeof(file5));
- test_rl_pure_test(24, c, m, 0, 100, file5, sizeof(file5));
- test_rl_pure_test(25, c, m, 200, 40, file5, sizeof(file5));
- test_rl_pure_test(26, c, m, 240, 40, file5, sizeof(file5));
- test_rl_pure_test(27, c, m, 260, 40, file5, sizeof(file5));
- test_rl_pure_test(28, c, m, 200, 100, file5, sizeof(file5));
- test_rl_pure_test(29, c, m, 400, 40, file5, sizeof(file5));
- test_rl_pure_test(30, c, m, 440, 40, file5, sizeof(file5));
- test_rl_pure_test(31, c, m, 460, 40, file5, sizeof(file5));
- test_rl_pure_test(32, c, m, 400, 100, file5, sizeof(file5));
- test_rl_pure_test(33, c, m, 160, 100, file6, sizeof(file6));
- test_rl_pure_test(34, c, m, 100, 140, file6, sizeof(file6));
-}
-
-/**
- * test_rl_zero - Runlist test: Merge a zero-length runlist
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_zero(void)
-{
- runlist_element *jim = NULL;
- runlist_element *bob = NULL;
-
- bob = calloc(3, sizeof(runlist_element));
- if (!bob)
- return;
-
- MKRL(bob+0, 10, 99, 5)
- MKRL(bob+1, 15, LCN_RL_NOT_MAPPED, 0)
-
- jim = test_rl_runlists_merge(jim, bob);
- if (!jim)
- return;
-
- free(jim);
-}
-
-/**
- * test_rl_frag_combine - Runlist test: Perform tests using fragmented files
- * @vol:
- * @attr1:
- * @attr2:
- * @attr3:
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_frag_combine(ntfs_volume *vol, ATTR_RECORD *attr1, ATTR_RECORD *attr2, ATTR_RECORD *attr3)
-{
- runlist_element *run1;
- runlist_element *run2;
- runlist_element *run3;
-
- run1 = ntfs_mapping_pairs_decompress(vol, attr1, NULL);
- if (!run1)
- return;
-
- run2 = ntfs_mapping_pairs_decompress(vol, attr2, NULL);
- if (!run2)
- return;
-
- run1 = test_rl_runlists_merge(run1, run2);
-
- run3 = ntfs_mapping_pairs_decompress(vol, attr3, NULL);
- if (!run3)
- return;
-
- run1 = test_rl_runlists_merge(run1, run3);
-
- free(run1);
-}
-
-/**
- * test_rl_frag - Runlist test: Create tests using very fragmented files
- * @test:
- *
- * Description...
- *
- * Returns:
- */
-static void test_rl_frag(char *test)
-{
- ntfs_volume vol;
- ATTR_RECORD *attr1 = ntfs_malloc(1024);
- ATTR_RECORD *attr2 = ntfs_malloc(1024);
- ATTR_RECORD *attr3 = ntfs_malloc(1024);
-
- if (!attr1 || !attr2 || !attr3)
- goto out;
-
- vol.sb = NULL;
- vol.sector_size_bits = 9;
- vol.cluster_size = 2048;
- vol.cluster_size_bits = 11;
- vol.major_ver = 3;
-
- if (!test_rl_read_buffer("runlist-data/attr1.bin", (u8*) attr1, 1024))
- goto out;
- if (!test_rl_read_buffer("runlist-data/attr2.bin", (u8*) attr2, 1024))
- goto out;
- if (!test_rl_read_buffer("runlist-data/attr3.bin", (u8*) attr3, 1024))
- goto out;
-
- if (strcmp(test, "123") == 0) test_rl_frag_combine(&vol, attr1, attr2, attr3);
- else if (strcmp(test, "132") == 0) test_rl_frag_combine(&vol, attr1, attr3, attr2);
- else if (strcmp(test, "213") == 0) test_rl_frag_combine(&vol, attr2, attr1, attr3);
- else if (strcmp(test, "231") == 0) test_rl_frag_combine(&vol, attr2, attr3, attr1);
- else if (strcmp(test, "312") == 0) test_rl_frag_combine(&vol, attr3, attr1, attr2);
- else if (strcmp(test, "321") == 0) test_rl_frag_combine(&vol, attr3, attr2, attr1);
- else
- printf("Frag: No such test '%s'\n", test);
-
-out:
- free(attr1);
- free(attr2);
- free(attr3);
-}
-
-/**
- * test_rl_main - Runlist test: Program start (main)
- * @argc:
- * @argv:
- *
- * Description...
- *
- * Returns:
- */
-int test_rl_main(int argc, char *argv[])
-{
- if ((argc == 2) && (strcmp(argv[1], "zero") == 0)) test_rl_zero();
- else if ((argc == 3) && (strcmp(argv[1], "frag") == 0)) test_rl_frag(argv[2]);
- else if ((argc == 4) && (strcmp(argv[1], "pure") == 0)) test_rl_pure(argv[2], argv[3]);
- else
- printf("rl [zero|frag|pure] {args}\n");
-
- return 0;
-}
-
-#endif
-
diff --git a/usr/src/lib/libntfs/common/libntfs/security.c b/usr/src/lib/libntfs/common/libntfs/security.c
deleted file mode 100644
index ed02148179..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/security.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * security.c - Handling security/ACLs in NTFS. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "layout.h"
-#include "security.h"
-
-/*
- * The zero GUID.
- */
-static const GUID __zero_guid = { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } };
-const GUID *const zero_guid = &__zero_guid;
-
-/**
- * ntfs_guid_is_zero - check if a GUID is zero
- * @guid: [IN] guid to check
- *
- * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
- * and FALSE otherwise.
- */
-BOOL ntfs_guid_is_zero(const GUID *guid)
-{
- return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
-}
-
-/**
- * ntfs_guid_to_mbs - convert a GUID to a multi byte string
- * @guid: [IN] guid to convert
- * @guid_str: [OUT] string in which to return the GUID (optional)
- *
- * Convert the GUID pointed to by @guid to a multi byte string of the form
- * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
- * needs to be able to store at least 37 bytes.
- *
- * If @guid_str is not NULL it will contain the converted GUID on return. If
- * it is NULL a string will be allocated and this will be returned. The caller
- * is responsible for free()ing the string in that case.
- *
- * On success return the converted string and on failure return NULL with errno
- * set to the error code.
- */
-char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
-{
- char *_guid_str;
- int res;
-
- if (!guid) {
- errno = EINVAL;
- return NULL;
- }
- _guid_str = guid_str;
- if (!_guid_str) {
- _guid_str = ntfs_malloc(37);
- if (!_guid_str)
- return _guid_str;
- }
- res = snprintf(_guid_str, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
- "%02x%02x-%02x%02x%02x%02x%02x%02x", guid->raw[0],
- guid->raw[1], guid->raw[2], guid->raw[3], guid->raw[4],
- guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8],
- guid->raw[9], guid->raw[10], guid->raw[11],
- guid->raw[12], guid->raw[13], guid->raw[14],
- guid->raw[15]);
- if (res == 36)
- return _guid_str;
- if (!guid_str)
- free(_guid_str);
- errno = EINVAL;
- return NULL;
-}
-
-/**
- * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
- * @sid: [IN] SID for which to determine the maximum string size
- *
- * Determine the maximum multi byte string size in bytes which is needed to
- * store the standard textual representation of the SID pointed to by @sid.
- * See ntfs_sid_to_mbs(), below.
- *
- * On success return the maximum number of bytes needed to store the multi byte
- * string and on failure return -1 with errno set to the error code.
- */
-int ntfs_sid_to_mbs_size(const SID *sid)
-{
- int size, i;
-
- if (!ntfs_sid_is_valid(sid)) {
- errno = EINVAL;
- return -1;
- }
- /* Start with "S-". */
- size = 2;
- /*
- * Add the SID_REVISION. Hopefully the compiler will optimize this
- * away as SID_REVISION is a constant.
- */
- for (i = SID_REVISION; i > 0; i /= 10)
- size++;
- /* Add the "-". */
- size++;
- /*
- * Add the identifier authority. If it needs to be in decimal, the
- * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
- * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
- */
- if (!sid->identifier_authority.s.high_part)
- size += 10;
- else
- size += 14;
- /*
- * Finally, add the sub authorities. For each we have a "-" followed
- * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
- */
- size += (1 + 10) * sid->sub_authority_count;
- /* We need the zero byte at the end, too. */
- size++;
- return size * sizeof(char);
-}
-
-/**
- * ntfs_sid_to_mbs - convert a SID to a multi byte string
- * @sid: [IN] SID to convert
- * @sid_str: [OUT] string in which to return the SID (optional)
- * @sid_str_size: [IN] size in bytes of @sid_str
- *
- * Convert the SID pointed to by @sid to its standard textual representation.
- * @sid_str (if not NULL) needs to be able to store at least
- * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
- * @sid_str if @sid_str is not NULL.
- *
- * The standard textual representation of the SID is of the form:
- * S-R-I-S-S...
- * Where:
- * - The first "S" is the literal character 'S' identifying the following
- * digits as a SID.
- * - R is the revision level of the SID expressed as a sequence of digits
- * in decimal.
- * - I is the 48-bit identifier_authority, expressed as digits in decimal,
- * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
- * - S... is one or more sub_authority values, expressed as digits in
- * decimal.
- *
- * If @sid_str is not NULL it will contain the converted SUID on return. If it
- * is NULL a string will be allocated and this will be returned. The caller is
- * responsible for free()ing the string in that case.
- *
- * On success return the converted string and on failure return NULL with errno
- * set to the error code.
- */
-char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
-{
- u64 u;
- char *s;
- int i, j, cnt;
-
- /*
- * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
- * check @sid, too. 8 is the minimum SID string size.
- */
- if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
- errno = EINVAL;
- return NULL;
- }
- /* Allocate string if not provided. */
- if (!sid_str) {
- cnt = ntfs_sid_to_mbs_size(sid);
- if (cnt < 0)
- return NULL;
- s = ntfs_malloc(cnt);
- if (!s)
- return s;
- sid_str = s;
- /* So we know we allocated it. */
- sid_str_size = 0;
- } else {
- s = sid_str;
- cnt = sid_str_size;
- }
- /* Start with "S-R-". */
- i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
- if (i < 0 || i >= cnt)
- goto err_out;
- s += i;
- cnt -= i;
- /* Add the identifier authority. */
- for (u = i = 0, j = 40; i < 6; i++, j -= 8)
- u += (u64)sid->identifier_authority.value[i] << j;
- if (!sid->identifier_authority.s.high_part)
- i = snprintf(s, cnt, "%lu", (unsigned long)u);
- else
- i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
- if (i < 0 || i >= cnt)
- goto err_out;
- s += i;
- cnt -= i;
- /* Finally, add the sub authorities. */
- for (j = 0; j < sid->sub_authority_count; j++) {
- i = snprintf(s, cnt, "-%u", (unsigned int)
- le32_to_cpu(sid->sub_authority[j]));
- if (i < 0 || i >= cnt)
- goto err_out;
- s += i;
- cnt -= i;
- }
- return sid_str;
-err_out:
- if (i >= cnt)
- i = EMSGSIZE;
- else
- i = errno;
- if (!sid_str_size)
- free(sid_str);
- errno = i;
- return NULL;
-}
-
-/**
- * ntfs_generate_guid - generatates a random current guid.
- * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
- *
- * perhaps not a very good random number generator though...
- */
-void ntfs_generate_guid(GUID *guid)
-{
- unsigned int i;
- u8 *p = (u8 *)guid;
-
- for (i = 0; i < sizeof(GUID); i++) {
- p[i] = (u8)(random() & 0xFF);
- if (i == 7)
- p[7] = (p[7] & 0x0F) | 0x40;
- if (i == 8)
- p[8] = (p[8] & 0x3F) | 0x80;
- }
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/unistr.c b/usr/src/lib/libntfs/common/libntfs/unistr.c
deleted file mode 100644
index d5fd2eeb99..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/unistr.c
+++ /dev/null
@@ -1,776 +0,0 @@
-/**
- * unistr.c - Unicode string handling. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_WCHAR_H
-#include <wchar.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "compat.h"
-#include "attrib.h"
-#include "endians.h"
-#include "types.h"
-#include "unistr.h"
-#include "debug.h"
-#include "logging.h"
-
-/*
- * IMPORTANT
- * =========
- *
- * All these routines assume that the Unicode characters are in little endian
- * encoding inside the strings!!!
- */
-
-/*
- * This is used by the name collation functions to quickly determine what
- * characters are (in)valid.
- */
-#if 0
-static const u8 legal_ansi_char_array[0x40] = {
- 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-
- 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
-
- 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
-};
-#endif
-
-/**
- * ntfs_names_are_equal - compare two Unicode names for equality
- * @s1: name to compare to @s2
- * @s1_len: length in Unicode characters of @s1
- * @s2: name to compare to @s1
- * @s2_len: length in Unicode characters of @s2
- * @ic: ignore case bool
- * @upcase: upcase table (only if @ic == IGNORE_CASE)
- * @upcase_size: length in Unicode characters of @upcase (if present)
- *
- * Compare the names @s1 and @s2 and return TRUE (1) if the names are
- * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
- * the @upcase table is used to perform a case insensitive comparison.
- */
-BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
- const ntfschar *s2, size_t s2_len,
- const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_size)
-{
- if (s1_len != s2_len)
- return FALSE;
- if (!s1_len)
- return TRUE;
- if (ic == CASE_SENSITIVE)
- return ntfs_ucsncmp(s1, s2, s1_len) ? FALSE: TRUE;
- return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? FALSE:
- TRUE;
-}
-
-/**
- * ntfs_names_collate - collate two Unicode names
- * @name1: first Unicode name to compare
- * @name1_len: length of first Unicode name to compare
- * @name2: second Unicode name to compare
- * @name2_len: length of second Unicode name to compare
- * @err_val: if @name1 contains an invalid character return this value
- * @ic: either CASE_SENSITIVE or IGNORE_CASE
- * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
- * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
- *
- * ntfs_names_collate() 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
- * @err_val if an invalid character is found in @name1 during the comparison.
- *
- * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
- */
-int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
- const ntfschar *name2, const u32 name2_len,
- const int err_val __attribute__((unused)),
- const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
- const u32 upcase_len)
-{
- u32 cnt;
- u16 c1, c2;
-
-#ifdef DEBUG
- if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
- ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
- exit(1);
- }
-#endif
- for (cnt = 0; cnt < min(name1_len, name2_len); ++cnt) {
- c1 = le16_to_cpu(*name1);
- name1++;
- c2 = le16_to_cpu(*name2);
- name2++;
- if (ic) {
- if (c1 < upcase_len)
- c1 = le16_to_cpu(upcase[c1]);
- if (c2 < upcase_len)
- c2 = le16_to_cpu(upcase[c2]);
- }
-#if 0
- if (c1 < 64 && legal_ansi_char_array[c1] & 8)
- return err_val;
-#endif
- if (c1 < c2)
- return -1;
- if (c1 > c2)
- return 1;
- }
- if (name1_len < name2_len)
- return -1;
- if (name1_len == name2_len)
- return 0;
- /* name1_len > name2_len */
-#if 0
- c1 = le16_to_cpu(*name1);
- if (c1 < 64 && legal_ansi_char_array[c1] & 8)
- return err_val;
-#endif
- return 1;
-}
-
-/**
- * ntfs_ucsncmp - compare two little endian Unicode strings
- * @s1: first string
- * @s2: second string
- * @n: maximum unicode characters to compare
- *
- * Compare the first @n characters of the Unicode strings @s1 and @s2,
- * The strings in little endian format and appropriate le16_to_cpu()
- * conversion is performed on non-little endian machines.
- *
- * The function returns an integer less than, equal to, or greater than zero
- * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
- * to be less than, to match, or be greater than @s2.
- */
-int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
-{
- u16 c1, c2;
- size_t i;
-
-#ifdef DEBUG
- if (!s1 || !s2) {
- ntfs_log_debug("ntfs_wcsncmp() received NULL pointer!\n");
- exit(1);
- }
-#endif
- for (i = 0; i < n; ++i) {
- c1 = le16_to_cpu(s1[i]);
- c2 = le16_to_cpu(s2[i]);
- if (c1 < c2)
- return -1;
- if (c1 > c2)
- return 1;
- if (!c1)
- break;
- }
- return 0;
-}
-
-/**
- * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
- * @s1: first string
- * @s2: second string
- * @n: maximum unicode characters to compare
- * @upcase: upcase table
- * @upcase_size: upcase table size in Unicode characters
- *
- * Compare the first @n characters of the Unicode strings @s1 and @s2,
- * ignoring case. The strings in little endian format and appropriate
- * le16_to_cpu() conversion is performed on non-little endian machines.
- *
- * Each character is uppercased using the @upcase table before the comparison.
- *
- * The function returns an integer less than, equal to, or greater than zero
- * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
- * to be less than, to match, or be greater than @s2.
- */
-int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
- const ntfschar *upcase, const u32 upcase_size)
-{
- u16 c1, c2;
- size_t i;
-
-#ifdef DEBUG
- if (!s1 || !s2 || !upcase) {
- ntfs_log_debug("ntfs_wcsncasecmp() received NULL pointer!\n");
- exit(1);
- }
-#endif
- for (i = 0; i < n; ++i) {
- if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
- c1 = le16_to_cpu(upcase[c1]);
- if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
- c2 = le16_to_cpu(upcase[c2]);
- if (c1 < c2)
- return -1;
- if (c1 > c2)
- return 1;
- if (!c1)
- break;
- }
- return 0;
-}
-
-/**
- * ntfs_ucsnlen - determine the length of a little endian Unicode string
- * @s: pointer to Unicode string
- * @maxlen: maximum length of string @s
- *
- * Return the number of Unicode characters in the little endian Unicode
- * string @s up to a maximum of maxlen Unicode characters, not including
- * the terminating (ntfschar)'\0'. If there is no (ntfschar)'\0' between @s
- * and @s + @maxlen, @maxlen is returned.
- *
- * This function never looks beyond @s + @maxlen.
- */
-u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen)
-{
- u32 i;
-
- for (i = 0; i < maxlen; i++) {
- if (!le16_to_cpu(s[i]))
- break;
- }
- return i;
-}
-
-/**
- * ntfs_ucsndup - duplicate little endian Unicode string
- * @s: pointer to Unicode string
- * @maxlen: maximum length of string @s
- *
- * Return a pointer to a new little endian Unicode string which is a duplicate
- * of the string s. Memory for the new string is obtained with malloc(3), and
- * can be freed with free(3).
- *
- * A maximum of @maxlen Unicode characters are copied and a terminating
- * (ntfschar)'\0' little endian Unicode character is added.
- *
- * This function never looks beyond @s + @maxlen.
- *
- * Return a pointer to the new little endian Unicode string on success and NULL
- * on failure with errno set to the error code.
- */
-ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
-{
- ntfschar *dst;
- u32 len;
-
- len = ntfs_ucsnlen(s, maxlen);
- dst = ntfs_malloc((len + 1) * sizeof(ntfschar));
- if (dst) {
- memcpy(dst, s, len * sizeof(ntfschar));
- dst[len] = 0;
- }
- return dst;
-}
-
-/**
- * ntfs_name_upcase - Map an Unicode name to its uppercase equivalent
- * @name:
- * @name_len:
- * @upcase:
- * @upcase_len:
- *
- * Description...
- *
- * Returns:
- */
-void ntfs_name_upcase(ntfschar *name, u32 name_len, const ntfschar *upcase,
- const u32 upcase_len)
-{
- u32 i;
- u16 u;
-
- for (i = 0; i < name_len; i++)
- if ((u = le16_to_cpu(name[i])) < upcase_len)
- name[i] = upcase[u];
-}
-
-/**
- * ntfs_file_value_upcase - Convert a filename to upper case
- * @file_name_attr:
- * @upcase:
- * @upcase_len:
- *
- * Description...
- *
- * Returns:
- */
-void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
- const ntfschar *upcase, const u32 upcase_len)
-{
- ntfs_name_upcase((ntfschar*)&file_name_attr->file_name,
- file_name_attr->file_name_length, upcase, upcase_len);
-}
-
-/**
- * ntfs_file_values_compare - Which of two filenames should be listed first
- * @file_name_attr1:
- * @file_name_attr2:
- * @err_val:
- * @ic:
- * @upcase:
- * @upcase_len:
- *
- * Description...
- *
- * Returns:
- */
-int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
- const FILE_NAME_ATTR *file_name_attr2,
- const int err_val, const IGNORE_CASE_BOOL ic,
- const ntfschar *upcase, const u32 upcase_len)
-{
- return ntfs_names_collate((ntfschar*)&file_name_attr1->file_name,
- file_name_attr1->file_name_length,
- (ntfschar*)&file_name_attr2->file_name,
- file_name_attr2->file_name_length,
- err_val, ic, upcase, upcase_len);
-}
-
-/**
- * ntfs_ucstombs - convert a little endian Unicode string to a multibyte string
- * @ins: input Unicode string buffer
- * @ins_len: length of input string in Unicode characters
- * @outs: on return contains the (allocated) output multibyte string
- * @outs_len: length of output buffer in bytes
- *
- * Convert the input little endian, 2-byte Unicode string @ins, of length
- * @ins_len into the multibyte string format dictated by the current locale.
- *
- * If *@outs is NULL, the function allocates the string and the caller is
- * responsible for calling free(*@outs); when finished with it.
- *
- * On success the function returns the number of bytes written to the output
- * string *@outs (>= 0), not counting the terminating NULL byte. If the output
- * string buffer was allocated, *@outs is set to it.
- *
- * On error, -1 is returned, and errno is set to the error code. The following
- * error codes can be expected:
- * EINVAL Invalid arguments (e.g. @ins or @outs is NULL).
- * EILSEQ The input string cannot be represented as a multibyte
- * sequence according to the current locale.
- * ENAMETOOLONG Destination buffer is too small for input string.
- * ENOMEM Not enough memory to allocate destination buffer.
- */
-int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
- int outs_len)
-{
- char *mbs;
- wchar_t wc;
- int i, o, mbs_len;
- int cnt = 0;
-#ifdef HAVE_MBSINIT
- mbstate_t mbstate;
-#endif
-
- if (!ins || !outs) {
- errno = EINVAL;
- return -1;
- }
- mbs = *outs;
- mbs_len = outs_len;
- if (mbs && !mbs_len) {
- errno = ENAMETOOLONG;
- return -1;
- }
- if (!mbs) {
- mbs_len = (ins_len + 1) * MB_CUR_MAX;
- mbs = (char*)ntfs_malloc(mbs_len);
- if (!mbs)
- return -1;
- }
-#ifdef HAVE_MBSINIT
- memset(&mbstate, 0, sizeof(mbstate));
-#else
- wctomb(NULL, 0);
-#endif
- for (i = o = 0; i < ins_len; i++) {
- /* Reallocate memory if necessary or abort. */
- if ((int)(o + MB_CUR_MAX) > mbs_len) {
- char *tc;
- if (mbs == *outs) {
- errno = ENAMETOOLONG;
- return -1;
- }
- tc = (char*)ntfs_malloc((mbs_len + 64) & ~63);
- if (!tc)
- goto err_out;
- memcpy(tc, mbs, mbs_len);
- mbs_len = (mbs_len + 64) & ~63;
- free(mbs);
- mbs = tc;
- }
- /* Convert the LE Unicode character to a CPU wide character. */
- wc = (wchar_t)le16_to_cpu(ins[i]);
- if (!wc)
- break;
- /* Convert the CPU endian wide character to multibyte. */
-#ifdef HAVE_MBSINIT
- cnt = wcrtomb(mbs + o, wc, &mbstate);
-#else
- cnt = wctomb(mbs + o, wc);
-#endif
- if (cnt == -1)
- goto err_out;
- if (cnt <= 0) {
- ntfs_log_debug("Eeek. cnt <= 0, cnt = %i\n", cnt);
- errno = EINVAL;
- goto err_out;
- }
- o += cnt;
- }
-#ifdef HAVE_MBSINIT
- /* Make sure we are back in the initial state. */
- if (!mbsinit(&mbstate)) {
- ntfs_log_debug("Eeek. mbstate not in initial state!\n");
- errno = EILSEQ;
- goto err_out;
- }
-#endif
- /* Now write the NULL character. */
- mbs[o] = 0;
- if (*outs != mbs)
- *outs = mbs;
- return o;
-err_out:
- if (mbs != *outs)
- free(mbs);
- return -1;
-}
-
-/**
- * ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string
- * @ins: input multibyte string buffer
- * @outs: on return contains the (allocated) output Unicode string
- * @outs_len: length of output buffer in Unicode characters
- *
- * Convert the input multibyte string @ins, from the current locale into the
- * corresponding little endian, 2-byte Unicode string.
- *
- * If *@outs is NULL, the function allocates the string and the caller is
- * responsible for calling free(*@outs); when finished with it.
- *
- * On success the function returns the number of Unicode characters written to
- * the output string *@outs (>= 0), not counting the terminating Unicode NULL
- * character. If the output string buffer was allocated, *@outs is set to it.
- *
- * On error, -1 is returned, and errno is set to the error code. The following
- * error codes can be expected:
- * EINVAL Invalid arguments (e.g. @ins or @outs is NULL).
- * EILSEQ The input string cannot be represented as a Unicode
- * string according to the current locale.
- * ENAMETOOLONG Destination buffer is too small for input string.
- * ENOMEM Not enough memory to allocate destination buffer.
- */
-int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
-{
- ntfschar *ucs;
- const char *s;
- wchar_t wc;
- int i, o, cnt, ins_len, ucs_len, ins_size;
-#ifdef HAVE_MBSINIT
- mbstate_t mbstate;
-#endif
-
- if (!ins || !outs) {
- errno = EINVAL;
- return -1;
- }
- ucs = *outs;
- ucs_len = outs_len;
- if (ucs && !ucs_len) {
- errno = ENAMETOOLONG;
- return -1;
- }
- /* Determine the size of the multi-byte string in bytes. */
- ins_size = strlen(ins);
- /* Determine the length of the multi-byte string. */
- s = ins;
-#if defined(HAVE_MBSINIT)
- memset(&mbstate, 0, sizeof(mbstate));
- ins_len = mbsrtowcs(NULL, (const char **)&s, 0, &mbstate);
-#ifdef __CYGWIN32__
- if (!ins_len && *ins) {
- /* Older Cygwin had broken mbsrtowcs() implementation. */
- ins_len = strlen(ins);
- }
-#endif
-#elif !defined(DJGPP)
- ins_len = mbstowcs(NULL, s, 0);
-#else
- /* Eeek!!! DJGPP has broken mbstowcs() implementation!!! */
- ins_len = strlen(ins);
-#endif
- if (ins_len == -1)
- return ins_len;
-#ifdef HAVE_MBSINIT
- if ((s != ins) || !mbsinit(&mbstate)) {
-#else
- if (s != ins) {
-#endif
- errno = EILSEQ;
- return -1;
- }
- /* Add the NULL terminator. */
- ins_len++;
- if (!ucs) {
- ucs_len = ins_len;
- ucs = (ntfschar*)ntfs_malloc(ucs_len * sizeof(ntfschar));
- if (!ucs)
- return -1;
- }
-#ifdef HAVE_MBSINIT
- memset(&mbstate, 0, sizeof(mbstate));
-#else
- mbtowc(NULL, NULL, 0);
-#endif
- for (i = o = cnt = 0; i < ins_size; i += cnt, o++) {
- /* Reallocate memory if necessary or abort. */
- if (o >= ucs_len) {
- ntfschar *tc;
- if (ucs == *outs) {
- errno = ENAMETOOLONG;
- return -1;
- }
- /*
- * We will never get here but hey, it's only a bit of
- * extra code...
- */
- ucs_len = (ucs_len * sizeof(ntfschar) + 64) & ~63;
- tc = (ntfschar*)realloc(ucs, ucs_len);
- if (!tc)
- goto err_out;
- ucs = tc;
- ucs_len /= sizeof(ntfschar);
- }
- /* Convert the multibyte character to a wide character. */
-#ifdef HAVE_MBSINIT
- cnt = mbrtowc(&wc, ins + i, ins_size - i, &mbstate);
-#else
- cnt = mbtowc(&wc, ins + i, ins_size - i);
-#endif
- if (!cnt)
- break;
- if (cnt == -1)
- goto err_out;
- if (cnt < -1) {
- ntfs_log_trace("Eeek. cnt = %i\n", cnt);
- errno = EINVAL;
- goto err_out;
- }
- /* Make sure we are not overflowing the NTFS Unicode set. */
- if ((unsigned long)wc >= (unsigned long)(1 <<
- (8 * sizeof(ntfschar)))) {
- errno = EILSEQ;
- goto err_out;
- }
- /* Convert the CPU wide character to a LE Unicode character. */
- ucs[o] = cpu_to_le16(wc);
- }
-#ifdef HAVE_MBSINIT
- /* Make sure we are back in the initial state. */
- if (!mbsinit(&mbstate)) {
- ntfs_log_trace("Eeek. mbstate not in initial state!\n");
- errno = EILSEQ;
- goto err_out;
- }
-#endif
- /* Now write the NULL character. */
- ucs[o] = 0;
- if (*outs != ucs)
- *outs = ucs;
- return o;
-err_out:
- if (ucs != *outs)
- free(ucs);
- return -1;
-}
-
-/**
- * ntfs_upcase_table_build - build the default upcase table for NTFS
- * @uc: destination buffer where to store the built table
- * @uc_len: size of destination buffer in bytes
- *
- * ntfs_upcase_table_build() builds the default upcase table for NTFS and
- * stores it in the caller supplied buffer @uc of size @uc_len.
- *
- * The generated $UpCase table is the one used by Windows Vista.
- *
- * Note, @uc_len must be at least 128kiB in size or bad things will happen!
- */
-void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
-{
- /*
- * "Start" is inclusive and "End" is exclusive, every value has the
- * value of "Add" added to it.
- */
- static int add[][3] = { /* Start, End, Add */
- {0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32},
- {0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130},
- {0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32},
- {0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64},
- {0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80},
- {0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8},
- {0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8},
- {0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8},
- {0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74},
- {0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128},
- {0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8},
- {0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8},
- {0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8},
- {0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9},
- {0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48},
- {0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0}
- };
- /*
- * "Start" is exclusive and "End" is inclusive, every second value is
- * decremented by one.
- */
- static int skip_dec[][2] = { /* Start, End */
- {0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178},
- {0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd},
- {0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220},
- {0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f},
- {0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481},
- {0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce},
- {0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513},
- {0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61},
- {0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0}
- };
- /*
- * Set the Unicode character at offset "Offset" to "Value". Note,
- * "Value" is host endian.
- */
- static int set[][2] = { /* Offset, Value */
- {0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184},
- {0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6},
- {0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7},
- {0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc},
- {0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca},
- {0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66},
- {0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190},
- {0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196},
- {0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f},
- {0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae},
- {0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9},
- {0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0}
- };
- unsigned i, r;
-
- memset(uc, 0, uc_len);
- uc_len /= 2;
- /* Start with a one-to-one mapping, i.e. no upcasing happens at all. */
- for (i = 0; i < uc_len; i++)
- uc[i] = cpu_to_le16(i);
- /* Adjust specified runs by the specified amount. */
- for (r = 0; add[r][0]; r++)
- for (i = add[r][0]; i < add[r][1]; i++)
- uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + add[r][2]);
- /* Decrement every second value in specified runs. */
- for (r = 0; skip_dec[r][0]; r++)
- for (i = skip_dec[r][0]; i < skip_dec[r][1];
- i += 2)
- uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1);
- /* Set specified characters to specified values. */
- for (r = 0; set[r][0]; r++)
- uc[set[r][0]] = cpu_to_le16(set[r][1]);
-}
-
-/**
- * ntfs_str2ucs - convert a string to a valid NTFS file name
- * @s: input string
- * @len: length of output buffer in Unicode characters
- *
- * Convert the input @s string into the corresponding little endian,
- * 2-byte Unicode string. The length of the converted string is less
- * or equal to the maximum length allowed by the NTFS format (255).
- *
- * If @s is NULL then return AT_UNNAMED.
- *
- * On success the function returns the Unicode string in an allocated
- * buffer and the caller is responsible to free it when it's not needed
- * anymore.
- *
- * On error NULL is returned and errno is set to the error code.
- */
-ntfschar *ntfs_str2ucs(const char *s, int *len)
-{
- ntfschar *ucs = NULL;
-
- if (s && ((*len = ntfs_mbstoucs(s, &ucs, 0)) == -1)) {
- ntfs_log_perror("Couldn't convert '%s' to Unicode", s);
- return NULL;
- }
- if (*len > NTFS_MAX_NAME_LEN) {
- free(ucs);
- errno = ENAMETOOLONG;
- return NULL;
- }
- if (!ucs || !*len) {
- ucs = AT_UNNAMED;
- *len = 0;
- }
- return ucs;
-}
-
-/**
- * ntfs_ucsfree - free memory allocated by ntfs_str2ucs()
- * @ucs: input string to be freed
- *
- * Free memory at @ucs and which was allocated by ntfs_str2ucs.
- *
- * Return value: none.
- */
-void ntfs_ucsfree(ntfschar *ucs)
-{
- if (ucs && (ucs != AT_UNNAMED))
- free(ucs);
-}
-
diff --git a/usr/src/lib/libntfs/common/libntfs/unix_io.c b/usr/src/lib/libntfs/common/libntfs/unix_io.c
deleted file mode 100644
index 9299284c17..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/unix_io.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * unix_io.c - Unix style disk io functions. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_LINUX_FD_H
-#include <linux/fd.h>
-#endif
-
-#include "compat.h"
-#include "types.h"
-#include "mst.h"
-#include "debug.h"
-#include "device.h"
-#include "logging.h"
-
-#define DEV_FD(dev) (*(int *)dev->d_private)
-
-/* Define to nothing if not present on this system. */
-#ifndef O_EXCL
-# define O_EXCL 0
-#endif
-
-/**
- * ntfs_device_unix_io_open - Open a device and lock it exclusively
- * @dev:
- * @flags:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
-{
- struct flock flk;
- struct stat sbuf;
- int err;
-
- if (NDevOpen(dev)) {
- errno = EBUSY;
- return -1;
- }
- if (!(dev->d_private = ntfs_malloc(sizeof(int))))
- return -1;
- *(int*)dev->d_private = open(dev->d_name, flags);
- if (*(int*)dev->d_private == -1) {
- err = errno;
- goto err_out;
- }
- /* Setup our read-only flag. */
- if ((flags & O_RDWR) != O_RDWR)
- NDevSetReadOnly(dev);
- /* Acquire exclusive (mandatory) lock on the whole device. */
- memset(&flk, 0, sizeof(flk));
- if (NDevReadOnly(dev))
- flk.l_type = F_RDLCK;
- else
- flk.l_type = F_WRLCK;
- flk.l_whence = SEEK_SET;
- flk.l_start = flk.l_len = 0LL;
- if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
- err = errno;
- ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s "
- "for %s\n", dev->d_name, NDevReadOnly(dev) ?
- "reading" : "writing");
- if (close(DEV_FD(dev)))
- ntfs_log_perror("ntfs_device_unix_io_open: Warning: "
- "Could not close %s", dev->d_name);
- goto err_out;
- }
- /* Determine if device is a block device or not, ignoring errors. */
- if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
- NDevSetBlock(dev);
- /* Set our open flag. */
- NDevSetOpen(dev);
- return 0;
-err_out:
- free(dev->d_private);
- dev->d_private = NULL;
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_device_unix_io_close - Close the device, releasing the lock
- * @dev:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_device_unix_io_close(struct ntfs_device *dev)
-{
- struct flock flk;
-
- if (!NDevOpen(dev)) {
- errno = EBADF;
- return -1;
- }
- if (NDevDirty(dev))
- fsync(DEV_FD(dev));
- /* Release exclusive (mandatory) lock on the whole device. */
- memset(&flk, 0, sizeof(flk));
- flk.l_type = F_UNLCK;
- flk.l_whence = SEEK_SET;
- flk.l_start = flk.l_len = 0LL;
- if (fcntl(DEV_FD(dev), F_SETLK, &flk))
- ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not "
- "unlock %s", dev->d_name);
- /* Close the file descriptor and clear our open flag. */
- if (close(DEV_FD(dev)))
- return -1;
- NDevClearOpen(dev);
- free(dev->d_private);
- dev->d_private = NULL;
- return 0;
-}
-
-/**
- * ntfs_device_unix_io_seek - Seek to a place on the device
- * @dev:
- * @offset:
- * @whence:
- *
- * Description...
- *
- * Returns:
- */
-static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
- int whence)
-{
- return lseek(DEV_FD(dev), offset, whence);
-}
-
-/**
- * ntfs_device_unix_io_read - Read from the device, from the current location
- * @dev:
- * @buf:
- * @count:
- *
- * Description...
- *
- * Returns:
- */
-static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf,
- s64 count)
-{
- return read(DEV_FD(dev), buf, count);
-}
-
-/**
- * ntfs_device_unix_io_write - Write to the device, at the current location
- * @dev:
- * @buf:
- * @count:
- *
- * Description...
- *
- * Returns:
- */
-static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf,
- s64 count)
-{
- if (NDevReadOnly(dev)) {
- errno = EROFS;
- return -1;
- }
- NDevSetDirty(dev);
- return write(DEV_FD(dev), buf, count);
-}
-
-/**
- * ntfs_device_unix_io_pread - Perform a positioned read from the device
- * @dev:
- * @buf:
- * @count:
- * @offset:
- *
- * Description...
- *
- * Returns:
- */
-static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
- s64 count, s64 offset)
-{
- return pread(DEV_FD(dev), buf, count, offset);
-}
-
-/**
- * ntfs_device_unix_io_pwrite - Perform a positioned write to the device
- * @dev:
- * @buf:
- * @count:
- * @offset:
- *
- * Description...
- *
- * Returns:
- */
-static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
- s64 count, s64 offset)
-{
- if (NDevReadOnly(dev)) {
- errno = EROFS;
- return -1;
- }
- NDevSetDirty(dev);
- return pwrite(DEV_FD(dev), buf, count, offset);
-}
-
-/**
- * ntfs_device_unix_io_sync - Flush any buffered changes to the device
- * @dev:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
-{
- if (!NDevReadOnly(dev) && NDevDirty(dev)) {
- int res = fsync(DEV_FD(dev));
- if (!res)
- NDevClearDirty(dev);
- return res;
- }
- return 0;
-}
-
-/**
- * ntfs_device_unix_io_stat - Get information about the device
- * @dev:
- * @buf:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
-{
- return fstat(DEV_FD(dev), buf);
-}
-
-/**
- * ntfs_device_unix_io_ioctl - Perform an ioctl on the device
- * @dev:
- * @request:
- * @argp:
- *
- * Description...
- *
- * Returns:
- */
-static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request,
- void *argp)
-{
- return ioctl(DEV_FD(dev), request, argp);
-}
-
-/**
- * Device operations for working with unix style devices and files.
- */
-struct ntfs_device_operations ntfs_device_unix_io_ops = {
- .open = ntfs_device_unix_io_open,
- .close = ntfs_device_unix_io_close,
- .seek = ntfs_device_unix_io_seek,
- .read = ntfs_device_unix_io_read,
- .write = ntfs_device_unix_io_write,
- .pread = ntfs_device_unix_io_pread,
- .pwrite = ntfs_device_unix_io_pwrite,
- .sync = ntfs_device_unix_io_sync,
- .stat = ntfs_device_unix_io_stat,
- .ioctl = ntfs_device_unix_io_ioctl,
-};
diff --git a/usr/src/lib/libntfs/common/libntfs/version.c b/usr/src/lib/libntfs/common/libntfs/version.c
deleted file mode 100644
index 7882e7177b..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/version.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * version.c - Info about the NTFS library. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- * Copyright (c) 2005 Richard Russon
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "version.h"
-
-#ifdef LTVERSION_LIBNTFS
-#define LIBNTFS_VERSION_STRING LTVERSION_LIBNTFS
-#else
-#define LIBNTFS_VERSION_STRING "unknown"
-#endif
-
-static const char *libntfs_version_string = LIBNTFS_VERSION_STRING;
-
-/**
- * ntfs_libntfs_version - query version number of the ntfs library libntfs
- *
- * Returns pointer to a text string representing the version of libntfs.
- */
-const char *ntfs_libntfs_version(void)
-{
- return libntfs_version_string;
-}
diff --git a/usr/src/lib/libntfs/common/libntfs/volume.c b/usr/src/lib/libntfs/common/libntfs/volume.c
deleted file mode 100644
index 2a783dddad..0000000000
--- a/usr/src/lib/libntfs/common/libntfs/volume.c
+++ /dev/null
@@ -1,1689 +0,0 @@
-/**
- * volume.c - NTFS volume handling code. Part of the Linux-NTFS project.
- *
- * Copyright (c) 2000-2006 Anton Altaparmakov
- * Copyright (c) 2002-2006 Szabolcs Szakacsits
- * Copyright (c) 2004-2005 Richard Russon
- * Copyright (c) 2005-2007 Yura Pakhuchiy
- *
- * This program/include file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program/include file is distributed in the hope that it will be
- * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (in the main directory of the Linux-NTFS
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include "compat.h"
-#include "volume.h"
-#include "attrib.h"
-#include "mft.h"
-#include "bootsect.h"
-#include "device.h"
-#include "debug.h"
-#include "inode.h"
-#include "runlist.h"
-#include "logfile.h"
-#include "dir.h"
-#include "logging.h"
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-/**
- * ntfs_volume_alloc - Create an NTFS volume object and initialise it
- *
- * Description...
- *
- * Returns:
- */
-ntfs_volume *ntfs_volume_alloc(void)
-{
- ntfs_volume *vol;
- int i;
-
- vol = calloc(1, sizeof(ntfs_volume));
- if (vol) {
- for (i = 0; i < NTFS_INODE_CACHE_SIZE; i++)
- INIT_LIST_HEAD(&vol->inode_cache[i]);
- }
- return vol;
-}
-
-/**
- * __ntfs_volume_release - Destroy an NTFS volume object
- * @v:
- *
- * Description...
- *
- * Returns:
- */
-static void __ntfs_volume_release(ntfs_volume *v)
-{
- struct list_head *pos, *tmp;
- int i;
-
- /* Sync and print error about not detached inodes. */
- for (i = 0; i < NTFS_INODE_CACHE_SIZE; i++)
- list_for_each_safe(pos, tmp, &v->inode_cache[i]) {
- ntfs_inode *ni =
- list_entry(pos, ntfs_inode, list_entry);
-
- switch (ni->mft_no) {
- case FILE_Volume:
- case FILE_Bitmap:
- case FILE_MFT:
- case FILE_MFTMirr:
- if (ni->nr_references == 1)
- continue;
- break;
- }
-
- ntfs_log_error("%s(): Inode %llu still have %d "
- "references.\n", "__ntfs_volume_release",
- ni->mft_no, ni->nr_references);
- ntfs_inode_sync(ni);
- }
- /*
- * Clear the dirty bit if it was not set before we mounted and this is
- * not a forensic mount.
- */
- if (!NVolReadOnly(v) && !NVolWasDirty(v) && !NVolForensicMount(v)) {
- v->flags &= ~VOLUME_IS_DIRTY;
- (void)ntfs_volume_write_flags(v, v->flags);
- }
- if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))
- ntfs_inode_sync(v->lcnbmp_ni);
- if (v->vol_ni)
- ntfs_inode_close(v->vol_ni);
- if (v->lcnbmp_na)
- ntfs_attr_close(v->lcnbmp_na);
- if (v->lcnbmp_ni)
- ntfs_inode_close(v->lcnbmp_ni);
- if (v->mft_ni && NInoDirty(v->mft_ni))
- ntfs_inode_sync(v->mft_ni);
- if (v->mftbmp_na)
- ntfs_attr_close(v->mftbmp_na);
- if (v->mft_na)
- ntfs_attr_close(v->mft_na);
- if (v->mft_ni)
- ntfs_inode_close(v->mft_ni);
- if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
- ntfs_inode_sync(v->mftmirr_ni);
- if (v->mftmirr_na)
- ntfs_attr_close(v->mftmirr_na);
- if (v->mftmirr_ni)
- ntfs_inode_close(v->mftmirr_ni);
- if (v->u.dev) {
- struct ntfs_device *dev = v->u.dev;
-
- if (NDevDirty(dev))
- dev->d_ops->sync(dev);
- if (dev->d_ops->close(dev))
- ntfs_log_perror("Failed to close the device");
- }
- free(v->vol_name);
- free(v->upcase);
- free(v->attrdef);
- free(v);
-}
-
-/**
- * ntfs_mft_load - load the $MFT and setup the ntfs volume with it
- * @vol: ntfs volume whose $MFT to load
- *
- * Load $MFT from @vol and setup @vol with it. After calling this function the
- * volume @vol is ready for use by all read access functions provided by the
- * ntfs library.
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-static int ntfs_mft_load(ntfs_volume *vol)
-{
- VCN next_vcn, last_vcn, highest_vcn;
- s64 l;
- MFT_RECORD *mb = NULL;
- ntfs_attr_search_ctx *ctx = NULL;
- ATTR_RECORD *a;
- STANDARD_INFORMATION *std_info;
- int eo;
-
- /* Manually setup an ntfs_inode. */
- vol->mft_ni = ntfs_inode_allocate(vol);
- mb = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size);
- if (!vol->mft_ni || !mb) {
- ntfs_log_perror("Error allocating memory for $MFT");
- goto error_exit;
- }
- vol->mft_ni->mft_no = 0;
- vol->mft_ni->mrec = mb;
- __ntfs_inode_add_to_cache(vol->mft_ni);
- /* Can't use any of the higher level functions yet! */
- l = ntfs_mst_pread(vol->u.dev, vol->mft_lcn << vol->cluster_size_bits, 1,
- vol->mft_record_size, mb);
- if (l != 1) {
- if (l != -1)
- errno = EIO;
- ntfs_log_perror("Error reading $MFT");
- goto error_exit;
- }
- if (ntfs_is_baad_record(mb->magic)) {
- ntfs_log_error("Incomplete multi sector transfer detected in "
- "$MFT.\n");
- goto io_error_exit;
- }
- if (!ntfs_is_mft_record(mb->magic)) {
- ntfs_log_error("$MFT has invalid magic.\n");
- goto io_error_exit;
- }
- ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
- if (!ctx) {
- ntfs_log_perror("Failed to allocate attribute search context");
- goto error_exit;
- }
- if (p2n(ctx->attr) < p2n(mb) ||
- (char*)ctx->attr > (char*)mb + vol->mft_record_size) {
- ntfs_log_error("$MFT is corrupt.\n");
- goto io_error_exit;
- }
- /* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */
- if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
- ctx)) {
- if (errno != ENOENT) {
- ntfs_log_error("$MFT has corrupt attribute list.\n");
- goto io_error_exit;
- }
- goto mft_has_no_attr_list;
- }
- NInoSetAttrList(vol->mft_ni);
- l = ntfs_get_attribute_value_length(ctx->attr);
- if (l <= 0 || l > 0x40000) {
- ntfs_log_error("$MFT/$ATTRIBUTE_LIST has invalid length.\n");
- goto io_error_exit;
- }
- vol->mft_ni->attr_list_size = l;
- vol->mft_ni->attr_list = ntfs_malloc(l);
- if (!vol->mft_ni->attr_list)
- goto error_exit;
-
- l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);
- if (!l) {
- ntfs_log_error("Failed to get value of "
- "$MFT/$ATTRIBUTE_LIST.\n");
- goto io_error_exit;
- }
- if (l != vol->mft_ni->attr_list_size) {
- ntfs_log_error("Got unexpected amount of data when "
- "reading $MFT/$ATTRIBUTE_LIST.\n");
- goto io_error_exit;
- }
-mft_has_no_attr_list:
- /* Receive attributes from STANDARD_INFORMATION. */
- std_info = ntfs_attr_readall(vol->mft_ni, AT_STANDARD_INFORMATION,
- AT_UNNAMED, 0, NULL);
- vol->mft_ni->flags = std_info->file_attributes;
- free(std_info);
-
- /* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
-
- /* Get an ntfs attribute for $MFT/$DATA and set it up, too. */
- vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
- if (!vol->mft_na) {
- ntfs_log_perror("Failed to open ntfs attribute");
- goto error_exit;
- }
- /* Read all extents from the $DATA attribute in $MFT. */
- ntfs_attr_reinit_search_ctx(ctx);
- last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;
- highest_vcn = next_vcn = 0;
- a = NULL;
- while (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, next_vcn, NULL, 0,
- ctx)) {
- runlist_element *nrl;
-
- a = ctx->attr;
- /* $MFT must be non-resident. */
- if (!a->non_resident) {
- ntfs_log_error("$MFT must be non-resident but a "
- "resident extent was found. $MFT is "
- "corrupt. Run chkdsk.\n");
- goto io_error_exit;
- }
- /* $MFT must be uncompressed and unencrypted. */
- if (a->flags & ATTR_COMPRESSION_MASK ||
- a->flags & ATTR_IS_ENCRYPTED) {
- ntfs_log_error("$MFT must be uncompressed and "
- "unencrypted but a compressed/encrypted"
- " extent was found. $MFT is corrupt. "
- "Run chkdsk.\n");
- goto io_error_exit;
- }
- /*
- * Decompress the mapping pairs array of this extent and merge
- * the result into the existing runlist. No need for locking
- * as we have exclusive access to the inode at this time and we
- * are a mount in progress task, too.
- */
- nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl);
- if (!nrl) {
- ntfs_log_perror("ntfs_mapping_pairs_decompress() "
- "failed");
- goto error_exit;
- }
- vol->mft_na->rl = nrl;
-
- /* Get the lowest vcn for the next extent. */
- highest_vcn = sle64_to_cpu(a->u.nonres.highest_vcn);
- next_vcn = highest_vcn + 1;
-
- /* Only one extent or error, which we catch below. */
- if (next_vcn <= 0)
- break;
-
- /* Avoid endless loops due to corruption. */
- if (next_vcn < sle64_to_cpu(a->u.nonres.lowest_vcn)) {
- ntfs_log_error("$MFT has corrupt attribute list "
- "attribute. Run chkdsk.\n");
- goto io_error_exit;
- }
- }
- if (!a) {
- ntfs_log_error("$MFT/$DATA attribute not found. "
- "$MFT is corrupt. Run chkdsk.\n");
- goto io_error_exit;
- }
- if (highest_vcn && highest_vcn != last_vcn - 1) {
- ntfs_log_error("Failed to load the complete runlist for "
- "$MFT/$DATA. Bug or corrupt $MFT. "
- "Run chkdsk.\n highest_vcn = 0x%llx, "
- "last_vcn - 1 = 0x%llx\n", (long long)
- highest_vcn, (long long)last_vcn - 1);
- goto io_error_exit;
- }
- /* Done with the $Mft mft record. */
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
- /*
- * The volume is now setup so we can use all read access functions.
- */
- vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, AT_UNNAMED, 0);
- if (!vol->mftbmp_na) {
- ntfs_log_perror("Failed to open $MFT/$BITMAP");
- goto error_exit;
- }
- return 0;
-io_error_exit:
- errno = EIO;
-error_exit:
- eo = errno;
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- if (vol->mft_na) {
- ntfs_attr_close(vol->mft_na);
- vol->mft_na = NULL;
- }
- if (vol->mft_ni) {
- ntfs_inode_close(vol->mft_ni);
- vol->mft_ni = NULL;
- }
- ntfs_log_error("%s(): Failed.\n", "ntfs_mft_load");
- errno = eo;
- return -1;
-}
-
-/**
- * ntfs_mftmirr_load - load the $MFTMirr and setup the ntfs volume with it
- * @vol: ntfs volume whose $MFTMirr to load
- *
- * Load $MFTMirr from @vol and setup @vol with it. After calling this function
- * the volume @vol is ready for use by all write access functions provided by
- * the ntfs library (assuming ntfs_mft_load() has been called successfully
- * beforehand).
- *
- * Return 0 on success and -1 on error with errno set to the error code.
- */
-static int ntfs_mftmirr_load(ntfs_volume *vol)
-{
- int err;
-
- vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr);
- if (!vol->mftmirr_ni) {
- ntfs_log_perror("Failed to open inode $MFTMirr");
- return -1;
- }
- /* Get an ntfs attribute for $MFTMirr/$DATA, too. */
- vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA,
- AT_UNNAMED, 0);
- if (!vol->mftmirr_na) {
- ntfs_log_perror("Failed to open $MFTMirr/$DATA");
- goto error_exit;
- }
- if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {
- ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
- goto error_exit;
- }
- /* Check $MFTMirr runlist. */
- if (vol->mftmirr_na->rl[0].lcn != vol->mftmirr_lcn ||
- vol->mftmirr_na->rl[0].length < (vol->mftmirr_size *
- vol->mft_record_size + vol->cluster_size - 1) /
- vol->cluster_size) {
- ntfs_log_error("$MFTMirr location mismatch or first 4 records "
- "are fragmented. Run chkdsk.\n");
- errno = EIO;
- goto error_exit;
-
- }
- return 0;
-error_exit:
- err = errno;
- if (vol->mftmirr_na) {
- ntfs_attr_close(vol->mftmirr_na);
- vol->mftmirr_na = NULL;
- }
- ntfs_inode_close(vol->mftmirr_ni);
- vol->mftmirr_ni = NULL;
- errno = err;
- return -1;
-}
-
-/**
- * ntfs_volume_startup - allocate and setup an ntfs volume
- * @dev: device to open
- * @flags: optional mount flags
- *
- * Load, verify, and parse bootsector; load and setup $MFT and $MFTMirr. After
- * calling this function, the volume is setup sufficiently to call all read
- * and write access functions provided by the library.
- *
- * Return the allocated volume structure on success and NULL on error with
- * errno set to the error code.
- */
-ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
- ntfs_mount_flags flags)
-{
- LCN mft_zone_size, mft_lcn;
- s64 br;
- ntfs_volume *vol;
- NTFS_BOOT_SECTOR *bs;
- int eo;
-#ifdef DEBUG
- const char *OK = "OK\n";
- const char *FAILED = "FAILED\n";
- BOOL debug = 1;
-#else
- BOOL debug = 0;
-#endif
-
- if (!dev || !dev->d_ops || !dev->d_name) {
- errno = EINVAL;
- return NULL;
- }
-
- if (!(bs = (NTFS_BOOT_SECTOR *)ntfs_malloc(sizeof(NTFS_BOOT_SECTOR))))
- return NULL;
-
- /* Allocate the volume structure. */
- vol = ntfs_volume_alloc();
- if (!vol)
- goto error_exit;
- /* Create the default upcase table. */
- vol->upcase_len = 65536;
- vol->upcase = (ntfschar*)ntfs_malloc(vol->upcase_len *
- sizeof(ntfschar));
- if (!vol->upcase)
- goto error_exit;
- ntfs_upcase_table_build(vol->upcase,
- vol->upcase_len * sizeof(ntfschar));
- if (flags & NTFS_MNT_RDONLY)
- NVolSetReadOnly(vol);
- if (flags & NTFS_MNT_CASE_SENSITIVE)
- NVolSetCaseSensitive(vol);
- if (flags & NTFS_MNT_INTERIX)
- NVolSetInterix(vol);
- ntfs_log_debug("Reading bootsector... ");
- if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY :
- ((flags & NTFS_MNT_NOT_EXCLUSIVE) ? O_RDWR :
- (O_RDWR | O_EXCL)))) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Error opening partition device");
- goto error_exit;
- }
- /* Attach the device to the volume. */
- vol->u.dev = dev;
- /* Now read the bootsector. */
- br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
- if (br != sizeof(NTFS_BOOT_SECTOR)) {
- ntfs_log_debug(FAILED);
- if (br != -1)
- errno = EINVAL;
- if (!br)
- ntfs_log_debug("Error: partition is smaller than "
- "bootsector size. Weird!\n");
- else
- ntfs_log_perror("Error reading bootsector");
- goto error_exit;
- }
- ntfs_log_debug(OK);
- if (!ntfs_boot_sector_is_ntfs(bs, !debug)) {
- ntfs_log_debug("Error: %s is not a valid NTFS partition!\n",
- dev->d_name);
- errno = EINVAL;
- goto error_exit;
- }
- if (ntfs_boot_sector_parse(vol, bs) < 0) {
- ntfs_log_perror("Failed to parse ntfs bootsector");
- goto error_exit;
- }
- free(bs);
- bs = NULL;
- /* Now set the device block size to the sector size. */
- if (ntfs_device_block_size_set(vol->u.dev, vol->sector_size))
- ntfs_log_debug("Failed to set the device block size to the "
- "sector size. This may affect performance "
- "but should be harmless otherwise. Error: "
- "%s\n", strerror(errno));
- /*
- * We now initialize the cluster allocator.
- *
- * FIXME: Move this to its own function? (AIA)
- */
-
- // TODO: Make this tunable at mount time. (AIA)
- vol->mft_zone_multiplier = 1;
-
- /* Determine the size of the MFT zone. */
- 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 the mft zone. */
- vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
- ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos);
-
- /*
- * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
- * source) and if the actual mft_lcn is in the expected place or even
- * further to the front of the volume, extend the mft_zone to cover the
- * beginning of the volume as well. This is in order to protect the
- * area reserved for the mft bitmap as well within the mft_zone itself.
- * On non-standard volumes we don't protect it as the overhead would be
- * higher than the speed increase we would get by doing it.
- */
- mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
- if (mft_lcn * vol->cluster_size < 16 * 1024)
- mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
- vol->cluster_size;
- if (vol->mft_zone_start <= mft_lcn)
- vol->mft_zone_start = 0;
- ntfs_log_debug("mft_zone_start = 0x%llx\n",
- (long long)vol->mft_zone_start);
-
- /*
- * Need to cap the mft zone on non-standard volumes so that it does
- * not point outside the boundaries of the volume. We do this by
- * halving the zone size until we are inside the volume.
- */
- vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
- while (vol->mft_zone_end >= vol->nr_clusters) {
- mft_zone_size >>= 1;
- vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
- }
- ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
-
- /*
- * Set the current position within each data zone to the start of the
- * respective zone.
- */
- vol->data1_zone_pos = vol->mft_zone_end;
- ntfs_log_debug("data1_zone_pos = 0x%llx\n", vol->data1_zone_pos);
- vol->data2_zone_pos = 0;
- ntfs_log_debug("data2_zone_pos = 0x%llx\n", vol->data2_zone_pos);
-
- /* Set the mft data allocation position to mft record 24. */
- vol->mft_data_pos = 24;
-
- /*
- * The cluster allocator is now fully operational.
- */
-
- /* Need to setup $MFT so we can use the library read functions. */
- ntfs_log_debug("Loading $MFT... ");
- if (ntfs_mft_load(vol) < 0) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to load $MFT");
- goto error_exit;
- }
- ntfs_log_debug(OK);
-
- /* Need to setup $MFTMirr so we can use the write functions, too. */
- ntfs_log_debug("Loading $MFTMirr... ");
- if (ntfs_mftmirr_load(vol) < 0) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to load $MFTMirr");
- goto error_exit;
- }
- ntfs_log_debug(OK);
- return vol;
-error_exit:
- eo = errno;
- free(bs);
- if (vol)
- __ntfs_volume_release(vol);
- errno = eo;
- return NULL;
-}
-
-/**
- * ntfs_volume_check_logfile - check logfile on target volume
- * @vol: volume on which to check logfile
- *
- * Return 0 on success and -1 on error with errno set error code.
- */
-static int ntfs_volume_check_logfile(ntfs_volume *vol)
-{
- ntfs_inode *ni;
- ntfs_attr *na = NULL;
- RESTART_PAGE_HEADER *rp = NULL;
- int err = 0;
-
- if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
- ntfs_log_debug("Failed to open inode FILE_LogFile.\n");
- errno = EIO;
- return -1;
- }
- if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
- ntfs_log_debug("Failed to open $FILE_LogFile/$DATA\n");
- err = EIO;
- goto exit;
- }
- if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
- err = EOPNOTSUPP;
- free(rp);
-exit:
- if (na)
- ntfs_attr_close(na);
- ntfs_inode_close(ni);
- if (err) {
- errno = err;
- return -1;
- }
- return 0;
-}
-
-/**
- * ntfs_hiberfile_open - Find and open '/hiberfil.sys'
- * @vol: An ntfs volume obtained from ntfs_mount
- *
- * Return: inode Success, hiberfil.sys is valid
- * NULL hiberfil.sys doesn't exist or some other error occurred
- */
-static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
-{
- u64 inode;
- ntfs_inode *ni_root;
- ntfs_inode *ni_hibr = NULL;
- ntfschar *unicode = NULL;
- int unicode_len;
- const char *hiberfile = "hiberfil.sys";
-
- if (!vol) {
- errno = EINVAL;
- return NULL;
- }
-
- ni_root = ntfs_inode_open(vol, FILE_root);
- if (!ni_root) {
- ntfs_log_debug("Couldn't open the root directory.\n");
- return NULL;
- }
-
- unicode_len = ntfs_mbstoucs(hiberfile, &unicode, 0);
- if (unicode_len < 0) {
- ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode");
- goto out;
- }
-
- inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len);
- if (inode == (u64)-1) {
- ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile);
- goto out;
- }
-
- inode = MREF(inode);
- ni_hibr = ntfs_inode_open(vol, inode);
- if (!ni_hibr) {
- ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode);
- goto out;
- }
-out:
- ntfs_inode_close(ni_root);
- free(unicode);
- return ni_hibr;
-}
-
-
-#define NTFS_HIBERFILE_HEADER_SIZE 4096
-
-/**
- * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is
- * hibernated on the target volume
- * @vol: volume on which to check hiberfil.sys
- *
- * Return: 0 if Windows isn't hibernated for sure
- * -1 otherwise and errno is set to the appropriate value
- */
-static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
-{
- ntfs_inode *ni;
- ntfs_attr *na = NULL;
- int bytes_read, ret = -1;
- char *buf = NULL;
-
- ni = ntfs_hiberfile_open(vol);
- if (!ni) {
- if (errno == ENOENT)
- return 0;
- return -1;
- }
-
- buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE);
- if (!buf)
- goto out;
-
- na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
- if (!na) {
- ntfs_log_perror("Failed to open hiberfil.sys data attribute");
- goto out;
- }
-
- bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf);
- if (bytes_read == -1) {
- ntfs_log_perror("Failed to read hiberfil.sys");
- goto out;
- }
- if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) {
- ntfs_log_debug("Hibernated non-system partition, refused to "
- "mount!\n");
- errno = EPERM;
- goto out;
- }
- if (memcmp(buf, "hibr", 4) == 0) {
- ntfs_log_debug("Windows is hibernated, refused to mount!\n");
- errno = EPERM;
- goto out;
- }
- ret = 0;
-out:
- if (na)
- ntfs_attr_close(na);
- free(buf);
- ntfs_inode_close(ni);
- return ret;
-}
-
-/**
- * ntfs_volume_get_nr_free_mft_records - calculate number of free MFT records
- * vol: ntfs volume for which perform calculations.
- *
- * This function initializes @vol->nr_free_mft_records. @vol->mftbmp_na should
- * be already opened upon call to this function.
- *
- * Return 0 on success. On error return -1 with errno set appropriately and
- * @vol->nr_free_mft_records is not touched in this case.
- */
-static int ntfs_volume_get_nr_free_mft_records(ntfs_volume *vol)
-{
- long nr_free = vol->mft_na->data_size >> vol->mft_record_size_bits;
- s64 br, total = 0;
- u8 *buf;
-
- buf = ntfs_malloc(vol->cluster_size);
- if (!buf)
- return -1;
- while (1) {
- int i, j;
-
- br = ntfs_attr_pread(vol->mftbmp_na, total,
- vol->cluster_size, buf);
- if (br <= 0)
- break;
- total += br;
- for (i = 0; i < br; i++)
- for (j = 0; j < 8; j++)
- if ((buf[i] >> j) & 1)
- nr_free--;
- }
- free(buf);
- if (!total || br < 0) {
- ntfs_log_error("pread: %s\n", strerror(errno));
- return -1;
- }
- vol->nr_free_mft_records = nr_free;
- return 0;
-}
-
-/**
- * ntfs_volume_get_nr_free_clusters - calculate number of free clusters
- * vol: ntfs volume for which perform calculations.
- *
- * This function initializes @vol->nr_free_clusters. @vol->lcnbmp_na should be
- * already opened upon call to this function.
- *
- * Return 0 on success. On error return -1 with errno set appropriately and
- * @vol->nr_free_clusters is not touched in this case.
- */
-static long ntfs_volume_get_nr_free_clusters(ntfs_volume *vol)
-{
- long nr_free = vol->nr_clusters;
- s64 br, total = 0;
- u8 *buf;
-
- buf = ntfs_malloc(vol->cluster_size);
- if (!buf)
- return -1;
- while (1) {
- int i, j;
-
- br = ntfs_attr_pread(vol->lcnbmp_na, total,
- vol->cluster_size, buf);
- if (br <= 0)
- break;
- total += br;
- for (i = 0; i < br; i++)
- for (j = 0; j < 8; j++)
- if ((buf[i] >> j) & 1)
- nr_free--;
- }
- free(buf);
- if (!total || br < 0) {
- ntfs_log_error("pread: %s\n", strerror(errno));
- return -1;
- }
- vol->nr_free_clusters = nr_free;
- return 0;
-}
-
-/**
- * ntfs_device_mount - open ntfs volume
- * @dev: device to open
- * @flags: optional mount flags
- *
- * This function mounts an ntfs volume. @dev should describe the device which
- * to mount as the ntfs volume.
- *
- * @flags is an optional second parameter. Some flags are similar to flags used
- * as for the mount system call (man 2 mount). Currently the following flags
- * are implemented:
- * NTFS_MNT_RDONLY - mount volume read-only
- * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if
- * they are not in POSIX namespace
- * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively
- * NTFS_MNT_FORENSIC - mount for forensic purposes, i.e. do not do
- * any writing at all during the mount, i.e. no
- * journal emptying, no dirty bit setting, etc.
- * NTFS_MNT_INTERIX - make libntfs recognize special Interix files
- *
- * The function opens the device @dev and verifies that it contains a valid
- * bootsector. Then, it allocates an ntfs_volume structure and initializes
- * some of the values inside the structure from the information stored in the
- * bootsector. It proceeds to load the necessary system files and completes
- * setting up the structure.
- *
- * Return the allocated volume structure on success and NULL on error with
- * errno set to the error code.
- */
-ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
-{
- s64 l;
-#ifdef DEBUG
- const char *OK = "OK\n";
- const char *FAILED = "FAILED\n";
-#endif
- ntfs_volume *vol;
- u8 *m = NULL, *m2 = NULL;
- ntfs_attr_search_ctx *ctx = NULL;
- ntfs_inode *ni;
- ntfs_attr *na;
- ATTR_RECORD *a;
- VOLUME_INFORMATION *vinf;
- ntfschar *vname;
- int i, j, eo;
- u32 u;
-
- vol = ntfs_volume_startup(dev, flags);
- if (!vol) {
- ntfs_log_perror("Failed to startup volume");
- return NULL;
- }
- /* Record whether this is a forensic mount. */
- if (flags & NTFS_MNT_FORENSIC)
- NVolSetForensicMount(vol);
- /* Load data from $MFT and $MFTMirr and compare the contents. */
- m = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
- m2 = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits);
- if (!m || !m2)
- goto error_exit;
-
- l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
- vol->mft_record_size, m);
- if (l != vol->mftmirr_size) {
- if (l == -1)
- ntfs_log_perror("Failed to read $MFT");
- else {
- ntfs_log_debug("Failed to read $MFT, unexpected length "
- "(%d != %lld).\n", vol->mftmirr_size, l);
- errno = EIO;
- }
- goto error_exit;
- }
- l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
- vol->mft_record_size, m2);
- if (l != vol->mftmirr_size) {
- if (l == -1)
- ntfs_log_perror("Failed to read $MFTMirr");
- else {
- ntfs_log_debug("Failed to read $MFTMirr, unexpected "
- "length (%d != %lld).\n",
- vol->mftmirr_size, l);
- errno = EIO;
- }
- goto error_exit;
- }
- ntfs_log_debug("Comparing $MFTMirr to $MFT... ");
- for (i = 0; i < vol->mftmirr_size; ++i) {
- MFT_RECORD *mrec, *mrec2;
- const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
- "$Volume", "$AttrDef", "root directory", "$Bitmap",
- "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
- const char *s;
-
- if (i < 12)
- s = ESTR[i];
- else if (i < 16)
- s = "system file";
- else
- s = "mft record";
-
- mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
- if (mrec->flags & MFT_RECORD_IN_USE) {
- if (ntfs_is_baad_record(mrec->magic)) {
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("$MFT error: Incomplete multi "
- "sector transfer detected in "
- "%s.\n", s);
- goto io_error_exit;
- }
- if (!ntfs_is_mft_record(mrec->magic)) {
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("$MFT error: Invalid mft "
- "record for %s.\n", s);
- goto io_error_exit;
- }
- }
- mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
- if (mrec2->flags & MFT_RECORD_IN_USE) {
- if (ntfs_is_baad_record(mrec2->magic)) {
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("$MFTMirr error: Incomplete "
- "multi sector transfer "
- "detected in %s.\n", s);
- goto io_error_exit;
- }
- if (!ntfs_is_mft_record(mrec2->magic)) {
- ntfs_log_debug("FAILED\n");
- ntfs_log_debug("$MFTMirr error: Invalid mft "
- "record for %s.\n", s);
- goto io_error_exit;
- }
- }
- if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("$MFTMirr does not match $MFT. Run "
- "chkdsk.\n");
- goto io_error_exit;
- }
- }
- ntfs_log_debug(OK);
-
- free(m2);
- free(m);
- m = m2 = NULL;
-
- /* Now load the bitmap from $Bitmap. */
- ntfs_log_debug("Loading $Bitmap... ");
- vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
- if (!vol->lcnbmp_ni) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open inode");
- goto error_exit;
- }
- /* Get an ntfs attribute for $Bitmap/$DATA. */
- vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
- if (!vol->lcnbmp_na) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open ntfs attribute");
- goto error_exit;
- }
- /* Done with the $Bitmap mft record. */
- ntfs_log_debug(OK);
-
- /* Now load the upcase table from $UpCase. */
- ntfs_log_debug("Loading $UpCase... ");
- ni = ntfs_inode_open(vol, FILE_UpCase);
- if (!ni) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open inode");
- goto error_exit;
- }
- /* Get an ntfs attribute for $UpCase/$DATA. */
- na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
- if (!na) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open ntfs attribute");
- goto error_exit;
- }
- /*
- * Note: Normally, the upcase table has a length equal to 65536
- * 2-byte Unicode characters but allow for different cases, so no
- * checks done. Just check we don't overflow 32-bits worth of Unicode
- * characters.
- */
- if (na->data_size & ~0x1ffffffffULL) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Upcase table is too big (max 32-bit "
- "allowed).\n");
- errno = EINVAL;
- goto error_exit;
- }
- if (vol->upcase_len != na->data_size >> 1) {
- vol->upcase_len = na->data_size >> 1;
- /* Throw away default table. */
- free(vol->upcase);
- vol->upcase = (ntfschar*)ntfs_malloc(na->data_size);
- if (!vol->upcase) {
- ntfs_log_debug(FAILED);
- goto error_exit;
- }
- }
- /* Read in the $DATA attribute value into the buffer. */
- l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
- if (l != na->data_size) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Amount of data read does not correspond to "
- "expected length!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Done with the $UpCase mft record. */
- ntfs_log_debug(OK);
- ntfs_attr_close(na);
- if (ntfs_inode_close(ni))
- ntfs_log_perror("Failed to close inode, leaking memory");
-
- /*
- * Now load $Volume and set the version information and flags in the
- * vol structure accordingly.
- */
- ntfs_log_debug("Loading $Volume... ");
- vol->vol_ni = ntfs_inode_open(vol, FILE_Volume);
- if (!vol->vol_ni) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open inode");
- goto error_exit;
- }
- /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
- ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
- if (!ctx) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to allocate attribute search context");
- goto error_exit;
- }
- /* Find the $VOLUME_INFORMATION attribute. */
- if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
- 0, ctx)) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("$VOLUME_INFORMATION attribute not found in "
- "$Volume?!?\n");
- goto error_exit;
- }
- a = ctx->attr;
- /* Has to be resident. */
- if (a->non_resident) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION must be "
- "resident (and it isn't)!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Get a pointer to the value of the attribute. */
- vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->u.res.value_offset) + (char*)a);
- /* Sanity checks. */
- if ((char*)vinf + le32_to_cpu(a->u.res.value_length) > (char*)ctx->mrec +
- le32_to_cpu(ctx->mrec->bytes_in_use) ||
- le16_to_cpu(a->u.res.value_offset) + le32_to_cpu(
- a->u.res.value_length) > le32_to_cpu(a->length)) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION in "
- "$Volume is corrupt!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Setup vol from the volume information attribute value. */
- vol->major_ver = vinf->major_ver;
- vol->minor_ver = vinf->minor_ver;
- /*
- * Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are defined
- * using cpu_to_le16() macro and hence are consistent.
- */
- vol->flags = vinf->flags;
- /* Record whether the volume was dirty or not. */
- if (vol->flags & VOLUME_IS_DIRTY)
- NVolSetWasDirty(vol);
- /*
- * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup.
- */
- ntfs_attr_reinit_search_ctx(ctx);
- if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
- ctx)) {
- if (errno != ENOENT) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Lookup of $VOLUME_NAME "
- "attribute in $Volume failed. "
- "This probably means something is "
- "corrupt. Run chkdsk.\n");
- goto error_exit;
- }
- /*
- * Attribute not present. This has been seen in the field.
- * Treat this the same way as if the attribute was present but
- * had zero length.
- */
- vol->vol_name = ntfs_malloc(1);
- if (!vol->vol_name) {
- ntfs_log_debug(FAILED);
- goto error_exit;
- }
- vol->vol_name[0] = '\0';
- } else {
- a = ctx->attr;
- /* Has to be resident. */
- if (a->non_resident) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Attribute $VOLUME_NAME must be "
- "resident!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Get a pointer to the value of the attribute. */
- vname = (ntfschar*)(le16_to_cpu(a->u.res.value_offset) + (char*)a);
- u = le32_to_cpu(a->u.res.value_length) / 2;
- /*
- * Convert Unicode volume name to current locale multibyte
- * format.
- */
- vol->vol_name = NULL;
- if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
- ntfs_log_perror("Error: Volume name could not be "
- "converted to current locale");
- ntfs_log_debug("Forcing name into ASCII by replacing "
- "non-ASCII characters with underscores.\n");
- vol->vol_name = ntfs_malloc(u + 1);
- if (!vol->vol_name) {
- ntfs_log_debug(FAILED);
- goto error_exit;
- }
- for (j = 0; j < (s32)u; j++) {
- u16 uc = le16_to_cpu(vname[j]);
- if (uc > 0xff)
- uc = (u16)'_';
- vol->vol_name[j] = (char)uc;
- }
- vol->vol_name[u] = 0;
- }
- }
- ntfs_log_debug(OK);
- ntfs_attr_put_search_ctx(ctx);
- ctx = NULL;
- /* Now load the attribute definitions from $AttrDef. */
- ntfs_log_debug("Loading $AttrDef... ");
- ni = ntfs_inode_open(vol, FILE_AttrDef);
- if (!ni) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open inode");
- goto error_exit;
- }
- /* Get an ntfs attribute for $AttrDef/$DATA. */
- na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
- if (!na) {
- ntfs_log_debug(FAILED);
- ntfs_log_perror("Failed to open ntfs attribute");
- goto error_exit;
- }
- /* Check we don't overflow 32-bits. */
- if (na->data_size > 0xffffffffLL) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Error: Attribute definition table is too big "
- "(max 32-bit allowed).\n");
- errno = EINVAL;
- goto error_exit;
- }
- vol->attrdef_len = na->data_size;
- vol->attrdef = (ATTR_DEF*)ntfs_malloc(na->data_size);
- if (!vol->attrdef) {
- ntfs_log_debug(FAILED);
- goto error_exit;
- }
- /* Read in the $DATA attribute value into the buffer. */
- l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef);
- if (l != na->data_size) {
- ntfs_log_debug(FAILED);
- ntfs_log_debug("Amount of data read does not correspond to "
- "expected length!\n");
- errno = EIO;
- goto error_exit;
- }
- /* Done with the $AttrDef mft record. */
- ntfs_log_debug(OK);
- ntfs_attr_close(na);
- if (ntfs_inode_close(ni))
- ntfs_log_perror("Failed to close inode, leaking memory");
- /* Initialize number of free clusters and MFT records. */
- if (ntfs_volume_get_nr_free_mft_records(vol)) {
- ntfs_log_perror("Failed to calculate number of free MFTs");
- goto error_exit;
- }
- if (ntfs_volume_get_nr_free_clusters(vol)) {
- ntfs_log_perror("Failed to calculate number of free clusters");
- goto error_exit;
- }
- /*
- * Check for dirty logfile and hibernated Windows.
- * We care only about read-write mounts.
- *
- * If all is ok, reset the logfile and set the dirty bit on the volume.
- *
- * But do not do that if this is a FORENSIC mount.
- */
- if (!(flags & NTFS_MNT_RDONLY)) {
- if (ntfs_volume_check_hiberfile(vol) < 0)
- goto error_exit;
- if (ntfs_volume_check_logfile(vol) < 0) {
- if (errno != EOPNOTSUPP || !(flags & NTFS_MNT_FORCE))
- goto error_exit;
- ntfs_log_warning("WARNING: $LogFile is not clean, "
- "forced to continue.\n");
- NVolSetWasDirty(vol); /* Leave volume dirty since we
- empted logfile. */
- }
- if (!NVolForensicMount(vol)) {
- if (ntfs_logfile_reset(vol) < 0)
- goto error_exit;
- if (!(vol->flags & VOLUME_IS_DIRTY)) {
- vol->flags |= VOLUME_IS_DIRTY;
- if (ntfs_volume_write_flags(vol, vol->flags) <
- 0)
- goto error_exit;
- }
- }
- }
- return vol;
-io_error_exit:
- errno = EIO;
-error_exit:
- eo = errno;
- if (ctx)
- ntfs_attr_put_search_ctx(ctx);
- free(m);
- free(m2);
- __ntfs_volume_release(vol);
- errno = eo;
- return NULL;
-}
-
-/**
- * ntfs_mount - open ntfs volume
- * @name: name of device/file to open
- * @flags: optional mount flags
- *
- * This function mounts an ntfs volume. @name should contain the name of the
- * device/file to mount as the ntfs volume.
- *
- * @flags is an optional second parameter. See ntfs_device_mount comment for
- * description.
- *
- * The function opens the device or file @name and verifies that it contains a
- * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
- * some of the values inside the structure from the information stored in the
- * bootsector. It proceeds to load the necessary system files and completes
- * setting up the structure.
- *
- * Return the allocated volume structure on success and NULL on error with
- * errno set to the error code.
- *
- * Note, that a copy is made of @name, and hence it can be discarded as
- * soon as the function returns.
- */
-ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
- ntfs_mount_flags flags __attribute__((unused)))
-{
-#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
- struct ntfs_device *dev;
- ntfs_volume *vol;
-
- /* Allocate an ntfs_device structure. */
- dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
- if (!dev)
- return NULL;
- /* Call ntfs_device_mount() to do the actual mount. */
- vol = ntfs_device_mount(dev, flags);
- if (!vol) {
- int eo = errno;
- ntfs_device_free(dev);
- errno = eo;
- }
- return vol;
-#else
- /*
- * ntfs_mount() makes no sense if NO_NTFS_DEVICE_DEFAULT_IO_OPS is
- * defined as there are no device operations available in libntfs in
- * this case.
- */
- errno = EOPNOTSUPP;
- return NULL;
-#endif
-}
-
-/**
- * ntfs_device_umount - close ntfs volume
- * @vol: address of ntfs_volume structure of volume to close
- * @force: if true force close the volume even if it is busy
- *
- * Deallocate all structures (including @vol itself) associated with the ntfs
- * volume @vol.
- *
- * Note it is up to the caller to destroy the device associated with the volume
- * being unmounted after this function returns.
- *
- * Return 0 on success. On error return -1 with errno set appropriately
- * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
- * an operation is in progress and if you try the close later the operation
- * might be completed and the close succeed.
- *
- * If @force is true (i.e. not zero) this function will close the volume even
- * if this means that data might be lost.
- *
- * @vol must have previously been returned by a call to ntfs_device_mount().
- *
- * @vol itself is deallocated and should no longer be dereferenced after this
- * function returns success. If it returns an error then nothing has been done
- * so it is safe to continue using @vol.
- */
-int ntfs_device_umount(ntfs_volume *vol,
- const BOOL force __attribute__((unused)))
-{
- if (!vol) {
- errno = EINVAL;
- return -1;
- }
- __ntfs_volume_release(vol);
- return 0;
-}
-
-/**
- * ntfs_umount - close ntfs volume
- * @vol: address of ntfs_volume structure of volume to close
- * @force: if true force close the volume even if it is busy
- *
- * Deallocate all structures (including @vol itself) associated with the ntfs
- * volume @vol.
- *
- * Return 0 on success. On error return -1 with errno set appropriately
- * (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
- * an operation is in progress and if you try the close later the operation
- * might be completed and the close succeed.
- *
- * If @force is true (i.e. not zero) this function will close the volume even
- * if this means that data might be lost.
- *
- * @vol must have previously been returned by a call to ntfs_mount().
- *
- * @vol itself is deallocated and should no longer be dereferenced after this
- * function returns success. If it returns an error then nothing has been done
- * so it is safe to continue using @vol.
- */
-int ntfs_umount(ntfs_volume *vol,
- const BOOL force __attribute__((unused)))
-{
- struct ntfs_device *dev;
-
- if (!vol) {
- errno = EINVAL;
- return -1;
- }
- dev = vol->u.dev;
- __ntfs_volume_release(vol);
- ntfs_device_free(dev);
- return 0;
-}
-
-#ifdef HAVE_MNTENT_H
-
-#ifndef HAVE_REALPATH
-/**
- * realpath - If there is no realpath on the system
- */
-static char *realpath(const char *path, char *resolved_path)
-{
- strncpy(resolved_path, path, PATH_MAX);
- resolved_path[PATH_MAX] = '\0';
- return resolved_path;
-}
-#endif
-
-/**
- * ntfs_mntent_check - desc
- *
- * If you are wanting to use this, you actually wanted to use
- * ntfs_check_if_mounted(), you just didn't realize. (-:
- *
- * See description of ntfs_check_if_mounted(), below.
- */
-static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
-{
- struct mntent *mnt;
- char *real_file = NULL, *real_fsname = NULL;
- FILE *f;
- int err = 0;
-
- real_file = ntfs_malloc(PATH_MAX + 1);
- if (!real_file)
- return -1;
- real_fsname = ntfs_malloc(PATH_MAX + 1);
- if (!real_fsname) {
- err = errno;
- goto exit;
- }
- if (!realpath(file, real_file)) {
- err = errno;
- goto exit;
- }
- if (!(f = setmntent(MOUNTED, "r"))) {
- err = errno;
- goto exit;
- }
- while ((mnt = getmntent(f))) {
- if (!realpath(mnt->mnt_fsname, real_fsname))
- continue;
- if (!strcmp(real_file, real_fsname))
- break;
- }
- endmntent(f);
- if (!mnt)
- goto exit;
- *mnt_flags = NTFS_MF_MOUNTED;
- if (!strcmp(mnt->mnt_dir, "/"))
- *mnt_flags |= NTFS_MF_ISROOT;
-#ifdef HAVE_HASMNTOPT
- if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
- *mnt_flags |= NTFS_MF_READONLY;
-#endif
-exit:
- free(real_file);
- free(real_fsname);
- if (err) {
- errno = err;
- return -1;
- }
- return 0;
-}
-#endif /* HAVE_MNTENT_H */
-
-/**
- * ntfs_check_if_mounted - check if an ntfs volume is currently mounted
- * @file: device file to check
- * @mnt_flags: pointer into which to return the ntfs mount flags (see volume.h)
- *
- * If the running system does not support the {set,get,end}mntent() calls,
- * just return 0 and set *@mnt_flags to zero.
- *
- * When the system does support the calls, ntfs_check_if_mounted() first tries
- * to find the device @file in /etc/mtab (or wherever this is kept on the
- * running system). If it is not found, assume the device is not mounted and
- * return 0 and set *@mnt_flags to zero.
- *
- * If the device @file is found, set the NTFS_MF_MOUNTED flags in *@mnt_flags.
- *
- * Further if @file is mounted as the file system root ("/"), set the flag
- * NTFS_MF_ISROOT in *@mnt_flags.
- *
- * Finally, check if the file system is mounted read-only, and if so set the
- * NTFS_MF_READONLY flag in *@mnt_flags.
- *
- * On success return 0 with *@mnt_flags set to the ntfs mount flags.
- *
- * On error return -1 with errno set to the error code.
- */
-int ntfs_check_if_mounted(const char *file __attribute__((unused)),
- unsigned long *mnt_flags)
-{
- *mnt_flags = 0;
-#ifdef HAVE_MNTENT_H
- return ntfs_mntent_check(file, mnt_flags);
-#else
- return 0;
-#endif
-}
-
-/**
- * ntfs_version_is_supported - check if NTFS version is supported.
- * @vol: ntfs volume whose version we're interested in.
- *
- * The function checks if the NTFS volume version is known or not.
- * Version 1.1 and 1.2 are used by Windows NT3.x and NT4.
- * Version 2.x is used by Windows 2000 Betas.
- * Version 3.0 is used by Windows 2000.
- * Version 3.1 is used by Windows XP, Windows Server 2003 and Vista.
- *
- * Return 0 if NTFS version is supported otherwise -1 with errno set.
- *
- * The following error codes are defined:
- * EOPNOTSUPP - Unknown NTFS version
- * EINVAL - Invalid argument
- */
-int ntfs_version_is_supported(ntfs_volume *vol)
-{
- u8 major, minor;
-
- if (!vol) {
- errno = EINVAL;
- return -1;
- }
-
- major = vol->major_ver;
- minor = vol->minor_ver;
-
- if (NTFS_V1_1(major, minor) || NTFS_V1_2(major, minor))
- return 0;
-
- if (NTFS_V2_X(major, minor))
- return 0;
-
- if (NTFS_V3_0(major, minor) || NTFS_V3_1(major, minor))
- return 0;
-
- errno = EOPNOTSUPP;
- return -1;
-}
-
-/**
- * ntfs_logfile_reset - "empty" $LogFile data attribute value
- * @vol: ntfs volume whose $LogFile we intend to reset.
- *
- * Fill the value of the $LogFile data attribute, i.e. the contents of
- * the file, with 0xff's, thus marking the journal as empty.
- *
- * FIXME(?): We might need to zero the LSN field of every single mft
- * record as well. (But, first try without doing that and see what
- * happens, since chkdsk might pickup the pieces and do it for us...)
- *
- * On success return 0.
- *
- * On error return -1 with errno set to the error code.
- */
-int ntfs_logfile_reset(ntfs_volume *vol)
-{
- ntfs_inode *ni;
- ntfs_attr *na;
- int eo;
-
- if (!vol) {
- errno = EINVAL;
- return -1;
- }
-
- if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
- ntfs_log_perror("Failed to open inode FILE_LogFile.");
- return -1;
- }
-
- if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
- eo = errno;
- ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
- goto error_exit;
- }
-
- if (ntfs_empty_logfile(na)) {
- eo = errno;
- ntfs_log_perror("Failed to empty $FILE_LogFile/$DATA");
- ntfs_attr_close(na);
- goto error_exit;
- }
- ntfs_attr_close(na);
- return ntfs_inode_close(ni);
-
-error_exit:
- ntfs_inode_close(ni);
- errno = eo;
- return -1;
-}
-
-/**
- * ntfs_volume_write_flags - set the flags of an ntfs volume
- * @vol: ntfs volume where we set the volume flags
- * @flags: new flags
- *
- * Set the on-disk volume flags in the mft record of $Volume and
- * on volume @vol to @flags.
- *
- * Return 0 if successful and -1 if not with errno set to the error code.
- */
-int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags)
-{
- ATTR_RECORD *a;
- VOLUME_INFORMATION *c;
- ntfs_attr_search_ctx *ctx;
- int ret = -1; /* failure */
-
- if (!vol || !vol->vol_ni) {
- errno = EINVAL;
- return -1;
- }
- /* Get a pointer to the volume information attribute. */
- ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
- if (!ctx) {
- ntfs_log_perror("Failed to allocate attribute search context");
- return -1;
- }
- if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
- 0, ctx)) {
- ntfs_log_error("Attribute $VOLUME_INFORMATION was not found "
- "in $Volume!\n");
- goto err_out;
- }
- a = ctx->attr;
- /* Sanity check. */
- if (a->non_resident) {
- ntfs_log_error("Attribute $VOLUME_INFORMATION must be "
- "resident (and it isn't)!\n");
- errno = EIO;
- goto err_out;
- }
- /* Get a pointer to the value of the attribute. */
- c = (VOLUME_INFORMATION*)(le16_to_cpu(a->u.res.value_offset) + (char*)a);
- /* Sanity checks. */
- if ((char*)c + le32_to_cpu(a->u.res.value_length) > (char*)ctx->mrec +
- le32_to_cpu(ctx->mrec->bytes_in_use) ||
- le16_to_cpu(a->u.res.value_offset) +
- le32_to_cpu(a->u.res.value_length) > le32_to_cpu(a->length)) {
- ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
- "corrupt!\n");
- errno = EIO;
- goto err_out;
- }
- /* Set the volume flags. */
- vol->flags = c->flags = flags & VOLUME_FLAGS_MASK;
- /* Write them to disk. */
- ntfs_inode_mark_dirty(vol->vol_ni);
- if (ntfs_inode_sync(vol->vol_ni)) {
- ntfs_log_perror("Error writing $Volume");
- goto err_out;
- }
- ret = 0; /* success */
-err_out:
- ntfs_attr_put_search_ctx(ctx);
- if (ret)
- ntfs_log_error("%s(): Failed.\n", "ntfs_volume_write_flags");
- return ret;
-}
-
diff --git a/usr/src/lib/libntfs/common/mapfile-vers b/usr/src/lib/libntfs/common/mapfile-vers
deleted file mode 100644
index f0e4c9f3d4..0000000000
--- a/usr/src/lib/libntfs/common/mapfile-vers
+++ /dev/null
@@ -1,134 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
-#
-
-#
-# MAPFILE HEADER START
-#
-# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
-# Object versioning must comply with the rules detailed in
-#
-# usr/src/lib/README.mapfiles
-#
-# You should not be making modifications here until you've read the most current
-# copy of that file. If you need help, contact a gatekeeper for guidance.
-#
-# MAPFILE HEADER END
-#
-
-$mapfile_version 2
-
-SYMBOL_VERSION SUNW_10.1 {
- global:
- AT_UNNAMED;
- NTFS_INDEX_I30;
- NTFS_INDEX_O;
- NTFS_INDEX_Q;
- NTFS_INDEX_R;
- NTFS_INDEX_SDH;
- NTFS_INDEX_SII;
- ntfs_attr_add;
- ntfs_attr_close;
- ntfs_attr_find_in_attrdef;
- ntfs_attr_get_search_ctx;
- ntfs_attr_lookup;
- ntfs_attr_mst_pread;
- ntfs_attr_open;
- ntfs_attr_pread;
- ntfs_attr_put_search_ctx;
- ntfs_attr_pwrite;
- ntfs_attr_readall;
- __ntfs_attr_truncate;
- ntfs_boot_sector_is_ntfs;
- ntfs_calloc;
- ntfs_check_if_mounted;
- ntfs_cluster_read;
- ntfs_create;
- ntfs_device_alloc;
- ntfs_device_block_size_set;
- ntfs_device_free;
- ntfs_device_heads_get;
- ntfs_device_partition_start_sector_get;
- ntfs_device_sector_size_get;
- ntfs_device_sectors_per_track_get;
- ntfs_device_size_get;
- ntfs_device_unix_io_ops;
- ntfs_file_record_read;
- ntfs_file_record_read;
- ntfs_file_values_compare;
- ntfs_get_attribute_value;
- ntfs_get_attribute_value_length;
- ntfs_get_size_for_mapping_pairs;
- ntfs_guid_is_zero;
- ntfs_guid_to_mbs;
- ntfs_ie_get_vcn;
- ntfs_index_root_get;
- ntfs_inode_badclus_bad;
- ntfs_inode_close;
- ntfs_inode_open;
- ntfs_inode_sync;
- ntfs_libntfs_version;
- ntfs_log_clear_levels;
- ntfs_logfile_reset;
- ntfs_log_get_levels;
- ntfs_log_handler_outerr;
- ntfs_log_handler_stderr;
- ntfs_log_parse_option;
- ntfs_log_redirect;
- ntfs_log_set_handler;
- ntfs_log_set_levels;
- ntfs_malloc;
- ntfs_mapping_pairs_build;
- ntfs_mapping_pairs_decompress;
- ntfs_mbstoucs;
- ntfs_mft_record_layout;
- ntfs_mft_records_write;
- ntfs_mft_usn_dec;
- ntfs_mount;
- ntfs_mst_post_read_fixup;
- ntfs_mst_post_write_fixup;
- ntfs_mst_pre_write_fixup;
- ntfs_mst_pwrite;
- ntfs_names_are_equal;
- ntfs_names_collate;
- ntfs_pathname_to_inode;
- ntfs_readdir;
- ntfs_resident_attr_value_resize;
- ntfs_rl_pread;
- ntfs_rl_pwrite;
- ntfs_rl_truncate;
- ntfs_rl_vcn_to_lcn;
- ntfs_sid_to_mbs;
- ntfs_str2ucs;
- ntfs_ucsfree;
- ntfs_ucsnlen;
- ntfs_ucstombs;
- ntfs_umount;
- ntfs_upcase_table_build;
- ntfs_version_is_supported;
- ntfs_volume_alloc;
- ntfs_volume_startup;
- ntfs_volume_write_flags;
- local:
- *;
-};