mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-16 00:15:08 +01:00
*Enabled NTFS writing
*Fixed favorite sorting
This commit is contained in:
parent
6012536f67
commit
9594155a8d
@ -2,8 +2,8 @@
|
||||
<app version="1">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r953</version>
|
||||
<release_date>201009190727</release_date>
|
||||
<version>1.0 r957</version>
|
||||
<release_date>201009191357</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
10
Makefile
10
Makefile
@ -41,15 +41,9 @@ SOURCES := source \
|
||||
source/libfat \
|
||||
source/memory \
|
||||
source/libntfs \
|
||||
source/usbloader/wbfs \
|
||||
# source/libhfs+ \
|
||||
# source/libhfs+/hfscommon/BTree \
|
||||
# source/libhfs+/hfscommon/Catalog \
|
||||
# source/libhfs+/hfscommon/Misc \
|
||||
# source/libhfs+/hfscommon/Unicode
|
||||
source/usbloader/wbfs
|
||||
DATA := data
|
||||
INCLUDES := source
|
||||
#source/libhfs+/hfscommon/headers
|
||||
INCLUDES := source
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include "usbloader/usbstorage2.h"
|
||||
#include "usbloader/sdhc.h"
|
||||
#include "usbloader/wbfs.h"
|
||||
#include "libfat/fat.h"
|
||||
#include "libntfs/ntfs.h"
|
||||
#include "libfat/fat.h"
|
||||
#include "gecko.h"
|
||||
|
||||
//these are the only stable and speed is good
|
||||
@ -215,7 +215,7 @@ s32 MountNTFS( u32 sector )
|
||||
// }
|
||||
/* Mount device */
|
||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
ret = ntfsMount( "NTFS", &__io_usbstorage2, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER );
|
||||
if ( !ret )
|
||||
{
|
||||
return -2;
|
||||
@ -226,11 +226,11 @@ s32 MountNTFS( u32 sector )
|
||||
{
|
||||
if ( sdhc_mode_sd == 0 )
|
||||
{
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_READ_ONLY | NTFS_RECOVER );
|
||||
ret = ntfsMount( "NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER );
|
||||
}
|
||||
if ( !ret )
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,30 +25,30 @@
|
||||
#define ACLS_H
|
||||
|
||||
/*
|
||||
* JPA configuration modes for security.c / acls.c
|
||||
* should be moved to some config file
|
||||
* JPA configuration modes for security.c / acls.c
|
||||
* should be moved to some config file
|
||||
*/
|
||||
|
||||
#define BUFSZ 1024 /* buffer size to read mapping file */
|
||||
#define BUFSZ 1024 /* buffer size to read mapping file */
|
||||
#define MAPPINGFILE ".NTFS-3G/UserMapping" /* default mapping file */
|
||||
#define LINESZ 120 /* maximum useful size of a mapping line */
|
||||
#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */
|
||||
#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */
|
||||
|
||||
/*
|
||||
* JPA The following must be in some library...
|
||||
* but did not found out where
|
||||
* JPA The following must be in some library...
|
||||
* but did not found out where
|
||||
*/
|
||||
|
||||
#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8))
|
||||
#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \
|
||||
| ((x & 0xff00) << 8) | ((x & 255) << 24))
|
||||
| ((x & 0xff00) << 8) | ((x & 255) << 24))
|
||||
|
||||
#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x))
|
||||
#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x))
|
||||
|
||||
/*
|
||||
* Macro definitions needed to share code with secaudit
|
||||
* Macro definitions needed to share code with secaudit
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf)
|
||||
@ -58,25 +58,25 @@
|
||||
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
* when setting, set them all
|
||||
* when checking, check one is present
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
* when setting, set them all
|
||||
* when checking, check one is present
|
||||
*/
|
||||
|
||||
/* flags which are set to mean exec, write or read */
|
||||
/* flags which are set to mean exec, write or read */
|
||||
|
||||
#define FILE_READ (FILE_READ_DATA)
|
||||
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define FILE_EXEC (FILE_EXECUTE)
|
||||
#define DIR_READ FILE_LIST_DIRECTORY
|
||||
#define DIR_WRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define DIR_EXEC (FILE_TRAVERSE)
|
||||
|
||||
/* flags tested for meaning exec, write or read */
|
||||
/* tests for write allow for interpretation of a sticky bit */
|
||||
/* flags tested for meaning exec, write or read */
|
||||
/* tests for write allow for interpretation of a sticky bit */
|
||||
|
||||
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
||||
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
||||
@ -85,116 +85,115 @@
|
||||
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
||||
#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE)
|
||||
|
||||
/* standard owner (and administrator) rights */
|
||||
/* standard owner (and administrator) rights */
|
||||
|
||||
#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \
|
||||
| SYNCHRONIZE \
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||
| FILE_READ_EA | FILE_WRITE_EA)
|
||||
| SYNCHRONIZE \
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||
| FILE_READ_EA | FILE_WRITE_EA)
|
||||
|
||||
/* standard world rights */
|
||||
/* standard world rights */
|
||||
|
||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
||||
| SYNCHRONIZE)
|
||||
| SYNCHRONIZE)
|
||||
|
||||
/* inheritance flags for files and directories */
|
||||
/* inheritance flags for files and directories */
|
||||
|
||||
#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
||||
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
||||
|
||||
/*
|
||||
* To identify NTFS ACL meaning Posix ACL granted to root
|
||||
* we use rights always granted to anybody, so they have no impact
|
||||
* either on Windows or on Linux.
|
||||
* To identify NTFS ACL meaning Posix ACL granted to root
|
||||
* we use rights always granted to anybody, so they have no impact
|
||||
* either on Windows or on Linux.
|
||||
*/
|
||||
|
||||
#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
|
||||
/*
|
||||
* A type large enough to hold any SID
|
||||
* A type large enough to hold any SID
|
||||
*/
|
||||
|
||||
typedef char BIGSID[40];
|
||||
|
||||
/*
|
||||
* Struct to hold the input mapping file
|
||||
* (private to this module)
|
||||
* Struct to hold the input mapping file
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST
|
||||
{
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
char *sidstr; /* sid text from the same record */
|
||||
char maptext[LINESZ + 1];
|
||||
struct MAPLIST {
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
char *sidstr; /* sid text from the same record */
|
||||
char maptext[LINESZ + 1];
|
||||
};
|
||||
|
||||
typedef int ( *FILEREADER )( void *fileid, char *buf, size_t size, off_t pos );
|
||||
typedef int (*FILEREADER)(void *fileid, char *buf, size_t size, off_t pos);
|
||||
|
||||
/*
|
||||
* Constants defined in acls.c
|
||||
* Constants defined in acls.c
|
||||
*/
|
||||
|
||||
extern const SID *adminsid;
|
||||
extern const SID *worldsid;
|
||||
|
||||
/*
|
||||
* Functions defined in acls.c
|
||||
* Functions defined in acls.c
|
||||
*/
|
||||
|
||||
BOOL ntfs_valid_descr( const char *securattr, unsigned int attrsz );
|
||||
BOOL ntfs_valid_pattern( const SID *sid );
|
||||
BOOL ntfs_valid_sid( const SID *sid );
|
||||
BOOL ntfs_same_sid( const SID *first, const SID *second );
|
||||
BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz);
|
||||
BOOL ntfs_valid_pattern(const SID *sid);
|
||||
BOOL ntfs_valid_sid(const SID *sid);
|
||||
BOOL ntfs_same_sid(const SID *first, const SID *second);
|
||||
|
||||
BOOL ntfs_is_user_sid( const SID *usid );
|
||||
BOOL ntfs_is_user_sid(const SID *usid);
|
||||
|
||||
|
||||
int ntfs_sid_size( const SID * sid );
|
||||
unsigned int ntfs_attr_size( const char *attr );
|
||||
int ntfs_sid_size(const SID * sid);
|
||||
unsigned int ntfs_attr_size(const char *attr);
|
||||
|
||||
const SID *ntfs_find_usid( const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid );
|
||||
const SID *ntfs_find_gsid( const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid );
|
||||
uid_t ntfs_find_user( const struct MAPPING *usermapping, const SID *usid );
|
||||
gid_t ntfs_find_group( const struct MAPPING *groupmapping, const SID * gsid );
|
||||
const SID *ntfs_acl_owner( const char *secattr );
|
||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid);
|
||||
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid);
|
||||
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||
const SID *ntfs_acl_owner(const char *secattr);
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
BOOL ntfs_valid_posix( const struct POSIX_SECURITY *pxdesc );
|
||||
void ntfs_sort_posix( struct POSIX_SECURITY *pxdesc );
|
||||
int ntfs_merge_mode_posix( struct POSIX_SECURITY *pxdesc, mode_t mode );
|
||||
BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc);
|
||||
void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc);
|
||||
int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
|
||||
struct POSIX_SECURITY *ntfs_build_inherited_posix(
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir );
|
||||
struct POSIX_SECURITY *ntfs_replace_acl( const struct POSIX_SECURITY *oldpxdesc,
|
||||
const struct POSIX_ACL *newacl, int count, BOOL deflt );
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
||||
const struct POSIX_ACL *newacl, int count, BOOL deflt);
|
||||
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
struct MAPPING* const mapping[],
|
||||
const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir );
|
||||
struct POSIX_SECURITY *ntfs_merge_descr_posix( const struct POSIX_SECURITY *first,
|
||||
const struct POSIX_SECURITY *second );
|
||||
char *ntfs_build_descr_posix( struct MAPPING* const mapping[],
|
||||
struct POSIX_SECURITY *pxdesc,
|
||||
int isdir, const SID *usid, const SID *gsid );
|
||||
struct MAPPING* const mapping[],
|
||||
const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first,
|
||||
const struct POSIX_SECURITY *second);
|
||||
char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
struct POSIX_SECURITY *pxdesc,
|
||||
int isdir, const SID *usid, const SID *gsid);
|
||||
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
int ntfs_inherit_acl( const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir );
|
||||
int ntfs_build_permissions( const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir );
|
||||
char *ntfs_build_descr( mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid );
|
||||
struct MAPLIST *ntfs_read_mapping( FILEREADER reader, void *fileid );
|
||||
struct MAPPING *ntfs_do_user_mapping( struct MAPLIST *firstitem );
|
||||
struct MAPPING *ntfs_do_group_mapping( struct MAPLIST *firstitem );
|
||||
void ntfs_free_mapping( struct MAPPING *mapping[] );
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir);
|
||||
int ntfs_build_permissions(const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
char *ntfs_build_descr(mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid);
|
||||
struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||
void ntfs_free_mapping(struct MAPPING *mapping[]);
|
||||
|
||||
#endif /* ACLS_H */
|
||||
|
||||
|
10780
source/libntfs/attrib.c
10780
source/libntfs/attrib.c
File diff suppressed because it is too large
Load Diff
@ -49,20 +49,19 @@ extern ntfschar TXF_DATA[10];
|
||||
*
|
||||
* 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,
|
||||
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
|
||||
* @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
|
||||
@ -76,36 +75,35 @@ typedef enum
|
||||
* 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;
|
||||
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 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 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 int ntfs_attr_position( const ATTR_TYPES type, ntfs_attr_search_ctx *ctx );
|
||||
extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef( const ntfs_volume *vol,
|
||||
const ATTR_TYPES type );
|
||||
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
|
||||
* @ctx: initialised attribute search context
|
||||
*
|
||||
* Syntactic sugar for walking attributes in an inode.
|
||||
*
|
||||
@ -113,42 +111,42 @@ extern ATTR_DEF *ntfs_attr_find_in_attrdef( const ntfs_volume *vol,
|
||||
* ntfs_attr_lookup().
|
||||
*
|
||||
* Example: When you want to enumerate all attributes in an open ntfs inode
|
||||
* @ni, you can simply do:
|
||||
* @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.
|
||||
* 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 )
|
||||
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 );
|
||||
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
|
||||
* @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,
|
||||
@ -176,70 +174,68 @@ static __inline__ int ntfs_attrs_walk( ntfs_attr_search_ctx *ctx )
|
||||
* @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;
|
||||
ATTR_FLAGS data_flags;
|
||||
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;
|
||||
s8 unused_runs; /* pre-reserved entries available */
|
||||
struct _ntfs_attr {
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
ATTR_FLAGS data_flags;
|
||||
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;
|
||||
s8 unused_runs; /* pre-reserved entries available */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
typedef enum {
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
} 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 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 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 NAttrNonResident(na) test_nattr_flag(na, NonResident)
|
||||
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
|
||||
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
|
||||
|
||||
#define NAttrBeingNonResident(na) test_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrSetBeingNonResident(na) set_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrClearBeingNonResident(na) clear_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrBeingNonResident(na) test_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrSetBeingNonResident(na) set_nattr_flag(na, BeingNonResident)
|
||||
#define NAttrClearBeingNonResident(na) clear_nattr_flag(na, BeingNonResident)
|
||||
|
||||
#define NAttrFullyMapped(na) test_nattr_flag(na, FullyMapped)
|
||||
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
|
||||
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
|
||||
#define NAttrFullyMapped(na) test_nattr_flag(na, FullyMapped)
|
||||
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
|
||||
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
|
||||
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
|
||||
#define GenNAttrIno(func_name, flag) \
|
||||
extern int NAttr##func_name(ntfs_attr *na); \
|
||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||
#define GenNAttrIno(func_name, flag) \
|
||||
extern int NAttr##func_name(ntfs_attr *na); \
|
||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||
extern void NAttrClear##func_name(ntfs_attr *na);
|
||||
|
||||
GenNAttrIno( Compressed, FILE_ATTR_COMPRESSED )
|
||||
GenNAttrIno( Encrypted, FILE_ATTR_ENCRYPTED )
|
||||
GenNAttrIno( Sparse, FILE_ATTR_SPARSE_FILE )
|
||||
GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
|
||||
GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED)
|
||||
GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||
#undef GenNAttrIno
|
||||
|
||||
/**
|
||||
@ -247,100 +243,99 @@ GenNAttrIno( Sparse, FILE_ATTR_SPARSE_FILE )
|
||||
*
|
||||
* 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;
|
||||
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 ATTR_FLAGS data_flags, 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 void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||
const ATTR_FLAGS data_flags, 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);
|
||||
|
||||
/* warning : in the following "name" has to be freeable */
|
||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
||||
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 );
|
||||
/* warning : in the following "name" has to be freeable */
|
||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
||||
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 int ntfs_attr_pclose( 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 int ntfs_attr_pclose(ntfs_attr *na);
|
||||
|
||||
extern void *ntfs_attr_readall( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len, s64 *data_size );
|
||||
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 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 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 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_resident( const ntfs_volume *vol,
|
||||
const ATTR_TYPES type );
|
||||
int ntfs_attr_make_non_resident( ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx );
|
||||
int ntfs_attr_force_non_resident( ntfs_attr *na );
|
||||
extern int ntfs_make_room_for_attr( MFT_RECORD *m, u8 *pos, u32 size );
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attr_force_non_resident(ntfs_attr *na);
|
||||
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_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_set_flags( ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask );
|
||||
extern int ntfs_attr_rm( ntfs_attr *na );
|
||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
||||
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_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_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_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_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
|
||||
|
||||
extern int ntfs_attr_truncate( ntfs_attr *na, const s64 newsize );
|
||||
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
|
||||
|
||||
/**
|
||||
* get_attribute_value_length - return the length of the value of an attribute
|
||||
* @a: pointer to a buffer containing the attribute record
|
||||
* @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).
|
||||
@ -349,13 +344,13 @@ extern int ntfs_attr_truncate( ntfs_attr *na, const s64 newsize );
|
||||
*
|
||||
* FIXME: Describe possible errnos.
|
||||
*/
|
||||
extern s64 ntfs_get_attribute_value_length( const ATTR_RECORD *a );
|
||||
extern 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
|
||||
* @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
|
||||
@ -365,16 +360,16 @@ extern s64 ntfs_get_attribute_value_length( const ATTR_RECORD *a );
|
||||
* then nothing was read due to a zero-length attribute value, otherwise
|
||||
* errno describes the error.
|
||||
*/
|
||||
extern s64 ntfs_get_attribute_value( const ntfs_volume *vol,
|
||||
const ATTR_RECORD *a, u8 *b );
|
||||
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *a, u8 *b);
|
||||
|
||||
extern void ntfs_attr_name_free( char **name );
|
||||
extern char *ntfs_attr_name_get( const ntfschar *uname, const int uname_len );
|
||||
extern int ntfs_attr_exist( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern int ntfs_attr_remove( ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern s64 ntfs_attr_get_free_bits( ntfs_attr *na );
|
||||
extern void ntfs_attr_name_free(char **name);
|
||||
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
||||
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS
|
||||
* project.
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
@ -47,7 +47,7 @@
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_need - check whether inode need attribute list
|
||||
* @ni: opened ntfs inode for which perform check
|
||||
* @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.
|
||||
@ -55,278 +55,260 @@
|
||||
* 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.
|
||||
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
||||
* attribute list.
|
||||
*/
|
||||
int ntfs_attrlist_need( ntfs_inode *ni )
|
||||
int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
|
||||
if ( !ni )
|
||||
{
|
||||
ntfs_log_trace( "Invalid arguments.\n" );
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
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 );
|
||||
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 (!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;
|
||||
}
|
||||
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;
|
||||
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
|
||||
* @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.
|
||||
* 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 )
|
||||
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;
|
||||
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 ) );
|
||||
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;
|
||||
}
|
||||
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 ) );
|
||||
mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
|
||||
|
||||
if ( ni->nr_extents == -1 )
|
||||
ni = ni->base_ni;
|
||||
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;
|
||||
}
|
||||
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 = ntfs_calloc( ni->attr_list_size + entry_len );
|
||||
if ( !new_al )
|
||||
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 = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
err = errno;
|
||||
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 );
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
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 ) );
|
||||
/* 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;
|
||||
}
|
||||
/* 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 );
|
||||
/* 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;
|
||||
/* 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;
|
||||
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
|
||||
* @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 )
|
||||
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;
|
||||
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 || !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;
|
||||
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 ) );
|
||||
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;
|
||||
}
|
||||
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 = ntfs_calloc( new_al_len );
|
||||
if ( !new_al )
|
||||
return -1;
|
||||
/* Allocate memory for new attribute list. */
|
||||
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||
new_al = ntfs_calloc(new_al_len);
|
||||
if (!new_al)
|
||||
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;
|
||||
}
|
||||
/* 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 ) );
|
||||
/* 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;
|
||||
/* 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;
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* attrlist.h - Exports for attribute list attribute handling.
|
||||
* Originated from Linux-NTFS project.
|
||||
* attrlist.h - Exports for attribute list attribute handling.
|
||||
* Originated from Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
@ -26,26 +26,26 @@
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
extern int ntfs_attrlist_need( ntfs_inode *ni );
|
||||
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 );
|
||||
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
|
||||
* @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 )
|
||||
static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
|
||||
{
|
||||
if ( ni->nr_extents == -1 )
|
||||
NInoAttrListSetDirty( ni->base_ni );
|
||||
else
|
||||
NInoAttrListSetDirty( ni );
|
||||
if (ni->nr_extents == -1)
|
||||
NInoAttrListSetDirty(ni->base_ni);
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
||||
|
@ -3,7 +3,7 @@
|
||||
Functions for dealing with conversion of data between types
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
@ -34,28 +34,24 @@
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8));
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
||||
{
|
||||
return ( item[offset] | ( item[offset + 1] << 8 ) | ( item[offset + 2] << 16 ) | ( item[offset + 3] << 24 ) );
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array ( uint8_t* item, int offset, uint16_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
||||
{
|
||||
item[offset] = ( uint8_t ) value;
|
||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
||||
item[offset + 3] = ( uint8_t )( value >> 24 );
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
item[offset + 2] = (uint8_t)(value >> 16);
|
||||
item[offset + 3] = (uint8_t)(value >> 24);
|
||||
}
|
||||
|
||||
#endif // _BIT_OPS_H
|
||||
|
@ -47,268 +47,254 @@
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @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.
|
||||
*/
|
||||
void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
||||
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 ) );
|
||||
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
|
||||
* @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.
|
||||
*/
|
||||
char ntfs_bit_get( const u8 *bitmap, const u64 bit )
|
||||
char ntfs_bit_get(const u8 *bitmap, const u64 bit)
|
||||
{
|
||||
if ( !bitmap )
|
||||
return -1;
|
||||
return ( bitmap[bit >> 3] >> ( bit & 7 ) ) & 1;
|
||||
if (!bitmap)
|
||||
return -1;
|
||||
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @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.
|
||||
*/
|
||||
char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
||||
char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
{
|
||||
register u8 old_bit, shift;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
* @value: value to set the bits to (i.e. 0 or 1)
|
||||
*
|
||||
* Set @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na to @value, where @value is either 0 or 1.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static int ntfs_bitmap_set_bits_in_run( ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value )
|
||||
static 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, ret = -1;
|
||||
s64 bufsize, br;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||
|
||||
if ( !na || start_bit < 0 || count < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
||||
return -1;
|
||||
}
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bit = start_bit & 7;
|
||||
if ( bit )
|
||||
firstbyte = 1;
|
||||
else
|
||||
firstbyte = 0;
|
||||
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;
|
||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||
if (bufsize > 8192)
|
||||
bufsize = 8192;
|
||||
|
||||
buf = ntfs_malloc( bufsize );
|
||||
if ( !buf )
|
||||
return -1;
|
||||
buf = ntfs_malloc(bufsize);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||
memset(buf, value ? 0xff : 0, bufsize);
|
||||
|
||||
/* 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) {
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* 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_error("Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if (lastbyte_pos <= bufsize) {
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* 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_error( "Lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n" );
|
||||
errno = 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)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", (long long)br);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Reading of last byte "
|
||||
"failed (%lld). Leaving inconsistent "
|
||||
"metadata", ( long long )br );
|
||||
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)
|
||||
if (br >= 0)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
(long long)br, (long long)bufsize);
|
||||
goto free_err_out;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
if ( br >= 0 )
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Failed to write buffer to bitmap "
|
||||
"(%lld != %lld). Leaving inconsistent metadata",
|
||||
( long long )br, ( long long )bufsize );
|
||||
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_error( "Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
( long long )count );
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
}
|
||||
while ( count > 0 );
|
||||
|
||||
ret = 0;
|
||||
/* 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_error("Last buffer but count is not zero "
|
||||
"(%lld). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
errno = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
|
||||
ret = 0;
|
||||
|
||||
free_err_out:
|
||||
free( buf );
|
||||
return ret;
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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 )
|
||||
int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter( "Set from bit %lld, count %lld\n",
|
||||
( long long )start_bit, ( long long )count );
|
||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 1 );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Set from bit %lld, count %lld\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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 )
|
||||
int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter( "Clear from bit %lld, count %lld\n",
|
||||
( long long )start_bit, ( long long )count );
|
||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 0 );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Clear from bit %lld, count %lld\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -36,38 +36,38 @@
|
||||
* size of the bitmap.
|
||||
*/
|
||||
|
||||
extern void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
||||
extern char ntfs_bit_get( const u8 *bitmap, const u64 bit );
|
||||
extern char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
||||
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 );
|
||||
extern void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
extern char ntfs_bit_get(const u8 *bitmap, const u64 bit);
|
||||
extern char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
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
|
||||
* @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 )
|
||||
static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit)
|
||||
{
|
||||
return ntfs_bitmap_set_run( na, bit, 1 );
|
||||
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
|
||||
* @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 )
|
||||
static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
|
||||
{
|
||||
return ntfs_bitmap_clear_run( na, bit, 1 );
|
||||
return ntfs_bitmap_clear_run(na, bit, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -76,9 +76,9 @@ static __inline__ int ntfs_bitmap_clear_bit( ntfs_attr *na, s64 bit )
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static __inline__ u32 ntfs_rol32( u32 word, unsigned int shift )
|
||||
static __inline__ u32 ntfs_rol32(u32 word, unsigned int shift)
|
||||
{
|
||||
return ( word << shift ) | ( word >> ( 32 - shift ) );
|
||||
return (word << shift) | (word >> (32 - shift));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -87,9 +87,9 @@ static __inline__ u32 ntfs_rol32( u32 word, unsigned int shift )
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static __inline__ u32 ntfs_ror32( u32 word, unsigned int shift )
|
||||
static __inline__ u32 ntfs_ror32(u32 word, unsigned int shift)
|
||||
{
|
||||
return ( word >> shift ) | ( word << ( 32 - shift ) );
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_BITMAP_H */
|
||||
|
@ -45,8 +45,8 @@
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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.
|
||||
@ -57,244 +57,229 @@
|
||||
*
|
||||
* Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
|
||||
*/
|
||||
BOOL ntfs_boot_sector_is_ntfs( NTFS_BOOT_SECTOR *b )
|
||||
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
{
|
||||
u32 i;
|
||||
BOOL ret = FALSE;
|
||||
u32 i;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
ntfs_log_debug( "Beginning bootsector check.\n" );
|
||||
ntfs_log_debug("Beginning bootsector check.\n");
|
||||
|
||||
ntfs_log_debug( "Checking OEMid, NTFS signature.\n" );
|
||||
if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
|
||||
{
|
||||
ntfs_log_error( "NTFS signature is missing.\n" );
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||
ntfs_log_error("NTFS signature is missing.\n");
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking bytes per sector.\n" );
|
||||
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug("Checking bytes per sector.\n");
|
||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 ||
|
||||
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
||||
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
||||
le16_to_cpu(b->bpb.bytes_per_sector));
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
||||
switch ( b->bpb.sectors_per_cluster )
|
||||
{
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error( "Unexpected sectors per cluster value (%d).\n",
|
||||
b->bpb.sectors_per_cluster );
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug("Checking sectors per cluster.\n");
|
||||
switch (b->bpb.sectors_per_cluster) {
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
||||
b->bpb.sectors_per_cluster);
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking cluster size.\n" );
|
||||
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if ( i > 65536 )
|
||||
{
|
||||
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug("Checking cluster size.\n");
|
||||
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
||||
b->bpb.sectors_per_cluster;
|
||||
if (i > 65536) {
|
||||
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
||||
goto not_ntfs;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking reserved fields are zero.\n" );
|
||||
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 )
|
||||
{
|
||||
ntfs_log_error( "Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
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("Checking reserved fields are zero.\n");
|
||||
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) {
|
||||
ntfs_log_error("Reserved fields aren't zero "
|
||||
"(%d, %d, %d, %d, %d, %d).\n",
|
||||
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( "Checking clusters per mft record.\n" );
|
||||
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:
|
||||
ntfs_log_error( "Unexpected clusters per mft record "
|
||||
"(%d).\n", b->clusters_per_mft_record );
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug("Checking clusters per mft record.\n");
|
||||
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:
|
||||
ntfs_log_error("Unexpected clusters per mft record "
|
||||
"(%d).\n", b->clusters_per_mft_record);
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Checking clusters per index block.\n" );
|
||||
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:
|
||||
ntfs_log_error( "Unexpected clusters per index record "
|
||||
"(%d).\n", b->clusters_per_index_record );
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug("Checking clusters per index block.\n");
|
||||
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:
|
||||
ntfs_log_error("Unexpected clusters per index record "
|
||||
"(%d).\n", b->clusters_per_index_record);
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
|
||||
if ( b->end_of_sector_marker != cpu_to_le16( 0xaa55 ) )
|
||||
ntfs_log_debug( "Warning: Bootsector has invalid end of sector "
|
||||
"marker.\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" );
|
||||
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||
|
||||
ret = TRUE;
|
||||
ret = TRUE;
|
||||
not_ntfs:
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *last_sector_error =
|
||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||
" or a wrong device is tried to be mounted,\n"
|
||||
" or the partition table is corrupt (partition is smaller than NTFS),\n"
|
||||
" or the NTFS boot sector is corrupt (NTFS size is not valid).\n";
|
||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\n"
|
||||
" or it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||
" or a wrong device is tried to be mounted,\n"
|
||||
" or the partition table is corrupt (partition is smaller than NTFS),\n"
|
||||
" or the NTFS boot sector is corrupt (NTFS size is not valid).\n";
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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 )
|
||||
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
{
|
||||
s64 sectors;
|
||||
u8 sectors_per_cluster;
|
||||
s8 c;
|
||||
s64 sectors;
|
||||
u8 sectors_per_cluster;
|
||||
s8 c;
|
||||
|
||||
/* We return -1 with errno = EINVAL on error. */
|
||||
errno = EINVAL;
|
||||
/* 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( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
||||
if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
||||
"\n", sectors_per_cluster );
|
||||
return -1;
|
||||
}
|
||||
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("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
||||
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
|
||||
"\n", sectors_per_cluster);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sectors = sle64_to_cpu(bs->number_of_sectors);
|
||||
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||
if (!sectors) {
|
||||
ntfs_log_error("Volume size is set to zero.\n");
|
||||
return -1;
|
||||
}
|
||||
if (vol->dev->d_ops->seek(vol->dev,
|
||||
(sectors - 1) << vol->sector_size_bits,
|
||||
SEEK_SET) == -1) {
|
||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||
(long long)sectors);
|
||||
ntfs_log_error("%s", last_sector_error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->nr_clusters = sectors >> (ffs(sectors_per_cluster) - 1);
|
||||
|
||||
sectors = sle64_to_cpu( bs->number_of_sectors );
|
||||
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
||||
if ( !sectors )
|
||||
{
|
||||
ntfs_log_error( "Volume size is set to zero.\n" );
|
||||
return -1;
|
||||
}
|
||||
if ( vol->dev->d_ops->seek( vol->dev,
|
||||
( sectors - 1 ) << vol->sector_size_bits,
|
||||
SEEK_SET ) == -1 )
|
||||
{
|
||||
ntfs_log_perror( "Failed to read last sector (%lld)",
|
||||
( long long )sectors );
|
||||
ntfs_log_error( "%s", last_sector_error );
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->nr_clusters = 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 = %lld\n", ( long long )vol->mft_lcn );
|
||||
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
||||
if ( vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters )
|
||||
{
|
||||
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
|
||||
( long long )vol->nr_clusters );
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||
if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
|
||||
{
|
||||
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
||||
vol->cluster_size );
|
||||
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_error( "mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size );
|
||||
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;
|
||||
vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
|
||||
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||
(long long)vol->nr_clusters);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
||||
ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
|
||||
vol->cluster_size);
|
||||
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_error("mft_record_size (%d) is not a power of 2.\n",
|
||||
vol->mft_record_size);
|
||||
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,6 +1,6 @@
|
||||
/*
|
||||
* bootsect.h - Exports for bootsector record handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
* bootsect.h - Exports for bootsector record handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
@ -30,13 +30,13 @@
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_is_ntfs - check a boot sector for describing an ntfs volume
|
||||
* @b: buffer containing the boot sector
|
||||
* @b: buffer containing the boot sector
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
extern BOOL ntfs_boot_sector_is_ntfs( NTFS_BOOT_SECTOR *b );
|
||||
extern int ntfs_boot_sector_parse( ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs );
|
||||
extern BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b);
|
||||
extern int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs);
|
||||
|
||||
#endif /* defined _NTFS_BOOTSECT_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,104 +24,96 @@
|
||||
|
||||
#include "volume.h"
|
||||
|
||||
struct CACHED_GENERIC
|
||||
{
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union
|
||||
{
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
struct CACHED_GENERIC {
|
||||
struct CACHED_GENERIC *next;
|
||||
struct CACHED_GENERIC *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
union {
|
||||
/* force alignment for pointers and u64 */
|
||||
u64 u64align;
|
||||
void *ptralign;
|
||||
} fixed[0];
|
||||
} ;
|
||||
|
||||
struct CACHED_INODE
|
||||
{
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
struct CACHED_INODE {
|
||||
struct CACHED_INODE *next;
|
||||
struct CACHED_INODE *previous;
|
||||
const char *pathname;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
struct CACHED_NIDATA
|
||||
{
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
size_t varsize; /* not used */
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
ntfs_inode *ni;
|
||||
struct CACHED_NIDATA {
|
||||
struct CACHED_NIDATA *next;
|
||||
struct CACHED_NIDATA *previous;
|
||||
const char *pathname; /* not used */
|
||||
size_t varsize; /* not used */
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 inum;
|
||||
ntfs_inode *ni;
|
||||
} ;
|
||||
|
||||
struct CACHED_LOOKUP
|
||||
{
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
size_t namesize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 parent;
|
||||
u64 inum;
|
||||
struct CACHED_LOOKUP {
|
||||
struct CACHED_LOOKUP *next;
|
||||
struct CACHED_LOOKUP *previous;
|
||||
const char *name;
|
||||
size_t namesize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 parent;
|
||||
u64 inum;
|
||||
} ;
|
||||
|
||||
enum
|
||||
{
|
||||
CACHE_FREE = 1,
|
||||
CACHE_NOHASH = 2
|
||||
enum {
|
||||
CACHE_FREE = 1,
|
||||
CACHE_NOHASH = 2
|
||||
} ;
|
||||
|
||||
typedef int ( *cache_compare )( const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *item );
|
||||
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
|
||||
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
||||
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
||||
const struct CACHED_GENERIC *item);
|
||||
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
||||
typedef int (*cache_hash)(const struct CACHED_GENERIC *cached);
|
||||
|
||||
struct HASH_ENTRY
|
||||
{
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
struct HASH_ENTRY {
|
||||
struct HASH_ENTRY *next;
|
||||
struct CACHED_GENERIC *entry;
|
||||
} ;
|
||||
|
||||
struct CACHE_HEADER
|
||||
{
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
struct CACHED_GENERIC *free_entry;
|
||||
struct HASH_ENTRY *free_hash;
|
||||
struct HASH_ENTRY **first_hash;
|
||||
cache_free dofree;
|
||||
cache_hash dohash;
|
||||
unsigned long reads;
|
||||
unsigned long writes;
|
||||
unsigned long hits;
|
||||
int fixed_size;
|
||||
int max_hash;
|
||||
struct CACHED_GENERIC entry[0];
|
||||
struct CACHE_HEADER {
|
||||
const char *name;
|
||||
struct CACHED_GENERIC *most_recent_entry;
|
||||
struct CACHED_GENERIC *oldest_entry;
|
||||
struct CACHED_GENERIC *free_entry;
|
||||
struct HASH_ENTRY *free_hash;
|
||||
struct HASH_ENTRY **first_hash;
|
||||
cache_free dofree;
|
||||
cache_hash dohash;
|
||||
unsigned long reads;
|
||||
unsigned long writes;
|
||||
unsigned long hits;
|
||||
int fixed_size;
|
||||
int max_hash;
|
||||
struct CACHED_GENERIC entry[0];
|
||||
} ;
|
||||
|
||||
/* cast to generic, avoiding gcc warnings */
|
||||
/* cast to generic, avoiding gcc warnings */
|
||||
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
|
||||
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare );
|
||||
struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare );
|
||||
int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare, int flags );
|
||||
int ntfs_remove_cache( struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags );
|
||||
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *wanted,
|
||||
cache_compare compare);
|
||||
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare);
|
||||
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||
const struct CACHED_GENERIC *item,
|
||||
cache_compare compare, int flags);
|
||||
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||
struct CACHED_GENERIC *item, int flags);
|
||||
|
||||
void ntfs_create_lru_caches( ntfs_volume *vol );
|
||||
void ntfs_free_lru_caches( ntfs_volume *vol );
|
||||
void ntfs_create_lru_caches(ntfs_volume *vol);
|
||||
void ntfs_free_lru_caches(ntfs_volume *vol);
|
||||
|
||||
#endif /* _NTFS_CACHE_H_ */
|
||||
|
||||
|
@ -45,365 +45,330 @@
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize )
|
||||
{
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
||||
NTFS_CACHE* cache;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
||||
if(numberOfPages==0 || sectorsPerPage==0) return NULL;
|
||||
|
||||
if ( numberOfPages < 4 )
|
||||
{
|
||||
numberOfPages = 4;
|
||||
}
|
||||
if (numberOfPages < 4) {
|
||||
numberOfPages = 4;
|
||||
}
|
||||
|
||||
if ( sectorsPerPage < 32 )
|
||||
{
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
if (sectorsPerPage < 32) {
|
||||
sectorsPerPage = 32;
|
||||
}
|
||||
|
||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
||||
if ( cache == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE));
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->sectorSize = sectorSize;
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->sectorSize = sectorSize;
|
||||
|
||||
|
||||
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
|
||||
if ( cacheEntries == NULL )
|
||||
{
|
||||
ntfs_free ( cache );
|
||||
return NULL;
|
||||
}
|
||||
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
ntfs_free (cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = ( uint8_t* ) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||
}
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = (uint8_t*) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
cache->cacheEntries = cacheEntries;
|
||||
|
||||
return cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _NTFS_cache_destructor ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
|
||||
if ( cache == NULL ) return;
|
||||
if(cache==NULL) return;
|
||||
|
||||
// Clear out cache before destroying it
|
||||
_NTFS_cache_flush( cache );
|
||||
// Clear out cache before destroying it
|
||||
_NTFS_cache_flush(cache);
|
||||
|
||||
// Free memory in reverse allocation order
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
ntfs_free ( cache->cacheEntries[i].cache );
|
||||
}
|
||||
ntfs_free ( cache->cacheEntries );
|
||||
ntfs_free ( cache );
|
||||
// Free memory in reverse allocation order
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
ntfs_free (cache->cacheEntries[i].cache);
|
||||
}
|
||||
ntfs_free (cache->cacheEntries);
|
||||
ntfs_free (cache);
|
||||
}
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime()
|
||||
{
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
static u32 accessTime(){
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage( NTFS_CACHE *cache, sec_t sector )
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
{
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &( cacheEntries[i] );
|
||||
}
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
|
||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
||||
{
|
||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
||||
{
|
||||
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
sector = ( sector / sectorsPerPage ) * sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if ( next_page > cache->endOfPartition ) next_page = cache->endOfPartition;
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
sector = (sector/sectorsPerPage)*sectorsPerPage; // align base sector to page size
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if(next_page > cache->endOfPartition) next_page = cache->endOfPartition;
|
||||
|
||||
if ( !cache->disc->readSectors( sector, next_page - sector, cacheEntries[oldUsed].cache ) ) return NULL;
|
||||
if(!cache->disc->readSectors(sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page - sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page-sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &( cacheEntries[oldUsed] );
|
||||
return &(cacheEntries[oldUsed]);
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector, sec_t count )
|
||||
{
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for ( i = 0; i < numberOfPages; i++ )
|
||||
{
|
||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
||||
{
|
||||
bool intersect;
|
||||
if ( sector > cacheEntries[i].sector )
|
||||
{
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
}
|
||||
else
|
||||
{
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
||||
{
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readSectors( NTFS_CACHE *cache, sec_t sector, sec_t numSectors, void *buffer )
|
||||
bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
uint8_t *dest = buffer;
|
||||
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
while(numSectors>0) {
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if ( secs_to_read > numSectors ) secs_to_read = numSectors;
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if(secs_to_read>numSectors) secs_to_read = numSectors;
|
||||
|
||||
memcpy( dest, entry->cache + ( sec*cache->sectorSize ), ( secs_to_read*cache->sectorSize ) );
|
||||
memcpy(dest,entry->cache + (sec*cache->sectorSize),(secs_to_read*cache->sectorSize));
|
||||
|
||||
dest += ( secs_to_read * cache->sectorSize );
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
dest += (secs_to_read*cache->sectorSize);
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Reads some data from a cache page, determined by the sector number
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_readPartialSector ( NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy( buffer, entry->cache + ( ( sec*cache->sectorSize ) + offset ), size );
|
||||
sec = sector - entry->sector;
|
||||
memcpy(buffer,entry->cache + ((sec*cache->sectorSize) + offset),size);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes )
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
||||
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
uint8_t buf[4];
|
||||
if (!_NTFS_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
|
||||
switch ( num_bytes )
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
switch(num_bytes) {
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16(buf,0); break;
|
||||
case 4: *value = u8array_to_u32(buf,0); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_writePartialSector ( NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
sec = sector - entry->sector;
|
||||
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch ( size )
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
||||
default: return false;
|
||||
}
|
||||
switch(size) {
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array(buf, 0, value); break;
|
||||
case 4: u32_to_u8array(buf, 0, value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return _NTFS_cache_writePartialSector( cache, buf, sector, offset, size );
|
||||
return _NTFS_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
|
||||
bool _NTFS_cache_eraseWritePartialSector ( NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size )
|
||||
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
|
||||
if ( offset + size > cache->sectorSize ) return false;
|
||||
if (offset + size > cache->sectorSize) return false;
|
||||
|
||||
entry = _NTFS_cache_getPage( cache, sector );
|
||||
if ( entry == NULL ) return false;
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memset( entry->cache + ( sec*cache->sectorSize ), 0, cache->sectorSize );
|
||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
||||
sec = sector - entry->sector;
|
||||
memset(entry->cache + (sec*cache->sectorSize),0,cache->sectorSize);
|
||||
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_writeSectors ( NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
NTFS_CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
NTFS_CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
|
||||
while ( numSectors > 0 )
|
||||
{
|
||||
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
||||
while(numSectors>0)
|
||||
{
|
||||
entry = _NTFS_cache_findPage(cache,sector,numSectors);
|
||||
|
||||
if ( entry != NULL )
|
||||
{
|
||||
if(entry!=NULL) {
|
||||
|
||||
if ( entry->sector > sector )
|
||||
{
|
||||
if ( entry->sector > sector) {
|
||||
|
||||
secs_to_write = entry->sector - sector;
|
||||
secs_to_write = entry->sector - sector;
|
||||
|
||||
cache->disc->writeSectors( sector, secs_to_write, src );
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
cache->disc->writeSectors(sector,secs_to_write,src);
|
||||
src += (secs_to_write*cache->sectorSize);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
|
||||
if ( secs_to_write > numSectors ) secs_to_write = numSectors;
|
||||
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||
|
||||
memcpy( entry->cache + ( sec*cache->sectorSize ), src, ( secs_to_write*cache->sectorSize ) );
|
||||
memcpy(entry->cache + (sec*cache->sectorSize),src,(secs_to_write*cache->sectorSize));
|
||||
|
||||
src += ( secs_to_write * cache->sectorSize );
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
src += (secs_to_write*cache->sectorSize);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
entry->dirty = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->disc->writeSectors( sector, numSectors, src );
|
||||
numSectors = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
cache->disc->writeSectors(sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL ) return true;
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
if(cache==NULL) return true;
|
||||
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
if ( cache->cacheEntries[i].dirty )
|
||||
{
|
||||
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
if (cache->cacheEntries[i].dirty) {
|
||||
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
||||
{
|
||||
unsigned int i;
|
||||
if ( cache == NULL )
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
if(cache==NULL)
|
||||
return;
|
||||
|
||||
_NTFS_cache_flush( cache );
|
||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
_NTFS_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -46,23 +46,21 @@
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
bool dirty;
|
||||
u8* cache;
|
||||
typedef struct {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
u64 last_access;
|
||||
bool dirty;
|
||||
u8* cache;
|
||||
} NTFS_CACHE_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
sec_t sectorSize;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
sec_t sectorSize;
|
||||
NTFS_CACHE_ENTRY* cacheEntries;
|
||||
} NTFS_CACHE;
|
||||
|
||||
/*
|
||||
@ -101,37 +99,37 @@ Precondition: offset + size <= BYTES_PER_READ
|
||||
/*
|
||||
Read several sectors from the NTFS_CACHE
|
||||
*/
|
||||
bool _NTFS_cache_readSectors ( NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, void* buffer );
|
||||
bool _NTFS_cache_readSectors (NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, void* buffer);
|
||||
|
||||
/*
|
||||
Read a full sector from the NTFS_CACHE
|
||||
*/
|
||||
//static inline bool _NTFS_cache_readSector (NTFS_CACHE* NTFS_CACHE, void* buffer, sec_t sector) {
|
||||
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
// return _NTFS_cache_readPartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
//}
|
||||
|
||||
/*
|
||||
Write a full sector to the NTFS_CACHE
|
||||
*/
|
||||
//static inline bool _NTFS_cache_writeSector (NTFS_CACHE* NTFS_CACHE, const void* buffer, sec_t sector) {
|
||||
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
// return _NTFS_cache_writePartialSector (NTFS_CACHE, buffer, sector, 0, BYTES_PER_READ);
|
||||
//}
|
||||
|
||||
bool _NTFS_cache_writeSectors ( NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* NTFS_CACHE, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
|
||||
/*
|
||||
Write any dirty sectors back to disc and clear out the contents of the NTFS_CACHE
|
||||
*/
|
||||
bool _NTFS_cache_flush ( NTFS_CACHE* NTFS_CACHE );
|
||||
bool _NTFS_cache_flush (NTFS_CACHE* NTFS_CACHE);
|
||||
|
||||
/*
|
||||
Clear out the contents of the NTFS_CACHE without writing any dirty sectors first
|
||||
*/
|
||||
void _NTFS_cache_invalidate ( NTFS_CACHE* NTFS_CACHE );
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* NTFS_CACHE);
|
||||
|
||||
NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize );
|
||||
NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize);
|
||||
|
||||
void _NTFS_cache_destructor ( NTFS_CACHE* NTFS_CACHE );
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* NTFS_CACHE);
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
||||
|
@ -52,23 +52,22 @@
|
||||
*
|
||||
* 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 )
|
||||
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;
|
||||
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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,32 +82,30 @@ static int ntfs_collate_binary( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
*
|
||||
* 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 )
|
||||
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;
|
||||
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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,43 +114,39 @@ static int ntfs_collate_ntofs_ulong( ntfs_volume *vol __attribute__( ( unused )
|
||||
* Returns: -1, 0 or 1 depending of how the arrays compare
|
||||
*/
|
||||
|
||||
static int ntfs_collate_ntofs_ulongs( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
int len;
|
||||
const le32 *p1, *p2;
|
||||
u32 d1, d2;
|
||||
int rc;
|
||||
int len;
|
||||
const le32 *p1, *p2;
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
|
||||
{
|
||||
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
len = data1_len;
|
||||
do
|
||||
{
|
||||
d1 = le32_to_cpup( p1 );
|
||||
p1++;
|
||||
d2 = le32_to_cpup( p2 );
|
||||
p2++;
|
||||
}
|
||||
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
||||
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_log_trace("Entering.\n");
|
||||
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
||||
ntfs_log_error("data1_len or data2_len not valid\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = (const le32*)data1;
|
||||
p2 = (const le32*)data2;
|
||||
len = data1_len;
|
||||
do {
|
||||
d1 = le32_to_cpup(p1);
|
||||
p1++;
|
||||
d2 = le32_to_cpup(p2);
|
||||
p2++;
|
||||
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,49 +162,45 @@ static int ntfs_collate_ntofs_ulongs( ntfs_volume *vol __attribute__( ( unused )
|
||||
*
|
||||
* Returns: -1, 0 or 1 depending of how the keys compare
|
||||
*/
|
||||
static int ntfs_collate_ntofs_security_hash( ntfs_volume *vol __attribute__( ( unused ) ),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len )
|
||||
static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
const le32 *p1, *p2;
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
const le32 *p1, *p2;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
if ( data1_len != data2_len || data1_len != 8 )
|
||||
{
|
||||
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = ( const le32* )data1;
|
||||
p2 = ( const le32* )data2;
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
{
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup( p1 );
|
||||
d2 = le32_to_cpup( p2 );
|
||||
if ( d1 < d2 )
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
if ( d1 > d2 )
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (data1_len != data2_len || data1_len != 8) {
|
||||
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
p1 = (const le32*)data1;
|
||||
p2 = (const le32*)data2;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else {
|
||||
p1++;
|
||||
p2++;
|
||||
d1 = le32_to_cpup(p1);
|
||||
d2 = le32_to_cpup(p2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 > d2)
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,58 +215,57 @@ static int ntfs_collate_ntofs_security_hash( ntfs_volume *vol __attribute__( ( u
|
||||
*
|
||||
* 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 ) ) )
|
||||
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)))
|
||||
{
|
||||
const FILE_NAME_ATTR *file_name_attr1;
|
||||
const FILE_NAME_ATTR *file_name_attr2;
|
||||
int rc;
|
||||
const FILE_NAME_ATTR *file_name_attr1;
|
||||
const FILE_NAME_ATTR *file_name_attr2;
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace( "Entering.\n" );
|
||||
file_name_attr1 = ( const FILE_NAME_ATTR* )data1;
|
||||
file_name_attr2 = ( const FILE_NAME_ATTR* )data2;
|
||||
rc = ntfs_names_full_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,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len );
|
||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
||||
return rc;
|
||||
ntfs_log_trace("Entering.\n");
|
||||
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
|
||||
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
|
||||
rc = ntfs_names_full_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,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len);
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to appropriate collation function.
|
||||
* Get a pointer to appropriate collation function.
|
||||
*
|
||||
* Returns NULL if the needed function is not implemented
|
||||
* Returns NULL if the needed function is not implemented
|
||||
*/
|
||||
|
||||
COLLATE ntfs_get_collate_function( COLLATION_RULES cr )
|
||||
COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
|
||||
{
|
||||
COLLATE collate;
|
||||
COLLATE collate;
|
||||
|
||||
switch ( cr )
|
||||
{
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
case COLLATION_FILE_NAME :
|
||||
collate = ntfs_collate_file_name;
|
||||
break;
|
||||
case COLLATION_NTOFS_SECURITY_HASH :
|
||||
collate = ntfs_collate_ntofs_security_hash;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONG :
|
||||
collate = ntfs_collate_ntofs_ulong;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONGS :
|
||||
collate = ntfs_collate_ntofs_ulongs;
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
collate = ( COLLATE )NULL;
|
||||
break;
|
||||
}
|
||||
return ( collate );
|
||||
switch (cr) {
|
||||
case COLLATION_BINARY :
|
||||
collate = ntfs_collate_binary;
|
||||
break;
|
||||
case COLLATION_FILE_NAME :
|
||||
collate = ntfs_collate_file_name;
|
||||
break;
|
||||
case COLLATION_NTOFS_SECURITY_HASH :
|
||||
collate = ntfs_collate_ntofs_security_hash;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONG :
|
||||
collate = ntfs_collate_ntofs_ulong;
|
||||
break;
|
||||
case COLLATION_NTOFS_ULONGS :
|
||||
collate = ntfs_collate_ntofs_ulongs;
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
collate = (COLLATE)NULL;
|
||||
break;
|
||||
}
|
||||
return (collate);
|
||||
}
|
||||
|
@ -29,6 +29,6 @@
|
||||
|
||||
#define NTFS_COLLATION_ERROR -2
|
||||
|
||||
extern COLLATE ntfs_get_collate_function( COLLATION_RULES );
|
||||
extern COLLATE ntfs_get_collate_function(COLLATION_RULES);
|
||||
|
||||
#endif /* _NTFS_COLLATE_H */
|
||||
|
@ -35,38 +35,33 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ffs( int x )
|
||||
int ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
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;
|
||||
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 */
|
||||
|
||||
@ -87,7 +82,7 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -99,8 +94,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
@ -125,37 +120,34 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
int daemon( int nochdir, int noclose )
|
||||
{
|
||||
int fd;
|
||||
int daemon(int nochdir, int noclose) {
|
||||
int fd;
|
||||
|
||||
switch ( fork() )
|
||||
{
|
||||
case -1:
|
||||
return ( -1 );
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit( 0 );
|
||||
}
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if ( setsid() == -1 )
|
||||
return ( -1 );
|
||||
if (setsid() == -1)
|
||||
return (-1);
|
||||
|
||||
if ( !nochdir )
|
||||
( void )chdir( "/" );
|
||||
if (!nochdir)
|
||||
(void)chdir("/");
|
||||
|
||||
if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
|
||||
{
|
||||
( void )dup2( fd, 0 );
|
||||
( void )dup2( fd, 1 );
|
||||
( void )dup2( fd, 2 );
|
||||
if ( fd > 2 )
|
||||
( void )close ( fd );
|
||||
}
|
||||
return ( 0 );
|
||||
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
(void)dup2(fd, 0);
|
||||
(void)dup2(fd, 1);
|
||||
(void)dup2(fd, 2);
|
||||
if (fd > 2)
|
||||
(void)close (fd);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
/*
|
||||
* End: src/lib/libresolv2/common/bsd/daemon.c
|
||||
*************************************************************/
|
||||
#endif /* HAVE_DAEMON */
|
||||
@ -177,7 +169,7 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -189,8 +181,8 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
@ -217,7 +209,7 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
|
||||
/*
|
||||
* Get next token from string *stringp, where tokens are possibly-empty
|
||||
* strings separated by characters from delim.
|
||||
* strings separated by characters from delim.
|
||||
*
|
||||
* Writes NULs into the string at *stringp to end tokens.
|
||||
* delim need not remain constant from call to call.
|
||||
@ -226,37 +218,32 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
||||
*
|
||||
* If *stringp is NULL, strsep returns NULL.
|
||||
*/
|
||||
char *strsep( char **stringp, const char *delim )
|
||||
{
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
char *strsep(char **stringp, const char *delim) {
|
||||
char *s;
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
|
||||
if ( ( s = *stringp ) == NULL )
|
||||
return ( NULL );
|
||||
for ( tok = s;; )
|
||||
{
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do
|
||||
{
|
||||
if ( ( sc = *spanp++ ) == c )
|
||||
{
|
||||
if ( c == 0 )
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return ( tok );
|
||||
}
|
||||
}
|
||||
while ( sc != 0 );
|
||||
}
|
||||
/* NOTREACHED */
|
||||
if ((s = *stringp) == NULL)
|
||||
return (NULL);
|
||||
for (tok = s;;) {
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return (tok);
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* End: src/lib/libresolv2/common/bsd/strsep.c
|
||||
*************************************************************/
|
||||
#endif /* HAVE_STRSEP */
|
||||
|
@ -36,38 +36,38 @@
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
extern int ffs( int i );
|
||||
extern int ffs(int i);
|
||||
#endif /* HAVE_FFS */
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon( int nochdir, int noclose );
|
||||
extern int daemon(int nochdir, int noclose);
|
||||
#endif /* HAVE_DAEMON */
|
||||
|
||||
#ifndef HAVE_STRSEP
|
||||
extern char *strsep( char **stringp, const char *delim );
|
||||
extern char *strsep(char **stringp, const char *delim);
|
||||
#endif /* HAVE_STRSEP */
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#define HAVE_STDIO_H /* mimic config.h */
|
||||
#define HAVE_STDIO_H /* mimic config.h */
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#define atoll _atoi64
|
||||
#define fdatasync commit
|
||||
#define __inline__ inline
|
||||
#define __attribute__(X) /*nothing*/
|
||||
#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 */
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
|
||||
#include "mem_allocate.h"
|
||||
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_REPLACE 2
|
||||
|
||||
#define MINORBITS 20
|
||||
@ -75,7 +75,7 @@ extern char *strsep( char **stringp, const char *delim );
|
||||
|
||||
#define major(dev) ((unsigned int) ((dev) >> MINORBITS))
|
||||
#define minor(dev) ((unsigned int) ((dev) & MINORMASK))
|
||||
#define mkdev(ma,mi) (((ma) << MINORBITS) | (mi))
|
||||
#define mkdev(ma,mi) (((ma) << MINORBITS) | (mi))
|
||||
#define random rand
|
||||
|
||||
#endif /* defined GEKKO */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* compress.h - Exports for compressed attribute handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
* compress.h - Exports for compressed attribute handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*
|
||||
@ -26,16 +26,16 @@
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
|
||||
extern s64 ntfs_compressed_attr_pread( ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b );
|
||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b);
|
||||
|
||||
extern s64 ntfs_compressed_pwrite( ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||
s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part,
|
||||
VCN *update_from );
|
||||
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||
s64 offs, s64 to_write, s64 rounded,
|
||||
const void *b, int compressed_part,
|
||||
VCN *update_from);
|
||||
|
||||
extern int ntfs_compressed_close( ntfs_attr *na, runlist_element *brl,
|
||||
s64 offs, VCN *update_from );
|
||||
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
|
||||
s64 offs, VCN *update_from);
|
||||
|
||||
#endif /* defined _NTFS_COMPRESS_H */
|
||||
|
||||
|
@ -42,43 +42,37 @@
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_debug_runlist_dump( const runlist_element *rl )
|
||||
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 "
|
||||
};
|
||||
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;
|
||||
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 (lcn < (LCN)0) {
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if ( idx > -LCN_EINVAL - 1 )
|
||||
idx = 4;
|
||||
ntfs_log_debug( "%-16lld %s %-16lld%s\n",
|
||||
( long long )rl[i].vcn, lcn_str[idx],
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
}
|
||||
else
|
||||
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
||||
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
||||
( long long )rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)" );
|
||||
}
|
||||
while ( rl[i++].length );
|
||||
if (idx > -LCN_EINVAL - 1)
|
||||
idx = 4;
|
||||
ntfs_log_debug("%-16lld %s %-16lld%s\n",
|
||||
(long long)rl[i].vcn, lcn_str[idx],
|
||||
(long long)rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)");
|
||||
} else
|
||||
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
||||
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
||||
(long long)rl[i].length,
|
||||
rl[i].length ? "" : " (runlist end)");
|
||||
} while (rl[i++].length);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -31,17 +31,17 @@
|
||||
struct _runlist_element;
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void ntfs_debug_runlist_dump( const struct _runlist_element *rl );
|
||||
extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
|
||||
#else
|
||||
static __inline__ void ntfs_debug_runlist_dump( const struct _runlist_element *rl __attribute__( ( unused ) ) ) {}
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
|
||||
#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]; \
|
||||
#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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,33 +36,32 @@
|
||||
*
|
||||
* 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. */
|
||||
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 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 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 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 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)
|
||||
#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 -
|
||||
@ -70,13 +69,12 @@ typedef enum
|
||||
* 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 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;
|
||||
@ -87,45 +85,44 @@ struct stat;
|
||||
* 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 );
|
||||
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 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_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_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_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 );
|
||||
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 */
|
||||
|
@ -41,29 +41,28 @@
|
||||
#else /* __CYGWIN32__ */
|
||||
|
||||
#ifndef HDIO_GETGEO
|
||||
# define HDIO_GETGEO 0x301
|
||||
# define HDIO_GETGEO 0x301
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry
|
||||
{
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
#endif
|
||||
#ifndef BLKGETSIZE
|
||||
# define BLKGETSIZE 0x1260
|
||||
# define BLKGETSIZE 0x1260
|
||||
#endif
|
||||
#ifndef BLKSSZGET
|
||||
# define BLKSSZGET 0x1268
|
||||
# define BLKSSZGET 0x1268
|
||||
#endif
|
||||
#ifndef BLKGETSIZE64
|
||||
# define BLKGETSIZE64 0x80041272
|
||||
# define BLKGETSIZE64 0x80041272
|
||||
#endif
|
||||
#ifndef BLKBSZSET
|
||||
# define BLKBSZSET 0x40041271
|
||||
# define BLKBSZSET 0x40041271
|
||||
#endif
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
|
4509
source/libntfs/dir.c
4509
source/libntfs/dir.c
File diff suppressed because it is too large
Load Diff
@ -59,40 +59,40 @@ extern ntfschar NTFS_INDEX_O[3];
|
||||
extern ntfschar NTFS_INDEX_Q[3];
|
||||
extern ntfschar NTFS_INDEX_R[3];
|
||||
|
||||
extern u64 ntfs_inode_lookup_by_name( ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len );
|
||||
extern u64 ntfs_inode_lookup_by_mbsname( ntfs_inode *dir_ni, const char *name );
|
||||
extern void ntfs_inode_update_mbsname( ntfs_inode *dir_ni, const char *name,
|
||||
u64 inum );
|
||||
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len);
|
||||
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
|
||||
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
|
||||
u64 inum);
|
||||
|
||||
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, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type );
|
||||
extern ntfs_inode *ntfs_create_device( ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev );
|
||||
extern ntfs_inode *ntfs_create_symlink( ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len );
|
||||
extern int ntfs_check_empty_dir( ntfs_inode *ni );
|
||||
extern int ntfs_delete( ntfs_volume *vol, const char *path,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_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, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
|
||||
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
||||
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 );
|
||||
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
|
||||
#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
|
||||
@ -100,27 +100,27 @@ extern int ntfs_link( ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
* 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 );
|
||||
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 );
|
||||
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir);
|
||||
|
||||
ntfs_inode *ntfs_dir_parent_inode( ntfs_inode *ni );
|
||||
ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size );
|
||||
int ntfs_set_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags );
|
||||
int ntfs_remove_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni );
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size);
|
||||
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#if CACHE_INODE_SIZE
|
||||
|
||||
struct CACHED_GENERIC;
|
||||
|
||||
extern int ntfs_dir_inode_hash( const struct CACHED_GENERIC *cached );
|
||||
extern int ntfs_dir_lookup_hash( const struct CACHED_GENERIC *cached );
|
||||
extern int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached);
|
||||
extern int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* efs.c - Limited processing of encrypted files
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2009 Martin Bene
|
||||
* Copyright (c) 2009-2010 Jean-Pierre Andre
|
||||
@ -58,305 +58,256 @@
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
static ntfschar logged_utility_stream_name[] =
|
||||
{
|
||||
const_cpu_to_le16( '$' ),
|
||||
const_cpu_to_le16( 'E' ),
|
||||
const_cpu_to_le16( 'F' ),
|
||||
const_cpu_to_le16( 'S' ),
|
||||
const_cpu_to_le16( 0 )
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('E'),
|
||||
const_cpu_to_le16('F'),
|
||||
const_cpu_to_le16('S'),
|
||||
const_cpu_to_le16(0)
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
* Get the ntfs EFS info into an extended attribute
|
||||
* Get the ntfs EFS info into an extended attribute
|
||||
*/
|
||||
|
||||
int ntfs_get_efs_info( ntfs_inode *ni, char *value, size_t size )
|
||||
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
|
||||
{
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
EFS_ATTR_HEADER *efs_info;
|
||||
s64 attr_size = 0;
|
||||
|
||||
if ( ni )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
||||
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
||||
&attr_size );
|
||||
if ( efs_info
|
||||
&& ( le32_to_cpu( efs_info->length ) == attr_size ) )
|
||||
{
|
||||
if ( attr_size <= ( s64 )size )
|
||||
{
|
||||
if ( value )
|
||||
memcpy( value, efs_info, attr_size );
|
||||
else
|
||||
{
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
}
|
||||
else if ( size )
|
||||
{
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free ( efs_info );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( efs_info )
|
||||
{
|
||||
free( efs_info );
|
||||
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_error( "Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
}
|
||||
}
|
||||
return ( attr_size ? ( int )attr_size : -errno );
|
||||
if (ni) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||
&attr_size);
|
||||
if (efs_info
|
||||
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||
if (attr_size <= (s64)size) {
|
||||
if (value)
|
||||
memcpy(value,efs_info,attr_size);
|
||||
else {
|
||||
errno = EFAULT;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else
|
||||
if (size) {
|
||||
errno = ERANGE;
|
||||
attr_size = 0;
|
||||
}
|
||||
free (efs_info);
|
||||
} else {
|
||||
if (efs_info) {
|
||||
free(efs_info);
|
||||
ntfs_log_error("Bad efs_info for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
} else {
|
||||
ntfs_log_error("Could not get efsinfo"
|
||||
" for inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
errno = EIO;
|
||||
attr_size = 0;
|
||||
}
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
}
|
||||
return (attr_size ? (int)attr_size : -errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix all encrypted AT_DATA attributes of an inode
|
||||
* Fix all encrypted AT_DATA attributes of an inode
|
||||
*
|
||||
* The fix may require making an attribute non resident, which
|
||||
* requires more space in the MFT record, and may cause some
|
||||
* attribute to be expelled and the full record to be reorganized.
|
||||
* When this happens, the search for data attributes has to be
|
||||
* reinitialized.
|
||||
* The fix may require making an attribute non resident, which
|
||||
* requires more space in the MFT record, and may cause some
|
||||
* attribute to be expelled and the full record to be reorganized.
|
||||
* When this happens, the search for data attributes has to be
|
||||
* reinitialized.
|
||||
*
|
||||
* Returns zero if successful.
|
||||
* -1 if there is a problem.
|
||||
* Returns zero if successful.
|
||||
* -1 if there is a problem.
|
||||
*/
|
||||
|
||||
static int fixup_loop( ntfs_inode *ni )
|
||||
static int fixup_loop(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_attr *na;
|
||||
ATTR_RECORD *a;
|
||||
BOOL restart;
|
||||
BOOL first;
|
||||
int cnt;
|
||||
int maxcnt;
|
||||
int res = 0;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_attr *na;
|
||||
ATTR_RECORD *a;
|
||||
BOOL restart;
|
||||
BOOL first;
|
||||
int cnt;
|
||||
int maxcnt;
|
||||
int res = 0;
|
||||
|
||||
maxcnt = 0;
|
||||
do
|
||||
{
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while ( !restart && !res
|
||||
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
||||
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
||||
a->name_length );
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "can't open DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
|
||||
{
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
/*
|
||||
* ntfs_attr_make_non_resident fails if there
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if ( ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* make sure there is some progress */
|
||||
if ( cnt <= maxcnt )
|
||||
{
|
||||
errno = EIO;
|
||||
ntfs_log_error( "Multiple failure"
|
||||
" making non resident\n" );
|
||||
res = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
ctx = ( ntfs_attr_search_ctx* )NULL;
|
||||
restart = TRUE;
|
||||
maxcnt = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !restart && !res
|
||||
&& ntfs_efs_fixup_attribute( ctx, na ) )
|
||||
{
|
||||
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
while ( restart && !res );
|
||||
if ( ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return ( res );
|
||||
maxcnt = 0;
|
||||
do {
|
||||
restart = FALSE;
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
res = -1;
|
||||
}
|
||||
cnt = 0;
|
||||
while (!restart && !res
|
||||
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
cnt++;
|
||||
a = ctx->attr;
|
||||
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||
a->name_length);
|
||||
if (!na) {
|
||||
ntfs_log_error("can't open DATA Attribute\n");
|
||||
res = -1;
|
||||
}
|
||||
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
/*
|
||||
* ntfs_attr_make_non_resident fails if there
|
||||
* is not enough space in the MFT record.
|
||||
* When this happens, force making non-resident
|
||||
* so that some other attribute is expelled.
|
||||
*/
|
||||
if (ntfs_attr_force_non_resident(na)) {
|
||||
res = -1;
|
||||
} else {
|
||||
/* make sure there is some progress */
|
||||
if (cnt <= maxcnt) {
|
||||
errno = EIO;
|
||||
ntfs_log_error("Multiple failure"
|
||||
" making non resident\n");
|
||||
res = -1;
|
||||
} else {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
restart = TRUE;
|
||||
maxcnt = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!restart && !res
|
||||
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
||||
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
first = FALSE;
|
||||
} while (restart && !res);
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the efs data from an extended attribute
|
||||
* Warning : the new data is not checked
|
||||
* Returns 0, or -1 if there is a problem
|
||||
* Set the efs data from an extended attribute
|
||||
* Warning : the new data is not checked
|
||||
* Returns 0, or -1 if there is a problem
|
||||
*/
|
||||
|
||||
int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
||||
int flags )
|
||||
|
||||
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
int flags)
|
||||
|
||||
{
|
||||
int res;
|
||||
int written;
|
||||
ntfs_attr *na;
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
int res;
|
||||
int written;
|
||||
ntfs_attr *na;
|
||||
const EFS_ATTR_HEADER *info_header;
|
||||
|
||||
res = 0;
|
||||
if ( ni && value && size )
|
||||
{
|
||||
if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
|
||||
{
|
||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
||||
{
|
||||
ntfs_log_trace( "Inode %lld already encrypted\n",
|
||||
( long long )ni->mft_no );
|
||||
errno = EEXIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
* restored as compressed.
|
||||
* TODO : decompress first.
|
||||
*/
|
||||
ntfs_log_error( "Inode %lld cannot be encrypted and compressed\n",
|
||||
( long long )ni->mft_no );
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if ( le32_to_cpu( info_header->length ) != size )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return ( -1 );
|
||||
}
|
||||
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
( ntfschar* )NULL, 0 ) )
|
||||
{
|
||||
if ( !( flags & XATTR_REPLACE ) )
|
||||
{
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
*/
|
||||
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4,
|
||||
( u8* )NULL, ( s64 )size );
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if ( !res )
|
||||
{
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4 );
|
||||
if ( na )
|
||||
{
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
||||
/* overwrite value if any */
|
||||
if ( !res && value )
|
||||
{
|
||||
written = ( int )ntfs_attr_pwrite( na,
|
||||
( s64 )0, ( s64 )size, value );
|
||||
if ( written != ( s64 )size )
|
||||
{
|
||||
ntfs_log_error( "Failed to "
|
||||
"update efs data\n" );
|
||||
errno = EIO;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close( na );
|
||||
}
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
if ( !res )
|
||||
{
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
if ( fixup_loop( ni ) )
|
||||
return -1;
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return ( res ? -1 : 0 );
|
||||
res = 0;
|
||||
if (ni && value && size) {
|
||||
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||
ntfs_log_trace("Inode %lld already encrypted\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = EEXIST;
|
||||
} else {
|
||||
/*
|
||||
* Possible problem : if encrypted file was
|
||||
* restored in a compressed directory, it was
|
||||
* restored as compressed.
|
||||
* TODO : decompress first.
|
||||
*/
|
||||
ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = EIO;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info_header = (const EFS_ATTR_HEADER*)value;
|
||||
/* make sure we get a likely efsinfo */
|
||||
if (le32_to_cpu(info_header->length) != size) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
(ntfschar*)NULL,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
/*
|
||||
* no logged_utility_stream attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
*/
|
||||
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name,4,
|
||||
(u8*)NULL,(s64)size);
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
errno = EEXIST;
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/*
|
||||
* open and update the existing efs data
|
||||
*/
|
||||
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||
logged_utility_stream_name, 4);
|
||||
if (na) {
|
||||
/* resize attribute */
|
||||
res = ntfs_attr_truncate(na, (s64)size);
|
||||
/* overwrite value if any */
|
||||
if (!res && value) {
|
||||
written = (int)ntfs_attr_pwrite(na,
|
||||
(s64)0, (s64)size, value);
|
||||
if (written != (s64)size) {
|
||||
ntfs_log_error("Failed to "
|
||||
"update efs data\n");
|
||||
errno = EIO;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
if (!res) {
|
||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
/* iterate over AT_DATA attributes */
|
||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||
|
||||
if (fixup_loop(ni))
|
||||
return -1;
|
||||
}
|
||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -364,144 +315,125 @@ int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
||||
* read padding length from last two bytes
|
||||
* truncate attribute, make non-resident,
|
||||
* set data size to match padding length
|
||||
* set ATTR_IS_ENCRYPTED flag on attribute
|
||||
* set ATTR_IS_ENCRYPTED flag on attribute
|
||||
*
|
||||
* Return 0 if successful
|
||||
* -1 if failed (errno tells why)
|
||||
* Return 0 if successful
|
||||
* -1 if failed (errno tells why)
|
||||
*/
|
||||
|
||||
int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na )
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
{
|
||||
u64 newsize;
|
||||
u64 oldsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
u64 newsize;
|
||||
u64 oldsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ntfs_inode *ni;
|
||||
BOOL close_ctx = FALSE;
|
||||
|
||||
if ( !na )
|
||||
{
|
||||
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
if ( !ctx )
|
||||
{
|
||||
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
||||
if ( !ctx )
|
||||
{
|
||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !NAttrNonResident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Cannot make non resident"
|
||||
" when a context has been allocated\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (!na) {
|
||||
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (!ctx) {
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get ctx for efs\n");
|
||||
goto err_out;
|
||||
}
|
||||
close_ctx = TRUE;
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
if (!NAttrNonResident(na)) {
|
||||
ntfs_log_error("Cannot make non resident"
|
||||
" when a context has been allocated\n");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* no extra bytes are added to void attributes */
|
||||
oldsize = na->data_size;
|
||||
if ( oldsize )
|
||||
{
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ( ( oldsize & 511 ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Bad raw encrypted stream\n" );
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
|
||||
{
|
||||
ntfs_log_error( "Error reading padding length\n" );
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu( appended_bytes );
|
||||
if ( padding_length > 511 || padding_length > na->data_size - 2 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
||||
padding_length, ( long long )oldsize );
|
||||
goto err_out;
|
||||
}
|
||||
newsize = oldsize - padding_length - 2;
|
||||
/*
|
||||
* truncate attribute to possibly free clusters allocated
|
||||
* for the last two bytes, but do not truncate to new size
|
||||
* to avoid losing useful data
|
||||
*/
|
||||
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
||||
{
|
||||
ntfs_log_error( "Error truncating attribute\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
newsize = 0;
|
||||
/* no extra bytes are added to void attributes */
|
||||
oldsize = na->data_size;
|
||||
if (oldsize) {
|
||||
/* make sure size is valid for a raw encrypted stream */
|
||||
if ((oldsize & 511) != 2) {
|
||||
ntfs_log_error("Bad raw encrypted stream\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* read padding length from last two bytes of attribute */
|
||||
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
||||
ntfs_log_error("Error reading padding length\n");
|
||||
goto err_out;
|
||||
}
|
||||
padding_length = le16_to_cpu(appended_bytes);
|
||||
if (padding_length > 511 || padding_length > na->data_size-2) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||
padding_length, (long long)oldsize);
|
||||
goto err_out;
|
||||
}
|
||||
newsize = oldsize - padding_length - 2;
|
||||
/*
|
||||
* truncate attribute to possibly free clusters allocated
|
||||
* for the last two bytes, but do not truncate to new size
|
||||
* to avoid losing useful data
|
||||
*/
|
||||
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
||||
ntfs_log_error("Error truncating attribute\n");
|
||||
goto err_out;
|
||||
}
|
||||
} else
|
||||
newsize = 0;
|
||||
|
||||
/*
|
||||
* Encrypted AT_DATA Attributes MUST be non-resident
|
||||
* This has to be done after the attribute is resized, as
|
||||
* resizing down to zero may cause the attribute to be made
|
||||
* resident.
|
||||
*/
|
||||
if ( !NAttrNonResident( na )
|
||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
||||
{
|
||||
if ( !close_ctx
|
||||
|| ntfs_attr_force_non_resident( na ) )
|
||||
{
|
||||
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
||||
goto err_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* non-resident. We need a context for updating
|
||||
* the state, and at this point, we are sure
|
||||
* the context is not used elsewhere.
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx( ctx );
|
||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
||||
{
|
||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if ( !na->name_len )
|
||||
{
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty( ni );
|
||||
NInoFileNameSetDirty( ni );
|
||||
/*
|
||||
* Encrypted AT_DATA Attributes MUST be non-resident
|
||||
* This has to be done after the attribute is resized, as
|
||||
* resizing down to zero may cause the attribute to be made
|
||||
* resident.
|
||||
*/
|
||||
if (!NAttrNonResident(na)
|
||||
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||
if (!close_ctx
|
||||
|| ntfs_attr_force_non_resident(na)) {
|
||||
ntfs_log_error("Error making DATA attribute non-resident\n");
|
||||
goto err_out;
|
||||
} else {
|
||||
/*
|
||||
* must reinitialize context after forcing
|
||||
* non-resident. We need a context for updating
|
||||
* the state, and at this point, we are sure
|
||||
* the context is not used elsewhere.
|
||||
*/
|
||||
ntfs_attr_reinit_search_ctx(ctx);
|
||||
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
ni = na->ni;
|
||||
if (!na->name_len) {
|
||||
ni->data_size = newsize;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
|
||||
ctx->attr->data_size = cpu_to_le64( newsize );
|
||||
if ( le64_to_cpu( ctx->attr->initialized_size ) > newsize )
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if ( close_ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
|
||||
return ( 0 );
|
||||
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if (close_ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
||||
return (0);
|
||||
err_out:
|
||||
if ( close_ctx && ctx )
|
||||
ntfs_attr_put_search_ctx( ctx );
|
||||
return ( -1 );
|
||||
if (close_ctx && ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
@ -21,10 +21,10 @@
|
||||
#ifndef EFS_H
|
||||
#define EFS_H
|
||||
|
||||
int ntfs_get_efs_info( ntfs_inode *ni, char *value, size_t size );
|
||||
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
int ntfs_set_efs_info( ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags );
|
||||
int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na );
|
||||
int ntfs_set_efs_info(ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags);
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na);
|
||||
|
||||
#endif /* EFS_H */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* endians.h - Definitions related to handling of byte ordering.
|
||||
* endians.h - Definitions related to handling of byte ordering.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
@ -29,9 +29,9 @@
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* We define the conversion functions including typecasts since the
|
||||
* 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
|
||||
* 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...
|
||||
*/
|
||||
@ -53,59 +53,59 @@
|
||||
#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
|
||||
# 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_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_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))
|
||||
#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>
|
||||
# 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)
|
||||
# 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)
|
||||
@ -152,52 +152,52 @@
|
||||
|
||||
/* 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_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))
|
||||
#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_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))
|
||||
#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_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))
|
||||
#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_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))
|
||||
#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_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)
|
||||
#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 */
|
||||
|
@ -66,93 +66,83 @@
|
||||
#define DEV_FD(dev) ((gekko_fd *)dev->d_private)
|
||||
|
||||
/* Prototypes */
|
||||
static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset, s64 count, void *buf );
|
||||
static bool ntfs_device_gekko_io_readsectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer );
|
||||
static s64 ntfs_device_gekko_io_writebytes( struct ntfs_device *dev, s64 offset, s64 count, const void *buf );
|
||||
static bool ntfs_device_gekko_io_writesectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer );
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf);
|
||||
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer);
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf);
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_open( struct ntfs_device *dev, int flags )
|
||||
static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, flags %i\n", dev, flags );
|
||||
ntfs_log_trace("dev %p, flags %i\n", dev, flags);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if ( !interface )
|
||||
{
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Start the device interface and ensure that it is inserted
|
||||
if ( !interface->startup() )
|
||||
{
|
||||
ntfs_log_perror( "device failed to start\n" );
|
||||
if (!interface->startup()) {
|
||||
ntfs_log_perror("device failed to start\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
ntfs_log_perror( "device media is not inserted\n" );
|
||||
if (!interface->isInserted()) {
|
||||
ntfs_log_perror("device media is not inserted\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device isn't already open (used by another volume?)
|
||||
if ( NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is busy (already open)\n" );
|
||||
if (NDevOpen(dev)) {
|
||||
ntfs_log_perror("device is busy (already open)\n");
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that there is a valid NTFS boot sector at the start of the device
|
||||
NTFS_BOOT_SECTOR boot;
|
||||
if ( interface->readSectors( fd->startSector, 1, &boot ) )
|
||||
{
|
||||
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
|
||||
{
|
||||
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
||||
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
||||
errno = EINVALPART;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
||||
} else {
|
||||
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse the boot sector
|
||||
fd->hiddenSectors = le32_to_cpu( boot.bpb.hidden_sectors );
|
||||
fd->sectorSize = le16_to_cpu( boot.bpb.bytes_per_sector );
|
||||
fd->sectorCount = sle64_to_cpu( boot.number_of_sectors );
|
||||
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
|
||||
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
|
||||
fd->sectorCount = sle64_to_cpu(boot.number_of_sectors);
|
||||
fd->pos = 0;
|
||||
fd->len = ( fd->sectorCount * fd->sectorSize );
|
||||
fd->ino = le64_to_cpu( boot.volume_serial_number );
|
||||
fd->len = (fd->sectorCount * fd->sectorSize);
|
||||
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
||||
|
||||
// Mark the device as read-only (if required)
|
||||
if ( flags & O_RDONLY )
|
||||
{
|
||||
NDevSetReadOnly( dev );
|
||||
if (flags & O_RDONLY) {
|
||||
NDevSetReadOnly(dev);
|
||||
}
|
||||
|
||||
// Create the cache
|
||||
fd->cache = _NTFS_cache_constructor( fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize );
|
||||
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize);
|
||||
|
||||
// Mark the device as open
|
||||
NDevSetBlock( dev );
|
||||
NDevSetOpen( dev );
|
||||
NDevSetBlock(dev);
|
||||
NDevSetOpen(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -160,47 +150,43 @@ static int ntfs_device_gekko_io_open( struct ntfs_device *dev, int flags )
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_close( struct ntfs_device *dev )
|
||||
static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
{
|
||||
ntfs_log_trace( "dev %p\n", dev );
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device is actually open
|
||||
if ( !NDevOpen( dev ) )
|
||||
{
|
||||
ntfs_log_perror( "device is not open\n" );
|
||||
if (!NDevOpen(dev)) {
|
||||
ntfs_log_perror("device is not open\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mark the device as closed
|
||||
NDevClearOpen( dev );
|
||||
NDevClearBlock( dev );
|
||||
NDevClearOpen(dev);
|
||||
NDevClearBlock(dev);
|
||||
|
||||
// Flush the device (if dirty and not read-only)
|
||||
if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
|
||||
{
|
||||
ntfs_log_debug( "device is dirty, will now sync\n" );
|
||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
||||
ntfs_log_debug("device is dirty, will now sync\n");
|
||||
|
||||
// ...?
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty( dev );
|
||||
NDevClearDirty(dev);
|
||||
|
||||
}
|
||||
|
||||
// Flush and destroy the cache (if required)
|
||||
if ( fd->cache )
|
||||
{
|
||||
_NTFS_cache_flush( fd->cache );
|
||||
_NTFS_cache_destructor( fd->cache );
|
||||
if (fd->cache) {
|
||||
_NTFS_cache_flush(fd->cache);
|
||||
_NTFS_cache_destructor(fd->cache);
|
||||
}
|
||||
|
||||
// Shutdown the device interface
|
||||
@ -210,7 +196,7 @@ static int ntfs_device_gekko_io_close( struct ntfs_device *dev )
|
||||
}*/
|
||||
|
||||
// Free the device driver private data
|
||||
ntfs_free( dev->d_private );
|
||||
ntfs_free(dev->d_private);
|
||||
dev->d_private = NULL;
|
||||
|
||||
return 0;
|
||||
@ -219,24 +205,22 @@ static int ntfs_device_gekko_io_close( struct ntfs_device *dev )
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_seek( struct ntfs_device *dev, s64 offset, int whence )
|
||||
static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int whence)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, offset %Li, whence %i\n", dev, offset, whence );
|
||||
ntfs_log_trace("dev %p, offset %Li, whence %i\n", dev, offset, whence);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the current position on the device (in bytes)
|
||||
switch ( whence )
|
||||
{
|
||||
case SEEK_SET: fd->pos = MIN( MAX( offset, 0 ), fd->len ); break;
|
||||
case SEEK_CUR: fd->pos = MIN( MAX( fd->pos + offset, 0 ), fd->len ); break;
|
||||
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
||||
switch(whence) {
|
||||
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
||||
case SEEK_CUR: fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len); break;
|
||||
case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -245,123 +229,115 @@ static s64 ntfs_device_gekko_io_seek( struct ntfs_device *dev, s64 offset, int w
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_read( struct ntfs_device *dev, void *buf, s64 count )
|
||||
static s64 ntfs_device_gekko_io_read(struct ntfs_device *dev, void *buf, s64 count)
|
||||
{
|
||||
return ntfs_device_gekko_io_readbytes( dev, DEV_FD( dev )->pos, count, buf );
|
||||
return ntfs_device_gekko_io_readbytes(dev, DEV_FD(dev)->pos, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_write( struct ntfs_device *dev, const void *buf, s64 count )
|
||||
static s64 ntfs_device_gekko_io_write(struct ntfs_device *dev, const void *buf, s64 count)
|
||||
{
|
||||
return ntfs_device_gekko_io_writebytes( dev, DEV_FD( dev )->pos, count, buf );
|
||||
return ntfs_device_gekko_io_writebytes(dev, DEV_FD(dev)->pos, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_pread( struct ntfs_device *dev, void *buf, s64 count, s64 offset )
|
||||
static s64 ntfs_device_gekko_io_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset)
|
||||
{
|
||||
return ntfs_device_gekko_io_readbytes( dev, offset, count, buf );
|
||||
return ntfs_device_gekko_io_readbytes(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_pwrite( struct ntfs_device *dev, const void *buf, s64 count, s64 offset )
|
||||
static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
|
||||
{
|
||||
return ntfs_device_gekko_io_writebytes( dev, offset, count, buf );
|
||||
return ntfs_device_gekko_io_writebytes(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset, s64 count, void *buf )
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, offset %Li, count %Li\n", dev, offset, count );
|
||||
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if ( !interface )
|
||||
{
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( offset < 0 )
|
||||
if(offset < 0)
|
||||
{
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( !count )
|
||||
if(!count)
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
||||
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this read
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
if (offset > 0) {
|
||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||
}
|
||||
if ( buffer_offset + count > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
if (buffer_offset+count > fd->sectorSize) {
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
||||
}
|
||||
|
||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||
|
||||
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||
{
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace( "direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Else read into a buffer and copy over only what was requested
|
||||
// Else read into a buffer and copy over only what was requested
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
|
||||
// Allocate a buffer to hold the read data
|
||||
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if ( !buffer )
|
||||
{
|
||||
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_log_trace( "count: %d sec_count:%d fd->sectorSize: %d )\n", ( u32 )count, ( u32 )sec_count, ( u32 )fd->sectorSize );
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_free( buffer );
|
||||
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy what was requested to the destination buffer
|
||||
memcpy( buf, buffer + buffer_offset, count );
|
||||
ntfs_free( buffer );
|
||||
memcpy(buf, buffer + buffer_offset, count);
|
||||
ntfs_free(buffer);
|
||||
|
||||
}
|
||||
|
||||
@ -371,159 +347,146 @@ static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_writebytes( struct ntfs_device *dev, s64 offset, s64 count, const void *buf )
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, offset %lli, count %lli\n", dev, offset, count );
|
||||
ntfs_log_trace("dev %p, offset %lli, count %lli\n", dev, offset, count);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if ( !interface )
|
||||
{
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the device can be written to
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( count < 0 || offset < 0 )
|
||||
{
|
||||
if(count < 0 || offset < 0) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( count == 0 )
|
||||
if(count == 0)
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
||||
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this write
|
||||
if ( offset > 0 )
|
||||
{
|
||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
||||
if (offset > 0) {
|
||||
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||
}
|
||||
if ( ( buffer_offset + count ) > fd->sectorSize )
|
||||
{
|
||||
sec_count = ( sec_t ) ceil( ( f64 ) ( buffer_offset + count ) / ( f64 ) fd->sectorSize );
|
||||
if ((buffer_offset+count) > fd->sectorSize) {
|
||||
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
||||
}
|
||||
|
||||
// If this write happens to be on the sector boundaries then do the write straight to disc
|
||||
if ( ( buffer_offset == 0 ) && ( count % fd->sectorSize == 0 ) )
|
||||
if((buffer_offset == 0) && (count % fd->sectorSize == 0))
|
||||
{
|
||||
// Write to the device
|
||||
ntfs_log_trace( "direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buf ) )
|
||||
{
|
||||
ntfs_log_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
||||
ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
// Else write from a buffer aligned to the sector boundaries
|
||||
// Else write from a buffer aligned to the sector boundaries
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocate a buffer to hold the write data
|
||||
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
||||
if ( !buffer )
|
||||
{
|
||||
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
// Read the first and last sectors of the buffer from disc (if required)
|
||||
// NOTE: This is done because the data does not line up with the sector boundaries,
|
||||
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
||||
if ( buffer_offset != 0 )
|
||||
if(buffer_offset != 0)
|
||||
{
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start, 1, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ( ( buffer_offset + count ) % fd->sectorSize != 0 )
|
||||
if((buffer_offset+count) % fd->sectorSize != 0)
|
||||
{
|
||||
if ( !ntfs_device_gekko_io_readsectors( dev, sec_start + sec_count - 1, 1, buffer + ( ( sec_count - 1 ) * fd->sectorSize ) ) )
|
||||
{
|
||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
||||
ntfs_free( buffer );
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the data into the write buffer
|
||||
memcpy( buffer + buffer_offset, buf, count );
|
||||
memcpy(buffer + buffer_offset, buf, count);
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
||||
if ( !ntfs_device_gekko_io_writesectors( dev, sec_start, sec_count, buffer ) )
|
||||
{
|
||||
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
||||
ntfs_free( buffer );
|
||||
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free the buffer
|
||||
ntfs_free( buffer );
|
||||
ntfs_free(buffer);
|
||||
}
|
||||
|
||||
// Mark the device as dirty (if we actually wrote anything)
|
||||
NDevSetDirty( dev );
|
||||
NDevSetDirty(dev);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool ntfs_device_gekko_io_readsectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer )
|
||||
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer)
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
// Read the sectors from disc (or cache, if enabled)
|
||||
if ( fd->cache )
|
||||
return _NTFS_cache_readSectors( fd->cache, sector, numSectors, buffer );
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->readSectors( sector, numSectors, buffer );
|
||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ntfs_device_gekko_io_writesectors( struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer )
|
||||
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
{
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the sectors to disc (or cache, if enabled)
|
||||
if ( fd->cache )
|
||||
return _NTFS_cache_writeSectors( fd->cache, sector, numSectors, buffer );
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->writeSectors( sector, numSectors, buffer );
|
||||
return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -531,26 +494,23 @@ static bool ntfs_device_gekko_io_writesectors( struct ntfs_device *dev, sec_t se
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_sync( struct ntfs_device *dev )
|
||||
static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
{
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
ntfs_log_trace( "dev %p\n", dev );
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
|
||||
// Check that the device can be written to
|
||||
if ( NDevReadOnly( dev ) )
|
||||
{
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty( dev );
|
||||
NDevClearDirty(dev);
|
||||
|
||||
// Flush any sectors in the disc cache (if required)
|
||||
if ( fd->cache )
|
||||
{
|
||||
if ( !_NTFS_cache_flush( fd->cache ) )
|
||||
{
|
||||
if (fd->cache) {
|
||||
if (!_NTFS_cache_flush(fd->cache)) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
@ -562,29 +522,28 @@ static int ntfs_device_gekko_io_sync( struct ntfs_device *dev )
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_stat( struct ntfs_device *dev, struct stat *buf )
|
||||
static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, buf %p\n", dev, buf );
|
||||
ntfs_log_trace("dev %p, buf %p\n", dev, buf);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if ( !buf )
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
// Build the device mode
|
||||
mode_t mode = ( S_IFBLK ) |
|
||||
( S_IRUSR | S_IRGRP | S_IROTH ) |
|
||||
( ( !NDevReadOnly( dev ) ) ? ( S_IWUSR | S_IWGRP | S_IWOTH ) : 0 );
|
||||
mode_t mode = (S_IFBLK) |
|
||||
(S_IRUSR | S_IRGRP | S_IROTH) |
|
||||
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset( buf, 0, sizeof( struct stat ) );
|
||||
memset(buf, 0, sizeof(struct stat));
|
||||
|
||||
// Build the device stats
|
||||
buf->st_dev = fd->interface->ioType;
|
||||
@ -600,79 +559,71 @@ static int ntfs_device_gekko_io_stat( struct ntfs_device *dev, struct stat *buf
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int ntfs_device_gekko_io_ioctl( struct ntfs_device *dev, int request, void *argp )
|
||||
static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void *argp)
|
||||
{
|
||||
ntfs_log_trace( "dev %p, request %i, argp %p\n", dev, request, argp );
|
||||
ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD( dev );
|
||||
if ( !fd )
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out which i/o control was requested
|
||||
switch ( request )
|
||||
{
|
||||
switch (request) {
|
||||
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE:
|
||||
{
|
||||
*( u32* )argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE: {
|
||||
*(u32*)argp = fd->sectorCount;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
geo->cylinders = 0;
|
||||
geo->start = fd->hiddenSectors;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||
geo->sectors = 0;
|
||||
geo->heads = 0;
|
||||
geo->cylinders = 0;
|
||||
geo->start = fd->hiddenSectors;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET:
|
||||
{
|
||||
*( int* )argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
*(int*)argp = fd->sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET:
|
||||
{
|
||||
int sectorSize = *( int* )argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
int sectorSize = *(int*)argp;
|
||||
fd->sectorSize = sectorSize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default:
|
||||
{
|
||||
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -682,8 +633,7 @@ static int ntfs_device_gekko_io_ioctl( struct ntfs_device *dev, int request, voi
|
||||
/**
|
||||
* Device operations for working with gekko style devices and files.
|
||||
*/
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops =
|
||||
{
|
||||
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
||||
.open = ntfs_device_gekko_io_open,
|
||||
.close = ntfs_device_gekko_io_close,
|
||||
.seek = ntfs_device_gekko_io_seek,
|
||||
|
@ -33,8 +33,7 @@
|
||||
/**
|
||||
* gekko_fd - Gekko device driver descriptor
|
||||
*/
|
||||
typedef struct _gekko_fd
|
||||
{
|
||||
typedef struct _gekko_fd {
|
||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||
sec_t startSector; /* LBA of partition start */
|
||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@
|
||||
* ... code requiring gcc 2.8 or later ...
|
||||
* #endif
|
||||
* Note - they won't work for gcc1 or glibc1, since the _MINOR macros
|
||||
* were not defined then.
|
||||
* were not defined then.
|
||||
*/
|
||||
|
||||
#ifndef __GNUC_PREREQ
|
||||
@ -61,31 +61,31 @@
|
||||
|
||||
#define VCN_INDEX_ROOT_PARENT ((VCN)-2)
|
||||
|
||||
#define MAX_PARENT_VCN 32
|
||||
#define MAX_PARENT_VCN 32
|
||||
|
||||
typedef int ( *COLLATE )( ntfs_volume *vol, const void *data1, int len1,
|
||||
const void *data2, int len2 );
|
||||
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||
const void *data2, int len2);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @parent_pos: parent entries' positions in the index block
|
||||
* @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT
|
||||
* @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
|
||||
* @parent_pos: parent entries' positions in the index block
|
||||
* @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT
|
||||
* @new_vcn: new VCN if we need to create a new index block
|
||||
* @median: move to the parent if splitting index blocks
|
||||
* @ib_dirty: TRUE if index block was changed
|
||||
* @block_size: index block size
|
||||
* @vcn_size_bits: VCN size bits for this index block
|
||||
* @median: move to the parent if splitting index blocks
|
||||
* @ib_dirty: TRUE if index block was changed
|
||||
* @block_size: index block size
|
||||
* @vcn_size_bits: VCN size bits for this index block
|
||||
*
|
||||
* @ni is the inode this context belongs to.
|
||||
*
|
||||
@ -112,57 +112,56 @@ typedef int ( *COLLATE )( ntfs_volume *vol, const void *data1, int len1,
|
||||
* 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;
|
||||
COLLATE collate;
|
||||
BOOL is_in_root;
|
||||
INDEX_ROOT *ir;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
INDEX_BLOCK *ib;
|
||||
ntfs_attr *ia_na;
|
||||
int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
|
||||
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
|
||||
int pindex; /* maximum it's the number of the parent nodes */
|
||||
BOOL ib_dirty;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
typedef struct {
|
||||
ntfs_inode *ni;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
INDEX_ENTRY *entry;
|
||||
void *data;
|
||||
u16 data_len;
|
||||
COLLATE collate;
|
||||
BOOL is_in_root;
|
||||
INDEX_ROOT *ir;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
INDEX_BLOCK *ib;
|
||||
ntfs_attr *ia_na;
|
||||
int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
|
||||
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
|
||||
int pindex; /* maximum it's the number of the parent nodes */
|
||||
BOOL ib_dirty;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
||||
extern ntfs_index_context *ntfs_index_ctx_get( ntfs_inode *ni,
|
||||
ntfschar *name, u32 name_len );
|
||||
extern void ntfs_index_ctx_put( ntfs_index_context *ictx );
|
||||
extern void ntfs_index_ctx_reinit( ntfs_index_context *ictx );
|
||||
extern 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 ) __attribute_warn_unused_result__;
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||
|
||||
extern INDEX_ENTRY *ntfs_index_next( INDEX_ENTRY *ie,
|
||||
ntfs_index_context *ictx );
|
||||
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
||||
ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_add_filename( ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref );
|
||||
extern int ntfs_index_remove( ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
const void *key, const int keylen );
|
||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref);
|
||||
extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
const void *key, const int keylen);
|
||||
|
||||
extern INDEX_ROOT *ntfs_index_root_get( ntfs_inode *ni, ATTR_RECORD *attr );
|
||||
extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
|
||||
extern VCN ntfs_ie_get_vcn( INDEX_ENTRY *ie );
|
||||
extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie);
|
||||
|
||||
extern void ntfs_index_entry_mark_dirty( ntfs_index_context *ictx );
|
||||
extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
|
||||
|
||||
extern char *ntfs_ie_filename_get( INDEX_ENTRY *ie );
|
||||
extern void ntfs_ie_filename_dump( INDEX_ENTRY *ie );
|
||||
extern void ntfs_ih_filename_dump( INDEX_HEADER *ih );
|
||||
extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ih_filename_dump(INDEX_HEADER *ih);
|
||||
|
||||
/* the following was added by JPA for use in security.c */
|
||||
extern int ntfs_ie_add( ntfs_index_context *icx, INDEX_ENTRY *ie );
|
||||
extern int ntfs_index_rm( ntfs_index_context *icx );
|
||||
extern int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie);
|
||||
extern int ntfs_index_rm(ntfs_index_context *icx);
|
||||
|
||||
#endif /* _NTFS_INDEX_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -40,63 +40,62 @@ typedef struct _ntfs_inode ntfs_inode;
|
||||
* 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. */
|
||||
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. */
|
||||
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
||||
NI_TimesSet, /* 1: Use times which were set */
|
||||
NI_KnownSize, /* 1: Set if sizes are meaningful */
|
||||
/* 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. */
|
||||
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
|
||||
NI_TimesSet, /* 1: Use times which were set */
|
||||
NI_KnownSize, /* 1: Set if sizes are meaningful */
|
||||
} 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_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 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 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 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_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 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 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)
|
||||
#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.
|
||||
@ -104,123 +103,120 @@ typedef enum
|
||||
* 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. */
|
||||
};
|
||||
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. */
|
||||
};
|
||||
|
||||
/* Below fields are valid only for base inode. */
|
||||
/* Below fields are valid only for base inode. */
|
||||
|
||||
/*
|
||||
* These two fields are used to sync filename index and guaranteed to be
|
||||
* correct, however value in index itself maybe wrong (windows itself
|
||||
* do not update them properly).
|
||||
* For directories, they hold the index size, provided the
|
||||
* flag KnownSize is set.
|
||||
*/
|
||||
s64 data_size; /* Data size of unnamed DATA attribute
|
||||
(or INDEX_ROOT for directories) */
|
||||
s64 allocated_size; /* Allocated size stored in the filename
|
||||
index. (NOTE: Equal to allocated size of
|
||||
the unnamed data attribute for normal or
|
||||
encrypted files and to compressed size
|
||||
of the unnamed data attribute for sparse or
|
||||
compressed files.) */
|
||||
/*
|
||||
* These two fields are used to sync filename index and guaranteed to be
|
||||
* correct, however value in index itself maybe wrong (windows itself
|
||||
* do not update them properly).
|
||||
* For directories, they hold the index size, provided the
|
||||
* flag KnownSize is set.
|
||||
*/
|
||||
s64 data_size; /* Data size of unnamed DATA attribute
|
||||
(or INDEX_ROOT for directories) */
|
||||
s64 allocated_size; /* Allocated size stored in the filename
|
||||
index. (NOTE: Equal to allocated size of
|
||||
the unnamed data attribute for normal or
|
||||
encrypted files and to compressed size
|
||||
of the unnamed data attribute for sparse or
|
||||
compressed files.) */
|
||||
|
||||
/*
|
||||
* These four fields are copy of relevant fields from
|
||||
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
|
||||
* attribute in the index.
|
||||
*/
|
||||
ntfs_time creation_time;
|
||||
ntfs_time last_data_change_time;
|
||||
ntfs_time last_mft_change_time;
|
||||
ntfs_time last_access_time;
|
||||
/* NTFS 3.x extensions added by JPA */
|
||||
/* only if NI_v3_Extensions is set in state */
|
||||
le32 owner_id;
|
||||
le32 security_id;
|
||||
le64 quota_charged;
|
||||
le64 usn;
|
||||
/*
|
||||
* These four fields are copy of relevant fields from
|
||||
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
|
||||
* attribute in the index.
|
||||
*/
|
||||
ntfs_time creation_time;
|
||||
ntfs_time last_data_change_time;
|
||||
ntfs_time last_mft_change_time;
|
||||
ntfs_time last_access_time;
|
||||
/* NTFS 3.x extensions added by JPA */
|
||||
/* only if NI_v3_Extensions is set in state */
|
||||
le32 owner_id;
|
||||
le32 security_id;
|
||||
le64 quota_charged;
|
||||
le64 usn;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NTFS_UPDATE_ATIME = 1 << 0,
|
||||
NTFS_UPDATE_MTIME = 1 << 1,
|
||||
NTFS_UPDATE_CTIME = 1 << 2,
|
||||
typedef enum {
|
||||
NTFS_UPDATE_ATIME = 1 << 0,
|
||||
NTFS_UPDATE_MTIME = 1 << 1,
|
||||
NTFS_UPDATE_CTIME = 1 << 2,
|
||||
} ntfs_time_update_flags;
|
||||
|
||||
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
|
||||
#define NTFS_UPDATE_AMCTIME (NTFS_UPDATE_ATIME | NTFS_UPDATE_MCTIME)
|
||||
|
||||
extern ntfs_inode *ntfs_inode_base( ntfs_inode *ni );
|
||||
extern ntfs_inode *ntfs_inode_base(ntfs_inode *ni);
|
||||
|
||||
extern ntfs_inode *ntfs_inode_allocate( ntfs_volume *vol );
|
||||
extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);
|
||||
|
||||
extern ntfs_inode *ntfs_inode_open( ntfs_volume *vol, const MFT_REF mref );
|
||||
extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);
|
||||
|
||||
extern int ntfs_inode_close( ntfs_inode *ni );
|
||||
extern int ntfs_inode_close_in_dir( ntfs_inode *ni, ntfs_inode *dir_ni );
|
||||
extern int ntfs_inode_close(ntfs_inode *ni);
|
||||
extern int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#if CACHE_NIDATA_SIZE
|
||||
|
||||
struct CACHED_GENERIC;
|
||||
|
||||
extern int ntfs_inode_real_close( ntfs_inode *ni );
|
||||
extern void ntfs_inode_invalidate( ntfs_volume *vol, const MFT_REF mref );
|
||||
extern void ntfs_inode_nidata_free( const struct CACHED_GENERIC *cached );
|
||||
extern int ntfs_inode_nidata_hash( const struct CACHED_GENERIC *item );
|
||||
extern int ntfs_inode_real_close(ntfs_inode *ni);
|
||||
extern void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref);
|
||||
extern void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached);
|
||||
extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
extern ntfs_inode *ntfs_extent_inode_open( ntfs_inode *base_ni,
|
||||
const MFT_REF mref );
|
||||
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 );
|
||||
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
|
||||
|
||||
extern void ntfs_inode_mark_dirty( ntfs_inode *ni );
|
||||
extern void ntfs_inode_mark_dirty(ntfs_inode *ni);
|
||||
|
||||
extern void ntfs_inode_update_times( ntfs_inode *ni, ntfs_time_update_flags mask );
|
||||
extern void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask);
|
||||
|
||||
extern int ntfs_inode_sync( ntfs_inode *ni );
|
||||
extern int ntfs_inode_sync(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_inode_add_attrlist( 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_free_space(ntfs_inode *ni, int size);
|
||||
|
||||
extern int ntfs_inode_badclus_bad( u64 mft_no, ATTR_RECORD *a );
|
||||
extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
|
||||
|
||||
extern int ntfs_inode_get_times( ntfs_inode *ni, char *value, size_t size );
|
||||
extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
extern int ntfs_inode_set_times( ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags );
|
||||
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
|
||||
/* debugging */
|
||||
#define debug_double_inode(num, type)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* lcnalloc.h - Exports for cluster (de)allocation. Originated from the Linux-NTFS
|
||||
* project.
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
@ -31,22 +31,21 @@
|
||||
/**
|
||||
* 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. */
|
||||
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 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_basic( ntfs_volume *vol, s64 lcn, s64 count );
|
||||
extern int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl);
|
||||
extern int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count);
|
||||
|
||||
extern int ntfs_cluster_free( ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
||||
s64 count );
|
||||
extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
||||
s64 count);
|
||||
|
||||
#endif /* defined _NTFS_LCNALLOC_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,69 +52,66 @@
|
||||
*/
|
||||
|
||||
/* Some $LogFile related constants. */
|
||||
#define MaxLogFileSize 0x100000000ULL
|
||||
#define DefaultLogPageSize 4096
|
||||
#define MinLogRecordPages 48
|
||||
#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. */
|
||||
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;
|
||||
/* 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
|
||||
#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__ ) );
|
||||
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;
|
||||
|
||||
@ -125,141 +122,139 @@ typedef le16 RESTART_AREA_FLAGS;
|
||||
* 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;
|
||||
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.
|
||||
@ -267,42 +262,40 @@ typedef struct
|
||||
* 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;
|
||||
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.
|
||||
@ -312,98 +305,90 @@ typedef struct
|
||||
* 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. */
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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 );
|
||||
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 */
|
||||
|
@ -63,35 +63,33 @@ static int tab;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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 BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||
struct ntfs_logging {
|
||||
u32 levels;
|
||||
u32 flags;
|
||||
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||
};
|
||||
|
||||
/**
|
||||
* ntfs_log
|
||||
* This struct controls all the logging within the library and tools.
|
||||
*/
|
||||
static struct ntfs_logging ntfs_log =
|
||||
{
|
||||
static struct ntfs_logging ntfs_log = {
|
||||
#ifdef DEBUG
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||
NTFS_LOG_LEVEL_LEAVE |
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||
NTFS_LOG_LEVEL_LEAVE |
|
||||
#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_PROGRESS,
|
||||
NTFS_LOG_FLAG_ONLYNAME,
|
||||
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
|
||||
NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
|
||||
NTFS_LOG_LEVEL_PROGRESS,
|
||||
NTFS_LOG_FLAG_ONLYNAME,
|
||||
#ifdef DEBUG
|
||||
ntfs_log_handler_outerr
|
||||
ntfs_log_handler_outerr
|
||||
#else
|
||||
ntfs_log_handler_null
|
||||
ntfs_log_handler_null
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -103,43 +101,43 @@ static struct ntfs_logging ntfs_log =
|
||||
*
|
||||
* Returns: Log levels in a 32-bit field
|
||||
*/
|
||||
u32 ntfs_log_get_levels( void )
|
||||
u32 ntfs_log_get_levels(void)
|
||||
{
|
||||
return ntfs_log.levels;
|
||||
return ntfs_log.levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_set_levels - Enable extra logging levels
|
||||
* @levels: 32-bit field of log levels to set
|
||||
* @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 ntfs_log_set_levels(u32 levels)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.levels;
|
||||
ntfs_log.levels |= levels;
|
||||
return old;
|
||||
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
|
||||
* @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 ntfs_log_clear_levels(u32 levels)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.levels;
|
||||
ntfs_log.levels &= ( ~levels );
|
||||
return old;
|
||||
u32 old;
|
||||
old = ntfs_log.levels;
|
||||
ntfs_log.levels &= (~levels);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
@ -150,167 +148,163 @@ u32 ntfs_log_clear_levels( u32 levels )
|
||||
*
|
||||
* Returns: Logging flags in a 32-bit field
|
||||
*/
|
||||
u32 ntfs_log_get_flags( void )
|
||||
u32 ntfs_log_get_flags(void)
|
||||
{
|
||||
return ntfs_log.flags;
|
||||
return ntfs_log.flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_set_flags - Enable extra logging style flags
|
||||
* @flags: 32-bit field of logging flags to set
|
||||
* @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 ntfs_log_set_flags(u32 flags)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.flags;
|
||||
ntfs_log.flags |= flags;
|
||||
return old;
|
||||
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
|
||||
* @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 ntfs_log_clear_flags(u32 flags)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.flags;
|
||||
ntfs_log.flags &= ( ~flags );
|
||||
return old;
|
||||
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
|
||||
* @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 )
|
||||
static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
FILE *stream;
|
||||
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;
|
||||
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_ENTER:
|
||||
case NTFS_LOG_LEVEL_LEAVE:
|
||||
case NTFS_LOG_LEVEL_WARNING:
|
||||
case NTFS_LOG_LEVEL_ERROR:
|
||||
case NTFS_LOG_LEVEL_CRITICAL:
|
||||
case NTFS_LOG_LEVEL_PERROR:
|
||||
default:
|
||||
stream = stderr;
|
||||
break;
|
||||
}
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
case NTFS_LOG_LEVEL_TRACE:
|
||||
case NTFS_LOG_LEVEL_ENTER:
|
||||
case NTFS_LOG_LEVEL_LEAVE:
|
||||
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;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_get_prefix - Default prefixes for logging levels
|
||||
* @level: Log level to be prefixed
|
||||
* @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 )
|
||||
static const char * ntfs_log_get_prefix(u32 level)
|
||||
{
|
||||
const char *prefix;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_set_handler - Provide an alternate logging handler
|
||||
* @handler: function to perform the logging
|
||||
* @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 )
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler)
|
||||
{
|
||||
if ( handler )
|
||||
{
|
||||
ntfs_log.handler = handler;
|
||||
if (handler) {
|
||||
ntfs_log.handler = handler;
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if ( handler == ntfs_log_handler_syslog )
|
||||
openlog( "ntfs-3g", LOG_PID, LOG_USER );
|
||||
if (handler == ntfs_log_handler_syslog)
|
||||
openlog("ntfs-3g", LOG_PID, LOG_USER);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ntfs_log.handler = ntfs_log_handler_null;
|
||||
} 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
|
||||
* @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).
|
||||
@ -319,35 +313,35 @@ void ntfs_log_set_handler( ntfs_log_handler *handler )
|
||||
* 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 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;
|
||||
int olderr = errno;
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
if ( !( ntfs_log.levels & level ) ) /* Don't log this message */
|
||||
return 0;
|
||||
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 );
|
||||
va_start(args, format);
|
||||
errno = olderr;
|
||||
ret = ntfs_log.handler(function, file, line, level, data, format, args);
|
||||
va_end(args);
|
||||
|
||||
errno = olderr;
|
||||
return ret;
|
||||
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
|
||||
* @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.
|
||||
*
|
||||
@ -359,52 +353,50 @@ int ntfs_log_redirect( const char *function, const char *file,
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
|
||||
#define LOG_LINE_LEN 512
|
||||
#define LOG_LINE_LEN 512
|
||||
|
||||
int ntfs_log_handler_syslog( const char *function __attribute__( ( unused ) ),
|
||||
const char *file __attribute__( ( unused ) ),
|
||||
int line __attribute__( ( unused ) ), u32 level,
|
||||
void *data __attribute__( ( unused ) ),
|
||||
const char *format, va_list args )
|
||||
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level,
|
||||
void *data __attribute__((unused)),
|
||||
const char *format, va_list args)
|
||||
{
|
||||
char logbuf[LOG_LINE_LEN];
|
||||
int ret, olderr = errno;
|
||||
char logbuf[LOG_LINE_LEN];
|
||||
int ret, olderr = errno;
|
||||
|
||||
#ifndef DEBUG
|
||||
if ( ( level & NTFS_LOG_LEVEL_PERROR ) && errno == ENOSPC )
|
||||
return 1;
|
||||
#endif
|
||||
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
vsyslog( LOG_NOTICE, format, args );
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( ( LOG_LINE_LEN > ret + 3 ) && ( level & NTFS_LOG_LEVEL_PERROR ) )
|
||||
{
|
||||
strncat( logbuf, ": ", LOG_LINE_LEN - ret - 1 );
|
||||
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
|
||||
ret = strlen( logbuf );
|
||||
}
|
||||
|
||||
syslog( LOG_NOTICE, "%s", logbuf );
|
||||
if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC)
|
||||
return 1;
|
||||
#endif
|
||||
ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
|
||||
if (ret < 0) {
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(logbuf);
|
||||
}
|
||||
|
||||
syslog(LOG_NOTICE, "%s", logbuf);
|
||||
out:
|
||||
errno = olderr;
|
||||
return ret;
|
||||
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
|
||||
* @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
|
||||
@ -417,93 +409,92 @@ out:
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_fprintf( const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args )
|
||||
int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
int i;
|
||||
#endif
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
FILE *stream;
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
FILE *stream;
|
||||
|
||||
if ( !data ) /* Interpret data as a FILE stream. */
|
||||
return 0; /* If it's NULL, we can't do anything. */
|
||||
stream = ( FILE* )data;
|
||||
if (!data) /* Interpret data as a FILE stream. */
|
||||
return 0; /* If it's NULL, we can't do anything. */
|
||||
stream = (FILE*)data;
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( level == NTFS_LOG_LEVEL_LEAVE )
|
||||
{
|
||||
if ( tab )
|
||||
tab--;
|
||||
return 0;
|
||||
}
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||
if (tab)
|
||||
tab--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < tab; i++)
|
||||
ret += fprintf(stream, " ");
|
||||
#endif
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
|
||||
for ( i = 0; i < tab; i++ )
|
||||
ret += fprintf( stream, " " );
|
||||
#endif
|
||||
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_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_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_LINE ) /* Source line number */
|
||||
ret += fprintf( stream, "(%d) ", line );
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||
(level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
if ( ( ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION ) || /* Source function */
|
||||
( level & NTFS_LOG_LEVEL_TRACE ) || ( level & NTFS_LOG_LEVEL_ENTER ) )
|
||||
ret += fprintf( stream, "%s(): ", function );
|
||||
ret += vfprintf(stream, format, args);
|
||||
|
||||
ret += vfprintf( stream, format, args );
|
||||
|
||||
if ( level & NTFS_LOG_LEVEL_PERROR )
|
||||
ret += fprintf( stream, ": %s\n", strerror( olderr ) );
|
||||
if (level & NTFS_LOG_LEVEL_PERROR)
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( level == NTFS_LOG_LEVEL_ENTER )
|
||||
tab++;
|
||||
#endif
|
||||
fflush( stream );
|
||||
errno = olderr;
|
||||
return ret;
|
||||
if (level == NTFS_LOG_LEVEL_ENTER)
|
||||
tab++;
|
||||
#endif
|
||||
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
|
||||
* @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 ) ) )
|
||||
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;
|
||||
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
|
||||
* @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.
|
||||
*
|
||||
@ -516,24 +507,24 @@ int ntfs_log_handler_null( const char *function __attribute__( ( unused ) ), con
|
||||
* 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 )
|
||||
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;
|
||||
if (!data)
|
||||
data = stdout;
|
||||
|
||||
return ntfs_log_handler_fprintf( function, file, line, level, data, format, args );
|
||||
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
|
||||
* @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.
|
||||
@ -547,24 +538,24 @@ int ntfs_log_handler_stdout( const char *function, const char *file,
|
||||
* 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 )
|
||||
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 );
|
||||
if (!data)
|
||||
data = ntfs_log_get_stream(level);
|
||||
|
||||
return ntfs_log_handler_fprintf( function, file, line, level, data, format, args );
|
||||
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
|
||||
* @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.
|
||||
*
|
||||
@ -577,19 +568,19 @@ int ntfs_log_handler_outerr( const char *function, const char *file,
|
||||
* 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 )
|
||||
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;
|
||||
if (!data)
|
||||
data = stderr;
|
||||
|
||||
return ntfs_log_handler_fprintf( function, file, line, level, data, format, args );
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_parse_option - Act upon command line options
|
||||
* @option: Option flag
|
||||
* @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
|
||||
@ -600,30 +591,23 @@ int ntfs_log_handler_stderr( const char *function, const char *file,
|
||||
* Returns: TRUE Option understood
|
||||
* FALSE Invalid log option
|
||||
*/
|
||||
BOOL ntfs_log_parse_option( const char *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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
ntfs_log_debug( "Unknown logging option '%s'\n", option );
|
||||
return FALSE;
|
||||
ntfs_log_debug("Unknown logging option '%s'\n", option);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -34,58 +34,58 @@
|
||||
#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 );
|
||||
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
|
||||
__attribute__( ( format( printf, 6, 0 ) ) ) );
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler
|
||||
__attribute__((format(printf, 6, 0))));
|
||||
|
||||
/* 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 ) ) );
|
||||
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 );
|
||||
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 );
|
||||
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 );
|
||||
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 ) ) );
|
||||
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_ENTER (1 << 10) /* Enter a function */
|
||||
#define NTFS_LOG_LEVEL_LEAVE (1 << 11) /* Leave a function */
|
||||
#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_ENTER (1 << 10) /* Enter a function */
|
||||
#define NTFS_LOG_LEVEL_LEAVE (1 << 11) /* Leave a function */
|
||||
|
||||
/* 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_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 */
|
||||
|
||||
/* Macros to simplify logging. One for each level defined above.
|
||||
* Note, ntfs_log_debug/trace have effect only if DEBUG is defined.
|
||||
|
@ -24,23 +24,20 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* ntfs_alloc ( size_t size )
|
||||
{
|
||||
return malloc( size );
|
||||
static inline void* ntfs_alloc (size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static inline void* ntfs_align ( size_t size )
|
||||
{
|
||||
#ifdef __wii__
|
||||
return memalign( 32, size );
|
||||
#else
|
||||
return malloc( size );
|
||||
#endif
|
||||
static inline void* ntfs_align (size_t size) {
|
||||
#ifdef __wii__
|
||||
return memalign(32, size);
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ntfs_free ( void* mem )
|
||||
{
|
||||
free( mem );
|
||||
static inline void ntfs_free (void* mem) {
|
||||
free(mem);
|
||||
}
|
||||
|
||||
#endif /* _MEM_ALLOCATE_H */
|
||||
|
3048
source/libntfs/mft.c
3048
source/libntfs/mft.c
File diff suppressed because it is too large
Load Diff
@ -29,14 +29,14 @@
|
||||
#include "layout.h"
|
||||
#include "logging.h"
|
||||
|
||||
extern int ntfs_mft_records_read( const ntfs_volume *vol, const MFT_REF mref,
|
||||
const s64 count, MFT_RECORD *b );
|
||||
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
|
||||
* @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.
|
||||
@ -47,31 +47,31 @@ extern int ntfs_mft_records_read( const ntfs_volume *vol, const MFT_REF mref,
|
||||
*
|
||||
* 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 )
|
||||
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
||||
ret = ntfs_mft_records_read( vol, mref, 1, b );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
|
||||
ret = ntfs_mft_records_read(vol, mref, 1, b);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern int ntfs_mft_record_check( const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *m );
|
||||
extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *m);
|
||||
|
||||
extern int ntfs_file_record_read( const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD **mrec, ATTR_RECORD **attr );
|
||||
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 );
|
||||
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
|
||||
* @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.
|
||||
@ -82,20 +82,20 @@ extern int ntfs_mft_records_write( const ntfs_volume *vol, const MFT_REF mref,
|
||||
*
|
||||
* 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 )
|
||||
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
||||
ret = ntfs_mft_records_write( vol, mref, 1, b );
|
||||
ntfs_log_leave( "\n" );
|
||||
return ret;
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
|
||||
ret = ntfs_mft_records_write(vol, mref, 1, b);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_get_data_size - return number of bytes used in mft record @b
|
||||
* @m: mft record to get the data size of
|
||||
* @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
|
||||
@ -109,24 +109,24 @@ static __inline__ int ntfs_mft_record_write( const ntfs_volume *vol,
|
||||
* 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 )
|
||||
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 );
|
||||
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_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 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 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_record_free(ntfs_volume *vol, ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_mft_usn_dec( MFT_RECORD *mrec );
|
||||
extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);
|
||||
|
||||
#endif /* defined _NTFS_MFT_H */
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* misc.c : miscellaneous :
|
||||
* - dealing with errors in memory allocation
|
||||
* - dealing with errors in memory allocation
|
||||
*
|
||||
* Copyright (c) 2008 Jean-Pierre Andre
|
||||
*
|
||||
@ -37,25 +37,25 @@
|
||||
|
||||
/**
|
||||
* ntfs_calloc
|
||||
*
|
||||
*
|
||||
* Return a pointer to the allocated memory or NULL if the request fails.
|
||||
*/
|
||||
void *ntfs_calloc( size_t size )
|
||||
void *ntfs_calloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = calloc( 1, size );
|
||||
if ( !p )
|
||||
ntfs_log_perror( "Failed to calloc %lld bytes", ( long long )size );
|
||||
return p;
|
||||
void *p;
|
||||
|
||||
p = calloc(1, size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *ntfs_malloc( size_t size )
|
||||
void *ntfs_malloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc( size );
|
||||
if ( !p )
|
||||
ntfs_log_perror( "Failed to malloc %lld bytes", ( long long )size );
|
||||
return p;
|
||||
void *p;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* misc.h : miscellaneous exports
|
||||
* - memory allocation
|
||||
* - memory allocation
|
||||
*
|
||||
* Copyright (c) 2008 Jean-Pierre Andre
|
||||
*
|
||||
@ -23,8 +23,8 @@
|
||||
#ifndef _NTFS_MISC_H_
|
||||
#define _NTFS_MISC_H_
|
||||
|
||||
void *ntfs_calloc( size_t size );
|
||||
void *ntfs_malloc( size_t size );
|
||||
void *ntfs_calloc(size_t size);
|
||||
void *ntfs_malloc(size_t size);
|
||||
|
||||
#endif /* _NTFS_MISC_H_ */
|
||||
|
||||
|
@ -33,8 +33,8 @@
|
||||
|
||||
/**
|
||||
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
* @size: size in bytes of @b
|
||||
* @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
|
||||
@ -43,89 +43,85 @@
|
||||
*
|
||||
* 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".
|
||||
* 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 )
|
||||
int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* 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;
|
||||
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||
"usa_count: %d", __FUNCTION__, *( le32 * )b,
|
||||
size, usa_ofs, usa_count );
|
||||
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.
|
||||
*/
|
||||
errno = EIO;
|
||||
ntfs_log_perror( "Incomplete multi-sector transfer: "
|
||||
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
|
||||
" %d data: %d usn: %d", *( le32 * )b, size,
|
||||
usa_ofs, usa_count, *data_pos, usn );
|
||||
b->magic = magic_BAAD;
|
||||
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;
|
||||
/* 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;
|
||||
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||
"usa_count: %d", __FUNCTION__, *(le32 *)b,
|
||||
size, usa_ofs, usa_count);
|
||||
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.
|
||||
*/
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Incomplete multi-sector transfer: "
|
||||
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
|
||||
" %d data: %d usn: %d", *(le32 *)b, size,
|
||||
usa_ofs, usa_count, *data_pos, usn);
|
||||
b->magic = magic_BAAD;
|
||||
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
|
||||
* @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.
|
||||
@ -142,98 +138,94 @@ int ntfs_mst_post_read_fixup( NTFS_RECORD *b, const u32 size )
|
||||
* 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 )
|
||||
int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if ( !b || ntfs_is_baad_record( b->magic ) ||
|
||||
ntfs_is_hole_record( b->magic ) )
|
||||
{
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
|
||||
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;
|
||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
||||
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;
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if (!b || ntfs_is_baad_record(b->magic) ||
|
||||
ntfs_is_hole_record(b->magic)) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: bad argument", __FUNCTION__);
|
||||
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;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
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
|
||||
* @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 )
|
||||
void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
{
|
||||
u16 *usa_pos, *data_pos;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
u16 usa_ofs = le16_to_cpu( b->usa_ofs );
|
||||
u16 usa_count = le16_to_cpu( b->usa_count ) - 1;
|
||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
|
||||
ntfs_log_trace( "Entering\n" );
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = ( u16* )b + usa_ofs / sizeof( u16 );
|
||||
/* 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;
|
||||
/* 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 );
|
||||
/* 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 );
|
||||
}
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,9 @@
|
||||
#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 );
|
||||
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 */
|
||||
|
||||
|
@ -41,10 +41,9 @@
|
||||
#include "cache.h"
|
||||
|
||||
// NTFS device driver devoptab
|
||||
static const devoptab_t devops_ntfs =
|
||||
{
|
||||
static const devoptab_t devops_ntfs = {
|
||||
NULL, /* Device name */
|
||||
sizeof ( ntfs_file_state ),
|
||||
sizeof (ntfs_file_state),
|
||||
ntfs_open_r,
|
||||
ntfs_close_r,
|
||||
ntfs_write_r,
|
||||
@ -57,7 +56,7 @@ static const devoptab_t devops_ntfs =
|
||||
ntfs_chdir_r,
|
||||
ntfs_rename_r,
|
||||
ntfs_mkdir_r,
|
||||
sizeof ( ntfs_dir_state ),
|
||||
sizeof (ntfs_dir_state),
|
||||
ntfs_diropen_r,
|
||||
ntfs_dirreset_r,
|
||||
ntfs_dirnext_r,
|
||||
@ -68,21 +67,20 @@ static const devoptab_t devops_ntfs =
|
||||
NULL /* Device data */
|
||||
};
|
||||
|
||||
void ntfsInit ( void )
|
||||
void ntfsInit (void)
|
||||
{
|
||||
static bool isInit = false;
|
||||
|
||||
// Initialise ntfs-3g (if not already done so)
|
||||
if ( !isInit )
|
||||
{
|
||||
if (!isInit) {
|
||||
isInit = true;
|
||||
|
||||
// Set the log handler
|
||||
#ifdef NTFS_ENABLE_LOG
|
||||
ntfs_log_set_handler( ntfs_log_handler_stderr );
|
||||
#else
|
||||
ntfs_log_set_handler( ntfs_log_handler_null );
|
||||
#endif
|
||||
#ifdef NTFS_ENABLE_LOG
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
#else
|
||||
ntfs_log_set_handler(ntfs_log_handler_null);
|
||||
#endif
|
||||
// Set our current local
|
||||
ntfs_set_locale();
|
||||
|
||||
@ -91,7 +89,7 @@ void ntfsInit ( void )
|
||||
return;
|
||||
}
|
||||
|
||||
int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
||||
int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||
{
|
||||
MASTER_BOOT_RECORD mbr;
|
||||
PARTITION_RECORD *partition = NULL;
|
||||
@ -100,8 +98,7 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
||||
sec_t part_lba = 0;
|
||||
int i;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
u8 buffer[512];
|
||||
MASTER_BOOT_RECORD mbr;
|
||||
EXTENDED_BOOT_RECORD ebr;
|
||||
@ -109,191 +106,156 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
||||
} sector;
|
||||
|
||||
// Sanity check
|
||||
if ( !interface )
|
||||
{
|
||||
if (!interface) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ( !partitions )
|
||||
if (!partitions)
|
||||
return 0;
|
||||
|
||||
// Initialise ntfs-3g
|
||||
ntfsInit();
|
||||
|
||||
// Start the device and check that it is inserted
|
||||
if ( !interface->startup() )
|
||||
{
|
||||
if (!interface->startup()) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if ( !interface->isInserted() )
|
||||
{
|
||||
if (!interface->isInserted()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read the first sector on the device
|
||||
if ( !interface->readSectors( 0, 1, §or.buffer ) )
|
||||
{
|
||||
if (!interface->readSectors(0, 1, §or.buffer)) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If this is the devices master boot record
|
||||
if ( sector.mbr.signature == MBR_SIGNATURE )
|
||||
{
|
||||
memcpy( &mbr, §or, sizeof( MASTER_BOOT_RECORD ) );
|
||||
ntfs_log_debug( "Valid Master Boot Record found\n" );
|
||||
if (sector.mbr.signature == MBR_SIGNATURE) {
|
||||
memcpy(&mbr, §or, sizeof(MASTER_BOOT_RECORD));
|
||||
ntfs_log_debug("Valid Master Boot Record found\n");
|
||||
|
||||
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
for (i = 0; i < 4; i++) {
|
||||
partition = &mbr.partitions[i];
|
||||
part_lba = le32_to_cpu( mbr.partitions[i].lba_start );
|
||||
part_lba = le32_to_cpu(mbr.partitions[i].lba_start);
|
||||
|
||||
ntfs_log_debug( "Partition %i: %s, sector %d, type 0x%x\n", i + 1,
|
||||
partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
part_lba, partition->type );
|
||||
ntfs_log_debug("Partition %i: %s, sector %d, type 0x%x\n", i + 1,
|
||||
partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
part_lba, partition->type);
|
||||
|
||||
// Figure out what type of partition this is
|
||||
switch ( partition->type )
|
||||
{
|
||||
switch (partition->type) {
|
||||
|
||||
// Ignore empty partitions
|
||||
// Ignore empty partitions
|
||||
case PARTITION_TYPE_EMPTY:
|
||||
continue;
|
||||
|
||||
// NTFS partition
|
||||
case PARTITION_TYPE_NTFS:
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
|
||||
// NTFS partition
|
||||
case PARTITION_TYPE_NTFS: {
|
||||
ntfs_log_debug("Partition %i: Claims to be NTFS\n", i + 1);
|
||||
|
||||
// Read and validate the NTFS partition
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
|
||||
// Read and validate the NTFS partition
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_debug("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// DOS 3.3+ or Windows 95 extended partition
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// DOS 3.3+ or Windows 95 extended partition
|
||||
case PARTITION_TYPE_DOS33_EXTENDED:
|
||||
case PARTITION_TYPE_WIN95_EXTENDED:
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
|
||||
case PARTITION_TYPE_WIN95_EXTENDED: {
|
||||
ntfs_log_debug("Partition %i: Claims to be Extended\n", i + 1);
|
||||
|
||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||
sec_t ebr_lba = part_lba;
|
||||
sec_t next_erb_lba = 0;
|
||||
do
|
||||
{
|
||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||
sec_t ebr_lba = part_lba;
|
||||
sec_t next_erb_lba = 0;
|
||||
do {
|
||||
|
||||
// Read and validate the extended boot record
|
||||
if ( interface->readSectors( ebr_lba + next_erb_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.ebr.signature == EBR_SIGNATURE )
|
||||
{
|
||||
ntfs_log_debug( "Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
sector.ebr.partition.type );
|
||||
// Read and validate the extended boot record
|
||||
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
||||
if (sector.ebr.signature == EBR_SIGNATURE) {
|
||||
ntfs_log_debug("Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||
sector.ebr.partition.type);
|
||||
|
||||
// Get the start sector of the current partition
|
||||
// and the next extended boot record in the chain
|
||||
part_lba = ebr_lba + next_erb_lba + le32_to_cpu( sector.ebr.partition.lba_start );
|
||||
next_erb_lba = le32_to_cpu( sector.ebr.next_ebr.lba_start );
|
||||
// Get the start sector of the current partition
|
||||
// and the next extended boot record in the chain
|
||||
part_lba = ebr_lba + next_erb_lba + le32_to_cpu(sector.ebr.partition.lba_start);
|
||||
next_erb_lba = le32_to_cpu(sector.ebr.next_ebr.lba_start);
|
||||
|
||||
// Check if this partition has a valid NTFS boot record
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba );
|
||||
if ( sector.ebr.partition.type != PARTITION_TYPE_NTFS )
|
||||
{
|
||||
ntfs_log_warning( "Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS );
|
||||
}
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
// Check if this partition has a valid NTFS boot record
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
ntfs_log_debug("Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba);
|
||||
if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
|
||||
ntfs_log_warning("Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS);
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
next_erb_lba = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
while ( next_erb_lba );
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Unknown or unsupported partition type
|
||||
default:
|
||||
{
|
||||
|
||||
// Check if this partition has a valid NTFS boot record anyway,
|
||||
// it might be misrepresented due to a lazy partition editor
|
||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
||||
if ( partition->type != PARTITION_TYPE_NTFS )
|
||||
{
|
||||
ntfs_log_warning( "Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS );
|
||||
}
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
} else {
|
||||
next_erb_lba = 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} while (next_erb_lba);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Unknown or unsupported partition type
|
||||
default: {
|
||||
|
||||
// Check if this partition has a valid NTFS boot record anyway,
|
||||
// it might be misrepresented due to a lazy partition editor
|
||||
if (interface->readSectors(part_lba, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
||||
if(partition->type != PARTITION_TYPE_NTFS) {
|
||||
ntfs_log_warning("Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS);
|
||||
}
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
partition_starts[partition_count] = part_lba;
|
||||
partition_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Else it is assumed this device has no master boot record
|
||||
}
|
||||
else
|
||||
{
|
||||
ntfs_log_debug( "No Master Boot Record was found!\n" );
|
||||
// Else it is assumed this device has no master boot record
|
||||
} else {
|
||||
ntfs_log_debug("No Master Boot Record was found!\n");
|
||||
|
||||
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
||||
for ( i = 0; i < 64; i++ )
|
||||
{
|
||||
if ( interface->readSectors( i, 1, §or ) )
|
||||
{
|
||||
if ( sector.boot.oem_id == NTFS_OEM_ID )
|
||||
{
|
||||
ntfs_log_debug( "Valid NTFS boot sector found at sector %d!\n", i );
|
||||
if ( partition_count < NTFS_MAX_PARTITIONS )
|
||||
{
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (interface->readSectors(i, 1, §or)) {
|
||||
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||
ntfs_log_debug("Valid NTFS boot sector found at sector %d!\n", i);
|
||||
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||
partition_starts[partition_count] = i;
|
||||
partition_count++;
|
||||
}
|
||||
@ -307,12 +269,10 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
||||
/*interface->shutdown();*/
|
||||
|
||||
// Return the found partitions (if any)
|
||||
if ( partition_count > 0 )
|
||||
{
|
||||
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
|
||||
if ( *partitions )
|
||||
{
|
||||
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
|
||||
if (partition_count > 0) {
|
||||
*partitions = (sec_t*)ntfs_alloc(sizeof(sec_t) * partition_count);
|
||||
if (*partitions) {
|
||||
memcpy(*partitions, &partition_starts, sizeof(sec_t) * partition_count);
|
||||
return partition_count;
|
||||
}
|
||||
}
|
||||
@ -320,7 +280,7 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
||||
int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||
{
|
||||
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
||||
const INTERFACE_ID *disc = NULL;
|
||||
@ -335,34 +295,26 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
||||
ntfsInit();
|
||||
|
||||
// Find and mount all NTFS partitions on all known devices
|
||||
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||
{
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||
if ( partition_count > 0 && partitions )
|
||||
{
|
||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||
{
|
||||
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
|
||||
// Find the next unused mount name
|
||||
do
|
||||
{
|
||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||
if ( k >= NTFS_MAX_MOUNTS )
|
||||
{
|
||||
ntfs_free( partitions );
|
||||
do {
|
||||
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
ntfs_free(partitions);
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while ( ntfsGetDevice( name, false ) );
|
||||
} while (ntfsGetDevice(name, false));
|
||||
|
||||
// Mount the partition
|
||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||
{
|
||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||
{
|
||||
strcpy( mount_points[mount_count].name, name );
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
strcpy(mount_points[mount_count].name, name);
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
mount_count++;
|
||||
@ -370,17 +322,15 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
||||
}
|
||||
|
||||
}
|
||||
ntfs_free( partitions );
|
||||
ntfs_free(partitions);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if ( mount_count > 0 && mounts )
|
||||
{
|
||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||
if ( *mounts )
|
||||
{
|
||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||
if (mount_count > 0 && mounts) {
|
||||
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||
if (*mounts) {
|
||||
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||
return mount_count;
|
||||
}
|
||||
}
|
||||
@ -388,7 +338,7 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flags )
|
||||
int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flags)
|
||||
{
|
||||
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
||||
const INTERFACE_ID *disc = NULL;
|
||||
@ -400,8 +350,7 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
||||
int i, j, k;
|
||||
|
||||
// Sanity check
|
||||
if ( !interface )
|
||||
{
|
||||
if (!interface) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -410,36 +359,27 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
||||
ntfsInit();
|
||||
|
||||
// Find the specified device then find and mount all NTFS partitions on it
|
||||
for ( i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++ )
|
||||
{
|
||||
if ( discs[i].interface == interface )
|
||||
{
|
||||
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||
if (discs[i].interface == interface) {
|
||||
disc = &discs[i];
|
||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
||||
if ( partition_count > 0 && partitions )
|
||||
{
|
||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
||||
{
|
||||
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||
if (partition_count > 0 && partitions) {
|
||||
for (j = 0, k = 0; j < partition_count; j++) {
|
||||
|
||||
// Find the next unused mount name
|
||||
do
|
||||
{
|
||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
||||
if ( k >= NTFS_MAX_MOUNTS )
|
||||
{
|
||||
ntfs_free( partitions );
|
||||
do {
|
||||
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||
if (k >= NTFS_MAX_MOUNTS) {
|
||||
ntfs_free(partitions);
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
while ( ntfsGetDevice( name, false ) );
|
||||
} while (ntfsGetDevice(name, false));
|
||||
|
||||
// Mount the partition
|
||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
||||
{
|
||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
||||
{
|
||||
strcpy( mount_points[mount_count].name, name );
|
||||
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||
strcpy(mount_points[mount_count].name, name);
|
||||
mount_points[mount_count].interface = disc->interface;
|
||||
mount_points[mount_count].startSector = partitions[j];
|
||||
mount_count++;
|
||||
@ -447,26 +387,23 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
||||
}
|
||||
|
||||
}
|
||||
ntfs_free( partitions );
|
||||
ntfs_free(partitions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't find the device then return with error status
|
||||
if ( !disc )
|
||||
{
|
||||
if (!disc) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return the mounts (if any)
|
||||
if ( mount_count > 0 && mounts )
|
||||
{
|
||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
||||
if ( *mounts )
|
||||
{
|
||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
||||
if (mount_count > 0 && mounts) {
|
||||
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||
if (*mounts) {
|
||||
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||
return mount_count;
|
||||
}
|
||||
}
|
||||
@ -474,14 +411,13 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags )
|
||||
bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
gekko_fd *fd = NULL;
|
||||
|
||||
// Sanity check
|
||||
if ( !name || !interface )
|
||||
{
|
||||
if (!name || !interface) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
@ -490,23 +426,20 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
||||
ntfsInit();
|
||||
|
||||
// Check that the requested mount name is free
|
||||
if ( ntfsGetDevice( name, false ) )
|
||||
{
|
||||
if (ntfsGetDevice(name, false)) {
|
||||
errno = EADDRINUSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that we can at least read from this device
|
||||
if ( !( interface->features & FEATURE_MEDIUM_CANREAD ) )
|
||||
{
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
||||
errno = EPERM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the volume descriptor
|
||||
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd));
|
||||
if (!vd) {
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -518,15 +451,14 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
||||
vd->gid = 0;
|
||||
vd->fmask = 0;
|
||||
vd->dmask = 0;
|
||||
vd->atime = ( ( flags & NTFS_UPDATE_ACCESS_TIMES ) ? ATIME_ENABLED : ATIME_DISABLED );
|
||||
vd->showHiddenFiles = ( flags & NTFS_SHOW_HIDDEN_FILES );
|
||||
vd->showSystemFiles = ( flags & NTFS_SHOW_SYSTEM_FILES );
|
||||
vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED);
|
||||
vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES);
|
||||
vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES);
|
||||
|
||||
// Allocate the device driver descriptor
|
||||
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
|
||||
if ( !fd )
|
||||
{
|
||||
ntfs_free( vd );
|
||||
fd = (gekko_fd*)ntfs_alloc(sizeof(gekko_fd));
|
||||
if (!fd) {
|
||||
ntfs_free(vd);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -540,94 +472,92 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
||||
fd->cachePageSize = cachePageSize;
|
||||
|
||||
// Allocate the device driver
|
||||
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
|
||||
if ( !vd->dev )
|
||||
{
|
||||
ntfs_free( fd );
|
||||
ntfs_free( vd );
|
||||
vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd);
|
||||
if (!vd->dev) {
|
||||
ntfs_free(fd);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the mount flags
|
||||
if ( flags & NTFS_READ_ONLY )
|
||||
vd->flags |= MS_RDONLY;
|
||||
if (flags & NTFS_READ_ONLY)
|
||||
vd->flags |= MS_RDONLY;
|
||||
else
|
||||
{
|
||||
if ( !( interface->features & FEATURE_MEDIUM_CANWRITE ) )
|
||||
vd->flags |= MS_RDONLY;
|
||||
if ( ( interface->features & FEATURE_MEDIUM_CANREAD ) && ( interface->features & FEATURE_MEDIUM_CANWRITE ) )
|
||||
vd->flags |= MS_EXCLUSIVE;
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_RDONLY;
|
||||
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_EXCLUSIVE;
|
||||
}
|
||||
if ( flags & NTFS_RECOVER )
|
||||
if (flags & NTFS_RECOVER)
|
||||
vd->flags |= MS_RECOVER;
|
||||
if ( flags & NTFS_IGNORE_HIBERFILE )
|
||||
if (flags & NTFS_IGNORE_HIBERFILE)
|
||||
vd->flags |= MS_IGNORE_HIBERFILE;
|
||||
|
||||
if ( vd->flags & MS_RDONLY )
|
||||
ntfs_log_debug( "Mounting \"%s\" as read-only\n", name );
|
||||
if (vd->flags & MS_RDONLY)
|
||||
ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
|
||||
|
||||
// Mount the device
|
||||
vd->vol = ntfs_device_mount( vd->dev, vd->flags );
|
||||
if ( !vd->vol )
|
||||
{
|
||||
switch ( ntfs_volume_error( errno ) )
|
||||
{
|
||||
vd->vol = ntfs_device_mount(vd->dev, vd->flags);
|
||||
if (!vd->vol) {
|
||||
switch(ntfs_volume_error(errno)) {
|
||||
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
||||
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
||||
case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
|
||||
default: errno = EINVAL; break;
|
||||
}
|
||||
ntfs_device_free( vd->dev );
|
||||
ntfs_free( vd );
|
||||
ntfs_device_free(vd->dev);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flags & NTFS_IGNORE_CASE)
|
||||
ntfs_set_ignore_case(vd->vol);
|
||||
|
||||
// Initialise the volume descriptor
|
||||
if ( ntfsInitVolume( vd ) )
|
||||
{
|
||||
ntfs_umount( vd->vol, true );
|
||||
ntfs_free( vd );
|
||||
if (ntfsInitVolume(vd)) {
|
||||
ntfs_umount(vd->vol, true);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the device to the devoptab table
|
||||
if ( ntfsAddDevice( name, vd ) )
|
||||
{
|
||||
ntfsDeinitVolume( vd );
|
||||
ntfs_umount( vd->vol, true );
|
||||
ntfs_free( vd );
|
||||
if (ntfsAddDevice(name, vd)) {
|
||||
ntfsDeinitVolume(vd);
|
||||
ntfs_umount(vd->vol, true);
|
||||
ntfs_free(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ntfsUnmount ( const char *name, bool force )
|
||||
void ntfsUnmount (const char *name, bool force)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume( name );
|
||||
if ( !vd )
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd)
|
||||
return;
|
||||
|
||||
// Remove the device from the devoptab table
|
||||
ntfsRemoveDevice( name );
|
||||
ntfsRemoveDevice(name);
|
||||
|
||||
// Deinitialise the volume descriptor
|
||||
ntfsDeinitVolume( vd );
|
||||
ntfsDeinitVolume(vd);
|
||||
|
||||
// Unmount the volume
|
||||
ntfs_umount( vd->vol, force );
|
||||
ntfs_umount(vd->vol, force);
|
||||
|
||||
// Free the volume descriptor
|
||||
ntfs_free( vd );
|
||||
ntfs_free(vd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const char *ntfsGetVolumeName ( const char *name )
|
||||
const char *ntfsGetVolumeName (const char *name)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
//ntfs_attr *na = NULL;
|
||||
@ -635,81 +565,79 @@ const char *ntfsGetVolumeName ( const char *name )
|
||||
//char *volumeName = NULL;
|
||||
|
||||
// Sanity check
|
||||
if ( !name )
|
||||
{
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume( name );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
return vd->vol->vol_name;
|
||||
/*
|
||||
|
||||
// If the volume name has already been cached then just use that
|
||||
if (vd->name[0])
|
||||
return vd->name;
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
// Check if the volume name attribute exists
|
||||
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
||||
if (!na) {
|
||||
ntfsUnlock(vd);
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate a buffer to store the raw volume name
|
||||
ulabel = ntfs_alloc(na->data_size * sizeof(ntfschar));
|
||||
if (!ulabel) {
|
||||
ntfsUnlock(vd);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the volume name
|
||||
if (ntfs_attr_pread(na, 0, na->data_size, ulabel) != na->data_size) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert the volume name to the current local
|
||||
if (ntfsUnicodeToLocal(ulabel, na->data_size, &volumeName, 0) < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the volume name was read then cache it (for future fetches)
|
||||
if (volumeName)
|
||||
strcpy(vd->name, volumeName);
|
||||
|
||||
// Close the volume name attribute
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
// Clean up
|
||||
ntfs_free(volumeName);
|
||||
ntfs_free(ulabel);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
/*
|
||||
|
||||
// If the volume name has already been cached then just use that
|
||||
if (vd->name[0])
|
||||
return vd->name;
|
||||
*/
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
// Check if the volume name attribute exists
|
||||
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
||||
if (!na) {
|
||||
ntfsUnlock(vd);
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate a buffer to store the raw volume name
|
||||
ulabel = ntfs_alloc(na->data_size * sizeof(ntfschar));
|
||||
if (!ulabel) {
|
||||
ntfsUnlock(vd);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the volume name
|
||||
if (ntfs_attr_pread(na, 0, na->data_size, ulabel) != na->data_size) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert the volume name to the current local
|
||||
if (ntfsUnicodeToLocal(ulabel, na->data_size, &volumeName, 0) < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the volume name was read then cache it (for future fetches)
|
||||
if (volumeName)
|
||||
strcpy(vd->name, volumeName);
|
||||
|
||||
// Close the volume name attribute
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
// Clean up
|
||||
ntfs_free(volumeName);
|
||||
ntfs_free(ulabel);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return vd->name;
|
||||
*/
|
||||
}
|
||||
|
||||
bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
||||
bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_attr *na = NULL;
|
||||
@ -717,62 +645,53 @@ bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
||||
int ulabel_len;
|
||||
|
||||
// Sanity check
|
||||
if ( !name )
|
||||
{
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the devices volume descriptor
|
||||
vd = ntfsGetVolume( name );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Convert the new volume name to unicode
|
||||
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
|
||||
if ( ulabel_len < 0 )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
|
||||
if (ulabel_len < 0) {
|
||||
ntfsUnlock(vd);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the volume name attribute exists
|
||||
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 );
|
||||
if ( na )
|
||||
{
|
||||
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
||||
if (na) {
|
||||
|
||||
// It does, resize it to match the length of the new volume name
|
||||
if ( ntfs_attr_truncate( na, ulabel_len ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
if (ntfs_attr_truncate(na, ulabel_len)) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the new volume name
|
||||
if ( ntfs_attr_pwrite( na, 0, ulabel_len, ulabel ) != ulabel_len )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
|
||||
// It doesn't, create it now
|
||||
if ( ntfs_attr_add( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, ( u8* )ulabel, ulabel_len ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -782,27 +701,26 @@ bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
||||
vd->name[0] = '\0';
|
||||
|
||||
// Close the volume name attribute
|
||||
if ( na )
|
||||
ntfs_attr_close( na );
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
// Sync the volume node
|
||||
if ( ntfs_inode_sync( vd->vol->vol_ni ) )
|
||||
{
|
||||
ntfs_free( ulabel );
|
||||
ntfsUnlock( vd );
|
||||
if (ntfs_inode_sync(vd->vol->vol_ni)) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
ntfs_free( ulabel );
|
||||
ntfs_free(ulabel);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const devoptab_t *ntfsGetDevOpTab ( void )
|
||||
const devoptab_t *ntfsGetDevOpTab (void)
|
||||
{
|
||||
return &devops_ntfs;
|
||||
}
|
||||
|
@ -23,25 +23,24 @@
|
||||
#define _LIBNTFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
#include <gccore.h>
|
||||
#include <ogc/disc_io.h>
|
||||
|
||||
/* NTFS errno values */
|
||||
/* NTFS errno values */
|
||||
#define ENOPART 3000 /* No partition was found */
|
||||
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
|
||||
#define EDIRTY 3002 /* Volume is dirty and NTFS_RECOVER was not specified during mount */
|
||||
#define EHIBERNATED 3003 /* Volume is hibernated and NTFS_IGNORE_HIBERFILE was not specified during mount */
|
||||
|
||||
/* NTFS cache options */
|
||||
/* NTFS cache options */
|
||||
#define CACHE_DEFAULT_PAGE_COUNT 8 /* The default number of pages in the cache */
|
||||
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
|
||||
|
||||
/* NTFS mount flags */
|
||||
/* NTFS mount flags */
|
||||
#define NTFS_DEFAULT 0x00000000 /* Standard mount, expects a clean, non-hibernated volume */
|
||||
#define NTFS_SHOW_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
|
||||
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
|
||||
@ -49,100 +48,97 @@ extern "C"
|
||||
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
|
||||
#define NTFS_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
|
||||
#define NTFS_READ_ONLY 0x00000020 /* Mount in read only mode */
|
||||
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
|
||||
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
|
||||
#define NTFS_IGNORE_CASE 0x00000040 /* Ignore case sensitivity. Everything must be and will be provided in lowercase. */
|
||||
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES | NTFS_SHOW_SYSTEM_FILES
|
||||
#define NTFS_FORCE NTFS_RECOVER | NTFS_IGNORE_HIBERFILE
|
||||
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md
|
||||
{
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
} ntfs_md;
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md {
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
} ntfs_md;
|
||||
|
||||
/**
|
||||
* Find all NTFS partitions on a block device.
|
||||
*
|
||||
* @param INTERFACE The block device to search
|
||||
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
|
||||
*
|
||||
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing PARTITIONS when finished with it
|
||||
*/
|
||||
extern int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions );
|
||||
/**
|
||||
* Find all NTFS partitions on a block device.
|
||||
*
|
||||
* @param INTERFACE The block device to search
|
||||
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
|
||||
*
|
||||
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing PARTITIONS when finished with it
|
||||
*/
|
||||
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on all inserted block devices.
|
||||
*
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note All device caches are setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountAll ( ntfs_md **mounts, u32 flags );
|
||||
/**
|
||||
* Mount all NTFS partitions on all inserted block devices.
|
||||
*
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note All device caches are setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on a block devices.
|
||||
*
|
||||
* @param INTERFACE The block device to mount.
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note The device cache is setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountDevice ( const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags );
|
||||
/**
|
||||
* Mount all NTFS partitions on a block devices.
|
||||
*
|
||||
* @param INTERFACE The block device to mount.
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note The device cache is setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount a NTFS partition from a specific sector on a block device.
|
||||
*
|
||||
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
|
||||
* @param INTERFACE The block device to mount
|
||||
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
|
||||
* @param CACHEPAGECOUNT The total number of pages in the device cache
|
||||
* @param CACHEPAGESIZE The number of sectors per cache page
|
||||
* @param FLAGS Additional mounting flags (see above)
|
||||
*
|
||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
||||
* @note ntfsFindPartitions should be used first to locate the partitions start sector
|
||||
*/
|
||||
extern bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags );
|
||||
/**
|
||||
* Mount a NTFS partition from a specific sector on a block device.
|
||||
*
|
||||
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
|
||||
* @param INTERFACE The block device to mount
|
||||
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
|
||||
* @param CACHEPAGECOUNT The total number of pages in the device cache
|
||||
* @param CACHEPAGESIZE The number of sectors per cache page
|
||||
* @param FLAGS Additional mounting flags (see above)
|
||||
*
|
||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
||||
* @note ntfsFindPartitions should be used first to locate the partitions start sector
|
||||
*/
|
||||
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
|
||||
|
||||
/**
|
||||
* Unmount a NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
|
||||
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
|
||||
*/
|
||||
extern void ntfsUnmount ( const char *name, bool force );
|
||||
/**
|
||||
* Unmount a NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
|
||||
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
|
||||
*/
|
||||
extern void ntfsUnmount (const char *name, bool force);
|
||||
|
||||
/**
|
||||
* Get the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
*
|
||||
* @return The volumes name if successful or NULL if an error occurred (see errno)
|
||||
*/
|
||||
extern const char *ntfsGetVolumeName ( const char *name );
|
||||
/**
|
||||
* Get the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
*
|
||||
* @return The volumes name if successful or NULL if an error occurred (see errno)
|
||||
*/
|
||||
extern const char *ntfsGetVolumeName (const char *name);
|
||||
|
||||
/**
|
||||
* Set the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
* @param VOLUMENAME The new volume name
|
||||
*
|
||||
* @return True if mount was successful, false if an error occurred (see errno)
|
||||
* @note The mount must be write-enabled else this will fail
|
||||
*/
|
||||
extern bool ntfsSetVolumeName ( const char *name, const char *volumeName );
|
||||
|
||||
typedef int ( *_ntfs_frag_append_t )( void *ff, u32 offset, u32 sector, u32 count );
|
||||
int _NTFS_get_fragments ( const char *path, _ntfs_frag_append_t append_fragment, void *callback_data );
|
||||
/**
|
||||
* Set the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
* @param VOLUMENAME The new volume name
|
||||
*
|
||||
* @return True if mount was successful, false if an error occurred (see errno)
|
||||
* @note The mount must be write-enabled else this will fail
|
||||
*/
|
||||
extern bool ntfsSetVolumeName (const char *name, const char *volumeName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -47,24 +47,23 @@
|
||||
|
||||
#define STATE(x) ((ntfs_dir_state*)(x)->dirStruct)
|
||||
|
||||
void ntfsCloseDir ( ntfs_dir_state *dir )
|
||||
void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
{
|
||||
// Sanity check
|
||||
if ( !dir || !dir->vd )
|
||||
if (!dir || !dir->vd)
|
||||
return;
|
||||
|
||||
// Free the directory entries (if any)
|
||||
while ( dir->first )
|
||||
{
|
||||
while (dir->first) {
|
||||
ntfs_dir_entry *next = dir->first->next;
|
||||
ntfs_free( dir->first->name );
|
||||
ntfs_free( dir->first );
|
||||
ntfs_free(dir->first->name);
|
||||
ntfs_free(dir->first);
|
||||
dir->first = next;
|
||||
}
|
||||
|
||||
// Close the directory (if open)
|
||||
if ( dir->ni )
|
||||
ntfsCloseEntry( dir->vd, dir->ni );
|
||||
if (dir->ni)
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
|
||||
// Reset the directory state
|
||||
dir->ni = NULL;
|
||||
@ -74,280 +73,264 @@ void ntfsCloseDir ( ntfs_dir_state *dir )
|
||||
return;
|
||||
}
|
||||
|
||||
int ntfs_stat_r ( struct _reent *r, const char *path, struct stat *st )
|
||||
int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if ( !st || !path )
|
||||
if (!st || !path)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace( "path %s, st %p\n", path, st );
|
||||
ntfs_log_trace("path %s, st %p\n", path, st);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( strcmp( path, "." ) == 0 || strcmp( path, ".." ) == 0 )
|
||||
if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
|
||||
{
|
||||
memset( st, 0, sizeof( struct stat ) );
|
||||
memset(st, 0, sizeof(struct stat));
|
||||
st->st_mode = S_IFDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry( vd, path );
|
||||
if ( !ni )
|
||||
{
|
||||
ni = ntfsOpenEntry(vd, path);
|
||||
if (!ni) {
|
||||
r->_errno = errno;
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the entry stats
|
||||
int ret = ntfsStat( vd, ni, st );
|
||||
if ( ret )
|
||||
int ret = ntfsStat(vd, ni, st);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
|
||||
// Close the entry
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_link_r ( struct _reent *r, const char *existing, const char *newLink )
|
||||
int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
{
|
||||
ntfs_log_trace( "existing %s, newLink %s\n", existing, newLink );
|
||||
ntfs_log_trace("existing %s, newLink %s\n", existing, newLink);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( existing );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(existing);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Create a symbolic link between the two paths
|
||||
ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
|
||||
if (!ni) {
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Close the symbolic link
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_unlink_r ( struct _reent *r, const char *name )
|
||||
int ntfs_unlink_r (struct _reent *r, const char *name)
|
||||
{
|
||||
ntfs_log_trace( "name %s\n", name );
|
||||
ntfs_log_trace("name %s\n", name);
|
||||
|
||||
// Unlink the entry
|
||||
int ret = ntfsUnlink( ntfsGetVolume( name ), name );
|
||||
if ( ret )
|
||||
int ret = ntfsUnlink(ntfsGetVolume(name), name);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ntfs_chdir_r ( struct _reent *r, const char *name )
|
||||
int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
{
|
||||
ntfs_log_trace( "name %s\n", name );
|
||||
ntfs_log_trace("name %s\n", name);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( name );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Find the directory
|
||||
ni = ntfsOpenEntry( vd, name );
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
ni = ntfsOpenEntry(vd, name);
|
||||
if (!ni) {
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if ( !( ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsUnlock( vd );
|
||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
ntfsCloseEntry(vd, ni);
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Close the old current directory (if any)
|
||||
if ( vd->cwd_ni )
|
||||
ntfsCloseEntry( vd, vd->cwd_ni );
|
||||
if (vd->cwd_ni)
|
||||
ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
|
||||
// Set the new current directory
|
||||
vd->cwd_ni = ni;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_rename_r ( struct _reent *r, const char *oldName, const char *newName )
|
||||
int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
{
|
||||
ntfs_log_trace( "oldName %s, newName %s\n", oldName, newName );
|
||||
ntfs_log_trace("oldName %s, newName %s\n", oldName, newName);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( oldName );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(oldName);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// You cannot rename between devices
|
||||
if ( vd != ntfsGetVolume( newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
if(vd != ntfsGetVolume(newName)) {
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that there is no existing entry with the new name
|
||||
ni = ntfsOpenEntry( vd, newName );
|
||||
if ( ni )
|
||||
{
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsUnlock( vd );
|
||||
ni = ntfsOpenEntry(vd, newName);
|
||||
if (ni) {
|
||||
ntfsCloseEntry(vd, ni);
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Link the old entry with the new one
|
||||
if ( ntfsLink( vd, oldName, newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
if (ntfsLink(vd, oldName, newName)) {
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlink the old entry
|
||||
if ( ntfsUnlink( vd, oldName ) )
|
||||
{
|
||||
if ( ntfsUnlink( vd, newName ) )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
if (ntfsUnlink(vd, oldName)) {
|
||||
if (ntfsUnlink(vd, newName)) {
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_mkdir_r ( struct _reent *r, const char *path, int mode )
|
||||
int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
{
|
||||
ntfs_log_trace( "path %s, mode %i\n", path, mode );
|
||||
ntfs_log_trace("path %s, mode %i\n", path, mode);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Create the directory
|
||||
ni = ntfsCreate( vd, path, S_IFDIR, NULL );
|
||||
if ( !ni )
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
ni = ntfsCreate(vd, path, S_IFDIR, NULL);
|
||||
if (!ni) {
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
ntfsCloseEntry( vd, ni );
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf )
|
||||
int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
{
|
||||
ntfs_log_trace( "path %s, buf %p\n", path, buf );
|
||||
ntfs_log_trace("path %s, buf %p\n", path, buf);
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
s64 size;
|
||||
int delta_bits;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume( path );
|
||||
if ( !vd )
|
||||
{
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if ( !buf )
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
// Lock
|
||||
ntfsLock( vd );
|
||||
ntfsLock(vd);
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset( buf, 0, sizeof( struct statvfs ) );
|
||||
memset(buf, 0, sizeof(struct statvfs));
|
||||
|
||||
if ( ntfs_volume_get_free_space( vd->vol ) < 0 )
|
||||
if(ntfs_volume_get_free_space(vd->vol) < 0)
|
||||
{
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -361,34 +344,34 @@ int ntfs_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf )
|
||||
buf->f_blocks = vd->vol->nr_clusters;
|
||||
|
||||
// Free blocks available for all and for non-privileged processes
|
||||
size = MAX( vd->vol->free_clusters, 0 );
|
||||
size = MAX(vd->vol->free_clusters, 0);
|
||||
buf->f_bfree = buf->f_bavail = size;
|
||||
|
||||
// Free inodes on the free space
|
||||
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
|
||||
if ( delta_bits >= 0 )
|
||||
if (delta_bits >= 0)
|
||||
size <<= delta_bits;
|
||||
else
|
||||
size >>= -delta_bits;
|
||||
|
||||
// Number of inodes at this point in time
|
||||
buf->f_files = ( vd->vol->mftbmp_na->allocated_size << 3 ) + size;
|
||||
buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;
|
||||
|
||||
// Free inodes available for all and for non-privileged processes
|
||||
size += vd->vol->free_mft_records;
|
||||
buf->f_ffree = buf->f_favail = MAX( size, 0 );
|
||||
buf->f_ffree = buf->f_favail = MAX(size, 0);
|
||||
|
||||
// File system id
|
||||
buf->f_fsid = vd->id;
|
||||
|
||||
// Bit mask of f_flag values.
|
||||
buf->f_flag = ( NVolReadOnly( vd->vol ) ? ST_RDONLY : 0 );
|
||||
buf->f_flag = (NVolReadOnly(vd->vol) ? ST_RDONLY : 0);
|
||||
|
||||
// Maximum length of filenames
|
||||
buf->f_namemax = NTFS_MAX_NAME_LEN;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( vd );
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -396,83 +379,74 @@ int ntfs_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf )
|
||||
/**
|
||||
* PRIVATE: Callback for directory walking
|
||||
*/
|
||||
int ntfs_readdir_filler ( DIR_ITER *dirState, const ntfschar *name, const int name_len, const int name_type,
|
||||
const s64 pos, const MFT_REF mref, const unsigned dt_type )
|
||||
int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int name_len, const int name_type,
|
||||
const s64 pos, const MFT_REF mref, const unsigned dt_type)
|
||||
{
|
||||
ntfs_dir_state *dir = STATE( dirState );
|
||||
ntfs_dir_state *dir = STATE(dirState);
|
||||
ntfs_dir_entry *entry = NULL;
|
||||
char *entry_name = NULL;
|
||||
|
||||
// Sanity check
|
||||
if ( !dir || !dir->vd )
|
||||
{
|
||||
if (!dir || !dir->vd) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ignore DOS file names
|
||||
if ( name_type == FILE_NAME_DOS )
|
||||
{
|
||||
if (name_type == FILE_NAME_DOS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
||||
if ( MREF( mref ) == FILE_root || MREF( mref ) >= FILE_first_user || dir->vd->showSystemFiles )
|
||||
{
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
|
||||
|
||||
// Convert the entry name to our current local
|
||||
if ( ntfsUnicodeToLocal( name, name_len, &entry_name, 0 ) < 0 )
|
||||
{
|
||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( dir->first && dir->first->mref == FILE_root &&
|
||||
MREF( mref ) == FILE_root && strcmp( entry_name, ".." ) == 0 )
|
||||
if(dir->first && dir->first->mref == FILE_root &&
|
||||
MREF(mref) == FILE_root && strcmp(entry_name, "..") == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this is not the parent or self directory reference
|
||||
if ( ( strcmp( entry_name, "." ) != 0 ) && ( strcmp( entry_name, ".." ) != 0 ) )
|
||||
{
|
||||
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
|
||||
|
||||
// Open the entry
|
||||
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
|
||||
if ( !ni )
|
||||
ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name);
|
||||
if (!ni)
|
||||
return -1;
|
||||
|
||||
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
||||
if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) ||
|
||||
( ( ni->flags & FILE_ATTR_SYSTEM ) && !dir->vd->showSystemFiles ) )
|
||||
{
|
||||
ntfs_inode_close( ni );
|
||||
if (((ni->flags & FILE_ATTR_HIDDEN) && !dir->vd->showHiddenFiles) ||
|
||||
((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) {
|
||||
ntfs_inode_close(ni);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Close the entry
|
||||
ntfs_inode_close( ni );
|
||||
ntfs_inode_close(ni);
|
||||
|
||||
}
|
||||
|
||||
// Allocate a new directory entry
|
||||
entry = ( ntfs_dir_entry * ) ntfs_alloc( sizeof( ntfs_dir_entry ) );
|
||||
if ( !entry )
|
||||
entry = (ntfs_dir_entry *) ntfs_alloc(sizeof(ntfs_dir_entry));
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
// Setup the entry
|
||||
entry->name = entry_name;
|
||||
entry->next = NULL;
|
||||
entry->mref = MREF( mref );
|
||||
entry->mref = MREF(mref);
|
||||
|
||||
// Link the entry to the directory
|
||||
if ( !dir->first )
|
||||
{
|
||||
if (!dir->first) {
|
||||
dir->first = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ntfs_dir_entry *last = dir->first;
|
||||
while ( last->next ) last = last->next;
|
||||
while (last->next) last = last->next;
|
||||
last->next = entry;
|
||||
}
|
||||
|
||||
@ -481,48 +455,44 @@ int ntfs_readdir_filler ( DIR_ITER *dirState, const ntfschar *name, const int na
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR_ITER *ntfs_diropen_r ( struct _reent *r, DIR_ITER *dirState, const char *path )
|
||||
DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||
{
|
||||
ntfs_log_trace( "dirState %p, path %s\n", dirState, path );
|
||||
ntfs_log_trace("dirState %p, path %s\n", dirState, path);
|
||||
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
s64 position = 0;
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
dir->vd = ntfsGetVolume( path );
|
||||
if ( !dir->vd )
|
||||
{
|
||||
dir->vd = ntfsGetVolume(path);
|
||||
if (!dir->vd) {
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( dir->vd );
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Find the directory
|
||||
dir->ni = ntfsOpenEntry( dir->vd, path );
|
||||
if ( !dir->ni )
|
||||
{
|
||||
ntfsUnlock( dir->vd );
|
||||
dir->ni = ntfsOpenEntry(dir->vd, path);
|
||||
if (!dir->ni) {
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if ( !( dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( dir->vd, dir->ni );
|
||||
ntfsUnlock( dir->vd );
|
||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the directory
|
||||
dir->first = dir->current = NULL;
|
||||
if ( ntfs_readdir( dir->ni, &position, dirState, ( ntfs_filldir_t )ntfs_readdir_filler ) )
|
||||
{
|
||||
ntfsCloseDir( dir );
|
||||
ntfsUnlock( dir->vd );
|
||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
||||
ntfsCloseDir(dir);
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = errno;
|
||||
return NULL;
|
||||
}
|
||||
@ -531,16 +501,13 @@ DIR_ITER *ntfs_diropen_r ( struct _reent *r, DIR_ITER *dirState, const char *pat
|
||||
dir->current = dir->first;
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Insert the directory into the double-linked FILO list of open directories
|
||||
if ( dir->vd->firstOpenDir )
|
||||
{
|
||||
if (dir->vd->firstOpenDir) {
|
||||
dir->nextOpenDir = dir->vd->firstOpenDir;
|
||||
dir->vd->firstOpenDir->prevOpenDir = dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
dir->nextOpenDir = NULL;
|
||||
}
|
||||
dir->prevOpenDir = NULL;
|
||||
@ -549,80 +516,76 @@ DIR_ITER *ntfs_diropen_r ( struct _reent *r, DIR_ITER *dirState, const char *pat
|
||||
dir->vd->openDirCount++;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( dir->vd );
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
return dirState;
|
||||
}
|
||||
|
||||
int ntfs_dirreset_r ( struct _reent *r, DIR_ITER *dirState )
|
||||
int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
ntfs_log_trace( "dirState %p\n", dirState );
|
||||
ntfs_log_trace("dirState %p\n", dirState);
|
||||
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
// Sanity check
|
||||
if ( !dir || !dir->vd || !dir->ni )
|
||||
{
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( dir->vd );
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Move to the first entry in the directory
|
||||
dir->current = dir->first;
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( dir->vd );
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat )
|
||||
int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||||
{
|
||||
ntfs_log_trace( "dirState %p, filename %p, filestat %p\n", dirState, filename, filestat );
|
||||
ntfs_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat);
|
||||
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
// Sanity check
|
||||
if ( !dir || !dir->vd || !dir->ni )
|
||||
{
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( dir->vd );
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Check that there is a entry waiting to be fetched
|
||||
if ( !dir->current )
|
||||
{
|
||||
ntfsUnlock( dir->vd );
|
||||
if (!dir->current) {
|
||||
ntfsUnlock(dir->vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fetch the current entry
|
||||
strcpy( filename, dir->current->name );
|
||||
if ( filestat != NULL )
|
||||
strcpy(filename, dir->current->name);
|
||||
if(filestat != NULL)
|
||||
{
|
||||
if ( strcmp( dir->current->name, "." ) == 0 || strcmp( dir->current->name, ".." ) == 0 )
|
||||
if(strcmp(dir->current->name, ".") == 0 || strcmp(dir->current->name, "..") == 0)
|
||||
{
|
||||
memset( filestat, 0, sizeof( struct stat ) );
|
||||
memset(filestat, 0, sizeof(struct stat));
|
||||
filestat->st_mode = S_IFDIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ni = ntfsOpenEntry( dir->vd, dir->current->name );
|
||||
if ( ni )
|
||||
{
|
||||
ntfsStat( dir->vd, ni, filestat );
|
||||
ntfsCloseEntry( dir->vd, ni );
|
||||
ni = ntfsOpenEntry(dir->vd, dir->current->name);
|
||||
if (ni) {
|
||||
ntfsStat(dir->vd, ni, filestat);
|
||||
ntfsCloseEntry(dir->vd, ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -631,44 +594,43 @@ int ntfs_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struc
|
||||
dir->current = dir->current->next;
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( dir->vd );
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_dirclose_r ( struct _reent *r, DIR_ITER *dirState )
|
||||
int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
ntfs_log_trace( "dirState %p\n", dirState );
|
||||
ntfs_log_trace("dirState %p\n", dirState);
|
||||
|
||||
ntfs_dir_state* dir = STATE( dirState );
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
// Sanity check
|
||||
if ( !dir || !dir->vd )
|
||||
{
|
||||
if (!dir || !dir->vd) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( dir->vd );
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Close the directory
|
||||
ntfsCloseDir( dir );
|
||||
ntfsCloseDir(dir);
|
||||
|
||||
// Remove the directory from the double-linked FILO list of open directories
|
||||
dir->vd->openDirCount--;
|
||||
if ( dir->nextOpenDir )
|
||||
if (dir->nextOpenDir)
|
||||
dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
|
||||
if ( dir->prevOpenDir )
|
||||
if (dir->prevOpenDir)
|
||||
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
|
||||
else
|
||||
dir->vd->firstOpenDir = dir->nextOpenDir;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( dir->vd );
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,8 +28,7 @@
|
||||
/**
|
||||
* ntfs_dir_entry - Directory entry
|
||||
*/
|
||||
typedef struct _ntfs_dir_entry
|
||||
{
|
||||
typedef struct _ntfs_dir_entry {
|
||||
char *name;
|
||||
u64 mref;
|
||||
struct _ntfs_dir_entry *next;
|
||||
@ -38,8 +37,7 @@ typedef struct _ntfs_dir_entry
|
||||
/**
|
||||
* ntfs_dir_state - Directory state
|
||||
*/
|
||||
typedef struct _ntfs_dir_state
|
||||
{
|
||||
typedef struct _ntfs_dir_state {
|
||||
ntfs_vd *vd; /* Volume this directory belongs to */
|
||||
ntfs_inode *ni; /* Directory descriptor */
|
||||
ntfs_dir_entry *first; /* The first entry in the directory */
|
||||
@ -49,22 +47,22 @@ typedef struct _ntfs_dir_state
|
||||
} ntfs_dir_state;
|
||||
|
||||
/* Directory state routines */
|
||||
void ntfsCloseDir ( ntfs_dir_state *file );
|
||||
void ntfsCloseDir (ntfs_dir_state *file);
|
||||
|
||||
/* Gekko devoptab directory routines for NTFS-based devices */
|
||||
extern int ntfs_stat_r ( struct _reent *r, const char *path, struct stat *st );
|
||||
extern int ntfs_link_r ( struct _reent *r, const char *existing, const char *newLink );
|
||||
extern int ntfs_unlink_r ( struct _reent *r, const char *name );
|
||||
extern int ntfs_chdir_r ( struct _reent *r, const char *name );
|
||||
extern int ntfs_rename_r ( struct _reent *r, const char *oldName, const char *newName );
|
||||
extern int ntfs_mkdir_r ( struct _reent *r, const char *path, int mode );
|
||||
extern int ntfs_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf );
|
||||
extern int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||
extern int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||
extern int ntfs_unlink_r (struct _reent *r, const char *name);
|
||||
extern int ntfs_chdir_r (struct _reent *r, const char *name);
|
||||
extern int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||
extern int ntfs_mkdir_r (struct _reent *r, const char *path, int mode);
|
||||
extern int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf);
|
||||
|
||||
/* Gekko devoptab directory walking routines for NTFS-based devices */
|
||||
extern DIR_ITER *ntfs_diropen_r ( struct _reent *r, DIR_ITER *dirState, const char *path );
|
||||
extern int ntfs_dirreset_r ( struct _reent *r, DIR_ITER *dirState );
|
||||
extern int ntfs_dirnext_r ( struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat );
|
||||
extern int ntfs_dirclose_r ( struct _reent *r, DIR_ITER *dirState );
|
||||
extern DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||
extern int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState);
|
||||
extern int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||
extern int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState);
|
||||
|
||||
#endif /* _NTFSDIR_H */
|
||||
|
||||
|
@ -45,36 +45,36 @@
|
||||
|
||||
#define STATE(x) ((ntfs_file_state*)x)
|
||||
|
||||
void ntfsCloseFile ( ntfs_file_state *file )
|
||||
void ntfsCloseFile (ntfs_file_state *file)
|
||||
{
|
||||
// Sanity check
|
||||
if ( !file || !file->vd )
|
||||
if (!file || !file->vd)
|
||||
return;
|
||||
|
||||
// Special case fix ups for compressed and/or encrypted files
|
||||
if ( file->compressed )
|
||||
ntfs_attr_pclose( file->data_na );
|
||||
if (file->compressed)
|
||||
ntfs_attr_pclose(file->data_na);
|
||||
#ifdef HAVE_SETXATTR
|
||||
if ( file->encrypted )
|
||||
ntfs_efs_fixup_attribute( NULL, file->data_na );
|
||||
if (file->encrypted)
|
||||
ntfs_efs_fixup_attribute(NULL, file->data_na);
|
||||
#endif
|
||||
// Close the file data attribute (if open)
|
||||
if ( file->data_na )
|
||||
ntfs_attr_close( file->data_na );
|
||||
if (file->data_na)
|
||||
ntfs_attr_close(file->data_na);
|
||||
|
||||
// Sync the file (and its attributes) to disc
|
||||
if ( file->write )
|
||||
if(file->write)
|
||||
{
|
||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME | NTFS_UPDATE_CTIME );
|
||||
ntfsSync( file->vd, file->ni );
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME | NTFS_UPDATE_CTIME);
|
||||
ntfsSync(file->vd, file->ni);
|
||||
}
|
||||
|
||||
if ( file->read )
|
||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
||||
if (file->read)
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Close the file (if open)
|
||||
if ( file->ni )
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
if (file->ni)
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
|
||||
// Reset the file state
|
||||
file->ni = NULL;
|
||||
@ -89,132 +89,106 @@ void ntfsCloseFile ( ntfs_file_state *file )
|
||||
return;
|
||||
}
|
||||
|
||||
int ntfs_open_r ( struct _reent *r, void *fileStruct, const char *path, int flags, int mode )
|
||||
int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
|
||||
{
|
||||
ntfs_log_trace( "fileStruct %p, path %s, flags %i, mode %i\n", fileStruct, path, flags, mode );
|
||||
ntfs_log_trace("fileStruct %p, path %s, flags %i, mode %i\n", fileStruct, path, flags, mode);
|
||||
|
||||
ntfs_file_state* file = STATE( fileStruct );
|
||||
ntfs_file_state* file = STATE(fileStruct);
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
file->vd = ntfsGetVolume( path );
|
||||
if ( !file->vd )
|
||||
{
|
||||
file->vd = ntfsGetVolume(path);
|
||||
if (!file->vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Determine which mode the file is opened for
|
||||
file->flags = flags;
|
||||
if ( ( flags & 0x03 ) == O_RDONLY )
|
||||
{
|
||||
if ((flags & 0x03) == O_RDONLY) {
|
||||
file->read = true;
|
||||
file->write = false;
|
||||
file->append = false;
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_WRONLY )
|
||||
{
|
||||
} else if ((flags & 0x03) == O_WRONLY) {
|
||||
file->read = false;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
}
|
||||
else if ( ( flags & 0x03 ) == O_RDWR )
|
||||
{
|
||||
file->append = (flags & O_APPEND);
|
||||
} else if ((flags & 0x03) == O_RDWR) {
|
||||
file->read = true;
|
||||
file->write = true;
|
||||
file->append = ( flags & O_APPEND );
|
||||
}
|
||||
else
|
||||
{
|
||||
file->append = (flags & O_APPEND);
|
||||
} else {
|
||||
r->_errno = EACCES;
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Try and find the file and (if found) ensure that it is not a directory
|
||||
file->ni = ntfsOpenEntry( file->vd, path );
|
||||
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
file->ni = ntfsOpenEntry(file->vd, path);
|
||||
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Are we creating this file?
|
||||
if ( flags & O_CREAT )
|
||||
{
|
||||
|
||||
// The file SHOULD NOT already exist
|
||||
if ( file->ni )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
if ((flags & O_CREAT) && !file->ni) {
|
||||
|
||||
// Create the file
|
||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
file->ni = ntfsCreate(file->vd, path, S_IFREG, NULL);
|
||||
if (!file->ni) {
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Sanity check, the file should be open by now
|
||||
if ( !file->ni )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (!file->ni) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open the files data attribute
|
||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
||||
if ( !file->data_na )
|
||||
{
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
file->data_na = ntfs_attr_open(file->ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if(!file->data_na) {
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Determine if this files data is compressed and/or encrypted
|
||||
file->compressed = NAttrCompressed( file->data_na ) || ( file->ni->flags & FILE_ATTR_COMPRESSED );
|
||||
file->encrypted = NAttrEncrypted( file->data_na ) || ( file->ni->flags & FILE_ATTR_ENCRYPTED );
|
||||
file->compressed = NAttrCompressed(file->data_na) || (file->ni->flags & FILE_ATTR_COMPRESSED);
|
||||
file->encrypted = NAttrEncrypted(file->data_na) || (file->ni->flags & FILE_ATTR_ENCRYPTED);
|
||||
|
||||
// We cannot read/write encrypted files
|
||||
if ( file->encrypted )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
if (file->encrypted) {
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we aren't trying to write to a read-only file
|
||||
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Truncate the file if requested
|
||||
if ( ( flags & O_TRUNC ) && file->write )
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
||||
{
|
||||
ntfs_attr_close( file->data_na );
|
||||
ntfsCloseEntry( file->vd, file->ni );
|
||||
ntfsUnlock( file->vd );
|
||||
if ((flags & O_TRUNC) && file->write) {
|
||||
if (ntfs_attr_truncate(file->data_na, 0)) {
|
||||
ntfs_attr_close(file->data_na);
|
||||
ntfsCloseEntry(file->vd, file->ni);
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
@ -224,19 +198,16 @@ int ntfs_open_r ( struct _reent *r, void *fileStruct, const char *path, int flag
|
||||
file->pos = 0;
|
||||
file->len = file->data_na->data_size;
|
||||
|
||||
ntfs_log_trace( "file->len %d\n", file->len );
|
||||
ntfs_log_trace("file->len %d\n", file->len);
|
||||
|
||||
// Update file times
|
||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
// Insert the file into the double-linked FILO list of open files
|
||||
if ( file->vd->firstOpenFile )
|
||||
{
|
||||
if (file->vd->firstOpenFile) {
|
||||
file->nextOpenFile = file->vd->firstOpenFile;
|
||||
file->vd->firstOpenFile->prevOpenFile = file;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
file->nextOpenFile = NULL;
|
||||
}
|
||||
file->prevOpenFile = NULL;
|
||||
@ -244,91 +215,84 @@ int ntfs_open_r ( struct _reent *r, void *fileStruct, const char *path, int flag
|
||||
file->vd->openFileCount++;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return ( int )fileStruct;
|
||||
return (int)fileStruct;
|
||||
}
|
||||
|
||||
int ntfs_close_r ( struct _reent *r, int fd )
|
||||
int ntfs_close_r (struct _reent *r, int fd)
|
||||
{
|
||||
ntfs_log_trace( "fd %p\n", fd );
|
||||
ntfs_log_trace("fd %p\n", fd);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd )
|
||||
{
|
||||
if (!file || !file->vd) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Close the file
|
||||
ntfsCloseFile( file );
|
||||
ntfsCloseFile(file);
|
||||
|
||||
// Remove the file from the double-linked FILO list of open files
|
||||
file->vd->openFileCount--;
|
||||
if ( file->nextOpenFile )
|
||||
if (file->nextOpenFile)
|
||||
file->nextOpenFile->prevOpenFile = file->prevOpenFile;
|
||||
if ( file->prevOpenFile )
|
||||
if (file->prevOpenFile)
|
||||
file->prevOpenFile->nextOpenFile = file->nextOpenFile;
|
||||
else
|
||||
file->vd->firstOpenFile = file->nextOpenFile;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t ntfs_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||
{
|
||||
ntfs_log_trace( "fd %p, ptr %p, len %Li\n", fd, ptr, len );
|
||||
ntfs_log_trace("fd %p, ptr %p, len %Li\n", fd, ptr, len);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
ssize_t written = 0;
|
||||
off_t old_pos = 0;
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if ( !ptr || len <= 0 )
|
||||
{
|
||||
if (!ptr || len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (!file->write) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are in append mode, backup the current position and move to the end of the file
|
||||
if ( file->append )
|
||||
{
|
||||
if (file->append) {
|
||||
old_pos = file->pos;
|
||||
file->pos = file->len;
|
||||
}
|
||||
|
||||
// Write to the files data atrribute
|
||||
while ( len )
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
||||
if ( ret <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
while (len) {
|
||||
ssize_t ret = ntfs_attr_pwrite(file->data_na, file->pos, len, ptr);
|
||||
if (ret <= 0) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
@ -338,72 +302,65 @@ ssize_t ntfs_write_r ( struct _reent *r, int fd, const char *ptr, size_t len )
|
||||
}
|
||||
|
||||
// If we are in append mode, restore the current position to were it was prior to this write
|
||||
if ( file->append )
|
||||
{
|
||||
if (file->append) {
|
||||
file->pos = old_pos;
|
||||
}
|
||||
|
||||
// Mark the file for archiving (if we actually wrote something)
|
||||
if ( written )
|
||||
if (written)
|
||||
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
|
||||
// Update the files data length
|
||||
file->len = file->data_na->data_size;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
ssize_t ntfs_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
{
|
||||
ntfs_log_trace( "fd %p, ptr %p, len %Li\n", fd, ptr, len );
|
||||
ntfs_log_trace("fd %p, ptr %p, len %Li\n", fd, ptr, len);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
ssize_t read = 0;
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases where we don't actually have to do anything
|
||||
if ( !ptr || len <= 0 )
|
||||
{
|
||||
if (!ptr || len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to read from this file
|
||||
if ( !file->read )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (!file->read) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Don't read past the end of file
|
||||
if ( file->pos + len > file->len )
|
||||
{
|
||||
if (file->pos + len > file->len) {
|
||||
r->_errno = EOVERFLOW;
|
||||
len = file->len - file->pos;
|
||||
ntfs_log_trace( "EOVERFLOW" );
|
||||
ntfs_log_trace("EOVERFLOW");
|
||||
}
|
||||
|
||||
ntfs_log_trace( "file->pos:%d, len:%d, file->len:%d \n", ( u32 )file->pos, ( u32 )len, ( u32 )file->len );
|
||||
ntfs_log_trace("file->pos:%d, len:%d, file->len:%d \n", (u32)file->pos, (u32)len, (u32)file->len);
|
||||
|
||||
// Read from the files data attribute
|
||||
while ( len )
|
||||
{
|
||||
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr );
|
||||
if ( ret <= 0 || ret > len )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
while (len) {
|
||||
ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
|
||||
if (ret <= 0 || ret > len) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
@ -416,166 +373,154 @@ ssize_t ntfs_read_r ( struct _reent *r, int fd, char *ptr, size_t len )
|
||||
// Update file times (if we actually read something)
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
off_t ntfs_seek_r ( struct _reent *r, int fd, off_t pos, int dir )
|
||||
off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||
{
|
||||
ntfs_log_trace( "fd %p, pos %Li, dir %i\n", fd, pos, dir );
|
||||
ntfs_log_trace("fd %p, pos %Li, dir %i\n", fd, pos, dir);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
off_t position = 0;
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Set the files current position
|
||||
switch ( dir )
|
||||
{
|
||||
case SEEK_SET: position = file->pos = MIN( MAX( pos, 0 ), file->len ); break;
|
||||
case SEEK_CUR: position = file->pos = MIN( MAX( file->pos + pos, 0 ), file->len ); break;
|
||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
||||
switch(dir) {
|
||||
case SEEK_SET: position = file->pos = MIN(MAX(pos, 0), file->len); break;
|
||||
case SEEK_CUR: position = file->pos = MIN(MAX(file->pos + pos, 0), file->len); break;
|
||||
case SEEK_END: position = file->pos = MIN(MAX(file->len + pos, 0), file->len); break;
|
||||
}
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return position;
|
||||
}
|
||||
int ntfs_fstat_r ( struct _reent *r, int fd, struct stat *st )
|
||||
int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||
{
|
||||
ntfs_log_trace( "fd %p\n", fd );
|
||||
ntfs_log_trace("fd %p\n", fd);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if ( !st )
|
||||
if (!st)
|
||||
return 0;
|
||||
|
||||
// Get the file stats
|
||||
ret = ntfsStat( file->vd, file->ni, st );
|
||||
if ( ret )
|
||||
ret = ntfsStat(file->vd, file->ni, st);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ntfs_ftruncate_r ( struct _reent *r, int fd, off_t len )
|
||||
int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||
{
|
||||
ntfs_log_trace( "fd %p, len %Li\n", fd, len );
|
||||
ntfs_log_trace("fd %p, len %Li\n", fd, len);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Check that we are allowed to write to this file
|
||||
if ( !file->write )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (!file->write) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// For compressed files, only deleting and expanding contents are implemented
|
||||
if ( file->compressed &&
|
||||
len > 0 &&
|
||||
len < file->data_na->initialized_size )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (file->compressed &&
|
||||
len > 0 &&
|
||||
len < file->data_na->initialized_size) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Resize the files data attribute, either by expanding or truncating
|
||||
if ( file->compressed && len > file->data_na->initialized_size )
|
||||
{
|
||||
if (file->compressed && len > file->data_na->initialized_size) {
|
||||
char zero = 0;
|
||||
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ntfs_attr_truncate( file->data_na, len ) )
|
||||
{
|
||||
ntfsUnlock( file->vd );
|
||||
} else {
|
||||
if (ntfs_attr_truncate(file->data_na, len)) {
|
||||
ntfsUnlock(file->vd);
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the file for archiving (if we actually changed something)
|
||||
if ( file->len != file->data_na->data_size )
|
||||
if (file->len != file->data_na->data_size)
|
||||
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
|
||||
// Update file times (if we actually changed something)
|
||||
if ( file->len != file->data_na->data_size )
|
||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_AMCTIME );
|
||||
if (file->len != file->data_na->data_size)
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);
|
||||
|
||||
// Update the files data length
|
||||
file->len = file->data_na->data_size;
|
||||
|
||||
// Sync the file (and its attributes) to disc
|
||||
ntfsSync( file->vd, file->ni );
|
||||
ntfsSync(file->vd, file->ni);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_fsync_r ( struct _reent *r, int fd )
|
||||
int ntfs_fsync_r (struct _reent *r, int fd)
|
||||
{
|
||||
ntfs_log_trace( "fd %p\n", fd );
|
||||
ntfs_log_trace("fd %p\n", fd);
|
||||
|
||||
ntfs_file_state* file = STATE( fd );
|
||||
ntfs_file_state* file = STATE(fd);
|
||||
int ret = 0;
|
||||
|
||||
// Sanity check
|
||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
||||
{
|
||||
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock( file->vd );
|
||||
ntfsLock(file->vd);
|
||||
|
||||
// Sync the file (and its attributes) to disc
|
||||
ret = ntfsSync( file->vd, file->ni );
|
||||
if ( ret )
|
||||
ret = ntfsSync(file->vd, file->ni);
|
||||
if (ret)
|
||||
r->_errno = errno;
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock( file->vd );
|
||||
ntfsUnlock(file->vd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -32,8 +32,7 @@
|
||||
/**
|
||||
* ntfs_file_state - File state
|
||||
*/
|
||||
typedef struct _ntfs_file_state
|
||||
{
|
||||
typedef struct _ntfs_file_state {
|
||||
ntfs_vd *vd; /* Volume this file belongs to */
|
||||
ntfs_inode *ni; /* File descriptor */
|
||||
ntfs_attr *data_na; /* File data descriptor */
|
||||
@ -50,17 +49,17 @@ typedef struct _ntfs_file_state
|
||||
} ntfs_file_state;
|
||||
|
||||
/* File state routines */
|
||||
void ntfsCloseFile ( ntfs_file_state *file );
|
||||
void ntfsCloseFile (ntfs_file_state *file);
|
||||
|
||||
/* Gekko devoptab file routines for NTFS-based devices */
|
||||
extern int ntfs_open_r ( struct _reent *r, void *fileStruct, const char *path, int flags, int mode );
|
||||
extern int ntfs_close_r ( struct _reent *r, int fd );
|
||||
extern ssize_t ntfs_write_r ( struct _reent *r, int fd, const char *ptr, size_t len );
|
||||
extern ssize_t ntfs_read_r ( struct _reent *r, int fd, char *ptr, size_t len );
|
||||
extern off_t ntfs_seek_r ( struct _reent *r, int fd, off_t pos, int dir );
|
||||
extern int ntfs_fstat_r ( struct _reent *r, int fd, struct stat *st );
|
||||
extern int ntfs_ftruncate_r ( struct _reent *r, int fd, off_t len );
|
||||
extern int ntfs_fsync_r ( struct _reent *r, int fd );
|
||||
extern int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
|
||||
extern int ntfs_close_r (struct _reent *r, int fd);
|
||||
extern ssize_t ntfs_write_r (struct _reent *r, int fd, const char *ptr, size_t len);
|
||||
extern ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len);
|
||||
extern off_t ntfs_seek_r (struct _reent *r, int fd, off_t pos, int dir);
|
||||
extern int ntfs_fstat_r (struct _reent *r, int fd, struct stat *st);
|
||||
extern int ntfs_ftruncate_r (struct _reent *r, int fd, off_t len);
|
||||
extern int ntfs_fsync_r (struct _reent *r, int fd);
|
||||
|
||||
#endif /* _NTFSFILE_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -69,43 +69,39 @@ struct _ntfs_dir_state;
|
||||
/**
|
||||
* PRIMARY_PARTITION - Block device partition record
|
||||
*/
|
||||
typedef struct _PARTITION_RECORD
|
||||
{
|
||||
typedef struct _PARTITION_RECORD {
|
||||
u8 status; /* Partition status; see above */
|
||||
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
||||
u8 type; /* Partition type; see above */
|
||||
u8 chs_end[3]; /* Cylinder-head-sector address to last block of partition */
|
||||
u32 lba_start; /* Local block address to first sector of partition */
|
||||
u32 block_count; /* Number of blocks in partition */
|
||||
} __attribute__( ( __packed__ ) ) PARTITION_RECORD;
|
||||
} __attribute__((__packed__)) PARTITION_RECORD;
|
||||
|
||||
/**
|
||||
* MASTER_BOOT_RECORD - Block device master boot record
|
||||
*/
|
||||
typedef struct _MASTER_BOOT_RECORD
|
||||
{
|
||||
typedef struct _MASTER_BOOT_RECORD {
|
||||
u8 code_area[446]; /* Code area; normally empty */
|
||||
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
||||
u16 signature; /* MBR signature; 0xAA55 */
|
||||
} __attribute__( ( __packed__ ) ) MASTER_BOOT_RECORD;
|
||||
} __attribute__((__packed__)) MASTER_BOOT_RECORD;
|
||||
|
||||
/**
|
||||
* EXTENDED_PARTITION - Block device extended boot record
|
||||
*/
|
||||
typedef struct _EXTENDED_BOOT_RECORD
|
||||
{
|
||||
typedef struct _EXTENDED_BOOT_RECORD {
|
||||
u8 code_area[446]; /* Code area; normally empty */
|
||||
PARTITION_RECORD partition; /* Primary partition */
|
||||
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
|
||||
u8 reserved[32]; /* Normally empty */
|
||||
u16 signature; /* EBR signature; 0xAA55 */
|
||||
} __attribute__( ( __packed__ ) ) EXTENDED_BOOT_RECORD;
|
||||
} __attribute__((__packed__)) EXTENDED_BOOT_RECORD;
|
||||
|
||||
/**
|
||||
* INTERFACE_ID - Disc interface identifier
|
||||
*/
|
||||
typedef struct _INTERFACE_ID
|
||||
{
|
||||
typedef struct _INTERFACE_ID {
|
||||
const char *name; /* Interface name */
|
||||
const DISC_INTERFACE *interface; /* Disc interface */
|
||||
} INTERFACE_ID;
|
||||
@ -113,8 +109,7 @@ typedef struct _INTERFACE_ID
|
||||
/**
|
||||
* ntfs_atime_t - File access time update strategies
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
ATIME_ENABLED, /* Update access times */
|
||||
ATIME_DISABLED /* Don't update access times */
|
||||
} ntfs_atime_t;
|
||||
@ -122,8 +117,7 @@ typedef enum
|
||||
/**
|
||||
* ntfs_vd - NTFS volume descriptor
|
||||
*/
|
||||
typedef struct _ntfs_vd
|
||||
{
|
||||
typedef struct _ntfs_vd {
|
||||
struct ntfs_device *dev; /* NTFS device handle */
|
||||
ntfs_volume *vol; /* NTFS volume handle */
|
||||
mutex_t lock; /* Volume lock mutex */
|
||||
@ -145,40 +139,40 @@ typedef struct _ntfs_vd
|
||||
} ntfs_vd;
|
||||
|
||||
/* Lock volume */
|
||||
static inline void ntfsLock ( ntfs_vd *vd )
|
||||
static inline void ntfsLock (ntfs_vd *vd)
|
||||
{
|
||||
LWP_MutexLock( vd->lock );
|
||||
LWP_MutexLock(vd->lock);
|
||||
}
|
||||
|
||||
/* Unlock volume */
|
||||
static inline void ntfsUnlock ( ntfs_vd *vd )
|
||||
static inline void ntfsUnlock (ntfs_vd *vd)
|
||||
{
|
||||
LWP_MutexUnlock( vd->lock );
|
||||
LWP_MutexUnlock(vd->lock);
|
||||
}
|
||||
|
||||
/* Gekko device related routines */
|
||||
int ntfsAddDevice ( const char *name, void *deviceData );
|
||||
void ntfsRemoveDevice ( const char *path );
|
||||
const devoptab_t *ntfsGetDevice ( const char *path, bool useDefaultDevice );
|
||||
const devoptab_t *ntfsGetDevOpTab ( void );
|
||||
const INTERFACE_ID* ntfsGetDiscInterfaces ( void );
|
||||
int ntfsAddDevice (const char *name, void *deviceData);
|
||||
void ntfsRemoveDevice (const char *path);
|
||||
const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice);
|
||||
const devoptab_t *ntfsGetDevOpTab (void);
|
||||
const INTERFACE_ID* ntfsGetDiscInterfaces (void);
|
||||
|
||||
/* Miscellaneous helper/support routines */
|
||||
int ntfsInitVolume ( ntfs_vd *vd );
|
||||
void ntfsDeinitVolume ( ntfs_vd *vd );
|
||||
ntfs_vd *ntfsGetVolume ( const char *path );
|
||||
ntfs_inode *ntfsOpenEntry ( ntfs_vd *vd, const char *path );
|
||||
ntfs_inode *ntfsParseEntry ( ntfs_vd *vd, const char *path, int reparseLevel );
|
||||
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni );
|
||||
ntfs_inode *ntfsCreate ( ntfs_vd *vd, const char *path, mode_t type, const char *target );
|
||||
int ntfsLink ( ntfs_vd *vd, const char *old_path, const char *new_path );
|
||||
int ntfsUnlink ( ntfs_vd *vd, const char *path );
|
||||
int ntfsSync ( ntfs_vd *vd, ntfs_inode *ni );
|
||||
int ntfsStat ( ntfs_vd *vd, ntfs_inode *ni, struct stat *st );
|
||||
void ntfsUpdateTimes ( ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask );
|
||||
int ntfsInitVolume (ntfs_vd *vd);
|
||||
void ntfsDeinitVolume (ntfs_vd *vd);
|
||||
ntfs_vd *ntfsGetVolume (const char *path);
|
||||
ntfs_inode *ntfsOpenEntry (ntfs_vd *vd, const char *path);
|
||||
ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel);
|
||||
void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni);
|
||||
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target);
|
||||
int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path);
|
||||
int ntfsUnlink (ntfs_vd *vd, const char *path);
|
||||
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni);
|
||||
int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st);
|
||||
void ntfsUpdateTimes (ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask);
|
||||
|
||||
const char *ntfsRealPath ( const char *path );
|
||||
int ntfsUnicodeToLocal ( const ntfschar *ins, const int ins_len, char **outs, int outs_len );
|
||||
int ntfsLocalToUnicode ( const char *ins, ntfschar **outs );
|
||||
const char *ntfsRealPath (const char *path);
|
||||
int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int outs_len);
|
||||
int ntfsLocalToUnicode (const char *ins, ntfschar **outs);
|
||||
|
||||
#endif /* _NTFSINTERNAL_H */
|
||||
|
@ -55,19 +55,19 @@ typedef sle64 ntfs_time;
|
||||
*
|
||||
* Return: A Unix time (number of seconds since 1970, and nanoseconds)
|
||||
*/
|
||||
static __inline__ struct timespec ntfs2timespec( ntfs_time ntfstime )
|
||||
static __inline__ struct timespec ntfs2timespec(ntfs_time ntfstime)
|
||||
{
|
||||
struct timespec spec;
|
||||
s64 cputime;
|
||||
struct timespec spec;
|
||||
s64 cputime;
|
||||
|
||||
cputime = sle64_to_cpu( ntfstime );
|
||||
spec.tv_sec = ( cputime - ( NTFS_TIME_OFFSET ) ) / 10000000;
|
||||
spec.tv_nsec = ( cputime - ( NTFS_TIME_OFFSET )
|
||||
- ( s64 )spec.tv_sec*10000000 )*100;
|
||||
/* force zero nsec for overflowing dates */
|
||||
if ( ( spec.tv_nsec < 0 ) || ( spec.tv_nsec > 999999999 ) )
|
||||
spec.tv_nsec = 0;
|
||||
return ( spec );
|
||||
cputime = sle64_to_cpu(ntfstime);
|
||||
spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000;
|
||||
spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET)
|
||||
- (s64)spec.tv_sec*10000000)*100;
|
||||
/* force zero nsec for overflowing dates */
|
||||
if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999))
|
||||
spec.tv_nsec = 0;
|
||||
return (spec);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,36 +86,36 @@ static __inline__ struct timespec ntfs2timespec( ntfs_time ntfstime )
|
||||
*
|
||||
* Return: An NTFS time (100ns units since Jan 1601)
|
||||
*/
|
||||
static __inline__ ntfs_time timespec2ntfs( struct timespec spec )
|
||||
static __inline__ ntfs_time timespec2ntfs(struct timespec spec)
|
||||
{
|
||||
s64 units;
|
||||
s64 units;
|
||||
|
||||
units = ( s64 )spec.tv_sec * 10000000
|
||||
+ NTFS_TIME_OFFSET + spec.tv_nsec / 100;
|
||||
return ( cpu_to_le64( units ) );
|
||||
units = (s64)spec.tv_sec * 10000000
|
||||
+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
|
||||
return (cpu_to_le64(units));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current time in ntfs format
|
||||
* Return the current time in ntfs format
|
||||
*/
|
||||
|
||||
static __inline__ ntfs_time ntfs_current_time( void )
|
||||
static __inline__ ntfs_time ntfs_current_time(void)
|
||||
{
|
||||
struct timespec now;
|
||||
struct timespec now;
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME)
|
||||
clock_gettime( CLOCK_REALTIME, &now );
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
struct timeval microseconds;
|
||||
struct timeval microseconds;
|
||||
|
||||
gettimeofday( µseconds, ( struct timezone* )NULL );
|
||||
now.tv_sec = microseconds.tv_sec;
|
||||
now.tv_nsec = microseconds.tv_usec * 1000;
|
||||
gettimeofday(µseconds, (struct timezone*)NULL);
|
||||
now.tv_sec = microseconds.tv_sec;
|
||||
now.tv_nsec = microseconds.tv_usec*1000;
|
||||
#else
|
||||
now.tv_sec = time( ( time_t* )NULL );
|
||||
now.tv_nsec = 0;
|
||||
now.tv_sec = time((time_t*)NULL);
|
||||
now.tv_nsec = 0;
|
||||
#endif
|
||||
return ( timespec2ntfs( now ) );
|
||||
return (timespec2ntfs(now));
|
||||
}
|
||||
|
||||
#endif /* _NTFS_NTFSTIME_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,12 +24,12 @@
|
||||
#ifndef OBJECT_ID_H
|
||||
#define OBJECT_ID_H
|
||||
|
||||
int ntfs_get_ntfs_object_id( ntfs_inode *ni, char *value, size_t size );
|
||||
int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
int ntfs_set_ntfs_object_id( ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags );
|
||||
int ntfs_remove_ntfs_object_id( ntfs_inode *ni );
|
||||
int ntfs_set_ntfs_object_id(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
int ntfs_remove_ntfs_object_id(ntfs_inode *ni);
|
||||
|
||||
int ntfs_delete_object_id_index( ntfs_inode *ni );
|
||||
int ntfs_delete_object_id_index(ntfs_inode *ni);
|
||||
|
||||
#endif /* OBJECT_ID_H */
|
||||
|
@ -22,59 +22,58 @@
|
||||
#ifndef _NTFS_PARAM_H
|
||||
#define _NTFS_PARAM_H
|
||||
|
||||
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
|
||||
#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */
|
||||
#define CACHE_LOOKUP_SIZE 64 /* lookup cache, zero or >= 3 and not too big */
|
||||
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
|
||||
#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */
|
||||
#define CACHE_LOOKUP_SIZE 64 /* lookup cache, zero or >= 3 and not too big */
|
||||
#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */
|
||||
#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */
|
||||
|
||||
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
|
||||
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
||||
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
|
||||
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
||||
|
||||
/* default security sub-authorities */
|
||||
enum
|
||||
{
|
||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||
DEFSECAUTH2 = 589793238,
|
||||
DEFSECAUTH3 = 462843383,
|
||||
DEFSECBASE = 10000
|
||||
/* default security sub-authorities */
|
||||
enum {
|
||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||
DEFSECAUTH2 = 589793238,
|
||||
DEFSECAUTH3 = 462843383,
|
||||
DEFSECBASE = 10000
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameters for compression
|
||||
* Parameters for compression
|
||||
*/
|
||||
|
||||
/* default option for compression */
|
||||
/* default option for compression */
|
||||
#define DEFAULT_COMPRESSION FALSE
|
||||
/* (log2 of) number of clusters in a compression block for new files */
|
||||
/* (log2 of) number of clusters in a compression block for new files */
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
/* maximum cluster size for allowing compression for new files */
|
||||
/* maximum cluster size for allowing compression for new files */
|
||||
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
|
||||
|
||||
/*
|
||||
* Permission checking modes for high level and low level
|
||||
* Permission checking modes for high level and low level
|
||||
*
|
||||
* The choices for high and low lowel are independent, they have
|
||||
* no effect on the library
|
||||
* The choices for high and low lowel are independent, they have
|
||||
* no effect on the library
|
||||
*
|
||||
* Stick to the recommended values unless you understand the consequences
|
||||
* on protection and performances. Use of cacheing is good for
|
||||
* performances, but bad on security.
|
||||
* Stick to the recommended values unless you understand the consequences
|
||||
* on protection and performances. Use of cacheing is good for
|
||||
* performances, but bad on security.
|
||||
*
|
||||
* Possible values for high level :
|
||||
* 1 : no cache, kernel control (recommended)
|
||||
* 4 : no cache, file system control
|
||||
* 7 : no cache, kernel control for ACLs
|
||||
* Possible values for high level :
|
||||
* 1 : no cache, kernel control (recommended)
|
||||
* 4 : no cache, file system control
|
||||
* 7 : no cache, kernel control for ACLs
|
||||
*
|
||||
* Possible values for low level :
|
||||
* 2 : no cache, kernel control
|
||||
* 3 : use kernel/fuse cache, kernel control
|
||||
* 5 : no cache, file system control (recommended)
|
||||
* 8 : no cache, kernel control for ACLs
|
||||
* Possible values for low level :
|
||||
* 2 : no cache, kernel control
|
||||
* 3 : use kernel/fuse cache, kernel control
|
||||
* 5 : no cache, file system control (recommended)
|
||||
* 8 : no cache, kernel control for ACLs
|
||||
*
|
||||
* Use of options 7 and 8 requires a patch to fuse
|
||||
* When Posix ACLs are selected in the configure options, a value
|
||||
* of 6 is added in the mount report.
|
||||
* Use of options 7 and 8 requires a patch to fuse
|
||||
* When Posix ACLs are selected in the configure options, a value
|
||||
* of 6 is added in the mount report.
|
||||
*/
|
||||
|
||||
#define HPERMSCONFIG 1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,16 +24,16 @@
|
||||
#ifndef REPARSE_H
|
||||
#define REPARSE_H
|
||||
|
||||
char *ntfs_make_symlink( ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size );
|
||||
BOOL ntfs_possible_symlink( ntfs_inode *ni );
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size);
|
||||
BOOL ntfs_possible_symlink(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_reparse_data( ntfs_inode *ni, char *value, size_t size );
|
||||
int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
int ntfs_set_ntfs_reparse_data( ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags );
|
||||
int ntfs_remove_ntfs_reparse_data( ntfs_inode *ni );
|
||||
int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni);
|
||||
|
||||
int ntfs_delete_reparse_index( ntfs_inode *ni );
|
||||
int ntfs_delete_reparse_index(ntfs_inode *ni);
|
||||
|
||||
#endif /* REPARSE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -34,57 +34,56 @@ typedef runlist_element runlist;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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. */
|
||||
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 runlist_element *ntfs_rl_extend( ntfs_attr *na, runlist_element *rl,
|
||||
int more_entries );
|
||||
extern runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
|
||||
int more_entries);
|
||||
|
||||
extern LCN ntfs_rl_vcn_to_lcn( const runlist_element *rl, const VCN vcn );
|
||||
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,
|
||||
s64 ofs, const s64 pos, s64 count, void *b );
|
||||
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,
|
||||
s64 ofs, const s64 pos, s64 count, void *b);
|
||||
|
||||
extern runlist_element *ntfs_runlists_merge( runlist_element *drl,
|
||||
runlist_element *srl );
|
||||
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 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_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, int max_size );
|
||||
extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
const runlist_element *rl, const VCN start_vcn, int max_size);
|
||||
|
||||
extern int ntfs_write_significant_bytes( u8 *dst, const u8 *dst_max,
|
||||
const s64 n );
|
||||
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, runlist_element const **stop_rl );
|
||||
extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
const int dst_len, const runlist_element *rl,
|
||||
const VCN start_vcn, runlist_element const **stop_rl);
|
||||
|
||||
extern int ntfs_rl_truncate( runlist **arl, const VCN start_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 );
|
||||
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[] );
|
||||
int test_rl_main(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif /* defined _NTFS_RUNLIST_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* security.h - Exports for handling security/ACLs in NTFS.
|
||||
* security.h - Exports for handling security/ACLs in NTFS.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
@ -40,7 +40,7 @@ typedef u32 be32;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define const_cpu_to_be16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L))
|
||||
#define const_cpu_to_be32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \
|
||||
+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
|
||||
+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
|
||||
#else
|
||||
#define const_cpu_to_be16(x) (x)
|
||||
#define const_cpu_to_be32(x) (x)
|
||||
@ -50,284 +50,270 @@ typedef u32 be32;
|
||||
* item in the mapping list
|
||||
*/
|
||||
|
||||
struct MAPPING
|
||||
{
|
||||
struct MAPPING *next;
|
||||
int xid; /* linux id : uid or gid */
|
||||
SID *sid; /* Windows id : usid or gsid */
|
||||
int grcnt; /* group count (for users only) */
|
||||
gid_t *groups; /* groups which the user is member of */
|
||||
struct MAPPING {
|
||||
struct MAPPING *next;
|
||||
int xid; /* linux id : uid or gid */
|
||||
SID *sid; /* Windows id : usid or gsid */
|
||||
int grcnt; /* group count (for users only) */
|
||||
gid_t *groups; /* groups which the user is member of */
|
||||
};
|
||||
|
||||
/*
|
||||
* Entry in the permissions cache
|
||||
* Note : this cache is not organized as a generic cache
|
||||
* Entry in the permissions cache
|
||||
* Note : this cache is not organized as a generic cache
|
||||
*/
|
||||
|
||||
struct CACHED_PERMISSIONS
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
le32 inh_fileid;
|
||||
le32 inh_dirid;
|
||||
struct CACHED_PERMISSIONS {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
le32 inh_fileid;
|
||||
le32 inh_dirid;
|
||||
#if POSIXACLS
|
||||
struct POSIX_SECURITY *pxdesc;
|
||||
unsigned int pxdescsize: 16;
|
||||
struct POSIX_SECURITY *pxdesc;
|
||||
unsigned int pxdescsize:16;
|
||||
#endif
|
||||
unsigned int mode: 12;
|
||||
unsigned int valid: 1;
|
||||
unsigned int mode:12;
|
||||
unsigned int valid:1;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Entry in the permissions cache for directories with no security_id
|
||||
* Entry in the permissions cache for directories with no security_id
|
||||
*/
|
||||
|
||||
struct CACHED_PERMISSIONS_LEGACY
|
||||
{
|
||||
struct CACHED_PERMISSIONS_LEGACY *next;
|
||||
struct CACHED_PERMISSIONS_LEGACY *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 mft_no;
|
||||
struct CACHED_PERMISSIONS perm;
|
||||
struct CACHED_PERMISSIONS_LEGACY {
|
||||
struct CACHED_PERMISSIONS_LEGACY *next;
|
||||
struct CACHED_PERMISSIONS_LEGACY *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
u64 mft_no;
|
||||
struct CACHED_PERMISSIONS perm;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Entry in the securid cache
|
||||
* Entry in the securid cache
|
||||
*/
|
||||
|
||||
struct CACHED_SECURID
|
||||
{
|
||||
struct CACHED_SECURID *next;
|
||||
struct CACHED_SECURID *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
unsigned int dmode;
|
||||
le32 securid;
|
||||
struct CACHED_SECURID {
|
||||
struct CACHED_SECURID *next;
|
||||
struct CACHED_SECURID *previous;
|
||||
void *variable;
|
||||
size_t varsize;
|
||||
/* above fields must match "struct CACHED_GENERIC" */
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
unsigned int dmode;
|
||||
le32 securid;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Header of the security cache
|
||||
* (has no cache structure by itself)
|
||||
* Header of the security cache
|
||||
* (has no cache structure by itself)
|
||||
*/
|
||||
|
||||
struct CACHED_PERMISSIONS_HEADER
|
||||
{
|
||||
unsigned int last;
|
||||
/* statistics for permissions */
|
||||
unsigned long p_writes;
|
||||
unsigned long p_reads;
|
||||
unsigned long p_hits;
|
||||
struct CACHED_PERMISSIONS_HEADER {
|
||||
unsigned int last;
|
||||
/* statistics for permissions */
|
||||
unsigned long p_writes;
|
||||
unsigned long p_reads;
|
||||
unsigned long p_hits;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* The whole permissions cache
|
||||
* The whole permissions cache
|
||||
*/
|
||||
|
||||
struct PERMISSIONS_CACHE
|
||||
{
|
||||
struct CACHED_PERMISSIONS_HEADER head;
|
||||
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
||||
struct PERMISSIONS_CACHE {
|
||||
struct CACHED_PERMISSIONS_HEADER head;
|
||||
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Security flags values
|
||||
* Security flags values
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||
SECURITY_STATICGRPS, /* use static groups for access control */
|
||||
SECURITY_WANTED /* a security related option was present */
|
||||
enum {
|
||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||
SECURITY_STATICGRPS, /* use static groups for access control */
|
||||
SECURITY_WANTED /* a security related option was present */
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Security context, needed by most security functions
|
||||
* Security context, needed by most security functions
|
||||
*/
|
||||
|
||||
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
||||
|
||||
struct SECURITY_CONTEXT
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
struct MAPPING *mapping[MAPCOUNT];
|
||||
struct PERMISSIONS_CACHE **pseccache;
|
||||
uid_t uid; /* uid of user requesting (not the mounter) */
|
||||
gid_t gid; /* gid of user requesting (not the mounter) */
|
||||
pid_t tid; /* thread id of thread requesting */
|
||||
mode_t umask; /* umask of requesting thread */
|
||||
} ;
|
||||
struct SECURITY_CONTEXT {
|
||||
ntfs_volume *vol;
|
||||
struct MAPPING *mapping[MAPCOUNT];
|
||||
struct PERMISSIONS_CACHE **pseccache;
|
||||
uid_t uid; /* uid of user requesting (not the mounter) */
|
||||
gid_t gid; /* gid of user requesting (not the mounter) */
|
||||
pid_t tid; /* thread id of thread requesting */
|
||||
mode_t umask; /* umask of requesting thread */
|
||||
} ;
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
/*
|
||||
* Posix ACL structures
|
||||
* Posix ACL structures
|
||||
*/
|
||||
|
||||
struct POSIX_ACE
|
||||
{
|
||||
u16 tag;
|
||||
u16 perms;
|
||||
s32 id;
|
||||
|
||||
struct POSIX_ACE {
|
||||
u16 tag;
|
||||
u16 perms;
|
||||
s32 id;
|
||||
} ;
|
||||
|
||||
struct POSIX_ACL {
|
||||
u8 version;
|
||||
u8 flags;
|
||||
u16 filler;
|
||||
struct POSIX_ACE ace[0];
|
||||
} ;
|
||||
|
||||
struct POSIX_ACL
|
||||
{
|
||||
u8 version;
|
||||
u8 flags;
|
||||
u16 filler;
|
||||
struct POSIX_ACE ace[0];
|
||||
struct POSIX_SECURITY {
|
||||
mode_t mode;
|
||||
int acccnt;
|
||||
int defcnt;
|
||||
int firstdef;
|
||||
u16 tagsset;
|
||||
struct POSIX_ACL acl;
|
||||
} ;
|
||||
|
||||
struct POSIX_SECURITY
|
||||
{
|
||||
mode_t mode;
|
||||
int acccnt;
|
||||
int defcnt;
|
||||
int firstdef;
|
||||
u16 tagsset;
|
||||
struct POSIX_ACL acl;
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
* Posix tags, cpu-endian 16 bits
|
||||
* Posix tags, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
POSIX_ACL_USER_OBJ = 1,
|
||||
POSIX_ACL_USER = 2,
|
||||
POSIX_ACL_GROUP_OBJ = 4,
|
||||
POSIX_ACL_GROUP = 8,
|
||||
POSIX_ACL_MASK = 16,
|
||||
POSIX_ACL_OTHER = 32,
|
||||
POSIX_ACL_SPECIAL = 64 /* internal use only */
|
||||
|
||||
enum {
|
||||
POSIX_ACL_USER_OBJ = 1,
|
||||
POSIX_ACL_USER = 2,
|
||||
POSIX_ACL_GROUP_OBJ = 4,
|
||||
POSIX_ACL_GROUP = 8,
|
||||
POSIX_ACL_MASK = 16,
|
||||
POSIX_ACL_OTHER = 32,
|
||||
POSIX_ACL_SPECIAL = 64 /* internal use only */
|
||||
} ;
|
||||
|
||||
#define POSIX_ACL_EXTENSIONS (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK)
|
||||
|
||||
|
||||
/*
|
||||
* Posix permissions, cpu-endian 16 bits
|
||||
* Posix permissions, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
POSIX_PERM_X = 1,
|
||||
POSIX_PERM_W = 2,
|
||||
POSIX_PERM_R = 4,
|
||||
POSIX_PERM_DENIAL = 64 /* internal use only */
|
||||
|
||||
enum {
|
||||
POSIX_PERM_X = 1,
|
||||
POSIX_PERM_W = 2,
|
||||
POSIX_PERM_R = 4,
|
||||
POSIX_PERM_DENIAL = 64 /* internal use only */
|
||||
} ;
|
||||
|
||||
#define POSIX_VERSION 2
|
||||
|
||||
#endif
|
||||
|
||||
extern BOOL ntfs_guid_is_zero( const GUID *guid );
|
||||
extern char *ntfs_guid_to_mbs( const GUID *guid, char *guid_str );
|
||||
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
|
||||
* @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 )
|
||||
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;
|
||||
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 );
|
||||
extern int ntfs_sd_add_everyone( ntfs_inode *ni );
|
||||
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);
|
||||
extern int ntfs_sd_add_everyone(ntfs_inode *ni);
|
||||
|
||||
extern le32 ntfs_security_hash( const SECURITY_DESCRIPTOR_RELATIVE *sd,
|
||||
const u32 len );
|
||||
extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd,
|
||||
const u32 len);
|
||||
|
||||
int ntfs_build_mapping( struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
||||
BOOL allowdef );
|
||||
int ntfs_get_owner_mode( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, struct stat* );
|
||||
int ntfs_set_mode( struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode );
|
||||
BOOL ntfs_allowed_as_owner( struct SECURITY_CONTEXT *scx, ntfs_inode *ni );
|
||||
int ntfs_allowed_access( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, int accesstype );
|
||||
BOOL old_ntfs_allowed_dir_access( struct SECURITY_CONTEXT *scx,
|
||||
const char *path, int accesstype );
|
||||
int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
||||
BOOL allowdef);
|
||||
int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, struct stat*);
|
||||
int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode);
|
||||
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
|
||||
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, int accesstype);
|
||||
BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
||||
const char *path, int accesstype);
|
||||
|
||||
#if POSIXACLS
|
||||
le32 ntfs_alloc_securid( struct SECURITY_CONTEXT *scx,
|
||||
uid_t uid, gid_t gid, ntfs_inode *dir_ni,
|
||||
mode_t mode, BOOL isdir );
|
||||
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
||||
uid_t uid, gid_t gid, ntfs_inode *dir_ni,
|
||||
mode_t mode, BOOL isdir);
|
||||
#else
|
||||
le32 ntfs_alloc_securid( struct SECURITY_CONTEXT *scx,
|
||||
uid_t uid, gid_t gid, mode_t mode, BOOL isdir );
|
||||
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
||||
uid_t uid, gid_t gid, mode_t mode, BOOL isdir);
|
||||
#endif
|
||||
int ntfs_set_owner( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
uid_t uid, gid_t gid );
|
||||
int ntfs_set_ownmod( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode );
|
||||
int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
uid_t uid, gid_t gid);
|
||||
int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
|
||||
#if POSIXACLS
|
||||
int ntfs_set_owner_mode( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||
mode_t mode, struct POSIX_SECURITY *pxdesc );
|
||||
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||
mode_t mode, struct POSIX_SECURITY *pxdesc);
|
||||
#else
|
||||
int ntfs_set_owner_mode( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode );
|
||||
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
|
||||
#endif
|
||||
le32 ntfs_inherited_id( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *dir_ni, BOOL fordir );
|
||||
int ntfs_open_secure( ntfs_volume *vol );
|
||||
void ntfs_close_secure( struct SECURITY_CONTEXT *scx );
|
||||
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *dir_ni, BOOL fordir);
|
||||
int ntfs_open_secure(ntfs_volume *vol);
|
||||
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
int ntfs_set_inherited_posix( struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||
ntfs_inode *dir_ni, mode_t mode );
|
||||
int ntfs_get_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name, char *value, size_t size );
|
||||
int ntfs_set_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name, const char *value, size_t size,
|
||||
int flags );
|
||||
int ntfs_remove_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name );
|
||||
int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||
ntfs_inode *dir_ni, mode_t mode);
|
||||
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name, char *value, size_t size);
|
||||
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name, const char *value, size_t size,
|
||||
int flags);
|
||||
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name);
|
||||
#endif
|
||||
|
||||
int ntfs_get_ntfs_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
char *value, size_t size );
|
||||
int ntfs_set_ntfs_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags );
|
||||
|
||||
int ntfs_get_ntfs_attrib( ntfs_inode *ni, char *value, size_t size );
|
||||
int ntfs_set_ntfs_attrib( ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags );
|
||||
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
char *value, size_t size);
|
||||
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags);
|
||||
|
||||
int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size);
|
||||
int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
||||
const char *value, size_t size, int flags);
|
||||
|
||||
|
||||
/*
|
||||
* Security API for direct access to security descriptors
|
||||
* based on Win32 API
|
||||
* Security API for direct access to security descriptors
|
||||
* based on Win32 API
|
||||
*/
|
||||
|
||||
#define MAGIC_API 0x09042009
|
||||
|
||||
struct SECURITY_API
|
||||
{
|
||||
u32 magic;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
struct SECURITY_API {
|
||||
u32 magic;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
} ;
|
||||
|
||||
/*
|
||||
@ -336,36 +322,36 @@ struct SECURITY_API
|
||||
* native cpu representation.
|
||||
* When disk representation (le) is needed, use SE_DACL_PRESENT, etc.
|
||||
*/
|
||||
enum { OWNER_SECURITY_INFORMATION = 1,
|
||||
GROUP_SECURITY_INFORMATION = 2,
|
||||
DACL_SECURITY_INFORMATION = 4,
|
||||
SACL_SECURITY_INFORMATION = 8
|
||||
} ;
|
||||
enum { OWNER_SECURITY_INFORMATION = 1,
|
||||
GROUP_SECURITY_INFORMATION = 2,
|
||||
DACL_SECURITY_INFORMATION = 4,
|
||||
SACL_SECURITY_INFORMATION = 8
|
||||
} ;
|
||||
|
||||
int ntfs_get_file_security( struct SECURITY_API *scapi,
|
||||
const char *path, u32 selection,
|
||||
char *buf, u32 buflen, u32 *psize );
|
||||
int ntfs_set_file_security( struct SECURITY_API *scapi,
|
||||
const char *path, u32 selection, const char *attr );
|
||||
int ntfs_get_file_attributes( struct SECURITY_API *scapi,
|
||||
const char *path );
|
||||
BOOL ntfs_set_file_attributes( struct SECURITY_API *scapi,
|
||||
const char *path, s32 attrib );
|
||||
BOOL ntfs_read_directory( struct SECURITY_API *scapi,
|
||||
const char *path, ntfs_filldir_t callback, void *context );
|
||||
int ntfs_read_sds( struct SECURITY_API *scapi,
|
||||
char *buf, u32 size, u32 offset );
|
||||
INDEX_ENTRY *ntfs_read_sii( struct SECURITY_API *scapi,
|
||||
INDEX_ENTRY *entry );
|
||||
INDEX_ENTRY *ntfs_read_sdh( struct SECURITY_API *scapi,
|
||||
INDEX_ENTRY *entry );
|
||||
struct SECURITY_API *ntfs_initialize_file_security( const char *device,
|
||||
int flags );
|
||||
BOOL ntfs_leave_file_security( struct SECURITY_API *scx );
|
||||
int ntfs_get_file_security(struct SECURITY_API *scapi,
|
||||
const char *path, u32 selection,
|
||||
char *buf, u32 buflen, u32 *psize);
|
||||
int ntfs_set_file_security(struct SECURITY_API *scapi,
|
||||
const char *path, u32 selection, const char *attr);
|
||||
int ntfs_get_file_attributes(struct SECURITY_API *scapi,
|
||||
const char *path);
|
||||
BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
|
||||
const char *path, s32 attrib);
|
||||
BOOL ntfs_read_directory(struct SECURITY_API *scapi,
|
||||
const char *path, ntfs_filldir_t callback, void *context);
|
||||
int ntfs_read_sds(struct SECURITY_API *scapi,
|
||||
char *buf, u32 size, u32 offset);
|
||||
INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
|
||||
INDEX_ENTRY *entry);
|
||||
INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
|
||||
INDEX_ENTRY *entry);
|
||||
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
||||
int flags);
|
||||
BOOL ntfs_leave_file_security(struct SECURITY_API *scx);
|
||||
|
||||
int ntfs_get_usid( struct SECURITY_API *scapi, uid_t uid, char *buf );
|
||||
int ntfs_get_gsid( struct SECURITY_API *scapi, gid_t gid, char *buf );
|
||||
int ntfs_get_user( struct SECURITY_API *scapi, const SID *usid );
|
||||
int ntfs_get_group( struct SECURITY_API *scapi, const SID *gsid );
|
||||
int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf);
|
||||
int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf);
|
||||
int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid);
|
||||
int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid);
|
||||
|
||||
#endif /* defined _NTFS_SECURITY_H */
|
||||
|
@ -33,24 +33,24 @@
|
||||
/*
|
||||
* Our mailing list. Use this define to prevent typos in email address.
|
||||
*/
|
||||
#define NTFS_DEV_LIST "ntfs-3g-devel@lists.sf.net"
|
||||
#define NTFS_DEV_LIST "ntfs-3g-devel@lists.sf.net"
|
||||
|
||||
/*
|
||||
* Generic macro to convert pointers to values for comparison purposes.
|
||||
*/
|
||||
#ifndef p2n
|
||||
#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
|
||||
#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))
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -63,22 +63,22 @@
|
||||
/*
|
||||
* 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_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_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; \
|
||||
#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 */
|
||||
|
@ -39,12 +39,12 @@
|
||||
#include "compat.h"
|
||||
#else /* GEKKO */
|
||||
|
||||
typedef uint8_t u8; /* Unsigned types of an exact size */
|
||||
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 int8_t s8; /* Signed types of an exact size */
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
@ -63,7 +63,7 @@ typedef u16 sle16;
|
||||
typedef u32 sle32;
|
||||
typedef u64 sle64;
|
||||
|
||||
typedef u16 ntfschar; /* 2-byte Unicode character type. */
|
||||
typedef u16 ntfschar; /* 2-byte Unicode character type. */
|
||||
#define UCHAR_T_SIZE_BITS 1
|
||||
|
||||
/*
|
||||
@ -92,25 +92,24 @@ typedef sle64 leLSN;
|
||||
/**
|
||||
* enum BOOL - These are just to make the code more readable...
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
#ifndef FALSE
|
||||
FALSE = 0,
|
||||
FALSE = 0,
|
||||
#endif
|
||||
#ifndef NO
|
||||
NO = 0,
|
||||
NO = 0,
|
||||
#endif
|
||||
#ifndef ZERO
|
||||
ZERO = 0,
|
||||
ZERO = 0,
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
TRUE = 1,
|
||||
TRUE = 1,
|
||||
#endif
|
||||
#ifndef YES
|
||||
YES = 1,
|
||||
YES = 1,
|
||||
#endif
|
||||
#ifndef ONE
|
||||
ONE = 1,
|
||||
ONE = 1,
|
||||
#endif
|
||||
} BOOL;
|
||||
#endif /* defined _WINDEF_H */
|
||||
@ -119,17 +118,16 @@ typedef enum
|
||||
/**
|
||||
* enum IGNORE_CASE_BOOL -
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
typedef enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
} IGNORE_CASE_BOOL;
|
||||
|
||||
#define STATUS_OK (0)
|
||||
#define STATUS_ERROR (-1)
|
||||
#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2)
|
||||
#define STATUS_KEEP_SEARCHING (-3)
|
||||
#define STATUS_NOT_FOUND (-4)
|
||||
#define STATUS_OK (0)
|
||||
#define STATUS_ERROR (-1)
|
||||
#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2)
|
||||
#define STATUS_KEEP_SEARCHING (-3)
|
||||
#define STATUS_NOT_FOUND (-4)
|
||||
|
||||
#endif /* defined _NTFS_TYPES_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* unistr.h - Exports for Unicode string handling. Originated from the Linux-NTFS
|
||||
* project.
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
*
|
||||
@ -26,53 +26,53 @@
|
||||
#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 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_full_collate( const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
const IGNORE_CASE_BOOL ic,
|
||||
const ntfschar *upcase, const u32 upcase_len );
|
||||
extern int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
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_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 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 u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen);
|
||||
|
||||
extern ntfschar *ntfs_ucsndup( 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_name_upcase(ntfschar *name, u32 name_len,
|
||||
const ntfschar *upcase, const u32 upcase_len);
|
||||
|
||||
extern void ntfs_name_locase( ntfschar *name, u32 name_len,
|
||||
const ntfschar *locase, const u32 locase_len );
|
||||
extern void ntfs_name_locase(ntfschar *name, u32 name_len,
|
||||
const ntfschar *locase, const u32 locase_len);
|
||||
|
||||
extern void ntfs_file_value_upcase( FILE_NAME_ATTR *file_name_attr,
|
||||
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_ucstombs( const ntfschar *ins, const int ins_len, char **outs,
|
||||
int outs_len );
|
||||
extern int ntfs_mbstoucs( const char *ins, ntfschar **outs );
|
||||
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);
|
||||
|
||||
extern char *ntfs_uppercase_mbs( const char *low,
|
||||
const ntfschar *upcase, u32 upcase_len );
|
||||
extern char *ntfs_uppercase_mbs(const char *low,
|
||||
const ntfschar *upcase, u32 upcase_len);
|
||||
|
||||
extern void ntfs_upcase_table_build( ntfschar *uc, u32 uc_len );
|
||||
extern ntfschar *ntfs_locase_table_build( const ntfschar *uc, u32 uc_cnt );
|
||||
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
|
||||
extern ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt);
|
||||
|
||||
extern ntfschar *ntfs_str2ucs( const char *s, int *len );
|
||||
extern ntfschar *ntfs_str2ucs(const char *s, int *len);
|
||||
|
||||
extern void ntfs_ucsfree( ntfschar *ucs );
|
||||
extern void ntfs_ucsfree(ntfschar *ucs);
|
||||
|
||||
extern BOOL ntfs_forbidden_chars( const ntfschar *name, int len );
|
||||
extern BOOL ntfs_collapsible_chars( ntfs_volume *vol,
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen );
|
||||
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len);
|
||||
extern BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen);
|
||||
|
||||
extern int ntfs_set_char_encoding( const char *locale );
|
||||
extern int ntfs_set_char_encoding(const char *locale);
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
/**
|
||||
@ -86,17 +86,17 @@ extern int ntfs_set_char_encoding( const char *locale );
|
||||
* normalization form. Since Windows and most other OS:es use the NFC form while Mac OS X
|
||||
* mostly uses NFD, this conversion increases compatibility between Mac applications and
|
||||
* NTFS-3G.
|
||||
*
|
||||
*
|
||||
* @param normalize decides whether or not the string functions will do automatic filename
|
||||
* normalization when converting to and from UTF-8. 0 means normalization is disabled,
|
||||
* 1 means it is enabled.
|
||||
* @return -1 if the argument was invalid or an error occurred, 0 if all went well.
|
||||
*/
|
||||
extern int ntfs_macosx_normalize_filenames( int normalize );
|
||||
extern int ntfs_macosx_normalize_filenames(int normalize);
|
||||
|
||||
/**
|
||||
* Mac OS X only.
|
||||
*
|
||||
*
|
||||
* Normalizes the input string "utf8_string" to one of the normalization forms NFD or NFC.
|
||||
* The parameter "composed" decides whether output should be in composed, NFC, form
|
||||
* (composed == 1) or decomposed, NFD, form (composed == 0).
|
||||
@ -111,7 +111,7 @@ extern int ntfs_macosx_normalize_filenames( int normalize );
|
||||
* @return -1 if the normalization failed for some reason, otherwise the length of the
|
||||
* normalized string stored in target.
|
||||
*/
|
||||
extern int ntfs_macosx_normalize_utf8( const char *utf8_string, char **target, int composed );
|
||||
extern int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, int composed);
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
|
||||
#endif /* defined _NTFS_UNISTR_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -74,30 +74,28 @@ typedef struct _ntfs_volume ntfs_volume;
|
||||
*
|
||||
* 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. */
|
||||
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 );
|
||||
extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NTFS_VOLUME_OK = 0,
|
||||
NTFS_VOLUME_SYNTAX_ERROR = 11,
|
||||
NTFS_VOLUME_NOT_NTFS = 12,
|
||||
NTFS_VOLUME_CORRUPT = 13,
|
||||
NTFS_VOLUME_HIBERNATED = 14,
|
||||
NTFS_VOLUME_UNCLEAN_UNMOUNT = 15,
|
||||
NTFS_VOLUME_LOCKED = 16,
|
||||
NTFS_VOLUME_RAID = 17,
|
||||
NTFS_VOLUME_UNKNOWN_REASON = 18,
|
||||
NTFS_VOLUME_NO_PRIVILEGE = 19,
|
||||
NTFS_VOLUME_OUT_OF_MEMORY = 20,
|
||||
NTFS_VOLUME_FUSE_ERROR = 21,
|
||||
NTFS_VOLUME_INSECURE = 22
|
||||
typedef enum {
|
||||
NTFS_VOLUME_OK = 0,
|
||||
NTFS_VOLUME_SYNTAX_ERROR = 11,
|
||||
NTFS_VOLUME_NOT_NTFS = 12,
|
||||
NTFS_VOLUME_CORRUPT = 13,
|
||||
NTFS_VOLUME_HIBERNATED = 14,
|
||||
NTFS_VOLUME_UNCLEAN_UNMOUNT = 15,
|
||||
NTFS_VOLUME_LOCKED = 16,
|
||||
NTFS_VOLUME_RAID = 17,
|
||||
NTFS_VOLUME_UNKNOWN_REASON = 18,
|
||||
NTFS_VOLUME_NO_PRIVILEGE = 19,
|
||||
NTFS_VOLUME_OUT_OF_MEMORY = 20,
|
||||
NTFS_VOLUME_FUSE_ERROR = 21,
|
||||
NTFS_VOLUME_INSECURE = 22
|
||||
} ntfs_volume_status;
|
||||
|
||||
/**
|
||||
@ -105,48 +103,47 @@ typedef enum
|
||||
*
|
||||
* 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_ShowSysFiles, /* 1: Show NTFS metafiles. */
|
||||
NV_ShowHidFiles, /* 1: Show files marked hidden. */
|
||||
NV_HideDotFiles, /* 1: Set hidden flag on dot files */
|
||||
NV_Compression, /* 1: allow compression */
|
||||
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_ShowSysFiles, /* 1: Show NTFS metafiles. */
|
||||
NV_ShowHidFiles, /* 1: Show files marked hidden. */
|
||||
NV_HideDotFiles, /* 1: Set hidden flag on dot files */
|
||||
NV_Compression, /* 1: allow compression */
|
||||
} 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 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 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 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 NVolLogFileEmpty(nv) test_nvol_flag(nv, LogFileEmpty)
|
||||
#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
|
||||
#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
|
||||
|
||||
#define NVolShowSysFiles(nv) test_nvol_flag(nv, ShowSysFiles)
|
||||
#define NVolSetShowSysFiles(nv) set_nvol_flag(nv, ShowSysFiles)
|
||||
#define NVolClearShowSysFiles(nv) clear_nvol_flag(nv, ShowSysFiles)
|
||||
#define NVolShowSysFiles(nv) test_nvol_flag(nv, ShowSysFiles)
|
||||
#define NVolSetShowSysFiles(nv) set_nvol_flag(nv, ShowSysFiles)
|
||||
#define NVolClearShowSysFiles(nv) clear_nvol_flag(nv, ShowSysFiles)
|
||||
|
||||
#define NVolShowHidFiles(nv) test_nvol_flag(nv, ShowHidFiles)
|
||||
#define NVolSetShowHidFiles(nv) set_nvol_flag(nv, ShowHidFiles)
|
||||
#define NVolClearShowHidFiles(nv) clear_nvol_flag(nv, ShowHidFiles)
|
||||
#define NVolShowHidFiles(nv) test_nvol_flag(nv, ShowHidFiles)
|
||||
#define NVolSetShowHidFiles(nv) set_nvol_flag(nv, ShowHidFiles)
|
||||
#define NVolClearShowHidFiles(nv) clear_nvol_flag(nv, ShowHidFiles)
|
||||
|
||||
#define NVolHideDotFiles(nv) test_nvol_flag(nv, HideDotFiles)
|
||||
#define NVolSetHideDotFiles(nv) set_nvol_flag(nv, HideDotFiles)
|
||||
#define NVolClearHideDotFiles(nv) clear_nvol_flag(nv, HideDotFiles)
|
||||
#define NVolHideDotFiles(nv) test_nvol_flag(nv, HideDotFiles)
|
||||
#define NVolSetHideDotFiles(nv) set_nvol_flag(nv, HideDotFiles)
|
||||
#define NVolClearHideDotFiles(nv) clear_nvol_flag(nv, HideDotFiles)
|
||||
|
||||
#define NVolCompression(nv) test_nvol_flag(nv, Compression)
|
||||
#define NVolSetCompression(nv) set_nvol_flag(nv, Compression)
|
||||
#define NVolClearCompression(nv) clear_nvol_flag(nv, Compression)
|
||||
#define NVolCompression(nv) test_nvol_flag(nv, Compression)
|
||||
#define NVolSetCompression(nv) set_nvol_flag(nv, Compression)
|
||||
#define NVolClearCompression(nv) clear_nvol_flag(nv, Compression)
|
||||
|
||||
/*
|
||||
* NTFS version 1.1 and 1.2 are used by Windows NT4.
|
||||
@ -166,143 +163,141 @@ typedef enum
|
||||
/**
|
||||
* 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. */
|
||||
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. */
|
||||
le16 flags; /* Bit array of VOLUME_* flags. */
|
||||
ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */
|
||||
u8 major_ver; /* Ntfs major version of volume. */
|
||||
u8 minor_ver; /* Ntfs minor version of volume. */
|
||||
le16 flags; /* Bit array of VOLUME_* flags. */
|
||||
|
||||
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. */
|
||||
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. */
|
||||
u8 full_zones; /* cluster zones which are full */
|
||||
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. */
|
||||
/* Variables used by the cluster and mft allocators. */
|
||||
u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
|
||||
u8 full_zones; /* cluster zones which are full */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
|
||||
ntfs_inode *secure_ni; /* ntfs_inode structure for FILE $Secure */
|
||||
ntfs_index_context *secure_xsii; /* index for using $Secure:$SII */
|
||||
ntfs_index_context *secure_xsdh; /* index for using $Secure:$SDH */
|
||||
int secure_reentry; /* check for non-rentries */
|
||||
unsigned int secure_flags; /* flags, see security.h for values */
|
||||
ntfs_inode *secure_ni; /* ntfs_inode structure for FILE $Secure */
|
||||
ntfs_index_context *secure_xsii; /* index for using $Secure:$SII */
|
||||
ntfs_index_context *secure_xsdh; /* index for using $Secure:$SDH */
|
||||
int secure_reentry; /* check for non-rentries */
|
||||
unsigned int secure_flags; /* flags, see security.h for values */
|
||||
|
||||
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. */
|
||||
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. */
|
||||
ntfschar *locase; /* Lower case equivalents of all 65536 2-byte
|
||||
Unicode characters. Only if option
|
||||
case_ignore is set. */
|
||||
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. */
|
||||
ntfschar *locase; /* Lower case equivalents of all 65536 2-byte
|
||||
Unicode characters. Only if option
|
||||
case_ignore is set. */
|
||||
|
||||
ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
|
||||
FILE_AttrDef. */
|
||||
s32 attrdef_len; /* Size of the attribute definition table in
|
||||
bytes. */
|
||||
ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
|
||||
FILE_AttrDef. */
|
||||
s32 attrdef_len; /* Size of the attribute definition table in
|
||||
bytes. */
|
||||
|
||||
s64 free_clusters; /* Track the number of free clusters which
|
||||
greatly improves statfs() performance */
|
||||
s64 free_mft_records; /* Same for free mft records (see above) */
|
||||
BOOL efs_raw; /* volume is mounted for raw access to
|
||||
efs-encrypted files */
|
||||
s64 free_clusters; /* Track the number of free clusters which
|
||||
greatly improves statfs() performance */
|
||||
s64 free_mft_records; /* Same for free mft records (see above) */
|
||||
BOOL efs_raw; /* volume is mounted for raw access to
|
||||
efs-encrypted files */
|
||||
|
||||
#if CACHE_INODE_SIZE
|
||||
struct CACHE_HEADER *xinode_cache;
|
||||
struct CACHE_HEADER *xinode_cache;
|
||||
#endif
|
||||
#if CACHE_NIDATA_SIZE
|
||||
struct CACHE_HEADER *nidata_cache;
|
||||
struct CACHE_HEADER *nidata_cache;
|
||||
#endif
|
||||
#if CACHE_LOOKUP_SIZE
|
||||
struct CACHE_HEADER *lookup_cache;
|
||||
struct CACHE_HEADER *lookup_cache;
|
||||
#endif
|
||||
#if CACHE_SECURID_SIZE
|
||||
struct CACHE_HEADER *securid_cache;
|
||||
struct CACHE_HEADER *securid_cache;
|
||||
#endif
|
||||
#if CACHE_LEGACY_SIZE
|
||||
struct CACHE_HEADER *legacy_cache;
|
||||
struct CACHE_HEADER *legacy_cache;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern const char *ntfs_home;
|
||||
|
||||
extern ntfs_volume *ntfs_volume_alloc( void );
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
||||
extern ntfs_volume *ntfs_volume_startup( struct ntfs_device *dev,
|
||||
unsigned long flags );
|
||||
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 ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
|
||||
extern ntfs_volume *ntfs_mount( const char *name, unsigned long flags );
|
||||
extern int ntfs_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_volume_check_hiberfile( ntfs_volume *vol, int verbose );
|
||||
extern int ntfs_logfile_reset( ntfs_volume *vol );
|
||||
extern int ntfs_version_is_supported(ntfs_volume *vol);
|
||||
extern int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose);
|
||||
extern int ntfs_logfile_reset(ntfs_volume *vol);
|
||||
|
||||
extern int ntfs_volume_write_flags( ntfs_volume *vol, const le16 flags );
|
||||
extern int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags);
|
||||
|
||||
extern int ntfs_volume_error( int err );
|
||||
extern void ntfs_mount_error( const char *vol, const char *mntpoint, int err );
|
||||
extern int ntfs_volume_error(int err);
|
||||
extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err);
|
||||
|
||||
extern int ntfs_volume_get_free_space( ntfs_volume *vol );
|
||||
extern int ntfs_volume_get_free_space(ntfs_volume *vol);
|
||||
|
||||
extern int ntfs_set_shown_files( ntfs_volume *vol,
|
||||
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files );
|
||||
extern int ntfs_set_locale( void );
|
||||
extern int ntfs_set_ignore_case( ntfs_volume *vol );
|
||||
extern int ntfs_set_shown_files(ntfs_volume *vol,
|
||||
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files);
|
||||
extern int ntfs_set_locale(void);
|
||||
extern int ntfs_set_ignore_case(ntfs_volume *vol);
|
||||
|
||||
#endif /* defined _NTFS_VOLUME_H */
|
||||
|
||||
|
@ -56,7 +56,7 @@ bool TitleSelector( char output[] )
|
||||
{
|
||||
gprintf("TitleSelector()\n");
|
||||
|
||||
u32 num_titles;
|
||||
s32 num_titles;
|
||||
s32 r = -1;
|
||||
bool ret = false;
|
||||
u64 *titleList = NULL;
|
||||
@ -93,7 +93,7 @@ bool TitleSelector( char output[] )
|
||||
customOptionList options4( num_titles + 1 );
|
||||
//write the titles on the option browser
|
||||
|
||||
u32 i = 0;
|
||||
s32 i = 0;
|
||||
titles.SetType( 0x10001 );
|
||||
while ( i < num_titles )
|
||||
{
|
||||
|
@ -96,10 +96,13 @@ int GameList::ReadGameList()
|
||||
return LoadUnfiltered();
|
||||
}
|
||||
|
||||
static bool WCharSortCallback( const wchar_t char1, const wchar_t char2 )
|
||||
static bool WCharSortCallback(const wchar_t char1, const wchar_t char2)
|
||||
{
|
||||
if( char2 == 0 )return true;
|
||||
if( char1 == 0 )return false;
|
||||
if(char2 == 0)
|
||||
return true;
|
||||
if(char1 == 0)
|
||||
return false;
|
||||
|
||||
return char2 > char1;
|
||||
}
|
||||
|
||||
@ -243,41 +246,41 @@ void GameList::SortList()
|
||||
|
||||
}
|
||||
|
||||
bool GameList::NameSortCallback( const struct discHdr *a, const struct discHdr *b )
|
||||
bool GameList::NameSortCallback(const struct discHdr *a, const struct discHdr *b)
|
||||
{
|
||||
return ( strcasecmp( get_title( ( struct discHdr * ) a ), get_title( ( struct discHdr * ) b ) ) < 0 );
|
||||
return (strcasecmp(get_title((struct discHdr *) a), get_title((struct discHdr *) b)) < 0);
|
||||
}
|
||||
|
||||
bool GameList::PlaycountSortCallback( const struct discHdr *a, const struct discHdr *b )
|
||||
bool GameList::PlaycountSortCallback(const struct discHdr *a, const struct discHdr *b)
|
||||
{
|
||||
struct Game_NUM* game_num1 = CFG_get_game_num( a->id );
|
||||
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
||||
int count1 = 0, count2 = 0;
|
||||
|
||||
if ( game_num1 )
|
||||
if (game_num1)
|
||||
count1 = game_num1->count;
|
||||
if ( game_num2 )
|
||||
if (game_num2)
|
||||
count2 = game_num2->count;
|
||||
|
||||
if ( count1 == count2 )
|
||||
return NameSortCallback( a, b );
|
||||
if (count1 == count2)
|
||||
return NameSortCallback(a, b);
|
||||
|
||||
return ( count1 > count2 );
|
||||
return (count1 > count2);
|
||||
}
|
||||
|
||||
bool GameList::FavoriteSortCallback( const struct discHdr *a, const struct discHdr *b )
|
||||
bool GameList::FavoriteSortCallback(const struct discHdr *a, const struct discHdr *b)
|
||||
{
|
||||
struct Game_NUM* game_num1 = CFG_get_game_num( a->id );
|
||||
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
||||
int fav1 = 0, fav2 = 0;
|
||||
|
||||
if ( game_num1 )
|
||||
if (game_num1)
|
||||
fav1 = game_num1->favorite;
|
||||
if ( game_num2 )
|
||||
if (game_num2)
|
||||
fav2 = game_num2->favorite;
|
||||
|
||||
if ( fav1 == fav2 );
|
||||
return NameSortCallback( a, b );
|
||||
if (fav1 == fav2)
|
||||
return NameSortCallback(a, b);
|
||||
|
||||
return ( fav1 > fav2 );
|
||||
return (fav1 > fav2);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user