Removed libntfs-specific sources.
parent
c3fa61b4e1
commit
f893a421c2
|
|
@ -1,38 +1,10 @@
|
|||
|
||||
linux_ntfsincludedir = $(includedir)/ntfs
|
||||
linux_ntfsinclude_HEADERS = \
|
||||
attrib.h \
|
||||
attrlist.h \
|
||||
bitmap.h \
|
||||
bootsect.h \
|
||||
collate.h \
|
||||
compat.h \
|
||||
compress.h \
|
||||
debug.h \
|
||||
device.h \
|
||||
device_io.h \
|
||||
dir.h \
|
||||
endians.h \
|
||||
gnome-vfs-method.h \
|
||||
gnome-vfs-module.h \
|
||||
index.h \
|
||||
inode.h \
|
||||
layout.h \
|
||||
lcnalloc.h \
|
||||
list.h \
|
||||
logfile.h \
|
||||
logging.h \
|
||||
mft.h \
|
||||
mst.h \
|
||||
ntfstime.h \
|
||||
rich.h \
|
||||
runlist.h \
|
||||
security.h \
|
||||
support.h \
|
||||
tree.h \
|
||||
types.h \
|
||||
unistr.h \
|
||||
version.h \
|
||||
volume.h
|
||||
tree.h
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
|
|||
|
|
@ -1,352 +0,0 @@
|
|||
/*
|
||||
* attrib.h - Exports for attribute handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-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_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 "types.h"
|
||||
#include "inode.h"
|
||||
#include "unistr.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "logging.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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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); \
|
||||
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)
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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_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);
|
||||
|
||||
// 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 */
|
||||
|
||||
|
|
@ -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->base_ni);
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
||||
|
|
@ -1,167 +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);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
|
||||
/**
|
||||
* struct ntfs_bmp -
|
||||
*
|
||||
* a cache for either dir/$BITMAP, $MFT/$BITMAP or $Bitmap/$DATA
|
||||
*/
|
||||
struct ntfs_bmp {
|
||||
ntfs_volume *vol;
|
||||
ntfs_attr *attr;
|
||||
int count;
|
||||
u8 **data;
|
||||
VCN *data_vcn;
|
||||
};
|
||||
|
||||
|
||||
int ntfs_bmp_rollback(struct ntfs_bmp *bmp);
|
||||
int ntfs_bmp_commit(struct ntfs_bmp *bmp);
|
||||
void ntfs_bmp_free(struct ntfs_bmp *bmp);
|
||||
struct ntfs_bmp * ntfs_bmp_create(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len);
|
||||
int ntfs_bmp_add_data(struct ntfs_bmp *bmp, VCN vcn, u8 *data);
|
||||
u8 * ntfs_bmp_get_data(struct ntfs_bmp *bmp, VCN vcn);
|
||||
int ntfs_bmp_set_range(struct ntfs_bmp *bmp, VCN vcn, s64 length, int value);
|
||||
s64 ntfs_bmp_find_last_set(struct ntfs_bmp *bmp);
|
||||
int ntfs_bmp_find_space(struct ntfs_bmp *bmp, LCN start, long size);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* defined _NTFS_BITMAP_H */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,63 +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
|
||||
|
||||
/**
|
||||
* ntfs_is_collation_rule_supported -
|
||||
* @cr:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static inline BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* FIXME: At the moment we only support COLLATION_BINARY,
|
||||
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return false
|
||||
* for everything else.
|
||||
*/
|
||||
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG &&
|
||||
cr != COLLATION_FILE_NAME)
|
||||
return FALSE;
|
||||
i = le32_to_cpu(cr);
|
||||
if (((i >= 0) && (i <= 0x02)) ||
|
||||
((i >= 0x10) && (i <= 0x13)))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len);
|
||||
|
||||
#endif /* _NTFS_COLLATE_H */
|
||||
|
|
@ -1,54 +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 */
|
||||
|
||||
#endif /* defined _NTFS_COMPAT_H */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,47 +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;
|
||||
|
||||
#ifdef NTFS_DISABLE_DEBUG_LOGGING
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
|
||||
#else
|
||||
extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
|
||||
#endif
|
||||
|
||||
#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]; \
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_DEBUG_H */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,143 +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 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 *ni, 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);
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
/**
|
||||
* struct ntfs_dir -
|
||||
*/
|
||||
struct ntfs_dir {
|
||||
ntfs_volume *vol;
|
||||
struct ntfs_dir *parent;
|
||||
ntfschar *name;
|
||||
int name_len;
|
||||
MFT_REF mft_num;
|
||||
struct ntfs_dt *index;
|
||||
struct ntfs_dir **children;
|
||||
int child_count;
|
||||
struct ntfs_bmp *bitmap;
|
||||
ntfs_inode *inode;
|
||||
ntfs_attr *iroot;
|
||||
ntfs_attr *ialloc;
|
||||
int index_size;
|
||||
};
|
||||
|
||||
|
||||
int ntfs_dir_rollback(struct ntfs_dir *dir);
|
||||
int ntfs_dir_truncate(ntfs_volume *vol, struct ntfs_dir *dir);
|
||||
int ntfs_dir_commit(struct ntfs_dir *dir);
|
||||
void ntfs_dir_free(struct ntfs_dir *dir);
|
||||
struct ntfs_dir * ntfs_dir_create(ntfs_volume *vol, MFT_REF mft_num);
|
||||
void ntfs_dir_add(struct ntfs_dir *parent, struct ntfs_dir *child);
|
||||
struct ntfs_dir * ntfs_dir_find2(struct ntfs_dir *dir, ntfschar *name, int name_len);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* defined _NTFS_DIR_H */
|
||||
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
* endians.h - Definitions related to handling of byte ordering. Part of the
|
||||
* Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 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_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) (x)
|
||||
#define __le32_to_cpu(x) (x)
|
||||
#define __le64_to_cpu(x) (x)
|
||||
|
||||
#define __cpu_to_le16(x) (x)
|
||||
#define __cpu_to_le32(x) (x)
|
||||
#define __cpu_to_le64(x) (x)
|
||||
|
||||
#define __constant_le16_to_cpu(x) (x)
|
||||
#define __constant_le32_to_cpu(x) (x)
|
||||
#define __constant_le64_to_cpu(x) (x)
|
||||
|
||||
#define __constant_cpu_to_le16(x) (x)
|
||||
#define __constant_cpu_to_le32(x) (x)
|
||||
#define __constant_cpu_to_le64(x) (x)
|
||||
|
||||
#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
|
||||
#define __le16_to_cpu(x) bswap_16(x)
|
||||
#define __le32_to_cpu(x) bswap_32(x)
|
||||
#define __le64_to_cpu(x) bswap_64(x)
|
||||
|
||||
#define __cpu_to_le16(x) bswap_16(x)
|
||||
#define __cpu_to_le32(x) bswap_32(x)
|
||||
#define __cpu_to_le64(x) bswap_64(x)
|
||||
|
||||
#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#define __constant_cpu_to_le16(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((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((u16)(x))
|
||||
#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x))
|
||||
#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x))
|
||||
|
||||
#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x))
|
||||
#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x))
|
||||
#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x))
|
||||
|
||||
/* Signed from LE to CPU conversion. */
|
||||
|
||||
#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x))
|
||||
#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x))
|
||||
#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x))
|
||||
|
||||
#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x))
|
||||
#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x))
|
||||
#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x))
|
||||
|
||||
/* Unsigned from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x))
|
||||
#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x))
|
||||
#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x))
|
||||
|
||||
#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x))
|
||||
#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x))
|
||||
#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x))
|
||||
|
||||
/* Signed from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x))
|
||||
#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x))
|
||||
#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x))
|
||||
|
||||
#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x))
|
||||
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
|
||||
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
|
||||
|
||||
/* Constant endianness conversion defines. */
|
||||
|
||||
#define const_le16_to_cpu(x) __constant_le16_to_cpu(x)
|
||||
#define const_le32_to_cpu(x) __constant_le32_to_cpu(x)
|
||||
#define const_le64_to_cpu(x) __constant_le64_to_cpu(x)
|
||||
|
||||
#define const_cpu_to_le16(x) __constant_cpu_to_le16(x)
|
||||
#define const_cpu_to_le32(x) __constant_cpu_to_le32(x)
|
||||
#define const_cpu_to_le64(x) __constant_cpu_to_le64(x)
|
||||
|
||||
#endif /* defined _NTFS_ENDIANS_H */
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* index.h - Defines for NTFS index handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005 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_INDEX_H
|
||||
#define _NTFS_INDEX_H
|
||||
|
||||
#include "attrib.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "mft.h"
|
||||
|
||||
/**
|
||||
* 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 @ia)
|
||||
* @data: index entry data (points into @entry)
|
||||
* @data_len: length in bytes of @data
|
||||
* @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ia
|
||||
* @ir: index root if @is_in_root or NULL otherwise
|
||||
* @actx: attribute search context if in root or NULL otherwise
|
||||
* @ia: index block if @is_in_root is FALSE or NULL otherwise
|
||||
* @ia_na: opened INDEX_ALLOCATION attribute
|
||||
* @ia_vcn: VCN from which @ia where read from
|
||||
* @ia_dirty: TRUE if index block was changed
|
||||
* @block_size: index block size
|
||||
* @vcn_size: VCN size for this index block
|
||||
* @vcn_size_bits: use instead of @vcn_size to speedup multiplication
|
||||
*
|
||||
* @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. @ia, @ia_vcn and
|
||||
* @ia_dirty are undefined in this case.
|
||||
*
|
||||
* If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
|
||||
* and @ia_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. @ia_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;
|
||||
BOOL is_in_root;
|
||||
INDEX_ROOT *ir;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
INDEX_ALLOCATION *ia;
|
||||
ntfs_attr *ia_na;
|
||||
VCN ia_vcn;
|
||||
BOOL ia_dirty;
|
||||
u32 block_size;
|
||||
u32 vcn_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);
|
||||
|
||||
/**
|
||||
* 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 ia_dirty to TRUE, thus index block will be updated during
|
||||
* ntfs_index_ctx_put.
|
||||
*/
|
||||
static inline 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->ia_dirty = TRUE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
void ntfs_ie_free(INDEX_ENTRY *ie);
|
||||
INDEX_ENTRY * ntfs_ie_create(void);
|
||||
VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie);
|
||||
INDEX_ENTRY * ntfs_ie_copy(INDEX_ENTRY *ie);
|
||||
INDEX_ENTRY * ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn);
|
||||
INDEX_ENTRY * ntfs_ie_remove_vcn(INDEX_ENTRY *ie);
|
||||
INDEX_ENTRY * ntfs_ie_set_name(INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype);
|
||||
INDEX_ENTRY * ntfs_ie_remove_name(INDEX_ENTRY *ie);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* _NTFS_INDEX_H */
|
||||
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
* inode.h - Defines for NTFS inode handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 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 "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. */
|
||||
|
||||
/* The NI_AttrList* tests 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. */
|
||||
};
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dt containing this inode */
|
||||
int ref_count;
|
||||
|
||||
/* Below fields are valid only for base inode. */
|
||||
s64 data_size; /* Data size stored in the filename index. */
|
||||
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.) */
|
||||
|
||||
time_t creation_time;
|
||||
time_t last_data_change_time;
|
||||
time_t last_mft_change_time;
|
||||
time_t last_access_time;
|
||||
};
|
||||
|
||||
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 MFT_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->base_ni);
|
||||
}
|
||||
|
||||
extern void ntfs_inode_update_atime(ntfs_inode *ni);
|
||||
extern void ntfs_inode_update_time(ntfs_inode *ni);
|
||||
|
||||
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);
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
int ntfs_inode_close2(ntfs_inode *ni);
|
||||
ntfs_inode * ntfs_inode_open2(ntfs_volume *vol, const MFT_REF mref);
|
||||
ntfs_inode * ntfs_inode_open3(ntfs_volume *vol, const MFT_REF mref);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* defined _NTFS_INODE_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
* logfile.h - Exports for $LogFile handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 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_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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* 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 = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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?).
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||
*/
|
||||
typedef struct {
|
||||
u16 seq_number;
|
||||
u16 client_index;
|
||||
} __attribute__((__packed__)) LOG_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* struct LOG_RECORD - Log record header.
|
||||
*
|
||||
* Each log record seems to have a constant size of 0x70 bytes.
|
||||
*/
|
||||
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[0];
|
||||
} __attribute__((__packed__)) LOG_RECORD;
|
||||
|
||||
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 */
|
||||
|
|
@ -1,113 +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 (1 << 0) /* x = 42 */
|
||||
#define NTFS_LOG_LEVEL_TRACE (1 << 1) /* Entering function x() */
|
||||
#define NTFS_LOG_LEVEL_QUIET (1 << 2) /* Quietable output */
|
||||
#define NTFS_LOG_LEVEL_INFO (1 << 3) /* Volume needs defragmenting */
|
||||
#define NTFS_LOG_LEVEL_VERBOSE (1 << 4) /* Forced to continue */
|
||||
#define NTFS_LOG_LEVEL_PROGRESS (1 << 5) /* 54% complete */
|
||||
#define NTFS_LOG_LEVEL_WARNING (1 << 6) /* You should backup before starting */
|
||||
#define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */
|
||||
#define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */
|
||||
#define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */
|
||||
#define NTFS_LOG_LEVEL_REASON (1 << 10) /* Human readable reason for failure */
|
||||
|
||||
/* Logging style flags - Manage the style of the output */
|
||||
#define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */
|
||||
#define NTFS_LOG_FLAG_FILENAME (1 << 1) /* Show the file origin of the message */
|
||||
#define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */
|
||||
#define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */
|
||||
#define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */
|
||||
#define NTFS_LOG_FLAG_COLOUR (1 << 5) /* Colour highlight some messages */
|
||||
|
||||
/* Macros to simplify logging. One for each level defined above.
|
||||
* Note, if NTFS_DISABLE_DEBUG_LOGGING is defined, then ntfs_log_debug/trace have no effect.
|
||||
*/
|
||||
#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)
|
||||
#define ntfs_log_reason(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_REASON,NULL,FORMAT,##ARGS)
|
||||
|
||||
/* By default debug and trace messages are compiled into the program,
|
||||
* but not displayed.
|
||||
*/
|
||||
#ifdef NTFS_DISABLE_DEBUG_LOGGING
|
||||
#define ntfs_log_debug(FORMAT, ARGS...)do {} while (0)
|
||||
#define ntfs_log_trace(FORMAT, ARGS...)do {} while (0)
|
||||
#else
|
||||
#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 /* NTFS_DISABLE_DEBUG_LOGGING */
|
||||
|
||||
#endif /* _LOGGING_H_ */
|
||||
|
||||
|
|
@ -1,130 +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);
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "dir.h"
|
||||
|
||||
int ntfs_mft_remove_attr(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type);
|
||||
ATTR_RECORD * ntfs_mft_add_attr(ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len);
|
||||
int ntfs_mft_resize_resident(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len);
|
||||
int ntfs_mft_free_space(struct ntfs_dir *dir);
|
||||
int ntfs_mft_add_index(struct ntfs_dir *dir);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* defined _NTFS_MFT_H */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* ntfstime.h - NTFS time related functions. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 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
|
||||
*/
|
||||
|
||||
#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(s64 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__ s64 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 */
|
||||
|
|
@ -1,87 +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 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 */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* support.h - Useful definitions and macros. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-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_SUPPORT_H
|
||||
#define _NTFS_SUPPORT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* 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))
|
||||
|
||||
#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 /* defined _NTFS_SUPPORT_H */
|
||||
|
||||
|
|
@ -1,118 +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
|
||||
*
|
||||
* 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;
|
||||
|
||||
typedef u16 le16;
|
||||
typedef u32 le32;
|
||||
typedef u64 le64;
|
||||
|
||||
/*
|
||||
* Declare sle{16,32,64} to be unsigned because we do not want sign extension
|
||||
* on BE architectures.
|
||||
*/
|
||||
typedef u16 sle16;
|
||||
typedef u32 sle32;
|
||||
typedef u64 sle64;
|
||||
|
||||
typedef u16 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> were 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;
|
||||
|
||||
#endif /* defined _NTFS_TYPES_H */
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* unistr.h - Exports for Unicode string handling. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2000-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_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 */
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* volume.h - Exports for NTFS volume handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 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_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
|
||||
|
||||
/*
|
||||
* Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY and MS_NOATIME,
|
||||
* so we define them ourselves.
|
||||
*/
|
||||
#ifndef MS_RDONLY
|
||||
#define MS_RDONLY 1
|
||||
#endif
|
||||
/*
|
||||
* Solaris defines MS_RDONLY but not MS_NOATIME thus we need to carefully
|
||||
* define MS_NOATIME.
|
||||
*/
|
||||
#ifndef MS_NOATIME
|
||||
#if (MS_RDONLY != 1)
|
||||
# define MS_NOATIME 1
|
||||
#else
|
||||
# define MS_NOATIME 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
#include "types.h"
|
||||
#include "support.h"
|
||||
#include "device.h"
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
|
||||
/**
|
||||
* enum ntfs_mount_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_mount_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. */
|
||||
} 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 NVolNoATime(nv) test_nvol_flag(nv, NoATime)
|
||||
#define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime)
|
||||
#define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime)
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
};
|
||||
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. */
|
||||
u16 flags; /* Bit array of VOLUME_* flags. */
|
||||
|
||||
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. */
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dir for . */
|
||||
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */
|
||||
void *private_bmp2; /* ntfs_bmp for $Bitmap */
|
||||
};
|
||||
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
||||
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
|
||||
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
extern int ntfs_device_umount(ntfs_volume *vol, const BOOL force);
|
||||
|
||||
extern ntfs_volume *ntfs_mount(const char *name, unsigned long 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 u16 flags);
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
int ntfs_volume_commit(ntfs_volume *vol);
|
||||
int ntfs_volume_rollback(ntfs_volume *vol);
|
||||
int ntfs_volume_umount2(ntfs_volume *vol, const BOOL force);
|
||||
ntfs_volume * ntfs_volume_mount2(const char *device, unsigned long flags, BOOL force);
|
||||
int utils_valid_device(const char *name, int force);
|
||||
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force);
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
#endif /* defined _NTFS_VOLUME_H */
|
||||
|
||||
|
|
@ -31,39 +31,6 @@ LTVERSION_LIBNTFS_GNOMEVFS = 1:0:0
|
|||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
|
||||
|
||||
lib_LTLIBRARIES = libntfs.la
|
||||
libntfs_la_LDFLAGS = -version-info $(LTVERSION_LIBNTFS) -no-undefined
|
||||
libntfs_la_CFLAGS = $(LIBNTFS_CFLAGS) \
|
||||
-DLTVERSION_LIBNTFS=\"$(LTVERSION_LIBNTFS)\"
|
||||
libntfs_la_SOURCES = \
|
||||
attrib.c \
|
||||
attrlist.c \
|
||||
bitmap.c \
|
||||
bootsect.c \
|
||||
collate.c \
|
||||
compat.c \
|
||||
compress.c \
|
||||
debug.c \
|
||||
device.c \
|
||||
device_io.c \
|
||||
dir.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
lcnalloc.c \
|
||||
logfile.c \
|
||||
logging.c \
|
||||
mft.c \
|
||||
mst.c \
|
||||
runlist.c \
|
||||
security.c \
|
||||
unistr.c \
|
||||
version.c \
|
||||
volume.c
|
||||
|
||||
if ENABLE_RICH
|
||||
libntfs_la_SOURCES += rich.c tree.c
|
||||
endif
|
||||
|
||||
if ENABLE_GNOME_VFS
|
||||
|
||||
gnomevfsmoduleslibdir = $(libdir)/gnome-vfs-2.0/modules
|
||||
|
|
@ -75,7 +42,7 @@ gnomevfsmodulesconf_DATA = libntfs.conf
|
|||
endif
|
||||
|
||||
libntfs_gnomevfs_la_LDFLAGS = -version-info $(LTVERSION_LIBNTFS_GNOMEVFS)
|
||||
libntfs_gnomevfs_la_LIBADD = libntfs.la
|
||||
libntfs_gnomevfs_la_LIBADD = libntfs-3g.la
|
||||
libntfs_gnomevfs_la_LIBS = $(LIBNTFS_GNOMEVFS_LIBS)
|
||||
libntfs_gnomevfs_la_CFLAGS = $(LIBNTFS_GNOMEVFS_CFLAGS)
|
||||
libntfs_gnomevfs_la_SOURCES = \
|
||||
|
|
@ -86,7 +53,7 @@ man_MANS = libntfs-gnomevfs.8
|
|||
|
||||
AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes)
|
||||
|
||||
EXTRA_DIST = unix_io.c win32_io.c libntfs.conf.in
|
||||
EXTRA_DIST = libntfs.conf.in
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
|
|
|
|||
5045
libntfs/attrib.c
5045
libntfs/attrib.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,449 +0,0 @@
|
|||
/* Reverse engineered functions in more or less modified form. find_attr()
|
||||
* is quite heavily modified but should be functionally equivalent to original.
|
||||
* lookup and lookup_external are less modified. Both should be functionally
|
||||
* equivalent to originals. */
|
||||
|
||||
/*
|
||||
* attr_search_context - used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @alist_mrec: mft record containing attribute list (i.e. base mft record)
|
||||
* @alist_attr: attribute list attribute record
|
||||
* @alist_val: attribute list value (if alist is resident in @alist_mrec)
|
||||
* @alist_val_end: end of attribute list value + 1
|
||||
* @alist_val_len: length of attribute list in bytes
|
||||
* @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. If the mft record in which to search has already
|
||||
* been loaded into memory, then initialize @base and @mrec to point to it,
|
||||
* @attr to point to the first attribute within @mrec, and set @is_first to
|
||||
* TRUE.
|
||||
*
|
||||
* @is_first is only honoured in lookup_attr() and only when called with @mrec
|
||||
* not NULL. Then, if @is_first is TRUE, lookup_attr() begins the search with
|
||||
* @attr. If @is_first is FALSE, lookup_attr() begins the search after @attr.
|
||||
* This is so that, after the first call to lookup_attr(), we can call
|
||||
* lookup_attr() again, without any modification of the search context, to
|
||||
* automagically get the next matching attribute.
|
||||
*
|
||||
* In contrast, find_attr() ignores @is_first and always begins the search with
|
||||
* @attr. find_attr() shouldn't really be called directly; it is just for
|
||||
* internal use. FIXME: Might want to change this behaviour later, but not
|
||||
* before I am finished with lookup_external_attr(). (AIA)
|
||||
*/
|
||||
typedef struct {
|
||||
u8 *base;
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
|
||||
u8 *alist_val_base;
|
||||
MFT_RECORD *alist_mrec;
|
||||
ATTR_RECORD *alist_attr;
|
||||
ATTR_LIST_ENTRY *alist_val;
|
||||
ATTR_LIST_ENTRY *alist_val_end;
|
||||
u32 alist_val_len;
|
||||
IS_FIRST_BOOL is_first;
|
||||
u8 *alist_old_base;
|
||||
} attr_search_context;
|
||||
|
||||
BOOL attr_find(const ntfs_volume *vol, const ATTR_TYPES type,
|
||||
const wchar_t *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;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!vol || !ctx || !ctx->mrec || !ctx->attr) {
|
||||
printf(stderr, "attr_find() received NULL pointer!\n");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
a = ctx->attr;
|
||||
/*
|
||||
* Iterate over attributes in mft record starting at @ctx->attr.
|
||||
* Note: Not using while/do/for loops so the comparison code
|
||||
* does not get indented out of the 80 characters wide screen... (AIA)
|
||||
*/
|
||||
goto search_loop;
|
||||
do_next:
|
||||
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
|
||||
if (a < ctx->mrec || a > (char*)ctx->mrec + vol->mft_record_size)
|
||||
goto file_corrupt;
|
||||
ctx->attr = a;
|
||||
search_loop:
|
||||
/* We catch $END with this more general check, too... */
|
||||
if (le32_to_cpu(a->type) > le32_to_cpu(type))
|
||||
goto not_found;
|
||||
if (!a->length)
|
||||
goto file_corrupt;
|
||||
if (a->type != type)
|
||||
goto do_next;
|
||||
/* If no @name is specified, check for @val. */
|
||||
if (!name) {
|
||||
register int rv;
|
||||
/* If no @val specified, we are done. */
|
||||
if (!val) {
|
||||
found_it:
|
||||
return TRUE;
|
||||
}
|
||||
rv = memcmp(val, (char*)a + le16_to_cpu(a->value_offset),
|
||||
min(val_len, le32_to_cpu(a->value_length)));
|
||||
/* If @val collates after the current attribute's value,
|
||||
continue searching as a matching attribute might follow. */
|
||||
if (!rv) {
|
||||
register u32 avl = le32_to_cpu(a->value_length);
|
||||
if (val_len == avl)
|
||||
goto found_it;
|
||||
if (val_len > avl)
|
||||
goto do_next;
|
||||
} else if (rv > 0)
|
||||
goto do_next;
|
||||
goto not_found;
|
||||
}
|
||||
if (ntfs_names_are_equal(name, name_len,
|
||||
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length, ic, vol->upcase, vol->upcase_len))
|
||||
goto found_it;
|
||||
{ register int rc = ntfs_names_collate(vol->upcase,
|
||||
vol->upcase_len, name, name_len,
|
||||
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length, IGNORE_CASE, 1);
|
||||
/* If case insensitive collation of names collates @name
|
||||
before a->name, there is no matching attribute. */
|
||||
if (rc == -1)
|
||||
goto not_found;
|
||||
/* If the strings are not equal, continue search. */
|
||||
if (rc)
|
||||
goto do_next;
|
||||
}
|
||||
/* If case sensitive collation of names doesn't collate @name before
|
||||
a->name, we continue the search. Otherwise we haven't found it. */
|
||||
if (ntfs_names_collate(vol->upcase, vol->upcase_len, name, name_len,
|
||||
(wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length, CASE_SENSITIVE, 1) != -1)
|
||||
goto do_next;
|
||||
not_found:
|
||||
return FALSE;
|
||||
file_corrupt:
|
||||
#ifdef DEBUG
|
||||
printf(stderr, "find_attr(): File is corrupt. Run chkdsk.\n");
|
||||
#endif
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
BOOL external_attr_lookup(const ntfs_volume *vol, const MFT_REFERENCE mref,
|
||||
const ATTR_TYPES type, const wchar_t *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const s64 lowest_vcn, const u8 *val,
|
||||
const u32 val_len, ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
ATTR_LIST_ENTRY *al_pos, **al_val, *al_val_start, *al_next_pos;
|
||||
ATTR_RECORD *attr_pos;
|
||||
MFT_RECORD *mrec, *m;
|
||||
u8 var1 = 0;
|
||||
u8 var2 = 0;
|
||||
u8 var3;
|
||||
int rc;
|
||||
wchar_t *al_name;
|
||||
u32 al_name_len;
|
||||
|
||||
al_val = &ctx->alist_val;
|
||||
if (ctx->alist_val_end <= *al_val && !ctx->is_first)
|
||||
goto file_corrupt;
|
||||
al_val_start = 0;
|
||||
if (ctx->base) {
|
||||
if (ctx->is_first)
|
||||
goto already_have_the_base_and_is_first;
|
||||
al_val_start = *al_val;
|
||||
al_pos = (char*)*al_val + le16_to_cpu((*al_val)->length);
|
||||
} else
|
||||
al_pos = *al_val;
|
||||
do_next:
|
||||
if (al_pos < ctx->alist_val_end)
|
||||
goto al_pos_below_alist_val_end;
|
||||
var1 = var2 = 1;
|
||||
al_pos = *al_val;
|
||||
do_next_2:
|
||||
*al_val = al_pos;
|
||||
if (!type || var1 || type == al_pos->type)
|
||||
goto compare_names;
|
||||
if (le32_to_cpu(al_pos->type) > le32_to_cpu(type))
|
||||
goto gone_too_far;
|
||||
al_pos = al_next_pos;
|
||||
goto do_next;
|
||||
already_have_the_base_and_is_first:
|
||||
ctx->is_first = FALSE;
|
||||
if (*al_val < ctx->alist_val_end)
|
||||
goto do_next;
|
||||
if (ctx->base) {
|
||||
// FIXME: CcUnpinData(ctx->base);
|
||||
ctx->base = NULL;
|
||||
}
|
||||
if (!type)
|
||||
return FALSE;
|
||||
if (ntfs_file_record_read(vol, mref, &ctx->mrec, &ctx->attr) < 0)
|
||||
return FALSE;
|
||||
ctx->base = ctx->mrec;
|
||||
attr_find(vol, type, name, name_len, ic, val, val_len, ctx);
|
||||
return FALSE;
|
||||
al_pos_below_alist_val_end:
|
||||
if (al_pos < ctx->alist_val)
|
||||
goto file_corrupt;
|
||||
if (al_pos >= ctx->alist_val_end)
|
||||
goto file_corrupt;
|
||||
if (!al_pos->length)
|
||||
goto file_corrupt;
|
||||
al_next_pos = (ATTR_LIST_ENTRY*)((char*)al_pos +
|
||||
le16_to_cpu(al_pos->length));
|
||||
goto do_next_2;
|
||||
gone_too_far:
|
||||
var1 = 1;
|
||||
compare_names:
|
||||
al_name_len = al_pos->name_length;
|
||||
al_name = (wchar_t*)((char*)al_pos + al_pos->name_offset);
|
||||
if (!name || var1)
|
||||
goto compare_lowest_vcn;
|
||||
if (ic == CASE_SENSITIVE) {
|
||||
if (name_len == al_name_len &&
|
||||
!memcmp(al_name, name, al_name_len << 1))
|
||||
rc = TRUE;
|
||||
else
|
||||
rc = FALSE;
|
||||
} else /* IGNORE_CASE */
|
||||
rc = ntfs_names_are_equal(al_name, al_name_len, name, name_len,
|
||||
ic, vol->upcase, vol->upcase_len);
|
||||
if (rc)
|
||||
goto compare_lowest_vcn;
|
||||
rc = ntfs_names_collate(vol->upcase, vol->upcase_len, name, name_len,
|
||||
al_name, al_name_len, IGNORE_CASE, 1);
|
||||
if (rc == -1)
|
||||
goto name_collates_before_al_name;
|
||||
if (!rc && ntfs_names_collate(vol->upcase, vol->upcase_len, name,
|
||||
name_len, al_name, al_name_len,
|
||||
IGNORE_CASE, 0) == -1)
|
||||
goto name_collates_before_al_name;
|
||||
al_pos = al_next_pos;
|
||||
goto do_next;
|
||||
name_collates_before_al_name:
|
||||
var1 = 1;
|
||||
compare_lowest_vcn:
|
||||
if (lowest_vcn && !var1 && al_next_pos < ctx->alist_val_end &&
|
||||
sle64_to_cpu(al_next_pos->lowest_vcn) <= sle64_to_cpu(lowest_vcn) &&
|
||||
al_next_pos->type == al_pos->type &&
|
||||
al_next_pos->name_length == al_name_len &&
|
||||
!memcmp((char*)al_next_pos + al_next_pos->name_offset, al_name,
|
||||
al_name_len << 1)) {
|
||||
al_pos = al_next_pos;
|
||||
goto do_next;
|
||||
}
|
||||
/* Don't mask the sequence number. If it isn't equal, the ref is stale.
|
||||
*/
|
||||
if (al_val_start &&
|
||||
al_pos->mft_reference == al_val_start->mft_reference) {
|
||||
mrec = ctx->mrec;
|
||||
attr_pos = (ATTR_RECORD*)((char*)mrec +
|
||||
le16_to_cpu(mrec->attrs_offset));
|
||||
} else {
|
||||
if (ctx->base) {
|
||||
// FIXME: CcUnpinData(ctx->base);
|
||||
ctx->base = 0;
|
||||
}
|
||||
if (ntfs_file_record_read(vol,
|
||||
le64_to_cpu(al_pos->mft_reference),
|
||||
&m, &attr_pos) < 0)
|
||||
return FALSE;
|
||||
mrec = ctx->mrec;
|
||||
ctx->base = ctx->mrec = m;
|
||||
}
|
||||
var3 = 0;
|
||||
do_next_attr_loop_start:
|
||||
if (attr_pos < mrec || attr_pos > (char*)mrec + vol->mft_record_size)
|
||||
goto file_corrupt;
|
||||
if (attr_pos->type == AT_END)
|
||||
goto do_next_al_entry;
|
||||
if (!attr_pos->length)
|
||||
goto file_corrupt;
|
||||
if (al_pos->instance != attr_pos->instance)
|
||||
goto do_next_attr;
|
||||
if (al_pos->type != attr_pos->type)
|
||||
goto do_next_al_entry;
|
||||
if (!name)
|
||||
goto skip_name_comparison;
|
||||
if (attr_pos->name_length != al_name_len)
|
||||
goto do_next_al_entry;
|
||||
if (memcmp((wchar_t*)((char*)attr_pos +
|
||||
le16_to_cpu(attr_pos->name_offset)), al_name,
|
||||
attr_pos->name_length << 1))
|
||||
goto do_next_al_entry;
|
||||
skip_name_comparison:
|
||||
var3 = 1;
|
||||
ctx->attr = attr_pos;
|
||||
if (var1)
|
||||
goto loc_5217c;
|
||||
if (!val)
|
||||
return TRUE;
|
||||
if (attr_pos->non_resident)
|
||||
goto do_next_attr;
|
||||
if (le32_to_cpu(attr_pos->value_length) != val_len)
|
||||
goto do_next_attr;
|
||||
if (!memcmp((char*)attr_pos + le16_to_cpu(attr_pos->value_offset),
|
||||
val, val_len))
|
||||
return TRUE;
|
||||
do_next_attr:
|
||||
attr_pos = (ATTR_RECORD*)((char*)attr_pos +
|
||||
le32_to_cpu(attr_pos->length));
|
||||
goto do_next_attr_loop_start;
|
||||
do_next_al_entry:
|
||||
if (!var3)
|
||||
goto file_corrupt;
|
||||
al_pos = (ATTR_RECORD*)((char*)al_pos + le16_to_cpu(al_pos->length));
|
||||
goto do_next;
|
||||
loc_5217c:
|
||||
if (var2)
|
||||
*al_val = (ATTR_RECORD*)((char*)al_pos +
|
||||
le16_to_cpu(al_pos->length));
|
||||
if (ctx->base) {
|
||||
// FIXME: CcUnpinData(ctx->base);
|
||||
ctx->base = 0;
|
||||
}
|
||||
if (!type)
|
||||
return FALSE;
|
||||
if (ntfs_file_record_read(vol, mref, &mrec, &ctx->attr) < 0)
|
||||
return FALSE;
|
||||
ctx->base = mrec;
|
||||
attr_find(vol, type, name, name_len, ic, val, val_len, ctx);
|
||||
return FALSE;
|
||||
file_corrupt:
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "lookup_attr() encountered corrupt file record.\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL attr_lookup(const ntfs_volume *vol, const MFT_REFERENCE *mref,
|
||||
const ATTR_TYPES type, const wchar_t *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const s64 lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
MFT_RECORD *m;
|
||||
ATTR_RECORD *a;
|
||||
s64 len;
|
||||
|
||||
if (!vol || !ctx) {
|
||||
#ifdef DEBUG
|
||||
printf(stderr, "lookup_attr() received NULL pointer!\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
if (ctx->base)
|
||||
goto already_have_the_base;
|
||||
if (ntfs_file_record_read(vol, mref, &m, &a) < 0)
|
||||
return FALSE;
|
||||
ctx->base = ctx->mrec = m;
|
||||
ctx->attr = a;
|
||||
ctx->alist_mrec = ctx->alist_attr = ctx->alist_val = NULL;
|
||||
/*
|
||||
* Look for an attribute list and at the same time check for attributes
|
||||
* which collate before the attribute list (i.e. $STANDARD_INFORMATION).
|
||||
*/
|
||||
if (le32_to_cpu(a->type) > le32_to_cpu(AT_ATTRIBUTE_LIST))
|
||||
goto no_attr_list;
|
||||
do_next:
|
||||
if (!a->length)
|
||||
goto file_corrupt;
|
||||
if (a->type == AT_ATTRIBUTE_LIST)
|
||||
goto attr_list_present;
|
||||
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
|
||||
if (a < m || a > (char*)m + vol->mft_record_size)
|
||||
goto file_corrupt;
|
||||
if (le32_to_cpu(a->type) <= le32_to_cpu(AT_ATTRIBUTE_LIST))
|
||||
goto do_next;
|
||||
no_attr_list:
|
||||
if (!type || type == AT_STANDARD_INFORMATION &&
|
||||
a->type == AT_STANDARD_INFORMATION)
|
||||
goto found_it;
|
||||
call_find_attr:
|
||||
return attr_find(vol, type, name, name_len, ic, val, val_len, ctx);
|
||||
found_it:
|
||||
ctx->attr = a;
|
||||
return TRUE;
|
||||
already_have_the_base:
|
||||
/*
|
||||
* If ctx->is_first, search starting with ctx->attr. Otherwise
|
||||
* continue search after ctx->attr.
|
||||
*/
|
||||
if (ctx->is_first) {
|
||||
a = ctx->attr;
|
||||
ctx->is_first = 0;
|
||||
} else
|
||||
a = (ATTR_RECORD*)((char*)ctx->attr +
|
||||
le32_to_cpu(ctx->attr->length));
|
||||
if (a < m || a > (char*)m + vol->mft_record_size)
|
||||
goto file_corrupt;
|
||||
if (a->type == AT_END)
|
||||
return FALSE;
|
||||
if (!a->length)
|
||||
goto file_corrupt;
|
||||
if (type)
|
||||
goto call_find_attr;
|
||||
goto found_it;
|
||||
attr_list_present:
|
||||
/*
|
||||
* Looking for zero means we return the first attribute, which will
|
||||
* be the first one listed in the attribute list.
|
||||
*/
|
||||
ctx->attr = a;
|
||||
if (!type)
|
||||
goto search_attr_list;
|
||||
if (type == AT_ATTRIBUTE_LIST)
|
||||
return TRUE;
|
||||
search_attr_list:
|
||||
/*
|
||||
* "a" contains the attribute list attribute at this stage.
|
||||
*/
|
||||
ctx->alist_attr = a;
|
||||
len = ntfs_get_attribute_value_length(a);
|
||||
#ifdef DEBUG
|
||||
if (len > 0x40000LL) {
|
||||
printf(stderr, "lookup_attr() found corrupt attribute list.\n");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
ctx->alist_val_len = len;
|
||||
if (!(ctx->alist_val = malloc(ctx->alist_val_len))) {
|
||||
#ifdef DEBUG
|
||||
printf(stderr, "lookup_attr() failed to allocate memory for "
|
||||
"attribute list value.\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
if (ntfs_get_attribute_value(vol, ctx->mrec, a, ctx->alist_val) !=
|
||||
ctx->alist_val_len) {
|
||||
#ifdef DEBUG
|
||||
printf(stderr, "lookup_attr() failed to read attribute list "
|
||||
"value.\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
ctx->alist_val_end = (char*)ctx->alist_val + ctx->alist_val_len;
|
||||
if (a->non_resident) {
|
||||
ctx->alist_old_base = ctx->alist_val_base;
|
||||
ctx->alist_val_base = ctx->base;
|
||||
ctx->base = NULL;
|
||||
} else if (ctx->base) {
|
||||
// FIXME: CcUnpinData(ctx->base);
|
||||
ctx->base = NULL;
|
||||
}
|
||||
lookup_external:
|
||||
return external_attr_lookup(vol, mref, type, name, name_len, ic,
|
||||
lowest_vcn, val, val_len, ctx);
|
||||
file_corrupt:
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "attr_lookup() encountered corrupt file record.\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
/**
|
||||
* attrlist.c - Attribute list attribute handling code. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-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
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
MFT_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->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) ? le64_to_cpu(attr->lowest_vcn) :
|
||||
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
||||
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||
0 : le32_to_cpu(attr->value_length), ctx)) {
|
||||
/* Found some extent, check it to be before new extent. */
|
||||
if (ctx->al_entry->lowest_vcn == attr->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);
|
||||
/* Zero it to fix valgrind warning. */
|
||||
memset(ale, 0, entry_len);
|
||||
/* 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->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
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) le64_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;
|
||||
}
|
||||
674
libntfs/bitmap.c
674
libntfs/bitmap.c
|
|
@ -1,674 +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 "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 __inline__ int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value)
|
||||
{
|
||||
s64 bufsize, br;
|
||||
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;
|
||||
|
||||
/* Allocate memory. */
|
||||
buf = (u8*)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) && count--) {
|
||||
if (value)
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~(1 << bit++);
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
start_bit = (start_bit + 7) & ~7;
|
||||
}
|
||||
|
||||
/* Loop until @count reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! 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 + count) >>
|
||||
3, 1, lastbyte_buf);
|
||||
if (br != 1) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! 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 && count--) {
|
||||
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("Eeek! 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;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! Last buffer but count is not zero (= "
|
||||
"%lli). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "rich.h"
|
||||
|
||||
/**
|
||||
* ntfs_bmp_rollback - Discard the in-memory bitmap changes
|
||||
* @bmp:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ntfs_bmp_rollback(struct ntfs_bmp *bmp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((!bmp) || (bmp->count == 0))
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type);
|
||||
|
||||
for (i = 0; i < bmp->count; i++)
|
||||
free(bmp->data[i]);
|
||||
|
||||
free(bmp->data);
|
||||
free(bmp->data_vcn);
|
||||
bmp->data = NULL;
|
||||
bmp->data_vcn = NULL;
|
||||
bmp->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_commit - Write the cached bitmap data to disk
|
||||
* @bmp:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ntfs_bmp_commit(struct ntfs_bmp *bmp)
|
||||
{
|
||||
int i;
|
||||
u32 cs;
|
||||
u32 ws; // write size
|
||||
|
||||
if (!bmp)
|
||||
return 0;
|
||||
if (bmp->count == 0)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type);
|
||||
#if 0
|
||||
ntfs_log_debug("attr = 0x%02X\n", bmp->attr->type);
|
||||
ntfs_log_debug("resident = %d\n", !NAttrNonResident(bmp->attr));
|
||||
ntfs_log_debug("\ta size = %lld\n", bmp->attr->allocated_size);
|
||||
ntfs_log_debug("\td size = %lld\n", bmp->attr->data_size);
|
||||
ntfs_log_debug("\ti size = %lld\n", bmp->attr->initialized_size);
|
||||
#endif
|
||||
|
||||
ntfs_log_debug("commit bmp inode %lld, 0x%02X (%sresident)\n", bmp->attr->ni->mft_no, bmp->attr->type, NAttrNonResident(bmp->attr) ? "non-" : "");
|
||||
|
||||
if (NAttrNonResident(bmp->attr)) {
|
||||
cs = bmp->vol->cluster_size;
|
||||
|
||||
// non-resident
|
||||
for (i = 0; i < bmp->count; i++) {
|
||||
if (((bmp->data_vcn[i]+1) * cs) < bmp->attr->data_size)
|
||||
ws = cs;
|
||||
else
|
||||
ws = bmp->attr->data_size & (cs - 1);
|
||||
//ntfs_log_debug("writing %d bytes\n", ws);
|
||||
ntfs_attr_pwrite(bmp->attr, bmp->data_vcn[i] * cs, ws, bmp->data[i]); // XXX retval
|
||||
ntfs_log_warning("\tntfs_attr_pwrite(vcn %lld)\n", bmp->data_vcn[i]);
|
||||
}
|
||||
} else {
|
||||
// resident
|
||||
ntfs_attr_pwrite(bmp->attr, bmp->data_vcn[0], bmp->attr->data_size, bmp->data[0]); // XXX retval
|
||||
ntfs_log_warning("\tntfs_attr_pwrite resident (%lld)\n", bmp->attr->data_size);
|
||||
}
|
||||
|
||||
ntfs_bmp_rollback(bmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_free - Destroy a bitmap object
|
||||
* @bmp:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_bmp_free(struct ntfs_bmp *bmp)
|
||||
{
|
||||
if (!bmp)
|
||||
return;
|
||||
|
||||
ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type);
|
||||
|
||||
ntfs_bmp_rollback(bmp);
|
||||
ntfs_attr_close(bmp->attr);
|
||||
|
||||
free(bmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_create - Create a representation of a bitmap
|
||||
* @inode:
|
||||
* @type:
|
||||
* @name:
|
||||
* @name_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
struct ntfs_bmp * ntfs_bmp_create(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len)
|
||||
{
|
||||
struct ntfs_bmp *bmp;
|
||||
ntfs_attr *attr;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
attr = ntfs_attr_open(inode, type, name, name_len);
|
||||
if (!attr)
|
||||
return NULL;
|
||||
|
||||
bmp = calloc(1, sizeof(*bmp));
|
||||
if (!bmp) {
|
||||
ntfs_attr_close(attr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ntfs_log_critical("bmp = %p, attr = %p, inode = %p, attr->ni->mft_no = %lld\n", bmp, attr, inode, MREF(attr->ni->mft_no));
|
||||
bmp->vol = inode->vol;
|
||||
bmp->attr = attr;
|
||||
bmp->data = NULL;
|
||||
bmp->data_vcn = NULL;
|
||||
bmp->count = 0;
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_add_data - Add a bitmap block to the current cache
|
||||
* @bmp:
|
||||
* @vcn:
|
||||
* @data:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ntfs_bmp_add_data(struct ntfs_bmp *bmp, VCN vcn, u8 *data)
|
||||
{
|
||||
int i = 0;
|
||||
int old;
|
||||
int new;
|
||||
|
||||
if (!bmp || !data)
|
||||
return -1;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
old = ROUND_UP(bmp->count, 16);
|
||||
bmp->count++;
|
||||
new = ROUND_UP(bmp->count, 16);
|
||||
|
||||
if (old != new) {
|
||||
bmp->data = realloc(bmp->data, new * sizeof(*bmp->data));
|
||||
bmp->data_vcn = realloc(bmp->data_vcn , new * sizeof(*bmp->data_vcn));
|
||||
}
|
||||
|
||||
for (i = 0; i < bmp->count-1; i++)
|
||||
if (bmp->data_vcn[i] > vcn)
|
||||
break;
|
||||
|
||||
if ((bmp->count-i) > 0) {
|
||||
memmove(&bmp->data[i+1], &bmp->data[i], (bmp->count-i) * sizeof(*bmp->data));
|
||||
memmove(&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof(*bmp->data_vcn));
|
||||
}
|
||||
|
||||
bmp->data[i] = data;
|
||||
bmp->data_vcn[i] = vcn;
|
||||
|
||||
return bmp->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_get_data - Ask for a bitmap block from the cache
|
||||
* @bmp:
|
||||
* @vcn:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
u8 * ntfs_bmp_get_data(struct ntfs_bmp *bmp, VCN vcn)
|
||||
{
|
||||
u8 *buffer;
|
||||
int i;
|
||||
int cs;
|
||||
int cb;
|
||||
|
||||
if (!bmp)
|
||||
return NULL;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
cs = bmp->vol->cluster_size;
|
||||
cb = bmp->vol->cluster_size_bits;
|
||||
|
||||
// XXX range check against vol,attr
|
||||
// never compressed, so data = init
|
||||
|
||||
vcn >>= (cb + 3); // convert to bitmap clusters
|
||||
|
||||
for (i = 0; i < bmp->count; i++) {
|
||||
if (vcn == bmp->data_vcn[i]) {
|
||||
//ntfs_log_debug("reusing bitmap cluster %lld\n", vcn);
|
||||
return bmp->data[i];
|
||||
}
|
||||
}
|
||||
|
||||
buffer = calloc(1, cs); // XXX could be smaller if attr size < cluster size
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
//ntfs_log_debug("loading from bitmap cluster %lld\n", vcn);
|
||||
//ntfs_log_debug("loading from bitmap byte %lld\n", vcn<<cb);
|
||||
if (ntfs_attr_pread(bmp->attr, vcn<<cb, cs, buffer) < 0) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ntfs_bmp_add_data(bmp, vcn, buffer); // XXX retval
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_set_range - Set a range of bits in the bitmap
|
||||
* @bmp:
|
||||
* @vcn:
|
||||
* @length:
|
||||
* @value:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ntfs_bmp_set_range(struct ntfs_bmp *bmp, VCN vcn, s64 length, int value)
|
||||
{
|
||||
// shouldn't all the vcns be lcns?
|
||||
s64 i;
|
||||
u8 *buffer;
|
||||
int csib; // cluster size in bits
|
||||
|
||||
int block_start, block_finish; // rename to c[sf] (rename to clust_)
|
||||
int vcn_start, vcn_finish; // rename to v[sf]
|
||||
int byte_start, byte_finish; // rename to b[sf]
|
||||
u8 mask_start, mask_finish; // rename to m[sf]
|
||||
|
||||
s64 a,b;
|
||||
|
||||
if (!bmp)
|
||||
return -1;
|
||||
|
||||
ntfs_log_trace ("vcn %lld, length %lld, value %d\n", vcn, length, value);
|
||||
if (value)
|
||||
value = 0xFF;
|
||||
|
||||
csib = bmp->vol->cluster_size << 3;
|
||||
|
||||
vcn_start = vcn;
|
||||
vcn_finish = vcn + length - 1;
|
||||
|
||||
//ntfs_log_debug("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish);
|
||||
a = ROUND_DOWN(vcn_start, csib);
|
||||
b = ROUND_DOWN(vcn_finish, csib) + 1;
|
||||
|
||||
//ntfs_log_debug("a = %lld, b = %lld\n", a, b);
|
||||
|
||||
for (i = a; i < b; i += csib) {
|
||||
//ntfs_log_debug("ntfs_bmp_get_data %lld\n", i);
|
||||
buffer = ntfs_bmp_get_data(bmp, i);
|
||||
if (!buffer)
|
||||
return -1;
|
||||
|
||||
block_start = i;
|
||||
block_finish = block_start + csib - 1;
|
||||
|
||||
mask_start = (0xFF << (vcn_start & 7));
|
||||
mask_finish = (0xFF >> (7 - (vcn_finish & 7)));
|
||||
|
||||
if ((vcn_start >= block_start) && (vcn_start <= block_finish)) {
|
||||
byte_start = (vcn_start - block_start) >> 3;
|
||||
} else {
|
||||
byte_start = 0;
|
||||
mask_start = 0xFF;
|
||||
}
|
||||
|
||||
if ((vcn_finish >= block_start) && (vcn_finish <= block_finish)) {
|
||||
byte_finish = (vcn_finish - block_start) >> 3;
|
||||
} else {
|
||||
byte_finish = bmp->vol->cluster_size - 1;
|
||||
mask_finish = 0xFF;
|
||||
}
|
||||
|
||||
if ((byte_finish - byte_start) > 1) {
|
||||
memset(buffer+byte_start+1, value, byte_finish-byte_start-1);
|
||||
} else if (byte_finish == byte_start) {
|
||||
mask_start &= mask_finish;
|
||||
mask_finish = 0x00;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
buffer[byte_start] |= mask_start;
|
||||
buffer[byte_finish] |= mask_finish;
|
||||
} else {
|
||||
buffer[byte_start] &= (~mask_start);
|
||||
buffer[byte_finish] &= (~mask_finish);
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
ntfs_log_debug("Modified: inode %lld, ", bmp->attr->ni->mft_no);
|
||||
switch (bmp->attr->type) {
|
||||
case AT_BITMAP: ntfs_log_debug("$BITMAP"); break;
|
||||
case AT_DATA: ntfs_log_debug("$DATA"); break;
|
||||
default: break;
|
||||
}
|
||||
ntfs_log_debug(" vcn %lld-%lld\n", vcn>>12, (vcn+length-1)>>12);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_find_last_set - Find the last set bit in the bitmap
|
||||
* @bmp:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
s64 ntfs_bmp_find_last_set(struct ntfs_bmp *bmp)
|
||||
{
|
||||
s64 clust_count;
|
||||
s64 byte_count;
|
||||
s64 clust;
|
||||
int byte;
|
||||
int bit;
|
||||
int note;
|
||||
u8 *buffer;
|
||||
|
||||
if (!bmp)
|
||||
return -2;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
// find byte size of bmp
|
||||
// find cluster size of bmp
|
||||
|
||||
byte_count = bmp->attr->data_size;
|
||||
clust_count = ROUND_UP(byte_count, bmp->vol->cluster_size) >> bmp->vol->cluster_size_bits;
|
||||
|
||||
//ntfs_log_debug("bitmap = %lld bytes\n", byte_count);
|
||||
//ntfs_log_debug("bitmap = %lld buffers\n", clust_count);
|
||||
|
||||
// for each cluster backwards
|
||||
for (clust = clust_count-1; clust >= 0; clust--) {
|
||||
//ntfs_log_debug("cluster %lld\n", clust);
|
||||
//ntfs_log_debug("get vcn %lld\n", clust << (bmp->vol->cluster_size_bits + 3));
|
||||
buffer = ntfs_bmp_get_data(bmp, clust << (bmp->vol->cluster_size_bits + 3));
|
||||
//utils_dump_mem(buffer, 0, 8, DM_NO_ASCII);
|
||||
if (!buffer)
|
||||
return -2;
|
||||
if ((clust == (clust_count-1) && ((byte_count % bmp->vol->cluster_size) != 0))) {
|
||||
byte = byte_count % bmp->vol->cluster_size;
|
||||
} else {
|
||||
byte = bmp->vol->cluster_size;
|
||||
}
|
||||
//ntfs_log_debug("start byte = %d\n", byte);
|
||||
// for each byte backward
|
||||
for (byte--; byte >= 0; byte--) {
|
||||
//ntfs_log_debug("\tbyte %d (%d)\n", byte, buffer[byte]);
|
||||
// for each bit shift up
|
||||
note = -1;
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
//ntfs_log_debug("\t\tbit %d (%d)\n", (1<<bit), buffer[byte] & (1<<bit));
|
||||
if (buffer[byte] & (1<<bit)) {
|
||||
// if set, keep note
|
||||
note = bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (note >= 0) {
|
||||
// if note, return value
|
||||
//ntfs_log_debug("match %lld (c=%lld,b=%d,n=%d)\n", (((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note, clust, byte, note);
|
||||
return ((((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bmp_find_space - Find an unused block of bits in a bitmap
|
||||
* @bmp:
|
||||
* @start:
|
||||
* @size:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ntfs_bmp_find_space(struct ntfs_bmp *bmp, LCN start, long size)
|
||||
{
|
||||
if (!bmp)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
start = 0;
|
||||
size = 0;
|
||||
|
||||
/*
|
||||
bmp find space - uncached bmp's
|
||||
$Bitmap/$DATA free space on volume
|
||||
dir/$BITMAP free index record
|
||||
$MFT/$BITMAP free record in mft
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
|
|
@ -1,272 +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");
|
||||
|
||||
/* Calculate the checksum. Note, this is just a simple addition of
|
||||
all u32 values in the bootsector starting at the beginning and
|
||||
finishing at the offset of the checksum itself (i.e. not including
|
||||
the checksum...). */
|
||||
if ((void*)b < (void*)&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)
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
}
|
||||
|
||||
/* Check OEMidentifier is "NTFS " */
|
||||
ntfs_log_debug("Checking OEMid... ");
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) /* "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->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->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->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->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);
|
||||
/*
|
||||
* Work out the size of the MFT mirror in number of mft records. If the
|
||||
* cluster size is less than or equal to the size taken by four mft
|
||||
* records, the mft mirror stores the first four mft records. If the
|
||||
* cluster size is bigger than the size taken by four mft records, the
|
||||
* mft mirror contains as many mft records as will fit into one
|
||||
* cluster.
|
||||
*/
|
||||
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,201 +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 "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, const int data1_len,
|
||||
const void *data2, const int 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, const int data1_len,
|
||||
const void *data2, const int 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, const int data1_len __attribute__((unused)),
|
||||
const void *data2, const int 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 *, const int,
|
||||
const void *, const int);
|
||||
|
||||
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_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, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (!vol || !data1 || !data2 || data1_len < 0 || data2_len < 0) {
|
||||
ntfs_log_error("Invalid arguments passed.\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
/*
|
||||
* FIXME: At the moment we only support COLLATION_BINARY,
|
||||
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return error
|
||||
* for everything else.
|
||||
*/
|
||||
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG &&
|
||||
cr != COLLATION_FILE_NAME)
|
||||
goto err;
|
||||
i = le32_to_cpu(cr);
|
||||
if (i < 0)
|
||||
goto err;
|
||||
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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -1,550 +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 "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 __inline__ 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 = malloc(cb_size);
|
||||
if (!cb)
|
||||
return -1;
|
||||
/* Need a temporary buffer for each uncompressed block. */
|
||||
dest = 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;
|
||||
}
|
||||
|
|
@ -1,72 +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 "types.h"
|
||||
#include "runlist.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
|
||||
#ifndef NTFS_DISABLE_DEBUG_LOGGING
|
||||
/**
|
||||
* 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
|
||||
|
||||
727
libntfs/device.c
727
libntfs/device.c
|
|
@ -1,727 +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 "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 *)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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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;
|
||||
/* Locate to position. */
|
||||
if (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 = dops->read(dev, (char*)b + total, count);
|
||||
/* If everything ok, continue. */
|
||||
if (br > 0)
|
||||
continue;
|
||||
/* If EOF or error return number of bytes read. */
|
||||
if (!br || total)
|
||||
return total;
|
||||
/* Nothing read and error, return error status. */
|
||||
return br;
|
||||
}
|
||||
/* Finally, return the number of bytes read. */
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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;
|
||||
/* Locate to position. */
|
||||
if (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 = dops->write(dev, (const char*)b + total, count);
|
||||
/* If everything ok, continue. */
|
||||
if (written > 0)
|
||||
continue;
|
||||
/*
|
||||
* If nothing written or error return number of bytes written.
|
||||
*/
|
||||
if (!written || total)
|
||||
break;
|
||||
/* 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->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->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 inline 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, §_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;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* device_io.c - Default device io operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2003 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
|
||||
|
||||
#ifndef __CYGWIN32__
|
||||
|
||||
/* Not on Cygwin; use standard Unix style low level device operations. */
|
||||
#include "unix_io.c"
|
||||
|
||||
#else /* __CYGWIN32__ */
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
#include "win32_io.c"
|
||||
|
||||
#endif /* __CYGWIN32__ */
|
||||
|
||||
#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */
|
||||
2125
libntfs/dir.c
2125
libntfs/dir.c
File diff suppressed because it is too large
Load Diff
982
libntfs/index.c
982
libntfs/index.c
|
|
@ -1,982 +0,0 @@
|
|||
/**
|
||||
* index.c - NTFS index handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2005 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 "attrib.h"
|
||||
#include "collate.h"
|
||||
#include "debug.h"
|
||||
#include "index.h"
|
||||
#include "mst.h"
|
||||
#include "dir.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* 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 *ictx;
|
||||
|
||||
if (!ni) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (ni->nr_extents == -1)
|
||||
ni = ni->base_ni;
|
||||
ictx = malloc(sizeof(ntfs_index_context));
|
||||
if (ictx)
|
||||
*ictx = (ntfs_index_context) {
|
||||
.ni = ni,
|
||||
.name = name,
|
||||
.name_len = name_len,
|
||||
};
|
||||
return ictx;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_index_ctx_put - release an index context
|
||||
* @ictx: index context to free
|
||||
*
|
||||
* Release the index context @ictx, releasing all associated resources.
|
||||
*/
|
||||
void ntfs_index_ctx_put(ntfs_index_context *ictx)
|
||||
{
|
||||
if (ictx->entry) {
|
||||
if (ictx->is_in_root) {
|
||||
if (ictx->actx)
|
||||
ntfs_attr_put_search_ctx(ictx->actx);
|
||||
} else {
|
||||
/* Write out index block it it's dirty. */
|
||||
if (ictx->ia_dirty) {
|
||||
if (ntfs_attr_mst_pwrite(ictx->ia_na,
|
||||
ictx->ia_vcn <<
|
||||
ictx->vcn_size_bits,
|
||||
1, ictx->block_size,
|
||||
ictx->ia) != 1)
|
||||
ntfs_log_error("Failed to write out "
|
||||
"index block.\n");
|
||||
}
|
||||
/* Free resources. */
|
||||
free(ictx->ia);
|
||||
ntfs_attr_close(ictx->ia_na);
|
||||
}
|
||||
}
|
||||
free(ictx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_index_ctx_reinit - reinitialize an index context
|
||||
* @ictx: index context to reinitialize
|
||||
*
|
||||
* Reinitialize the index context @ictx so it can be used for ntfs_index_lookup.
|
||||
*/
|
||||
void ntfs_index_ctx_reinit(ntfs_index_context *ictx)
|
||||
{
|
||||
if (ictx->entry) {
|
||||
if (ictx->is_in_root) {
|
||||
if (ictx->actx)
|
||||
ntfs_attr_put_search_ctx(ictx->actx);
|
||||
} else {
|
||||
/* Write out index block it it's dirty. */
|
||||
if (ictx->ia_dirty) {
|
||||
if (ntfs_attr_mst_pwrite(ictx->ia_na,
|
||||
ictx->ia_vcn <<
|
||||
ictx->vcn_size_bits,
|
||||
1, ictx->block_size,
|
||||
ictx->ia) != 1)
|
||||
ntfs_log_error("Failed to write out "
|
||||
"index block.\n");
|
||||
}
|
||||
/* Free resources. */
|
||||
free(ictx->ia);
|
||||
ntfs_attr_close(ictx->ia_na);
|
||||
}
|
||||
}
|
||||
*ictx = (ntfs_index_context) {
|
||||
.ni = ictx->ni,
|
||||
.name = ictx->name,
|
||||
.name_len = ictx->name_len,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @ictx: [IN/OUT] context describing the index and the returned entry
|
||||
*
|
||||
* Before calling ntfs_index_lookup(), @ictx 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 @ictx.
|
||||
* 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 @ictx is setup to
|
||||
* describe the index entry containing the matching @key. @ictx->entry is the
|
||||
* index entry and @ictx->data and @ictx->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
|
||||
* @ictx 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 @ictx 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 *ictx)
|
||||
{
|
||||
COLLATION_RULES cr;
|
||||
VCN vcn;
|
||||
ntfs_inode *ni = ictx->ni;
|
||||
ntfs_volume *vol = ni->vol;
|
||||
INDEX_ROOT *ir;
|
||||
INDEX_ENTRY *ie;
|
||||
INDEX_ALLOCATION *ia = NULL;
|
||||
u8 *index_end;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
ntfs_attr *na = NULL;
|
||||
int rc, err = 0;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (!key || key_len <= 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
actx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!actx) {
|
||||
err = ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Find the index root attribute in the mft record. */
|
||||
err = ntfs_attr_lookup(AT_INDEX_ROOT, ictx->name, ictx->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, actx);
|
||||
if (err) {
|
||||
if (errno == ENOENT) {
|
||||
ntfs_log_error("Index root attribute missing in inode "
|
||||
"0x%llx.\n", ni->mft_no);
|
||||
err = EIO;
|
||||
} else
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
/* Get to the index root value (it has been verified in read_inode). */
|
||||
ir = (INDEX_ROOT*)((u8*)actx->attr +
|
||||
le16_to_cpu(actx->attr->value_offset));
|
||||
index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
|
||||
/* Save index block size for future use. */
|
||||
ictx->block_size = le32_to_cpu(ir->index_block_size);
|
||||
/* Determine the size of a vcn in the directory index. */
|
||||
if (vol->cluster_size <= ictx->block_size) {
|
||||
ictx->vcn_size = vol->cluster_size;
|
||||
ictx->vcn_size_bits = vol->cluster_size_bits;
|
||||
} else {
|
||||
ictx->vcn_size = vol->sector_size;
|
||||
ictx->vcn_size_bits = vol->sector_size_bits;
|
||||
}
|
||||
/* Get collation rule type and validate it. */
|
||||
cr = ir->collation_rule;
|
||||
if (!ntfs_is_collation_rule_supported(cr)) {
|
||||
ntfs_log_error("Index uses unsupported collation rule 0x%x. "
|
||||
"Aborting lookup.\n", (unsigned)le32_to_cpu(cr));
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
/* 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*)actx->mrec || (u8*)ie +
|
||||
sizeof(INDEX_ENTRY_HEADER) > index_end ||
|
||||
(u8*)ie + le16_to_cpu(ie->length) > index_end)
|
||||
goto idx_err_out;
|
||||
/*
|
||||
* 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 (ie->flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
/* If the keys match perfectly, we setup @ictx and return 0. */
|
||||
if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
|
||||
&ie->key, key_len)) {
|
||||
ir_done:
|
||||
ictx->is_in_root = TRUE;
|
||||
ictx->actx = actx;
|
||||
ictx->ia = NULL;
|
||||
ictx->ir = ir;
|
||||
done:
|
||||
ictx->entry = ie;
|
||||
ictx->data = (u8*)ie + offsetof(INDEX_ENTRY, key);
|
||||
ictx->data_len = le16_to_cpu(ie->key_length);
|
||||
ntfs_log_trace("Done.\n");
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* 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(vol, cr, key, key_len, &ie->key,
|
||||
le16_to_cpu(ie->key_length));
|
||||
if (rc == NTFS_COLLATION_ERROR) {
|
||||
ntfs_log_error("Collation error. Probably filename "
|
||||
"contain invalid characters.\n");
|
||||
err = ERANGE;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* A match should never happen as the memcmp() call should have
|
||||
* caught it, but we still treat it correctly.
|
||||
*/
|
||||
if (!rc)
|
||||
goto ir_done;
|
||||
/* The keys are not equal, continue the search. */
|
||||
}
|
||||
/*
|
||||
* We have finished with this index without success. Check for the
|
||||
* presence of a child node and if not present setup @ictx and return
|
||||
* -1 with errno ENOENT.
|
||||
*/
|
||||
if (!(ie->flags & INDEX_ENTRY_NODE)) {
|
||||
ntfs_log_debug("Entry not found.\n");
|
||||
err = ENOENT;
|
||||
goto ir_done;
|
||||
} /* Child node present, descend into it. */
|
||||
/* Get the starting vcn of the index_block holding the child node. */
|
||||
vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
|
||||
/* We are done with the index root. Release attribute search ctx. */
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
actx = NULL;
|
||||
/* Open INDEX_ALLOCATION. */
|
||||
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION,
|
||||
ictx->name, ictx->name_len);
|
||||
if (!na) {
|
||||
ntfs_log_error("No index allocation attribute but index entry "
|
||||
"requires one. Inode 0x%llx is corrupt or "
|
||||
"library bug.\n", ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
/* Allocate memory to store index block. */
|
||||
ia = malloc(ictx->block_size);
|
||||
if (!ia) {
|
||||
ntfs_log_error("Not enough memory to allocate buffer for index"
|
||||
" allocation.\n");
|
||||
err = ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
descend_into_child_node:
|
||||
ntfs_log_debug("Descend into node with VCN %lld.\n", vcn);
|
||||
/* Read index allocation block. */
|
||||
if (ntfs_attr_mst_pread(na, vcn << ictx->vcn_size_bits, 1,
|
||||
ictx->block_size, ia) != 1) {
|
||||
ntfs_log_error("Failed to read index allocation.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Catch multi sector transfer fixup errors. */
|
||||
if (!ntfs_is_indx_record(ia->magic)) {
|
||||
ntfs_log_error("Index record with vcn 0x%llx is corrupt. "
|
||||
"Corrupt inode 0x%llx. Run chkdsk.\n",
|
||||
(long long)vcn, ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
|
||||
ntfs_log_error("Actual VCN (0x%llx) of index buffer is "
|
||||
"different from expected VCN (0x%llx). Inode "
|
||||
"0x%llx is corrupt or driver bug.\n",
|
||||
(unsigned long long)
|
||||
sle64_to_cpu(ia->index_block_vcn),
|
||||
(unsigned long long)vcn, ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != ictx->block_size) {
|
||||
ntfs_log_error("Index buffer (VCN 0x%llx) of inode 0x%llx has "
|
||||
"a size (%u) differing from the index "
|
||||
"specified size (%u). Inode is corrupt or "
|
||||
"driver bug.\n", (unsigned long long)vcn,
|
||||
ni->mft_no, (unsigned)
|
||||
le32_to_cpu(ia->index.allocated_size) + 0x18,
|
||||
(unsigned)ictx->block_size);
|
||||
goto err_out;
|
||||
}
|
||||
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
|
||||
if (index_end > (u8*)ia + ictx->block_size) {
|
||||
ntfs_log_error("Size of index buffer (VCN 0x%llx) of inode "
|
||||
"0x%llx exceeds maximum size.\n",
|
||||
(unsigned long long)vcn, ni->mft_no);
|
||||
goto 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 checks. */
|
||||
if ((u8*)ie < (u8*)ia || (u8*)ie +
|
||||
sizeof(INDEX_ENTRY_HEADER) > index_end ||
|
||||
(u8*)ie + le16_to_cpu(ie->length) > index_end) {
|
||||
ntfs_log_error("Index entry out of bounds in inode "
|
||||
"0x%llx.\n", ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* 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 (ie->flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
/* If the keys match perfectly, we setup @ictx and return 0. */
|
||||
if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
|
||||
&ie->key, key_len)) {
|
||||
ia_done:
|
||||
ictx->is_in_root = FALSE;
|
||||
ictx->actx = NULL;
|
||||
ictx->ia = ia;
|
||||
ictx->ia_vcn = vcn;
|
||||
ictx->ia_na = na;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* 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(vol, cr, key, key_len, &ie->key,
|
||||
le16_to_cpu(ie->key_length));
|
||||
if (rc == NTFS_COLLATION_ERROR) {
|
||||
ntfs_log_error("Collation error. Probably filename "
|
||||
"contain invalid characters.\n");
|
||||
err = ERANGE;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* A match should never happen as the memcmp() call should have
|
||||
* caught it, but we still treat it correctly.
|
||||
*/
|
||||
if (!rc)
|
||||
goto ia_done;
|
||||
/* The keys are not equal, continue the search. */
|
||||
}
|
||||
/*
|
||||
* We have finished with this index buffer without success. Check for
|
||||
* the presence of a child node and if not present return ENOENT.
|
||||
*/
|
||||
if (!(ie->flags & INDEX_ENTRY_NODE)) {
|
||||
ntfs_log_debug("Entry not found.\n");
|
||||
err = ENOENT;
|
||||
goto ia_done;
|
||||
}
|
||||
if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
|
||||
ntfs_log_error("Index entry with child node found in a leaf "
|
||||
"node in inode 0x%llx.\n", ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
/* Child node present, descend into it. */
|
||||
vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
|
||||
if (vcn >= 0)
|
||||
goto descend_into_child_node;
|
||||
ntfs_log_error("Negative child node vcn in inode 0x%llx.\n", ni->mft_no);
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(ia);
|
||||
if (!err)
|
||||
err = EIO;
|
||||
if (actx)
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
errno = err;
|
||||
return -1;
|
||||
idx_err_out:
|
||||
ntfs_log_error("Corrupt index. Aborting lookup.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* NOTE: This function does not support all cases, so it can fail with
|
||||
* EOPNOTSUPP error code.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
ntfs_index_context *ictx;
|
||||
INDEX_ENTRY *ie;
|
||||
INDEX_HEADER *ih;
|
||||
int err, fn_size, ie_size, allocated_size = 0;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (!ni || !fn) {
|
||||
ntfs_log_error("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ictx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
|
||||
if (!ictx)
|
||||
return -1;
|
||||
fn_size = (fn->file_name_length * sizeof(ntfschar)) +
|
||||
sizeof(FILE_NAME_ATTR);
|
||||
ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
|
||||
retry:
|
||||
/* Find place where insert new entry. */
|
||||
if (!ntfs_index_lookup(fn, fn_size, ictx)) {
|
||||
err = EEXIST;
|
||||
ntfs_log_error("Index already have such entry.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to find place where to insert new entry.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Some setup. */
|
||||
if (ictx->is_in_root)
|
||||
ih = &ictx->ir->index;
|
||||
else
|
||||
ih = &ictx->ia->index;
|
||||
if (!allocated_size)
|
||||
allocated_size = le16_to_cpu(ih->allocated_size);
|
||||
/* Check whether we have enough space in the index. */
|
||||
if (le16_to_cpu(ih->index_length) + ie_size > allocated_size) {
|
||||
/* If we in the index root try to resize it. */
|
||||
if (ictx->is_in_root) {
|
||||
ntfs_attr *na;
|
||||
|
||||
allocated_size = le16_to_cpu(ih->index_length) +
|
||||
ie_size;
|
||||
na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name,
|
||||
ictx->name_len);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to open INDEX_ROOT.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, allocated_size + offsetof(
|
||||
INDEX_ROOT, index))) {
|
||||
err = EOPNOTSUPP;
|
||||
ntfs_attr_close(na);
|
||||
ntfs_log_debug("Failed to truncate "
|
||||
"INDEX_ROOT.\n");
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
ntfs_index_ctx_reinit(ictx);
|
||||
goto retry;
|
||||
}
|
||||
ntfs_log_debug("Not implemented case.\n");
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
/* Update allocated size if we in INDEX_ROOT. */
|
||||
if (ictx->is_in_root)
|
||||
ih->allocated_size = cpu_to_le16(allocated_size);
|
||||
/* Create entry. */
|
||||
ie = calloc(1, ie_size);
|
||||
if (!ie) {
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
ie->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);
|
||||
/* Update index length, move following entries forard and copy entry. */
|
||||
ih->index_length = cpu_to_le16(le16_to_cpu(ih->index_length) + ie_size);
|
||||
memmove((u8*)ictx->entry + ie_size, ictx->entry,
|
||||
le16_to_cpu(ih->index_length) -
|
||||
((u8*)ictx->entry - (u8*)ih) - ie_size);
|
||||
memcpy(ictx->entry, ie, ie_size);
|
||||
/* Done! */
|
||||
ntfs_index_entry_mark_dirty(ictx);
|
||||
ntfs_index_ctx_put(ictx);
|
||||
free(ie);
|
||||
ntfs_log_trace("Done.\n");
|
||||
return 0;
|
||||
err_out:
|
||||
ntfs_log_trace("Failed.\n");
|
||||
ntfs_index_ctx_put(ictx);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_index_rm - remove entry from the index
|
||||
* @ictx: index context describing entry to delete
|
||||
*
|
||||
* Delete entry described by @ictx from the index. NOTE: This function does not
|
||||
* support all cases, so it can fail with EOPNOTSUPP error code. In any case
|
||||
* 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 *ictx)
|
||||
{
|
||||
INDEX_HEADER *ih;
|
||||
u32 new_index_length;
|
||||
int err;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (!ictx || (!ictx->ia && !ictx->ir) ||
|
||||
ictx->entry->flags & INDEX_ENTRY_END) {
|
||||
ntfs_log_error("Invalid arguments.\n");
|
||||
err = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
if (ictx->is_in_root)
|
||||
ih = &ictx->ir->index;
|
||||
else
|
||||
ih = &ictx->ia->index;
|
||||
/* Don't support deletion of entries with subnodes yet. */
|
||||
if (ictx->entry->flags & INDEX_ENTRY_NODE) {
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
/* Calculate new length of the index. */
|
||||
new_index_length = le32_to_cpu(ih->index_length) -
|
||||
le16_to_cpu(ictx->entry->length);
|
||||
/* Don't support deletion of the last entry in the allocation block. */
|
||||
if (!ictx->is_in_root && (new_index_length <=
|
||||
le32_to_cpu(ih->entries_offset) +
|
||||
sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN))) {
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
/* Update index length and remove index entry. */
|
||||
ih->index_length = cpu_to_le32(new_index_length);
|
||||
if (ictx->is_in_root)
|
||||
ih->allocated_size = ih->index_length;
|
||||
memmove(ictx->entry, (u8*)ictx->entry + le16_to_cpu(
|
||||
ictx->entry->length), new_index_length -
|
||||
((u8*)ictx->entry - (u8*)ih));
|
||||
ntfs_index_entry_mark_dirty(ictx);
|
||||
/* Resize INDEX_ROOT attribute. */
|
||||
if (ictx->is_in_root) {
|
||||
ntfs_attr *na;
|
||||
|
||||
na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name,
|
||||
ictx->name_len);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to open INDEX_ROOT attribute. "
|
||||
"Leaving inconsistent metadata.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_index_length + offsetof(
|
||||
INDEX_ROOT, index))) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to truncate INDEX_ROOT "
|
||||
"attribute. Leaving inconsistent "
|
||||
"metadata.\n");
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
ntfs_index_ctx_reinit(ictx);
|
||||
ntfs_log_trace("Done.\n");
|
||||
return 0;
|
||||
err_out:
|
||||
ntfs_index_ctx_reinit(ictx);
|
||||
ntfs_log_trace("Failed.\n");
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NTFS_RICH
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include "rich.h"
|
||||
|
||||
/**
|
||||
* ntfs_ie_free - Destroy an index entry object
|
||||
* @ie:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_ie_free(INDEX_ENTRY *ie)
|
||||
{
|
||||
ntfs_log_trace ("ie %p, inode %lld\n", ie, MREF(ie->indexed_file));
|
||||
free(ie);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_create - Create a representation of an directory index entry
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_create(void)
|
||||
{
|
||||
int length;
|
||||
INDEX_ENTRY *ie;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
length = 16;
|
||||
ie = calloc(1, length);
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
ie->indexed_file = 0;
|
||||
ie->length = length;
|
||||
ie->key_length = 0;
|
||||
ie->flags = INDEX_ENTRY_END;
|
||||
ie->reserved = 0;
|
||||
return ie;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_get_vcn - Get the VCN associated with an index entry
|
||||
* @ie:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie)
|
||||
{
|
||||
if (!ie)
|
||||
return -1;
|
||||
if (!(ie->flags & INDEX_ENTRY_NODE))
|
||||
return -1;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
return *((VCN*) ((u8*) ie + ie->length - 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_copy - Create a copy of an index entry
|
||||
* @ie:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_copy(INDEX_ENTRY *ie)
|
||||
{
|
||||
INDEX_ENTRY *copy = NULL;
|
||||
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
copy = malloc(ie->length);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
memcpy(copy, ie, ie->length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_set_vcn - Set VCN associated with an index entry
|
||||
* @ie:
|
||||
* @vcn:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn)
|
||||
{
|
||||
if (!ie)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
if (!(ie->flags & INDEX_ENTRY_NODE)) {
|
||||
ie->length += 8;
|
||||
ie = realloc(ie, ie->length);
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
ie->flags |= INDEX_ENTRY_NODE;
|
||||
}
|
||||
|
||||
*((VCN*) ((u8*) ie + ie->length - 8)) = vcn;
|
||||
return ie;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_remove_vcn - Remove the VCN associated with an index entry
|
||||
* @ie:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_remove_vcn(INDEX_ENTRY *ie)
|
||||
{
|
||||
if (!ie)
|
||||
return NULL;
|
||||
if (!(ie->flags & INDEX_ENTRY_NODE))
|
||||
return ie;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
ie->length -= 8;
|
||||
ie->flags &= ~INDEX_ENTRY_NODE;
|
||||
ie = realloc(ie, ie->length);
|
||||
return ie;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_set_name - Associate a name with an index entry
|
||||
* @ie:
|
||||
* @name:
|
||||
* @namelen:
|
||||
* @nametype:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_set_name(INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype)
|
||||
{
|
||||
FILE_NAME_ATTR *file;
|
||||
int need;
|
||||
BOOL wipe = FALSE;
|
||||
VCN vcn = 0;
|
||||
|
||||
if (!ie || !name)
|
||||
return NULL;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
/*
|
||||
* INDEX_ENTRY
|
||||
* MFT_REF indexed_file;
|
||||
* u16 length;
|
||||
* u16 key_length;
|
||||
* INDEX_ENTRY_FLAGS flags;
|
||||
* u16 reserved;
|
||||
*
|
||||
* FILENAME
|
||||
* MFT_REF parent_directory;
|
||||
* s64 creation_time;
|
||||
* s64 last_data_change_time;
|
||||
* s64 last_mft_change_time;
|
||||
* s64 last_access_time;
|
||||
* s64 allocated_size;
|
||||
* s64 data_size;
|
||||
* FILE_ATTR_FLAGS file_attributes;
|
||||
* u32 reserved;
|
||||
* u8 file_name_length;
|
||||
* FILE_NAME_TYPE_FLAGS file_name_type;
|
||||
* ntfschar file_name[l];
|
||||
* u8 reserved[n]
|
||||
*
|
||||
* VCN vcn;
|
||||
*/
|
||||
|
||||
//ntfs_log_debug("key length = 0x%02X\n", ie->key_length);
|
||||
//ntfs_log_debug("new name length = %d\n", namelen);
|
||||
if (ie->key_length > 0) {
|
||||
file = &ie->key.file_name;
|
||||
//ntfs_log_debug("filename, length %d\n", file->file_name_length);
|
||||
need = ATTR_SIZE(namelen * sizeof(ntfschar) + 2) -
|
||||
ATTR_SIZE(file->file_name_length * sizeof(ntfschar) + 2);
|
||||
} else {
|
||||
//ntfs_log_debug("no filename\n");
|
||||
need = ATTR_SIZE(sizeof(FILE_NAME_ATTR) + (namelen * sizeof(ntfschar)));
|
||||
wipe = TRUE;
|
||||
}
|
||||
|
||||
//ntfs_log_debug("need 0x%02X bytes\n", need);
|
||||
|
||||
if (need != 0) {
|
||||
if (ie->flags & INDEX_ENTRY_NODE)
|
||||
vcn = ntfs_ie_get_vcn(ie);
|
||||
|
||||
ie->length += need;
|
||||
ie->key_length += need;
|
||||
|
||||
//ntfs_log_debug("realloc 0x%02X\n", ie->length);
|
||||
ie = realloc(ie, ie->length);
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
if (ie->flags & INDEX_ENTRY_NODE)
|
||||
ie = ntfs_ie_set_vcn(ie, vcn);
|
||||
|
||||
if (wipe)
|
||||
memset(&ie->key.file_name, 0, sizeof(FILE_NAME_ATTR));
|
||||
if (need > 0)
|
||||
memset((u8*)ie + ie->length - need, 0, need);
|
||||
}
|
||||
|
||||
memcpy(ie->key.file_name.file_name, name, namelen * sizeof(ntfschar));
|
||||
|
||||
ie->key.file_name.file_name_length = namelen;
|
||||
ie->key.file_name.file_name_type = nametype;
|
||||
ie->flags &= ~INDEX_ENTRY_END;
|
||||
|
||||
//ntfs_log_debug("ie->length = 0x%02X\n", ie->length);
|
||||
//ntfs_log_debug("ie->key_length = 0x%02X\n", ie->key_length);
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ie_remove_name - Remove the name from an index-entry
|
||||
* @ie:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
INDEX_ENTRY * ntfs_ie_remove_name(INDEX_ENTRY *ie)
|
||||
{
|
||||
VCN vcn = 0;
|
||||
|
||||
if (!ie)
|
||||
return NULL;
|
||||
if (ie->key_length == 0)
|
||||
return ie;
|
||||
|
||||
ntfs_log_trace ("\n");
|
||||
if (ie->flags & INDEX_ENTRY_NODE)
|
||||
vcn = ntfs_ie_get_vcn(ie);
|
||||
|
||||
ie->length -= ATTR_SIZE(ie->key_length);
|
||||
ie->key_length = 0;
|
||||
ie->flags |= INDEX_ENTRY_END;
|
||||
|
||||
ie = realloc(ie, ie->length);
|
||||
if (!ie)
|
||||
return NULL;
|
||||
|
||||
if (ie->flags & INDEX_ENTRY_NODE)
|
||||
ie = ntfs_ie_set_vcn(ie, vcn);
|
||||
return ie;
|
||||
}
|
||||
|
||||
|
||||
#endif /* NTFS_RICH */
|
||||
|
||||
/**
|
||||
* 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));
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_perror("ntfs_get_search_ctx failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ntfs_attr_lookup(AT_INDEX_ROOT, name, attr->name_length, 0, 0, NULL,
|
||||
0, ctx)) {
|
||||
ntfs_log_perror("ntfs_attr_lookup failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
root = malloc(sizeof(INDEX_ROOT));
|
||||
if (!root) {
|
||||
ntfs_log_perror("malloc failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*root = *((INDEX_ROOT *)((u8 *)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset)));
|
||||
out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
1288
libntfs/inode.c
1288
libntfs/inode.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,856 +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 "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 = 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*)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;
|
||||
/* 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;
|
||||
}
|
||||
|
|
@ -1,775 +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 "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 = malloc(le32_to_cpu(rp->system_page_size));
|
||||
if (!trp) {
|
||||
ntfs_log_error("Failed to allocate memory for $LogFile "
|
||||
"restart page buffer.\n");
|
||||
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 = malloc(NTFS_BLOCK_SIZE);
|
||||
if (!kaddr) {
|
||||
ntfs_log_error("Not enough memory.\n");
|
||||
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:
|
||||
ntfs_attr_close(na);
|
||||
ntfs_inode_close(na->ni);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1,670 +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 "logging.h"
|
||||
|
||||
#ifndef PATH_SEP
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
/* Colour prefixes and a suffix */
|
||||
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";
|
||||
|
||||
/**
|
||||
* 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 within the library and tools.
|
||||
*/
|
||||
static struct ntfs_logging ntfs_log = {
|
||||
#ifdef DEBUG
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
|
||||
#endif
|
||||
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_REASON | NTFS_LOG_LEVEL_PROGRESS,
|
||||
NTFS_LOG_FLAG_ONLYNAME,
|
||||
#ifdef DEBUG
|
||||
ntfs_log_handler_outerr
|
||||
#else
|
||||
ntfs_log_handler_null
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 simple syslog logging handler. Ignores colors.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
const char *file, __attribute__((unused)) int line, u32 level,
|
||||
void *data __attribute__((unused)), const char *format, va_list args)
|
||||
{
|
||||
const int reason_size = 128;
|
||||
static char *reason = NULL;
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
|
||||
if (level == NTFS_LOG_LEVEL_REASON) {
|
||||
if (!reason)
|
||||
reason = malloc(reason_size);
|
||||
if (reason) {
|
||||
memset(reason, 0, reason_size);
|
||||
return vsnprintf(reason, reason_size, format, args);
|
||||
} else {
|
||||
/* Rather than call ourselves, just drop through */
|
||||
level = NTFS_LOG_LEVEL_PERROR;
|
||||
format = "Couldn't create reason";
|
||||
args = NULL;
|
||||
olderr = errno;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
#if 0 /* FIXME: Implement this all. */
|
||||
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) {
|
||||
if (reason)
|
||||
ret += fprintf(stream, " : %s\n", reason);
|
||||
else
|
||||
ret += fprintf(stream, " : %s\n", strerror(olderr));
|
||||
}
|
||||
#endif
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1; /* FIXME: caclulate how many bytes had been written. */
|
||||
|
||||
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)
|
||||
{
|
||||
const int reason_size = 128;
|
||||
static char *reason = NULL;
|
||||
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 (level == NTFS_LOG_LEVEL_REASON) {
|
||||
if (!reason)
|
||||
reason = malloc(reason_size);
|
||||
if (reason) {
|
||||
memset(reason, 0, reason_size);
|
||||
return vsnprintf(reason, reason_size, format, args);
|
||||
} else {
|
||||
/* Rather than call ourselves, just drop through */
|
||||
level = NTFS_LOG_LEVEL_PERROR;
|
||||
format = "Couldn't create reason";
|
||||
args = NULL;
|
||||
olderr = errno;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (reason)
|
||||
ret += fprintf(stream, " : %s\n", reason);
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
1960
libntfs/mft.c
1960
libntfs/mft.c
File diff suppressed because it is too large
Load Diff
214
libntfs/mst.c
214
libntfs/mst.c
|
|
@ -1,214 +0,0 @@
|
|||
/**
|
||||
* mst.c - Multi sector fixup handling code. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-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 "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;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
/* 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 = (u16*)((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;
|
||||
usn = cpu_to_le16(usn);
|
||||
*usa_pos = usn;
|
||||
/* Position in 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 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 = usn;
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
2126
libntfs/runlist.c
2126
libntfs/runlist.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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 "types.h"
|
||||
#include "layout.h"
|
||||
#include "security.h"
|
||||
|
||||
/*
|
||||
* The zero GUID.
|
||||
*/
|
||||
static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
|
||||
const_cpu_to_le16(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 = malloc(37);
|
||||
if (!_guid_str)
|
||||
return _guid_str;
|
||||
}
|
||||
res = snprintf(_guid_str, 37,
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
(unsigned int)le32_to_cpu(guid->data1),
|
||||
le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
|
||||
guid->data4[0], guid->data4[1],
|
||||
guid->data4[2], guid->data4[3], guid->data4[4],
|
||||
guid->data4[5], guid->data4[6], guid->data4[7]);
|
||||
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.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 = 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.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;
|
||||
}
|
||||
}
|
||||
|
||||
755
libntfs/unistr.c
755
libntfs/unistr.c
|
|
@ -1,755 +0,0 @@
|
|||
/**
|
||||
* unistr.c - Unicode string handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-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_WCHAR_H
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "attrib.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;
|
||||
ntfschar 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)
|
||||
{
|
||||
ntfschar 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)
|
||||
{
|
||||
ntfschar 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 = malloc((len + 1) * sizeof(ntfschar));
|
||||
if (dst) {
|
||||
memcpy(dst, s, len * sizeof(ntfschar));
|
||||
dst[len] = cpu_to_le16(L'\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;
|
||||
ntfschar 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*)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*)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) {
|
||||
int eo = errno;
|
||||
free(mbs);
|
||||
errno = eo;
|
||||
}
|
||||
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*)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] = cpu_to_le16(L'\0');
|
||||
if (*outs != ucs)
|
||||
*outs = ucs;
|
||||
return o;
|
||||
err_out:
|
||||
if (ucs != *outs) {
|
||||
int eo = errno;
|
||||
free(ucs);
|
||||
errno = eo;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
||||
{0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128},
|
||||
{0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112},
|
||||
{0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126},
|
||||
{0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8},
|
||||
{0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8},
|
||||
{0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8},
|
||||
{0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7},
|
||||
{0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16},
|
||||
{0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26},
|
||||
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
||||
{0}
|
||||
};
|
||||
static int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
||||
{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
|
||||
{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
|
||||
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
||||
{0}
|
||||
};
|
||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
||||
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
||||
{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
|
||||
{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
|
||||
{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
|
||||
{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
|
||||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
int i, r;
|
||||
|
||||
memset((char*)uc, 0, uc_len);
|
||||
uc_len >>= 1;
|
||||
if (uc_len > 65536)
|
||||
uc_len = 65536;
|
||||
for (i = 0; (u32)i < uc_len; i++)
|
||||
uc[i] = i;
|
||||
for (r = 0; uc_run_table[r][0]; r++)
|
||||
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
|
||||
uc[i] += uc_run_table[r][2];
|
||||
for (r = 0; uc_dup_table[r][0]; r++)
|
||||
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
|
||||
uc[i + 1]--;
|
||||
for (r = 0; uc_byte_table[r][0]; r++)
|
||||
uc[uc_byte_table[r][0]] = uc_byte_table[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 > 0xff) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1,325 +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 "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 = malloc(sizeof(int))))
|
||||
return -1;
|
||||
/*
|
||||
* Open the device/file obtaining the file descriptor for exclusive
|
||||
* access (but only if mounting r/w).
|
||||
*/
|
||||
if ((flags & O_RDWR) == O_RDWR)
|
||||
flags |= O_EXCL;
|
||||
*(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 ntfs_pread(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ntfs_pwrite(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
1901
libntfs/volume.c
1901
libntfs/volume.c
File diff suppressed because it is too large
Load Diff
1473
libntfs/win32_io.c
1473
libntfs/win32_io.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue