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">
|
<app version="1">
|
||||||
<name> USB Loader GX</name>
|
<name> USB Loader GX</name>
|
||||||
<coder>USB Loader GX Team</coder>
|
<coder>USB Loader GX Team</coder>
|
||||||
<version>1.0 r953</version>
|
<version>1.0 r957</version>
|
||||||
<release_date>201009190727</release_date>
|
<release_date>201009191357</release_date>
|
||||||
<short_description>Loads games from USB-devices</short_description>
|
<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.
|
<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.
|
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||||
|
8
Makefile
8
Makefile
@ -41,15 +41,9 @@ SOURCES := source \
|
|||||||
source/libfat \
|
source/libfat \
|
||||||
source/memory \
|
source/memory \
|
||||||
source/libntfs \
|
source/libntfs \
|
||||||
source/usbloader/wbfs \
|
source/usbloader/wbfs
|
||||||
# source/libhfs+ \
|
|
||||||
# source/libhfs+/hfscommon/BTree \
|
|
||||||
# source/libhfs+/hfscommon/Catalog \
|
|
||||||
# source/libhfs+/hfscommon/Misc \
|
|
||||||
# source/libhfs+/hfscommon/Unicode
|
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := source
|
INCLUDES := source
|
||||||
#source/libhfs+/hfscommon/headers
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include "usbloader/usbstorage2.h"
|
#include "usbloader/usbstorage2.h"
|
||||||
#include "usbloader/sdhc.h"
|
#include "usbloader/sdhc.h"
|
||||||
#include "usbloader/wbfs.h"
|
#include "usbloader/wbfs.h"
|
||||||
#include "libfat/fat.h"
|
|
||||||
#include "libntfs/ntfs.h"
|
#include "libntfs/ntfs.h"
|
||||||
|
#include "libfat/fat.h"
|
||||||
#include "gecko.h"
|
#include "gecko.h"
|
||||||
|
|
||||||
//these are the only stable and speed is good
|
//these are the only stable and speed is good
|
||||||
@ -215,7 +215,7 @@ s32 MountNTFS( u32 sector )
|
|||||||
// }
|
// }
|
||||||
/* Mount device */
|
/* Mount device */
|
||||||
// if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
// 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 )
|
if ( !ret )
|
||||||
{
|
{
|
||||||
return -2;
|
return -2;
|
||||||
@ -226,11 +226,11 @@ s32 MountNTFS( u32 sector )
|
|||||||
{
|
{
|
||||||
if ( sdhc_mode_sd == 0 )
|
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
|
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 )
|
if ( !ret )
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -64,7 +64,7 @@
|
|||||||
* when checking, check one is present
|
* 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_READ (FILE_READ_DATA)
|
||||||
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||||
@ -75,8 +75,8 @@
|
|||||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||||
#define DIR_EXEC (FILE_TRAVERSE)
|
#define DIR_EXEC (FILE_TRAVERSE)
|
||||||
|
|
||||||
/* flags tested for meaning exec, write or read */
|
/* flags tested for meaning exec, write or read */
|
||||||
/* tests for write allow for interpretation of a sticky bit */
|
/* tests for write allow for interpretation of a sticky bit */
|
||||||
|
|
||||||
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ)
|
||||||
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)
|
||||||
@ -85,19 +85,19 @@
|
|||||||
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE)
|
||||||
#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE)
|
#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 \
|
#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \
|
||||||
| SYNCHRONIZE \
|
| SYNCHRONIZE \
|
||||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||||
| FILE_READ_EA | FILE_WRITE_EA)
|
| FILE_READ_EA | FILE_WRITE_EA)
|
||||||
|
|
||||||
/* standard world rights */
|
/* standard world rights */
|
||||||
|
|
||||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
#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 FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
||||||
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
||||||
@ -122,8 +122,7 @@ typedef char BIGSID[40];
|
|||||||
* (private to this module)
|
* (private to this module)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct MAPLIST
|
struct MAPLIST {
|
||||||
{
|
|
||||||
struct MAPLIST *next;
|
struct MAPLIST *next;
|
||||||
char *uidstr; /* uid text from the same record */
|
char *uidstr; /* uid text from the same record */
|
||||||
char *gidstr; /* gid text from the same record */
|
char *gidstr; /* gid text from the same record */
|
||||||
@ -131,7 +130,7 @@ struct MAPLIST
|
|||||||
char maptext[LINESZ + 1];
|
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
|
||||||
@ -144,57 +143,57 @@ 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_descr(const char *securattr, unsigned int attrsz);
|
||||||
BOOL ntfs_valid_pattern( const SID *sid );
|
BOOL ntfs_valid_pattern(const SID *sid);
|
||||||
BOOL ntfs_valid_sid( const SID *sid );
|
BOOL ntfs_valid_sid(const SID *sid);
|
||||||
BOOL ntfs_same_sid( const SID *first, const SID *second );
|
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 );
|
int ntfs_sid_size(const SID * sid);
|
||||||
unsigned int ntfs_attr_size( const char *attr );
|
unsigned int ntfs_attr_size(const char *attr);
|
||||||
|
|
||||||
const SID *ntfs_find_usid( const struct MAPPING *usermapping,
|
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
||||||
uid_t uid, SID *pdefsid );
|
uid_t uid, SID *pdefsid);
|
||||||
const SID *ntfs_find_gsid( const struct MAPPING *groupmapping,
|
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping,
|
||||||
gid_t gid, SID *pdefsid );
|
gid_t gid, SID *pdefsid);
|
||||||
uid_t ntfs_find_user( const struct MAPPING *usermapping, const SID *usid );
|
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||||
gid_t ntfs_find_group( const struct MAPPING *groupmapping, const SID * gsid );
|
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||||
const SID *ntfs_acl_owner( const char *secattr );
|
const SID *ntfs_acl_owner(const char *secattr);
|
||||||
|
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
|
|
||||||
BOOL ntfs_valid_posix( const struct POSIX_SECURITY *pxdesc );
|
BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc);
|
||||||
void ntfs_sort_posix( struct POSIX_SECURITY *pxdesc );
|
void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc);
|
||||||
int ntfs_merge_mode_posix( struct POSIX_SECURITY *pxdesc, mode_t mode );
|
int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
|
||||||
struct POSIX_SECURITY *ntfs_build_inherited_posix(
|
struct POSIX_SECURITY *ntfs_build_inherited_posix(
|
||||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||||
mode_t umask, BOOL isdir );
|
mode_t umask, BOOL isdir);
|
||||||
struct POSIX_SECURITY *ntfs_replace_acl( const struct POSIX_SECURITY *oldpxdesc,
|
struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
||||||
const struct POSIX_ACL *newacl, int count, BOOL deflt );
|
const struct POSIX_ACL *newacl, int count, BOOL deflt);
|
||||||
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||||
struct MAPPING* const mapping[],
|
struct MAPPING* const mapping[],
|
||||||
const char *securattr,
|
const char *securattr,
|
||||||
const SID *usid, const SID *gsid, BOOL isdir );
|
const SID *usid, const SID *gsid, BOOL isdir);
|
||||||
struct POSIX_SECURITY *ntfs_merge_descr_posix( const struct POSIX_SECURITY *first,
|
struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first,
|
||||||
const struct POSIX_SECURITY *second );
|
const struct POSIX_SECURITY *second);
|
||||||
char *ntfs_build_descr_posix( struct MAPPING* const mapping[],
|
char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||||
struct POSIX_SECURITY *pxdesc,
|
struct POSIX_SECURITY *pxdesc,
|
||||||
int isdir, const SID *usid, const SID *gsid );
|
int isdir, const SID *usid, const SID *gsid);
|
||||||
|
|
||||||
#endif /* POSIXACLS */
|
#endif /* POSIXACLS */
|
||||||
|
|
||||||
int ntfs_inherit_acl( const ACL *oldacl, ACL *newacl,
|
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||||
const SID *usid, const SID *gsid, BOOL fordir );
|
const SID *usid, const SID *gsid, BOOL fordir);
|
||||||
int ntfs_build_permissions( const char *securattr,
|
int ntfs_build_permissions(const char *securattr,
|
||||||
const SID *usid, const SID *gsid, BOOL isdir );
|
const SID *usid, const SID *gsid, BOOL isdir);
|
||||||
char *ntfs_build_descr( mode_t mode,
|
char *ntfs_build_descr(mode_t mode,
|
||||||
int isdir, const SID * usid, const SID * gsid );
|
int isdir, const SID * usid, const SID * gsid);
|
||||||
struct MAPLIST *ntfs_read_mapping( FILEREADER reader, void *fileid );
|
struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||||
struct MAPPING *ntfs_do_user_mapping( struct MAPLIST *firstitem );
|
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||||
struct MAPPING *ntfs_do_group_mapping( struct MAPLIST *firstitem );
|
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||||
void ntfs_free_mapping( struct MAPPING *mapping[] );
|
void ntfs_free_mapping(struct MAPPING *mapping[]);
|
||||||
|
|
||||||
#endif /* ACLS_H */
|
#endif /* ACLS_H */
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -49,8 +49,7 @@ extern ntfschar TXF_DATA[10];
|
|||||||
*
|
*
|
||||||
* TODO: Describe them.
|
* TODO: Describe them.
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||||
LCN_RL_NOT_MAPPED = -2,
|
LCN_RL_NOT_MAPPED = -2,
|
||||||
LCN_ENOENT = -3,
|
LCN_ENOENT = -3,
|
||||||
@ -76,8 +75,7 @@ typedef enum
|
|||||||
* any modification of the search context, to automagically get the next
|
* any modification of the search context, to automagically get the next
|
||||||
* matching attribute.
|
* matching attribute.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr_search_ctx
|
struct _ntfs_attr_search_ctx {
|
||||||
{
|
|
||||||
MFT_RECORD *mrec;
|
MFT_RECORD *mrec;
|
||||||
ATTR_RECORD *attr;
|
ATTR_RECORD *attr;
|
||||||
BOOL is_first;
|
BOOL is_first;
|
||||||
@ -88,20 +86,20 @@ struct _ntfs_attr_search_ctx
|
|||||||
ATTR_RECORD *base_attr;
|
ATTR_RECORD *base_attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void ntfs_attr_reinit_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,
|
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||||
MFT_RECORD *mrec );
|
MFT_RECORD *mrec);
|
||||||
extern void ntfs_attr_put_search_ctx( ntfs_attr_search_ctx *ctx );
|
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||||
|
|
||||||
extern int ntfs_attr_lookup( const ATTR_TYPES type, const ntfschar *name,
|
extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
|
||||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||||
ntfs_attr_search_ctx *ctx );
|
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,
|
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||||
const ATTR_TYPES type );
|
const ATTR_TYPES type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||||
@ -128,10 +126,10 @@ extern ATTR_DEF *ntfs_attr_find_in_attrdef( const ntfs_volume *vol,
|
|||||||
* // Ooops. An error occurred! You should handle this case.
|
* // Ooops. An error occurred! You should handle this case.
|
||||||
* // Now finished with all attributes in the inode.
|
* // 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,
|
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||||
NULL, 0, ctx );
|
NULL, 0, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,8 +174,7 @@ static __inline__ int ntfs_attrs_walk( ntfs_attr_search_ctx *ctx )
|
|||||||
* @state contains NTFS attribute specific flags describing this attribute
|
* @state contains NTFS attribute specific flags describing this attribute
|
||||||
* structure. See ntfs_attr_state_bits above.
|
* structure. See ntfs_attr_state_bits above.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_attr
|
struct _ntfs_attr {
|
||||||
{
|
|
||||||
runlist_element *rl;
|
runlist_element *rl;
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ATTR_TYPES type;
|
ATTR_TYPES type;
|
||||||
@ -199,8 +196,7 @@ struct _ntfs_attr
|
|||||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr
|
||||||
* structure
|
* structure
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NA_Initialized, /* 1: structure is initialized. */
|
NA_Initialized, /* 1: structure is initialized. */
|
||||||
NA_NonResident, /* 1: Attribute is not resident. */
|
NA_NonResident, /* 1: Attribute is not resident. */
|
||||||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||||
@ -237,9 +233,9 @@ extern int NAttr##func_name(ntfs_attr *na); \
|
|||||||
extern void NAttrSet##func_name(ntfs_attr *na); \
|
extern void NAttrSet##func_name(ntfs_attr *na); \
|
||||||
extern void NAttrClear##func_name(ntfs_attr *na);
|
extern void NAttrClear##func_name(ntfs_attr *na);
|
||||||
|
|
||||||
GenNAttrIno( Compressed, FILE_ATTR_COMPRESSED )
|
GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
|
||||||
GenNAttrIno( Encrypted, FILE_ATTR_ENCRYPTED )
|
GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED)
|
||||||
GenNAttrIno( Sparse, FILE_ATTR_SPARSE_FILE )
|
GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE)
|
||||||
#undef GenNAttrIno
|
#undef GenNAttrIno
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,8 +243,7 @@ GenNAttrIno( Sparse, FILE_ATTR_SPARSE_FILE )
|
|||||||
*
|
*
|
||||||
* For convenience. Used in the attr structure.
|
* For convenience. Used in the attr structure.
|
||||||
*/
|
*/
|
||||||
typedef union
|
typedef union {
|
||||||
{
|
|
||||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||||
a_val without specifying any of the below. */
|
a_val without specifying any of the below. */
|
||||||
STANDARD_INFORMATION std_inf;
|
STANDARD_INFORMATION std_inf;
|
||||||
@ -270,73 +265,73 @@ typedef union
|
|||||||
EFS_ATTR_HEADER efs;
|
EFS_ATTR_HEADER efs;
|
||||||
} attr_val;
|
} attr_val;
|
||||||
|
|
||||||
extern void ntfs_attr_init( ntfs_attr *na, const BOOL non_resident,
|
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||||
const ATTR_FLAGS data_flags, const BOOL encrypted,
|
const ATTR_FLAGS data_flags, const BOOL encrypted,
|
||||||
const BOOL sparse,
|
const BOOL sparse,
|
||||||
const s64 allocated_size, const s64 data_size,
|
const s64 allocated_size, const s64 data_size,
|
||||||
const s64 initialized_size, const s64 compressed_size,
|
const s64 initialized_size, const s64 compressed_size,
|
||||||
const u8 compression_unit );
|
const u8 compression_unit);
|
||||||
|
|
||||||
/* warning : in the following "name" has to be freeable */
|
/* warning : in the following "name" has to be freeable */
|
||||||
/* or one of constants AT_UNNAMED, NTFS_INDEX_I30 or STREAM_SDS */
|
/* 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,
|
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||||
ntfschar *name, u32 name_len );
|
ntfschar *name, u32 name_len);
|
||||||
extern void ntfs_attr_close( ntfs_attr *na );
|
extern void ntfs_attr_close(ntfs_attr *na);
|
||||||
|
|
||||||
extern s64 ntfs_attr_pread( ntfs_attr *na, const s64 pos, s64 count,
|
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
|
||||||
void *b );
|
void *b);
|
||||||
extern s64 ntfs_attr_pwrite( ntfs_attr *na, const s64 pos, s64 count,
|
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count,
|
||||||
const void *b );
|
const void *b);
|
||||||
extern int ntfs_attr_pclose( ntfs_attr *na );
|
extern int ntfs_attr_pclose(ntfs_attr *na);
|
||||||
|
|
||||||
extern void *ntfs_attr_readall( ntfs_inode *ni, const ATTR_TYPES type,
|
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
|
||||||
ntfschar *name, u32 name_len, s64 *data_size );
|
ntfschar *name, u32 name_len, s64 *data_size);
|
||||||
|
|
||||||
extern s64 ntfs_attr_mst_pread( ntfs_attr *na, const s64 pos,
|
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
|
||||||
const s64 bk_cnt, const u32 bk_size, void *dst );
|
const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||||
extern s64 ntfs_attr_mst_pwrite( ntfs_attr *na, const s64 pos,
|
extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
|
||||||
s64 bk_cnt, const u32 bk_size, void *src );
|
s64 bk_cnt, const u32 bk_size, void *src);
|
||||||
|
|
||||||
extern int ntfs_attr_map_runlist( ntfs_attr *na, VCN vcn );
|
extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
|
||||||
extern int ntfs_attr_map_whole_runlist( ntfs_attr *na );
|
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||||
|
|
||||||
extern LCN ntfs_attr_vcn_to_lcn( 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 runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||||
|
|
||||||
extern int ntfs_attr_size_bounds_check( const ntfs_volume *vol,
|
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||||
const ATTR_TYPES type, const s64 size );
|
const ATTR_TYPES type, const s64 size);
|
||||||
extern int ntfs_attr_can_be_resident( const ntfs_volume *vol,
|
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||||
const ATTR_TYPES type );
|
const ATTR_TYPES type);
|
||||||
int ntfs_attr_make_non_resident( ntfs_attr *na,
|
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||||
ntfs_attr_search_ctx *ctx );
|
ntfs_attr_search_ctx *ctx);
|
||||||
int ntfs_attr_force_non_resident( ntfs_attr *na );
|
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_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||||
|
|
||||||
extern int ntfs_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||||
ATTR_FLAGS flags );
|
ATTR_FLAGS flags);
|
||||||
extern int ntfs_non_resident_attr_record_add( ntfs_inode *ni, ATTR_TYPES type,
|
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,
|
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||||
ATTR_FLAGS flags );
|
ATTR_FLAGS flags);
|
||||||
extern int ntfs_attr_record_rm( ntfs_attr_search_ctx *ctx );
|
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
||||||
|
|
||||||
extern int ntfs_attr_add( ntfs_inode *ni, ATTR_TYPES type,
|
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||||
ntfschar *name, u8 name_len, u8 *val, s64 size );
|
ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||||
extern int ntfs_attr_set_flags( ntfs_inode *ni, ATTR_TYPES type,
|
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask );
|
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
||||||
extern int ntfs_attr_rm( ntfs_attr *na );
|
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,
|
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||||
const u32 new_size );
|
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_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_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
|
* get_attribute_value_length - return the length of the value of an attribute
|
||||||
@ -349,7 +344,7 @@ extern int ntfs_attr_truncate( ntfs_attr *na, const s64 newsize );
|
|||||||
*
|
*
|
||||||
* FIXME: Describe possible errnos.
|
* 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
|
* get_attribute_value - return the attribute value of an attribute
|
||||||
@ -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
|
* then nothing was read due to a zero-length attribute value, otherwise
|
||||||
* errno describes the error.
|
* errno describes the error.
|
||||||
*/
|
*/
|
||||||
extern s64 ntfs_get_attribute_value( const ntfs_volume *vol,
|
extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
||||||
const ATTR_RECORD *a, u8 *b );
|
const ATTR_RECORD *a, u8 *b);
|
||||||
|
|
||||||
extern void ntfs_attr_name_free( char **name );
|
extern void ntfs_attr_name_free(char **name);
|
||||||
extern char *ntfs_attr_name_get( const ntfschar *uname, const int uname_len );
|
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,
|
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
|
||||||
ntfschar *name, u32 name_len );
|
ntfschar *name, u32 name_len);
|
||||||
extern int ntfs_attr_remove( ntfs_inode *ni, const ATTR_TYPES type,
|
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||||
ntfschar *name, u32 name_len );
|
ntfschar *name, u32 name_len);
|
||||||
extern s64 ntfs_attr_get_free_bits( ntfs_attr *na );
|
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||||
|
|
||||||
#endif /* defined _NTFS_ATTRIB_H */
|
#endif /* defined _NTFS_ATTRIB_H */
|
||||||
|
|
||||||
|
@ -58,40 +58,36 @@
|
|||||||
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
||||||
* attribute list.
|
* 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 )
|
if (!ni) {
|
||||||
{
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
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 ) )
|
if (!NInoAttrList(ni)) {
|
||||||
{
|
ntfs_log_trace("Inode haven't got attribute list.\n");
|
||||||
ntfs_log_trace( "Inode haven't got attribute list.\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ni->attr_list )
|
if (!ni->attr_list) {
|
||||||
{
|
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||||
ntfs_log_trace( "Corrupt in-memory struct.\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
|
ale = (ATTR_LIST_ENTRY *)ni->attr_list;
|
||||||
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
|
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
||||||
{
|
if (MREF_LE(ale->mft_reference) != ni->mft_no)
|
||||||
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
|
|
||||||
return 1;
|
return 1;
|
||||||
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
|
ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -108,7 +104,7 @@ int ntfs_attrlist_need( ntfs_inode *ni )
|
|||||||
* EIO - I/O error occurred or damaged filesystem.
|
* EIO - I/O error occurred or damaged filesystem.
|
||||||
* EEXIST - Such attribute already present in attribute list.
|
* 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;
|
ATTR_LIST_ENTRY *ale;
|
||||||
MFT_REF mref;
|
MFT_REF mref;
|
||||||
@ -117,132 +113,122 @@ int ntfs_attrlist_entry_add( ntfs_inode *ni, ATTR_RECORD *attr )
|
|||||||
u8 *new_al;
|
u8 *new_al;
|
||||||
int entry_len, entry_offset, err;
|
int entry_len, entry_offset, err;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x.\n",
|
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||||
( long long ) ni->mft_no,
|
(long long) ni->mft_no,
|
||||||
( unsigned ) le32_to_cpu( attr->type ) );
|
(unsigned) le32_to_cpu(attr->type));
|
||||||
|
|
||||||
if ( !ni || !attr )
|
if (!ni || !attr) {
|
||||||
{
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
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 )
|
if (ni->nr_extents == -1)
|
||||||
ni = ni->base_ni;
|
ni = ni->base_ni;
|
||||||
|
|
||||||
if ( !NInoAttrList( ni ) )
|
if (!NInoAttrList(ni)) {
|
||||||
{
|
ntfs_log_trace("Attribute list isn't present.\n");
|
||||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine size and allocate memory for new attribute list. */
|
/* Determine size and allocate memory for new attribute list. */
|
||||||
entry_len = ( sizeof( ATTR_LIST_ENTRY ) + sizeof( ntfschar ) *
|
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
|
||||||
attr->name_length + 7 ) & ~7;
|
attr->name_length + 7) & ~7;
|
||||||
new_al = ntfs_calloc( ni->attr_list_size + entry_len );
|
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||||
if ( !new_al )
|
if (!new_al)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Find place for the new entry. */
|
/* Find place for the new entry. */
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||||
if ( !ctx )
|
if (!ctx) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if ( !ntfs_attr_lookup( attr->type, ( attr->name_length ) ? ( ntfschar* )
|
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
||||||
( ( u8* )attr + le16_to_cpu( attr->name_offset ) ) :
|
((u8*)attr + le16_to_cpu(attr->name_offset)) :
|
||||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
||||||
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
|
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
|
||||||
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
|
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
||||||
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
|
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||||
0 : le32_to_cpu( attr->value_length ), ctx ) )
|
0 : le32_to_cpu(attr->value_length), ctx)) {
|
||||||
{
|
|
||||||
/* Found some extent, check it to be before new extent. */
|
/* Found some extent, check it to be before new extent. */
|
||||||
if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
|
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
||||||
{
|
|
||||||
err = EEXIST;
|
err = EEXIST;
|
||||||
ntfs_log_trace( "Such attribute already present in the "
|
ntfs_log_trace("Such attribute already present in the "
|
||||||
"attribute list.\n" );
|
"attribute list.\n");
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* Add new entry after this extent. */
|
/* Add new entry after this extent. */
|
||||||
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
|
ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
|
||||||
le16_to_cpu( ctx->al_entry->length ) );
|
le16_to_cpu(ctx->al_entry->length));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Check for real errors. */
|
/* Check for real errors. */
|
||||||
if ( errno != ENOENT )
|
if (errno != ENOENT) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Attribute lookup failed.\n" );
|
ntfs_log_trace("Attribute lookup failed.\n");
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* No previous extents found. */
|
/* No previous extents found. */
|
||||||
ale = ctx->al_entry;
|
ale = ctx->al_entry;
|
||||||
}
|
}
|
||||||
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
|
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
|
|
||||||
/* Determine new entry offset. */
|
/* Determine new entry offset. */
|
||||||
entry_offset = ( ( u8 * )ale - ni->attr_list );
|
entry_offset = ((u8 *)ale - ni->attr_list);
|
||||||
/* Set pointer to new entry. */
|
/* Set pointer to new entry. */
|
||||||
ale = ( ATTR_LIST_ENTRY * )( new_al + entry_offset );
|
ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
|
||||||
/* Zero it to fix valgrind warning. */
|
/* Zero it to fix valgrind warning. */
|
||||||
memset( ale, 0, entry_len );
|
memset(ale, 0, entry_len);
|
||||||
/* Form new entry. */
|
/* Form new entry. */
|
||||||
ale->type = attr->type;
|
ale->type = attr->type;
|
||||||
ale->length = cpu_to_le16( entry_len );
|
ale->length = cpu_to_le16(entry_len);
|
||||||
ale->name_length = attr->name_length;
|
ale->name_length = attr->name_length;
|
||||||
ale->name_offset = offsetof( ATTR_LIST_ENTRY, name );
|
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
||||||
if ( attr->non_resident )
|
if (attr->non_resident)
|
||||||
ale->lowest_vcn = attr->lowest_vcn;
|
ale->lowest_vcn = attr->lowest_vcn;
|
||||||
else
|
else
|
||||||
ale->lowest_vcn = 0;
|
ale->lowest_vcn = 0;
|
||||||
ale->mft_reference = mref;
|
ale->mft_reference = mref;
|
||||||
ale->instance = attr->instance;
|
ale->instance = attr->instance;
|
||||||
memcpy( ale->name, ( u8 * )attr + le16_to_cpu( attr->name_offset ),
|
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
||||||
attr->name_length * sizeof( ntfschar ) );
|
attr->name_length * sizeof(ntfschar));
|
||||||
|
|
||||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||||
if ( !na )
|
if (!na) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
|
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy entries from old attribute list to new. */
|
/* Copy entries from old attribute list to new. */
|
||||||
memcpy( new_al, ni->attr_list, entry_offset );
|
memcpy(new_al, ni->attr_list, entry_offset);
|
||||||
memcpy( new_al + entry_offset + entry_len, ni->attr_list +
|
memcpy(new_al + entry_offset + entry_len, ni->attr_list +
|
||||||
entry_offset, ni->attr_list_size - entry_offset );
|
entry_offset, ni->attr_list_size - entry_offset);
|
||||||
|
|
||||||
/* Set new runlist. */
|
/* Set new runlist. */
|
||||||
free( ni->attr_list );
|
free(ni->attr_list);
|
||||||
ni->attr_list = new_al;
|
ni->attr_list = new_al;
|
||||||
ni->attr_list_size = ni->attr_list_size + entry_len;
|
ni->attr_list_size = ni->attr_list_size + entry_len;
|
||||||
NInoAttrListSetDirty( ni );
|
NInoAttrListSetDirty(ni);
|
||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
err_out:
|
||||||
if ( na )
|
if (na)
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
free( new_al );
|
free(new_al);
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -255,7 +241,7 @@ err_out:
|
|||||||
*
|
*
|
||||||
* Return 0 on success and -1 on error with errno set to the error code.
|
* 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;
|
u8 *new_al;
|
||||||
int new_al_len;
|
int new_al_len;
|
||||||
@ -264,69 +250,65 @@ int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx )
|
|||||||
ATTR_LIST_ENTRY *ale;
|
ATTR_LIST_ENTRY *ale;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
|
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||||
{
|
ntfs_log_trace("Invalid arguments.\n");
|
||||||
ntfs_log_trace( "Invalid arguments.\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ctx->base_ntfs_ino )
|
if (ctx->base_ntfs_ino)
|
||||||
base_ni = ctx->base_ntfs_ino;
|
base_ni = ctx->base_ntfs_ino;
|
||||||
else
|
else
|
||||||
base_ni = ctx->ntfs_ino;
|
base_ni = ctx->ntfs_ino;
|
||||||
ale = ctx->al_entry;
|
ale = ctx->al_entry;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||||
( long long ) ctx->ntfs_ino->mft_no,
|
(long long) ctx->ntfs_ino->mft_no,
|
||||||
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
|
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
||||||
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
|
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||||
|
|
||||||
if ( !NInoAttrList( base_ni ) )
|
if (!NInoAttrList(base_ni)) {
|
||||||
{
|
ntfs_log_trace("Attribute list isn't present.\n");
|
||||||
ntfs_log_trace( "Attribute list isn't present.\n" );
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory for new attribute list. */
|
/* Allocate memory for new attribute list. */
|
||||||
new_al_len = base_ni->attr_list_size - le16_to_cpu( ale->length );
|
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||||
new_al = ntfs_calloc( new_al_len );
|
new_al = ntfs_calloc(new_al_len);
|
||||||
if ( !new_al )
|
if (!new_al)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||||
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
|
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||||
if ( !na )
|
if (!na) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
|
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if ( ntfs_attr_truncate( na, new_al_len ) )
|
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
|
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy entries from old attribute list to new. */
|
/* Copy entries from old attribute list to new. */
|
||||||
memcpy( new_al, base_ni->attr_list, ( u8* )ale - base_ni->attr_list );
|
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(
|
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 ) );
|
ale->length), new_al_len - ((u8*)ale - base_ni->attr_list));
|
||||||
|
|
||||||
/* Set new runlist. */
|
/* Set new runlist. */
|
||||||
free( base_ni->attr_list );
|
free(base_ni->attr_list);
|
||||||
base_ni->attr_list = new_al;
|
base_ni->attr_list = new_al;
|
||||||
base_ni->attr_list_size = new_al_len;
|
base_ni->attr_list_size = new_al_len;
|
||||||
NInoAttrListSetDirty( base_ni );
|
NInoAttrListSetDirty(base_ni);
|
||||||
/* Done! */
|
/* Done! */
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
err_out:
|
||||||
if ( na )
|
if (na)
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
free( new_al );
|
free(new_al);
|
||||||
errno = err;
|
errno = err;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@
|
|||||||
|
|
||||||
#include "attrib.h"
|
#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_add(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||||
extern int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx );
|
extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_attrlist_mark_dirty - set the attribute list dirty
|
* ntfs_attrlist_mark_dirty - set the attribute list dirty
|
||||||
@ -40,12 +40,12 @@ extern int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx );
|
|||||||
*
|
*
|
||||||
* This function cannot fail.
|
* 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 )
|
if (ni->nr_extents == -1)
|
||||||
NInoAttrListSetDirty( ni->base_ni );
|
NInoAttrListSetDirty(ni->base_ni);
|
||||||
else
|
else
|
||||||
NInoAttrListSetDirty( ni );
|
NInoAttrListSetDirty(ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined _NTFS_ATTRLIST_H */
|
#endif /* defined _NTFS_ATTRLIST_H */
|
||||||
|
@ -34,28 +34,24 @@
|
|||||||
/*-----------------------------------------------------------------
|
/*-----------------------------------------------------------------
|
||||||
Functions to deal with little endian values stored in uint8_t arrays
|
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 )
|
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||||
{
|
return ( item[offset] | (item[offset + 1] << 8));
|
||||||
return ( item[offset] | ( item[offset + 1] << 8 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t u8array_to_u32 ( const uint8_t* item, int offset )
|
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));
|
||||||
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 )
|
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||||
{
|
item[offset] = (uint8_t) value;
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset + 1] = (uint8_t)(value >> 8);
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u32_to_u8array ( uint8_t* item, int offset, uint32_t value )
|
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||||
{
|
item[offset] = (uint8_t) value;
|
||||||
item[offset] = ( uint8_t ) value;
|
item[offset + 1] = (uint8_t)(value >> 8);
|
||||||
item[offset + 1] = ( uint8_t )( value >> 8 );
|
item[offset + 2] = (uint8_t)(value >> 16);
|
||||||
item[offset + 2] = ( uint8_t )( value >> 16 );
|
item[offset + 3] = (uint8_t)(value >> 24);
|
||||||
item[offset + 3] = ( uint8_t )( value >> 24 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _BIT_OPS_H
|
#endif // _BIT_OPS_H
|
||||||
|
@ -53,14 +53,14 @@
|
|||||||
*
|
*
|
||||||
* Set the bit @bit in the @bitmap to @new_value. Ignore all errors.
|
* 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 )
|
if (!bitmap || new_value > 1)
|
||||||
return;
|
return;
|
||||||
if ( !new_value )
|
if (!new_value)
|
||||||
bitmap[bit >> 3] &= ~( 1 << ( bit & 7 ) );
|
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||||
else
|
else
|
||||||
bitmap[bit >> 3] |= ( 1 << ( bit & 7 ) );
|
bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,11 +71,11 @@ void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
|||||||
* Get and return the value of the bit @bit in @bitmap (0 or 1).
|
* Get and return the value of the bit @bit in @bitmap (0 or 1).
|
||||||
* Return -1 on error.
|
* 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 )
|
if (!bitmap)
|
||||||
return -1;
|
return -1;
|
||||||
return ( bitmap[bit >> 3] >> ( bit & 7 ) ) & 1;
|
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,15 +87,15 @@ char ntfs_bit_get( const u8 *bitmap, const u64 bit )
|
|||||||
* Return the value of the bit @bit and set it to @new_value (0 or 1).
|
* Return the value of the bit @bit and set it to @new_value (0 or 1).
|
||||||
* Return -1 on error.
|
* 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 )
|
if (!bitmap || new_value > 1)
|
||||||
return -1;
|
return -1;
|
||||||
shift = bit & 7;
|
shift = bit & 7;
|
||||||
old_bit = ( bitmap[bit >> 3] >> shift ) & 1;
|
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||||
if ( new_value != old_bit )
|
if (new_value != old_bit)
|
||||||
bitmap[bit >> 3] ^= 1 << shift;
|
bitmap[bit >> 3] ^= 1 << shift;
|
||||||
return old_bit;
|
return old_bit;
|
||||||
}
|
}
|
||||||
@ -112,105 +112,95 @@ char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value )
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* 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,
|
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||||
s64 count, int value )
|
s64 count, int value)
|
||||||
{
|
{
|
||||||
s64 bufsize, br;
|
s64 bufsize, br;
|
||||||
u8 *buf, *lastbyte_buf;
|
u8 *buf, *lastbyte_buf;
|
||||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, ret = -1;
|
||||||
|
|
||||||
if ( !na || start_bit < 0 || count < 0 )
|
if (!na || start_bit < 0 || count < 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: Invalid argument (%p, %lld, %lld)",
|
ntfs_log_perror("%s: Invalid argument (%p, %lld, %lld)",
|
||||||
__FUNCTION__, na, ( long long )start_bit, ( long long )count );
|
__FUNCTION__, na, (long long)start_bit, (long long)count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit = start_bit & 7;
|
bit = start_bit & 7;
|
||||||
if ( bit )
|
if (bit)
|
||||||
firstbyte = 1;
|
firstbyte = 1;
|
||||||
else
|
else
|
||||||
firstbyte = 0;
|
firstbyte = 0;
|
||||||
|
|
||||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||||
bufsize = ( ( count - ( bit ? 8 - bit : 0 ) + 7 ) >> 3 ) + firstbyte;
|
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||||
if ( bufsize > 8192 )
|
if (bufsize > 8192)
|
||||||
bufsize = 8192;
|
bufsize = 8192;
|
||||||
|
|
||||||
buf = ntfs_malloc( bufsize );
|
buf = ntfs_malloc(bufsize);
|
||||||
if ( !buf )
|
if (!buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||||
memset( buf, value ? 0xff : 0, bufsize );
|
memset(buf, value ? 0xff : 0, bufsize);
|
||||||
|
|
||||||
/* If there is a first partial byte... */
|
/* If there is a first partial byte... */
|
||||||
if ( bit )
|
if (bit) {
|
||||||
{
|
|
||||||
/* read it in... */
|
/* read it in... */
|
||||||
br = ntfs_attr_pread( na, start_bit >> 3, 1, buf );
|
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||||
if ( br != 1 )
|
if (br != 1) {
|
||||||
{
|
if (br >= 0)
|
||||||
if ( br >= 0 )
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set or clear the appropriate bits in it. */
|
/* and set or clear the appropriate bits in it. */
|
||||||
while ( ( bit & 7 ) && count-- )
|
while ((bit & 7) && count--) {
|
||||||
{
|
if (value)
|
||||||
if ( value )
|
|
||||||
*buf |= 1 << bit++;
|
*buf |= 1 << bit++;
|
||||||
else
|
else
|
||||||
*buf &= ~( 1 << bit++ );
|
*buf &= ~(1 << bit++);
|
||||||
}
|
}
|
||||||
/* Update @start_bit to the new position. */
|
/* Update @start_bit to the new position. */
|
||||||
start_bit = ( start_bit + 7 ) & ~7;
|
start_bit = (start_bit + 7) & ~7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop until @count reaches zero. */
|
/* Loop until @count reaches zero. */
|
||||||
lastbyte = 0;
|
lastbyte = 0;
|
||||||
lastbyte_buf = NULL;
|
lastbyte_buf = NULL;
|
||||||
bit = count & 7;
|
bit = count & 7;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
/* If there is a last partial byte... */
|
/* If there is a last partial byte... */
|
||||||
if ( count > 0 && bit )
|
if (count > 0 && bit) {
|
||||||
{
|
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||||
lastbyte_pos = ( ( count + 7 ) >> 3 ) + firstbyte;
|
if (!lastbyte_pos) {
|
||||||
if ( !lastbyte_pos )
|
|
||||||
{
|
|
||||||
// FIXME: Eeek! BUG!
|
// FIXME: Eeek! BUG!
|
||||||
ntfs_log_error( "Lastbyte is zero. Leaving "
|
ntfs_log_error("Lastbyte is zero. Leaving "
|
||||||
"inconsistent metadata.\n" );
|
"inconsistent metadata.\n");
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and it is in the currently loaded bitmap window... */
|
/* and it is in the currently loaded bitmap window... */
|
||||||
if ( lastbyte_pos <= bufsize )
|
if (lastbyte_pos <= bufsize) {
|
||||||
{
|
|
||||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||||
|
|
||||||
/* read the byte in... */
|
/* read the byte in... */
|
||||||
br = ntfs_attr_pread( na, ( start_bit + count ) >>
|
br = ntfs_attr_pread(na, (start_bit + count) >>
|
||||||
3, 1, lastbyte_buf );
|
3, 1, lastbyte_buf);
|
||||||
if ( br != 1 )
|
if (br != 1) {
|
||||||
{
|
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if ( br >= 0 )
|
if (br >= 0)
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Reading of last byte "
|
ntfs_log_perror("Reading of last byte "
|
||||||
"failed (%lld). Leaving inconsistent "
|
"failed (%lld). Leaving inconsistent "
|
||||||
"metadata", ( long long )br );
|
"metadata", (long long)br);
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
/* and set/clear the appropriate bits in it. */
|
/* and set/clear the appropriate bits in it. */
|
||||||
while ( bit && count-- )
|
while (bit && count--) {
|
||||||
{
|
if (value)
|
||||||
if ( value )
|
|
||||||
*lastbyte_buf |= 1 << --bit;
|
*lastbyte_buf |= 1 << --bit;
|
||||||
else
|
else
|
||||||
*lastbyte_buf &= ~( 1 << --bit );
|
*lastbyte_buf &= ~(1 << --bit);
|
||||||
}
|
}
|
||||||
/* We don't want to come back here... */
|
/* We don't want to come back here... */
|
||||||
bit = 0;
|
bit = 0;
|
||||||
@ -220,23 +210,21 @@ static int ntfs_bitmap_set_bits_in_run( ntfs_attr *na, s64 start_bit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write the prepared buffer to disk. */
|
/* Write the prepared buffer to disk. */
|
||||||
tmp = ( start_bit >> 3 ) - firstbyte;
|
tmp = (start_bit >> 3) - firstbyte;
|
||||||
br = ntfs_attr_pwrite( na, tmp, bufsize, buf );
|
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||||
if ( br != bufsize )
|
if (br != bufsize) {
|
||||||
{
|
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
if ( br >= 0 )
|
if (br >= 0)
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Failed to write buffer to bitmap "
|
ntfs_log_perror("Failed to write buffer to bitmap "
|
||||||
"(%lld != %lld). Leaving inconsistent metadata",
|
"(%lld != %lld). Leaving inconsistent metadata",
|
||||||
( long long )br, ( long long )bufsize );
|
(long long)br, (long long)bufsize);
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update counters. */
|
/* Update counters. */
|
||||||
tmp = ( bufsize - firstbyte - lastbyte ) << 3;
|
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||||
if ( firstbyte )
|
if (firstbyte) {
|
||||||
{
|
|
||||||
firstbyte = 0;
|
firstbyte = 0;
|
||||||
/*
|
/*
|
||||||
* Re-set the partial first byte so a subsequent write
|
* Re-set the partial first byte so a subsequent write
|
||||||
@ -246,25 +234,23 @@ static int ntfs_bitmap_set_bits_in_run( ntfs_attr *na, s64 start_bit,
|
|||||||
}
|
}
|
||||||
start_bit += tmp;
|
start_bit += tmp;
|
||||||
count -= tmp;
|
count -= tmp;
|
||||||
if ( bufsize > ( tmp = ( count + 7 ) >> 3 ) )
|
if (bufsize > (tmp = (count + 7) >> 3))
|
||||||
bufsize = tmp;
|
bufsize = tmp;
|
||||||
|
|
||||||
if ( lastbyte && count != 0 )
|
if (lastbyte && count != 0) {
|
||||||
{
|
|
||||||
// FIXME: Eeek! BUG!
|
// FIXME: Eeek! BUG!
|
||||||
ntfs_log_error( "Last buffer but count is not zero "
|
ntfs_log_error("Last buffer but count is not zero "
|
||||||
"(%lld). Leaving inconsistent metadata.\n",
|
"(%lld). Leaving inconsistent metadata.\n",
|
||||||
( long long )count );
|
(long long)count);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
goto free_err_out;
|
goto free_err_out;
|
||||||
}
|
}
|
||||||
}
|
} while (count > 0);
|
||||||
while ( count > 0 );
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
free_err_out:
|
free_err_out:
|
||||||
free( buf );
|
free(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,14 +265,14 @@ free_err_out:
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* 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;
|
int ret;
|
||||||
|
|
||||||
ntfs_log_enter( "Set from bit %lld, count %lld\n",
|
ntfs_log_enter("Set from bit %lld, count %lld\n",
|
||||||
( long long )start_bit, ( long long )count );
|
(long long)start_bit, (long long)count);
|
||||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 1 );
|
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,14 +287,14 @@ int ntfs_bitmap_set_run( ntfs_attr *na, s64 start_bit, s64 count )
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* 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;
|
int ret;
|
||||||
|
|
||||||
ntfs_log_enter( "Clear from bit %lld, count %lld\n",
|
ntfs_log_enter("Clear from bit %lld, count %lld\n",
|
||||||
( long long )start_bit, ( long long )count );
|
(long long)start_bit, (long long)count);
|
||||||
ret = ntfs_bitmap_set_bits_in_run( na, start_bit, count, 0 );
|
ret = ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@
|
|||||||
* size of the bitmap.
|
* size of the bitmap.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void ntfs_bit_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
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(const u8 *bitmap, const u64 bit);
|
||||||
extern char ntfs_bit_get_and_set( u8 *bitmap, const u64 bit, const u8 new_value );
|
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_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 int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_bitmap_set_bit - set a bit in a bitmap
|
* ntfs_bitmap_set_bit - set a bit in a bitmap
|
||||||
@ -51,9 +51,9 @@ extern int ntfs_bitmap_clear_run( ntfs_attr *na, s64 start_bit, s64 count );
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,9 +65,9 @@ static __inline__ int ntfs_bitmap_set_bit( ntfs_attr *na, s64 bit )
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* 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
|
* @word: value to rotate
|
||||||
* @shift: bits to roll
|
* @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
|
* @word: value to rotate
|
||||||
* @shift: bits to roll
|
* @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 */
|
#endif /* defined _NTFS_BITMAP_H */
|
||||||
|
@ -57,103 +57,94 @@
|
|||||||
*
|
*
|
||||||
* Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
|
* 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;
|
u32 i;
|
||||||
BOOL ret = FALSE;
|
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" );
|
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
||||||
if ( b->oem_id != cpu_to_le64( 0x202020205346544eULL ) ) /* "NTFS " */
|
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||||
{
|
ntfs_log_error("NTFS signature is missing.\n");
|
||||||
ntfs_log_error( "NTFS signature is missing.\n" );
|
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking bytes per sector.\n" );
|
ntfs_log_debug("Checking bytes per sector.\n");
|
||||||
if ( le16_to_cpu( b->bpb.bytes_per_sector ) < 256 ||
|
if (le16_to_cpu(b->bpb.bytes_per_sector) < 256 ||
|
||||||
le16_to_cpu( b->bpb.bytes_per_sector ) > 4096 )
|
le16_to_cpu(b->bpb.bytes_per_sector) > 4096) {
|
||||||
{
|
ntfs_log_error("Unexpected bytes per sector value (%d).\n",
|
||||||
ntfs_log_error( "Unexpected bytes per sector value (%d).\n",
|
le16_to_cpu(b->bpb.bytes_per_sector));
|
||||||
le16_to_cpu( b->bpb.bytes_per_sector ) );
|
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking sectors per cluster.\n" );
|
ntfs_log_debug("Checking sectors per cluster.\n");
|
||||||
switch ( b->bpb.sectors_per_cluster )
|
switch (b->bpb.sectors_per_cluster) {
|
||||||
{
|
|
||||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error( "Unexpected sectors per cluster value (%d).\n",
|
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
|
||||||
b->bpb.sectors_per_cluster );
|
b->bpb.sectors_per_cluster);
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking cluster size.\n" );
|
ntfs_log_debug("Checking cluster size.\n");
|
||||||
i = ( u32 )le16_to_cpu( b->bpb.bytes_per_sector ) *
|
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
||||||
b->bpb.sectors_per_cluster;
|
b->bpb.sectors_per_cluster;
|
||||||
if ( i > 65536 )
|
if (i > 65536) {
|
||||||
{
|
ntfs_log_error("Unexpected cluster size (%d).\n", i);
|
||||||
ntfs_log_error( "Unexpected cluster size (%d).\n", i );
|
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking reserved fields are zero.\n" );
|
ntfs_log_debug("Checking reserved fields are zero.\n");
|
||||||
if ( le16_to_cpu( b->bpb.reserved_sectors ) ||
|
if (le16_to_cpu(b->bpb.reserved_sectors) ||
|
||||||
le16_to_cpu( b->bpb.root_entries ) ||
|
le16_to_cpu(b->bpb.root_entries) ||
|
||||||
le16_to_cpu( b->bpb.sectors ) ||
|
le16_to_cpu(b->bpb.sectors) ||
|
||||||
le16_to_cpu( b->bpb.sectors_per_fat ) ||
|
le16_to_cpu(b->bpb.sectors_per_fat) ||
|
||||||
le32_to_cpu( b->bpb.large_sectors ) ||
|
le32_to_cpu(b->bpb.large_sectors) ||
|
||||||
b->bpb.fats )
|
b->bpb.fats) {
|
||||||
{
|
ntfs_log_error("Reserved fields aren't zero "
|
||||||
ntfs_log_error( "Reserved fields aren't zero "
|
|
||||||
"(%d, %d, %d, %d, %d, %d).\n",
|
"(%d, %d, %d, %d, %d, %d).\n",
|
||||||
le16_to_cpu( b->bpb.reserved_sectors ),
|
le16_to_cpu(b->bpb.reserved_sectors),
|
||||||
le16_to_cpu( b->bpb.root_entries ),
|
le16_to_cpu(b->bpb.root_entries),
|
||||||
le16_to_cpu( b->bpb.sectors ),
|
le16_to_cpu(b->bpb.sectors),
|
||||||
le16_to_cpu( b->bpb.sectors_per_fat ),
|
le16_to_cpu(b->bpb.sectors_per_fat),
|
||||||
le32_to_cpu( b->bpb.large_sectors ),
|
le32_to_cpu(b->bpb.large_sectors),
|
||||||
b->bpb.fats );
|
b->bpb.fats);
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking clusters per mft record.\n" );
|
ntfs_log_debug("Checking clusters per mft record.\n");
|
||||||
if ( ( u8 )b->clusters_per_mft_record < 0xe1 ||
|
if ((u8)b->clusters_per_mft_record < 0xe1 ||
|
||||||
( u8 )b->clusters_per_mft_record > 0xf7 )
|
(u8)b->clusters_per_mft_record > 0xf7) {
|
||||||
{
|
switch (b->clusters_per_mft_record) {
|
||||||
switch ( b->clusters_per_mft_record )
|
|
||||||
{
|
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error( "Unexpected clusters per mft record "
|
ntfs_log_error("Unexpected clusters per mft record "
|
||||||
"(%d).\n", b->clusters_per_mft_record );
|
"(%d).\n", b->clusters_per_mft_record);
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Checking clusters per index block.\n" );
|
ntfs_log_debug("Checking clusters per index block.\n");
|
||||||
if ( ( u8 )b->clusters_per_index_record < 0xe1 ||
|
if ((u8)b->clusters_per_index_record < 0xe1 ||
|
||||||
( u8 )b->clusters_per_index_record > 0xf7 )
|
(u8)b->clusters_per_index_record > 0xf7) {
|
||||||
{
|
switch (b->clusters_per_index_record) {
|
||||||
switch ( b->clusters_per_index_record )
|
|
||||||
{
|
|
||||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfs_log_error( "Unexpected clusters per index record "
|
ntfs_log_error("Unexpected clusters per index record "
|
||||||
"(%d).\n", b->clusters_per_index_record );
|
"(%d).\n", b->clusters_per_index_record);
|
||||||
goto not_ntfs;
|
goto not_ntfs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( b->end_of_sector_marker != cpu_to_le16( 0xaa55 ) )
|
if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
|
||||||
ntfs_log_debug( "Warning: Bootsector has invalid end of sector "
|
ntfs_log_debug("Warning: Bootsector has invalid end of sector "
|
||||||
"marker.\n" );
|
"marker.\n");
|
||||||
|
|
||||||
ntfs_log_debug( "Bootsector check completed successfully.\n" );
|
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
not_ntfs:
|
not_ntfs:
|
||||||
@ -161,11 +152,11 @@ not_ntfs:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *last_sector_error =
|
static const char *last_sector_error =
|
||||||
"HINTS: Either the volume is a RAID/LDM but it wasn't setup yet,\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 it was not setup correctly (e.g. by not using mdadm --build ...),\n"
|
||||||
" or a wrong device is tried to be mounted,\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 partition table is corrupt (partition is smaller than NTFS),\n"
|
||||||
" or the NTFS boot sector is corrupt (NTFS size is not valid).\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
|
* ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
|
||||||
@ -177,7 +168,7 @@ static const char *last_sector_error =
|
|||||||
*
|
*
|
||||||
* Return 0 on success or -1 on error with errno set to the error code EINVAL.
|
* 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;
|
s64 sectors;
|
||||||
u8 sectors_per_cluster;
|
u8 sectors_per_cluster;
|
||||||
@ -186,103 +177,97 @@ int ntfs_boot_sector_parse( ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs )
|
|||||||
/* We return -1 with errno = EINVAL on error. */
|
/* We return -1 with errno = EINVAL on error. */
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
|
||||||
vol->sector_size = le16_to_cpu( bs->bpb.bytes_per_sector );
|
vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
|
||||||
vol->sector_size_bits = ffs( vol->sector_size ) - 1;
|
vol->sector_size_bits = ffs(vol->sector_size) - 1;
|
||||||
ntfs_log_debug( "SectorSize = 0x%x\n", vol->sector_size );
|
ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
|
||||||
ntfs_log_debug( "SectorSizeBits = %u\n", vol->sector_size_bits );
|
ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
|
||||||
/*
|
/*
|
||||||
* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
|
* 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
|
* 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.
|
* ntfs_boot_sector_is_ntfs but in this way we can just do this once.
|
||||||
*/
|
*/
|
||||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||||
ntfs_log_debug( "SectorsPerCluster = 0x%x\n", sectors_per_cluster );
|
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
||||||
if ( sectors_per_cluster & ( sectors_per_cluster - 1 ) )
|
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
||||||
{
|
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
|
||||||
ntfs_log_error( "sectors_per_cluster (%d) is not a power of 2."
|
"\n", sectors_per_cluster);
|
||||||
"\n", sectors_per_cluster );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sectors = sle64_to_cpu( bs->number_of_sectors );
|
sectors = sle64_to_cpu(bs->number_of_sectors);
|
||||||
ntfs_log_debug( "NumberOfSectors = %lld\n", ( long long )sectors );
|
ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors);
|
||||||
if ( !sectors )
|
if (!sectors) {
|
||||||
{
|
ntfs_log_error("Volume size is set to zero.\n");
|
||||||
ntfs_log_error( "Volume size is set to zero.\n" );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( vol->dev->d_ops->seek( vol->dev,
|
if (vol->dev->d_ops->seek(vol->dev,
|
||||||
( sectors - 1 ) << vol->sector_size_bits,
|
(sectors - 1) << vol->sector_size_bits,
|
||||||
SEEK_SET ) == -1 )
|
SEEK_SET) == -1) {
|
||||||
{
|
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||||
ntfs_log_perror( "Failed to read last sector (%lld)",
|
(long long)sectors);
|
||||||
( long long )sectors );
|
ntfs_log_error("%s", last_sector_error);
|
||||||
ntfs_log_error( "%s", last_sector_error );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vol->nr_clusters = sectors >> ( ffs( sectors_per_cluster ) - 1 );
|
vol->nr_clusters = sectors >> (ffs(sectors_per_cluster) - 1);
|
||||||
|
|
||||||
vol->mft_lcn = sle64_to_cpu( bs->mft_lcn );
|
vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
|
||||||
vol->mftmirr_lcn = sle64_to_cpu( bs->mftmirr_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("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||||
ntfs_log_debug( "MFTMirr LCN = %lld\n", ( long long )vol->mftmirr_lcn );
|
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||||
if ( vol->mft_lcn > vol->nr_clusters ||
|
if (vol->mft_lcn > vol->nr_clusters ||
|
||||||
vol->mftmirr_lcn > vol->nr_clusters )
|
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||||
{
|
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||||
ntfs_log_error( "$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
|
||||||
"greater than the number of clusters (%lld).\n",
|
"greater than the number of clusters (%lld).\n",
|
||||||
( long long )vol->mft_lcn, ( long long )vol->mftmirr_lcn,
|
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||||
( long long )vol->nr_clusters );
|
(long long)vol->nr_clusters);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||||
if ( vol->cluster_size & ( vol->cluster_size - 1 ) )
|
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
||||||
{
|
ntfs_log_error("cluster_size (%d) is not a power of 2.\n",
|
||||||
ntfs_log_error( "cluster_size (%d) is not a power of 2.\n",
|
vol->cluster_size);
|
||||||
vol->cluster_size );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
vol->cluster_size_bits = ffs( vol->cluster_size ) - 1;
|
vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
|
||||||
/*
|
/*
|
||||||
* Need to get the clusters per mft record and handle it if it is
|
* 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
|
* negative. Then calculate the mft_record_size. A value of 0x80 is
|
||||||
* illegal, thus signed char is actually ok!
|
* illegal, thus signed char is actually ok!
|
||||||
*/
|
*/
|
||||||
c = bs->clusters_per_mft_record;
|
c = bs->clusters_per_mft_record;
|
||||||
ntfs_log_debug( "ClusterSize = 0x%x\n", ( unsigned )vol->cluster_size );
|
ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
|
||||||
ntfs_log_debug( "ClusterSizeBits = %u\n", vol->cluster_size_bits );
|
ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
|
||||||
ntfs_log_debug( "ClustersPerMftRecord = 0x%x\n", c );
|
ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
|
||||||
/*
|
/*
|
||||||
* When clusters_per_mft_record is negative, it means that it is to
|
* 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
|
* be taken to be the negative base 2 logarithm of the mft_record_size
|
||||||
* min bytes. Then:
|
* min bytes. Then:
|
||||||
* mft_record_size = 2^(-clusters_per_mft_record) bytes.
|
* mft_record_size = 2^(-clusters_per_mft_record) bytes.
|
||||||
*/
|
*/
|
||||||
if ( c < 0 )
|
if (c < 0)
|
||||||
vol->mft_record_size = 1 << -c;
|
vol->mft_record_size = 1 << -c;
|
||||||
else
|
else
|
||||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||||
if ( vol->mft_record_size & ( vol->mft_record_size - 1 ) )
|
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
||||||
{
|
ntfs_log_error("mft_record_size (%d) is not a power of 2.\n",
|
||||||
ntfs_log_error( "mft_record_size (%d) is not a power of 2.\n",
|
vol->mft_record_size);
|
||||||
vol->mft_record_size );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
vol->mft_record_size_bits = ffs( vol->mft_record_size ) - 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("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
|
||||||
ntfs_log_debug( "MftRecordSizeBits = %u\n", vol->mft_record_size_bits );
|
ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
|
||||||
/* Same as above for INDX record. */
|
/* Same as above for INDX record. */
|
||||||
c = bs->clusters_per_index_record;
|
c = bs->clusters_per_index_record;
|
||||||
ntfs_log_debug( "ClustersPerINDXRecord = 0x%x\n", c );
|
ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
|
||||||
if ( c < 0 )
|
if (c < 0)
|
||||||
vol->indx_record_size = 1 << -c;
|
vol->indx_record_size = 1 << -c;
|
||||||
else
|
else
|
||||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
vol->indx_record_size = c << vol->cluster_size_bits;
|
||||||
vol->indx_record_size_bits = ffs( vol->indx_record_size ) - 1;
|
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("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
|
||||||
ntfs_log_debug( "INDXRecordSizeBits = %u\n", vol->indx_record_size_bits );
|
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
|
* 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
|
* cluster size is less than or equal to the size taken by four mft
|
||||||
@ -291,7 +276,7 @@ int ntfs_boot_sector_parse( ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs )
|
|||||||
* mft mirror contains as many mft records as will fit into one
|
* mft mirror contains as many mft records as will fit into one
|
||||||
* cluster.
|
* cluster.
|
||||||
*/
|
*/
|
||||||
if ( vol->cluster_size <= 4 * vol->mft_record_size )
|
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||||
vol->mftmirr_size = 4;
|
vol->mftmirr_size = 4;
|
||||||
else
|
else
|
||||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||||
|
@ -35,8 +35,8 @@
|
|||||||
* This function checks the boot sector in @b for describing a valid ntfs
|
* 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.
|
* 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 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 int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs);
|
||||||
|
|
||||||
#endif /* defined _NTFS_BOOTSECT_H */
|
#endif /* defined _NTFS_BOOTSECT_H */
|
||||||
|
|
||||||
|
@ -60,45 +60,38 @@
|
|||||||
* Do not call when a record has been modified (with no key change)
|
* Do not call when a record has been modified (with no key change)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void inserthashindex( struct CACHE_HEADER *cache,
|
static void inserthashindex(struct CACHE_HEADER *cache,
|
||||||
struct CACHED_GENERIC *current )
|
struct CACHED_GENERIC *current)
|
||||||
{
|
{
|
||||||
int h;
|
int h;
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *first;
|
struct HASH_ENTRY *first;
|
||||||
|
|
||||||
if ( cache->dohash )
|
if (cache->dohash) {
|
||||||
{
|
h = cache->dohash(current);
|
||||||
h = cache->dohash( current );
|
if ((h >= 0) && (h < cache->max_hash)) {
|
||||||
if ( ( h >= 0 ) && ( h < cache->max_hash ) )
|
|
||||||
{
|
|
||||||
/* get a free link and insert at top of hash list */
|
/* get a free link and insert at top of hash list */
|
||||||
link = cache->free_hash;
|
link = cache->free_hash;
|
||||||
if ( link )
|
if (link) {
|
||||||
{
|
|
||||||
cache->free_hash = link->next;
|
cache->free_hash = link->next;
|
||||||
first = cache->first_hash[h];
|
first = cache->first_hash[h];
|
||||||
if ( first )
|
if (first)
|
||||||
link->next = first;
|
link->next = first;
|
||||||
else
|
else
|
||||||
link->next = NULL;
|
link->next = NULL;
|
||||||
link->entry = current;
|
link->entry = current;
|
||||||
cache->first_hash[h] = link;
|
cache->first_hash[h] = link;
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_error("No more hash entries,"
|
||||||
{
|
|
||||||
ntfs_log_error( "No more hash entries,"
|
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name);
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = (cache_hash)NULL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_error("Illegal hash value,"
|
||||||
{
|
|
||||||
ntfs_log_error( "Illegal hash value,"
|
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name);
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = (cache_hash)NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,47 +100,39 @@ static void inserthashindex( struct CACHE_HEADER *cache,
|
|||||||
* Drop a hash index when a record is about to be deleted
|
* Drop a hash index when a record is about to be deleted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void drophashindex( struct CACHE_HEADER *cache,
|
static void drophashindex(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *current, int hash )
|
const struct CACHED_GENERIC *current, int hash)
|
||||||
{
|
{
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
struct HASH_ENTRY *previous;
|
struct HASH_ENTRY *previous;
|
||||||
|
|
||||||
if ( cache->dohash )
|
if (cache->dohash) {
|
||||||
{
|
if ((hash >= 0) && (hash < cache->max_hash)) {
|
||||||
if ( ( hash >= 0 ) && ( hash < cache->max_hash ) )
|
|
||||||
{
|
|
||||||
/* find the link and unlink */
|
/* find the link and unlink */
|
||||||
link = cache->first_hash[hash];
|
link = cache->first_hash[hash];
|
||||||
previous = ( struct HASH_ENTRY* )NULL;
|
previous = (struct HASH_ENTRY*)NULL;
|
||||||
while ( link && ( link->entry != current ) )
|
while (link && (link->entry != current)) {
|
||||||
{
|
|
||||||
previous = link;
|
previous = link;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
}
|
}
|
||||||
if ( link )
|
if (link) {
|
||||||
{
|
if (previous)
|
||||||
if ( previous )
|
|
||||||
previous->next = link->next;
|
previous->next = link->next;
|
||||||
else
|
else
|
||||||
cache->first_hash[hash] = link->next;
|
cache->first_hash[hash] = link->next;
|
||||||
link->next = cache->free_hash;
|
link->next = cache->free_hash;
|
||||||
cache->free_hash = link;
|
cache->free_hash = link;
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_error("Bad hash list,"
|
||||||
{
|
|
||||||
ntfs_log_error( "Bad hash list,"
|
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name);
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = (cache_hash)NULL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_error("Illegal hash value,"
|
||||||
{
|
|
||||||
ntfs_log_error( "Illegal hash value,"
|
|
||||||
" cache %s hashing dropped\n",
|
" cache %s hashing dropped\n",
|
||||||
cache->name );
|
cache->name);
|
||||||
cache->dohash = ( cache_hash )NULL;
|
cache->dohash = (cache_hash)NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,55 +144,49 @@ static void drophashindex( struct CACHE_HEADER *cache,
|
|||||||
* The returned entry may be modified, but not freed
|
* The returned entry may be modified, but not freed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *wanted, cache_compare compare )
|
const struct CACHED_GENERIC *wanted, cache_compare compare)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = (struct CACHED_GENERIC*)NULL;
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
if (cache->dohash) {
|
||||||
if ( cache->dohash )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* locate the entry if present
|
* locate the entry if present
|
||||||
*/
|
*/
|
||||||
h = cache->dohash( wanted );
|
h = cache->dohash(wanted);
|
||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while ( link && compare( link->entry, wanted ) )
|
while (link && compare(link->entry, wanted))
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if ( link )
|
if (link)
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
}
|
}
|
||||||
if ( !cache->dohash )
|
if (!cache->dohash) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list if no hash table
|
* Search sequentially in LRU list if no hash table
|
||||||
* or if hashing has just failed
|
* or if hashing has just failed
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while ( current
|
while (current
|
||||||
&& compare( current, wanted ) )
|
&& compare(current, wanted)) {
|
||||||
{
|
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( current )
|
if (current) {
|
||||||
{
|
|
||||||
previous = current->previous;
|
previous = current->previous;
|
||||||
cache->hits++;
|
cache->hits++;
|
||||||
if ( previous )
|
if (previous) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* found and not at head of list, unlink from current
|
* found and not at head of list, unlink from current
|
||||||
* position and relink as head of list
|
* position and relink as head of list
|
||||||
*/
|
*/
|
||||||
previous->next = current->next;
|
previous->next = current->next;
|
||||||
if ( current->next )
|
if (current->next)
|
||||||
current->next->previous
|
current->next->previous
|
||||||
= current->previous;
|
= current->previous;
|
||||||
else
|
else
|
||||||
@ -215,14 +194,14 @@ struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
|||||||
= current->previous;
|
= current->previous;
|
||||||
current->next = cache->most_recent_entry;
|
current->next = cache->most_recent_entry;
|
||||||
current->previous
|
current->previous
|
||||||
= ( struct CACHED_GENERIC* )NULL;
|
= (struct CACHED_GENERIC*)NULL;
|
||||||
cache->most_recent_entry->previous = current;
|
cache->most_recent_entry->previous = current;
|
||||||
cache->most_recent_entry = current;
|
cache->most_recent_entry = current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache->reads++;
|
cache->reads++;
|
||||||
}
|
}
|
||||||
return ( current );
|
return (current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -230,35 +209,31 @@ struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
|||||||
* returns the cache entry or NULL if not possible
|
* returns the cache entry or NULL if not possible
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *item,
|
const struct CACHED_GENERIC *item,
|
||||||
cache_compare compare )
|
cache_compare compare)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
struct CACHED_GENERIC *before;
|
struct CACHED_GENERIC *before;
|
||||||
struct HASH_ENTRY *link;
|
struct HASH_ENTRY *link;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = (struct CACHED_GENERIC*)NULL;
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
if (cache->dohash) {
|
||||||
if ( cache->dohash )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
*/
|
*/
|
||||||
h = cache->dohash( item );
|
h = cache->dohash(item);
|
||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while ( link && compare( link->entry, item ) )
|
while (link && compare(link->entry, item))
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if ( link )
|
if (link) {
|
||||||
{
|
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !cache->dohash )
|
if (!cache->dohash) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list to locate the end,
|
* Search sequentially in LRU list to locate the end,
|
||||||
* and find out whether the entry is already in list
|
* and find out whether the entry is already in list
|
||||||
@ -266,15 +241,13 @@ struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
|||||||
* kept.
|
* kept.
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
while ( current
|
while (current
|
||||||
&& compare( current, item ) )
|
&& compare(current, item)) {
|
||||||
{
|
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !current )
|
if (!current) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Not in list, get a free entry or reuse the
|
* Not in list, get a free entry or reuse the
|
||||||
* last entry, and relink as head of list
|
* last entry, and relink as head of list
|
||||||
@ -283,66 +256,54 @@ struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
|||||||
* an entry is reused.
|
* an entry is reused.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( cache->free_entry )
|
if (cache->free_entry) {
|
||||||
{
|
|
||||||
current = cache->free_entry;
|
current = cache->free_entry;
|
||||||
cache->free_entry = cache->free_entry->next;
|
cache->free_entry = cache->free_entry->next;
|
||||||
if ( item->varsize )
|
if (item->varsize) {
|
||||||
{
|
|
||||||
current->variable = ntfs_malloc(
|
current->variable = ntfs_malloc(
|
||||||
item->varsize );
|
item->varsize);
|
||||||
}
|
} else
|
||||||
else
|
current->variable = (void*)NULL;
|
||||||
current->variable = ( void* )NULL;
|
|
||||||
current->varsize = item->varsize;
|
current->varsize = item->varsize;
|
||||||
if ( !cache->oldest_entry )
|
if (!cache->oldest_entry)
|
||||||
cache->oldest_entry = current;
|
cache->oldest_entry = current;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* reusing the oldest entry */
|
/* reusing the oldest entry */
|
||||||
current = cache->oldest_entry;
|
current = cache->oldest_entry;
|
||||||
before = current->previous;
|
before = current->previous;
|
||||||
before->next = ( struct CACHED_GENERIC* )NULL;
|
before->next = (struct CACHED_GENERIC*)NULL;
|
||||||
if ( cache->dohash )
|
if (cache->dohash)
|
||||||
drophashindex( cache, current,
|
drophashindex(cache,current,
|
||||||
cache->dohash( current ) );
|
cache->dohash(current));
|
||||||
if ( cache->dofree )
|
if (cache->dofree)
|
||||||
cache->dofree( current );
|
cache->dofree(current);
|
||||||
cache->oldest_entry = current->previous;
|
cache->oldest_entry = current->previous;
|
||||||
if ( item->varsize )
|
if (item->varsize) {
|
||||||
{
|
if (current->varsize)
|
||||||
if ( current->varsize )
|
|
||||||
current->variable = realloc(
|
current->variable = realloc(
|
||||||
current->variable,
|
current->variable,
|
||||||
item->varsize );
|
item->varsize);
|
||||||
else
|
else
|
||||||
current->variable = ntfs_malloc(
|
current->variable = ntfs_malloc(
|
||||||
item->varsize );
|
item->varsize);
|
||||||
}
|
} else {
|
||||||
else
|
if (current->varsize)
|
||||||
{
|
free(current->variable);
|
||||||
if ( current->varsize )
|
current->variable = (void*)NULL;
|
||||||
free( current->variable );
|
|
||||||
current->variable = ( void* )NULL;
|
|
||||||
}
|
}
|
||||||
current->varsize = item->varsize;
|
current->varsize = item->varsize;
|
||||||
}
|
}
|
||||||
current->next = cache->most_recent_entry;
|
current->next = cache->most_recent_entry;
|
||||||
current->previous = ( struct CACHED_GENERIC* )NULL;
|
current->previous = (struct CACHED_GENERIC*)NULL;
|
||||||
if ( cache->most_recent_entry )
|
if (cache->most_recent_entry)
|
||||||
cache->most_recent_entry->previous = current;
|
cache->most_recent_entry->previous = current;
|
||||||
cache->most_recent_entry = current;
|
cache->most_recent_entry = current;
|
||||||
memcpy( current->fixed, item->fixed, cache->fixed_size );
|
memcpy(current->fixed, item->fixed, cache->fixed_size);
|
||||||
if ( item->varsize )
|
if (item->varsize) {
|
||||||
{
|
if (current->variable) {
|
||||||
if ( current->variable )
|
memcpy(current->variable,
|
||||||
{
|
item->variable, item->varsize);
|
||||||
memcpy( current->variable,
|
} else {
|
||||||
item->variable, item->varsize );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* no more memory for variable part
|
* no more memory for variable part
|
||||||
* recycle entry in free list
|
* recycle entry in free list
|
||||||
@ -351,20 +312,18 @@ struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
|||||||
cache->most_recent_entry = current->next;
|
cache->most_recent_entry = current->next;
|
||||||
current->next = cache->free_entry;
|
current->next = cache->free_entry;
|
||||||
cache->free_entry = current;
|
cache->free_entry = current;
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = (struct CACHED_GENERIC*)NULL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
current->variable = (void*)NULL;
|
||||||
{
|
|
||||||
current->variable = ( void* )NULL;
|
|
||||||
current->varsize = 0;
|
current->varsize = 0;
|
||||||
}
|
}
|
||||||
if ( cache->dohash && current )
|
if (cache->dohash && current)
|
||||||
inserthashindex( cache, current );
|
inserthashindex(cache,current);
|
||||||
}
|
}
|
||||||
cache->writes++;
|
cache->writes++;
|
||||||
}
|
}
|
||||||
return ( current );
|
return (current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -373,31 +332,31 @@ struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
|||||||
* A specific function may be called for entry deletion
|
* A specific function may be called for entry deletion
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void do_invalidate( struct CACHE_HEADER *cache,
|
static void do_invalidate(struct CACHE_HEADER *cache,
|
||||||
struct CACHED_GENERIC *current, int flags )
|
struct CACHED_GENERIC *current, int flags)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
|
|
||||||
previous = current->previous;
|
previous = current->previous;
|
||||||
if ( ( flags & CACHE_FREE ) && cache->dofree )
|
if ((flags & CACHE_FREE) && cache->dofree)
|
||||||
cache->dofree( current );
|
cache->dofree(current);
|
||||||
/*
|
/*
|
||||||
* Relink into free list
|
* Relink into free list
|
||||||
*/
|
*/
|
||||||
if ( current->next )
|
if (current->next)
|
||||||
current->next->previous = current->previous;
|
current->next->previous = current->previous;
|
||||||
else
|
else
|
||||||
cache->oldest_entry = current->previous;
|
cache->oldest_entry = current->previous;
|
||||||
if ( previous )
|
if (previous)
|
||||||
previous->next = current->next;
|
previous->next = current->next;
|
||||||
else
|
else
|
||||||
cache->most_recent_entry = current->next;
|
cache->most_recent_entry = current->next;
|
||||||
current->next = cache->free_entry;
|
current->next = cache->free_entry;
|
||||||
cache->free_entry = current;
|
cache->free_entry = current;
|
||||||
if ( current->variable )
|
if (current->variable)
|
||||||
free( current->variable );
|
free(current->variable);
|
||||||
current->varsize = 0;
|
current->varsize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -412,9 +371,9 @@ static void do_invalidate( struct CACHE_HEADER *cache,
|
|||||||
* supposed to be found.
|
* supposed to be found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *item, cache_compare compare,
|
const struct CACHED_GENERIC *item, cache_compare compare,
|
||||||
int flags )
|
int flags)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *current;
|
struct CACHED_GENERIC *current;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
@ -423,100 +382,87 @@ int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
|||||||
int count;
|
int count;
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
current = ( struct CACHED_GENERIC* )NULL;
|
current = (struct CACHED_GENERIC*)NULL;
|
||||||
count = 0;
|
count = 0;
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
if (!(flags & CACHE_NOHASH) && cache->dohash) {
|
||||||
if ( !( flags & CACHE_NOHASH ) && cache->dohash )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* When possible, use the hash table to
|
* When possible, use the hash table to
|
||||||
* find out whether the entry if present
|
* find out whether the entry if present
|
||||||
*/
|
*/
|
||||||
h = cache->dohash( item );
|
h = cache->dohash(item);
|
||||||
link = cache->first_hash[h];
|
link = cache->first_hash[h];
|
||||||
while ( link )
|
while (link) {
|
||||||
{
|
if (compare(link->entry, item))
|
||||||
if ( compare( link->entry, item ) )
|
|
||||||
link = link->next;
|
link = link->next;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
current = link->entry;
|
current = link->entry;
|
||||||
link = link->next;
|
link = link->next;
|
||||||
if ( current )
|
if (current) {
|
||||||
{
|
drophashindex(cache,current,h);
|
||||||
drophashindex( cache, current, h );
|
do_invalidate(cache,
|
||||||
do_invalidate( cache,
|
current,flags);
|
||||||
current, flags );
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ( flags & CACHE_NOHASH ) || !cache->dohash )
|
if ((flags & CACHE_NOHASH) || !cache->dohash) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Search sequentially in LRU list
|
* Search sequentially in LRU list
|
||||||
*/
|
*/
|
||||||
current = cache->most_recent_entry;
|
current = cache->most_recent_entry;
|
||||||
previous = ( struct CACHED_GENERIC* )NULL;
|
previous = (struct CACHED_GENERIC*)NULL;
|
||||||
while ( current )
|
while (current) {
|
||||||
{
|
if (!compare(current, item)) {
|
||||||
if ( !compare( current, item ) )
|
|
||||||
{
|
|
||||||
next = current->next;
|
next = current->next;
|
||||||
if ( cache->dohash )
|
if (cache->dohash)
|
||||||
drophashindex( cache, current,
|
drophashindex(cache,current,
|
||||||
cache->dohash( current ) );
|
cache->dohash(current));
|
||||||
do_invalidate( cache, current, flags );
|
do_invalidate(cache,current,flags);
|
||||||
current = next;
|
current = next;
|
||||||
count++;
|
count++;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
previous = current;
|
previous = current;
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ( count );
|
return (count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ntfs_remove_cache( struct CACHE_HEADER *cache,
|
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||||
struct CACHED_GENERIC *item, int flags )
|
struct CACHED_GENERIC *item, int flags)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
if (cache->dohash)
|
||||||
if ( cache->dohash )
|
drophashindex(cache,item,cache->dohash(item));
|
||||||
drophashindex( cache, item, cache->dohash( item ) );
|
do_invalidate(cache,item,flags);
|
||||||
do_invalidate( cache, item, flags );
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return ( count );
|
return (count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory allocated to a cache
|
* Free memory allocated to a cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void ntfs_free_cache( struct CACHE_HEADER *cache )
|
static void ntfs_free_cache(struct CACHE_HEADER *cache)
|
||||||
{
|
{
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
|
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
|
||||||
for ( entry = cache->most_recent_entry; entry; entry = entry->next )
|
if (cache->dofree)
|
||||||
{
|
cache->dofree(entry);
|
||||||
if ( cache->dofree )
|
if (entry->variable)
|
||||||
cache->dofree( entry );
|
free(entry->variable);
|
||||||
if ( entry->variable )
|
|
||||||
free( entry->variable );
|
|
||||||
}
|
}
|
||||||
free( cache );
|
free(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,10 +472,10 @@ static void ntfs_free_cache( struct CACHE_HEADER *cache )
|
|||||||
* Returns the cache header, or NULL if the cache could not be created
|
* Returns the cache header, or NULL if the cache could not be created
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct CACHE_HEADER *ntfs_create_cache( const char *name,
|
static struct CACHE_HEADER *ntfs_create_cache(const char *name,
|
||||||
cache_free dofree, cache_hash dohash,
|
cache_free dofree, cache_hash dohash,
|
||||||
int full_item_size,
|
int full_item_size,
|
||||||
int item_count, int max_hash )
|
int item_count, int max_hash)
|
||||||
{
|
{
|
||||||
struct CACHE_HEADER *cache;
|
struct CACHE_HEADER *cache;
|
||||||
struct CACHED_GENERIC *pc;
|
struct CACHED_GENERIC *pc;
|
||||||
@ -540,78 +486,68 @@ static struct CACHE_HEADER *ntfs_create_cache( const char *name,
|
|||||||
size_t size;
|
size_t size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
size = sizeof( struct CACHE_HEADER ) + item_count*full_item_size;
|
size = sizeof(struct CACHE_HEADER) + item_count*full_item_size;
|
||||||
if ( max_hash )
|
if (max_hash)
|
||||||
size += item_count*sizeof( struct HASH_ENTRY )
|
size += item_count*sizeof(struct HASH_ENTRY)
|
||||||
+ max_hash*sizeof( struct HASH_ENTRY* );
|
+ max_hash*sizeof(struct HASH_ENTRY*);
|
||||||
cache = ( struct CACHE_HEADER* )ntfs_malloc( size );
|
cache = (struct CACHE_HEADER*)ntfs_malloc(size);
|
||||||
if ( cache )
|
if (cache) {
|
||||||
{
|
|
||||||
/* header */
|
/* header */
|
||||||
cache->name = name;
|
cache->name = name;
|
||||||
cache->dofree = dofree;
|
cache->dofree = dofree;
|
||||||
if ( dohash && max_hash )
|
if (dohash && max_hash) {
|
||||||
{
|
|
||||||
cache->dohash = dohash;
|
cache->dohash = dohash;
|
||||||
cache->max_hash = max_hash;
|
cache->max_hash = max_hash;
|
||||||
}
|
} else {
|
||||||
else
|
cache->dohash = (cache_hash)NULL;
|
||||||
{
|
|
||||||
cache->dohash = ( cache_hash )NULL;
|
|
||||||
cache->max_hash = 0;
|
cache->max_hash = 0;
|
||||||
}
|
}
|
||||||
cache->fixed_size = full_item_size - sizeof( struct CACHED_GENERIC );
|
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
|
||||||
cache->reads = 0;
|
cache->reads = 0;
|
||||||
cache->writes = 0;
|
cache->writes = 0;
|
||||||
cache->hits = 0;
|
cache->hits = 0;
|
||||||
/* chain the data entries, and mark an invalid entry */
|
/* chain the data entries, and mark an invalid entry */
|
||||||
cache->most_recent_entry = ( struct CACHED_GENERIC* )NULL;
|
cache->most_recent_entry = (struct CACHED_GENERIC*)NULL;
|
||||||
cache->oldest_entry = ( struct CACHED_GENERIC* )NULL;
|
cache->oldest_entry = (struct CACHED_GENERIC*)NULL;
|
||||||
cache->free_entry = &cache->entry[0];
|
cache->free_entry = &cache->entry[0];
|
||||||
pc = &cache->entry[0];
|
pc = &cache->entry[0];
|
||||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
for (i=0; i<(item_count - 1); i++) {
|
||||||
{
|
qc = (struct CACHED_GENERIC*)((char*)pc
|
||||||
qc = ( struct CACHED_GENERIC* )( ( char* )pc
|
+ full_item_size);
|
||||||
+ full_item_size );
|
|
||||||
pc->next = qc;
|
pc->next = qc;
|
||||||
pc->variable = ( void* )NULL;
|
pc->variable = (void*)NULL;
|
||||||
pc->varsize = 0;
|
pc->varsize = 0;
|
||||||
pc = qc;
|
pc = qc;
|
||||||
}
|
}
|
||||||
/* special for the last entry */
|
/* special for the last entry */
|
||||||
pc->next = ( struct CACHED_GENERIC* )NULL;
|
pc->next = (struct CACHED_GENERIC*)NULL;
|
||||||
pc->variable = ( void* )NULL;
|
pc->variable = (void*)NULL;
|
||||||
pc->varsize = 0;
|
pc->varsize = 0;
|
||||||
|
|
||||||
if ( max_hash )
|
if (max_hash) {
|
||||||
{
|
|
||||||
/* chain the hash entries */
|
/* chain the hash entries */
|
||||||
ph = ( struct HASH_ENTRY* )( ( ( char* )pc ) + full_item_size );
|
ph = (struct HASH_ENTRY*)(((char*)pc) + full_item_size);
|
||||||
cache->free_hash = ph;
|
cache->free_hash = ph;
|
||||||
for ( i = 0; i < ( item_count - 1 ); i++ )
|
for (i=0; i<(item_count - 1); i++) {
|
||||||
{
|
|
||||||
qh = &ph[1];
|
qh = &ph[1];
|
||||||
ph->next = qh;
|
ph->next = qh;
|
||||||
ph = qh;
|
ph = qh;
|
||||||
}
|
}
|
||||||
/* special for the last entry */
|
/* special for the last entry */
|
||||||
if ( item_count )
|
if (item_count) {
|
||||||
{
|
ph->next = (struct HASH_ENTRY*)NULL;
|
||||||
ph->next = ( struct HASH_ENTRY* )NULL;
|
|
||||||
}
|
}
|
||||||
/* create and initialize the hash indexes */
|
/* create and initialize the hash indexes */
|
||||||
px = ( struct HASH_ENTRY** ) & ph[1];
|
px = (struct HASH_ENTRY**)&ph[1];
|
||||||
cache->first_hash = px;
|
cache->first_hash = px;
|
||||||
for ( i = 0; i < max_hash; i++ )
|
for (i=0; i<max_hash; i++)
|
||||||
px[i] = ( struct HASH_ENTRY* )NULL;
|
px[i] = (struct HASH_ENTRY*)NULL;
|
||||||
}
|
} else {
|
||||||
else
|
cache->free_hash = (struct HASH_ENTRY*)NULL;
|
||||||
{
|
cache->first_hash = (struct HASH_ENTRY**)NULL;
|
||||||
cache->free_hash = ( struct HASH_ENTRY* )NULL;
|
|
||||||
cache->first_hash = ( struct HASH_ENTRY** )NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ( cache );
|
return (cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -621,33 +557,33 @@ static struct CACHE_HEADER *ntfs_create_cache( const char *name,
|
|||||||
* just be not available
|
* just be not available
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ntfs_create_lru_caches( ntfs_volume *vol )
|
void ntfs_create_lru_caches(ntfs_volume *vol)
|
||||||
{
|
{
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
/* inode cache */
|
/* inode cache */
|
||||||
vol->xinode_cache = ntfs_create_cache( "inode", ( cache_free )NULL,
|
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
|
||||||
ntfs_dir_inode_hash, sizeof( struct CACHED_INODE ),
|
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
|
||||||
CACHE_INODE_SIZE, 2 * CACHE_INODE_SIZE );
|
CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
#if CACHE_NIDATA_SIZE
|
#if CACHE_NIDATA_SIZE
|
||||||
/* idata cache */
|
/* idata cache */
|
||||||
vol->nidata_cache = ntfs_create_cache( "nidata",
|
vol->nidata_cache = ntfs_create_cache("nidata",
|
||||||
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
|
||||||
sizeof( struct CACHED_NIDATA ),
|
sizeof(struct CACHED_NIDATA),
|
||||||
CACHE_NIDATA_SIZE, 2 * CACHE_NIDATA_SIZE );
|
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
|
||||||
#endif
|
#endif
|
||||||
#if CACHE_LOOKUP_SIZE
|
#if CACHE_LOOKUP_SIZE
|
||||||
/* lookup cache */
|
/* lookup cache */
|
||||||
vol->lookup_cache = ntfs_create_cache( "lookup",
|
vol->lookup_cache = ntfs_create_cache("lookup",
|
||||||
( cache_free )NULL, ntfs_dir_lookup_hash,
|
(cache_free)NULL, ntfs_dir_lookup_hash,
|
||||||
sizeof( struct CACHED_LOOKUP ),
|
sizeof(struct CACHED_LOOKUP),
|
||||||
CACHE_LOOKUP_SIZE, 2 * CACHE_LOOKUP_SIZE );
|
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
|
||||||
#endif
|
#endif
|
||||||
vol->securid_cache = ntfs_create_cache( "securid", ( cache_free )NULL,
|
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
|
||||||
( cache_hash )NULL, sizeof( struct CACHED_SECURID ), CACHE_SECURID_SIZE, 0 );
|
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
|
||||||
#if CACHE_LEGACY_SIZE
|
#if CACHE_LEGACY_SIZE
|
||||||
vol->legacy_cache = ntfs_create_cache( "legacy", ( cache_free )NULL,
|
vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL,
|
||||||
( cache_hash )NULL, sizeof( struct CACHED_PERMISSIONS_LEGACY ), CACHE_LEGACY_SIZE, 0 );
|
(cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,19 +591,19 @@ void ntfs_create_lru_caches( ntfs_volume *vol )
|
|||||||
* Free all LRU caches
|
* Free all LRU caches
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ntfs_free_lru_caches( ntfs_volume *vol )
|
void ntfs_free_lru_caches(ntfs_volume *vol)
|
||||||
{
|
{
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
ntfs_free_cache( vol->xinode_cache );
|
ntfs_free_cache(vol->xinode_cache);
|
||||||
#endif
|
#endif
|
||||||
#if CACHE_NIDATA_SIZE
|
#if CACHE_NIDATA_SIZE
|
||||||
ntfs_free_cache( vol->nidata_cache );
|
ntfs_free_cache(vol->nidata_cache);
|
||||||
#endif
|
#endif
|
||||||
#if CACHE_LOOKUP_SIZE
|
#if CACHE_LOOKUP_SIZE
|
||||||
ntfs_free_cache( vol->lookup_cache );
|
ntfs_free_cache(vol->lookup_cache);
|
||||||
#endif
|
#endif
|
||||||
ntfs_free_cache( vol->securid_cache );
|
ntfs_free_cache(vol->securid_cache);
|
||||||
#if CACHE_LEGACY_SIZE
|
#if CACHE_LEGACY_SIZE
|
||||||
ntfs_free_cache( vol->legacy_cache );
|
ntfs_free_cache(vol->legacy_cache);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,19 @@
|
|||||||
|
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
|
||||||
struct CACHED_GENERIC
|
struct CACHED_GENERIC {
|
||||||
{
|
|
||||||
struct CACHED_GENERIC *next;
|
struct CACHED_GENERIC *next;
|
||||||
struct CACHED_GENERIC *previous;
|
struct CACHED_GENERIC *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
size_t varsize;
|
size_t varsize;
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
/* force alignment for pointers and u64 */
|
/* force alignment for pointers and u64 */
|
||||||
u64 u64align;
|
u64 u64align;
|
||||||
void *ptralign;
|
void *ptralign;
|
||||||
} fixed[0];
|
} fixed[0];
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_INODE
|
struct CACHED_INODE {
|
||||||
{
|
|
||||||
struct CACHED_INODE *next;
|
struct CACHED_INODE *next;
|
||||||
struct CACHED_INODE *previous;
|
struct CACHED_INODE *previous;
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
@ -48,8 +45,7 @@ struct CACHED_INODE
|
|||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_NIDATA
|
struct CACHED_NIDATA {
|
||||||
{
|
|
||||||
struct CACHED_NIDATA *next;
|
struct CACHED_NIDATA *next;
|
||||||
struct CACHED_NIDATA *previous;
|
struct CACHED_NIDATA *previous;
|
||||||
const char *pathname; /* not used */
|
const char *pathname; /* not used */
|
||||||
@ -59,8 +55,7 @@ struct CACHED_NIDATA
|
|||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHED_LOOKUP
|
struct CACHED_LOOKUP {
|
||||||
{
|
|
||||||
struct CACHED_LOOKUP *next;
|
struct CACHED_LOOKUP *next;
|
||||||
struct CACHED_LOOKUP *previous;
|
struct CACHED_LOOKUP *previous;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -70,25 +65,22 @@ struct CACHED_LOOKUP
|
|||||||
u64 inum;
|
u64 inum;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
CACHE_FREE = 1,
|
CACHE_FREE = 1,
|
||||||
CACHE_NOHASH = 2
|
CACHE_NOHASH = 2
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef int ( *cache_compare )( const struct CACHED_GENERIC *cached,
|
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
|
||||||
const struct CACHED_GENERIC *item );
|
const struct CACHED_GENERIC *item);
|
||||||
typedef void ( *cache_free )( const struct CACHED_GENERIC *cached );
|
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
|
||||||
typedef int ( *cache_hash )( const struct CACHED_GENERIC *cached );
|
typedef int (*cache_hash)(const struct CACHED_GENERIC *cached);
|
||||||
|
|
||||||
struct HASH_ENTRY
|
struct HASH_ENTRY {
|
||||||
{
|
|
||||||
struct HASH_ENTRY *next;
|
struct HASH_ENTRY *next;
|
||||||
struct CACHED_GENERIC *entry;
|
struct CACHED_GENERIC *entry;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct CACHE_HEADER
|
struct CACHE_HEADER {
|
||||||
{
|
|
||||||
const char *name;
|
const char *name;
|
||||||
struct CACHED_GENERIC *most_recent_entry;
|
struct CACHED_GENERIC *most_recent_entry;
|
||||||
struct CACHED_GENERIC *oldest_entry;
|
struct CACHED_GENERIC *oldest_entry;
|
||||||
@ -105,23 +97,23 @@ struct CACHE_HEADER
|
|||||||
struct CACHED_GENERIC entry[0];
|
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))
|
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
|
||||||
|
|
||||||
struct CACHED_GENERIC *ntfs_fetch_cache( struct CACHE_HEADER *cache,
|
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *wanted,
|
const struct CACHED_GENERIC *wanted,
|
||||||
cache_compare compare );
|
cache_compare compare);
|
||||||
struct CACHED_GENERIC *ntfs_enter_cache( struct CACHE_HEADER *cache,
|
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *item,
|
const struct CACHED_GENERIC *item,
|
||||||
cache_compare compare );
|
cache_compare compare);
|
||||||
int ntfs_invalidate_cache( struct CACHE_HEADER *cache,
|
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
|
||||||
const struct CACHED_GENERIC *item,
|
const struct CACHED_GENERIC *item,
|
||||||
cache_compare compare, int flags );
|
cache_compare compare, int flags);
|
||||||
int ntfs_remove_cache( struct CACHE_HEADER *cache,
|
int ntfs_remove_cache(struct CACHE_HEADER *cache,
|
||||||
struct CACHED_GENERIC *item, int flags );
|
struct CACHED_GENERIC *item, int flags);
|
||||||
|
|
||||||
void ntfs_create_lru_caches( ntfs_volume *vol );
|
void ntfs_create_lru_caches(ntfs_volume *vol);
|
||||||
void ntfs_free_lru_caches( ntfs_volume *vol );
|
void ntfs_free_lru_caches(ntfs_volume *vol);
|
||||||
|
|
||||||
#endif /* _NTFS_CACHE_H_ */
|
#endif /* _NTFS_CACHE_H_ */
|
||||||
|
|
||||||
|
@ -45,27 +45,23 @@
|
|||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#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* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, sec_t sectorSize) {
|
||||||
{
|
|
||||||
NTFS_CACHE* cache;
|
NTFS_CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries;
|
||||||
|
|
||||||
if ( numberOfPages == 0 || sectorsPerPage == 0 ) return NULL;
|
if(numberOfPages==0 || sectorsPerPage==0) return NULL;
|
||||||
|
|
||||||
if ( numberOfPages < 4 )
|
if (numberOfPages < 4) {
|
||||||
{
|
|
||||||
numberOfPages = 4;
|
numberOfPages = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sectorsPerPage < 32 )
|
if (sectorsPerPage < 32) {
|
||||||
{
|
|
||||||
sectorsPerPage = 32;
|
sectorsPerPage = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = ( NTFS_CACHE* ) ntfs_alloc ( sizeof( NTFS_CACHE ) );
|
cache = (NTFS_CACHE*) ntfs_alloc (sizeof(NTFS_CACHE));
|
||||||
if ( cache == NULL )
|
if (cache == NULL) {
|
||||||
{
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,20 +72,18 @@ NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int s
|
|||||||
cache->sectorSize = sectorSize;
|
cache->sectorSize = sectorSize;
|
||||||
|
|
||||||
|
|
||||||
cacheEntries = ( NTFS_CACHE_ENTRY* ) ntfs_alloc ( sizeof( NTFS_CACHE_ENTRY ) * numberOfPages );
|
cacheEntries = (NTFS_CACHE_ENTRY*) ntfs_alloc ( sizeof(NTFS_CACHE_ENTRY) * numberOfPages);
|
||||||
if ( cacheEntries == NULL )
|
if (cacheEntries == NULL) {
|
||||||
{
|
ntfs_free (cache);
|
||||||
ntfs_free ( cache );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for (i = 0; i < numberOfPages; i++) {
|
||||||
{
|
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
cacheEntries[i].last_access = 0;
|
cacheEntries[i].last_access = 0;
|
||||||
cacheEntries[i].dirty = false;
|
cacheEntries[i].dirty = false;
|
||||||
cacheEntries[i].cache = ( uint8_t* ) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
cacheEntries[i].cache = (uint8_t*) ntfs_align ( sectorsPerPage * cache->sectorSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->cacheEntries = cacheEntries;
|
cache->cacheEntries = cacheEntries;
|
||||||
@ -97,33 +91,30 @@ NTFS_CACHE* _NTFS_cache_constructor ( unsigned int numberOfPages, unsigned int s
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_destructor ( NTFS_CACHE* cache )
|
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||||
{
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if ( cache == NULL ) return;
|
if(cache==NULL) return;
|
||||||
|
|
||||||
// Clear out cache before destroying it
|
// Clear out cache before destroying it
|
||||||
_NTFS_cache_flush( cache );
|
_NTFS_cache_flush(cache);
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
{
|
ntfs_free (cache->cacheEntries[i].cache);
|
||||||
ntfs_free ( cache->cacheEntries[i].cache );
|
|
||||||
}
|
}
|
||||||
ntfs_free ( cache->cacheEntries );
|
ntfs_free (cache->cacheEntries);
|
||||||
ntfs_free ( cache );
|
ntfs_free (cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 accessCounter = 0;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
static u32 accessTime()
|
static u32 accessTime(){
|
||||||
{
|
|
||||||
accessCounter++;
|
accessCounter++;
|
||||||
return 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;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -134,42 +125,37 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage( NTFS_CACHE *cache, sec_t sector )
|
|||||||
unsigned int oldUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int oldAccess = UINT_MAX;
|
unsigned int oldAccess = UINT_MAX;
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for(i=0;i<numberOfPages;i++) {
|
||||||
{
|
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count)) {
|
||||||
if ( sector >= cacheEntries[i].sector && sector < ( cacheEntries[i].sector + cacheEntries[i].count ) )
|
|
||||||
{
|
|
||||||
cacheEntries[i].last_access = accessTime();
|
cacheEntries[i].last_access = accessTime();
|
||||||
return &( cacheEntries[i] );
|
return &(cacheEntries[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( foundFree == false && ( cacheEntries[i].sector == CACHE_FREE || cacheEntries[i].last_access < oldAccess ) )
|
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||||
{
|
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||||
if ( cacheEntries[i].sector == CACHE_FREE ) foundFree = true;
|
|
||||||
oldUsed = i;
|
oldUsed = i;
|
||||||
oldAccess = cacheEntries[i].last_access;
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( foundFree == false && cacheEntries[oldUsed].dirty == true )
|
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||||
{
|
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||||
if ( !cache->disc->writeSectors( cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache ) ) return NULL;
|
|
||||||
cacheEntries[oldUsed].dirty = false;
|
cacheEntries[oldUsed].dirty = false;
|
||||||
}
|
}
|
||||||
sector = ( sector / sectorsPerPage ) * sectorsPerPage; // align base sector to page size
|
sector = (sector/sectorsPerPage)*sectorsPerPage; // align base sector to page size
|
||||||
sec_t next_page = sector + sectorsPerPage;
|
sec_t next_page = sector + sectorsPerPage;
|
||||||
if ( next_page > cache->endOfPartition ) next_page = cache->endOfPartition;
|
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].sector = sector;
|
||||||
cacheEntries[oldUsed].count = next_page - sector;
|
cacheEntries[oldUsed].count = next_page-sector;
|
||||||
cacheEntries[oldUsed].last_access = accessTime();
|
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;
|
unsigned int i;
|
||||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
@ -177,22 +163,16 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector,
|
|||||||
NTFS_CACHE_ENTRY *entry = NULL;
|
NTFS_CACHE_ENTRY *entry = NULL;
|
||||||
sec_t lowest = UINT_MAX;
|
sec_t lowest = UINT_MAX;
|
||||||
|
|
||||||
for ( i = 0; i < numberOfPages; i++ )
|
for(i=0;i<numberOfPages;i++) {
|
||||||
{
|
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||||
if ( cacheEntries[i].sector != CACHE_FREE )
|
|
||||||
{
|
|
||||||
bool intersect;
|
bool intersect;
|
||||||
if ( sector > cacheEntries[i].sector )
|
if (sector > cacheEntries[i].sector) {
|
||||||
{
|
|
||||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
intersect = cacheEntries[i].sector - sector < count;
|
intersect = cacheEntries[i].sector - sector < count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( intersect && ( cacheEntries[i].sector < lowest ) )
|
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||||
{
|
|
||||||
lowest = cacheEntries[i].sector;
|
lowest = cacheEntries[i].sector;
|
||||||
entry = &cacheEntries[i];
|
entry = &cacheEntries[i];
|
||||||
}
|
}
|
||||||
@ -202,25 +182,24 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_findPage( NTFS_CACHE *cache, sec_t sector,
|
|||||||
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 sec;
|
||||||
sec_t secs_to_read;
|
sec_t secs_to_read;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
uint8_t *dest = buffer;
|
uint8_t *dest = buffer;
|
||||||
|
|
||||||
while ( numSectors > 0 )
|
while(numSectors>0) {
|
||||||
{
|
entry = _NTFS_cache_getPage(cache,sector);
|
||||||
entry = _NTFS_cache_getPage( cache, sector );
|
if(entry==NULL) return false;
|
||||||
if ( entry == NULL ) return false;
|
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
secs_to_read = entry->count - sec;
|
secs_to_read = entry->count - sec;
|
||||||
if ( secs_to_read > numSectors ) secs_to_read = numSectors;
|
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 );
|
dest += (secs_to_read*cache->sectorSize);
|
||||||
sector += secs_to_read;
|
sector += secs_to_read;
|
||||||
numSectors -= secs_to_read;
|
numSectors -= secs_to_read;
|
||||||
}
|
}
|
||||||
@ -232,32 +211,30 @@ bool _NTFS_cache_readSectors( NTFS_CACHE *cache, sec_t sector, sec_t numSectors,
|
|||||||
Reads some data from a cache page, determined by the sector number
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if ( offset + size > cache->sectorSize ) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage( cache, sector );
|
entry = _NTFS_cache_getPage(cache,sector);
|
||||||
if ( entry == NULL ) return false;
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memcpy( buffer, entry->cache + ( ( sec*cache->sectorSize ) + offset ), size );
|
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 )
|
bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||||
{
|
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
if ( !_NTFS_cache_readPartialSector( cache, buf, sector, offset, num_bytes ) ) return false;
|
if (!_NTFS_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||||
|
|
||||||
switch ( num_bytes )
|
switch(num_bytes) {
|
||||||
{
|
|
||||||
case 1: *value = buf[0]; break;
|
case 1: *value = buf[0]; break;
|
||||||
case 2: *value = u8array_to_u16( buf, 0 ); break;
|
case 2: *value = u8array_to_u16(buf,0); break;
|
||||||
case 4: *value = u8array_to_u32( buf, 0 ); break;
|
case 4: *value = u8array_to_u32(buf,0); break;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -267,81 +244,77 @@ bool _NTFS_cache_readLittleEndianValue ( NTFS_CACHE* cache, uint32_t *value, sec
|
|||||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if ( offset + size > cache->sectorSize ) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage( cache, sector );
|
entry = _NTFS_cache_getPage(cache,sector);
|
||||||
if ( entry == NULL ) return false;
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _NTFS_cache_writeLittleEndianValue ( NTFS_CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size )
|
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};
|
uint8_t buf[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
switch ( size )
|
switch(size) {
|
||||||
{
|
|
||||||
case 1: buf[0] = value; break;
|
case 1: buf[0] = value; break;
|
||||||
case 2: u16_to_u8array( buf, 0, value ); break;
|
case 2: u16_to_u8array(buf, 0, value); break;
|
||||||
case 4: u32_to_u8array( buf, 0, value ); break;
|
case 4: u32_to_u8array(buf, 0, value); break;
|
||||||
default: return false;
|
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
|
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;
|
sec_t sec;
|
||||||
NTFS_CACHE_ENTRY *entry;
|
NTFS_CACHE_ENTRY *entry;
|
||||||
|
|
||||||
if ( offset + size > cache->sectorSize ) return false;
|
if (offset + size > cache->sectorSize) return false;
|
||||||
|
|
||||||
entry = _NTFS_cache_getPage( cache, sector );
|
entry = _NTFS_cache_getPage(cache,sector);
|
||||||
if ( entry == NULL ) return false;
|
if(entry==NULL) return false;
|
||||||
|
|
||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
memset( entry->cache + ( sec*cache->sectorSize ), 0, cache->sectorSize );
|
memset(entry->cache + (sec*cache->sectorSize),0,cache->sectorSize);
|
||||||
memcpy( entry->cache + ( ( sec*cache->sectorSize ) + offset ), buffer, size );
|
memcpy(entry->cache + ((sec*cache->sectorSize) + offset),buffer,size);
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
return 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 sec;
|
||||||
sec_t secs_to_write;
|
sec_t secs_to_write;
|
||||||
NTFS_CACHE_ENTRY* entry;
|
NTFS_CACHE_ENTRY* entry;
|
||||||
const uint8_t *src = buffer;
|
const uint8_t *src = buffer;
|
||||||
|
|
||||||
while ( numSectors > 0 )
|
while(numSectors>0)
|
||||||
{
|
{
|
||||||
entry = _NTFS_cache_findPage( cache, sector, numSectors );
|
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 );
|
cache->disc->writeSectors(sector,secs_to_write,src);
|
||||||
src += ( secs_to_write * cache->sectorSize );
|
src += (secs_to_write*cache->sectorSize);
|
||||||
sector += secs_to_write;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
}
|
}
|
||||||
@ -349,21 +322,19 @@ bool _NTFS_cache_writeSectors ( NTFS_CACHE* cache, sec_t sector, sec_t numSector
|
|||||||
sec = sector - entry->sector;
|
sec = sector - entry->sector;
|
||||||
secs_to_write = entry->count - sec;
|
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 );
|
src += (secs_to_write*cache->sectorSize);
|
||||||
sector += secs_to_write;
|
sector += secs_to_write;
|
||||||
numSectors -= secs_to_write;
|
numSectors -= secs_to_write;
|
||||||
|
|
||||||
entry->dirty = true;
|
entry->dirty = true;
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else
|
cache->disc->writeSectors(sector,numSectors,src);
|
||||||
{
|
numSectors=0;
|
||||||
cache->disc->writeSectors( sector, numSectors, src );
|
|
||||||
numSectors = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -372,17 +343,13 @@ bool _NTFS_cache_writeSectors ( NTFS_CACHE* cache, sec_t sector, sec_t numSector
|
|||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||||
*/
|
*/
|
||||||
bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||||
{
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if ( cache == NULL ) return true;
|
if(cache==NULL) return true;
|
||||||
|
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
{
|
if (cache->cacheEntries[i].dirty) {
|
||||||
if ( cache->cacheEntries[i].dirty )
|
if (!cache->disc->writeSectors (cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||||
{
|
|
||||||
if ( !cache->disc->writeSectors ( cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache ) )
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,15 +359,13 @@ bool _NTFS_cache_flush ( NTFS_CACHE* cache )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _NTFS_cache_invalidate ( NTFS_CACHE* cache )
|
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||||
{
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
if ( cache == NULL )
|
if(cache==NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_NTFS_cache_flush( cache );
|
_NTFS_cache_flush(cache);
|
||||||
for ( i = 0; i < cache->numberOfPages; i++ )
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
{
|
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
cache->cacheEntries[i].last_access = 0;
|
cache->cacheEntries[i].last_access = 0;
|
||||||
cache->cacheEntries[i].count = 0;
|
cache->cacheEntries[i].count = 0;
|
||||||
|
@ -46,8 +46,7 @@
|
|||||||
#include <ogc/disc_io.h>
|
#include <ogc/disc_io.h>
|
||||||
#include <gccore.h>
|
#include <gccore.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
u64 last_access;
|
u64 last_access;
|
||||||
@ -55,8 +54,7 @@ typedef struct
|
|||||||
u8* cache;
|
u8* cache;
|
||||||
} NTFS_CACHE_ENTRY;
|
} NTFS_CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
sec_t endOfPartition;
|
sec_t endOfPartition;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
@ -101,7 +99,7 @@ Precondition: offset + size <= BYTES_PER_READ
|
|||||||
/*
|
/*
|
||||||
Read several sectors from the NTFS_CACHE
|
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
|
Read a full sector from the NTFS_CACHE
|
||||||
@ -117,21 +115,21 @@ Write a full sector to the NTFS_CACHE
|
|||||||
// 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
|
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
|
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
|
#endif // _CACHE_H
|
||||||
|
|
||||||
|
@ -52,22 +52,21 @@
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
static int ntfs_collate_binary( ntfs_volume *vol __attribute__( ( unused ) ),
|
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||||
const void *data1, const int data1_len,
|
const void *data1, const int data1_len,
|
||||||
const void *data2, const int data2_len )
|
const void *data2, const int data2_len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
rc = memcmp( data1, data2, min( data1_len, data2_len ) );
|
rc = memcmp(data1, data2, min(data1_len, data2_len));
|
||||||
if ( !rc && ( data1_len != data2_len ) )
|
if (!rc && (data1_len != data2_len)) {
|
||||||
{
|
if (data1_len < data2_len)
|
||||||
if ( data1_len < data2_len )
|
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,31 +82,29 @@ static int ntfs_collate_binary( ntfs_volume *vol __attribute__( ( unused ) ),
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
static int ntfs_collate_ntofs_ulong( ntfs_volume *vol __attribute__( ( unused ) ),
|
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||||
const void *data1, const int data1_len,
|
const void *data1, const int data1_len,
|
||||||
const void *data2, const int data2_len )
|
const void *data2, const int data2_len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
if ( data1_len != data2_len || data1_len != 4 )
|
if (data1_len != data2_len || data1_len != 4) {
|
||||||
{
|
ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
|
||||||
ntfs_log_error( "data1_len or/and data2_len not equal to 4.\n" );
|
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
d1 = le32_to_cpup( data1 );
|
d1 = le32_to_cpup(data1);
|
||||||
d2 = le32_to_cpup( data2 );
|
d2 = le32_to_cpup(data2);
|
||||||
if ( d1 < d2 )
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else {
|
||||||
{
|
if (d1 == d2)
|
||||||
if ( d1 == d2 )
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,42 +114,38 @@ static int ntfs_collate_ntofs_ulong( ntfs_volume *vol __attribute__( ( unused )
|
|||||||
* Returns: -1, 0 or 1 depending of how the arrays compare
|
* Returns: -1, 0 or 1 depending of how the arrays compare
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int ntfs_collate_ntofs_ulongs( ntfs_volume *vol __attribute__( ( unused ) ),
|
static int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
|
||||||
const void *data1, const int data1_len,
|
const void *data1, const int data1_len,
|
||||||
const void *data2, const int data2_len )
|
const void *data2, const int data2_len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int len;
|
int len;
|
||||||
const le32 *p1, *p2;
|
const le32 *p1, *p2;
|
||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
if ( ( data1_len != data2_len ) || ( data1_len <= 0 ) || ( data1_len & 3 ) )
|
if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
|
||||||
{
|
ntfs_log_error("data1_len or data2_len not valid\n");
|
||||||
ntfs_log_error( "data1_len or data2_len not valid\n" );
|
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
p1 = ( const le32* )data1;
|
p1 = (const le32*)data1;
|
||||||
p2 = ( const le32* )data2;
|
p2 = (const le32*)data2;
|
||||||
len = data1_len;
|
len = data1_len;
|
||||||
do
|
do {
|
||||||
{
|
d1 = le32_to_cpup(p1);
|
||||||
d1 = le32_to_cpup( p1 );
|
|
||||||
p1++;
|
p1++;
|
||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup(p2);
|
||||||
p2++;
|
p2++;
|
||||||
}
|
} while ((d1 == d2) && ((len -= 4) > 0));
|
||||||
while ( ( d1 == d2 ) && ( ( len -= 4 ) > 0 ) );
|
if (d1 < d2)
|
||||||
if ( d1 < d2 )
|
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else {
|
||||||
{
|
if (d1 == d2)
|
||||||
if ( d1 == d2 )
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else
|
else
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,48 +162,44 @@ static int ntfs_collate_ntofs_ulongs( ntfs_volume *vol __attribute__( ( unused )
|
|||||||
*
|
*
|
||||||
* Returns: -1, 0 or 1 depending of how the keys compare
|
* Returns: -1, 0 or 1 depending of how the keys compare
|
||||||
*/
|
*/
|
||||||
static int ntfs_collate_ntofs_security_hash( ntfs_volume *vol __attribute__( ( unused ) ),
|
static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)),
|
||||||
const void *data1, const int data1_len,
|
const void *data1, const int data1_len,
|
||||||
const void *data2, const int data2_len )
|
const void *data2, const int data2_len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 d1, d2;
|
u32 d1, d2;
|
||||||
const le32 *p1, *p2;
|
const le32 *p1, *p2;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
if ( data1_len != data2_len || data1_len != 8 )
|
if (data1_len != data2_len || data1_len != 8) {
|
||||||
{
|
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
|
||||||
ntfs_log_error( "data1_len or/and data2_len not equal to 8.\n" );
|
|
||||||
return NTFS_COLLATION_ERROR;
|
return NTFS_COLLATION_ERROR;
|
||||||
}
|
}
|
||||||
p1 = ( const le32* )data1;
|
p1 = (const le32*)data1;
|
||||||
p2 = ( const le32* )data2;
|
p2 = (const le32*)data2;
|
||||||
d1 = le32_to_cpup( p1 );
|
d1 = le32_to_cpup(p1);
|
||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup(p2);
|
||||||
if ( d1 < d2 )
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else {
|
||||||
{
|
if (d1 > d2)
|
||||||
if ( d1 > d2 )
|
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
p1++;
|
p1++;
|
||||||
p2++;
|
p2++;
|
||||||
d1 = le32_to_cpup( p1 );
|
d1 = le32_to_cpup(p1);
|
||||||
d2 = le32_to_cpup( p2 );
|
d2 = le32_to_cpup(p2);
|
||||||
if ( d1 < d2 )
|
if (d1 < d2)
|
||||||
rc = -1;
|
rc = -1;
|
||||||
else
|
else {
|
||||||
{
|
if (d1 > d2)
|
||||||
if ( d1 > d2 )
|
|
||||||
rc = 1;
|
rc = 1;
|
||||||
else
|
else
|
||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,24 +215,24 @@ static int ntfs_collate_ntofs_security_hash( ntfs_volume *vol __attribute__( ( u
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
static int ntfs_collate_file_name( ntfs_volume *vol,
|
static int ntfs_collate_file_name(ntfs_volume *vol,
|
||||||
const void *data1, const int data1_len __attribute__( ( unused ) ),
|
const void *data1, const int data1_len __attribute__((unused)),
|
||||||
const void *data2, const int data2_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_attr1;
|
||||||
const FILE_NAME_ATTR *file_name_attr2;
|
const FILE_NAME_ATTR *file_name_attr2;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
file_name_attr1 = ( const FILE_NAME_ATTR* )data1;
|
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
|
||||||
file_name_attr2 = ( const FILE_NAME_ATTR* )data2;
|
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
|
||||||
rc = ntfs_names_full_collate(
|
rc = ntfs_names_full_collate(
|
||||||
( ntfschar* ) & file_name_attr1->file_name,
|
(ntfschar*)&file_name_attr1->file_name,
|
||||||
file_name_attr1->file_name_length,
|
file_name_attr1->file_name_length,
|
||||||
( ntfschar* ) & file_name_attr2->file_name,
|
(ntfschar*)&file_name_attr2->file_name,
|
||||||
file_name_attr2->file_name_length,
|
file_name_attr2->file_name_length,
|
||||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len );
|
CASE_SENSITIVE, vol->upcase, vol->upcase_len);
|
||||||
ntfs_log_trace( "Done, returning %i.\n", rc );
|
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,12 +242,11 @@ static int ntfs_collate_file_name( ntfs_volume *vol,
|
|||||||
* 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 )
|
switch (cr) {
|
||||||
{
|
|
||||||
case COLLATION_BINARY :
|
case COLLATION_BINARY :
|
||||||
collate = ntfs_collate_binary;
|
collate = ntfs_collate_binary;
|
||||||
break;
|
break;
|
||||||
@ -276,8 +264,8 @@ COLLATE ntfs_get_collate_function( COLLATION_RULES cr )
|
|||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
collate = ( COLLATE )NULL;
|
collate = (COLLATE)NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ( collate );
|
return (collate);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,6 @@
|
|||||||
|
|
||||||
#define NTFS_COLLATION_ERROR -2
|
#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 */
|
#endif /* _NTFS_COLLATE_H */
|
||||||
|
@ -35,34 +35,29 @@
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
int ffs( int x )
|
int ffs(int x)
|
||||||
{
|
{
|
||||||
int r = 1;
|
int r = 1;
|
||||||
|
|
||||||
if ( !x )
|
if (!x)
|
||||||
return 0;
|
return 0;
|
||||||
if ( !( x & 0xffff ) )
|
if (!(x & 0xffff)) {
|
||||||
{
|
|
||||||
x >>= 16;
|
x >>= 16;
|
||||||
r += 16;
|
r += 16;
|
||||||
}
|
}
|
||||||
if ( !( x & 0xff ) )
|
if (!(x & 0xff)) {
|
||||||
{
|
|
||||||
x >>= 8;
|
x >>= 8;
|
||||||
r += 8;
|
r += 8;
|
||||||
}
|
}
|
||||||
if ( !( x & 0xf ) )
|
if (!(x & 0xf)) {
|
||||||
{
|
|
||||||
x >>= 4;
|
x >>= 4;
|
||||||
r += 4;
|
r += 4;
|
||||||
}
|
}
|
||||||
if ( !( x & 3 ) )
|
if (!(x & 3)) {
|
||||||
{
|
|
||||||
x >>= 2;
|
x >>= 2;
|
||||||
r += 2;
|
r += 2;
|
||||||
}
|
}
|
||||||
if ( !( x & 1 ) )
|
if (!(x & 1)) {
|
||||||
{
|
|
||||||
x >>= 1;
|
x >>= 1;
|
||||||
r += 1;
|
r += 1;
|
||||||
}
|
}
|
||||||
@ -125,35 +120,32 @@ static const char rcsid[] = "$Id: compat.c,v 1.1.1.1.2.1 2008-08-16 15:17:44 jpa
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int daemon( int nochdir, int noclose )
|
int daemon(int nochdir, int noclose) {
|
||||||
{
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
switch ( fork() )
|
switch (fork()) {
|
||||||
{
|
|
||||||
case -1:
|
case -1:
|
||||||
return ( -1 );
|
return (-1);
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_exit( 0 );
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( setsid() == -1 )
|
if (setsid() == -1)
|
||||||
return ( -1 );
|
return (-1);
|
||||||
|
|
||||||
if ( !nochdir )
|
if (!nochdir)
|
||||||
( void )chdir( "/" );
|
(void)chdir("/");
|
||||||
|
|
||||||
if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
|
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||||
{
|
(void)dup2(fd, 0);
|
||||||
( void )dup2( fd, 0 );
|
(void)dup2(fd, 1);
|
||||||
( void )dup2( fd, 1 );
|
(void)dup2(fd, 2);
|
||||||
( void )dup2( fd, 2 );
|
if (fd > 2)
|
||||||
if ( fd > 2 )
|
(void)close (fd);
|
||||||
( void )close ( fd );
|
|
||||||
}
|
}
|
||||||
return ( 0 );
|
return (0);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* End: src/lib/libresolv2/common/bsd/daemon.c
|
* End: src/lib/libresolv2/common/bsd/daemon.c
|
||||||
@ -226,32 +218,27 @@ 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.
|
* If *stringp is NULL, strsep returns NULL.
|
||||||
*/
|
*/
|
||||||
char *strsep( char **stringp, const char *delim )
|
char *strsep(char **stringp, const char *delim) {
|
||||||
{
|
|
||||||
char *s;
|
char *s;
|
||||||
const char *spanp;
|
const char *spanp;
|
||||||
int c, sc;
|
int c, sc;
|
||||||
char *tok;
|
char *tok;
|
||||||
|
|
||||||
if ( ( s = *stringp ) == NULL )
|
if ((s = *stringp) == NULL)
|
||||||
return ( NULL );
|
return (NULL);
|
||||||
for ( tok = s;; )
|
for (tok = s;;) {
|
||||||
{
|
|
||||||
c = *s++;
|
c = *s++;
|
||||||
spanp = delim;
|
spanp = delim;
|
||||||
do
|
do {
|
||||||
{
|
if ((sc = *spanp++) == c) {
|
||||||
if ( ( sc = *spanp++ ) == c )
|
if (c == 0)
|
||||||
{
|
|
||||||
if ( c == 0 )
|
|
||||||
s = NULL;
|
s = NULL;
|
||||||
else
|
else
|
||||||
s[-1] = 0;
|
s[-1] = 0;
|
||||||
*stringp = s;
|
*stringp = s;
|
||||||
return ( tok );
|
return (tok);
|
||||||
}
|
}
|
||||||
}
|
} while (sc != 0);
|
||||||
while ( sc != 0 );
|
|
||||||
}
|
}
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
@ -36,15 +36,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_FFS
|
#ifndef HAVE_FFS
|
||||||
extern int ffs( int i );
|
extern int ffs(int i);
|
||||||
#endif /* HAVE_FFS */
|
#endif /* HAVE_FFS */
|
||||||
|
|
||||||
#ifndef HAVE_DAEMON
|
#ifndef HAVE_DAEMON
|
||||||
extern int daemon( int nochdir, int noclose );
|
extern int daemon(int nochdir, int noclose);
|
||||||
#endif /* HAVE_DAEMON */
|
#endif /* HAVE_DAEMON */
|
||||||
|
|
||||||
#ifndef HAVE_STRSEP
|
#ifndef HAVE_STRSEP
|
||||||
extern char *strsep( char **stringp, const char *delim );
|
extern char *strsep(char **stringp, const char *delim);
|
||||||
#endif /* HAVE_STRSEP */
|
#endif /* HAVE_STRSEP */
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,16 +26,16 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "attrib.h"
|
#include "attrib.h"
|
||||||
|
|
||||||
extern s64 ntfs_compressed_attr_pread( ntfs_attr *na, s64 pos, s64 count,
|
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
||||||
void *b );
|
void *b);
|
||||||
|
|
||||||
extern s64 ntfs_compressed_pwrite( ntfs_attr *na, runlist_element *brl, s64 wpos,
|
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos,
|
||||||
s64 offs, s64 to_write, s64 rounded,
|
s64 offs, s64 to_write, s64 rounded,
|
||||||
const void *b, int compressed_part,
|
const void *b, int compressed_part,
|
||||||
VCN *update_from );
|
VCN *update_from);
|
||||||
|
|
||||||
extern int ntfs_compressed_close( ntfs_attr *na, runlist_element *brl,
|
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
|
||||||
s64 offs, VCN *update_from );
|
s64 offs, VCN *update_from);
|
||||||
|
|
||||||
#endif /* defined _NTFS_COMPRESS_H */
|
#endif /* defined _NTFS_COMPRESS_H */
|
||||||
|
|
||||||
|
@ -42,43 +42,37 @@
|
|||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*/
|
*/
|
||||||
void ntfs_debug_runlist_dump( const runlist_element *rl )
|
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||||
"LCN_unknown "
|
"LCN_unknown " };
|
||||||
};
|
|
||||||
|
|
||||||
ntfs_log_debug( "NTFS-fs DEBUG: Dumping runlist (values in hex):\n" );
|
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||||
if ( !rl )
|
if (!rl) {
|
||||||
{
|
ntfs_log_debug("Run list not present.\n");
|
||||||
ntfs_log_debug( "Run list not present.\n" );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ntfs_log_debug( "VCN LCN Run length\n" );
|
ntfs_log_debug("VCN LCN Run length\n");
|
||||||
do
|
do {
|
||||||
{
|
LCN lcn = (rl + i)->lcn;
|
||||||
LCN lcn = ( rl + i )->lcn;
|
|
||||||
|
|
||||||
if ( lcn < ( LCN )0 )
|
if (lcn < (LCN)0) {
|
||||||
{
|
|
||||||
int idx = -lcn - 1;
|
int idx = -lcn - 1;
|
||||||
|
|
||||||
if ( idx > -LCN_EINVAL - 1 )
|
if (idx > -LCN_EINVAL - 1)
|
||||||
idx = 4;
|
idx = 4;
|
||||||
ntfs_log_debug( "%-16lld %s %-16lld%s\n",
|
ntfs_log_debug("%-16lld %s %-16lld%s\n",
|
||||||
( long long )rl[i].vcn, lcn_str[idx],
|
(long long)rl[i].vcn, lcn_str[idx],
|
||||||
( long long )rl[i].length,
|
(long long)rl[i].length,
|
||||||
rl[i].length ? "" : " (runlist end)" );
|
rl[i].length ? "" : " (runlist end)");
|
||||||
}
|
} else
|
||||||
else
|
ntfs_log_debug("%-16lld %-16lld %-16lld%s\n",
|
||||||
ntfs_log_debug( "%-16lld %-16lld %-16lld%s\n",
|
(long long)rl[i].vcn, (long long)rl[i].lcn,
|
||||||
( long long )rl[i].vcn, ( long long )rl[i].lcn,
|
(long long)rl[i].length,
|
||||||
( long long )rl[i].length,
|
rl[i].length ? "" : " (runlist end)");
|
||||||
rl[i].length ? "" : " (runlist end)" );
|
} while (rl[i++].length);
|
||||||
}
|
|
||||||
while ( rl[i++].length );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,9 +31,9 @@
|
|||||||
struct _runlist_element;
|
struct _runlist_element;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
#define NTFS_BUG(msg) \
|
#define NTFS_BUG(msg) \
|
||||||
|
@ -103,24 +103,21 @@
|
|||||||
* On success return a pointer to the allocated ntfs device structure and on
|
* On success return a pointer to the allocated ntfs device structure and on
|
||||||
* error return NULL with errno set to the error code returned by ntfs_malloc().
|
* error return NULL with errno set to the error code returned by ntfs_malloc().
|
||||||
*/
|
*/
|
||||||
struct ntfs_device *ntfs_device_alloc( const char *name, const long state,
|
struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||||
struct ntfs_device_operations *dops, void *priv_data )
|
struct ntfs_device_operations *dops, void *priv_data)
|
||||||
{
|
{
|
||||||
struct ntfs_device *dev;
|
struct ntfs_device *dev;
|
||||||
|
|
||||||
if ( !name )
|
if (!name) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = ntfs_malloc( sizeof( struct ntfs_device ) );
|
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
||||||
if ( dev )
|
if (dev) {
|
||||||
{
|
if (!(dev->d_name = strdup(name))) {
|
||||||
if ( !( dev->d_name = strdup( name ) ) )
|
|
||||||
{
|
|
||||||
int eo = errno;
|
int eo = errno;
|
||||||
free( dev );
|
free(dev);
|
||||||
errno = eo;
|
errno = eo;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -142,20 +139,18 @@ struct ntfs_device *ntfs_device_alloc( const char *name, const long state,
|
|||||||
* EINVAL Invalid pointer @dev.
|
* EINVAL Invalid pointer @dev.
|
||||||
* EBUSY Device is still open. Close it before freeing it!
|
* EBUSY Device is still open. Close it before freeing it!
|
||||||
*/
|
*/
|
||||||
int ntfs_device_free( struct ntfs_device *dev )
|
int ntfs_device_free(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( NDevOpen( dev ) )
|
if (NDevOpen(dev)) {
|
||||||
{
|
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
free( dev->d_name );
|
free(dev->d_name);
|
||||||
free( dev );
|
free(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,31 +173,29 @@ int ntfs_device_free( struct ntfs_device *dev )
|
|||||||
* to the return code of either seek, read, or set to EINVAL in case of
|
* to the return code of either seek, read, or set to EINVAL in case of
|
||||||
* invalid arguments.
|
* invalid arguments.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_pread( struct ntfs_device *dev, const s64 pos, s64 count, void *b )
|
s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||||
{
|
{
|
||||||
s64 br, total;
|
s64 br, total;
|
||||||
struct ntfs_device_operations *dops;
|
struct ntfs_device_operations *dops;
|
||||||
|
|
||||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||||
|
|
||||||
if ( !b || count < 0 || pos < 0 )
|
if (!b || count < 0 || pos < 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !count )
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
for ( total = 0; count; count -= br, total += br )
|
for (total = 0; count; count -= br, total += br) {
|
||||||
{
|
br = dops->pread(dev, (char*)b + total, count, pos + total);
|
||||||
br = dops->pread( dev, ( char* )b + total, count, pos + total );
|
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
if ( br > 0 )
|
if (br > 0)
|
||||||
continue;
|
continue;
|
||||||
/* If EOF or error return number of bytes read. */
|
/* If EOF or error return number of bytes read. */
|
||||||
if ( !br || total )
|
if (!br || total)
|
||||||
return total;
|
return total;
|
||||||
/* Nothing read and error, return error status. */
|
/* Nothing read and error, return error status. */
|
||||||
return br;
|
return br;
|
||||||
@ -230,41 +223,38 @@ s64 ntfs_pread( struct ntfs_device *dev, const s64 pos, s64 count, void *b )
|
|||||||
* appropriately to the return code of either seek, write, or set
|
* appropriately to the return code of either seek, write, or set
|
||||||
* to EINVAL in case of invalid arguments.
|
* to EINVAL in case of invalid arguments.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const void *b )
|
const void *b)
|
||||||
{
|
{
|
||||||
s64 written, total, ret = -1;
|
s64 written, total, ret = -1;
|
||||||
struct ntfs_device_operations *dops;
|
struct ntfs_device_operations *dops;
|
||||||
|
|
||||||
ntfs_log_trace( "pos %lld, count %lld\n", ( long long )pos, ( long long )count );
|
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||||
|
|
||||||
if ( !b || count < 0 || pos < 0 )
|
if (!b || count < 0 || pos < 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ( !count )
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
if ( NDevReadOnly( dev ) )
|
if (NDevReadOnly(dev)) {
|
||||||
{
|
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dops = dev->d_ops;
|
dops = dev->d_ops;
|
||||||
|
|
||||||
NDevSetDirty( dev );
|
NDevSetDirty(dev);
|
||||||
for ( total = 0; count; count -= written, total += written )
|
for (total = 0; count; count -= written, total += written) {
|
||||||
{
|
written = dops->pwrite(dev, (const char*)b + total, count,
|
||||||
written = dops->pwrite( dev, ( const char* )b + total, count,
|
pos + total);
|
||||||
pos + total );
|
|
||||||
/* If everything ok, continue. */
|
/* If everything ok, continue. */
|
||||||
if ( written > 0 )
|
if (written > 0)
|
||||||
continue;
|
continue;
|
||||||
/*
|
/*
|
||||||
* If nothing written or error return number of bytes written.
|
* If nothing written or error return number of bytes written.
|
||||||
*/
|
*/
|
||||||
if ( !written || total )
|
if (!written || total)
|
||||||
break;
|
break;
|
||||||
/* Nothing written and error, return error status. */
|
/* Nothing written and error, return error status. */
|
||||||
total = written;
|
total = written;
|
||||||
@ -304,19 +294,18 @@ out:
|
|||||||
* sector transfer error. This should be detected by the caller by checking for
|
* sector transfer error. This should be detected by the caller by checking for
|
||||||
* the magic being "BAAD".
|
* the magic being "BAAD".
|
||||||
*/
|
*/
|
||||||
s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const u32 bksize, void *b )
|
const u32 bksize, void *b)
|
||||||
{
|
{
|
||||||
s64 br, i;
|
s64 br, i;
|
||||||
|
|
||||||
if ( bksize & ( bksize - 1 ) || bksize % NTFS_BLOCK_SIZE )
|
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Do the read. */
|
/* Do the read. */
|
||||||
br = ntfs_pread( dev, pos, count * bksize, b );
|
br = ntfs_pread(dev, pos, count * bksize, b);
|
||||||
if ( br < 0 )
|
if (br < 0)
|
||||||
return br;
|
return br;
|
||||||
/*
|
/*
|
||||||
* Apply fixups to successfully read data, disregarding any errors
|
* Apply fixups to successfully read data, disregarding any errors
|
||||||
@ -325,9 +314,9 @@ s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
* magic will be detected later on.
|
* magic will be detected later on.
|
||||||
*/
|
*/
|
||||||
count = br / bksize;
|
count = br / bksize;
|
||||||
for ( i = 0; i < count; ++i )
|
for (i = 0; i < count; ++i)
|
||||||
ntfs_mst_post_read_fixup( ( NTFS_RECORD* )
|
ntfs_mst_post_read_fixup((NTFS_RECORD*)
|
||||||
( ( u8* )b + i * bksize ), bksize );
|
((u8*)b + i * bksize), bksize);
|
||||||
/* Finally, return the number of complete blocks read. */
|
/* Finally, return the number of complete blocks read. */
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -362,40 +351,37 @@ s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
* simulating an mst read on the written data. This way cache coherency is
|
* simulating an mst read on the written data. This way cache coherency is
|
||||||
* achieved.
|
* achieved.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_mst_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const u32 bksize, void *b )
|
const u32 bksize, void *b)
|
||||||
{
|
{
|
||||||
s64 written, i;
|
s64 written, i;
|
||||||
|
|
||||||
if ( count < 0 || bksize % NTFS_BLOCK_SIZE )
|
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !count )
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
/* Prepare data for writing. */
|
/* Prepare data for writing. */
|
||||||
for ( i = 0; i < count; ++i )
|
for (i = 0; i < count; ++i) {
|
||||||
{
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = ntfs_mst_pre_write_fixup( ( NTFS_RECORD* )
|
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
|
||||||
( ( u8* )b + i * bksize ), bksize );
|
((u8*)b + i * bksize), bksize);
|
||||||
if ( err < 0 )
|
if (err < 0) {
|
||||||
{
|
|
||||||
/* Abort write at this position. */
|
/* Abort write at this position. */
|
||||||
if ( !i )
|
if (!i)
|
||||||
return err;
|
return err;
|
||||||
count = i;
|
count = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Write the prepared data. */
|
/* Write the prepared data. */
|
||||||
written = ntfs_pwrite( dev, pos, count * bksize, b );
|
written = ntfs_pwrite(dev, pos, count * bksize, b);
|
||||||
/* Quickly deprotect the data again. */
|
/* Quickly deprotect the data again. */
|
||||||
for ( i = 0; i < count; ++i )
|
for (i = 0; i < count; ++i)
|
||||||
ntfs_mst_post_write_fixup( ( NTFS_RECORD* )( ( u8* )b + i * bksize ) );
|
ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
|
||||||
if ( written <= 0 )
|
if (written <= 0)
|
||||||
return written;
|
return written;
|
||||||
/* Finally, return the number of complete blocks written. */
|
/* Finally, return the number of complete blocks written. */
|
||||||
return written / bksize;
|
return written / bksize;
|
||||||
@ -412,29 +398,26 @@ s64 ntfs_mst_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
|||||||
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
||||||
* with errno set to the error code.
|
* with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_cluster_read( const ntfs_volume *vol, const s64 lcn, const s64 count,
|
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||||
void *b )
|
void *b)
|
||||||
{
|
{
|
||||||
s64 br;
|
s64 br;
|
||||||
|
|
||||||
if ( !vol || lcn < 0 || count < 0 )
|
if (!vol || lcn < 0 || count < 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( vol->nr_clusters < lcn + count )
|
if (vol->nr_clusters < lcn + count) {
|
||||||
{
|
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to read outside of volume "
|
ntfs_log_perror("Trying to read outside of volume "
|
||||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||||
( long long )lcn + count );
|
(long long)lcn + count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
br = ntfs_pread( vol->dev, lcn << vol->cluster_size_bits,
|
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
|
||||||
count << vol->cluster_size_bits, b );
|
count << vol->cluster_size_bits, b);
|
||||||
if ( br < 0 )
|
if (br < 0) {
|
||||||
{
|
ntfs_log_perror("Error reading cluster(s)");
|
||||||
ntfs_log_perror( "Error reading cluster(s)" );
|
|
||||||
return br;
|
return br;
|
||||||
}
|
}
|
||||||
return br >> vol->cluster_size_bits;
|
return br >> vol->cluster_size_bits;
|
||||||
@ -451,32 +434,29 @@ s64 ntfs_cluster_read( const ntfs_volume *vol, const s64 lcn, const s64 count,
|
|||||||
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
||||||
* error, with errno set to the error code.
|
* error, with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_cluster_write( const ntfs_volume *vol, const s64 lcn,
|
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||||
const s64 count, const void *b )
|
const s64 count, const void *b)
|
||||||
{
|
{
|
||||||
s64 bw;
|
s64 bw;
|
||||||
|
|
||||||
if ( !vol || lcn < 0 || count < 0 )
|
if (!vol || lcn < 0 || count < 0) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( vol->nr_clusters < lcn + count )
|
if (vol->nr_clusters < lcn + count) {
|
||||||
{
|
|
||||||
errno = ESPIPE;
|
errno = ESPIPE;
|
||||||
ntfs_log_perror( "Trying to write outside of volume "
|
ntfs_log_perror("Trying to write outside of volume "
|
||||||
"(%lld < %lld)", ( long long )vol->nr_clusters,
|
"(%lld < %lld)", (long long)vol->nr_clusters,
|
||||||
( long long )lcn + count );
|
(long long)lcn + count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !NVolReadOnly( vol ) )
|
if (!NVolReadOnly(vol))
|
||||||
bw = ntfs_pwrite( vol->dev, lcn << vol->cluster_size_bits,
|
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
|
||||||
count << vol->cluster_size_bits, b );
|
count << vol->cluster_size_bits, b);
|
||||||
else
|
else
|
||||||
bw = count << vol->cluster_size_bits;
|
bw = count << vol->cluster_size_bits;
|
||||||
if ( bw < 0 )
|
if (bw < 0) {
|
||||||
{
|
ntfs_log_perror("Error writing cluster(s)");
|
||||||
ntfs_log_perror( "Error writing cluster(s)" );
|
|
||||||
return bw;
|
return bw;
|
||||||
}
|
}
|
||||||
return bw >> vol->cluster_size_bits;
|
return bw >> vol->cluster_size_bits;
|
||||||
@ -492,12 +472,12 @@ s64 ntfs_cluster_write( const ntfs_volume *vol, const s64 lcn,
|
|||||||
*
|
*
|
||||||
* Return 0 if it is valid and -1 if it is not valid.
|
* Return 0 if it is valid and -1 if it is not valid.
|
||||||
*/
|
*/
|
||||||
static int ntfs_device_offset_valid( struct ntfs_device *dev, s64 ofs )
|
static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
if ( dev->d_ops->seek( dev, ofs, SEEK_SET ) >= 0 &&
|
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
|
||||||
dev->d_ops->read( dev, &ch, 1 ) == 1 )
|
dev->d_ops->read(dev, &ch, 1) == 1)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -514,47 +494,43 @@ static int ntfs_device_offset_valid( struct ntfs_device *dev, s64 ofs )
|
|||||||
*
|
*
|
||||||
* On error return -1 with errno set to the error code.
|
* On error return -1 with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
s64 ntfs_device_size_get( struct ntfs_device *dev, int block_size )
|
s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||||
{
|
{
|
||||||
s64 high, low;
|
s64 high, low;
|
||||||
|
|
||||||
if ( !dev || block_size <= 0 || ( block_size - 1 ) & block_size )
|
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKGETSIZE64
|
#ifdef BLKGETSIZE64
|
||||||
{ u64 size;
|
{ u64 size;
|
||||||
|
|
||||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE64, &size ) >= 0 )
|
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
||||||
{
|
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||||
ntfs_log_debug( "BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
(unsigned long long)size,
|
||||||
( unsigned long long )size,
|
(unsigned long long)size);
|
||||||
( unsigned long long )size );
|
return (s64)size / block_size;
|
||||||
return ( s64 )size / block_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef BLKGETSIZE
|
#ifdef BLKGETSIZE
|
||||||
{ unsigned long size;
|
{ unsigned long size;
|
||||||
|
|
||||||
if ( dev->d_ops->ioctl( dev, BLKGETSIZE, &size ) >= 0 )
|
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
||||||
{
|
ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
ntfs_log_debug( "BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
size, size);
|
||||||
size, size );
|
return (s64)size * 512 / block_size;
|
||||||
return ( s64 )size * 512 / block_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef FDGETPRM
|
#ifdef FDGETPRM
|
||||||
{ struct floppy_struct this_floppy;
|
{ struct floppy_struct this_floppy;
|
||||||
|
|
||||||
if ( dev->d_ops->ioctl( dev, FDGETPRM, &this_floppy ) >= 0 )
|
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
||||||
{
|
ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||||
ntfs_log_debug( "FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
(unsigned long)this_floppy.size,
|
||||||
( unsigned long )this_floppy.size,
|
(unsigned long)this_floppy.size);
|
||||||
( unsigned long )this_floppy.size );
|
return (s64)this_floppy.size * 512 / block_size;
|
||||||
return ( s64 )this_floppy.size * 512 / block_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -563,19 +539,18 @@ s64 ntfs_device_size_get( struct ntfs_device *dev, int block_size )
|
|||||||
* so do binary search to find the size of the device.
|
* so do binary search to find the size of the device.
|
||||||
*/
|
*/
|
||||||
low = 0LL;
|
low = 0LL;
|
||||||
for ( high = 1024LL; !ntfs_device_offset_valid( dev, high ); high <<= 1 )
|
for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
|
||||||
low = high;
|
low = high;
|
||||||
while ( low < high - 1LL )
|
while (low < high - 1LL) {
|
||||||
{
|
const s64 mid = (low + high) / 2;
|
||||||
const s64 mid = ( low + high ) / 2;
|
|
||||||
|
|
||||||
if ( !ntfs_device_offset_valid( dev, mid ) )
|
if (!ntfs_device_offset_valid(dev, mid))
|
||||||
low = mid;
|
low = mid;
|
||||||
else
|
else
|
||||||
high = mid;
|
high = mid;
|
||||||
}
|
}
|
||||||
dev->d_ops->seek( dev, 0LL, SEEK_SET );
|
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
||||||
return ( low + 1LL ) / block_size;
|
return (low + 1LL) / block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -590,20 +565,18 @@ s64 ntfs_device_size_get( struct ntfs_device *dev, int block_size )
|
|||||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||||
*/
|
*/
|
||||||
s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
|
s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||||
{
|
ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
||||||
ntfs_log_debug( "HDIO_GETGEO start_sect = %lu (0x%lx)\n",
|
geo.start, geo.start);
|
||||||
geo.start, geo.start );
|
|
||||||
return geo.start;
|
return geo.start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,21 +598,19 @@ s64 ntfs_device_partition_start_sector_get( struct ntfs_device *dev )
|
|||||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||||
*/
|
*/
|
||||||
int ntfs_device_heads_get( struct ntfs_device *dev )
|
int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||||
{
|
ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
|
||||||
ntfs_log_debug( "HDIO_GETGEO heads = %u (0x%x)\n",
|
(unsigned)geo.heads,
|
||||||
( unsigned )geo.heads,
|
(unsigned)geo.heads);
|
||||||
( unsigned )geo.heads );
|
|
||||||
return geo.heads;
|
return geo.heads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -661,21 +632,19 @@ int ntfs_device_heads_get( struct ntfs_device *dev )
|
|||||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||||
*/
|
*/
|
||||||
int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef HDIO_GETGEO
|
#ifdef HDIO_GETGEO
|
||||||
{ struct hd_geometry geo;
|
{ struct hd_geometry geo;
|
||||||
|
|
||||||
if ( !dev->d_ops->ioctl( dev, HDIO_GETGEO, &geo ) )
|
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
|
||||||
{
|
ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
||||||
ntfs_log_debug( "HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
|
(unsigned)geo.sectors,
|
||||||
( unsigned )geo.sectors,
|
(unsigned)geo.sectors);
|
||||||
( unsigned )geo.sectors );
|
|
||||||
return geo.sectors;
|
return geo.sectors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -697,10 +666,9 @@ int ntfs_device_sectors_per_track_get( struct ntfs_device *dev )
|
|||||||
* EOPNOTSUPP System does not support BLKSSZGET ioctl
|
* EOPNOTSUPP System does not support BLKSSZGET ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting BLKSSZGET
|
* ENOTTY @dev is a file or a device not supporting BLKSSZGET
|
||||||
*/
|
*/
|
||||||
int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -708,10 +676,9 @@ int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
|||||||
{
|
{
|
||||||
int sect_size = 0;
|
int sect_size = 0;
|
||||||
|
|
||||||
if ( !dev->d_ops->ioctl( dev, BLKSSZGET, §_size ) )
|
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
||||||
{
|
ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
|
||||||
ntfs_log_debug( "BLKSSZGET sector size = %d bytes\n",
|
sect_size);
|
||||||
sect_size );
|
|
||||||
return sect_size;
|
return sect_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,30 +701,28 @@ int ntfs_device_sector_size_get( struct ntfs_device *dev )
|
|||||||
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
||||||
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
||||||
*/
|
*/
|
||||||
int ntfs_device_block_size_set( struct ntfs_device *dev,
|
int ntfs_device_block_size_set(struct ntfs_device *dev,
|
||||||
int block_size __attribute__( ( unused ) ) )
|
int block_size __attribute__((unused)))
|
||||||
{
|
{
|
||||||
if ( !dev )
|
if (!dev) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef BLKBSZSET
|
#ifdef BLKBSZSET
|
||||||
{
|
{
|
||||||
size_t s_block_size = block_size;
|
size_t s_block_size = block_size;
|
||||||
if ( !dev->d_ops->ioctl( dev, BLKBSZSET, &s_block_size ) )
|
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
||||||
{
|
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
||||||
ntfs_log_debug( "Used BLKBSZSET to set block size to "
|
"%d bytes.\n", block_size);
|
||||||
"%d bytes.\n", block_size );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* If not a block device, pretend it was successful. */
|
/* If not a block device, pretend it was successful. */
|
||||||
if ( !NDevBlock( dev ) )
|
if (!NDevBlock(dev))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* If not a block device, pretend it was successful. */
|
/* If not a block device, pretend it was successful. */
|
||||||
if ( !NDevBlock( dev ) )
|
if (!NDevBlock(dev))
|
||||||
return 0;
|
return 0;
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
#endif
|
#endif
|
||||||
|
@ -36,8 +36,7 @@
|
|||||||
*
|
*
|
||||||
* Defined bits for the state field in the ntfs_device structure.
|
* Defined bits for the state field in the ntfs_device structure.
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
ND_Open, /* 1: Device is open. */
|
ND_Open, /* 1: Device is open. */
|
||||||
ND_ReadOnly, /* 1: Device is read-only. */
|
ND_ReadOnly, /* 1: Device is read-only. */
|
||||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||||
@ -70,8 +69,7 @@ typedef enum
|
|||||||
* The ntfs device structure defining all operations needed to access the low
|
* The ntfs device structure defining all operations needed to access the low
|
||||||
* level device underlying the ntfs volume.
|
* level device underlying the ntfs volume.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device
|
struct ntfs_device {
|
||||||
{
|
|
||||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||||
unsigned long d_state; /* State of the device. */
|
unsigned long d_state; /* State of the device. */
|
||||||
char *d_name; /* Name of device. */
|
char *d_name; /* Name of device. */
|
||||||
@ -87,45 +85,44 @@ struct stat;
|
|||||||
* The ntfs device operations defining all operations that can be performed on
|
* The ntfs device operations defining all operations that can be performed on
|
||||||
* the low level device described by an ntfs device structure.
|
* the low level device described by an ntfs device structure.
|
||||||
*/
|
*/
|
||||||
struct ntfs_device_operations
|
struct ntfs_device_operations {
|
||||||
{
|
int (*open)(struct ntfs_device *dev, int flags);
|
||||||
int ( *open )( struct ntfs_device *dev, int flags );
|
int (*close)(struct ntfs_device *dev);
|
||||||
int ( *close )( struct ntfs_device *dev );
|
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
||||||
s64 ( *seek )( struct ntfs_device *dev, s64 offset, int whence );
|
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
||||||
s64 ( *read )( struct ntfs_device *dev, void *buf, s64 count );
|
s64 (*write)(struct ntfs_device *dev, const 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 ( *pread )( struct ntfs_device *dev, void *buf, s64 count, s64 offset );
|
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
|
||||||
s64 ( *pwrite )( struct ntfs_device *dev, const void *buf, s64 count,
|
s64 offset);
|
||||||
s64 offset );
|
int (*sync)(struct ntfs_device *dev);
|
||||||
int ( *sync )( struct ntfs_device *dev );
|
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
||||||
int ( *stat )( struct ntfs_device *dev, struct stat *buf );
|
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
|
||||||
int ( *ioctl )( struct ntfs_device *dev, int request, void *argp );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct ntfs_device *ntfs_device_alloc( const char *name, const long state,
|
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||||
struct ntfs_device_operations *dops, void *priv_data );
|
struct ntfs_device_operations *dops, void *priv_data);
|
||||||
extern int ntfs_device_free( struct ntfs_device *dev );
|
extern int ntfs_device_free(struct ntfs_device *dev);
|
||||||
|
|
||||||
extern s64 ntfs_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
void *b );
|
void *b);
|
||||||
extern s64 ntfs_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const void *b );
|
const void *b);
|
||||||
|
|
||||||
extern s64 ntfs_mst_pread( struct ntfs_device *dev, const s64 pos, s64 count,
|
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const u32 bksize, void *b );
|
const u32 bksize, void *b);
|
||||||
extern s64 ntfs_mst_pwrite( struct ntfs_device *dev, const s64 pos, s64 count,
|
extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||||
const u32 bksize, void *b );
|
const u32 bksize, void *b);
|
||||||
|
|
||||||
extern s64 ntfs_cluster_read( const ntfs_volume *vol, const s64 lcn,
|
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||||
const s64 count, void *b );
|
const s64 count, void *b);
|
||||||
extern s64 ntfs_cluster_write( const ntfs_volume *vol, const s64 lcn,
|
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||||
const s64 count, const void *b );
|
const s64 count, const void *b);
|
||||||
|
|
||||||
extern s64 ntfs_device_size_get( 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 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_heads_get(struct ntfs_device *dev);
|
||||||
extern int ntfs_device_sectors_per_track_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_sector_size_get(struct ntfs_device *dev);
|
||||||
extern int ntfs_device_block_size_set( struct ntfs_device *dev, int block_size );
|
extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size);
|
||||||
|
|
||||||
#endif /* defined _NTFS_DEVICE_H */
|
#endif /* defined _NTFS_DEVICE_H */
|
||||||
|
@ -45,8 +45,7 @@
|
|||||||
/**
|
/**
|
||||||
* struct hd_geometry -
|
* struct hd_geometry -
|
||||||
*/
|
*/
|
||||||
struct hd_geometry
|
struct hd_geometry {
|
||||||
{
|
|
||||||
unsigned char heads;
|
unsigned char heads;
|
||||||
unsigned char sectors;
|
unsigned char sectors;
|
||||||
unsigned short cylinders;
|
unsigned short cylinders;
|
||||||
|
2195
source/libntfs/dir.c
2195
source/libntfs/dir.c
File diff suppressed because it is too large
Load Diff
@ -59,27 +59,27 @@ extern ntfschar NTFS_INDEX_O[3];
|
|||||||
extern ntfschar NTFS_INDEX_Q[3];
|
extern ntfschar NTFS_INDEX_Q[3];
|
||||||
extern ntfschar NTFS_INDEX_R[3];
|
extern ntfschar NTFS_INDEX_R[3];
|
||||||
|
|
||||||
extern u64 ntfs_inode_lookup_by_name( ntfs_inode *dir_ni,
|
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||||
const ntfschar *uname, const int uname_len );
|
const ntfschar *uname, const int uname_len);
|
||||||
extern u64 ntfs_inode_lookup_by_mbsname( ntfs_inode *dir_ni, const char *name );
|
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,
|
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
|
||||||
u64 inum );
|
u64 inum);
|
||||||
|
|
||||||
extern ntfs_inode *ntfs_pathname_to_inode( ntfs_volume *vol, ntfs_inode *parent,
|
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||||
const char *pathname );
|
const char *pathname);
|
||||||
extern ntfs_inode *ntfs_create( ntfs_inode *dir_ni, le32 securid,
|
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||||
ntfschar *name, u8 name_len, mode_t type );
|
ntfschar *name, u8 name_len, mode_t type);
|
||||||
extern ntfs_inode *ntfs_create_device( ntfs_inode *dir_ni, le32 securid,
|
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev );
|
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||||
extern ntfs_inode *ntfs_create_symlink( ntfs_inode *dir_ni, le32 securid,
|
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len );
|
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
|
||||||
extern int ntfs_check_empty_dir( ntfs_inode *ni );
|
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||||
extern int ntfs_delete( ntfs_volume *vol, const char *path,
|
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
||||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||||
u8 name_len );
|
u8 name_len);
|
||||||
|
|
||||||
extern int ntfs_link( ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||||
u8 name_len );
|
u8 name_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File types (adapted from include <linux/fs.h>)
|
* File types (adapted from include <linux/fs.h>)
|
||||||
@ -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
|
* This allows the caller to read directories into their application or
|
||||||
* to have different dirent layouts depending on the binary type.
|
* to have different dirent layouts depending on the binary type.
|
||||||
*/
|
*/
|
||||||
typedef int ( *ntfs_filldir_t )( void *dirent, const ntfschar *name,
|
typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
|
||||||
const int name_len, const int name_type, const s64 pos,
|
const int name_len, const int name_type, const s64 pos,
|
||||||
const MFT_REF mref, const unsigned dt_type );
|
const MFT_REF mref, const unsigned dt_type);
|
||||||
|
|
||||||
extern int ntfs_readdir( ntfs_inode *dir_ni, s64 *pos,
|
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||||
void *dirent, ntfs_filldir_t filldir );
|
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,
|
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||||
char *value, size_t size );
|
char *value, size_t size);
|
||||||
int ntfs_set_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni,
|
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||||
const char *value, size_t size, int flags );
|
const char *value, size_t size, int flags);
|
||||||
int ntfs_remove_ntfs_dos_name( ntfs_inode *ni, ntfs_inode *dir_ni );
|
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||||
|
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
|
|
||||||
struct CACHED_GENERIC;
|
struct CACHED_GENERIC;
|
||||||
|
|
||||||
extern int ntfs_dir_inode_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 );
|
extern int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -60,13 +60,12 @@
|
|||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
|
|
||||||
static ntfschar logged_utility_stream_name[] =
|
static ntfschar logged_utility_stream_name[] = {
|
||||||
{
|
const_cpu_to_le16('$'),
|
||||||
const_cpu_to_le16( '$' ),
|
const_cpu_to_le16('E'),
|
||||||
const_cpu_to_le16( 'E' ),
|
const_cpu_to_le16('F'),
|
||||||
const_cpu_to_le16( 'F' ),
|
const_cpu_to_le16('S'),
|
||||||
const_cpu_to_le16( 'S' ),
|
const_cpu_to_le16(0)
|
||||||
const_cpu_to_le16( 0 )
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -74,64 +73,51 @@ static ntfschar logged_utility_stream_name[] =
|
|||||||
* 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;
|
EFS_ATTR_HEADER *efs_info;
|
||||||
s64 attr_size = 0;
|
s64 attr_size = 0;
|
||||||
|
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
|
||||||
{
|
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
|
||||||
efs_info = ( EFS_ATTR_HEADER* )ntfs_attr_readall( ni,
|
&attr_size);
|
||||||
AT_LOGGED_UTILITY_STREAM, ( ntfschar* )NULL, 0,
|
if (efs_info
|
||||||
&attr_size );
|
&& (le32_to_cpu(efs_info->length) == attr_size)) {
|
||||||
if ( efs_info
|
if (attr_size <= (s64)size) {
|
||||||
&& ( le32_to_cpu( efs_info->length ) == attr_size ) )
|
if (value)
|
||||||
{
|
memcpy(value,efs_info,attr_size);
|
||||||
if ( attr_size <= ( s64 )size )
|
else {
|
||||||
{
|
|
||||||
if ( value )
|
|
||||||
memcpy( value, efs_info, attr_size );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EFAULT;
|
errno = EFAULT;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else if ( size )
|
if (size) {
|
||||||
{
|
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
free ( efs_info );
|
free (efs_info);
|
||||||
}
|
} else {
|
||||||
else
|
if (efs_info) {
|
||||||
{
|
free(efs_info);
|
||||||
if ( efs_info )
|
ntfs_log_error("Bad efs_info for inode %lld\n",
|
||||||
{
|
(long long)ni->mft_no);
|
||||||
free( efs_info );
|
} else {
|
||||||
ntfs_log_error( "Bad efs_info for inode %lld\n",
|
ntfs_log_error("Could not get efsinfo"
|
||||||
( long long )ni->mft_no );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ntfs_log_error( "Could not get efsinfo"
|
|
||||||
" for inode %lld\n",
|
" for inode %lld\n",
|
||||||
( long long )ni->mft_no );
|
(long long)ni->mft_no);
|
||||||
}
|
}
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
attr_size = 0;
|
attr_size = 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
ntfs_log_trace( "Inode %lld is not encrypted\n",
|
ntfs_log_trace("Inode %lld is not encrypted\n",
|
||||||
( long long )ni->mft_no );
|
(long long)ni->mft_no);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ( attr_size ? ( int )attr_size : -errno );
|
return (attr_size ? (int)attr_size : -errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -147,7 +133,7 @@ int ntfs_get_efs_info( ntfs_inode *ni, char *value, size_t size )
|
|||||||
* -1 if there is a problem.
|
* -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_search_ctx *ctx;
|
||||||
ntfs_attr *na;
|
ntfs_attr *na;
|
||||||
@ -159,80 +145,66 @@ static int fixup_loop( ntfs_inode *ni )
|
|||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
maxcnt = 0;
|
maxcnt = 0;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
restart = FALSE;
|
restart = FALSE;
|
||||||
ctx = ntfs_attr_get_search_ctx( ni, NULL );
|
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||||
if ( !ctx )
|
if (!ctx) {
|
||||||
{
|
ntfs_log_error("Failed to get ctx for efs\n");
|
||||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
while ( !restart && !res
|
while (!restart && !res
|
||||||
&& !ntfs_attr_lookup( AT_DATA, NULL, 0,
|
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||||
{
|
|
||||||
cnt++;
|
cnt++;
|
||||||
a = ctx->attr;
|
a = ctx->attr;
|
||||||
na = ntfs_attr_open( ctx->ntfs_ino, AT_DATA,
|
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
|
||||||
( ntfschar* )( ( u8* )a + le16_to_cpu( a->name_offset ) ),
|
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
|
||||||
a->name_length );
|
a->name_length);
|
||||||
if ( !na )
|
if (!na) {
|
||||||
{
|
ntfs_log_error("can't open DATA Attribute\n");
|
||||||
ntfs_log_error( "can't open DATA Attribute\n" );
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if ( na && !( ctx->attr->flags & ATTR_IS_ENCRYPTED ) )
|
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
|
||||||
{
|
if (!NAttrNonResident(na)
|
||||||
if ( !NAttrNonResident( na )
|
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* ntfs_attr_make_non_resident fails if there
|
* ntfs_attr_make_non_resident fails if there
|
||||||
* is not enough space in the MFT record.
|
* is not enough space in the MFT record.
|
||||||
* When this happens, force making non-resident
|
* When this happens, force making non-resident
|
||||||
* so that some other attribute is expelled.
|
* so that some other attribute is expelled.
|
||||||
*/
|
*/
|
||||||
if ( ntfs_attr_force_non_resident( na ) )
|
if (ntfs_attr_force_non_resident(na)) {
|
||||||
{
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* make sure there is some progress */
|
/* make sure there is some progress */
|
||||||
if ( cnt <= maxcnt )
|
if (cnt <= maxcnt) {
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_error( "Multiple failure"
|
ntfs_log_error("Multiple failure"
|
||||||
" making non resident\n" );
|
" making non resident\n");
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
{
|
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
|
||||||
ctx = ( ntfs_attr_search_ctx* )NULL;
|
|
||||||
restart = TRUE;
|
restart = TRUE;
|
||||||
maxcnt = cnt;
|
maxcnt = cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( !restart && !res
|
if (!restart && !res
|
||||||
&& ntfs_efs_fixup_attribute( ctx, na ) )
|
&& ntfs_efs_fixup_attribute(ctx, na)) {
|
||||||
{
|
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
|
||||||
ntfs_log_error( "Error in efs fixup of AT_DATA Attribute\n" );
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( na )
|
if (na)
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
}
|
}
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
}
|
} while (restart && !res);
|
||||||
while ( restart && !res );
|
if (ctx)
|
||||||
if ( ctx )
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
return (res);
|
||||||
return ( res );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -241,8 +213,8 @@ static int fixup_loop( ntfs_inode *ni )
|
|||||||
* Returns 0, or -1 if there is a problem
|
* Returns 0, or -1 if there is a problem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||||
int flags )
|
int flags)
|
||||||
|
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -251,112 +223,91 @@ int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
|||||||
const EFS_ATTR_HEADER *info_header;
|
const EFS_ATTR_HEADER *info_header;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if ( ni && value && size )
|
if (ni && value && size) {
|
||||||
{
|
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
|
||||||
if ( ni->flags & ( FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED ) )
|
if (ni->flags & FILE_ATTR_ENCRYPTED) {
|
||||||
{
|
ntfs_log_trace("Inode %lld already encrypted\n",
|
||||||
if ( ni->flags & FILE_ATTR_ENCRYPTED )
|
(long long)ni->mft_no);
|
||||||
{
|
|
||||||
ntfs_log_trace( "Inode %lld already encrypted\n",
|
|
||||||
( long long )ni->mft_no );
|
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Possible problem : if encrypted file was
|
* Possible problem : if encrypted file was
|
||||||
* restored in a compressed directory, it was
|
* restored in a compressed directory, it was
|
||||||
* restored as compressed.
|
* restored as compressed.
|
||||||
* TODO : decompress first.
|
* TODO : decompress first.
|
||||||
*/
|
*/
|
||||||
ntfs_log_error( "Inode %lld cannot be encrypted and compressed\n",
|
ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
|
||||||
( long long )ni->mft_no );
|
(long long)ni->mft_no);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
info_header = ( const EFS_ATTR_HEADER* )value;
|
info_header = (const EFS_ATTR_HEADER*)value;
|
||||||
/* make sure we get a likely efsinfo */
|
/* make sure we get a likely efsinfo */
|
||||||
if ( le32_to_cpu( info_header->length ) != size )
|
if (le32_to_cpu(info_header->length) != size) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return ( -1 );
|
return (-1);
|
||||||
}
|
}
|
||||||
if ( !ntfs_attr_exist( ni, AT_LOGGED_UTILITY_STREAM,
|
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
|
||||||
( ntfschar* )NULL, 0 ) )
|
(ntfschar*)NULL,0)) {
|
||||||
{
|
if (!(flags & XATTR_REPLACE)) {
|
||||||
if ( !( flags & XATTR_REPLACE ) )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* no logged_utility_stream attribute : add one,
|
* no logged_utility_stream attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
*/
|
*/
|
||||||
res = ntfs_attr_add( ni, AT_LOGGED_UTILITY_STREAM,
|
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name, 4,
|
logged_utility_stream_name,4,
|
||||||
( u8* )NULL, ( s64 )size );
|
(u8*)NULL,(s64)size);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if ( !res )
|
if (!res) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* open and update the existing efs data
|
* open and update the existing efs data
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open( ni, AT_LOGGED_UTILITY_STREAM,
|
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
|
||||||
logged_utility_stream_name, 4 );
|
logged_utility_stream_name, 4);
|
||||||
if ( na )
|
if (na) {
|
||||||
{
|
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate( na, ( s64 )size );
|
res = ntfs_attr_truncate(na, (s64)size);
|
||||||
/* overwrite value if any */
|
/* overwrite value if any */
|
||||||
if ( !res && value )
|
if (!res && value) {
|
||||||
{
|
written = (int)ntfs_attr_pwrite(na,
|
||||||
written = ( int )ntfs_attr_pwrite( na,
|
(s64)0, (s64)size, value);
|
||||||
( s64 )0, ( s64 )size, value );
|
if (written != (s64)size) {
|
||||||
if ( written != ( s64 )size )
|
ntfs_log_error("Failed to "
|
||||||
{
|
"update efs data\n");
|
||||||
ntfs_log_error( "Failed to "
|
|
||||||
"update efs data\n" );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
if ( !res )
|
if (!res) {
|
||||||
{
|
|
||||||
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
|
||||||
if ( !( ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||||
{
|
|
||||||
/* iterate over AT_DATA attributes */
|
/* iterate over AT_DATA attributes */
|
||||||
/* set encrypted flag, truncate attribute to match padding bytes */
|
/* set encrypted flag, truncate attribute to match padding bytes */
|
||||||
|
|
||||||
if ( fixup_loop( ni ) )
|
if (fixup_loop(ni))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ni->flags |= FILE_ATTR_ENCRYPTED;
|
ni->flags |= FILE_ATTR_ENCRYPTED;
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty(ni);
|
||||||
NInoFileNameSetDirty( ni );
|
NInoFileNameSetDirty(ni);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
return ( res ? -1 : 0 );
|
return (res ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -370,7 +321,7 @@ int ntfs_set_efs_info( ntfs_inode *ni, const char *value, size_t size,
|
|||||||
* -1 if failed (errno tells why)
|
* -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 newsize;
|
||||||
u64 oldsize;
|
u64 oldsize;
|
||||||
@ -379,59 +330,48 @@ int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na )
|
|||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
BOOL close_ctx = FALSE;
|
BOOL close_ctx = FALSE;
|
||||||
|
|
||||||
if ( !na )
|
if (!na) {
|
||||||
{
|
ntfs_log_error("no na specified for efs_fixup_attribute\n");
|
||||||
ntfs_log_error( "no na specified for efs_fixup_attribute\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if ( !ctx )
|
if (!ctx) {
|
||||||
{
|
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||||
ctx = ntfs_attr_get_search_ctx( na->ni, NULL );
|
if (!ctx) {
|
||||||
if ( !ctx )
|
ntfs_log_error("Failed to get ctx for efs\n");
|
||||||
{
|
|
||||||
ntfs_log_error( "Failed to get ctx for efs\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
close_ctx = TRUE;
|
close_ctx = TRUE;
|
||||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||||
{
|
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
if (!NAttrNonResident(na)) {
|
||||||
{
|
ntfs_log_error("Cannot make non resident"
|
||||||
if ( !NAttrNonResident( na ) )
|
" when a context has been allocated\n");
|
||||||
{
|
|
||||||
ntfs_log_error( "Cannot make non resident"
|
|
||||||
" when a context has been allocated\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no extra bytes are added to void attributes */
|
/* no extra bytes are added to void attributes */
|
||||||
oldsize = na->data_size;
|
oldsize = na->data_size;
|
||||||
if ( oldsize )
|
if (oldsize) {
|
||||||
{
|
|
||||||
/* make sure size is valid for a raw encrypted stream */
|
/* make sure size is valid for a raw encrypted stream */
|
||||||
if ( ( oldsize & 511 ) != 2 )
|
if ((oldsize & 511) != 2) {
|
||||||
{
|
ntfs_log_error("Bad raw encrypted stream\n");
|
||||||
ntfs_log_error( "Bad raw encrypted stream\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
/* read padding length from last two bytes of attribute */
|
/* read padding length from last two bytes of attribute */
|
||||||
if ( ntfs_attr_pread( na, oldsize - 2, 2, &appended_bytes ) != 2 )
|
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
|
||||||
{
|
ntfs_log_error("Error reading padding length\n");
|
||||||
ntfs_log_error( "Error reading padding length\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
padding_length = le16_to_cpu( appended_bytes );
|
padding_length = le16_to_cpu(appended_bytes);
|
||||||
if ( padding_length > 511 || padding_length > na->data_size - 2 )
|
if (padding_length > 511 || padding_length > na->data_size-2) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_error( "invalid padding length %d for data_size %lld\n",
|
ntfs_log_error("invalid padding length %d for data_size %lld\n",
|
||||||
padding_length, ( long long )oldsize );
|
padding_length, (long long)oldsize);
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
newsize = oldsize - padding_length - 2;
|
newsize = oldsize - padding_length - 2;
|
||||||
@ -440,13 +380,11 @@ int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na )
|
|||||||
* for the last two bytes, but do not truncate to new size
|
* for the last two bytes, but do not truncate to new size
|
||||||
* to avoid losing useful data
|
* to avoid losing useful data
|
||||||
*/
|
*/
|
||||||
if ( ntfs_attr_truncate( na, oldsize - 2 ) )
|
if (ntfs_attr_truncate(na, oldsize - 2)) {
|
||||||
{
|
ntfs_log_error("Error truncating attribute\n");
|
||||||
ntfs_log_error( "Error truncating attribute\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
newsize = 0;
|
newsize = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -455,53 +393,47 @@ int ntfs_efs_fixup_attribute( ntfs_attr_search_ctx *ctx, ntfs_attr *na )
|
|||||||
* resizing down to zero may cause the attribute to be made
|
* resizing down to zero may cause the attribute to be made
|
||||||
* resident.
|
* resident.
|
||||||
*/
|
*/
|
||||||
if ( !NAttrNonResident( na )
|
if (!NAttrNonResident(na)
|
||||||
&& ntfs_attr_make_non_resident( na, ctx ) )
|
&& ntfs_attr_make_non_resident(na, ctx)) {
|
||||||
{
|
if (!close_ctx
|
||||||
if ( !close_ctx
|
|| ntfs_attr_force_non_resident(na)) {
|
||||||
|| ntfs_attr_force_non_resident( na ) )
|
ntfs_log_error("Error making DATA attribute non-resident\n");
|
||||||
{
|
|
||||||
ntfs_log_error( "Error making DATA attribute non-resident\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* must reinitialize context after forcing
|
* must reinitialize context after forcing
|
||||||
* non-resident. We need a context for updating
|
* non-resident. We need a context for updating
|
||||||
* the state, and at this point, we are sure
|
* the state, and at this point, we are sure
|
||||||
* the context is not used elsewhere.
|
* the context is not used elsewhere.
|
||||||
*/
|
*/
|
||||||
ntfs_attr_reinit_search_ctx( ctx );
|
ntfs_attr_reinit_search_ctx(ctx);
|
||||||
if ( ntfs_attr_lookup( AT_DATA, na->name, na->name_len,
|
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
|
||||||
CASE_SENSITIVE, 0, NULL, 0, ctx ) )
|
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||||
{
|
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
|
||||||
ntfs_log_error( "attr lookup for AT_DATA attribute failed in efs fixup\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ni = na->ni;
|
ni = na->ni;
|
||||||
if ( !na->name_len )
|
if (!na->name_len) {
|
||||||
{
|
|
||||||
ni->data_size = newsize;
|
ni->data_size = newsize;
|
||||||
ni->allocated_size = na->allocated_size;
|
ni->allocated_size = na->allocated_size;
|
||||||
}
|
}
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty(ni);
|
||||||
NInoFileNameSetDirty( ni );
|
NInoFileNameSetDirty(ni);
|
||||||
|
|
||||||
ctx->attr->data_size = cpu_to_le64( newsize );
|
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||||
if ( le64_to_cpu( ctx->attr->initialized_size ) > newsize )
|
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||||
if ( close_ctx )
|
if (close_ctx)
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
|
|
||||||
return ( 0 );
|
return (0);
|
||||||
err_out:
|
err_out:
|
||||||
if ( close_ctx && ctx )
|
if (close_ctx && ctx)
|
||||||
ntfs_attr_put_search_ctx( ctx );
|
ntfs_attr_put_search_ctx(ctx);
|
||||||
return ( -1 );
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
|
@ -21,10 +21,10 @@
|
|||||||
#ifndef EFS_H
|
#ifndef EFS_H
|
||||||
#define 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,
|
int ntfs_set_efs_info(ntfs_inode *ni,
|
||||||
const char *value, size_t size, int flags );
|
const char *value, size_t size, int flags);
|
||||||
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);
|
||||||
|
|
||||||
#endif /* EFS_H */
|
#endif /* EFS_H */
|
||||||
|
@ -66,93 +66,83 @@
|
|||||||
#define DEV_FD(dev) ((gekko_fd *)dev->d_private)
|
#define DEV_FD(dev) ((gekko_fd *)dev->d_private)
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if ( !interface )
|
if (!interface) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the device interface and ensure that it is inserted
|
// Start the device interface and ensure that it is inserted
|
||||||
if ( !interface->startup() )
|
if (!interface->startup()) {
|
||||||
{
|
ntfs_log_perror("device failed to start\n");
|
||||||
ntfs_log_perror( "device failed to start\n" );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !interface->isInserted() )
|
if (!interface->isInserted()) {
|
||||||
{
|
ntfs_log_perror("device media is not inserted\n");
|
||||||
ntfs_log_perror( "device media is not inserted\n" );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device isn't already open (used by another volume?)
|
// Check that the device isn't already open (used by another volume?)
|
||||||
if ( NDevOpen( dev ) )
|
if (NDevOpen(dev)) {
|
||||||
{
|
ntfs_log_perror("device is busy (already open)\n");
|
||||||
ntfs_log_perror( "device is busy (already open)\n" );
|
|
||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is a valid NTFS boot sector at the start of the device
|
// Check that there is a valid NTFS boot sector at the start of the device
|
||||||
NTFS_BOOT_SECTOR boot;
|
NTFS_BOOT_SECTOR boot;
|
||||||
if ( interface->readSectors( fd->startSector, 1, &boot ) )
|
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
||||||
{
|
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
||||||
if ( !ntfs_boot_sector_is_ntfs( &boot ) )
|
|
||||||
{
|
|
||||||
errno = EINVALPART;
|
errno = EINVALPART;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
||||||
{
|
|
||||||
ntfs_log_perror( "read failure @ sector %d\n", fd->startSector );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the boot sector
|
// Parse the boot sector
|
||||||
fd->hiddenSectors = le32_to_cpu( boot.bpb.hidden_sectors );
|
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
|
||||||
fd->sectorSize = le16_to_cpu( boot.bpb.bytes_per_sector );
|
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
|
||||||
fd->sectorCount = sle64_to_cpu( boot.number_of_sectors );
|
fd->sectorCount = sle64_to_cpu(boot.number_of_sectors);
|
||||||
fd->pos = 0;
|
fd->pos = 0;
|
||||||
fd->len = ( fd->sectorCount * fd->sectorSize );
|
fd->len = (fd->sectorCount * fd->sectorSize);
|
||||||
fd->ino = le64_to_cpu( boot.volume_serial_number );
|
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
||||||
|
|
||||||
// Mark the device as read-only (if required)
|
// Mark the device as read-only (if required)
|
||||||
if ( flags & O_RDONLY )
|
if (flags & O_RDONLY) {
|
||||||
{
|
NDevSetReadOnly(dev);
|
||||||
NDevSetReadOnly( dev );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the cache
|
// 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
|
// Mark the device as open
|
||||||
NDevSetBlock( dev );
|
NDevSetBlock(dev);
|
||||||
NDevSetOpen( dev );
|
NDevSetOpen(dev);
|
||||||
|
|
||||||
return 0;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device is actually open
|
// Check that the device is actually open
|
||||||
if ( !NDevOpen( dev ) )
|
if (!NDevOpen(dev)) {
|
||||||
{
|
ntfs_log_perror("device is not open\n");
|
||||||
ntfs_log_perror( "device is not open\n" );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the device as closed
|
// Mark the device as closed
|
||||||
NDevClearOpen( dev );
|
NDevClearOpen(dev);
|
||||||
NDevClearBlock( dev );
|
NDevClearBlock(dev);
|
||||||
|
|
||||||
// Flush the device (if dirty and not read-only)
|
// Flush the device (if dirty and not read-only)
|
||||||
if ( NDevDirty( dev ) && !NDevReadOnly( dev ) )
|
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
||||||
{
|
ntfs_log_debug("device is dirty, will now sync\n");
|
||||||
ntfs_log_debug( "device is dirty, will now sync\n" );
|
|
||||||
|
|
||||||
// ...?
|
// ...?
|
||||||
|
|
||||||
// Mark the device as clean
|
// Mark the device as clean
|
||||||
NDevClearDirty( dev );
|
NDevClearDirty(dev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush and destroy the cache (if required)
|
// Flush and destroy the cache (if required)
|
||||||
if ( fd->cache )
|
if (fd->cache) {
|
||||||
{
|
_NTFS_cache_flush(fd->cache);
|
||||||
_NTFS_cache_flush( fd->cache );
|
_NTFS_cache_destructor(fd->cache);
|
||||||
_NTFS_cache_destructor( fd->cache );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown the device interface
|
// 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
|
// Free the device driver private data
|
||||||
ntfs_free( dev->d_private );
|
ntfs_free(dev->d_private);
|
||||||
dev->d_private = NULL;
|
dev->d_private = NULL;
|
||||||
|
|
||||||
return 0;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the current position on the device (in bytes)
|
// Set the current position on the device (in bytes)
|
||||||
switch ( whence )
|
switch(whence) {
|
||||||
{
|
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
||||||
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_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;
|
||||||
case SEEK_END: fd->pos = MIN( MAX( fd->len + offset, 0 ), fd->len ); break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -245,92 +229,86 @@ 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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if ( !interface )
|
if (!interface) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( offset < 0 )
|
if(offset < 0)
|
||||||
{
|
{
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !count )
|
if(!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
sec_t sec_start = (sec_t) fd->startSector;
|
||||||
sec_t sec_count = 1;
|
sec_t sec_count = 1;
|
||||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this read
|
// Determine the range of sectors required for this read
|
||||||
if ( offset > 0 )
|
if (offset > 0) {
|
||||||
{
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
|
||||||
}
|
}
|
||||||
if ( buffer_offset + count > fd->sectorSize )
|
if (buffer_offset+count > fd->sectorSize) {
|
||||||
{
|
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) 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 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
|
// Read from the device
|
||||||
ntfs_log_trace( "direct read from 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 ) )
|
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_perror( "direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -341,27 +319,25 @@ static s64 ntfs_device_gekko_io_readbytes( struct ntfs_device *dev, s64 offset,
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Allocate a buffer to hold the read data
|
// Allocate a buffer to hold the read data
|
||||||
buffer = ( u8* )ntfs_alloc( sec_count * fd->sectorSize );
|
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
||||||
if ( !buffer )
|
if (!buffer) {
|
||||||
{
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from the device
|
// Read from the device
|
||||||
ntfs_log_trace( "buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
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 );
|
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 ) )
|
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_log_perror( "buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
ntfs_free(buffer);
|
||||||
ntfs_free( buffer );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy what was requested to the destination buffer
|
// Copy what was requested to the destination buffer
|
||||||
memcpy( buf, buffer + buffer_offset, count );
|
memcpy(buf, buffer + buffer_offset, count);
|
||||||
ntfs_free( buffer );
|
ntfs_free(buffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,65 +347,58 @@ 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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the device interface
|
// Get the device interface
|
||||||
const DISC_INTERFACE* interface = fd->interface;
|
const DISC_INTERFACE* interface = fd->interface;
|
||||||
if ( !interface )
|
if (!interface) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if ( NDevReadOnly( dev ) )
|
if (NDevReadOnly(dev)) {
|
||||||
{
|
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( count < 0 || offset < 0 )
|
if(count < 0 || offset < 0) {
|
||||||
{
|
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( count == 0 )
|
if(count == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sec_t sec_start = ( sec_t ) fd->startSector;
|
sec_t sec_start = (sec_t) fd->startSector;
|
||||||
sec_t sec_count = 1;
|
sec_t sec_count = 1;
|
||||||
u32 buffer_offset = ( u32 ) ( offset % fd->sectorSize );
|
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
||||||
u8 *buffer = NULL;
|
u8 *buffer = NULL;
|
||||||
|
|
||||||
// Determine the range of sectors required for this write
|
// Determine the range of sectors required for this write
|
||||||
if ( offset > 0 )
|
if (offset > 0) {
|
||||||
{
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
||||||
sec_start += ( sec_t ) floor( ( f64 ) offset / ( f64 ) fd->sectorSize );
|
|
||||||
}
|
}
|
||||||
if ( ( buffer_offset + count ) > fd->sectorSize )
|
if ((buffer_offset+count) > fd->sectorSize) {
|
||||||
{
|
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) 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 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
|
// Write to the device
|
||||||
ntfs_log_trace( "direct write to 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 ) )
|
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_perror( "direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -438,92 +407,86 @@ static s64 ntfs_device_gekko_io_writebytes( struct ntfs_device *dev, s64 offset,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Allocate a buffer to hold the write data
|
// Allocate a buffer to hold the write data
|
||||||
buffer = ( u8 * ) ntfs_alloc( sec_count * fd->sectorSize );
|
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
||||||
if ( !buffer )
|
if (!buffer) {
|
||||||
{
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Read the first and last sectors of the buffer from disc (if required)
|
// 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,
|
// 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
|
// 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 ) )
|
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
||||||
{
|
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
||||||
ntfs_log_perror( "read failure @ sector %d\n", sec_start );
|
ntfs_free(buffer);
|
||||||
ntfs_free( buffer );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
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 ) ) )
|
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_log_perror( "read failure @ sector %d\n", sec_start + sec_count - 1 );
|
ntfs_free(buffer);
|
||||||
ntfs_free( buffer );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the data into the write buffer
|
// Copy the data into the write buffer
|
||||||
memcpy( buffer + buffer_offset, buf, count );
|
memcpy(buffer + buffer_offset, buf, count);
|
||||||
|
|
||||||
// Write to the device
|
// Write to the device
|
||||||
ntfs_log_trace( "buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count );
|
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 ) )
|
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||||
{
|
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||||
ntfs_log_perror( "buffered write failure @ sector %d\n", sec_start );
|
ntfs_free(buffer);
|
||||||
ntfs_free( buffer );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the buffer
|
// Free the buffer
|
||||||
ntfs_free( buffer );
|
ntfs_free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the device as dirty (if we actually wrote anything)
|
// Mark the device as dirty (if we actually wrote anything)
|
||||||
NDevSetDirty( dev );
|
NDevSetDirty(dev);
|
||||||
|
|
||||||
return count;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Read the sectors from disc (or cache, if enabled)
|
// Read the sectors from disc (or cache, if enabled)
|
||||||
if ( fd->cache )
|
if (fd->cache)
|
||||||
return _NTFS_cache_readSectors( fd->cache, sector, numSectors, buffer );
|
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||||
else
|
else
|
||||||
return fd->interface->readSectors( sector, numSectors, buffer );
|
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||||
|
|
||||||
return false;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the sectors to disc (or cache, if enabled)
|
// Write the sectors to disc (or cache, if enabled)
|
||||||
if ( fd->cache )
|
if (fd->cache)
|
||||||
return _NTFS_cache_writeSectors( fd->cache, sector, numSectors, buffer );
|
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||||
else
|
else
|
||||||
return fd->interface->writeSectors( sector, numSectors, buffer );
|
return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||||
|
|
||||||
return false;
|
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 );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
ntfs_log_trace( "dev %p\n", dev );
|
ntfs_log_trace("dev %p\n", dev);
|
||||||
|
|
||||||
// Check that the device can be written to
|
// Check that the device can be written to
|
||||||
if ( NDevReadOnly( dev ) )
|
if (NDevReadOnly(dev)) {
|
||||||
{
|
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the device as clean
|
// Mark the device as clean
|
||||||
NDevClearDirty( dev );
|
NDevClearDirty(dev);
|
||||||
|
|
||||||
// Flush any sectors in the disc cache (if required)
|
// Flush any sectors in the disc cache (if required)
|
||||||
if ( fd->cache )
|
if (fd->cache) {
|
||||||
{
|
if (!_NTFS_cache_flush(fd->cache)) {
|
||||||
if ( !_NTFS_cache_flush( fd->cache ) )
|
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases were we don't actually have to do anything
|
// Short circuit cases were we don't actually have to do anything
|
||||||
if ( !buf )
|
if (!buf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Build the device mode
|
// Build the device mode
|
||||||
mode_t mode = ( S_IFBLK ) |
|
mode_t mode = (S_IFBLK) |
|
||||||
( S_IRUSR | S_IRGRP | S_IROTH ) |
|
(S_IRUSR | S_IRGRP | S_IROTH) |
|
||||||
( ( !NDevReadOnly( dev ) ) ? ( S_IWUSR | S_IWGRP | S_IWOTH ) : 0 );
|
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
||||||
|
|
||||||
// Zero out the stat buffer
|
// Zero out the stat buffer
|
||||||
memset( buf, 0, sizeof( struct stat ) );
|
memset(buf, 0, sizeof(struct stat));
|
||||||
|
|
||||||
// Build the device stats
|
// Build the device stats
|
||||||
buf->st_dev = fd->interface->ioType;
|
buf->st_dev = fd->interface->ioType;
|
||||||
@ -600,76 +559,68 @@ 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
|
// Get the device driver descriptor
|
||||||
gekko_fd *fd = DEV_FD( dev );
|
gekko_fd *fd = DEV_FD(dev);
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out which i/o control was requested
|
// Figure out which i/o control was requested
|
||||||
switch ( request )
|
switch (request) {
|
||||||
{
|
|
||||||
|
|
||||||
// Get block device size (sectors)
|
// Get block device size (sectors)
|
||||||
#if defined(BLKGETSIZE)
|
#if defined(BLKGETSIZE)
|
||||||
case BLKGETSIZE:
|
case BLKGETSIZE: {
|
||||||
{
|
*(u32*)argp = fd->sectorCount;
|
||||||
*( u32* )argp = fd->sectorCount;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get block device size (bytes)
|
// Get block device size (bytes)
|
||||||
#if defined(BLKGETSIZE64)
|
#if defined(BLKGETSIZE64)
|
||||||
case BLKGETSIZE64:
|
case BLKGETSIZE64: {
|
||||||
{
|
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
||||||
*( u64* )argp = ( fd->sectorCount * fd->sectorSize );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get hard drive geometry
|
// Get hard drive geometry
|
||||||
#if defined(HDIO_GETGEO)
|
#if defined(HDIO_GETGEO)
|
||||||
case HDIO_GETGEO:
|
case HDIO_GETGEO: {
|
||||||
{
|
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
||||||
struct hd_geometry *geo = ( struct hd_geometry* )argp;
|
|
||||||
geo->sectors = 0;
|
geo->sectors = 0;
|
||||||
geo->heads = 0;
|
geo->heads = 0;
|
||||||
geo->cylinders = 0;
|
geo->cylinders = 0;
|
||||||
geo->start = fd->hiddenSectors;
|
geo->start = fd->hiddenSectors;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get block device sector size (bytes)
|
// Get block device sector size (bytes)
|
||||||
#if defined(BLKSSZGET)
|
#if defined(BLKSSZGET)
|
||||||
case BLKSSZGET:
|
case BLKSSZGET: {
|
||||||
{
|
*(int*)argp = fd->sectorSize;
|
||||||
*( int* )argp = fd->sectorSize;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set block device block size (bytes)
|
// Set block device block size (bytes)
|
||||||
#if defined(BLKBSZSET)
|
#if defined(BLKBSZSET)
|
||||||
case BLKBSZSET:
|
case BLKBSZSET: {
|
||||||
{
|
int sectorSize = *(int*)argp;
|
||||||
int sectorSize = *( int* )argp;
|
|
||||||
fd->sectorSize = sectorSize;
|
fd->sectorSize = sectorSize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Unimplemented ioctrl
|
// Unimplemented ioctrl
|
||||||
default:
|
default: {
|
||||||
{
|
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||||
ntfs_log_perror( "Unimplemented ioctrl %i\n", request );
|
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
return -1;
|
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.
|
* 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,
|
.open = ntfs_device_gekko_io_open,
|
||||||
.close = ntfs_device_gekko_io_close,
|
.close = ntfs_device_gekko_io_close,
|
||||||
.seek = ntfs_device_gekko_io_seek,
|
.seek = ntfs_device_gekko_io_seek,
|
||||||
|
@ -33,8 +33,7 @@
|
|||||||
/**
|
/**
|
||||||
* gekko_fd - Gekko device driver descriptor
|
* gekko_fd - Gekko device driver descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _gekko_fd
|
typedef struct _gekko_fd {
|
||||||
{
|
|
||||||
const DISC_INTERFACE* interface; /* Device disc interface */
|
const DISC_INTERFACE* interface; /* Device disc interface */
|
||||||
sec_t startSector; /* LBA of partition start */
|
sec_t startSector; /* LBA of partition start */
|
||||||
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
sec_t hiddenSectors; /* LBA offset to true partition start (as described by boot sector) */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -63,8 +63,8 @@
|
|||||||
|
|
||||||
#define MAX_PARENT_VCN 32
|
#define MAX_PARENT_VCN 32
|
||||||
|
|
||||||
typedef int ( *COLLATE )( ntfs_volume *vol, const void *data1, int len1,
|
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
|
||||||
const void *data2, int len2 );
|
const void *data2, int len2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ntfs_index_context -
|
* struct ntfs_index_context -
|
||||||
@ -112,8 +112,7 @@ 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
|
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||||
* to disk.
|
* to disk.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
ntfschar *name;
|
ntfschar *name;
|
||||||
u32 name_len;
|
u32 name_len;
|
||||||
@ -134,35 +133,35 @@ typedef struct
|
|||||||
u8 vcn_size_bits;
|
u8 vcn_size_bits;
|
||||||
} ntfs_index_context;
|
} ntfs_index_context;
|
||||||
|
|
||||||
extern ntfs_index_context *ntfs_index_ctx_get( ntfs_inode *ni,
|
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||||
ntfschar *name, u32 name_len );
|
ntfschar *name, u32 name_len);
|
||||||
extern void ntfs_index_ctx_put( ntfs_index_context *ictx );
|
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||||
extern void ntfs_index_ctx_reinit( 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,
|
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||||
ntfs_index_context *ictx ) __attribute_warn_unused_result__;
|
ntfs_index_context *ictx) __attribute_warn_unused_result__;
|
||||||
|
|
||||||
extern INDEX_ENTRY *ntfs_index_next( INDEX_ENTRY *ie,
|
extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie,
|
||||||
ntfs_index_context *ictx );
|
ntfs_index_context *ictx);
|
||||||
|
|
||||||
extern int ntfs_index_add_filename( ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||||
MFT_REF mref );
|
MFT_REF mref);
|
||||||
extern int ntfs_index_remove( ntfs_inode *dir_ni, ntfs_inode *ni,
|
extern int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||||
const void *key, const int keylen );
|
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 char *ntfs_ie_filename_get(INDEX_ENTRY *ie);
|
||||||
extern void ntfs_ie_filename_dump( INDEX_ENTRY *ie );
|
extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie);
|
||||||
extern void ntfs_ih_filename_dump( INDEX_HEADER *ih );
|
extern void ntfs_ih_filename_dump(INDEX_HEADER *ih);
|
||||||
|
|
||||||
/* the following was added by JPA for use in security.c */
|
/* 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_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie);
|
||||||
extern int ntfs_index_rm( ntfs_index_context *icx );
|
extern int ntfs_index_rm(ntfs_index_context *icx);
|
||||||
|
|
||||||
#endif /* _NTFS_INDEX_H */
|
#endif /* _NTFS_INDEX_H */
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -40,8 +40,7 @@ typedef struct _ntfs_inode ntfs_inode;
|
|||||||
* Defined bits for the state field in the ntfs_inode structure.
|
* Defined bits for the state field in the ntfs_inode structure.
|
||||||
* (f) = files only, (d) = directories only
|
* (f) = files only, (d) = directories only
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||||
|
|
||||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||||
@ -104,8 +103,7 @@ typedef enum
|
|||||||
* It is just used as an extension to the fields already provided in the VFS
|
* It is just used as an extension to the fields already provided in the VFS
|
||||||
* inode.
|
* inode.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_inode
|
struct _ntfs_inode {
|
||||||
{
|
|
||||||
u64 mft_no; /* Inode / mft record number. */
|
u64 mft_no; /* Inode / mft record number. */
|
||||||
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
||||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||||
@ -124,8 +122,7 @@ struct _ntfs_inode
|
|||||||
s32 nr_extents; /* For a base mft record, the number of
|
s32 nr_extents; /* For a base mft record, the number of
|
||||||
attached extent inodes (0 if none), for
|
attached extent inodes (0 if none), for
|
||||||
extent records this is -1. */
|
extent records this is -1. */
|
||||||
union /* This union is only used if nr_extents != 0. */
|
union { /* This union is only used if nr_extents != 0. */
|
||||||
{
|
|
||||||
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
||||||
ntfs inodes of the extent mft
|
ntfs inodes of the extent mft
|
||||||
records belonging to this base
|
records belonging to this base
|
||||||
@ -169,8 +166,7 @@ struct _ntfs_inode
|
|||||||
le64 usn;
|
le64 usn;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NTFS_UPDATE_ATIME = 1 << 0,
|
NTFS_UPDATE_ATIME = 1 << 0,
|
||||||
NTFS_UPDATE_MTIME = 1 << 1,
|
NTFS_UPDATE_MTIME = 1 << 1,
|
||||||
NTFS_UPDATE_CTIME = 1 << 2,
|
NTFS_UPDATE_CTIME = 1 << 2,
|
||||||
@ -179,48 +175,48 @@ typedef enum
|
|||||||
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
|
#define NTFS_UPDATE_MCTIME (NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME)
|
||||||
#define NTFS_UPDATE_AMCTIME (NTFS_UPDATE_ATIME | NTFS_UPDATE_MCTIME)
|
#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(ntfs_inode *ni);
|
||||||
extern int ntfs_inode_close_in_dir( ntfs_inode *ni, ntfs_inode *dir_ni );
|
extern int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||||
|
|
||||||
#if CACHE_NIDATA_SIZE
|
#if CACHE_NIDATA_SIZE
|
||||||
|
|
||||||
struct CACHED_GENERIC;
|
struct CACHED_GENERIC;
|
||||||
|
|
||||||
extern int ntfs_inode_real_close( ntfs_inode *ni );
|
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_invalidate(ntfs_volume *vol, const MFT_REF mref);
|
||||||
extern void ntfs_inode_nidata_free( const struct CACHED_GENERIC *cached );
|
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_nidata_hash(const struct CACHED_GENERIC *item);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern ntfs_inode *ntfs_extent_inode_open( ntfs_inode *base_ni,
|
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
||||||
const MFT_REF mref );
|
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,
|
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value,
|
||||||
size_t size, int flags );
|
size_t size, int flags);
|
||||||
|
|
||||||
/* debugging */
|
/* debugging */
|
||||||
#define debug_double_inode(num, type)
|
#define debug_double_inode(num, type)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -55,36 +55,35 @@
|
|||||||
#define NTFS_LCNALLOC_BSIZE 4096
|
#define NTFS_LCNALLOC_BSIZE 4096
|
||||||
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
ZONE_MFT = 1,
|
ZONE_MFT = 1,
|
||||||
ZONE_DATA1 = 2,
|
ZONE_DATA1 = 2,
|
||||||
ZONE_DATA2 = 4
|
ZONE_DATA2 = 4
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static void ntfs_cluster_set_zone_pos( LCN start, LCN end, LCN *pos, LCN tc )
|
static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
|
||||||
{
|
{
|
||||||
ntfs_log_trace( "pos: %lld tc: %lld\n", ( long long )*pos, ( long long )tc );
|
ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, (long long)tc);
|
||||||
|
|
||||||
if ( tc >= end )
|
if (tc >= end)
|
||||||
*pos = start;
|
*pos = start;
|
||||||
else if ( tc >= start )
|
else if (tc >= start)
|
||||||
*pos = tc;
|
*pos = tc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ntfs_cluster_update_zone_pos( ntfs_volume *vol, u8 zone, LCN tc )
|
static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
||||||
{
|
{
|
||||||
ntfs_log_trace( "tc = %lld, zone = %d\n", ( long long )tc, zone );
|
ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone);
|
||||||
|
|
||||||
if ( zone == ZONE_MFT )
|
if (zone == ZONE_MFT)
|
||||||
ntfs_cluster_set_zone_pos( vol->mft_lcn, vol->mft_zone_end,
|
ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end,
|
||||||
&vol->mft_zone_pos, tc );
|
&vol->mft_zone_pos, tc);
|
||||||
else if ( zone == ZONE_DATA1 )
|
else if (zone == ZONE_DATA1)
|
||||||
ntfs_cluster_set_zone_pos( vol->mft_zone_end, vol->nr_clusters,
|
ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters,
|
||||||
&vol->data1_zone_pos, tc );
|
&vol->data1_zone_pos, tc);
|
||||||
else /* zone == ZONE_DATA2 */
|
else /* zone == ZONE_DATA2 */
|
||||||
ntfs_cluster_set_zone_pos( 0, vol->mft_zone_start,
|
ntfs_cluster_set_zone_pos(0, vol->mft_zone_start,
|
||||||
&vol->data2_zone_pos, tc );
|
&vol->data2_zone_pos, tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -93,86 +92,68 @@ static void ntfs_cluster_update_zone_pos( ntfs_volume *vol, u8 zone, LCN tc )
|
|||||||
* Next allocation will reuse the freed cluster
|
* Next allocation will reuse the freed cluster
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void update_full_status( ntfs_volume *vol, LCN lcn )
|
static void update_full_status(ntfs_volume *vol, LCN lcn)
|
||||||
{
|
{
|
||||||
if ( lcn >= vol->mft_zone_end )
|
if (lcn >= vol->mft_zone_end) {
|
||||||
{
|
if (vol->full_zones & ZONE_DATA1) {
|
||||||
if ( vol->full_zones & ZONE_DATA1 )
|
ntfs_cluster_update_zone_pos(vol, ZONE_DATA1, lcn);
|
||||||
{
|
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA1, lcn );
|
|
||||||
vol->full_zones &= ~ZONE_DATA1;
|
vol->full_zones &= ~ZONE_DATA1;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else if ( lcn < vol->mft_zone_start )
|
if (lcn < vol->mft_zone_start) {
|
||||||
{
|
if (vol->full_zones & ZONE_DATA2) {
|
||||||
if ( vol->full_zones & ZONE_DATA2 )
|
ntfs_cluster_update_zone_pos(vol, ZONE_DATA2, lcn);
|
||||||
{
|
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_DATA2, lcn );
|
|
||||||
vol->full_zones &= ~ZONE_DATA2;
|
vol->full_zones &= ~ZONE_DATA2;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
if (vol->full_zones & ZONE_MFT) {
|
||||||
{
|
ntfs_cluster_update_zone_pos(vol, ZONE_MFT, lcn);
|
||||||
if ( vol->full_zones & ZONE_MFT )
|
|
||||||
{
|
|
||||||
ntfs_cluster_update_zone_pos( vol, ZONE_MFT, lcn );
|
|
||||||
vol->full_zones &= ~ZONE_MFT;
|
vol->full_zones &= ~ZONE_MFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 max_empty_bit_range( unsigned char *buf, int size )
|
static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||||
{
|
{
|
||||||
int i, j, run = 0;
|
int i, j, run = 0;
|
||||||
int max_range = 0;
|
int max_range = 0;
|
||||||
s64 start_pos = -1;
|
s64 start_pos = -1;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace("Entering\n");
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while ( i < size )
|
while (i < size) {
|
||||||
{
|
switch (*buf) {
|
||||||
switch ( *buf )
|
|
||||||
{
|
|
||||||
case 0 :
|
case 0 :
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
buf++;
|
buf++;
|
||||||
run += 8;
|
run += 8;
|
||||||
i++;
|
i++;
|
||||||
}
|
} while ((i < size) && !*buf);
|
||||||
while ( ( i < size ) && !*buf );
|
|
||||||
break;
|
break;
|
||||||
case 255 :
|
case 255 :
|
||||||
if ( run > max_range )
|
if (run > max_range) {
|
||||||
{
|
|
||||||
max_range = run;
|
max_range = run;
|
||||||
start_pos = ( s64 )i * 8 - run;
|
start_pos = (s64)i * 8 - run;
|
||||||
}
|
}
|
||||||
run = 0;
|
run = 0;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
buf++;
|
buf++;
|
||||||
i++;
|
i++;
|
||||||
}
|
} while ((i < size) && (*buf == 255));
|
||||||
while ( ( i < size ) && ( *buf == 255 ) );
|
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
for ( j = 0; j < 8; j++ )
|
for (j = 0; j < 8; j++) {
|
||||||
{
|
|
||||||
|
|
||||||
int bit = *buf & ( 1 << j );
|
int bit = *buf & (1 << j);
|
||||||
|
|
||||||
if ( bit )
|
if (bit) {
|
||||||
{
|
if (run > max_range) {
|
||||||
if ( run > max_range )
|
|
||||||
{
|
|
||||||
max_range = run;
|
max_range = run;
|
||||||
start_pos = ( s64 )i * 8 + ( j - run );
|
start_pos = (s64)i * 8 + (j - run);
|
||||||
}
|
}
|
||||||
run = 0;
|
run = 0;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
run++;
|
run++;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@ -181,31 +162,30 @@ static s64 max_empty_bit_range( unsigned char *buf, int size )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( run > max_range )
|
if (run > max_range)
|
||||||
start_pos = ( s64 )i * 8 - run;
|
start_pos = (s64)i * 8 - run;
|
||||||
|
|
||||||
return start_pos;
|
return start_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bitmap_writeback( ntfs_volume *vol, s64 pos, s64 size, void *b,
|
static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||||
u8 *writeback )
|
u8 *writeback)
|
||||||
{
|
{
|
||||||
s64 written;
|
s64 written;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace("Entering\n");
|
||||||
|
|
||||||
if ( !*writeback )
|
if (!*writeback)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
*writeback = 0;
|
*writeback = 0;
|
||||||
|
|
||||||
written = ntfs_attr_pwrite( vol->lcnbmp_na, pos, size, b );
|
written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b);
|
||||||
if ( written != size )
|
if (written != size) {
|
||||||
{
|
if (!written)
|
||||||
if ( !written )
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Bitmap write error (%lld, %lld)",
|
ntfs_log_perror("Bitmap write error (%lld, %lld)",
|
||||||
( long long )pos, ( long long )size );
|
(long long)pos, (long long)size);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,8 +232,8 @@ static int bitmap_writeback( ntfs_volume *vol, s64 pos, s64 size, void *b,
|
|||||||
* 2) causes reduction in fragmentation.
|
* 2) causes reduction in fragmentation.
|
||||||
* The code is not optimized for speed.
|
* The code is not optimized for speed.
|
||||||
*/
|
*/
|
||||||
runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone )
|
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
|
||||||
{
|
{
|
||||||
LCN zone_start, zone_end; /* current search range */
|
LCN zone_start, zone_end; /* current search range */
|
||||||
LCN last_read_pos, lcn;
|
LCN last_read_pos, lcn;
|
||||||
@ -268,26 +248,23 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
u8 has_guess, used_zone_pos;
|
u8 has_guess, used_zone_pos;
|
||||||
int err = 0, rlpos, rlsize, buf_size;
|
int err = 0, rlpos, rlsize, buf_size;
|
||||||
|
|
||||||
ntfs_log_enter( "Entering with count = 0x%llx, start_lcn = 0x%llx, "
|
ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, "
|
||||||
"zone = %s_ZONE.\n", ( long long )count, ( long long )
|
"zone = %s_ZONE.\n", (long long)count, (long long)
|
||||||
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA" );
|
start_lcn, zone == MFT_ZONE ? "MFT" : "DATA");
|
||||||
|
|
||||||
if ( !vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
||||||
( s8 )zone < FIRST_ZONE || zone > LAST_ZONE )
|
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: vcn: %lld, count: %lld, lcn: %lld",
|
ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld",
|
||||||
__FUNCTION__, ( long long )start_vcn,
|
__FUNCTION__, (long long)start_vcn,
|
||||||
( long long )count, ( long long )start_lcn );
|
(long long)count, (long long)start_lcn);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return empty runlist if @count == 0 */
|
/* Return empty runlist if @count == 0 */
|
||||||
if ( !count )
|
if (!count) {
|
||||||
{
|
rl = ntfs_malloc(0x1000);
|
||||||
rl = ntfs_malloc( 0x1000 );
|
if (rl) {
|
||||||
if ( rl )
|
|
||||||
{
|
|
||||||
rl[0].vcn = start_vcn;
|
rl[0].vcn = start_vcn;
|
||||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||||
rl[0].length = 0;
|
rl[0].length = 0;
|
||||||
@ -295,8 +272,8 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = ntfs_malloc( NTFS_LCNALLOC_BSIZE );
|
buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
|
||||||
if ( !buf )
|
if (!buf)
|
||||||
goto out;
|
goto out;
|
||||||
/*
|
/*
|
||||||
* If no @start_lcn was requested, use the current zone
|
* If no @start_lcn was requested, use the current zone
|
||||||
@ -305,9 +282,8 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
has_guess = 1;
|
has_guess = 1;
|
||||||
zone_start = start_lcn;
|
zone_start = start_lcn;
|
||||||
|
|
||||||
if ( zone_start < 0 )
|
if (zone_start < 0) {
|
||||||
{
|
if (zone == DATA_ZONE)
|
||||||
if ( zone == DATA_ZONE )
|
|
||||||
zone_start = vol->data1_zone_pos;
|
zone_start = vol->data1_zone_pos;
|
||||||
else
|
else
|
||||||
zone_start = vol->mft_zone_pos;
|
zone_start = vol->mft_zone_pos;
|
||||||
@ -316,22 +292,17 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
|
|
||||||
used_zone_pos = has_guess ? 0 : 1;
|
used_zone_pos = has_guess ? 0 : 1;
|
||||||
|
|
||||||
if ( !zone_start || zone_start == vol->mft_zone_start ||
|
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||||
zone_start == vol->mft_zone_end )
|
zone_start == vol->mft_zone_end)
|
||||||
pass = 2;
|
pass = 2;
|
||||||
|
|
||||||
if ( zone_start < vol->mft_zone_start )
|
if (zone_start < vol->mft_zone_start) {
|
||||||
{
|
|
||||||
zone_end = vol->mft_zone_start;
|
zone_end = vol->mft_zone_start;
|
||||||
search_zone = ZONE_DATA2;
|
search_zone = ZONE_DATA2;
|
||||||
}
|
} else if (zone_start < vol->mft_zone_end) {
|
||||||
else if ( zone_start < vol->mft_zone_end )
|
|
||||||
{
|
|
||||||
zone_end = vol->mft_zone_end;
|
zone_end = vol->mft_zone_end;
|
||||||
search_zone = ZONE_MFT;
|
search_zone = ZONE_MFT;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
zone_end = vol->nr_clusters;
|
zone_end = vol->nr_clusters;
|
||||||
search_zone = ZONE_DATA1;
|
search_zone = ZONE_DATA1;
|
||||||
}
|
}
|
||||||
@ -341,47 +312,40 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
/* Loop until all clusters are allocated. */
|
/* Loop until all clusters are allocated. */
|
||||||
clusters = count;
|
clusters = count;
|
||||||
rlpos = rlsize = 0;
|
rlpos = rlsize = 0;
|
||||||
while ( 1 )
|
while (1) {
|
||||||
{
|
|
||||||
/* check whether we have exhausted the current zone */
|
/* check whether we have exhausted the current zone */
|
||||||
if ( search_zone & vol->full_zones )
|
if (search_zone & vol->full_zones)
|
||||||
goto zone_pass_done;
|
goto zone_pass_done;
|
||||||
last_read_pos = bmp_pos >> 3;
|
last_read_pos = bmp_pos >> 3;
|
||||||
br = ntfs_attr_pread( vol->lcnbmp_na, last_read_pos,
|
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos,
|
||||||
NTFS_LCNALLOC_BSIZE, buf );
|
NTFS_LCNALLOC_BSIZE, buf);
|
||||||
if ( br <= 0 )
|
if (br <= 0) {
|
||||||
{
|
if (!br)
|
||||||
if ( !br )
|
|
||||||
goto zone_pass_done;
|
goto zone_pass_done;
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_perror( "Reading $BITMAP failed" );
|
ntfs_log_perror("Reading $BITMAP failed");
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* We might have read less than NTFS_LCNALLOC_BSIZE bytes
|
* We might have read less than NTFS_LCNALLOC_BSIZE bytes
|
||||||
* if we are close to the end of the attribute.
|
* if we are close to the end of the attribute.
|
||||||
*/
|
*/
|
||||||
buf_size = ( int )br << 3;
|
buf_size = (int)br << 3;
|
||||||
lcn = bmp_pos & 7;
|
lcn = bmp_pos & 7;
|
||||||
bmp_pos &= ~7;
|
bmp_pos &= ~7;
|
||||||
writeback = 0;
|
writeback = 0;
|
||||||
|
|
||||||
while ( lcn < buf_size )
|
while (lcn < buf_size) {
|
||||||
{
|
byte = buf + (lcn >> 3);
|
||||||
byte = buf + ( lcn >> 3 );
|
bit = 1 << (lcn & 7);
|
||||||
bit = 1 << ( lcn & 7 );
|
if (has_guess) {
|
||||||
if ( has_guess )
|
if (*byte & bit) {
|
||||||
{
|
|
||||||
if ( *byte & bit )
|
|
||||||
{
|
|
||||||
has_guess = 0;
|
has_guess = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
lcn = max_empty_bit_range(buf, br);
|
||||||
{
|
if (lcn < 0)
|
||||||
lcn = max_empty_bit_range( buf, br );
|
|
||||||
if ( lcn < 0 )
|
|
||||||
break;
|
break;
|
||||||
has_guess = 1;
|
has_guess = 1;
|
||||||
continue;
|
continue;
|
||||||
@ -390,14 +354,12 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
/* First free bit is at lcn + bmp_pos. */
|
/* First free bit is at lcn + bmp_pos. */
|
||||||
|
|
||||||
/* Reallocate memory if necessary. */
|
/* Reallocate memory if necessary. */
|
||||||
if ( ( rlpos + 2 ) * ( int )sizeof( runlist ) >= rlsize )
|
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
||||||
{
|
|
||||||
rlsize += 4096;
|
rlsize += 4096;
|
||||||
trl = realloc( rl, rlsize );
|
trl = realloc(rl, rlsize);
|
||||||
if ( !trl )
|
if (!trl) {
|
||||||
{
|
|
||||||
err = ENOMEM;
|
err = ENOMEM;
|
||||||
ntfs_log_perror( "realloc() failed" );
|
ntfs_log_perror("realloc() failed");
|
||||||
goto wb_err_ret;
|
goto wb_err_ret;
|
||||||
}
|
}
|
||||||
rl = trl;
|
rl = trl;
|
||||||
@ -406,10 +368,10 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
/* Allocate the bitmap bit. */
|
/* Allocate the bitmap bit. */
|
||||||
*byte |= bit;
|
*byte |= bit;
|
||||||
writeback = 1;
|
writeback = 1;
|
||||||
if ( vol->free_clusters <= 0 )
|
if (vol->free_clusters <= 0)
|
||||||
ntfs_log_error( "Non-positive free clusters "
|
ntfs_log_error("Non-positive free clusters "
|
||||||
"(%lld)!\n",
|
"(%lld)!\n",
|
||||||
( long long )vol->free_clusters );
|
(long long)vol->free_clusters);
|
||||||
else
|
else
|
||||||
vol->free_clusters--;
|
vol->free_clusters--;
|
||||||
|
|
||||||
@ -417,26 +379,22 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
* Coalesce with previous run if adjacent LCNs.
|
* Coalesce with previous run if adjacent LCNs.
|
||||||
* Otherwise, append a new run.
|
* Otherwise, append a new run.
|
||||||
*/
|
*/
|
||||||
if ( prev_lcn == lcn + bmp_pos - prev_run_len && rlpos )
|
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
||||||
{
|
ntfs_log_debug("Cluster coalesce: prev_lcn: "
|
||||||
ntfs_log_debug( "Cluster coalesce: prev_lcn: "
|
|
||||||
"%lld lcn: %lld bmp_pos: %lld "
|
"%lld lcn: %lld bmp_pos: %lld "
|
||||||
"prev_run_len: %lld\n",
|
"prev_run_len: %lld\n",
|
||||||
( long long )prev_lcn,
|
(long long)prev_lcn,
|
||||||
( long long )lcn, ( long long )bmp_pos,
|
(long long)lcn, (long long)bmp_pos,
|
||||||
( long long )prev_run_len );
|
(long long)prev_run_len);
|
||||||
rl[rlpos - 1].length = ++prev_run_len;
|
rl[rlpos - 1].length = ++prev_run_len;
|
||||||
}
|
} else {
|
||||||
else
|
if (rlpos)
|
||||||
{
|
|
||||||
if ( rlpos )
|
|
||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||||
prev_run_len;
|
prev_run_len;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
rl[rlpos].vcn = start_vcn;
|
rl[rlpos].vcn = start_vcn;
|
||||||
ntfs_log_debug( "Start_vcn: %lld\n",
|
ntfs_log_debug("Start_vcn: %lld\n",
|
||||||
( long long )start_vcn );
|
(long long)start_vcn);
|
||||||
}
|
}
|
||||||
|
|
||||||
rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
|
rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
|
||||||
@ -444,68 +402,63 @@ runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
|||||||
rlpos++;
|
rlpos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "RUN: %-16lld %-16lld %-16lld\n",
|
ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n",
|
||||||
( long long )rl[rlpos - 1].vcn,
|
(long long)rl[rlpos - 1].vcn,
|
||||||
( long long )rl[rlpos - 1].lcn,
|
(long long)rl[rlpos - 1].lcn,
|
||||||
( long long )rl[rlpos - 1].length );
|
(long long)rl[rlpos - 1].length);
|
||||||
/* Done? */
|
/* Done? */
|
||||||
if ( !--clusters )
|
if (!--clusters) {
|
||||||
{
|
if (used_zone_pos)
|
||||||
if ( used_zone_pos )
|
ntfs_cluster_update_zone_pos(vol,
|
||||||
ntfs_cluster_update_zone_pos( vol,
|
|
||||||
search_zone, lcn + bmp_pos + 1 +
|
search_zone, lcn + bmp_pos + 1 +
|
||||||
NTFS_LCNALLOC_SKIP );
|
NTFS_LCNALLOC_SKIP);
|
||||||
goto done_ret;
|
goto done_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
lcn++;
|
lcn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !used_zone_pos )
|
if (!used_zone_pos) {
|
||||||
{
|
|
||||||
|
|
||||||
used_zone_pos = 1;
|
used_zone_pos = 1;
|
||||||
|
|
||||||
if ( search_zone == ZONE_MFT )
|
if (search_zone == ZONE_MFT)
|
||||||
zone_start = vol->mft_zone_pos;
|
zone_start = vol->mft_zone_pos;
|
||||||
else if ( search_zone == ZONE_DATA1 )
|
else if (search_zone == ZONE_DATA1)
|
||||||
zone_start = vol->data1_zone_pos;
|
zone_start = vol->data1_zone_pos;
|
||||||
else
|
else
|
||||||
zone_start = vol->data2_zone_pos;
|
zone_start = vol->data2_zone_pos;
|
||||||
|
|
||||||
if ( !zone_start || zone_start == vol->mft_zone_start ||
|
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||||
zone_start == vol->mft_zone_end )
|
zone_start == vol->mft_zone_end)
|
||||||
pass = 2;
|
pass = 2;
|
||||||
bmp_pos = zone_start;
|
bmp_pos = zone_start;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
bmp_pos += buf_size;
|
bmp_pos += buf_size;
|
||||||
|
|
||||||
if ( bmp_pos < zone_end )
|
if (bmp_pos < zone_end)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
zone_pass_done:
|
zone_pass_done:
|
||||||
ntfs_log_trace( "Finished current zone pass(%i).\n", pass );
|
ntfs_log_trace("Finished current zone pass(%i).\n", pass);
|
||||||
if ( pass == 1 )
|
if (pass == 1) {
|
||||||
{
|
|
||||||
pass = 2;
|
pass = 2;
|
||||||
zone_end = zone_start;
|
zone_end = zone_start;
|
||||||
|
|
||||||
if ( search_zone == ZONE_MFT )
|
if (search_zone == ZONE_MFT)
|
||||||
zone_start = vol->mft_zone_start;
|
zone_start = vol->mft_zone_start;
|
||||||
else if ( search_zone == ZONE_DATA1 )
|
else if (search_zone == ZONE_DATA1)
|
||||||
zone_start = vol->mft_zone_end;
|
zone_start = vol->mft_zone_end;
|
||||||
else
|
else
|
||||||
zone_start = 0;
|
zone_start = 0;
|
||||||
|
|
||||||
/* Sanity check. */
|
/* Sanity check. */
|
||||||
if ( zone_end < zone_start )
|
if (zone_end < zone_start)
|
||||||
zone_end = zone_start;
|
zone_end = zone_start;
|
||||||
|
|
||||||
bmp_pos = zone_start;
|
bmp_pos = zone_start;
|
||||||
@ -516,106 +469,98 @@ zone_pass_done:
|
|||||||
done_zones_check:
|
done_zones_check:
|
||||||
done_zones |= search_zone;
|
done_zones |= search_zone;
|
||||||
vol->full_zones |= search_zone;
|
vol->full_zones |= search_zone;
|
||||||
if ( done_zones < ( ZONE_MFT + ZONE_DATA1 + ZONE_DATA2 ) )
|
if (done_zones < (ZONE_MFT + ZONE_DATA1 + ZONE_DATA2)) {
|
||||||
{
|
ntfs_log_trace("Switching zone.\n");
|
||||||
ntfs_log_trace( "Switching zone.\n" );
|
|
||||||
pass = 1;
|
pass = 1;
|
||||||
if ( rlpos )
|
if (rlpos) {
|
||||||
{
|
|
||||||
LCN tc = rl[rlpos - 1].lcn +
|
LCN tc = rl[rlpos - 1].lcn +
|
||||||
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||||
|
|
||||||
if ( used_zone_pos )
|
if (used_zone_pos)
|
||||||
ntfs_cluster_update_zone_pos( vol,
|
ntfs_cluster_update_zone_pos(vol,
|
||||||
search_zone, tc );
|
search_zone, tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( search_zone )
|
switch (search_zone) {
|
||||||
{
|
|
||||||
case ZONE_MFT:
|
case ZONE_MFT:
|
||||||
ntfs_log_trace( "Zone switch: mft -> data1\n" );
|
ntfs_log_trace("Zone switch: mft -> data1\n");
|
||||||
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
switch_to_data1_zone: search_zone = ZONE_DATA1;
|
||||||
zone_start = vol->data1_zone_pos;
|
zone_start = vol->data1_zone_pos;
|
||||||
zone_end = vol->nr_clusters;
|
zone_end = vol->nr_clusters;
|
||||||
if ( zone_start == vol->mft_zone_end )
|
if (zone_start == vol->mft_zone_end)
|
||||||
pass = 2;
|
pass = 2;
|
||||||
break;
|
break;
|
||||||
case ZONE_DATA1:
|
case ZONE_DATA1:
|
||||||
ntfs_log_trace( "Zone switch: data1 -> data2\n" );
|
ntfs_log_trace("Zone switch: data1 -> data2\n");
|
||||||
search_zone = ZONE_DATA2;
|
search_zone = ZONE_DATA2;
|
||||||
zone_start = vol->data2_zone_pos;
|
zone_start = vol->data2_zone_pos;
|
||||||
zone_end = vol->mft_zone_start;
|
zone_end = vol->mft_zone_start;
|
||||||
if ( !zone_start )
|
if (!zone_start)
|
||||||
pass = 2;
|
pass = 2;
|
||||||
break;
|
break;
|
||||||
case ZONE_DATA2:
|
case ZONE_DATA2:
|
||||||
if ( !( done_zones & ZONE_DATA1 ) )
|
if (!(done_zones & ZONE_DATA1)) {
|
||||||
{
|
ntfs_log_trace("data2 -> data1\n");
|
||||||
ntfs_log_trace( "data2 -> data1\n" );
|
|
||||||
goto switch_to_data1_zone;
|
goto switch_to_data1_zone;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Zone switch: data2 -> mft\n" );
|
ntfs_log_trace("Zone switch: data2 -> mft\n");
|
||||||
search_zone = ZONE_MFT;
|
search_zone = ZONE_MFT;
|
||||||
zone_start = vol->mft_zone_pos;
|
zone_start = vol->mft_zone_pos;
|
||||||
zone_end = vol->mft_zone_end;
|
zone_end = vol->mft_zone_end;
|
||||||
if ( zone_start == vol->mft_zone_start )
|
if (zone_start == vol->mft_zone_start)
|
||||||
pass = 2;
|
pass = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bmp_pos = zone_start;
|
bmp_pos = zone_start;
|
||||||
|
|
||||||
if ( zone_start == zone_end )
|
if (zone_start == zone_end) {
|
||||||
{
|
ntfs_log_trace("Empty zone, skipped.\n");
|
||||||
ntfs_log_trace( "Empty zone, skipped.\n" );
|
|
||||||
goto done_zones_check;
|
goto done_zones_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_trace( "All zones are finished, no space on device.\n" );
|
ntfs_log_trace("All zones are finished, no space on device.\n");
|
||||||
err = ENOSPC;
|
err = ENOSPC;
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
done_ret:
|
done_ret:
|
||||||
ntfs_log_debug( "At done_ret.\n" );
|
ntfs_log_debug("At done_ret.\n");
|
||||||
/* Add runlist terminator element. */
|
/* Add runlist terminator element. */
|
||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||||
rl[rlpos].length = 0;
|
rl[rlpos].length = 0;
|
||||||
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
goto err_ret;
|
goto err_ret;
|
||||||
}
|
}
|
||||||
done_err_ret:
|
done_err_ret:
|
||||||
free( buf );
|
free(buf);
|
||||||
if ( err )
|
if (err) {
|
||||||
{
|
|
||||||
errno = err;
|
errno = err;
|
||||||
ntfs_log_perror( "Failed to allocate clusters" );
|
ntfs_log_perror("Failed to allocate clusters");
|
||||||
rl = NULL;
|
rl = NULL;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return rl;
|
return rl;
|
||||||
|
|
||||||
wb_err_ret:
|
wb_err_ret:
|
||||||
ntfs_log_trace( "At wb_err_ret.\n" );
|
ntfs_log_trace("At wb_err_ret.\n");
|
||||||
if ( bitmap_writeback( vol, last_read_pos, br, buf, &writeback ) )
|
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
|
||||||
err = errno;
|
err = errno;
|
||||||
err_ret:
|
err_ret:
|
||||||
ntfs_log_trace( "At err_ret.\n" );
|
ntfs_log_trace("At err_ret.\n");
|
||||||
if ( rl )
|
if (rl) {
|
||||||
{
|
|
||||||
/* Add runlist terminator element. */
|
/* Add runlist terminator element. */
|
||||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||||
rl[rlpos].length = 0;
|
rl[rlpos].length = 0;
|
||||||
ntfs_debug_runlist_dump( rl );
|
ntfs_debug_runlist_dump(rl);
|
||||||
ntfs_cluster_free_from_rl( vol, rl );
|
ntfs_cluster_free_from_rl(vol, rl);
|
||||||
free( rl );
|
free(rl);
|
||||||
rl = NULL;
|
rl = NULL;
|
||||||
}
|
}
|
||||||
goto done_err_ret;
|
goto done_err_ret;
|
||||||
@ -628,29 +573,26 @@ err_ret:
|
|||||||
*
|
*
|
||||||
* On success return 0 and on error return -1 with errno set to the error code.
|
* On success return 0 and on error return -1 with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
int ntfs_cluster_free_from_rl( ntfs_volume *vol, runlist *rl )
|
int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||||
{
|
{
|
||||||
s64 nr_freed = 0;
|
s64 nr_freed = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
|
|
||||||
for ( ; rl->length; rl++ )
|
for (; rl->length; rl++) {
|
||||||
{
|
|
||||||
|
|
||||||
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||||
( long long )rl->lcn, ( long long )rl->length );
|
(long long)rl->lcn, (long long)rl->length);
|
||||||
|
|
||||||
if ( rl->lcn >= 0 )
|
if (rl->lcn >= 0) {
|
||||||
{
|
update_full_status(vol,rl->lcn);
|
||||||
update_full_status( vol, rl->lcn );
|
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
rl->length)) {
|
||||||
rl->length ) )
|
ntfs_log_perror("Cluster deallocation failed "
|
||||||
{
|
|
||||||
ntfs_log_perror( "Cluster deallocation failed "
|
|
||||||
"(%lld, %lld)",
|
"(%lld, %lld)",
|
||||||
( long long )rl->lcn,
|
(long long)rl->lcn,
|
||||||
( long long )rl->length );
|
(long long)rl->length);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nr_freed += rl->length ;
|
nr_freed += rl->length ;
|
||||||
@ -660,10 +602,10 @@ int ntfs_cluster_free_from_rl( ntfs_volume *vol, runlist *rl )
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
vol->free_clusters += nr_freed;
|
vol->free_clusters += nr_freed;
|
||||||
if ( vol->free_clusters > vol->nr_clusters )
|
if (vol->free_clusters > vol->nr_clusters)
|
||||||
ntfs_log_error( "Too many free clusters (%lld > %lld)!",
|
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||||
( long long )vol->free_clusters,
|
(long long)vol->free_clusters,
|
||||||
( long long )vol->nr_clusters );
|
(long long)vol->nr_clusters);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,25 +614,23 @@ out:
|
|||||||
* Returns 0 if successful
|
* Returns 0 if successful
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_cluster_free_basic( ntfs_volume *vol, s64 lcn, s64 count )
|
int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
|
||||||
{
|
{
|
||||||
s64 nr_freed = 0;
|
s64 nr_freed = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
ntfs_log_trace( "Dealloc lcn 0x%llx, len 0x%llx.\n",
|
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||||
( long long )lcn, ( long long )count );
|
(long long)lcn, (long long)count);
|
||||||
|
|
||||||
if ( lcn >= 0 )
|
if (lcn >= 0) {
|
||||||
{
|
update_full_status(vol,lcn);
|
||||||
update_full_status( vol, lcn );
|
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn,
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, lcn,
|
count)) {
|
||||||
count ) )
|
ntfs_log_perror("Cluster deallocation failed "
|
||||||
{
|
|
||||||
ntfs_log_perror( "Cluster deallocation failed "
|
|
||||||
"(%lld, %lld)",
|
"(%lld, %lld)",
|
||||||
( long long )lcn,
|
(long long)lcn,
|
||||||
( long long )count );
|
(long long)count);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nr_freed += count;
|
nr_freed += count;
|
||||||
@ -698,10 +638,10 @@ int ntfs_cluster_free_basic( ntfs_volume *vol, s64 lcn, s64 count )
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
vol->free_clusters += nr_freed;
|
vol->free_clusters += nr_freed;
|
||||||
if ( vol->free_clusters > vol->nr_clusters )
|
if (vol->free_clusters > vol->nr_clusters)
|
||||||
ntfs_log_error( "Too many free clusters (%lld > %lld)!",
|
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||||
( long long )vol->free_clusters,
|
(long long)vol->free_clusters,
|
||||||
( long long )vol->nr_clusters );
|
(long long)vol->nr_clusters);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,37 +661,34 @@ out:
|
|||||||
* On success return the number of deallocated clusters (not counting sparse
|
* On success return the number of deallocated clusters (not counting sparse
|
||||||
* clusters) and on error return -1 with errno set to the error code.
|
* clusters) and on error return -1 with errno set to the error code.
|
||||||
*/
|
*/
|
||||||
int ntfs_cluster_free( ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count )
|
int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||||
{
|
{
|
||||||
runlist *rl;
|
runlist *rl;
|
||||||
s64 delta, to_free, nr_freed = 0;
|
s64 delta, to_free, nr_freed = 0;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if ( !vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
||||||
( count < 0 && count != -1 ) )
|
(count < 0 && count != -1)) {
|
||||||
{
|
ntfs_log_trace("Invalid arguments!\n");
|
||||||
ntfs_log_trace( "Invalid arguments!\n" );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_enter( "Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
|
ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
|
||||||
"vcn 0x%llx.\n", ( unsigned long long )na->ni->mft_no,
|
"vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
|
||||||
na->type, ( long long )count, ( long long )start_vcn );
|
na->type, (long long)count, (long long)start_vcn);
|
||||||
|
|
||||||
rl = ntfs_attr_find_vcn( na, start_vcn );
|
rl = ntfs_attr_find_vcn(na, start_vcn);
|
||||||
if ( !rl )
|
if (!rl) {
|
||||||
{
|
if (errno == ENOENT)
|
||||||
if ( errno == ENOENT )
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Unexpected lcn (%lld)", __FUNCTION__,
|
ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
|
||||||
( long long )rl->lcn );
|
(long long)rl->lcn);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,81 +697,75 @@ int ntfs_cluster_free( ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count
|
|||||||
|
|
||||||
/* The number of clusters in this run that need freeing. */
|
/* The number of clusters in this run that need freeing. */
|
||||||
to_free = rl->length - delta;
|
to_free = rl->length - delta;
|
||||||
if ( count >= 0 && to_free > count )
|
if (count >= 0 && to_free > count)
|
||||||
to_free = count;
|
to_free = count;
|
||||||
|
|
||||||
if ( rl->lcn != LCN_HOLE )
|
if (rl->lcn != LCN_HOLE) {
|
||||||
{
|
|
||||||
/* Do the actual freeing of the clusters in this run. */
|
/* Do the actual freeing of the clusters in this run. */
|
||||||
update_full_status( vol, rl->lcn + delta );
|
update_full_status(vol,rl->lcn + delta);
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn + delta,
|
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
|
||||||
to_free ) )
|
to_free))
|
||||||
goto leave;
|
goto leave;
|
||||||
nr_freed = to_free;
|
nr_freed = to_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Go to the next run and adjust the number of clusters left to free. */
|
/* Go to the next run and adjust the number of clusters left to free. */
|
||||||
++rl;
|
++rl;
|
||||||
if ( count >= 0 )
|
if (count >= 0)
|
||||||
count -= to_free;
|
count -= to_free;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop over the remaining runs, using @count as a capping value, and
|
* Loop over the remaining runs, using @count as a capping value, and
|
||||||
* free them.
|
* free them.
|
||||||
*/
|
*/
|
||||||
for ( ; rl->length && count != 0; ++rl )
|
for (; rl->length && count != 0; ++rl) {
|
||||||
{
|
|
||||||
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
||||||
// list support! (AIA)
|
// list support! (AIA)
|
||||||
if ( rl->lcn < 0 && rl->lcn != LCN_HOLE )
|
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||||
{
|
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: Invalid lcn (%lli)",
|
ntfs_log_perror("%s: Invalid lcn (%lli)",
|
||||||
__FUNCTION__, ( long long )rl->lcn );
|
__FUNCTION__, (long long)rl->lcn);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The number of clusters in this run that need freeing. */
|
/* The number of clusters in this run that need freeing. */
|
||||||
to_free = rl->length;
|
to_free = rl->length;
|
||||||
if ( count >= 0 && to_free > count )
|
if (count >= 0 && to_free > count)
|
||||||
to_free = count;
|
to_free = count;
|
||||||
|
|
||||||
if ( rl->lcn != LCN_HOLE )
|
if (rl->lcn != LCN_HOLE) {
|
||||||
{
|
update_full_status(vol,rl->lcn);
|
||||||
update_full_status( vol, rl->lcn );
|
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||||
if ( ntfs_bitmap_clear_run( vol->lcnbmp_na, rl->lcn,
|
to_free)) {
|
||||||
to_free ) )
|
|
||||||
{
|
|
||||||
// FIXME: Eeek! We need rollback! (AIA)
|
// FIXME: Eeek! We need rollback! (AIA)
|
||||||
ntfs_log_perror( "%s: Clearing bitmap run failed",
|
ntfs_log_perror("%s: Clearing bitmap run failed",
|
||||||
__FUNCTION__ );
|
__FUNCTION__);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
nr_freed += to_free;
|
nr_freed += to_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( count >= 0 )
|
if (count >= 0)
|
||||||
count -= to_free;
|
count -= to_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( count != -1 && count != 0 )
|
if (count != -1 && count != 0) {
|
||||||
{
|
|
||||||
// FIXME: Eeek! BUG()
|
// FIXME: Eeek! BUG()
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "%s: count still not zero (%lld)", __FUNCTION__,
|
ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
|
||||||
( long long )count );
|
(long long)count);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nr_freed;
|
ret = nr_freed;
|
||||||
out:
|
out:
|
||||||
vol->free_clusters += nr_freed ;
|
vol->free_clusters += nr_freed ;
|
||||||
if ( vol->free_clusters > vol->nr_clusters )
|
if (vol->free_clusters > vol->nr_clusters)
|
||||||
ntfs_log_error( "Too many free clusters (%lld > %lld)!",
|
ntfs_log_error("Too many free clusters (%lld > %lld)!",
|
||||||
( long long )vol->free_clusters,
|
(long long)vol->free_clusters,
|
||||||
( long long )vol->nr_clusters );
|
(long long)vol->nr_clusters);
|
||||||
leave:
|
leave:
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -31,22 +31,21 @@
|
|||||||
/**
|
/**
|
||||||
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
FIRST_ZONE = 0, /* For sanity checking. */
|
FIRST_ZONE = 0, /* For sanity checking. */
|
||||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||||
LAST_ZONE = 1, /* For sanity checking. */
|
LAST_ZONE = 1, /* For sanity checking. */
|
||||||
} NTFS_CLUSTER_ALLOCATION_ZONES;
|
} NTFS_CLUSTER_ALLOCATION_ZONES;
|
||||||
|
|
||||||
extern runlist *ntfs_cluster_alloc( ntfs_volume *vol, VCN start_vcn, s64 count,
|
extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone );
|
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_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_basic(ntfs_volume *vol, s64 lcn, s64 count);
|
||||||
|
|
||||||
extern int ntfs_cluster_free( ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
||||||
s64 count );
|
s64 count);
|
||||||
|
|
||||||
#endif /* defined _NTFS_LCNALLOC_H */
|
#endif /* defined _NTFS_LCNALLOC_H */
|
||||||
|
|
||||||
|
@ -54,73 +54,67 @@
|
|||||||
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
||||||
* require the full restart page.
|
* require the full restart page.
|
||||||
*/
|
*/
|
||||||
static BOOL ntfs_check_restart_page_header( RESTART_PAGE_HEADER *rp, s64 pos )
|
static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||||
{
|
{
|
||||||
u32 logfile_system_page_size, logfile_log_page_size;
|
u32 logfile_system_page_size, logfile_log_page_size;
|
||||||
u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
|
u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
|
||||||
BOOL have_usa = TRUE;
|
BOOL have_usa = TRUE;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
/*
|
/*
|
||||||
* If the system or log page sizes are smaller than the ntfs block size
|
* If the system or log page sizes are smaller than the ntfs block size
|
||||||
* or either is not a power of 2 we cannot handle this log file.
|
* or either is not a power of 2 we cannot handle this log file.
|
||||||
*/
|
*/
|
||||||
logfile_system_page_size = le32_to_cpu( rp->system_page_size );
|
logfile_system_page_size = le32_to_cpu(rp->system_page_size);
|
||||||
logfile_log_page_size = le32_to_cpu( rp->log_page_size );
|
logfile_log_page_size = le32_to_cpu(rp->log_page_size);
|
||||||
if ( logfile_system_page_size < NTFS_BLOCK_SIZE ||
|
if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
|
||||||
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
||||||
logfile_system_page_size &
|
logfile_system_page_size &
|
||||||
( logfile_system_page_size - 1 ) ||
|
(logfile_system_page_size - 1) ||
|
||||||
logfile_log_page_size & ( logfile_log_page_size - 1 ) )
|
logfile_log_page_size & (logfile_log_page_size - 1)) {
|
||||||
{
|
ntfs_log_error("$LogFile uses unsupported page size.\n");
|
||||||
ntfs_log_error( "$LogFile uses unsupported page size.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* We must be either at !pos (1st restart page) or at pos = system page
|
* We must be either at !pos (1st restart page) or at pos = system page
|
||||||
* size (2nd restart page).
|
* size (2nd restart page).
|
||||||
*/
|
*/
|
||||||
if ( pos && pos != logfile_system_page_size )
|
if (pos && pos != logfile_system_page_size) {
|
||||||
{
|
ntfs_log_error("Found restart area in incorrect "
|
||||||
ntfs_log_error( "Found restart area in incorrect "
|
"position in $LogFile.\n");
|
||||||
"position in $LogFile.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* We only know how to handle version 1.1. */
|
/* We only know how to handle version 1.1. */
|
||||||
if ( sle16_to_cpu( rp->major_ver ) != 1 ||
|
if (sle16_to_cpu(rp->major_ver) != 1 ||
|
||||||
sle16_to_cpu( rp->minor_ver ) != 1 )
|
sle16_to_cpu(rp->minor_ver) != 1) {
|
||||||
{
|
ntfs_log_error("$LogFile version %i.%i is not "
|
||||||
ntfs_log_error( "$LogFile version %i.%i is not "
|
|
||||||
"supported. (This driver supports version "
|
"supported. (This driver supports version "
|
||||||
"1.1 only.)\n", ( int )sle16_to_cpu( rp->major_ver ),
|
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
|
||||||
( int )sle16_to_cpu( rp->minor_ver ) );
|
(int)sle16_to_cpu(rp->minor_ver));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If chkdsk has been run the restart page may not be protected by an
|
* If chkdsk has been run the restart page may not be protected by an
|
||||||
* update sequence array.
|
* update sequence array.
|
||||||
*/
|
*/
|
||||||
if ( ntfs_is_chkd_record( rp->magic ) && !le16_to_cpu( rp->usa_count ) )
|
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
|
||||||
{
|
|
||||||
have_usa = FALSE;
|
have_usa = FALSE;
|
||||||
goto skip_usa_checks;
|
goto skip_usa_checks;
|
||||||
}
|
}
|
||||||
/* Verify the size of the update sequence array. */
|
/* Verify the size of the update sequence array. */
|
||||||
usa_count = 1 + ( logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS );
|
usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
|
||||||
if ( usa_count != le16_to_cpu( rp->usa_count ) )
|
if (usa_count != le16_to_cpu(rp->usa_count)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart page specifies "
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
"inconsistent update sequence array count.\n");
|
||||||
"inconsistent update sequence array count.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* Verify the position of the update sequence array. */
|
/* Verify the position of the update sequence array. */
|
||||||
usa_ofs = le16_to_cpu( rp->usa_ofs );
|
usa_ofs = le16_to_cpu(rp->usa_ofs);
|
||||||
usa_end = usa_ofs + usa_count * sizeof( u16 );
|
usa_end = usa_ofs + usa_count * sizeof(u16);
|
||||||
if ( usa_ofs < sizeof( RESTART_PAGE_HEADER ) ||
|
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
|
||||||
usa_end > NTFS_BLOCK_SIZE - sizeof( u16 ) )
|
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart page specifies "
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
"inconsistent update sequence array offset.\n");
|
||||||
"inconsistent update sequence array offset.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
skip_usa_checks:
|
skip_usa_checks:
|
||||||
@ -130,26 +124,24 @@ skip_usa_checks:
|
|||||||
* - after the update sequence array, and
|
* - after the update sequence array, and
|
||||||
* - within the system page size.
|
* - within the system page size.
|
||||||
*/
|
*/
|
||||||
ra_ofs = le16_to_cpu( rp->restart_area_offset );
|
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||||
if ( ra_ofs & 7 || ( have_usa ? ra_ofs < usa_end :
|
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
|
||||||
ra_ofs < sizeof( RESTART_PAGE_HEADER ) ) ||
|
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
|
||||||
ra_ofs > logfile_system_page_size )
|
ra_ofs > logfile_system_page_size) {
|
||||||
{
|
ntfs_log_error("$LogFile restart page specifies "
|
||||||
ntfs_log_error( "$LogFile restart page specifies "
|
"inconsistent restart area offset.\n");
|
||||||
"inconsistent restart area offset.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
||||||
* set.
|
* set.
|
||||||
*/
|
*/
|
||||||
if ( !ntfs_is_chkd_record( rp->magic ) && sle64_to_cpu( rp->chkdsk_lsn ) )
|
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart page is not modified "
|
||||||
ntfs_log_error( "$LogFile restart page is not modified "
|
"by chkdsk but a chkdsk LSN is specified.\n");
|
||||||
"by chkdsk but a chkdsk LSN is specified.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace("Done.\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,26 +158,25 @@ skip_usa_checks:
|
|||||||
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
||||||
* require the full restart page.
|
* require the full restart page.
|
||||||
*/
|
*/
|
||||||
static BOOL ntfs_check_restart_area( RESTART_PAGE_HEADER *rp )
|
static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||||
{
|
{
|
||||||
u64 file_size;
|
u64 file_size;
|
||||||
RESTART_AREA *ra;
|
RESTART_AREA *ra;
|
||||||
u16 ra_ofs, ra_len, ca_ofs;
|
u16 ra_ofs, ra_len, ca_ofs;
|
||||||
u8 fs_bits;
|
u8 fs_bits;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
ra_ofs = le16_to_cpu( rp->restart_area_offset );
|
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||||
ra = ( RESTART_AREA* )( ( u8* )rp + ra_ofs );
|
ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
|
||||||
/*
|
/*
|
||||||
* Everything before ra->file_size must be before the first word
|
* Everything before ra->file_size must be before the first word
|
||||||
* protected by an update sequence number. This ensures that it is
|
* protected by an update sequence number. This ensures that it is
|
||||||
* safe to access ra->client_array_offset.
|
* safe to access ra->client_array_offset.
|
||||||
*/
|
*/
|
||||||
if ( ra_ofs + offsetof( RESTART_AREA, file_size ) >
|
if (ra_ofs + offsetof(RESTART_AREA, file_size) >
|
||||||
NTFS_BLOCK_SIZE - sizeof( u16 ) )
|
NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"inconsistent file offset.\n");
|
||||||
"inconsistent file offset.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -195,13 +186,12 @@ static BOOL ntfs_check_restart_area( RESTART_PAGE_HEADER *rp )
|
|||||||
* restart area elements safely. Also, the client array offset must be
|
* restart area elements safely. Also, the client array offset must be
|
||||||
* aligned to an 8-byte boundary.
|
* aligned to an 8-byte boundary.
|
||||||
*/
|
*/
|
||||||
ca_ofs = le16_to_cpu( ra->client_array_offset );
|
ca_ofs = le16_to_cpu(ra->client_array_offset);
|
||||||
if ( ( ( ca_ofs + 7 ) & ~7 ) != ca_ofs ||
|
if (((ca_ofs + 7) & ~7) != ca_ofs ||
|
||||||
ra_ofs + ca_ofs > ( u16 )( NTFS_BLOCK_SIZE -
|
ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE -
|
||||||
sizeof( u16 ) ) )
|
sizeof(u16))) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"inconsistent client array offset.\n");
|
||||||
"inconsistent client array offset.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -209,17 +199,16 @@ static BOOL ntfs_check_restart_area( RESTART_PAGE_HEADER *rp )
|
|||||||
* calculated manually and as specified by ra->restart_area_length.
|
* calculated manually and as specified by ra->restart_area_length.
|
||||||
* Also, the calculated length must not exceed the specified length.
|
* Also, the calculated length must not exceed the specified length.
|
||||||
*/
|
*/
|
||||||
ra_len = ca_ofs + le16_to_cpu( ra->log_clients ) *
|
ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
|
||||||
sizeof( LOG_CLIENT_RECORD );
|
sizeof(LOG_CLIENT_RECORD);
|
||||||
if ( ( u32 )( ra_ofs + ra_len ) > le32_to_cpu( rp->system_page_size ) ||
|
if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) ||
|
||||||
( u32 )( ra_ofs + le16_to_cpu( ra->restart_area_length ) ) >
|
(u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) >
|
||||||
le32_to_cpu( rp->system_page_size ) ||
|
le32_to_cpu(rp->system_page_size) ||
|
||||||
ra_len > le16_to_cpu( ra->restart_area_length ) )
|
ra_len > le16_to_cpu(ra->restart_area_length)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area is out of bounds "
|
||||||
ntfs_log_error( "$LogFile restart area is out of bounds "
|
|
||||||
"of the system page size specified by the "
|
"of the system page size specified by the "
|
||||||
"restart page header and/or the specified "
|
"restart page header and/or the specified "
|
||||||
"restart area length is inconsistent.\n" );
|
"restart area length is inconsistent.\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -227,51 +216,46 @@ static BOOL ntfs_check_restart_area( RESTART_PAGE_HEADER *rp )
|
|||||||
* LOGFILE_NO_CLIENT or less than ra->log_clients or they are
|
* LOGFILE_NO_CLIENT or less than ra->log_clients or they are
|
||||||
* overflowing the client array.
|
* overflowing the client array.
|
||||||
*/
|
*/
|
||||||
if ( ( ra->client_free_list != LOGFILE_NO_CLIENT &&
|
if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
|
||||||
le16_to_cpu( ra->client_free_list ) >=
|
le16_to_cpu(ra->client_free_list) >=
|
||||||
le16_to_cpu( ra->log_clients ) ) ||
|
le16_to_cpu(ra->log_clients)) ||
|
||||||
( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
(ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||||
le16_to_cpu( ra->client_in_use_list ) >=
|
le16_to_cpu(ra->client_in_use_list) >=
|
||||||
le16_to_cpu( ra->log_clients ) ) )
|
le16_to_cpu(ra->log_clients))) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"overflowing client free and/or in use lists.\n");
|
||||||
"overflowing client free and/or in use lists.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Check ra->seq_number_bits against ra->file_size for consistency.
|
* Check ra->seq_number_bits against ra->file_size for consistency.
|
||||||
* We cannot just use ffs() because the file size is not a power of 2.
|
* We cannot just use ffs() because the file size is not a power of 2.
|
||||||
*/
|
*/
|
||||||
file_size = ( u64 )sle64_to_cpu( ra->file_size );
|
file_size = (u64)sle64_to_cpu(ra->file_size);
|
||||||
fs_bits = 0;
|
fs_bits = 0;
|
||||||
while ( file_size )
|
while (file_size) {
|
||||||
{
|
|
||||||
file_size >>= 1;
|
file_size >>= 1;
|
||||||
fs_bits++;
|
fs_bits++;
|
||||||
}
|
}
|
||||||
if ( le32_to_cpu( ra->seq_number_bits ) != ( u32 )( 67 - fs_bits ) )
|
if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"inconsistent sequence number bits.\n");
|
||||||
"inconsistent sequence number bits.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* The log record header length must be a multiple of 8. */
|
/* The log record header length must be a multiple of 8. */
|
||||||
if ( ( ( le16_to_cpu( ra->log_record_header_length ) + 7 ) & ~7 ) !=
|
if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
|
||||||
le16_to_cpu( ra->log_record_header_length ) )
|
le16_to_cpu(ra->log_record_header_length)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"inconsistent log record header length.\n");
|
||||||
"inconsistent log record header length.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* Ditto for the log page data offset. */
|
/* Ditto for the log page data offset. */
|
||||||
if ( ( ( le16_to_cpu( ra->log_page_data_offset ) + 7 ) & ~7 ) !=
|
if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
|
||||||
le16_to_cpu( ra->log_page_data_offset ) )
|
le16_to_cpu(ra->log_page_data_offset)) {
|
||||||
{
|
ntfs_log_error("$LogFile restart area specifies "
|
||||||
ntfs_log_error( "$LogFile restart area specifies "
|
"inconsistent log page data offset.\n");
|
||||||
"inconsistent log page data offset.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace("Done.\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,17 +273,17 @@ static BOOL ntfs_check_restart_area( RESTART_PAGE_HEADER *rp )
|
|||||||
* function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
|
* function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
|
||||||
* restart page and the page must be multi sector transfer deprotected.
|
* restart page and the page must be multi sector transfer deprotected.
|
||||||
*/
|
*/
|
||||||
static BOOL ntfs_check_log_client_array( RESTART_PAGE_HEADER *rp )
|
static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
||||||
{
|
{
|
||||||
RESTART_AREA *ra;
|
RESTART_AREA *ra;
|
||||||
LOG_CLIENT_RECORD *ca, *cr;
|
LOG_CLIENT_RECORD *ca, *cr;
|
||||||
u16 nr_clients, idx;
|
u16 nr_clients, idx;
|
||||||
BOOL in_free_list, idx_is_first;
|
BOOL in_free_list, idx_is_first;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
ra = ( RESTART_AREA* )( ( u8* )rp + le16_to_cpu( rp->restart_area_offset ) );
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||||
ca = ( LOG_CLIENT_RECORD* )( ( u8* )ra +
|
ca = (LOG_CLIENT_RECORD*)((u8*)ra +
|
||||||
le16_to_cpu( ra->client_array_offset ) );
|
le16_to_cpu(ra->client_array_offset));
|
||||||
/*
|
/*
|
||||||
* Check the ra->client_free_list first and then check the
|
* Check the ra->client_free_list first and then check the
|
||||||
* ra->client_in_use_list. Check each of the log client records in
|
* ra->client_in_use_list. Check each of the log client records in
|
||||||
@ -308,36 +292,33 @@ static BOOL ntfs_check_log_client_array( RESTART_PAGE_HEADER *rp )
|
|||||||
* visited as there cannot be more than ra->log_clients records and
|
* visited as there cannot be more than ra->log_clients records and
|
||||||
* that way we detect eventual loops in within a list.
|
* that way we detect eventual loops in within a list.
|
||||||
*/
|
*/
|
||||||
nr_clients = le16_to_cpu( ra->log_clients );
|
nr_clients = le16_to_cpu(ra->log_clients);
|
||||||
idx = le16_to_cpu( ra->client_free_list );
|
idx = le16_to_cpu(ra->client_free_list);
|
||||||
in_free_list = TRUE;
|
in_free_list = TRUE;
|
||||||
check_list:
|
check_list:
|
||||||
for ( idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
||||||
idx = le16_to_cpu( cr->next_client ) )
|
idx = le16_to_cpu(cr->next_client)) {
|
||||||
{
|
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
|
||||||
if ( !nr_clients || idx >= le16_to_cpu( ra->log_clients ) )
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
/* Set @cr to the current log client record. */
|
/* Set @cr to the current log client record. */
|
||||||
cr = ca + idx;
|
cr = ca + idx;
|
||||||
/* The first log client record must not have a prev_client. */
|
/* The first log client record must not have a prev_client. */
|
||||||
if ( idx_is_first )
|
if (idx_is_first) {
|
||||||
{
|
if (cr->prev_client != LOGFILE_NO_CLIENT)
|
||||||
if ( cr->prev_client != LOGFILE_NO_CLIENT )
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
idx_is_first = FALSE;
|
idx_is_first = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Switch to and check the in use list if we just did the free list. */
|
/* Switch to and check the in use list if we just did the free list. */
|
||||||
if ( in_free_list )
|
if (in_free_list) {
|
||||||
{
|
|
||||||
in_free_list = FALSE;
|
in_free_list = FALSE;
|
||||||
idx = le16_to_cpu( ra->client_in_use_list );
|
idx = le16_to_cpu(ra->client_in_use_list);
|
||||||
goto check_list;
|
goto check_list;
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace("Done.\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
err_out:
|
err_out:
|
||||||
ntfs_log_error( "$LogFile log client array is corrupt.\n" );
|
ntfs_log_error("$LogFile log client array is corrupt.\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,50 +349,47 @@ err_out:
|
|||||||
* ENOMEM - Not enough memory to load the restart page.
|
* ENOMEM - Not enough memory to load the restart page.
|
||||||
* EIO - Failed to reading from $LogFile.
|
* EIO - Failed to reading from $LogFile.
|
||||||
*/
|
*/
|
||||||
static int ntfs_check_and_load_restart_page( ntfs_attr *log_na,
|
static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||||
RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
|
RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
|
||||||
LSN *lsn )
|
LSN *lsn)
|
||||||
{
|
{
|
||||||
RESTART_AREA *ra;
|
RESTART_AREA *ra;
|
||||||
RESTART_PAGE_HEADER *trp;
|
RESTART_PAGE_HEADER *trp;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
/* Check the restart page header for consistency. */
|
/* Check the restart page header for consistency. */
|
||||||
if ( !ntfs_check_restart_page_header( rp, pos ) )
|
if (!ntfs_check_restart_page_header(rp, pos)) {
|
||||||
{
|
|
||||||
/* Error output already done inside the function. */
|
/* Error output already done inside the function. */
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
/* Check the restart area for consistency. */
|
/* Check the restart area for consistency. */
|
||||||
if ( !ntfs_check_restart_area( rp ) )
|
if (!ntfs_check_restart_area(rp)) {
|
||||||
{
|
|
||||||
/* Error output already done inside the function. */
|
/* Error output already done inside the function. */
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
ra = ( RESTART_AREA* )( ( u8* )rp + le16_to_cpu( rp->restart_area_offset ) );
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||||
/*
|
/*
|
||||||
* Allocate a buffer to store the whole restart page so we can multi
|
* Allocate a buffer to store the whole restart page so we can multi
|
||||||
* sector transfer deprotect it.
|
* sector transfer deprotect it.
|
||||||
*/
|
*/
|
||||||
trp = ntfs_malloc( le32_to_cpu( rp->system_page_size ) );
|
trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
|
||||||
if ( !trp )
|
if (!trp)
|
||||||
return errno;
|
return errno;
|
||||||
/*
|
/*
|
||||||
* Read the whole of the restart page into the buffer. If it fits
|
* Read the whole of the restart page into the buffer. If it fits
|
||||||
* completely inside @rp, just copy it from there. Otherwise read it
|
* completely inside @rp, just copy it from there. Otherwise read it
|
||||||
* from disk.
|
* from disk.
|
||||||
*/
|
*/
|
||||||
if ( le32_to_cpu( rp->system_page_size ) <= NTFS_BLOCK_SIZE )
|
if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE)
|
||||||
memcpy( trp, rp, le32_to_cpu( rp->system_page_size ) );
|
memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
|
||||||
else if ( ntfs_attr_pread( log_na, pos,
|
else if (ntfs_attr_pread(log_na, pos,
|
||||||
le32_to_cpu( rp->system_page_size ), trp ) !=
|
le32_to_cpu(rp->system_page_size), trp) !=
|
||||||
le32_to_cpu( rp->system_page_size ) )
|
le32_to_cpu(rp->system_page_size)) {
|
||||||
{
|
|
||||||
err = errno;
|
err = errno;
|
||||||
ntfs_log_error( "Failed to read whole restart page into the "
|
ntfs_log_error("Failed to read whole restart page into the "
|
||||||
"buffer.\n" );
|
"buffer.\n");
|
||||||
if ( err != ENOMEM )
|
if (err != ENOMEM)
|
||||||
err = EIO;
|
err = EIO;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -419,21 +397,19 @@ static int ntfs_check_and_load_restart_page( ntfs_attr *log_na,
|
|||||||
* Perform the multi sector transfer deprotection on the buffer if the
|
* Perform the multi sector transfer deprotection on the buffer if the
|
||||||
* restart page is protected.
|
* restart page is protected.
|
||||||
*/
|
*/
|
||||||
if ( ( !ntfs_is_chkd_record( trp->magic ) || le16_to_cpu( trp->usa_count ) )
|
if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
|
||||||
&& ntfs_mst_post_read_fixup( ( NTFS_RECORD* )trp,
|
&& ntfs_mst_post_read_fixup((NTFS_RECORD*)trp,
|
||||||
le32_to_cpu( rp->system_page_size ) ) )
|
le32_to_cpu(rp->system_page_size))) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* A multi sector tranfer error was detected. We only need to
|
* A multi sector tranfer error was detected. We only need to
|
||||||
* abort if the restart page contents exceed the multi sector
|
* abort if the restart page contents exceed the multi sector
|
||||||
* transfer fixup of the first sector.
|
* transfer fixup of the first sector.
|
||||||
*/
|
*/
|
||||||
if ( le16_to_cpu( rp->restart_area_offset ) +
|
if (le16_to_cpu(rp->restart_area_offset) +
|
||||||
le16_to_cpu( ra->restart_area_length ) >
|
le16_to_cpu(ra->restart_area_length) >
|
||||||
NTFS_BLOCK_SIZE - ( int )sizeof( u16 ) )
|
NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
|
||||||
{
|
ntfs_log_error("Multi sector transfer error "
|
||||||
ntfs_log_error( "Multi sector transfer error "
|
"detected in $LogFile restart page.\n");
|
||||||
"detected in $LogFile restart page.\n" );
|
|
||||||
err = EINVAL;
|
err = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
@ -444,29 +420,25 @@ static int ntfs_check_and_load_restart_page( ntfs_attr *log_na,
|
|||||||
* check the log client records for consistency, too.
|
* check the log client records for consistency, too.
|
||||||
*/
|
*/
|
||||||
err = 0;
|
err = 0;
|
||||||
if ( ntfs_is_rstr_record( rp->magic ) &&
|
if (ntfs_is_rstr_record(rp->magic) &&
|
||||||
ra->client_in_use_list != LOGFILE_NO_CLIENT )
|
ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
||||||
{
|
if (!ntfs_check_log_client_array(trp)) {
|
||||||
if ( !ntfs_check_log_client_array( trp ) )
|
|
||||||
{
|
|
||||||
err = EINVAL;
|
err = EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( lsn )
|
if (lsn) {
|
||||||
{
|
if (ntfs_is_rstr_record(rp->magic))
|
||||||
if ( ntfs_is_rstr_record( rp->magic ) )
|
*lsn = sle64_to_cpu(ra->current_lsn);
|
||||||
*lsn = sle64_to_cpu( ra->current_lsn );
|
|
||||||
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
||||||
*lsn = sle64_to_cpu( rp->chkdsk_lsn );
|
*lsn = sle64_to_cpu(rp->chkdsk_lsn);
|
||||||
}
|
}
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace("Done.\n");
|
||||||
if ( wrp )
|
if (wrp)
|
||||||
*wrp = trp;
|
*wrp = trp;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
err_out:
|
err_out:
|
||||||
free( trp );
|
free(trp);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -488,7 +460,7 @@ err_out:
|
|||||||
* if the $LogFile was created on a system with a different page size to ours
|
* if the $LogFile was created on a system with a different page size to ours
|
||||||
* yet and mst deprotection would fail if our page size is smaller.
|
* yet and mst deprotection would fail if our page size is smaller.
|
||||||
*/
|
*/
|
||||||
BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||||
{
|
{
|
||||||
s64 size, pos;
|
s64 size, pos;
|
||||||
LSN rstr1_lsn, rstr2_lsn;
|
LSN rstr1_lsn, rstr2_lsn;
|
||||||
@ -500,13 +472,13 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
BOOL logfile_is_empty = TRUE;
|
BOOL logfile_is_empty = TRUE;
|
||||||
u8 log_page_bits;
|
u8 log_page_bits;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
/* An empty $LogFile must have been clean before it got emptied. */
|
/* An empty $LogFile must have been clean before it got emptied. */
|
||||||
if ( NVolLogFileEmpty( vol ) )
|
if (NVolLogFileEmpty(vol))
|
||||||
goto is_empty;
|
goto is_empty;
|
||||||
size = log_na->data_size;
|
size = log_na->data_size;
|
||||||
/* Make sure the file doesn't exceed the maximum allowed size. */
|
/* Make sure the file doesn't exceed the maximum allowed size. */
|
||||||
if ( size > ( s64 )MaxLogFileSize )
|
if (size > (s64)MaxLogFileSize)
|
||||||
size = MaxLogFileSize;
|
size = MaxLogFileSize;
|
||||||
log_page_size = DefaultLogPageSize;
|
log_page_size = DefaultLogPageSize;
|
||||||
log_page_mask = log_page_size - 1;
|
log_page_mask = log_page_size - 1;
|
||||||
@ -514,22 +486,21 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
* Use generic_ffs() instead of ffs() to enable the compiler to
|
* Use generic_ffs() instead of ffs() to enable the compiler to
|
||||||
* optimize log_page_size and log_page_bits into constants.
|
* optimize log_page_size and log_page_bits into constants.
|
||||||
*/
|
*/
|
||||||
log_page_bits = ffs( log_page_size ) - 1;
|
log_page_bits = ffs(log_page_size) - 1;
|
||||||
size &= ~( log_page_size - 1 );
|
size &= ~(log_page_size - 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure the log file is big enough to store at least the two restart
|
* Ensure the log file is big enough to store at least the two restart
|
||||||
* pages and the minimum number of log record pages.
|
* pages and the minimum number of log record pages.
|
||||||
*/
|
*/
|
||||||
if ( size < log_page_size * 2 || ( size - log_page_size * 2 ) >>
|
if (size < log_page_size * 2 || (size - log_page_size * 2) >>
|
||||||
log_page_bits < MinLogRecordPages )
|
log_page_bits < MinLogRecordPages) {
|
||||||
{
|
ntfs_log_error("$LogFile is too small.\n");
|
||||||
ntfs_log_error( "$LogFile is too small.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* Allocate memory for restart page. */
|
/* Allocate memory for restart page. */
|
||||||
kaddr = ntfs_malloc( NTFS_BLOCK_SIZE );
|
kaddr = ntfs_malloc(NTFS_BLOCK_SIZE);
|
||||||
if ( !kaddr )
|
if (!kaddr)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
/*
|
/*
|
||||||
* Read through the file looking for a restart page. Since the restart
|
* Read through the file looking for a restart page. Since the restart
|
||||||
@ -539,16 +510,14 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
* contain empty and uninitialized records, the log file can be assumed
|
* contain empty and uninitialized records, the log file can be assumed
|
||||||
* to be empty.
|
* to be empty.
|
||||||
*/
|
*/
|
||||||
for ( pos = 0; pos < size; pos <<= 1 )
|
for (pos = 0; pos < size; pos <<= 1) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
||||||
*/
|
*/
|
||||||
if ( ntfs_attr_pread( log_na, pos, NTFS_BLOCK_SIZE, kaddr ) !=
|
if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) !=
|
||||||
NTFS_BLOCK_SIZE )
|
NTFS_BLOCK_SIZE) {
|
||||||
{
|
ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE "
|
||||||
ntfs_log_error( "Failed to read first NTFS_BLOCK_SIZE "
|
"bytes of potential restart page.\n");
|
||||||
"bytes of potential restart page.\n" );
|
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,21 +526,20 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
* empty block after a non-empty block has been encountered
|
* empty block after a non-empty block has been encountered
|
||||||
* means we are done.
|
* means we are done.
|
||||||
*/
|
*/
|
||||||
if ( !ntfs_is_empty_recordp( ( le32* )kaddr ) )
|
if (!ntfs_is_empty_recordp((le32*)kaddr))
|
||||||
logfile_is_empty = FALSE;
|
logfile_is_empty = FALSE;
|
||||||
else if ( !logfile_is_empty )
|
else if (!logfile_is_empty)
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
* A log record page means there cannot be a restart page after
|
* A log record page means there cannot be a restart page after
|
||||||
* this so no need to continue searching.
|
* this so no need to continue searching.
|
||||||
*/
|
*/
|
||||||
if ( ntfs_is_rcrd_recordp( ( le32* )kaddr ) )
|
if (ntfs_is_rcrd_recordp((le32*)kaddr))
|
||||||
break;
|
break;
|
||||||
/* If not a (modified by chkdsk) restart page, continue. */
|
/* If not a (modified by chkdsk) restart page, continue. */
|
||||||
if ( !ntfs_is_rstr_recordp( ( le32* )kaddr ) &&
|
if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
|
||||||
!ntfs_is_chkd_recordp( ( le32* )kaddr ) )
|
!ntfs_is_chkd_recordp((le32*)kaddr)) {
|
||||||
{
|
if (!pos)
|
||||||
if ( !pos )
|
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -580,18 +548,16 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
* and get a copy of the complete multi sector transfer
|
* and get a copy of the complete multi sector transfer
|
||||||
* deprotected restart page.
|
* deprotected restart page.
|
||||||
*/
|
*/
|
||||||
err = ntfs_check_and_load_restart_page( log_na,
|
err = ntfs_check_and_load_restart_page(log_na,
|
||||||
( RESTART_PAGE_HEADER* )kaddr, pos,
|
(RESTART_PAGE_HEADER*)kaddr, pos,
|
||||||
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
||||||
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn );
|
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
|
||||||
if ( !err )
|
if (!err) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* If we have now found the first (modified by chkdsk)
|
* If we have now found the first (modified by chkdsk)
|
||||||
* restart page, continue looking for the second one.
|
* restart page, continue looking for the second one.
|
||||||
*/
|
*/
|
||||||
if ( !pos )
|
if (!pos) {
|
||||||
{
|
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -606,66 +572,59 @@ BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp )
|
|||||||
* not abort if the restart page was invalid as we might still
|
* not abort if the restart page was invalid as we might still
|
||||||
* find a valid one further in the file.
|
* find a valid one further in the file.
|
||||||
*/
|
*/
|
||||||
if ( err != EINVAL )
|
if (err != EINVAL)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
/* Continue looking. */
|
/* Continue looking. */
|
||||||
if ( !pos )
|
if (!pos)
|
||||||
pos = NTFS_BLOCK_SIZE >> 1;
|
pos = NTFS_BLOCK_SIZE >> 1;
|
||||||
}
|
}
|
||||||
if ( kaddr )
|
if (kaddr) {
|
||||||
{
|
free(kaddr);
|
||||||
free( kaddr );
|
|
||||||
kaddr = NULL;
|
kaddr = NULL;
|
||||||
}
|
}
|
||||||
if ( logfile_is_empty )
|
if (logfile_is_empty) {
|
||||||
{
|
NVolSetLogFileEmpty(vol);
|
||||||
NVolSetLogFileEmpty( vol );
|
|
||||||
is_empty:
|
is_empty:
|
||||||
ntfs_log_trace( "Done. ($LogFile is empty.)\n" );
|
ntfs_log_trace("Done. ($LogFile is empty.)\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if ( !rstr1_ph )
|
if (!rstr1_ph) {
|
||||||
{
|
if (rstr2_ph)
|
||||||
if ( rstr2_ph )
|
ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
|
||||||
ntfs_log_error( "BUG: rstr2_ph isn't NULL!\n" );
|
ntfs_log_error("Did not find any restart pages in "
|
||||||
ntfs_log_error( "Did not find any restart pages in "
|
"$LogFile and it was not empty.\n");
|
||||||
"$LogFile and it was not empty.\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* If both restart pages were found, use the more recent one. */
|
/* If both restart pages were found, use the more recent one. */
|
||||||
if ( rstr2_ph )
|
if (rstr2_ph) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* If the second restart area is more recent, switch to it.
|
* If the second restart area is more recent, switch to it.
|
||||||
* Otherwise just throw it away.
|
* Otherwise just throw it away.
|
||||||
*/
|
*/
|
||||||
if ( rstr2_lsn > rstr1_lsn )
|
if (rstr2_lsn > rstr1_lsn) {
|
||||||
{
|
ntfs_log_debug("Using second restart page as it is more "
|
||||||
ntfs_log_debug( "Using second restart page as it is more "
|
"recent.\n");
|
||||||
"recent.\n" );
|
free(rstr1_ph);
|
||||||
free( rstr1_ph );
|
|
||||||
rstr1_ph = rstr2_ph;
|
rstr1_ph = rstr2_ph;
|
||||||
/* rstr1_lsn = rstr2_lsn; */
|
/* rstr1_lsn = rstr2_lsn; */
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_debug("Using first restart page as it is more "
|
||||||
{
|
"recent.\n");
|
||||||
ntfs_log_debug( "Using first restart page as it is more "
|
free(rstr2_ph);
|
||||||
"recent.\n" );
|
|
||||||
free( rstr2_ph );
|
|
||||||
}
|
}
|
||||||
rstr2_ph = NULL;
|
rstr2_ph = NULL;
|
||||||
}
|
}
|
||||||
/* All consistency checks passed. */
|
/* All consistency checks passed. */
|
||||||
if ( rp )
|
if (rp)
|
||||||
*rp = rstr1_ph;
|
*rp = rstr1_ph;
|
||||||
else
|
else
|
||||||
free( rstr1_ph );
|
free(rstr1_ph);
|
||||||
ntfs_log_trace( "Done.\n" );
|
ntfs_log_trace("Done.\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
err_out:
|
err_out:
|
||||||
free( kaddr );
|
free(kaddr);
|
||||||
free( rstr1_ph );
|
free(rstr1_ph);
|
||||||
free( rstr2_ph );
|
free(rstr2_ph);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,45 +648,41 @@ err_out:
|
|||||||
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
|
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
|
||||||
* empty volume will be reported as dirty.
|
* empty volume will be reported as dirty.
|
||||||
*/
|
*/
|
||||||
BOOL ntfs_is_logfile_clean( ntfs_attr *log_na, RESTART_PAGE_HEADER *rp )
|
BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||||
{
|
{
|
||||||
RESTART_AREA *ra;
|
RESTART_AREA *ra;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
/* An empty $LogFile must have been clean before it got emptied. */
|
/* An empty $LogFile must have been clean before it got emptied. */
|
||||||
if ( NVolLogFileEmpty( log_na->ni->vol ) )
|
if (NVolLogFileEmpty(log_na->ni->vol)) {
|
||||||
{
|
ntfs_log_trace("$LogFile is empty\n");
|
||||||
ntfs_log_trace( "$LogFile is empty\n" );
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if ( !rp )
|
if (!rp) {
|
||||||
{
|
ntfs_log_error("Restart page header is NULL\n");
|
||||||
ntfs_log_error( "Restart page header is NULL\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if ( !ntfs_is_rstr_record( rp->magic ) &&
|
if (!ntfs_is_rstr_record(rp->magic) &&
|
||||||
!ntfs_is_chkd_record( rp->magic ) )
|
!ntfs_is_chkd_record(rp->magic)) {
|
||||||
{
|
ntfs_log_error("Restart page buffer is invalid\n");
|
||||||
ntfs_log_error( "Restart page buffer is invalid\n" );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ra = ( RESTART_AREA* )( ( u8* )rp + le16_to_cpu( rp->restart_area_offset ) );
|
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||||
/*
|
/*
|
||||||
* If the $LogFile has active clients, i.e. it is open, and we do not
|
* If the $LogFile has active clients, i.e. it is open, and we do not
|
||||||
* have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
|
* have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
|
||||||
* we assume there was an unclean shutdown.
|
* we assume there was an unclean shutdown.
|
||||||
*/
|
*/
|
||||||
if ( ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||||
!( ra->flags & RESTART_VOLUME_IS_CLEAN ) )
|
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
||||||
{
|
ntfs_log_error("The disk contains an unclean file system (%d, "
|
||||||
ntfs_log_error( "The disk contains an unclean file system (%d, "
|
"%d).\n", le16_to_cpu(ra->client_in_use_list),
|
||||||
"%d).\n", le16_to_cpu( ra->client_in_use_list ),
|
le16_to_cpu(ra->flags));
|
||||||
le16_to_cpu( ra->flags ) );
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* $LogFile indicates a clean shutdown. */
|
/* $LogFile indicates a clean shutdown. */
|
||||||
ntfs_log_trace( "$LogFile indicates a clean shutdown\n" );
|
ntfs_log_trace("$LogFile indicates a clean shutdown\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,44 +697,41 @@ BOOL ntfs_is_logfile_clean( ntfs_attr *log_na, RESTART_PAGE_HEADER *rp )
|
|||||||
* checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
|
* checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
|
||||||
* has been used to ensure that the $LogFile is clean.
|
* has been used to ensure that the $LogFile is clean.
|
||||||
*/
|
*/
|
||||||
int ntfs_empty_logfile( ntfs_attr *na )
|
int ntfs_empty_logfile(ntfs_attr *na)
|
||||||
{
|
{
|
||||||
s64 pos, count;
|
s64 pos, count;
|
||||||
char buf[NTFS_BUF_SIZE];
|
char buf[NTFS_BUF_SIZE];
|
||||||
|
|
||||||
ntfs_log_trace( "Entering.\n" );
|
ntfs_log_trace("Entering.\n");
|
||||||
|
|
||||||
if ( NVolLogFileEmpty( na->ni->vol ) )
|
if (NVolLogFileEmpty(na->ni->vol))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ( !NAttrNonResident( na ) )
|
if (!NAttrNonResident(na)) {
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Resident $LogFile $DATA attribute" );
|
ntfs_log_perror("Resident $LogFile $DATA attribute");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( buf, -1, NTFS_BUF_SIZE );
|
memset(buf, -1, NTFS_BUF_SIZE);
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while ( ( count = na->data_size - pos ) > 0 )
|
while ((count = na->data_size - pos) > 0) {
|
||||||
{
|
|
||||||
|
|
||||||
if ( count > NTFS_BUF_SIZE )
|
if (count > NTFS_BUF_SIZE)
|
||||||
count = NTFS_BUF_SIZE;
|
count = NTFS_BUF_SIZE;
|
||||||
|
|
||||||
count = ntfs_attr_pwrite( na, pos, count, buf );
|
count = ntfs_attr_pwrite(na, pos, count, buf);
|
||||||
if ( count <= 0 )
|
if (count <= 0) {
|
||||||
{
|
ntfs_log_perror("Failed to reset $LogFile");
|
||||||
ntfs_log_perror( "Failed to reset $LogFile" );
|
if (count != -1)
|
||||||
if ( count != -1 )
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pos += count;
|
pos += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
NVolSetLogFileEmpty( na->ni->vol );
|
NVolSetLogFileEmpty(na->ni->vol);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -61,42 +61,40 @@
|
|||||||
*
|
*
|
||||||
* Begins the restart area.
|
* Begins the restart area.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
/*Ofs*/
|
||||||
/*Ofs*/
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||||
/* 0*/
|
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||||
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
|
When creating, set this to be immediately
|
||||||
after this header structure (without any
|
after this header structure (without any
|
||||||
alignment). */
|
alignment). */
|
||||||
/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||||
|
|
||||||
/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
|
/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
|
||||||
chkdsk. Only used when the magic is changed
|
chkdsk. Only used when the magic is changed
|
||||||
to "CHKD". Otherwise this is zero. */
|
to "CHKD". Otherwise this is zero. */
|
||||||
/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
|
/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
|
||||||
was created, has to be >= 512 and a power of
|
was created, has to be >= 512 and a power of
|
||||||
2. Use this to calculate the required size
|
2. Use this to calculate the required size
|
||||||
of the usa (usa_count) and add it to usa_ofs.
|
of the usa (usa_count) and add it to usa_ofs.
|
||||||
Then verify that the result is less than the
|
Then verify that the result is less than the
|
||||||
value of the restart_area_offset. */
|
value of the restart_area_offset. */
|
||||||
/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
|
/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
|
||||||
512 and a power of 2. The default is 4096
|
512 and a power of 2. The default is 4096
|
||||||
and is used when the system page size is
|
and is used when the system page size is
|
||||||
between 4096 and 8192. Otherwise this is
|
between 4096 and 8192. Otherwise this is
|
||||||
set to the system page size instead. */
|
set to the system page size instead. */
|
||||||
/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
|
/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
|
||||||
the RESTART_AREA. Value has to be aligned
|
the RESTART_AREA. Value has to be aligned
|
||||||
to 8-byte boundary. When creating, set this
|
to 8-byte boundary. When creating, set this
|
||||||
to be after the usa. */
|
to be after the usa. */
|
||||||
/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
|
/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
|
||||||
version is 1. */
|
version is 1. */
|
||||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||||
version 1.1. */
|
version 1.1. */
|
||||||
/* sizeof() = 30 (0x1e) bytes */
|
/* sizeof() = 30 (0x1e) bytes */
|
||||||
} __attribute__( ( __packed__ ) ) RESTART_PAGE_HEADER;
|
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constant for the log client indices meaning that there are no client records
|
* Constant for the log client indices meaning that there are no client records
|
||||||
@ -110,11 +108,10 @@ typedef struct
|
|||||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||||
* information about the log file in which they are present.
|
* information about the log file in which they are present.
|
||||||
*/
|
*/
|
||||||
enum
|
enum {
|
||||||
{
|
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
|
||||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16( 0x0002 ),
|
|
||||||
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||||
} __attribute__( ( __packed__ ) );
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
typedef le16 RESTART_AREA_FLAGS;
|
typedef le16 RESTART_AREA_FLAGS;
|
||||||
|
|
||||||
@ -125,20 +122,18 @@ typedef le16 RESTART_AREA_FLAGS;
|
|||||||
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
||||||
* See notes at restart_area_offset above.
|
* See notes at restart_area_offset above.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
/*Ofs*/
|
||||||
/*Ofs*/
|
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||||
/* 0*/
|
|
||||||
leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
|
||||||
when the restart area was last written.
|
when the restart area was last written.
|
||||||
This happens often but what is the interval?
|
This happens often but what is the interval?
|
||||||
Is it just fixed time or is it every time a
|
Is it just fixed time or is it every time a
|
||||||
check point is written or something else?
|
check point is written or something else?
|
||||||
On create set to 0. */
|
On create set to 0. */
|
||||||
/* 8*/ le16 log_clients; /* Number of log client records in the array of
|
/* 8*/ le16 log_clients; /* Number of log client records in the array of
|
||||||
log client records which follows this
|
log client records which follows this
|
||||||
restart area. Must be 1. */
|
restart area. Must be 1. */
|
||||||
/* 10*/ le16 client_free_list; /* The index of the first free log client record
|
/* 10*/ le16 client_free_list; /* The index of the first free log client record
|
||||||
in the array of log client records.
|
in the array of log client records.
|
||||||
LOGFILE_NO_CLIENT means that there are no
|
LOGFILE_NO_CLIENT means that there are no
|
||||||
free log client records in the array.
|
free log client records in the array.
|
||||||
@ -154,7 +149,7 @@ typedef struct
|
|||||||
and presumably later, the logfile is always
|
and presumably later, the logfile is always
|
||||||
open, even on clean shutdown so this should
|
open, even on clean shutdown so this should
|
||||||
always be LOGFILE_NO_CLIENT. */
|
always be LOGFILE_NO_CLIENT. */
|
||||||
/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
|
/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
|
||||||
record in the array of log client records.
|
record in the array of log client records.
|
||||||
LOGFILE_NO_CLIENT means that there are no
|
LOGFILE_NO_CLIENT means that there are no
|
||||||
in-use log client records in the array. If
|
in-use log client records in the array. If
|
||||||
@ -171,7 +166,7 @@ typedef struct
|
|||||||
presumably later, the logfile is always
|
presumably later, the logfile is always
|
||||||
open, even on clean shutdown so this should
|
open, even on clean shutdown so this should
|
||||||
always be 0. */
|
always be 0. */
|
||||||
/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
||||||
and presumably earlier this is always 0. On
|
and presumably earlier this is always 0. On
|
||||||
WinXP and presumably later, if the logfile
|
WinXP and presumably later, if the logfile
|
||||||
was shutdown cleanly, the second bit,
|
was shutdown cleanly, the second bit,
|
||||||
@ -187,13 +182,13 @@ typedef struct
|
|||||||
clean. If on the other hand the logfile is
|
clean. If on the other hand the logfile is
|
||||||
open and this bit is clear, we can be almost
|
open and this bit is clear, we can be almost
|
||||||
certain that the logfile is dirty. */
|
certain that the logfile is dirty. */
|
||||||
/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
|
/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
|
||||||
number. This is calculated as 67 - the
|
number. This is calculated as 67 - the
|
||||||
number of bits required to store the logfile
|
number of bits required to store the logfile
|
||||||
size in bytes and this can be used in with
|
size in bytes and this can be used in with
|
||||||
the specified file_size as a consistency
|
the specified file_size as a consistency
|
||||||
check. */
|
check. */
|
||||||
/* 20*/ le16 restart_area_length;/* Length of the restart area including the
|
/* 20*/ le16 restart_area_length;/* Length of the restart area including the
|
||||||
client array. Following checks required if
|
client array. Following checks required if
|
||||||
version matches. Otherwise, skip them.
|
version matches. Otherwise, skip them.
|
||||||
restart_area_offset + restart_area_length
|
restart_area_offset + restart_area_length
|
||||||
@ -201,7 +196,7 @@ typedef struct
|
|||||||
restart_area_length has to be >=
|
restart_area_length has to be >=
|
||||||
client_array_offset + (log_clients *
|
client_array_offset + (log_clients *
|
||||||
sizeof(log client record)). */
|
sizeof(log client record)). */
|
||||||
/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
|
/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
|
||||||
the first log client record if versions are
|
the first log client record if versions are
|
||||||
matched. When creating, set this to be
|
matched. When creating, set this to be
|
||||||
after this restart area structure, aligned
|
after this restart area structure, aligned
|
||||||
@ -223,7 +218,7 @@ typedef struct
|
|||||||
the client array. This probably means that
|
the client array. This probably means that
|
||||||
the RESTART_AREA record is actually bigger
|
the RESTART_AREA record is actually bigger
|
||||||
in WinXP and later. */
|
in WinXP and later. */
|
||||||
/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
|
/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
|
||||||
restart_area_offset + the offset of the
|
restart_area_offset + the offset of the
|
||||||
file_size are > 510 then corruption has
|
file_size are > 510 then corruption has
|
||||||
occurred. This is the very first check when
|
occurred. This is the very first check when
|
||||||
@ -236,10 +231,10 @@ typedef struct
|
|||||||
then it has to be at least big enough to
|
then it has to be at least big enough to
|
||||||
store the two restart pages and 48 (0x30)
|
store the two restart pages and 48 (0x30)
|
||||||
log record pages. */
|
log record pages. */
|
||||||
/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
||||||
the log record header. On create set to
|
the log record header. On create set to
|
||||||
0. */
|
0. */
|
||||||
/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
|
/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
|
||||||
If the version matches then check that the
|
If the version matches then check that the
|
||||||
value of log_record_header_length is a
|
value of log_record_header_length is a
|
||||||
multiple of 8, i.e.
|
multiple of 8, i.e.
|
||||||
@ -247,19 +242,19 @@ typedef struct
|
|||||||
log_record_header_length. When creating set
|
log_record_header_length. When creating set
|
||||||
it to sizeof(LOG_RECORD_HEADER), aligned to
|
it to sizeof(LOG_RECORD_HEADER), aligned to
|
||||||
8 bytes. */
|
8 bytes. */
|
||||||
/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record
|
/* 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
|
page. Must be a multiple of 8. On create
|
||||||
set it to immediately after the update
|
set it to immediately after the update
|
||||||
sequence array of the log record page. */
|
sequence array of the log record page. */
|
||||||
/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
|
/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
|
||||||
time the logfile is restarted which happens
|
time the logfile is restarted which happens
|
||||||
at mount time when the logfile is opened.
|
at mount time when the logfile is opened.
|
||||||
When creating set to a random value. Win2k
|
When creating set to a random value. Win2k
|
||||||
sets it to the low 32 bits of the current
|
sets it to the low 32 bits of the current
|
||||||
system time in NTFS format (see time.h). */
|
system time in NTFS format (see time.h). */
|
||||||
/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
||||||
/* sizeof() = 48 (0x30) bytes */
|
/* sizeof() = 48 (0x30) bytes */
|
||||||
} __attribute__( ( __packed__ ) ) RESTART_AREA;
|
} __attribute__((__packed__)) RESTART_AREA;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct LOG_CLIENT_RECORD - Log client record.
|
* 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
|
* The offset of this record is found by adding the offset of the
|
||||||
* RESTART_AREA to the client_array_offset value found in it.
|
* RESTART_AREA to the client_array_offset value found in it.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
/*Ofs*/
|
||||||
/*Ofs*/
|
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||||
/* 0*/
|
|
||||||
leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
|
||||||
set to 0. */
|
set to 0. */
|
||||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||||
the volume, i.e. the current position within
|
the volume, i.e. the current position within
|
||||||
the log file. At present, if clean this
|
the log file. At present, if clean this
|
||||||
should = current_lsn in restart area but it
|
should = current_lsn in restart area but it
|
||||||
probably also = current_lsn when dirty most
|
probably also = current_lsn when dirty most
|
||||||
of the time. At create set to 0. */
|
of the time. At create set to 0. */
|
||||||
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
||||||
in the array of log client records.
|
in the array of log client records.
|
||||||
LOGFILE_NO_CLIENT means there is no previous
|
LOGFILE_NO_CLIENT means there is no previous
|
||||||
client record, i.e. this is the first one.
|
client record, i.e. this is the first one.
|
||||||
This is always LOGFILE_NO_CLIENT. */
|
This is always LOGFILE_NO_CLIENT. */
|
||||||
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
||||||
the array of log client records.
|
the array of log client records.
|
||||||
LOGFILE_NO_CLIENT means there are no next
|
LOGFILE_NO_CLIENT means there are no next
|
||||||
client records, i.e. this is the last one.
|
client records, i.e. this is the last one.
|
||||||
This is always LOGFILE_NO_CLIENT. */
|
This is always LOGFILE_NO_CLIENT. */
|
||||||
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||||
to zero every time the logfile is restarted
|
to zero every time the logfile is restarted
|
||||||
and it is incremented when the logfile is
|
and it is incremented when the logfile is
|
||||||
closed at dismount time. Thus it is 0 when
|
closed at dismount time. Thus it is 0 when
|
||||||
dirty and 1 when clean. On WinXP and
|
dirty and 1 when clean. On WinXP and
|
||||||
presumably later, this is always 0. */
|
presumably later, this is always 0. */
|
||||||
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
||||||
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
||||||
always be 8. */
|
always be 8. */
|
||||||
/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
|
/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
|
||||||
always be "NTFS" with the remaining bytes
|
always be "NTFS" with the remaining bytes
|
||||||
set to 0. */
|
set to 0. */
|
||||||
/* sizeof() = 160 (0xa0) bytes */
|
/* sizeof() = 160 (0xa0) bytes */
|
||||||
} __attribute__( ( __packed__ ) ) LOG_CLIENT_RECORD;
|
} __attribute__((__packed__)) LOG_CLIENT_RECORD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct RECORD_PAGE_HEADER - Log page record page header.
|
* struct RECORD_PAGE_HEADER - Log page record page header.
|
||||||
@ -312,9 +305,8 @@ typedef struct
|
|||||||
* following update sequence array and then aligned to 8 byte boundary, but is
|
* following update sequence array and then aligned to 8 byte boundary, but is
|
||||||
* this specified anywhere?).
|
* this specified anywhere?).
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
|
||||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||||
When creating, set this to be immediately
|
When creating, set this to be immediately
|
||||||
@ -322,54 +314,48 @@ typedef struct
|
|||||||
alignment). */
|
alignment). */
|
||||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
LSN last_lsn;
|
LSN last_lsn;
|
||||||
s64 file_offset;
|
s64 file_offset;
|
||||||
} __attribute__( ( __packed__ ) ) copy;
|
} __attribute__((__packed__)) copy;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
u16 page_count;
|
u16 page_count;
|
||||||
u16 page_position;
|
u16 page_position;
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
|
||||||
{
|
|
||||||
u16 next_record_offset;
|
u16 next_record_offset;
|
||||||
u8 reserved[6];
|
u8 reserved[6];
|
||||||
LSN last_end_lsn;
|
LSN last_end_lsn;
|
||||||
} __attribute__( ( __packed__ ) ) packed;
|
} __attribute__((__packed__)) packed;
|
||||||
} __attribute__( ( __packed__ ) ) header;
|
} __attribute__((__packed__)) header;
|
||||||
} __attribute__( ( __packed__ ) ) RECORD_PAGE_HEADER;
|
} __attribute__((__packed__)) RECORD_PAGE_HEADER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
|
* enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
|
||||||
*
|
*
|
||||||
* (Or is it log record pages?)
|
* (Or is it log record pages?)
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
|
||||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16( 0x0001 ), /* ??? */
|
|
||||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||||
/* This has nothing to do with the log record. It is only so
|
/* This has nothing to do with the log record. It is only so
|
||||||
gcc knows to make the flags 16-bit. */
|
gcc knows to make the flags 16-bit. */
|
||||||
} __attribute__( ( __packed__ ) ) LOG_RECORD_FLAGS;
|
} __attribute__((__packed__)) LOG_RECORD_FLAGS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
u16 seq_number;
|
u16 seq_number;
|
||||||
u16 client_index;
|
u16 client_index;
|
||||||
} __attribute__( ( __packed__ ) ) LOG_CLIENT_ID;
|
} __attribute__((__packed__)) LOG_CLIENT_ID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct LOG_RECORD - Log record header.
|
* struct LOG_RECORD - Log record header.
|
||||||
*
|
*
|
||||||
* Each log record seems to have a constant size of 0x70 bytes.
|
* Each log record seems to have a constant size of 0x70 bytes.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
LSN this_lsn;
|
LSN this_lsn;
|
||||||
LSN client_previous_lsn;
|
LSN client_previous_lsn;
|
||||||
LSN client_undo_next_lsn;
|
LSN client_undo_next_lsn;
|
||||||
@ -379,7 +365,7 @@ typedef struct
|
|||||||
u32 transaction_id;
|
u32 transaction_id;
|
||||||
u16 flags;
|
u16 flags;
|
||||||
u16 reserved_or_alignment[3];
|
u16 reserved_or_alignment[3];
|
||||||
/* Now are at ofs 0x30 into struct. */
|
/* Now are at ofs 0x30 into struct. */
|
||||||
u16 redo_operation;
|
u16 redo_operation;
|
||||||
u16 undo_operation;
|
u16 undo_operation;
|
||||||
u16 redo_offset;
|
u16 redo_offset;
|
||||||
@ -389,21 +375,20 @@ typedef struct
|
|||||||
u16 target_attribute;
|
u16 target_attribute;
|
||||||
u16 lcns_to_follow; /* Number of lcn_list entries
|
u16 lcns_to_follow; /* Number of lcn_list entries
|
||||||
following this entry. */
|
following this entry. */
|
||||||
/* Now at ofs 0x40. */
|
/* Now at ofs 0x40. */
|
||||||
u16 record_offset;
|
u16 record_offset;
|
||||||
u16 attribute_offset;
|
u16 attribute_offset;
|
||||||
u32 alignment_or_reserved;
|
u32 alignment_or_reserved;
|
||||||
VCN target_vcn;
|
VCN target_vcn;
|
||||||
/* Now at ofs 0x50. */
|
/* Now at ofs 0x50. */
|
||||||
struct
|
struct { /* Only present if lcns_to_follow
|
||||||
{ /* Only present if lcns_to_follow
|
|
||||||
is not 0. */
|
is not 0. */
|
||||||
LCN lcn;
|
LCN lcn;
|
||||||
} __attribute__( ( __packed__ ) ) lcn_list[0];
|
} __attribute__((__packed__)) lcn_list[0];
|
||||||
} __attribute__( ( __packed__ ) ) LOG_RECORD;
|
} __attribute__((__packed__)) LOG_RECORD;
|
||||||
|
|
||||||
extern BOOL ntfs_check_logfile( ntfs_attr *log_na, RESTART_PAGE_HEADER **rp );
|
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 BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp);
|
||||||
extern int ntfs_empty_logfile( ntfs_attr *na );
|
extern int ntfs_empty_logfile(ntfs_attr *na);
|
||||||
|
|
||||||
#endif /* defined _NTFS_LOGFILE_H */
|
#endif /* defined _NTFS_LOGFILE_H */
|
||||||
|
@ -67,8 +67,7 @@ static int tab;
|
|||||||
* @flags: Flags which affect the output style
|
* @flags: Flags which affect the output style
|
||||||
* @handler: Function to perform the actual logging
|
* @handler: Function to perform the actual logging
|
||||||
*/
|
*/
|
||||||
struct ntfs_logging
|
struct ntfs_logging {
|
||||||
{
|
|
||||||
u32 levels;
|
u32 levels;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
|
||||||
@ -78,8 +77,7 @@ struct ntfs_logging
|
|||||||
* ntfs_log
|
* ntfs_log
|
||||||
* This struct controls all the logging within the library and tools.
|
* 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
|
#ifdef DEBUG
|
||||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
|
||||||
NTFS_LOG_LEVEL_LEAVE |
|
NTFS_LOG_LEVEL_LEAVE |
|
||||||
@ -103,7 +101,7 @@ static struct ntfs_logging ntfs_log =
|
|||||||
*
|
*
|
||||||
* Returns: Log levels in a 32-bit field
|
* 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;
|
||||||
}
|
}
|
||||||
@ -117,7 +115,7 @@ u32 ntfs_log_get_levels( void )
|
|||||||
*
|
*
|
||||||
* Returns: Log levels that were enabled before the call
|
* 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;
|
u32 old;
|
||||||
old = ntfs_log.levels;
|
old = ntfs_log.levels;
|
||||||
@ -134,11 +132,11 @@ u32 ntfs_log_set_levels( u32 levels )
|
|||||||
*
|
*
|
||||||
* Returns: Log levels that were enabled before the call
|
* 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;
|
u32 old;
|
||||||
old = ntfs_log.levels;
|
old = ntfs_log.levels;
|
||||||
ntfs_log.levels &= ( ~levels );
|
ntfs_log.levels &= (~levels);
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +148,7 @@ u32 ntfs_log_clear_levels( u32 levels )
|
|||||||
*
|
*
|
||||||
* Returns: Logging flags in a 32-bit field
|
* 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;
|
||||||
}
|
}
|
||||||
@ -164,7 +162,7 @@ u32 ntfs_log_get_flags( void )
|
|||||||
*
|
*
|
||||||
* Returns: Logging flags that were enabled before the call
|
* 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;
|
u32 old;
|
||||||
old = ntfs_log.flags;
|
old = ntfs_log.flags;
|
||||||
@ -181,11 +179,11 @@ u32 ntfs_log_set_flags( u32 flags )
|
|||||||
*
|
*
|
||||||
* Returns: Logging flags that were enabled before the call
|
* 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;
|
u32 old;
|
||||||
old = ntfs_log.flags;
|
old = ntfs_log.flags;
|
||||||
ntfs_log.flags &= ( ~flags );
|
ntfs_log.flags &= (~flags);
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,12 +197,11 @@ u32 ntfs_log_clear_flags( u32 flags )
|
|||||||
*
|
*
|
||||||
* Returns: "string" Prefix to be used
|
* 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 )
|
switch (level) {
|
||||||
{
|
|
||||||
case NTFS_LOG_LEVEL_INFO:
|
case NTFS_LOG_LEVEL_INFO:
|
||||||
case NTFS_LOG_LEVEL_QUIET:
|
case NTFS_LOG_LEVEL_QUIET:
|
||||||
case NTFS_LOG_LEVEL_PROGRESS:
|
case NTFS_LOG_LEVEL_PROGRESS:
|
||||||
@ -236,12 +233,11 @@ static FILE * ntfs_log_get_stream( u32 level )
|
|||||||
*
|
*
|
||||||
* Returns: "string" Prefix to be used
|
* 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 )
|
switch (level) {
|
||||||
{
|
|
||||||
case NTFS_LOG_LEVEL_DEBUG:
|
case NTFS_LOG_LEVEL_DEBUG:
|
||||||
prefix = "DEBUG: ";
|
prefix = "DEBUG: ";
|
||||||
break;
|
break;
|
||||||
@ -288,17 +284,15 @@ static const char * ntfs_log_get_prefix( u32 level )
|
|||||||
* This alternate handler will be called for all future logging requests.
|
* This alternate handler will be called for all future logging requests.
|
||||||
* If no @handler is specified, logging will revert to the default handler.
|
* 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 )
|
if (handler) {
|
||||||
{
|
|
||||||
ntfs_log.handler = handler;
|
ntfs_log.handler = handler;
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
if ( handler == ntfs_log_handler_syslog )
|
if (handler == ntfs_log_handler_syslog)
|
||||||
openlog( "ntfs-3g", LOG_PID, LOG_USER );
|
openlog("ntfs-3g", LOG_PID, LOG_USER);
|
||||||
#endif
|
#endif
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
ntfs_log.handler = ntfs_log_handler_null;
|
ntfs_log.handler = ntfs_log_handler_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,20 +313,20 @@ void ntfs_log_set_handler( ntfs_log_handler *handler )
|
|||||||
* 0 Message wasn't logged
|
* 0 Message wasn't logged
|
||||||
* num Number of output characters
|
* num Number of output characters
|
||||||
*/
|
*/
|
||||||
int ntfs_log_redirect( const char *function, const char *file,
|
int ntfs_log_redirect(const char *function, const char *file,
|
||||||
int line, u32 level, void *data, const char *format, ... )
|
int line, u32 level, void *data, const char *format, ...)
|
||||||
{
|
{
|
||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
int ret;
|
int ret;
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
if ( !( ntfs_log.levels & level ) ) /* Don't log this message */
|
if (!(ntfs_log.levels & level)) /* Don't log this message */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
va_start( args, format );
|
va_start(args, format);
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
ret = ntfs_log.handler( function, file, line, level, data, format, args );
|
ret = ntfs_log.handler(function, file, line, level, data, format, args);
|
||||||
va_end( args );
|
va_end(args);
|
||||||
|
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
return ret;
|
return ret;
|
||||||
@ -361,35 +355,33 @@ int ntfs_log_redirect( const char *function, const char *file,
|
|||||||
|
|
||||||
#define LOG_LINE_LEN 512
|
#define LOG_LINE_LEN 512
|
||||||
|
|
||||||
int ntfs_log_handler_syslog( const char *function __attribute__( ( unused ) ),
|
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||||
const char *file __attribute__( ( unused ) ),
|
const char *file __attribute__((unused)),
|
||||||
int line __attribute__( ( unused ) ), u32 level,
|
int line __attribute__((unused)), u32 level,
|
||||||
void *data __attribute__( ( unused ) ),
|
void *data __attribute__((unused)),
|
||||||
const char *format, va_list args )
|
const char *format, va_list args)
|
||||||
{
|
{
|
||||||
char logbuf[LOG_LINE_LEN];
|
char logbuf[LOG_LINE_LEN];
|
||||||
int ret, olderr = errno;
|
int ret, olderr = errno;
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
if ( ( level & NTFS_LOG_LEVEL_PERROR ) && errno == ENOSPC )
|
if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC)
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
ret = vsnprintf( logbuf, LOG_LINE_LEN, format, args );
|
ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
|
||||||
if ( ret < 0 )
|
if (ret < 0) {
|
||||||
{
|
vsyslog(LOG_NOTICE, format, args);
|
||||||
vsyslog( LOG_NOTICE, format, args );
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( LOG_LINE_LEN > ret + 3 ) && ( level & NTFS_LOG_LEVEL_PERROR ) )
|
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||||
{
|
strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
|
||||||
strncat( logbuf, ": ", LOG_LINE_LEN - ret - 1 );
|
strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||||
strncat( logbuf, strerror( olderr ), LOG_LINE_LEN - ( ret + 3 ) );
|
ret = strlen(logbuf);
|
||||||
ret = strlen( logbuf );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog( LOG_NOTICE, "%s", logbuf );
|
syslog(LOG_NOTICE, "%s", logbuf);
|
||||||
out:
|
out:
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
return ret;
|
return ret;
|
||||||
@ -417,8 +409,8 @@ out:
|
|||||||
* 0 Message wasn't logged
|
* 0 Message wasn't logged
|
||||||
* num Number of output characters
|
* num Number of output characters
|
||||||
*/
|
*/
|
||||||
int ntfs_log_handler_fprintf( const char *function, const char *file,
|
int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||||
int line, u32 level, void *data, const char *format, va_list args )
|
int line, u32 level, void *data, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
int i;
|
int i;
|
||||||
@ -427,48 +419,47 @@ int ntfs_log_handler_fprintf( const char *function, const char *file,
|
|||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
|
|
||||||
if ( !data ) /* Interpret data as a FILE stream. */
|
if (!data) /* Interpret data as a FILE stream. */
|
||||||
return 0; /* If it's NULL, we can't do anything. */
|
return 0; /* If it's NULL, we can't do anything. */
|
||||||
stream = ( FILE* )data;
|
stream = (FILE*)data;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if ( level == NTFS_LOG_LEVEL_LEAVE )
|
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||||
{
|
if (tab)
|
||||||
if ( tab )
|
|
||||||
tab--;
|
tab--;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i = 0; i < tab; i++ )
|
for (i = 0; i < tab; i++)
|
||||||
ret += fprintf( stream, " " );
|
ret += fprintf(stream, " ");
|
||||||
#endif
|
#endif
|
||||||
if ( ( ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME ) &&
|
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||||
( strchr( file, PATH_SEP ) ) ) /* Abbreviate the filename */
|
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||||
file = strrchr( file, PATH_SEP ) + 1;
|
file = strrchr(file, PATH_SEP) + 1;
|
||||||
|
|
||||||
if ( ntfs_log.flags & NTFS_LOG_FLAG_PREFIX ) /* Prefix the output */
|
if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
|
||||||
ret += fprintf( stream, "%s", ntfs_log_get_prefix( level ) );
|
ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
|
||||||
|
|
||||||
if ( ntfs_log.flags & NTFS_LOG_FLAG_FILENAME ) /* Source filename */
|
if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */
|
||||||
ret += fprintf( stream, "%s ", file );
|
ret += fprintf(stream, "%s ", file);
|
||||||
|
|
||||||
if ( ntfs_log.flags & NTFS_LOG_FLAG_LINE ) /* Source line number */
|
if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */
|
||||||
ret += fprintf( stream, "(%d) ", line );
|
ret += fprintf(stream, "(%d) ", line);
|
||||||
|
|
||||||
if ( ( ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION ) || /* Source function */
|
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||||
( level & NTFS_LOG_LEVEL_TRACE ) || ( level & NTFS_LOG_LEVEL_ENTER ) )
|
(level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
|
||||||
ret += fprintf( stream, "%s(): ", function );
|
ret += fprintf(stream, "%s(): ", function);
|
||||||
|
|
||||||
ret += vfprintf( stream, format, args );
|
ret += vfprintf(stream, format, args);
|
||||||
|
|
||||||
if ( level & NTFS_LOG_LEVEL_PERROR )
|
if (level & NTFS_LOG_LEVEL_PERROR)
|
||||||
ret += fprintf( stream, ": %s\n", strerror( olderr ) );
|
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if ( level == NTFS_LOG_LEVEL_ENTER )
|
if (level == NTFS_LOG_LEVEL_ENTER)
|
||||||
tab++;
|
tab++;
|
||||||
#endif
|
#endif
|
||||||
fflush( stream );
|
fflush(stream);
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -488,9 +479,9 @@ int ntfs_log_handler_fprintf( const char *function, const char *file,
|
|||||||
*
|
*
|
||||||
* Returns: 0 Message wasn't logged
|
* Returns: 0 Message wasn't logged
|
||||||
*/
|
*/
|
||||||
int ntfs_log_handler_null( const char *function __attribute__( ( unused ) ), const char *file __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 ) ),
|
int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)),
|
||||||
const char *format __attribute__( ( unused ) ), va_list args __attribute__( ( unused ) ) )
|
const char *format __attribute__((unused)), va_list args __attribute__((unused)))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -516,13 +507,13 @@ int ntfs_log_handler_null( const char *function __attribute__( ( unused ) ), con
|
|||||||
* 0 Message wasn't logged
|
* 0 Message wasn't logged
|
||||||
* num Number of output characters
|
* num Number of output characters
|
||||||
*/
|
*/
|
||||||
int ntfs_log_handler_stdout( const char *function, const char *file,
|
int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||||
int line, u32 level, void *data, const char *format, va_list args )
|
int line, u32 level, void *data, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
if ( !data )
|
if (!data)
|
||||||
data = stdout;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -547,13 +538,13 @@ int ntfs_log_handler_stdout( const char *function, const char *file,
|
|||||||
* 0 Message wasn't logged
|
* 0 Message wasn't logged
|
||||||
* num Number of output characters
|
* num Number of output characters
|
||||||
*/
|
*/
|
||||||
int ntfs_log_handler_outerr( const char *function, const char *file,
|
int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||||
int line, u32 level, void *data, const char *format, va_list args )
|
int line, u32 level, void *data, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
if ( !data )
|
if (!data)
|
||||||
data = ntfs_log_get_stream( level );
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -577,13 +568,13 @@ int ntfs_log_handler_outerr( const char *function, const char *file,
|
|||||||
* 0 Message wasn't logged
|
* 0 Message wasn't logged
|
||||||
* num Number of output characters
|
* num Number of output characters
|
||||||
*/
|
*/
|
||||||
int ntfs_log_handler_stderr( const char *function, const char *file,
|
int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||||
int line, u32 level, void *data, const char *format, va_list args )
|
int line, u32 level, void *data, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
if ( !data )
|
if (!data)
|
||||||
data = stderr;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -600,30 +591,23 @@ int ntfs_log_handler_stderr( const char *function, const char *file,
|
|||||||
* Returns: TRUE Option understood
|
* Returns: TRUE Option understood
|
||||||
* FALSE Invalid log option
|
* 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 )
|
if (strcmp(option, "--log-debug") == 0) {
|
||||||
{
|
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_DEBUG );
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
} else if (strcmp(option, "--log-verbose") == 0) {
|
||||||
else if ( strcmp( option, "--log-verbose" ) == 0 )
|
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
|
||||||
{
|
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_VERBOSE );
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
} else if (strcmp(option, "--log-quiet") == 0) {
|
||||||
else if ( strcmp( option, "--log-quiet" ) == 0 )
|
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
|
||||||
{
|
|
||||||
ntfs_log_clear_levels( NTFS_LOG_LEVEL_QUIET );
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
} else if (strcmp(option, "--log-trace") == 0) {
|
||||||
else if ( strcmp( option, "--log-trace" ) == 0 )
|
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||||
{
|
|
||||||
ntfs_log_set_levels( NTFS_LOG_LEVEL_TRACE );
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfs_log_debug( "Unknown logging option '%s'\n", option );
|
ntfs_log_debug("Unknown logging option '%s'\n", option);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,37 +34,37 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
/* Function prototype for the logging handlers */
|
/* Function prototype for the logging handlers */
|
||||||
typedef int ( ntfs_log_handler )( const char *function, const char *file, int line,
|
typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
|
||||||
u32 level, void *data, const char *format, va_list args );
|
u32 level, void *data, const char *format, va_list args);
|
||||||
|
|
||||||
/* Set the logging handler from one of the functions, below. */
|
/* Set the logging handler from one of the functions, below. */
|
||||||
void ntfs_log_set_handler( ntfs_log_handler *handler
|
void ntfs_log_set_handler(ntfs_log_handler *handler
|
||||||
__attribute__( ( format( printf, 6, 0 ) ) ) );
|
__attribute__((format(printf, 6, 0))));
|
||||||
|
|
||||||
/* Logging handlers */
|
/* Logging handlers */
|
||||||
ntfs_log_handler ntfs_log_handler_syslog __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_fprintf __attribute__((format(printf, 6, 0)));
|
||||||
ntfs_log_handler ntfs_log_handler_null __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_stdout __attribute__((format(printf, 6, 0)));
|
||||||
ntfs_log_handler ntfs_log_handler_outerr __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_stderr __attribute__((format(printf, 6, 0)));
|
||||||
|
|
||||||
/* Enable/disable certain log levels */
|
/* Enable/disable certain log levels */
|
||||||
u32 ntfs_log_set_levels( u32 levels );
|
u32 ntfs_log_set_levels(u32 levels);
|
||||||
u32 ntfs_log_clear_levels( u32 levels );
|
u32 ntfs_log_clear_levels(u32 levels);
|
||||||
u32 ntfs_log_get_levels( void );
|
u32 ntfs_log_get_levels(void);
|
||||||
|
|
||||||
/* Enable/disable certain log flags */
|
/* Enable/disable certain log flags */
|
||||||
u32 ntfs_log_set_flags( u32 flags );
|
u32 ntfs_log_set_flags(u32 flags);
|
||||||
u32 ntfs_log_clear_flags( u32 flags );
|
u32 ntfs_log_clear_flags(u32 flags);
|
||||||
u32 ntfs_log_get_flags( void );
|
u32 ntfs_log_get_flags(void);
|
||||||
|
|
||||||
/* Turn command-line options into logging flags */
|
/* 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,
|
int ntfs_log_redirect(const char *function, const char *file, int line,
|
||||||
u32 level, void *data, const char *format, ... )
|
u32 level, void *data, const char *format, ...)
|
||||||
__attribute__( ( format( printf, 6, 7 ) ) );
|
__attribute__((format(printf, 6, 7)));
|
||||||
|
|
||||||
/* Logging levels - Determine what gets logged */
|
/* Logging levels - Determine what gets logged */
|
||||||
#define NTFS_LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */
|
#define NTFS_LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */
|
||||||
|
@ -24,23 +24,20 @@
|
|||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
static inline void* ntfs_alloc ( size_t size )
|
static inline void* ntfs_alloc (size_t size) {
|
||||||
{
|
return malloc(size);
|
||||||
return malloc( size );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void* ntfs_align ( size_t size )
|
static inline void* ntfs_align (size_t size) {
|
||||||
{
|
#ifdef __wii__
|
||||||
#ifdef __wii__
|
return memalign(32, size);
|
||||||
return memalign( 32, size );
|
#else
|
||||||
#else
|
return malloc(size);
|
||||||
return malloc( size );
|
#endif
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ntfs_free ( void* mem )
|
static inline void ntfs_free (void* mem) {
|
||||||
{
|
free(mem);
|
||||||
free( mem );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _MEM_ALLOCATE_H */
|
#endif /* _MEM_ALLOCATE_H */
|
||||||
|
1354
source/libntfs/mft.c
1354
source/libntfs/mft.c
File diff suppressed because it is too large
Load Diff
@ -29,8 +29,8 @@
|
|||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
extern int ntfs_mft_records_read( const ntfs_volume *vol, const MFT_REF mref,
|
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||||
const s64 count, MFT_RECORD *b );
|
const s64 count, MFT_RECORD *b);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_mft_record_read - read a record from the mft
|
* ntfs_mft_record_read - read a record from the mft
|
||||||
@ -47,25 +47,25 @@ 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.
|
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||||
*/
|
*/
|
||||||
static __inline__ int ntfs_mft_record_read( const ntfs_volume *vol,
|
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
|
||||||
const MFT_REF mref, MFT_RECORD *b )
|
const MFT_REF mref, MFT_RECORD *b)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
|
||||||
ret = ntfs_mft_records_read( vol, mref, 1, b );
|
ret = ntfs_mft_records_read(vol, mref, 1, b);
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ntfs_mft_record_check( const ntfs_volume *vol, const MFT_REF mref,
|
extern int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
|
||||||
MFT_RECORD *m );
|
MFT_RECORD *m);
|
||||||
|
|
||||||
extern int ntfs_file_record_read( const ntfs_volume *vol, const MFT_REF mref,
|
extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||||
MFT_RECORD **mrec, ATTR_RECORD **attr );
|
MFT_RECORD **mrec, ATTR_RECORD **attr);
|
||||||
|
|
||||||
extern int ntfs_mft_records_write( const ntfs_volume *vol, const MFT_REF mref,
|
extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||||
const s64 count, MFT_RECORD *b );
|
const s64 count, MFT_RECORD *b);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_mft_record_write - write an mft record to disk
|
* ntfs_mft_record_write - write an mft record to disk
|
||||||
@ -82,14 +82,14 @@ 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.
|
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||||
*/
|
*/
|
||||||
static __inline__ int ntfs_mft_record_write( const ntfs_volume *vol,
|
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
|
||||||
const MFT_REF mref, MFT_RECORD *b )
|
const MFT_REF mref, MFT_RECORD *b)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ntfs_log_enter( "Entering for inode %lld\n", ( long long )MREF( mref ) );
|
ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref));
|
||||||
ret = ntfs_mft_records_write( vol, mref, 1, b );
|
ret = ntfs_mft_records_write(vol, mref, 1, b);
|
||||||
ntfs_log_leave( "\n" );
|
ntfs_log_leave("\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
* non-existent (don't know if Windows' NTFS driver/chkdsk wouldn't view this
|
||||||
* as corruption in itself though).
|
* 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 ) )
|
if (!m || !ntfs_is_mft_record(m->magic))
|
||||||
return 0;
|
return 0;
|
||||||
/* Get the number of used bytes and return it. */
|
/* Get the number of used bytes and return it. */
|
||||||
return le32_to_cpu( m->bytes_in_use );
|
return le32_to_cpu(m->bytes_in_use);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ntfs_mft_record_layout( const ntfs_volume *vol, const MFT_REF mref,
|
extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||||
MFT_RECORD *mrec );
|
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 */
|
#endif /* defined _NTFS_MFT_H */
|
||||||
|
|
||||||
|
@ -40,22 +40,22 @@
|
|||||||
*
|
*
|
||||||
* Return a pointer to the allocated memory or NULL if the request fails.
|
* 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;
|
void *p;
|
||||||
|
|
||||||
p = calloc( 1, size );
|
p = calloc(1, size);
|
||||||
if ( !p )
|
if (!p)
|
||||||
ntfs_log_perror( "Failed to calloc %lld bytes", ( long long )size );
|
ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ntfs_malloc( size_t size )
|
void *ntfs_malloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
p = malloc( size );
|
p = malloc(size);
|
||||||
if ( !p )
|
if (!p)
|
||||||
ntfs_log_perror( "Failed to malloc %lld bytes", ( long long )size );
|
ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#ifndef _NTFS_MISC_H_
|
#ifndef _NTFS_MISC_H_
|
||||||
#define _NTFS_MISC_H_
|
#define _NTFS_MISC_H_
|
||||||
|
|
||||||
void *ntfs_calloc( size_t size );
|
void *ntfs_calloc(size_t size);
|
||||||
void *ntfs_malloc( size_t size );
|
void *ntfs_malloc(size_t size);
|
||||||
|
|
||||||
#endif /* _NTFS_MISC_H_ */
|
#endif /* _NTFS_MISC_H_ */
|
||||||
|
|
||||||
|
@ -47,30 +47,29 @@
|
|||||||
* EIO Multi sector transfer error was detected. Magic of the NTFS
|
* EIO Multi sector transfer error was detected. Magic of the NTFS
|
||||||
* record in @b will have been set to "BAAD".
|
* 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_ofs, usa_count, usn;
|
||||||
u16 *usa_pos, *data_pos;
|
u16 *usa_pos, *data_pos;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace("Entering\n");
|
||||||
|
|
||||||
/* Setup the variables. */
|
/* Setup the variables. */
|
||||||
usa_ofs = le16_to_cpu( b->usa_ofs );
|
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
/* Decrement usa_count to get number of fixups. */
|
/* Decrement usa_count to get number of fixups. */
|
||||||
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||||
/* Size and alignment checks. */
|
/* Size and alignment checks. */
|
||||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||||
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: magic: 0x%08x size: %d usa_ofs: %d "
|
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
|
||||||
"usa_count: %d", __FUNCTION__, *( le32 * )b,
|
"usa_count: %d", __FUNCTION__, *(le32 *)b,
|
||||||
size, usa_ofs, usa_count );
|
size, usa_ofs, usa_count);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Position of usn in update sequence array. */
|
/* Position of usn in update sequence array. */
|
||||||
usa_pos = ( u16* )b + usa_ofs / sizeof( u16 );
|
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||||
/*
|
/*
|
||||||
* The update sequence number which has to be equal to each of the
|
* 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
|
* u16 values before they are fixed up. Note no need to care for
|
||||||
@ -82,42 +81,39 @@ int ntfs_mst_post_read_fixup( NTFS_RECORD *b, const u32 size )
|
|||||||
/*
|
/*
|
||||||
* Position in protected data of first u16 that needs fixing up.
|
* Position in protected data of first u16 that needs fixing up.
|
||||||
*/
|
*/
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
/*
|
/*
|
||||||
* Check for incomplete multi sector transfer(s).
|
* Check for incomplete multi sector transfer(s).
|
||||||
*/
|
*/
|
||||||
while ( usa_count-- )
|
while (usa_count--) {
|
||||||
{
|
if (*data_pos != usn) {
|
||||||
if ( *data_pos != usn )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Incomplete multi sector transfer detected! )-:
|
* Incomplete multi sector transfer detected! )-:
|
||||||
* Set the magic to "BAAD" and return failure.
|
* Set the magic to "BAAD" and return failure.
|
||||||
* Note that magic_BAAD is already converted to le32.
|
* Note that magic_BAAD is already converted to le32.
|
||||||
*/
|
*/
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
ntfs_log_perror( "Incomplete multi-sector transfer: "
|
ntfs_log_perror("Incomplete multi-sector transfer: "
|
||||||
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
|
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
|
||||||
" %d data: %d usn: %d", *( le32 * )b, size,
|
" %d data: %d usn: %d", *(le32 *)b, size,
|
||||||
usa_ofs, usa_count, *data_pos, usn );
|
usa_ofs, usa_count, *data_pos, usn);
|
||||||
b->magic = magic_BAAD;
|
b->magic = magic_BAAD;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data_pos += NTFS_BLOCK_SIZE / sizeof( u16 );
|
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||||
}
|
}
|
||||||
/* Re-setup the variables. */
|
/* Re-setup the variables. */
|
||||||
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while ( usa_count-- )
|
while (usa_count--) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
*/
|
*/
|
||||||
*data_pos = *( ++usa_pos );
|
*data_pos = *(++usa_pos);
|
||||||
/* Increment position in data as well. */
|
/* Increment position in data as well. */
|
||||||
data_pos += NTFS_BLOCK_SIZE / sizeof( u16 );
|
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -142,59 +138,56 @@ 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
|
* otherwise a random word will be used (whatever was in the record at that
|
||||||
* position at that time).
|
* 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_ofs, usa_count, usn;
|
||||||
u16 *usa_pos, *data_pos;
|
u16 *usa_pos, *data_pos;
|
||||||
|
|
||||||
ntfs_log_trace( "Entering\n" );
|
ntfs_log_trace("Entering\n");
|
||||||
|
|
||||||
/* Sanity check + only fixup if it makes sense. */
|
/* Sanity check + only fixup if it makes sense. */
|
||||||
if ( !b || ntfs_is_baad_record( b->magic ) ||
|
if (!b || ntfs_is_baad_record(b->magic) ||
|
||||||
ntfs_is_hole_record( b->magic ) )
|
ntfs_is_hole_record(b->magic)) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s: bad argument", __FUNCTION__ );
|
ntfs_log_perror("%s: bad argument", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Setup the variables. */
|
/* Setup the variables. */
|
||||||
usa_ofs = le16_to_cpu( b->usa_ofs );
|
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
/* Decrement usa_count to get number of fixups. */
|
/* Decrement usa_count to get number of fixups. */
|
||||||
usa_count = le16_to_cpu( b->usa_count ) - 1;
|
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||||
/* Size and alignment checks. */
|
/* Size and alignment checks. */
|
||||||
if ( size & ( NTFS_BLOCK_SIZE - 1 ) || usa_ofs & 1 ||
|
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||||
( u32 )( usa_ofs + ( usa_count * 2 ) ) > size ||
|
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||||
( size >> NTFS_BLOCK_SIZE_BITS ) != usa_count )
|
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror( "%s", __FUNCTION__ );
|
ntfs_log_perror("%s", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* Position of usn in update sequence array. */
|
/* Position of usn in update sequence array. */
|
||||||
usa_pos = ( u16* )( ( u8* )b + usa_ofs );
|
usa_pos = (u16*)((u8*)b + usa_ofs);
|
||||||
/*
|
/*
|
||||||
* Cyclically increment the update sequence number
|
* Cyclically increment the update sequence number
|
||||||
* (skipping 0 and -1, i.e. 0xffff).
|
* (skipping 0 and -1, i.e. 0xffff).
|
||||||
*/
|
*/
|
||||||
usn = le16_to_cpup( usa_pos ) + 1;
|
usn = le16_to_cpup(usa_pos) + 1;
|
||||||
if ( usn == 0xffff || !usn )
|
if (usn == 0xffff || !usn)
|
||||||
usn = 1;
|
usn = 1;
|
||||||
usn = cpu_to_le16( usn );
|
usn = cpu_to_le16(usn);
|
||||||
*usa_pos = usn;
|
*usa_pos = usn;
|
||||||
/* Position in data of first u16 that needs fixing up. */
|
/* Position in data of first u16 that needs fixing up. */
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while ( usa_count-- )
|
while (usa_count--) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Increment the position in the usa and save the
|
* Increment the position in the usa and save the
|
||||||
* original data from the data buffer into the usa.
|
* original data from the data buffer into the usa.
|
||||||
*/
|
*/
|
||||||
*( ++usa_pos ) = *data_pos;
|
*(++usa_pos) = *data_pos;
|
||||||
/* Apply fixup to data. */
|
/* Apply fixup to data. */
|
||||||
*data_pos = usn;
|
*data_pos = usn;
|
||||||
/* Increment position in data as well. */
|
/* Increment position in data as well. */
|
||||||
data_pos += NTFS_BLOCK_SIZE / sizeof( u16 );
|
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -208,32 +201,31 @@ int ntfs_mst_pre_write_fixup( NTFS_RECORD *b, const u32 size )
|
|||||||
* ntfs_mst_pre_write_fixup(), thus the data will be fine or we would never
|
* ntfs_mst_pre_write_fixup(), thus the data will be fine or we would never
|
||||||
* have gotten here.
|
* 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_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
u16 usa_count = le16_to_cpu( b->usa_count ) - 1;
|
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. */
|
/* Position of usn in update sequence array. */
|
||||||
usa_pos = ( u16* )b + usa_ofs / sizeof( u16 );
|
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||||
|
|
||||||
/* Position in protected data of first u16 that needs fixing up. */
|
/* Position in protected data of first u16 that needs fixing up. */
|
||||||
data_pos = ( u16* )b + NTFS_BLOCK_SIZE / sizeof( u16 ) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
|
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while ( usa_count-- )
|
while (usa_count--) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
*/
|
*/
|
||||||
*data_pos = *( ++usa_pos );
|
*data_pos = *(++usa_pos);
|
||||||
|
|
||||||
/* Increment position in data as well. */
|
/* Increment position in data as well. */
|
||||||
data_pos += NTFS_BLOCK_SIZE / sizeof( u16 );
|
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
|
||||||
extern int ntfs_mst_post_read_fixup( NTFS_RECORD *b, const u32 size );
|
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 int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size);
|
||||||
extern void ntfs_mst_post_write_fixup( NTFS_RECORD *b );
|
extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b);
|
||||||
|
|
||||||
#endif /* defined _NTFS_MST_H */
|
#endif /* defined _NTFS_MST_H */
|
||||||
|
|
||||||
|
@ -41,10 +41,9 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
// NTFS device driver devoptab
|
// NTFS device driver devoptab
|
||||||
static const devoptab_t devops_ntfs =
|
static const devoptab_t devops_ntfs = {
|
||||||
{
|
|
||||||
NULL, /* Device name */
|
NULL, /* Device name */
|
||||||
sizeof ( ntfs_file_state ),
|
sizeof (ntfs_file_state),
|
||||||
ntfs_open_r,
|
ntfs_open_r,
|
||||||
ntfs_close_r,
|
ntfs_close_r,
|
||||||
ntfs_write_r,
|
ntfs_write_r,
|
||||||
@ -57,7 +56,7 @@ static const devoptab_t devops_ntfs =
|
|||||||
ntfs_chdir_r,
|
ntfs_chdir_r,
|
||||||
ntfs_rename_r,
|
ntfs_rename_r,
|
||||||
ntfs_mkdir_r,
|
ntfs_mkdir_r,
|
||||||
sizeof ( ntfs_dir_state ),
|
sizeof (ntfs_dir_state),
|
||||||
ntfs_diropen_r,
|
ntfs_diropen_r,
|
||||||
ntfs_dirreset_r,
|
ntfs_dirreset_r,
|
||||||
ntfs_dirnext_r,
|
ntfs_dirnext_r,
|
||||||
@ -68,21 +67,20 @@ static const devoptab_t devops_ntfs =
|
|||||||
NULL /* Device data */
|
NULL /* Device data */
|
||||||
};
|
};
|
||||||
|
|
||||||
void ntfsInit ( void )
|
void ntfsInit (void)
|
||||||
{
|
{
|
||||||
static bool isInit = false;
|
static bool isInit = false;
|
||||||
|
|
||||||
// Initialise ntfs-3g (if not already done so)
|
// Initialise ntfs-3g (if not already done so)
|
||||||
if ( !isInit )
|
if (!isInit) {
|
||||||
{
|
|
||||||
isInit = true;
|
isInit = true;
|
||||||
|
|
||||||
// Set the log handler
|
// Set the log handler
|
||||||
#ifdef NTFS_ENABLE_LOG
|
#ifdef NTFS_ENABLE_LOG
|
||||||
ntfs_log_set_handler( ntfs_log_handler_stderr );
|
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||||
#else
|
#else
|
||||||
ntfs_log_set_handler( ntfs_log_handler_null );
|
ntfs_log_set_handler(ntfs_log_handler_null);
|
||||||
#endif
|
#endif
|
||||||
// Set our current local
|
// Set our current local
|
||||||
ntfs_set_locale();
|
ntfs_set_locale();
|
||||||
|
|
||||||
@ -91,7 +89,7 @@ void ntfsInit ( void )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
||||||
{
|
{
|
||||||
MASTER_BOOT_RECORD mbr;
|
MASTER_BOOT_RECORD mbr;
|
||||||
PARTITION_RECORD *partition = NULL;
|
PARTITION_RECORD *partition = NULL;
|
||||||
@ -100,8 +98,7 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
sec_t part_lba = 0;
|
sec_t part_lba = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
u8 buffer[512];
|
u8 buffer[512];
|
||||||
MASTER_BOOT_RECORD mbr;
|
MASTER_BOOT_RECORD mbr;
|
||||||
EXTENDED_BOOT_RECORD ebr;
|
EXTENDED_BOOT_RECORD ebr;
|
||||||
@ -109,79 +106,66 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
} sector;
|
} sector;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !interface )
|
if (!interface) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !partitions )
|
if (!partitions)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Initialise ntfs-3g
|
// Initialise ntfs-3g
|
||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Start the device and check that it is inserted
|
// Start the device and check that it is inserted
|
||||||
if ( !interface->startup() )
|
if (!interface->startup()) {
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( !interface->isInserted() )
|
if (!interface->isInserted()) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the first sector on the device
|
// Read the first sector on the device
|
||||||
if ( !interface->readSectors( 0, 1, §or.buffer ) )
|
if (!interface->readSectors(0, 1, §or.buffer)) {
|
||||||
{
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the devices master boot record
|
// If this is the devices master boot record
|
||||||
if ( sector.mbr.signature == MBR_SIGNATURE )
|
if (sector.mbr.signature == MBR_SIGNATURE) {
|
||||||
{
|
memcpy(&mbr, §or, sizeof(MASTER_BOOT_RECORD));
|
||||||
memcpy( &mbr, §or, sizeof( MASTER_BOOT_RECORD ) );
|
ntfs_log_debug("Valid Master Boot Record found\n");
|
||||||
ntfs_log_debug( "Valid Master Boot Record found\n" );
|
|
||||||
|
|
||||||
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
// 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];
|
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,
|
ntfs_log_debug("Partition %i: %s, sector %d, type 0x%x\n", i + 1,
|
||||||
partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||||
part_lba, partition->type );
|
part_lba, partition->type);
|
||||||
|
|
||||||
// Figure out what type of partition this is
|
// Figure out what type of partition this is
|
||||||
switch ( partition->type )
|
switch (partition->type) {
|
||||||
{
|
|
||||||
|
|
||||||
// Ignore empty partitions
|
// Ignore empty partitions
|
||||||
case PARTITION_TYPE_EMPTY:
|
case PARTITION_TYPE_EMPTY:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// NTFS partition
|
// NTFS partition
|
||||||
case PARTITION_TYPE_NTFS:
|
case PARTITION_TYPE_NTFS: {
|
||||||
{
|
ntfs_log_debug("Partition %i: Claims to be NTFS\n", i + 1);
|
||||||
ntfs_log_debug( "Partition %i: Claims to be NTFS\n", i + 1 );
|
|
||||||
|
|
||||||
// Read and validate the NTFS partition
|
// Read and validate the NTFS partition
|
||||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
if (interface->readSectors(part_lba, 1, §or)) {
|
||||||
{
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||||
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) {
|
||||||
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_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_debug("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
|
||||||
{
|
|
||||||
ntfs_log_debug( "Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,79 +175,63 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
|
|
||||||
// DOS 3.3+ or Windows 95 extended partition
|
// DOS 3.3+ or Windows 95 extended partition
|
||||||
case PARTITION_TYPE_DOS33_EXTENDED:
|
case PARTITION_TYPE_DOS33_EXTENDED:
|
||||||
case PARTITION_TYPE_WIN95_EXTENDED:
|
case PARTITION_TYPE_WIN95_EXTENDED: {
|
||||||
{
|
ntfs_log_debug("Partition %i: Claims to be Extended\n", i + 1);
|
||||||
ntfs_log_debug( "Partition %i: Claims to be Extended\n", i + 1 );
|
|
||||||
|
|
||||||
// Walk the extended partition chain, finding all NTFS partitions within it
|
// Walk the extended partition chain, finding all NTFS partitions within it
|
||||||
sec_t ebr_lba = part_lba;
|
sec_t ebr_lba = part_lba;
|
||||||
sec_t next_erb_lba = 0;
|
sec_t next_erb_lba = 0;
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
|
|
||||||
// Read and validate the extended boot record
|
// Read and validate the extended boot record
|
||||||
if ( interface->readSectors( ebr_lba + next_erb_lba, 1, §or ) )
|
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
||||||
{
|
if (sector.ebr.signature == EBR_SIGNATURE) {
|
||||||
if ( sector.ebr.signature == EBR_SIGNATURE )
|
ntfs_log_debug("Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
||||||
{
|
|
||||||
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.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
||||||
sector.ebr.partition.type );
|
sector.ebr.partition.type);
|
||||||
|
|
||||||
// Get the start sector of the current partition
|
// Get the start sector of the current partition
|
||||||
// and the next extended boot record in the chain
|
// and the next extended boot record in the chain
|
||||||
part_lba = ebr_lba + next_erb_lba + le32_to_cpu( sector.ebr.partition.lba_start );
|
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 );
|
next_erb_lba = le32_to_cpu(sector.ebr.next_ebr.lba_start);
|
||||||
|
|
||||||
// Check if this partition has a valid NTFS boot record
|
// Check if this partition has a valid NTFS boot record
|
||||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
if (interface->readSectors(part_lba, 1, §or)) {
|
||||||
{
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||||
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_debug( "Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba );
|
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 ( 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 )
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||||
{
|
|
||||||
partition_starts[partition_count] = part_lba;
|
partition_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
next_erb_lba = 0;
|
next_erb_lba = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} while (next_erb_lba);
|
||||||
while ( next_erb_lba );
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unknown or unsupported partition type
|
// Unknown or unsupported partition type
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
|
|
||||||
// Check if this partition has a valid NTFS boot record anyway,
|
// Check if this partition has a valid NTFS boot record anyway,
|
||||||
// it might be misrepresented due to a lazy partition editor
|
// it might be misrepresented due to a lazy partition editor
|
||||||
if ( interface->readSectors( part_lba, 1, §or ) )
|
if (interface->readSectors(part_lba, 1, §or)) {
|
||||||
{
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
||||||
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_debug( "Partition %i: Valid NTFS boot sector found\n", i + 1 );
|
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->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 )
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||||
{
|
|
||||||
partition_starts[partition_count] = part_lba;
|
partition_starts[partition_count] = part_lba;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
@ -279,21 +247,15 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Else it is assumed this device has no master boot record
|
// Else it is assumed this device has no master boot record
|
||||||
}
|
} else {
|
||||||
else
|
ntfs_log_debug("No Master Boot Record was found!\n");
|
||||||
{
|
|
||||||
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
|
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
||||||
for ( i = 0; i < 64; i++ )
|
for (i = 0; i < 64; i++) {
|
||||||
{
|
if (interface->readSectors(i, 1, §or)) {
|
||||||
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 ( sector.boot.oem_id == NTFS_OEM_ID )
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
||||||
{
|
|
||||||
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_starts[partition_count] = i;
|
||||||
partition_count++;
|
partition_count++;
|
||||||
}
|
}
|
||||||
@ -307,12 +269,10 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
/*interface->shutdown();*/
|
/*interface->shutdown();*/
|
||||||
|
|
||||||
// Return the found partitions (if any)
|
// Return the found partitions (if any)
|
||||||
if ( partition_count > 0 )
|
if (partition_count > 0) {
|
||||||
{
|
*partitions = (sec_t*)ntfs_alloc(sizeof(sec_t) * partition_count);
|
||||||
*partitions = ( sec_t* )ntfs_alloc( sizeof( sec_t ) * partition_count );
|
if (*partitions) {
|
||||||
if ( *partitions )
|
memcpy(*partitions, &partition_starts, sizeof(sec_t) * partition_count);
|
||||||
{
|
|
||||||
memcpy( *partitions, &partition_starts, sizeof( sec_t ) * partition_count );
|
|
||||||
return partition_count;
|
return partition_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,7 +280,7 @@ int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
||||||
{
|
{
|
||||||
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
||||||
const INTERFACE_ID *disc = NULL;
|
const INTERFACE_ID *disc = NULL;
|
||||||
@ -335,34 +295,26 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Find and mount all NTFS partitions on all known devices
|
// 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];
|
disc = &discs[i];
|
||||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||||
if ( partition_count > 0 && partitions )
|
if (partition_count > 0 && partitions) {
|
||||||
{
|
for (j = 0, k = 0; j < partition_count; j++) {
|
||||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
|
||||||
{
|
|
||||||
|
|
||||||
// Find the next unused mount name
|
// Find the next unused mount name
|
||||||
do
|
do {
|
||||||
{
|
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
if (k >= NTFS_MAX_MOUNTS) {
|
||||||
if ( k >= NTFS_MAX_MOUNTS )
|
ntfs_free(partitions);
|
||||||
{
|
|
||||||
ntfs_free( partitions );
|
|
||||||
errno = EADDRNOTAVAIL;
|
errno = EADDRNOTAVAIL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} while (ntfsGetDevice(name, false));
|
||||||
while ( ntfsGetDevice( name, false ) );
|
|
||||||
|
|
||||||
// Mount the partition
|
// Mount the partition
|
||||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||||
{
|
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
strcpy(mount_points[mount_count].name, name);
|
||||||
{
|
|
||||||
strcpy( mount_points[mount_count].name, name );
|
|
||||||
mount_points[mount_count].interface = disc->interface;
|
mount_points[mount_count].interface = disc->interface;
|
||||||
mount_points[mount_count].startSector = partitions[j];
|
mount_points[mount_count].startSector = partitions[j];
|
||||||
mount_count++;
|
mount_count++;
|
||||||
@ -370,17 +322,15 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ntfs_free( partitions );
|
ntfs_free(partitions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the mounts (if any)
|
// Return the mounts (if any)
|
||||||
if ( mount_count > 0 && mounts )
|
if (mount_count > 0 && mounts) {
|
||||||
{
|
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
if (*mounts) {
|
||||||
if ( *mounts )
|
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||||
{
|
|
||||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
|
||||||
return mount_count;
|
return mount_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,7 +338,7 @@ int ntfsMountAll ( ntfs_md **mounts, u32 flags )
|
|||||||
return 0;
|
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 *discs = ntfsGetDiscInterfaces();
|
||||||
const INTERFACE_ID *disc = NULL;
|
const INTERFACE_ID *disc = NULL;
|
||||||
@ -400,8 +350,7 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
|||||||
int i, j, k;
|
int i, j, k;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !interface )
|
if (!interface) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -410,36 +359,27 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Find the specified device then find and mount all NTFS partitions on it
|
// 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++ )
|
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
||||||
{
|
if (discs[i].interface == interface) {
|
||||||
if ( discs[i].interface == interface )
|
|
||||||
{
|
|
||||||
disc = &discs[i];
|
disc = &discs[i];
|
||||||
partition_count = ntfsFindPartitions( disc->interface, &partitions );
|
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
||||||
if ( partition_count > 0 && partitions )
|
if (partition_count > 0 && partitions) {
|
||||||
{
|
for (j = 0, k = 0; j < partition_count; j++) {
|
||||||
for ( j = 0, k = 0; j < partition_count; j++ )
|
|
||||||
{
|
|
||||||
|
|
||||||
// Find the next unused mount name
|
// Find the next unused mount name
|
||||||
do
|
do {
|
||||||
{
|
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
||||||
sprintf( name, "%s%i", NTFS_MOUNT_PREFIX, k++ );
|
if (k >= NTFS_MAX_MOUNTS) {
|
||||||
if ( k >= NTFS_MAX_MOUNTS )
|
ntfs_free(partitions);
|
||||||
{
|
|
||||||
ntfs_free( partitions );
|
|
||||||
errno = EADDRNOTAVAIL;
|
errno = EADDRNOTAVAIL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} while (ntfsGetDevice(name, false));
|
||||||
while ( ntfsGetDevice( name, false ) );
|
|
||||||
|
|
||||||
// Mount the partition
|
// Mount the partition
|
||||||
if ( mount_count < NTFS_MAX_MOUNTS )
|
if (mount_count < NTFS_MAX_MOUNTS) {
|
||||||
{
|
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
||||||
if ( ntfsMount( name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags ) )
|
strcpy(mount_points[mount_count].name, name);
|
||||||
{
|
|
||||||
strcpy( mount_points[mount_count].name, name );
|
|
||||||
mount_points[mount_count].interface = disc->interface;
|
mount_points[mount_count].interface = disc->interface;
|
||||||
mount_points[mount_count].startSector = partitions[j];
|
mount_points[mount_count].startSector = partitions[j];
|
||||||
mount_count++;
|
mount_count++;
|
||||||
@ -447,26 +387,23 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
ntfs_free( partitions );
|
ntfs_free(partitions);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we couldn't find the device then return with error status
|
// If we couldn't find the device then return with error status
|
||||||
if ( !disc )
|
if (!disc) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the mounts (if any)
|
// Return the mounts (if any)
|
||||||
if ( mount_count > 0 && mounts )
|
if (mount_count > 0 && mounts) {
|
||||||
{
|
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
||||||
*mounts = ( ntfs_md* )ntfs_alloc( sizeof( ntfs_md ) * mount_count );
|
if (*mounts) {
|
||||||
if ( *mounts )
|
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
||||||
{
|
|
||||||
memcpy( *mounts, &mount_points, sizeof( ntfs_md ) * mount_count );
|
|
||||||
return mount_count;
|
return mount_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,14 +411,13 @@ int ntfsMountDevice ( const DISC_INTERFACE *interface, ntfs_md **mounts, u32 fla
|
|||||||
return 0;
|
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;
|
ntfs_vd *vd = NULL;
|
||||||
gekko_fd *fd = NULL;
|
gekko_fd *fd = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !name || !interface )
|
if (!name || !interface) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -490,23 +426,20 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
|||||||
ntfsInit();
|
ntfsInit();
|
||||||
|
|
||||||
// Check that the requested mount name is free
|
// Check that the requested mount name is free
|
||||||
if ( ntfsGetDevice( name, false ) )
|
if (ntfsGetDevice(name, false)) {
|
||||||
{
|
|
||||||
errno = EADDRINUSE;
|
errno = EADDRINUSE;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we can at least read from this device
|
// Check that we can at least read from this device
|
||||||
if ( !( interface->features & FEATURE_MEDIUM_CANREAD ) )
|
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
||||||
{
|
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the volume descriptor
|
// Allocate the volume descriptor
|
||||||
vd = ( ntfs_vd* )ntfs_alloc( sizeof( ntfs_vd ) );
|
vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd));
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -518,15 +451,14 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
|||||||
vd->gid = 0;
|
vd->gid = 0;
|
||||||
vd->fmask = 0;
|
vd->fmask = 0;
|
||||||
vd->dmask = 0;
|
vd->dmask = 0;
|
||||||
vd->atime = ( ( flags & NTFS_UPDATE_ACCESS_TIMES ) ? ATIME_ENABLED : ATIME_DISABLED );
|
vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED);
|
||||||
vd->showHiddenFiles = ( flags & NTFS_SHOW_HIDDEN_FILES );
|
vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES);
|
||||||
vd->showSystemFiles = ( flags & NTFS_SHOW_SYSTEM_FILES );
|
vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES);
|
||||||
|
|
||||||
// Allocate the device driver descriptor
|
// Allocate the device driver descriptor
|
||||||
fd = ( gekko_fd* )ntfs_alloc( sizeof( gekko_fd ) );
|
fd = (gekko_fd*)ntfs_alloc(sizeof(gekko_fd));
|
||||||
if ( !fd )
|
if (!fd) {
|
||||||
{
|
ntfs_free(vd);
|
||||||
ntfs_free( vd );
|
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -540,94 +472,92 @@ bool ntfsMount ( const char *name, const DISC_INTERFACE *interface, sec_t startS
|
|||||||
fd->cachePageSize = cachePageSize;
|
fd->cachePageSize = cachePageSize;
|
||||||
|
|
||||||
// Allocate the device driver
|
// Allocate the device driver
|
||||||
vd->dev = ntfs_device_alloc( name, 0, &ntfs_device_gekko_io_ops, fd );
|
vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd);
|
||||||
if ( !vd->dev )
|
if (!vd->dev) {
|
||||||
{
|
ntfs_free(fd);
|
||||||
ntfs_free( fd );
|
ntfs_free(vd);
|
||||||
ntfs_free( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the mount flags
|
// Build the mount flags
|
||||||
if ( flags & NTFS_READ_ONLY )
|
if (flags & NTFS_READ_ONLY)
|
||||||
vd->flags |= MS_RDONLY;
|
vd->flags |= MS_RDONLY;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( !( interface->features & FEATURE_MEDIUM_CANWRITE ) )
|
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||||
vd->flags |= MS_RDONLY;
|
vd->flags |= MS_RDONLY;
|
||||||
if ( ( interface->features & FEATURE_MEDIUM_CANREAD ) && ( interface->features & FEATURE_MEDIUM_CANWRITE ) )
|
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||||
vd->flags |= MS_EXCLUSIVE;
|
vd->flags |= MS_EXCLUSIVE;
|
||||||
}
|
}
|
||||||
if ( flags & NTFS_RECOVER )
|
if (flags & NTFS_RECOVER)
|
||||||
vd->flags |= MS_RECOVER;
|
vd->flags |= MS_RECOVER;
|
||||||
if ( flags & NTFS_IGNORE_HIBERFILE )
|
if (flags & NTFS_IGNORE_HIBERFILE)
|
||||||
vd->flags |= MS_IGNORE_HIBERFILE;
|
vd->flags |= MS_IGNORE_HIBERFILE;
|
||||||
|
|
||||||
if ( vd->flags & MS_RDONLY )
|
if (vd->flags & MS_RDONLY)
|
||||||
ntfs_log_debug( "Mounting \"%s\" as read-only\n", name );
|
ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
|
||||||
|
|
||||||
// Mount the device
|
// Mount the device
|
||||||
vd->vol = ntfs_device_mount( vd->dev, vd->flags );
|
vd->vol = ntfs_device_mount(vd->dev, vd->flags);
|
||||||
if ( !vd->vol )
|
if (!vd->vol) {
|
||||||
{
|
switch(ntfs_volume_error(errno)) {
|
||||||
switch ( ntfs_volume_error( errno ) )
|
|
||||||
{
|
|
||||||
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
||||||
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
||||||
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
||||||
case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
|
case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
|
||||||
default: errno = EINVAL; break;
|
default: errno = EINVAL; break;
|
||||||
}
|
}
|
||||||
ntfs_device_free( vd->dev );
|
ntfs_device_free(vd->dev);
|
||||||
ntfs_free( vd );
|
ntfs_free(vd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & NTFS_IGNORE_CASE)
|
||||||
|
ntfs_set_ignore_case(vd->vol);
|
||||||
|
|
||||||
// Initialise the volume descriptor
|
// Initialise the volume descriptor
|
||||||
if ( ntfsInitVolume( vd ) )
|
if (ntfsInitVolume(vd)) {
|
||||||
{
|
ntfs_umount(vd->vol, true);
|
||||||
ntfs_umount( vd->vol, true );
|
ntfs_free(vd);
|
||||||
ntfs_free( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the device to the devoptab table
|
// Add the device to the devoptab table
|
||||||
if ( ntfsAddDevice( name, vd ) )
|
if (ntfsAddDevice(name, vd)) {
|
||||||
{
|
ntfsDeinitVolume(vd);
|
||||||
ntfsDeinitVolume( vd );
|
ntfs_umount(vd->vol, true);
|
||||||
ntfs_umount( vd->vol, true );
|
ntfs_free(vd);
|
||||||
ntfs_free( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ntfsUnmount ( const char *name, bool force )
|
void ntfsUnmount (const char *name, bool force)
|
||||||
{
|
{
|
||||||
ntfs_vd *vd = NULL;
|
ntfs_vd *vd = NULL;
|
||||||
|
|
||||||
// Get the devices volume descriptor
|
// Get the devices volume descriptor
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume(name);
|
||||||
if ( !vd )
|
if (!vd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Remove the device from the devoptab table
|
// Remove the device from the devoptab table
|
||||||
ntfsRemoveDevice( name );
|
ntfsRemoveDevice(name);
|
||||||
|
|
||||||
// Deinitialise the volume descriptor
|
// Deinitialise the volume descriptor
|
||||||
ntfsDeinitVolume( vd );
|
ntfsDeinitVolume(vd);
|
||||||
|
|
||||||
// Unmount the volume
|
// Unmount the volume
|
||||||
ntfs_umount( vd->vol, force );
|
ntfs_umount(vd->vol, force);
|
||||||
|
|
||||||
// Free the volume descriptor
|
// Free the volume descriptor
|
||||||
ntfs_free( vd );
|
ntfs_free(vd);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *ntfsGetVolumeName ( const char *name )
|
const char *ntfsGetVolumeName (const char *name)
|
||||||
{
|
{
|
||||||
ntfs_vd *vd = NULL;
|
ntfs_vd *vd = NULL;
|
||||||
//ntfs_attr *na = NULL;
|
//ntfs_attr *na = NULL;
|
||||||
@ -635,21 +565,19 @@ const char *ntfsGetVolumeName ( const char *name )
|
|||||||
//char *volumeName = NULL;
|
//char *volumeName = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !name )
|
if (!name) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the devices volume descriptor
|
// Get the devices volume descriptor
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume(name);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return vd->vol->vol_name;
|
return vd->vol->vol_name;
|
||||||
/*
|
/*
|
||||||
|
|
||||||
// If the volume name has already been cached then just use that
|
// If the volume name has already been cached then just use that
|
||||||
if (vd->name[0])
|
if (vd->name[0])
|
||||||
@ -706,10 +634,10 @@ const char *ntfsGetVolumeName ( const char *name )
|
|||||||
ntfsUnlock(vd);
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return vd->name;
|
return vd->name;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||||
{
|
{
|
||||||
ntfs_vd *vd = NULL;
|
ntfs_vd *vd = NULL;
|
||||||
ntfs_attr *na = NULL;
|
ntfs_attr *na = NULL;
|
||||||
@ -717,62 +645,53 @@ bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
|||||||
int ulabel_len;
|
int ulabel_len;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !name )
|
if (!name) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the devices volume descriptor
|
// Get the devices volume descriptor
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume(name);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Convert the new volume name to unicode
|
// Convert the new volume name to unicode
|
||||||
ulabel_len = ntfsLocalToUnicode( volumeName, &ulabel ) * sizeof( ntfschar );
|
ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
|
||||||
if ( ulabel_len < 0 )
|
if (ulabel_len < 0) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the volume name attribute exists
|
// Check if the volume name attribute exists
|
||||||
na = ntfs_attr_open( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0 );
|
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
||||||
if ( na )
|
if (na) {
|
||||||
{
|
|
||||||
|
|
||||||
// It does, resize it to match the length of the new volume name
|
// It does, resize it to match the length of the new volume name
|
||||||
if ( ntfs_attr_truncate( na, ulabel_len ) )
|
if (ntfs_attr_truncate(na, ulabel_len)) {
|
||||||
{
|
ntfs_free(ulabel);
|
||||||
ntfs_free( ulabel );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the new volume name
|
// Write the new volume name
|
||||||
if ( ntfs_attr_pwrite( na, 0, ulabel_len, ulabel ) != ulabel_len )
|
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
||||||
{
|
ntfs_free(ulabel);
|
||||||
ntfs_free( ulabel );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
// It doesn't, create it now
|
// It doesn't, create it now
|
||||||
if ( ntfs_attr_add( vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, ( u8* )ulabel, ulabel_len ) )
|
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
|
||||||
{
|
ntfs_free(ulabel);
|
||||||
ntfs_free( ulabel );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,27 +701,26 @@ bool ntfsSetVolumeName ( const char *name, const char *volumeName )
|
|||||||
vd->name[0] = '\0';
|
vd->name[0] = '\0';
|
||||||
|
|
||||||
// Close the volume name attribute
|
// Close the volume name attribute
|
||||||
if ( na )
|
if (na)
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
|
|
||||||
// Sync the volume node
|
// Sync the volume node
|
||||||
if ( ntfs_inode_sync( vd->vol->vol_ni ) )
|
if (ntfs_inode_sync(vd->vol->vol_ni)) {
|
||||||
{
|
ntfs_free(ulabel);
|
||||||
ntfs_free( ulabel );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
ntfs_free( ulabel );
|
ntfs_free(ulabel);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const devoptab_t *ntfsGetDevOpTab ( void )
|
const devoptab_t *ntfsGetDevOpTab (void)
|
||||||
{
|
{
|
||||||
return &devops_ntfs;
|
return &devops_ntfs;
|
||||||
}
|
}
|
||||||
|
@ -23,25 +23,24 @@
|
|||||||
#define _LIBNTFS_H
|
#define _LIBNTFS_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C" {
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gctypes.h>
|
#include <gctypes.h>
|
||||||
#include <gccore.h>
|
#include <gccore.h>
|
||||||
#include <ogc/disc_io.h>
|
#include <ogc/disc_io.h>
|
||||||
|
|
||||||
/* NTFS errno values */
|
/* NTFS errno values */
|
||||||
#define ENOPART 3000 /* No partition was found */
|
#define ENOPART 3000 /* No partition was found */
|
||||||
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
|
#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 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 */
|
#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_COUNT 8 /* The default number of pages in the cache */
|
||||||
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
|
#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_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_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
|
||||||
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
|
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
|
||||||
@ -49,20 +48,20 @@ extern "C"
|
|||||||
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
|
#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_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
|
||||||
#define NTFS_READ_ONLY 0x00000020 /* Mount in read only mode */
|
#define NTFS_READ_ONLY 0x00000020 /* Mount in read only mode */
|
||||||
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
|
#define NTFS_IGNORE_CASE 0x00000040 /* Ignore case sensitivity. Everything must be and will be provided in lowercase. */
|
||||||
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
|
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES | NTFS_SHOW_SYSTEM_FILES
|
||||||
|
#define NTFS_FORCE NTFS_RECOVER | NTFS_IGNORE_HIBERFILE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_md - NTFS mount descriptor
|
* ntfs_md - NTFS mount descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_md
|
typedef struct _ntfs_md {
|
||||||
{
|
|
||||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||||
sec_t startSector; /* Local block address to first sector of partition */
|
sec_t startSector; /* Local block address to first sector of partition */
|
||||||
} ntfs_md;
|
} ntfs_md;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all NTFS partitions on a block device.
|
* Find all NTFS partitions on a block device.
|
||||||
*
|
*
|
||||||
* @param INTERFACE The block device to search
|
* @param INTERFACE The block device to search
|
||||||
@ -71,9 +70,9 @@ extern "C"
|
|||||||
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
|
* @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
|
* @note The caller is responsible for freeing PARTITIONS when finished with it
|
||||||
*/
|
*/
|
||||||
extern int ntfsFindPartitions ( const DISC_INTERFACE *interface, sec_t **partitions );
|
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount all NTFS partitions on all inserted block devices.
|
* Mount all NTFS partitions on all inserted block devices.
|
||||||
*
|
*
|
||||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||||
@ -83,9 +82,9 @@ extern "C"
|
|||||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||||
* @note All device caches are setup using default values (see above)
|
* @note All device caches are setup using default values (see above)
|
||||||
*/
|
*/
|
||||||
extern int ntfsMountAll ( ntfs_md **mounts, u32 flags );
|
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount all NTFS partitions on a block devices.
|
* Mount all NTFS partitions on a block devices.
|
||||||
*
|
*
|
||||||
* @param INTERFACE The block device to mount.
|
* @param INTERFACE The block device to mount.
|
||||||
@ -96,9 +95,9 @@ extern "C"
|
|||||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||||
* @note The device cache is setup using default values (see above)
|
* @note The device cache is setup using default values (see above)
|
||||||
*/
|
*/
|
||||||
extern int ntfsMountDevice ( const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags );
|
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount a NTFS partition from a specific sector on a block device.
|
* 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 NAME The name to mount the device under (can then be accessed as "NAME:/")
|
||||||
@ -111,26 +110,26 @@ extern "C"
|
|||||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
* @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
|
* @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 );
|
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unmount a NTFS partition.
|
* Unmount a NTFS partition.
|
||||||
*
|
*
|
||||||
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
|
* @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)
|
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
|
||||||
*/
|
*/
|
||||||
extern void ntfsUnmount ( const char *name, bool force );
|
extern void ntfsUnmount (const char *name, bool force);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the volume name of a mounted NTFS partition.
|
* Get the volume name of a mounted NTFS partition.
|
||||||
*
|
*
|
||||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
* @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)
|
* @return The volumes name if successful or NULL if an error occurred (see errno)
|
||||||
*/
|
*/
|
||||||
extern const char *ntfsGetVolumeName ( const char *name );
|
extern const char *ntfsGetVolumeName (const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the volume name of a mounted NTFS partition.
|
* Set the volume name of a mounted NTFS partition.
|
||||||
*
|
*
|
||||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||||
@ -139,10 +138,7 @@ extern "C"
|
|||||||
* @return True if mount was successful, false if an error occurred (see errno)
|
* @return True if mount was successful, false if an error occurred (see errno)
|
||||||
* @note The mount must be write-enabled else this will fail
|
* @note The mount must be write-enabled else this will fail
|
||||||
*/
|
*/
|
||||||
extern bool ntfsSetVolumeName ( const char *name, const char *volumeName );
|
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 );
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -47,24 +47,23 @@
|
|||||||
|
|
||||||
#define STATE(x) ((ntfs_dir_state*)(x)->dirStruct)
|
#define STATE(x) ((ntfs_dir_state*)(x)->dirStruct)
|
||||||
|
|
||||||
void ntfsCloseDir ( ntfs_dir_state *dir )
|
void ntfsCloseDir (ntfs_dir_state *dir)
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !dir || !dir->vd )
|
if (!dir || !dir->vd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Free the directory entries (if any)
|
// Free the directory entries (if any)
|
||||||
while ( dir->first )
|
while (dir->first) {
|
||||||
{
|
|
||||||
ntfs_dir_entry *next = dir->first->next;
|
ntfs_dir_entry *next = dir->first->next;
|
||||||
ntfs_free( dir->first->name );
|
ntfs_free(dir->first->name);
|
||||||
ntfs_free( dir->first );
|
ntfs_free(dir->first);
|
||||||
dir->first = next;
|
dir->first = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the directory (if open)
|
// Close the directory (if open)
|
||||||
if ( dir->ni )
|
if (dir->ni)
|
||||||
ntfsCloseEntry( dir->vd, dir->ni );
|
ntfsCloseEntry(dir->vd, dir->ni);
|
||||||
|
|
||||||
// Reset the directory state
|
// Reset the directory state
|
||||||
dir->ni = NULL;
|
dir->ni = NULL;
|
||||||
@ -74,280 +73,264 @@ void ntfsCloseDir ( ntfs_dir_state *dir )
|
|||||||
return;
|
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
|
// Short circuit cases were we don't actually have to do anything
|
||||||
if ( !st || !path )
|
if (!st || !path)
|
||||||
return 0;
|
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_vd *vd = NULL;
|
||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume(path);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
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;
|
st->st_mode = S_IFDIR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Find the entry
|
// Find the entry
|
||||||
ni = ntfsOpenEntry( vd, path );
|
ni = ntfsOpenEntry(vd, path);
|
||||||
if ( !ni )
|
if (!ni) {
|
||||||
{
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the entry stats
|
// Get the entry stats
|
||||||
int ret = ntfsStat( vd, ni, st );
|
int ret = ntfsStat(vd, ni, st);
|
||||||
if ( ret )
|
if (ret)
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
|
|
||||||
// Close the entry
|
// Close the entry
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry(vd, ni);
|
||||||
|
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
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_vd *vd = NULL;
|
||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( existing );
|
vd = ntfsGetVolume(existing);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Create a symbolic link between the two paths
|
// Create a symbolic link between the two paths
|
||||||
ni = ntfsCreate( vd, existing, S_IFLNK, newLink );
|
ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
|
||||||
if ( !ni )
|
if (!ni) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the symbolic link
|
// Close the symbolic link
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry(vd, ni);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
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
|
// Unlink the entry
|
||||||
int ret = ntfsUnlink( ntfsGetVolume( name ), name );
|
int ret = ntfsUnlink(ntfsGetVolume(name), name);
|
||||||
if ( ret )
|
if (ret)
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
|
|
||||||
return ret;
|
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_vd *vd = NULL;
|
||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( name );
|
vd = ntfsGetVolume(name);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Find the directory
|
// Find the directory
|
||||||
ni = ntfsOpenEntry( vd, name );
|
ni = ntfsOpenEntry(vd, name);
|
||||||
if ( !ni )
|
if (!ni) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that this directory is indeed a directory
|
// Ensure that this directory is indeed a directory
|
||||||
if ( !( ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||||
{
|
ntfsCloseEntry(vd, ni);
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the old current directory (if any)
|
// Close the old current directory (if any)
|
||||||
if ( vd->cwd_ni )
|
if (vd->cwd_ni)
|
||||||
ntfsCloseEntry( vd, vd->cwd_ni );
|
ntfsCloseEntry(vd, vd->cwd_ni);
|
||||||
|
|
||||||
// Set the new current directory
|
// Set the new current directory
|
||||||
vd->cwd_ni = ni;
|
vd->cwd_ni = ni;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
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_vd *vd = NULL;
|
||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( oldName );
|
vd = ntfsGetVolume(oldName);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// You cannot rename between devices
|
// You cannot rename between devices
|
||||||
if ( vd != ntfsGetVolume( newName ) )
|
if(vd != ntfsGetVolume(newName)) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = EXDEV;
|
r->_errno = EXDEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is no existing entry with the new name
|
// Check that there is no existing entry with the new name
|
||||||
ni = ntfsOpenEntry( vd, newName );
|
ni = ntfsOpenEntry(vd, newName);
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
ntfsCloseEntry(vd, ni);
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = EEXIST;
|
r->_errno = EEXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link the old entry with the new one
|
// Link the old entry with the new one
|
||||||
if ( ntfsLink( vd, oldName, newName ) )
|
if (ntfsLink(vd, oldName, newName)) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink the old entry
|
// Unlink the old entry
|
||||||
if ( ntfsUnlink( vd, oldName ) )
|
if (ntfsUnlink(vd, oldName)) {
|
||||||
{
|
if (ntfsUnlink(vd, newName)) {
|
||||||
if ( ntfsUnlink( vd, newName ) )
|
ntfsUnlock(vd);
|
||||||
{
|
|
||||||
ntfsUnlock( vd );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
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_vd *vd = NULL;
|
||||||
ntfs_inode *ni = NULL;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume(path);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Create the directory
|
// Create the directory
|
||||||
ni = ntfsCreate( vd, path, S_IFDIR, NULL );
|
ni = ntfsCreate(vd, path, S_IFDIR, NULL);
|
||||||
if ( !ni )
|
if (!ni) {
|
||||||
{
|
ntfsUnlock(vd);
|
||||||
ntfsUnlock( vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the directory
|
// Close the directory
|
||||||
ntfsCloseEntry( vd, ni );
|
ntfsCloseEntry(vd, ni);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
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;
|
ntfs_vd *vd = NULL;
|
||||||
s64 size;
|
s64 size;
|
||||||
int delta_bits;
|
int delta_bits;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
vd = ntfsGetVolume( path );
|
vd = ntfsGetVolume(path);
|
||||||
if ( !vd )
|
if (!vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases were we don't actually have to do anything
|
// Short circuit cases were we don't actually have to do anything
|
||||||
if ( !buf )
|
if (!buf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( vd );
|
ntfsLock(vd);
|
||||||
|
|
||||||
// Zero out the stat buffer
|
// 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;
|
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;
|
buf->f_blocks = vd->vol->nr_clusters;
|
||||||
|
|
||||||
// Free blocks available for all and for non-privileged processes
|
// 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;
|
buf->f_bfree = buf->f_bavail = size;
|
||||||
|
|
||||||
// Free inodes on the free space
|
// Free inodes on the free space
|
||||||
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
|
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
|
||||||
if ( delta_bits >= 0 )
|
if (delta_bits >= 0)
|
||||||
size <<= delta_bits;
|
size <<= delta_bits;
|
||||||
else
|
else
|
||||||
size >>= -delta_bits;
|
size >>= -delta_bits;
|
||||||
|
|
||||||
// Number of inodes at this point in time
|
// 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
|
// Free inodes available for all and for non-privileged processes
|
||||||
size += vd->vol->free_mft_records;
|
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
|
// File system id
|
||||||
buf->f_fsid = vd->id;
|
buf->f_fsid = vd->id;
|
||||||
|
|
||||||
// Bit mask of f_flag values.
|
// 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
|
// Maximum length of filenames
|
||||||
buf->f_namemax = NTFS_MAX_NAME_LEN;
|
buf->f_namemax = NTFS_MAX_NAME_LEN;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( vd );
|
ntfsUnlock(vd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -396,83 +379,74 @@ int ntfs_statvfs_r ( struct _reent *r, const char *path, struct statvfs *buf )
|
|||||||
/**
|
/**
|
||||||
* PRIVATE: Callback for directory walking
|
* PRIVATE: Callback for directory walking
|
||||||
*/
|
*/
|
||||||
int ntfs_readdir_filler ( DIR_ITER *dirState, const ntfschar *name, const int name_len, const int name_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 )
|
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;
|
ntfs_dir_entry *entry = NULL;
|
||||||
char *entry_name = NULL;
|
char *entry_name = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !dir || !dir->vd )
|
if (!dir || !dir->vd) {
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore DOS file names
|
// Ignore DOS file names
|
||||||
if ( name_type == FILE_NAME_DOS )
|
if (name_type == FILE_NAME_DOS) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
// 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
|
// 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dir->first && dir->first->mref == FILE_root &&
|
if(dir->first && dir->first->mref == FILE_root &&
|
||||||
MREF( mref ) == FILE_root && strcmp( entry_name, ".." ) == 0 )
|
MREF(mref) == FILE_root && strcmp(entry_name, "..") == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is not the parent or self directory reference
|
// 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
|
// Open the entry
|
||||||
ntfs_inode *ni = ntfs_pathname_to_inode( dir->vd->vol, dir->ni, entry_name );
|
ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name);
|
||||||
if ( !ni )
|
if (!ni)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
// Double check that this entry can be emuerated (as described by the volume descriptor)
|
||||||
if ( ( ( ni->flags & FILE_ATTR_HIDDEN ) && !dir->vd->showHiddenFiles ) ||
|
if (((ni->flags & FILE_ATTR_HIDDEN) && !dir->vd->showHiddenFiles) ||
|
||||||
( ( ni->flags & FILE_ATTR_SYSTEM ) && !dir->vd->showSystemFiles ) )
|
((ni->flags & FILE_ATTR_SYSTEM) && !dir->vd->showSystemFiles)) {
|
||||||
{
|
ntfs_inode_close(ni);
|
||||||
ntfs_inode_close( ni );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the entry
|
// Close the entry
|
||||||
ntfs_inode_close( ni );
|
ntfs_inode_close(ni);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a new directory entry
|
// Allocate a new directory entry
|
||||||
entry = ( ntfs_dir_entry * ) ntfs_alloc( sizeof( ntfs_dir_entry ) );
|
entry = (ntfs_dir_entry *) ntfs_alloc(sizeof(ntfs_dir_entry));
|
||||||
if ( !entry )
|
if (!entry)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// Setup the entry
|
// Setup the entry
|
||||||
entry->name = entry_name;
|
entry->name = entry_name;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
entry->mref = MREF( mref );
|
entry->mref = MREF(mref);
|
||||||
|
|
||||||
// Link the entry to the directory
|
// Link the entry to the directory
|
||||||
if ( !dir->first )
|
if (!dir->first) {
|
||||||
{
|
|
||||||
dir->first = entry;
|
dir->first = entry;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ntfs_dir_entry *last = dir->first;
|
ntfs_dir_entry *last = dir->first;
|
||||||
while ( last->next ) last = last->next;
|
while (last->next) last = last->next;
|
||||||
last->next = entry;
|
last->next = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,48 +455,44 @@ int ntfs_readdir_filler ( DIR_ITER *dirState, const ntfschar *name, const int na
|
|||||||
return 0;
|
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;
|
s64 position = 0;
|
||||||
|
|
||||||
// Get the volume descriptor for this path
|
// Get the volume descriptor for this path
|
||||||
dir->vd = ntfsGetVolume( path );
|
dir->vd = ntfsGetVolume(path);
|
||||||
if ( !dir->vd )
|
if (!dir->vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( dir->vd );
|
ntfsLock(dir->vd);
|
||||||
|
|
||||||
// Find the directory
|
// Find the directory
|
||||||
dir->ni = ntfsOpenEntry( dir->vd, path );
|
dir->ni = ntfsOpenEntry(dir->vd, path);
|
||||||
if ( !dir->ni )
|
if (!dir->ni) {
|
||||||
{
|
ntfsUnlock(dir->vd);
|
||||||
ntfsUnlock( dir->vd );
|
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that this directory is indeed a directory
|
// Ensure that this directory is indeed a directory
|
||||||
if ( !( dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY ) )
|
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||||
{
|
ntfsCloseEntry(dir->vd, dir->ni);
|
||||||
ntfsCloseEntry( dir->vd, dir->ni );
|
ntfsUnlock(dir->vd);
|
||||||
ntfsUnlock( dir->vd );
|
|
||||||
r->_errno = ENOTDIR;
|
r->_errno = ENOTDIR;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the directory
|
// Read the directory
|
||||||
dir->first = dir->current = NULL;
|
dir->first = dir->current = NULL;
|
||||||
if ( ntfs_readdir( dir->ni, &position, dirState, ( ntfs_filldir_t )ntfs_readdir_filler ) )
|
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
||||||
{
|
ntfsCloseDir(dir);
|
||||||
ntfsCloseDir( dir );
|
ntfsUnlock(dir->vd);
|
||||||
ntfsUnlock( dir->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -531,16 +501,13 @@ DIR_ITER *ntfs_diropen_r ( struct _reent *r, DIR_ITER *dirState, const char *pat
|
|||||||
dir->current = dir->first;
|
dir->current = dir->first;
|
||||||
|
|
||||||
// Update directory times
|
// 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
|
// 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->nextOpenDir = dir->vd->firstOpenDir;
|
||||||
dir->vd->firstOpenDir->prevOpenDir = dir;
|
dir->vd->firstOpenDir->prevOpenDir = dir;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
dir->nextOpenDir = NULL;
|
dir->nextOpenDir = NULL;
|
||||||
}
|
}
|
||||||
dir->prevOpenDir = 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++;
|
dir->vd->openDirCount++;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock(dir->vd);
|
||||||
|
|
||||||
return dirState;
|
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
|
// Sanity check
|
||||||
if ( !dir || !dir->vd || !dir->ni )
|
if (!dir || !dir->vd || !dir->ni) {
|
||||||
{
|
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( dir->vd );
|
ntfsLock(dir->vd);
|
||||||
|
|
||||||
// Move to the first entry in the directory
|
// Move to the first entry in the directory
|
||||||
dir->current = dir->first;
|
dir->current = dir->first;
|
||||||
|
|
||||||
// Update directory times
|
// Update directory times
|
||||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock(dir->vd);
|
||||||
|
|
||||||
return 0;
|
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;
|
ntfs_inode *ni = NULL;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !dir || !dir->vd || !dir->ni )
|
if (!dir || !dir->vd || !dir->ni) {
|
||||||
{
|
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( dir->vd );
|
ntfsLock(dir->vd);
|
||||||
|
|
||||||
// Check that there is a entry waiting to be fetched
|
// Check that there is a entry waiting to be fetched
|
||||||
if ( !dir->current )
|
if (!dir->current) {
|
||||||
{
|
ntfsUnlock(dir->vd);
|
||||||
ntfsUnlock( dir->vd );
|
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the current entry
|
// Fetch the current entry
|
||||||
strcpy( filename, dir->current->name );
|
strcpy(filename, dir->current->name);
|
||||||
if ( filestat != NULL )
|
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;
|
filestat->st_mode = S_IFDIR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ni = ntfsOpenEntry( dir->vd, dir->current->name );
|
ni = ntfsOpenEntry(dir->vd, dir->current->name);
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
ntfsStat(dir->vd, ni, filestat);
|
||||||
ntfsStat( dir->vd, ni, filestat );
|
ntfsCloseEntry(dir->vd, ni);
|
||||||
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;
|
dir->current = dir->current->next;
|
||||||
|
|
||||||
// Update directory times
|
// Update directory times
|
||||||
ntfsUpdateTimes( dir->vd, dir->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock(dir->vd);
|
||||||
|
|
||||||
return 0;
|
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
|
// Sanity check
|
||||||
if ( !dir || !dir->vd )
|
if (!dir || !dir->vd) {
|
||||||
{
|
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( dir->vd );
|
ntfsLock(dir->vd);
|
||||||
|
|
||||||
// Close the directory
|
// Close the directory
|
||||||
ntfsCloseDir( dir );
|
ntfsCloseDir(dir);
|
||||||
|
|
||||||
// Remove the directory from the double-linked FILO list of open directories
|
// Remove the directory from the double-linked FILO list of open directories
|
||||||
dir->vd->openDirCount--;
|
dir->vd->openDirCount--;
|
||||||
if ( dir->nextOpenDir )
|
if (dir->nextOpenDir)
|
||||||
dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
|
dir->nextOpenDir->prevOpenDir = dir->prevOpenDir;
|
||||||
if ( dir->prevOpenDir )
|
if (dir->prevOpenDir)
|
||||||
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
|
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
|
||||||
else
|
else
|
||||||
dir->vd->firstOpenDir = dir->nextOpenDir;
|
dir->vd->firstOpenDir = dir->nextOpenDir;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( dir->vd );
|
ntfsUnlock(dir->vd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,7 @@
|
|||||||
/**
|
/**
|
||||||
* ntfs_dir_entry - Directory entry
|
* ntfs_dir_entry - Directory entry
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_dir_entry
|
typedef struct _ntfs_dir_entry {
|
||||||
{
|
|
||||||
char *name;
|
char *name;
|
||||||
u64 mref;
|
u64 mref;
|
||||||
struct _ntfs_dir_entry *next;
|
struct _ntfs_dir_entry *next;
|
||||||
@ -38,8 +37,7 @@ typedef struct _ntfs_dir_entry
|
|||||||
/**
|
/**
|
||||||
* ntfs_dir_state - Directory state
|
* ntfs_dir_state - Directory state
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_dir_state
|
typedef struct _ntfs_dir_state {
|
||||||
{
|
|
||||||
ntfs_vd *vd; /* Volume this directory belongs to */
|
ntfs_vd *vd; /* Volume this directory belongs to */
|
||||||
ntfs_inode *ni; /* Directory descriptor */
|
ntfs_inode *ni; /* Directory descriptor */
|
||||||
ntfs_dir_entry *first; /* The first entry in the directory */
|
ntfs_dir_entry *first; /* The first entry in the directory */
|
||||||
@ -49,22 +47,22 @@ typedef struct _ntfs_dir_state
|
|||||||
} ntfs_dir_state;
|
} ntfs_dir_state;
|
||||||
|
|
||||||
/* Directory state routines */
|
/* Directory state routines */
|
||||||
void ntfsCloseDir ( ntfs_dir_state *file );
|
void ntfsCloseDir (ntfs_dir_state *file);
|
||||||
|
|
||||||
/* Gekko devoptab directory routines for NTFS-based devices */
|
/* 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_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_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_unlink_r (struct _reent *r, const char *name);
|
||||||
extern int ntfs_chdir_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_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_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_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf);
|
||||||
|
|
||||||
/* Gekko devoptab directory walking routines for NTFS-based devices */
|
/* 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 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_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_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 int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState);
|
||||||
|
|
||||||
#endif /* _NTFSDIR_H */
|
#endif /* _NTFSDIR_H */
|
||||||
|
|
||||||
|
@ -45,36 +45,36 @@
|
|||||||
|
|
||||||
#define STATE(x) ((ntfs_file_state*)x)
|
#define STATE(x) ((ntfs_file_state*)x)
|
||||||
|
|
||||||
void ntfsCloseFile ( ntfs_file_state *file )
|
void ntfsCloseFile (ntfs_file_state *file)
|
||||||
{
|
{
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd )
|
if (!file || !file->vd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Special case fix ups for compressed and/or encrypted files
|
// Special case fix ups for compressed and/or encrypted files
|
||||||
if ( file->compressed )
|
if (file->compressed)
|
||||||
ntfs_attr_pclose( file->data_na );
|
ntfs_attr_pclose(file->data_na);
|
||||||
#ifdef HAVE_SETXATTR
|
#ifdef HAVE_SETXATTR
|
||||||
if ( file->encrypted )
|
if (file->encrypted)
|
||||||
ntfs_efs_fixup_attribute( NULL, file->data_na );
|
ntfs_efs_fixup_attribute(NULL, file->data_na);
|
||||||
#endif
|
#endif
|
||||||
// Close the file data attribute (if open)
|
// Close the file data attribute (if open)
|
||||||
if ( file->data_na )
|
if (file->data_na)
|
||||||
ntfs_attr_close( file->data_na );
|
ntfs_attr_close(file->data_na);
|
||||||
|
|
||||||
// Sync the file (and its attributes) to disc
|
// 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 );
|
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME | NTFS_UPDATE_CTIME);
|
||||||
ntfsSync( file->vd, file->ni );
|
ntfsSync(file->vd, file->ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( file->read )
|
if (file->read)
|
||||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_ATIME );
|
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||||
|
|
||||||
// Close the file (if open)
|
// Close the file (if open)
|
||||||
if ( file->ni )
|
if (file->ni)
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
|
|
||||||
// Reset the file state
|
// Reset the file state
|
||||||
file->ni = NULL;
|
file->ni = NULL;
|
||||||
@ -89,132 +89,106 @@ void ntfsCloseFile ( ntfs_file_state *file )
|
|||||||
return;
|
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
|
// Get the volume descriptor for this path
|
||||||
file->vd = ntfsGetVolume( path );
|
file->vd = ntfsGetVolume(path);
|
||||||
if ( !file->vd )
|
if (!file->vd) {
|
||||||
{
|
|
||||||
r->_errno = ENODEV;
|
r->_errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Determine which mode the file is opened for
|
// Determine which mode the file is opened for
|
||||||
file->flags = flags;
|
file->flags = flags;
|
||||||
if ( ( flags & 0x03 ) == O_RDONLY )
|
if ((flags & 0x03) == O_RDONLY) {
|
||||||
{
|
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = false;
|
file->write = false;
|
||||||
file->append = false;
|
file->append = false;
|
||||||
}
|
} else if ((flags & 0x03) == O_WRONLY) {
|
||||||
else if ( ( flags & 0x03 ) == O_WRONLY )
|
|
||||||
{
|
|
||||||
file->read = false;
|
file->read = false;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = (flags & O_APPEND);
|
||||||
}
|
} else if ((flags & 0x03) == O_RDWR) {
|
||||||
else if ( ( flags & 0x03 ) == O_RDWR )
|
|
||||||
{
|
|
||||||
file->read = true;
|
file->read = true;
|
||||||
file->write = true;
|
file->write = true;
|
||||||
file->append = ( flags & O_APPEND );
|
file->append = (flags & O_APPEND);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try and find the file and (if found) ensure that it is not a directory
|
// Try and find the file and (if found) ensure that it is not a directory
|
||||||
file->ni = ntfsOpenEntry( file->vd, path );
|
file->ni = ntfsOpenEntry(file->vd, path);
|
||||||
if ( file->ni && ( file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ) )
|
if (file->ni && (file->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||||
{
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EISDIR;
|
r->_errno = EISDIR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we creating this file?
|
// Are we creating this file?
|
||||||
if ( flags & O_CREAT )
|
if ((flags & O_CREAT) && !file->ni) {
|
||||||
{
|
|
||||||
|
|
||||||
// The file SHOULD NOT already exist
|
|
||||||
if ( file->ni )
|
|
||||||
{
|
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EEXIST;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the file
|
// Create the file
|
||||||
file->ni = ntfsCreate( file->vd, path, S_IFREG, NULL );
|
file->ni = ntfsCreate(file->vd, path, S_IFREG, NULL);
|
||||||
if ( !file->ni )
|
if (!file->ni) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check, the file should be open by now
|
// Sanity check, the file should be open by now
|
||||||
if ( !file->ni )
|
if (!file->ni) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = ENOENT;
|
r->_errno = ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the files data attribute
|
// Open the files data attribute
|
||||||
file->data_na = ntfs_attr_open( file->ni, AT_DATA, AT_UNNAMED, 0 );
|
file->data_na = ntfs_attr_open(file->ni, AT_DATA, AT_UNNAMED, 0);
|
||||||
if ( !file->data_na )
|
if(!file->data_na) {
|
||||||
{
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if this files data is compressed and/or encrypted
|
// Determine if this files data is compressed and/or encrypted
|
||||||
file->compressed = NAttrCompressed( file->data_na ) || ( file->ni->flags & FILE_ATTR_COMPRESSED );
|
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->encrypted = NAttrEncrypted(file->data_na) || (file->ni->flags & FILE_ATTR_ENCRYPTED);
|
||||||
|
|
||||||
// We cannot read/write encrypted files
|
// We cannot read/write encrypted files
|
||||||
if ( file->encrypted )
|
if (file->encrypted) {
|
||||||
{
|
ntfs_attr_close(file->data_na);
|
||||||
ntfs_attr_close( file->data_na );
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we aren't trying to write to a read-only file
|
// Make sure we aren't trying to write to a read-only file
|
||||||
if ( ( file->ni->flags & FILE_ATTR_READONLY ) && file->write )
|
if ((file->ni->flags & FILE_ATTR_READONLY) && file->write) {
|
||||||
{
|
ntfs_attr_close(file->data_na);
|
||||||
ntfs_attr_close( file->data_na );
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EROFS;
|
r->_errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate the file if requested
|
// Truncate the file if requested
|
||||||
if ( ( flags & O_TRUNC ) && file->write )
|
if ((flags & O_TRUNC) && file->write) {
|
||||||
{
|
if (ntfs_attr_truncate(file->data_na, 0)) {
|
||||||
if ( ntfs_attr_truncate( file->data_na, 0 ) )
|
ntfs_attr_close(file->data_na);
|
||||||
{
|
ntfsCloseEntry(file->vd, file->ni);
|
||||||
ntfs_attr_close( file->data_na );
|
ntfsUnlock(file->vd);
|
||||||
ntfsCloseEntry( file->vd, file->ni );
|
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -224,19 +198,16 @@ int ntfs_open_r ( struct _reent *r, void *fileStruct, const char *path, int flag
|
|||||||
file->pos = 0;
|
file->pos = 0;
|
||||||
file->len = file->data_na->data_size;
|
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
|
// 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
|
// 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->nextOpenFile = file->vd->firstOpenFile;
|
||||||
file->vd->firstOpenFile->prevOpenFile = file;
|
file->vd->firstOpenFile->prevOpenFile = file;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
file->nextOpenFile = NULL;
|
file->nextOpenFile = NULL;
|
||||||
}
|
}
|
||||||
file->prevOpenFile = 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++;
|
file->vd->openFileCount++;
|
||||||
|
|
||||||
// Unlock
|
// 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
|
// Sanity check
|
||||||
if ( !file || !file->vd )
|
if (!file || !file->vd) {
|
||||||
{
|
|
||||||
r->_errno = EBADF;
|
r->_errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Close the file
|
// Close the file
|
||||||
ntfsCloseFile( file );
|
ntfsCloseFile(file);
|
||||||
|
|
||||||
// Remove the file from the double-linked FILO list of open files
|
// Remove the file from the double-linked FILO list of open files
|
||||||
file->vd->openFileCount--;
|
file->vd->openFileCount--;
|
||||||
if ( file->nextOpenFile )
|
if (file->nextOpenFile)
|
||||||
file->nextOpenFile->prevOpenFile = file->prevOpenFile;
|
file->nextOpenFile->prevOpenFile = file->prevOpenFile;
|
||||||
if ( file->prevOpenFile )
|
if (file->prevOpenFile)
|
||||||
file->prevOpenFile->nextOpenFile = file->nextOpenFile;
|
file->prevOpenFile->nextOpenFile = file->nextOpenFile;
|
||||||
else
|
else
|
||||||
file->vd->firstOpenFile = file->nextOpenFile;
|
file->vd->firstOpenFile = file->nextOpenFile;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return 0;
|
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;
|
ssize_t written = 0;
|
||||||
off_t old_pos = 0;
|
off_t old_pos = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases where we don't actually have to do anything
|
// Short circuit cases where we don't actually have to do anything
|
||||||
if ( !ptr || len <= 0 )
|
if (!ptr || len <= 0) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if ( !file->write )
|
if (!file->write) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are in append mode, backup the current position and move to the end of the file
|
// 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;
|
old_pos = file->pos;
|
||||||
file->pos = file->len;
|
file->pos = file->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to the files data atrribute
|
// Write to the files data atrribute
|
||||||
while ( len )
|
while (len) {
|
||||||
{
|
ssize_t ret = ntfs_attr_pwrite(file->data_na, file->pos, len, ptr);
|
||||||
ssize_t ret = ntfs_attr_pwrite( file->data_na, file->pos, len, ptr );
|
if (ret <= 0) {
|
||||||
if ( ret <= 0 )
|
ntfsUnlock(file->vd);
|
||||||
{
|
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
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 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;
|
file->pos = old_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the file for archiving (if we actually wrote something)
|
// Mark the file for archiving (if we actually wrote something)
|
||||||
if ( written )
|
if (written)
|
||||||
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||||
|
|
||||||
// Update the files data length
|
// Update the files data length
|
||||||
file->len = file->data_na->data_size;
|
file->len = file->data_na->data_size;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return written;
|
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;
|
ssize_t read = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases where we don't actually have to do anything
|
// Short circuit cases where we don't actually have to do anything
|
||||||
if ( !ptr || len <= 0 )
|
if (!ptr || len <= 0) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Check that we are allowed to read from this file
|
// Check that we are allowed to read from this file
|
||||||
if ( !file->read )
|
if (!file->read) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't read past the end of file
|
// Don't read past the end of file
|
||||||
if ( file->pos + len > file->len )
|
if (file->pos + len > file->len) {
|
||||||
{
|
|
||||||
r->_errno = EOVERFLOW;
|
r->_errno = EOVERFLOW;
|
||||||
len = file->len - file->pos;
|
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
|
// Read from the files data attribute
|
||||||
while ( len )
|
while (len) {
|
||||||
{
|
ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
|
||||||
ssize_t ret = ntfs_attr_pread( file->data_na, file->pos, len, ptr );
|
if (ret <= 0 || ret > len) {
|
||||||
if ( ret <= 0 || ret > len )
|
ntfsUnlock(file->vd);
|
||||||
{
|
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
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)
|
// Update file times (if we actually read something)
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return read;
|
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;
|
off_t position = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Set the files current position
|
// Set the files current position
|
||||||
switch ( dir )
|
switch(dir) {
|
||||||
{
|
case SEEK_SET: position = file->pos = MIN(MAX(pos, 0), file->len); break;
|
||||||
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_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;
|
||||||
case SEEK_END: position = file->pos = MIN( MAX( file->len + pos, 0 ), file->len ); break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return position;
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short circuit cases were we don't actually have to do anything
|
// Short circuit cases were we don't actually have to do anything
|
||||||
if ( !st )
|
if (!st)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Get the file stats
|
// Get the file stats
|
||||||
ret = ntfsStat( file->vd, file->ni, st );
|
ret = ntfsStat(file->vd, file->ni, st);
|
||||||
if ( ret )
|
if (ret)
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
|
|
||||||
return ret;
|
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
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Check that we are allowed to write to this file
|
// Check that we are allowed to write to this file
|
||||||
if ( !file->write )
|
if (!file->write) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EACCES;
|
r->_errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For compressed files, only deleting and expanding contents are implemented
|
// For compressed files, only deleting and expanding contents are implemented
|
||||||
if ( file->compressed &&
|
if (file->compressed &&
|
||||||
len > 0 &&
|
len > 0 &&
|
||||||
len < file->data_na->initialized_size )
|
len < file->data_na->initialized_size) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = EOPNOTSUPP;
|
r->_errno = EOPNOTSUPP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize the files data attribute, either by expanding or truncating
|
// 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;
|
char zero = 0;
|
||||||
if ( ntfs_attr_pwrite( file->data_na, len - 1, 1, &zero ) <= 0 )
|
if (ntfs_attr_pwrite(file->data_na, len - 1, 1, &zero) <= 0) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
if (ntfs_attr_truncate(file->data_na, len)) {
|
||||||
{
|
ntfsUnlock(file->vd);
|
||||||
if ( ntfs_attr_truncate( file->data_na, len ) )
|
|
||||||
{
|
|
||||||
ntfsUnlock( file->vd );
|
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the file for archiving (if we actually changed something)
|
// 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;
|
file->ni->flags |= FILE_ATTR_ARCHIVE;
|
||||||
|
|
||||||
// Update file times (if we actually changed something)
|
// Update file times (if we actually changed something)
|
||||||
if ( file->len != file->data_na->data_size )
|
if (file->len != file->data_na->data_size)
|
||||||
ntfsUpdateTimes( file->vd, file->ni, NTFS_UPDATE_AMCTIME );
|
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_AMCTIME);
|
||||||
|
|
||||||
// Update the files data length
|
// Update the files data length
|
||||||
file->len = file->data_na->data_size;
|
file->len = file->data_na->data_size;
|
||||||
|
|
||||||
// Sync the file (and its attributes) to disc
|
// Sync the file (and its attributes) to disc
|
||||||
ntfsSync( file->vd, file->ni );
|
ntfsSync(file->vd, file->ni);
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return 0;
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if ( !file || !file->vd || !file->ni || !file->data_na )
|
if (!file || !file->vd || !file->ni || !file->data_na) {
|
||||||
{
|
|
||||||
r->_errno = EINVAL;
|
r->_errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
ntfsLock( file->vd );
|
ntfsLock(file->vd);
|
||||||
|
|
||||||
// Sync the file (and its attributes) to disc
|
// Sync the file (and its attributes) to disc
|
||||||
ret = ntfsSync( file->vd, file->ni );
|
ret = ntfsSync(file->vd, file->ni);
|
||||||
if ( ret )
|
if (ret)
|
||||||
r->_errno = errno;
|
r->_errno = errno;
|
||||||
|
|
||||||
// Unlock
|
// Unlock
|
||||||
ntfsUnlock( file->vd );
|
ntfsUnlock(file->vd);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,7 @@
|
|||||||
/**
|
/**
|
||||||
* ntfs_file_state - File state
|
* ntfs_file_state - File state
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_file_state
|
typedef struct _ntfs_file_state {
|
||||||
{
|
|
||||||
ntfs_vd *vd; /* Volume this file belongs to */
|
ntfs_vd *vd; /* Volume this file belongs to */
|
||||||
ntfs_inode *ni; /* File descriptor */
|
ntfs_inode *ni; /* File descriptor */
|
||||||
ntfs_attr *data_na; /* File data descriptor */
|
ntfs_attr *data_na; /* File data descriptor */
|
||||||
@ -50,17 +49,17 @@ typedef struct _ntfs_file_state
|
|||||||
} ntfs_file_state;
|
} ntfs_file_state;
|
||||||
|
|
||||||
/* File state routines */
|
/* File state routines */
|
||||||
void ntfsCloseFile ( ntfs_file_state *file );
|
void ntfsCloseFile (ntfs_file_state *file);
|
||||||
|
|
||||||
/* Gekko devoptab file routines for NTFS-based devices */
|
/* 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_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 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_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 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 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_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_ftruncate_r (struct _reent *r, int fd, off_t len);
|
||||||
extern int ntfs_fsync_r ( struct _reent *r, int fd );
|
extern int ntfs_fsync_r (struct _reent *r, int fd);
|
||||||
|
|
||||||
#endif /* _NTFSFILE_H */
|
#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
|
* PRIMARY_PARTITION - Block device partition record
|
||||||
*/
|
*/
|
||||||
typedef struct _PARTITION_RECORD
|
typedef struct _PARTITION_RECORD {
|
||||||
{
|
|
||||||
u8 status; /* Partition status; see above */
|
u8 status; /* Partition status; see above */
|
||||||
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */
|
||||||
u8 type; /* Partition type; see above */
|
u8 type; /* Partition type; see above */
|
||||||
u8 chs_end[3]; /* Cylinder-head-sector address to last block of partition */
|
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 lba_start; /* Local block address to first sector of partition */
|
||||||
u32 block_count; /* Number of blocks in 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
|
* 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 */
|
u8 code_area[446]; /* Code area; normally empty */
|
||||||
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
PARTITION_RECORD partitions[4]; /* 4 primary partitions */
|
||||||
u16 signature; /* MBR signature; 0xAA55 */
|
u16 signature; /* MBR signature; 0xAA55 */
|
||||||
} __attribute__( ( __packed__ ) ) MASTER_BOOT_RECORD;
|
} __attribute__((__packed__)) MASTER_BOOT_RECORD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXTENDED_PARTITION - Block device extended 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 */
|
u8 code_area[446]; /* Code area; normally empty */
|
||||||
PARTITION_RECORD partition; /* Primary partition */
|
PARTITION_RECORD partition; /* Primary partition */
|
||||||
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
|
PARTITION_RECORD next_ebr; /* Next extended boot record in the chain */
|
||||||
u8 reserved[32]; /* Normally empty */
|
u8 reserved[32]; /* Normally empty */
|
||||||
u16 signature; /* EBR signature; 0xAA55 */
|
u16 signature; /* EBR signature; 0xAA55 */
|
||||||
} __attribute__( ( __packed__ ) ) EXTENDED_BOOT_RECORD;
|
} __attribute__((__packed__)) EXTENDED_BOOT_RECORD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERFACE_ID - Disc interface identifier
|
* INTERFACE_ID - Disc interface identifier
|
||||||
*/
|
*/
|
||||||
typedef struct _INTERFACE_ID
|
typedef struct _INTERFACE_ID {
|
||||||
{
|
|
||||||
const char *name; /* Interface name */
|
const char *name; /* Interface name */
|
||||||
const DISC_INTERFACE *interface; /* Disc interface */
|
const DISC_INTERFACE *interface; /* Disc interface */
|
||||||
} INTERFACE_ID;
|
} INTERFACE_ID;
|
||||||
@ -113,8 +109,7 @@ typedef struct _INTERFACE_ID
|
|||||||
/**
|
/**
|
||||||
* ntfs_atime_t - File access time update strategies
|
* ntfs_atime_t - File access time update strategies
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
ATIME_ENABLED, /* Update access times */
|
ATIME_ENABLED, /* Update access times */
|
||||||
ATIME_DISABLED /* Don't update access times */
|
ATIME_DISABLED /* Don't update access times */
|
||||||
} ntfs_atime_t;
|
} ntfs_atime_t;
|
||||||
@ -122,8 +117,7 @@ typedef enum
|
|||||||
/**
|
/**
|
||||||
* ntfs_vd - NTFS volume descriptor
|
* ntfs_vd - NTFS volume descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct _ntfs_vd
|
typedef struct _ntfs_vd {
|
||||||
{
|
|
||||||
struct ntfs_device *dev; /* NTFS device handle */
|
struct ntfs_device *dev; /* NTFS device handle */
|
||||||
ntfs_volume *vol; /* NTFS volume handle */
|
ntfs_volume *vol; /* NTFS volume handle */
|
||||||
mutex_t lock; /* Volume lock mutex */
|
mutex_t lock; /* Volume lock mutex */
|
||||||
@ -145,40 +139,40 @@ typedef struct _ntfs_vd
|
|||||||
} ntfs_vd;
|
} ntfs_vd;
|
||||||
|
|
||||||
/* Lock volume */
|
/* 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 */
|
/* 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 */
|
/* Gekko device related routines */
|
||||||
int ntfsAddDevice ( const char *name, void *deviceData );
|
int ntfsAddDevice (const char *name, void *deviceData);
|
||||||
void ntfsRemoveDevice ( const char *path );
|
void ntfsRemoveDevice (const char *path);
|
||||||
const devoptab_t *ntfsGetDevice ( const char *path, bool useDefaultDevice );
|
const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice);
|
||||||
const devoptab_t *ntfsGetDevOpTab ( void );
|
const devoptab_t *ntfsGetDevOpTab (void);
|
||||||
const INTERFACE_ID* ntfsGetDiscInterfaces ( void );
|
const INTERFACE_ID* ntfsGetDiscInterfaces (void);
|
||||||
|
|
||||||
/* Miscellaneous helper/support routines */
|
/* Miscellaneous helper/support routines */
|
||||||
int ntfsInitVolume ( ntfs_vd *vd );
|
int ntfsInitVolume (ntfs_vd *vd);
|
||||||
void ntfsDeinitVolume ( ntfs_vd *vd );
|
void ntfsDeinitVolume (ntfs_vd *vd);
|
||||||
ntfs_vd *ntfsGetVolume ( const char *path );
|
ntfs_vd *ntfsGetVolume (const char *path);
|
||||||
ntfs_inode *ntfsOpenEntry ( ntfs_vd *vd, const char *path );
|
ntfs_inode *ntfsOpenEntry (ntfs_vd *vd, const char *path);
|
||||||
ntfs_inode *ntfsParseEntry ( ntfs_vd *vd, const char *path, int reparseLevel );
|
ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel);
|
||||||
void ntfsCloseEntry ( ntfs_vd *vd, ntfs_inode *ni );
|
void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni);
|
||||||
ntfs_inode *ntfsCreate ( ntfs_vd *vd, const char *path, mode_t type, const char *target );
|
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 ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path);
|
||||||
int ntfsUnlink ( ntfs_vd *vd, const char *path );
|
int ntfsUnlink (ntfs_vd *vd, const char *path);
|
||||||
int ntfsSync ( ntfs_vd *vd, ntfs_inode *ni );
|
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni);
|
||||||
int ntfsStat ( ntfs_vd *vd, ntfs_inode *ni, struct stat *st );
|
int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st);
|
||||||
void ntfsUpdateTimes ( ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask );
|
void ntfsUpdateTimes (ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask);
|
||||||
|
|
||||||
const char *ntfsRealPath ( const char *path );
|
const char *ntfsRealPath (const char *path);
|
||||||
int ntfsUnicodeToLocal ( const ntfschar *ins, const int ins_len, char **outs, int outs_len );
|
int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int outs_len);
|
||||||
int ntfsLocalToUnicode ( const char *ins, ntfschar **outs );
|
int ntfsLocalToUnicode (const char *ins, ntfschar **outs);
|
||||||
|
|
||||||
#endif /* _NTFSINTERNAL_H */
|
#endif /* _NTFSINTERNAL_H */
|
||||||
|
@ -55,19 +55,19 @@ typedef sle64 ntfs_time;
|
|||||||
*
|
*
|
||||||
* Return: A Unix time (number of seconds since 1970, and nanoseconds)
|
* 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;
|
struct timespec spec;
|
||||||
s64 cputime;
|
s64 cputime;
|
||||||
|
|
||||||
cputime = sle64_to_cpu( ntfstime );
|
cputime = sle64_to_cpu(ntfstime);
|
||||||
spec.tv_sec = ( cputime - ( NTFS_TIME_OFFSET ) ) / 10000000;
|
spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000;
|
||||||
spec.tv_nsec = ( cputime - ( NTFS_TIME_OFFSET )
|
spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET)
|
||||||
- ( s64 )spec.tv_sec*10000000 )*100;
|
- (s64)spec.tv_sec*10000000)*100;
|
||||||
/* force zero nsec for overflowing dates */
|
/* force zero nsec for overflowing dates */
|
||||||
if ( ( spec.tv_nsec < 0 ) || ( spec.tv_nsec > 999999999 ) )
|
if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999))
|
||||||
spec.tv_nsec = 0;
|
spec.tv_nsec = 0;
|
||||||
return ( spec );
|
return (spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,36 +86,36 @@ static __inline__ struct timespec ntfs2timespec( ntfs_time ntfstime )
|
|||||||
*
|
*
|
||||||
* Return: An NTFS time (100ns units since Jan 1601)
|
* 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
|
units = (s64)spec.tv_sec * 10000000
|
||||||
+ NTFS_TIME_OFFSET + spec.tv_nsec / 100;
|
+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
|
||||||
return ( cpu_to_le64( units ) );
|
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)
|
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME)
|
||||||
clock_gettime( CLOCK_REALTIME, &now );
|
clock_gettime(CLOCK_REALTIME, &now);
|
||||||
#elif defined(HAVE_GETTIMEOFDAY)
|
#elif defined(HAVE_GETTIMEOFDAY)
|
||||||
struct timeval microseconds;
|
struct timeval microseconds;
|
||||||
|
|
||||||
gettimeofday( µseconds, ( struct timezone* )NULL );
|
gettimeofday(µseconds, (struct timezone*)NULL);
|
||||||
now.tv_sec = microseconds.tv_sec;
|
now.tv_sec = microseconds.tv_sec;
|
||||||
now.tv_nsec = microseconds.tv_usec * 1000;
|
now.tv_nsec = microseconds.tv_usec*1000;
|
||||||
#else
|
#else
|
||||||
now.tv_sec = time( ( time_t* )NULL );
|
now.tv_sec = time((time_t*)NULL);
|
||||||
now.tv_nsec = 0;
|
now.tv_nsec = 0;
|
||||||
#endif
|
#endif
|
||||||
return ( timespec2ntfs( now ) );
|
return (timespec2ntfs(now));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _NTFS_NTFSTIME_H */
|
#endif /* _NTFS_NTFSTIME_H */
|
||||||
|
@ -106,29 +106,25 @@
|
|||||||
* ---------------------- end from RFC 4122 -----------------------
|
* ---------------------- end from RFC 4122 -----------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
GUID object_id;
|
GUID object_id;
|
||||||
} OBJECT_ID_INDEX_KEY;
|
} OBJECT_ID_INDEX_KEY;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
le64 file_id;
|
le64 file_id;
|
||||||
GUID birth_volume_id;
|
GUID birth_volume_id;
|
||||||
GUID birth_object_id;
|
GUID birth_object_id;
|
||||||
GUID domain_id;
|
GUID domain_id;
|
||||||
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
|
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
|
||||||
|
|
||||||
struct OBJECT_ID_INDEX /* index entry in $Extend/$ObjId */
|
struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */
|
||||||
{
|
|
||||||
INDEX_ENTRY_HEADER header;
|
INDEX_ENTRY_HEADER header;
|
||||||
OBJECT_ID_INDEX_KEY key;
|
OBJECT_ID_INDEX_KEY key;
|
||||||
OBJECT_ID_INDEX_DATA data;
|
OBJECT_ID_INDEX_DATA data;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
|
static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
|
||||||
const_cpu_to_le16( 'O' )
|
const_cpu_to_le16('O') };
|
||||||
};
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -138,8 +134,8 @@ static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
|
|||||||
* -1 if failure, explained by errno
|
* -1 if failure, explained by errno
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int set_object_id_index( ntfs_inode *ni, ntfs_index_context *xo,
|
static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
|
||||||
const OBJECT_ID_ATTR *object_id )
|
const OBJECT_ID_ATTR *object_id)
|
||||||
{
|
{
|
||||||
struct OBJECT_ID_INDEX indx;
|
struct OBJECT_ID_INDEX indx;
|
||||||
u64 file_id_cpu;
|
u64 file_id_cpu;
|
||||||
@ -147,32 +143,32 @@ static int set_object_id_index( ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
le16 seqn;
|
le16 seqn;
|
||||||
|
|
||||||
seqn = ni->mrec->sequence_number;
|
seqn = ni->mrec->sequence_number;
|
||||||
file_id_cpu = MK_MREF( ni->mft_no, le16_to_cpu( seqn ) );
|
file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn));
|
||||||
file_id = cpu_to_le64( file_id_cpu );
|
file_id = cpu_to_le64(file_id_cpu);
|
||||||
indx.header.data_offset = const_cpu_to_le16(
|
indx.header.data_offset = const_cpu_to_le16(
|
||||||
sizeof( INDEX_ENTRY_HEADER )
|
sizeof(INDEX_ENTRY_HEADER)
|
||||||
+ sizeof( OBJECT_ID_INDEX_KEY ) );
|
+ sizeof(OBJECT_ID_INDEX_KEY));
|
||||||
indx.header.data_length = const_cpu_to_le16(
|
indx.header.data_length = const_cpu_to_le16(
|
||||||
sizeof( OBJECT_ID_INDEX_DATA ) );
|
sizeof(OBJECT_ID_INDEX_DATA));
|
||||||
indx.header.reservedV = const_cpu_to_le32( 0 );
|
indx.header.reservedV = const_cpu_to_le32(0);
|
||||||
indx.header.length = const_cpu_to_le16(
|
indx.header.length = const_cpu_to_le16(
|
||||||
sizeof( struct OBJECT_ID_INDEX ) );
|
sizeof(struct OBJECT_ID_INDEX));
|
||||||
indx.header.key_length = const_cpu_to_le16(
|
indx.header.key_length = const_cpu_to_le16(
|
||||||
sizeof( OBJECT_ID_INDEX_KEY ) );
|
sizeof(OBJECT_ID_INDEX_KEY));
|
||||||
indx.header.flags = const_cpu_to_le16( 0 );
|
indx.header.flags = const_cpu_to_le16(0);
|
||||||
indx.header.reserved = const_cpu_to_le16( 0 );
|
indx.header.reserved = const_cpu_to_le16(0);
|
||||||
|
|
||||||
memcpy( &indx.key.object_id, object_id, sizeof( GUID ) );
|
memcpy(&indx.key.object_id,object_id,sizeof(GUID));
|
||||||
|
|
||||||
indx.data.file_id = file_id;
|
indx.data.file_id = file_id;
|
||||||
memcpy( &indx.data.birth_volume_id,
|
memcpy(&indx.data.birth_volume_id,
|
||||||
&object_id->birth_volume_id, sizeof( GUID ) );
|
&object_id->birth_volume_id,sizeof(GUID));
|
||||||
memcpy( &indx.data.birth_object_id,
|
memcpy(&indx.data.birth_object_id,
|
||||||
&object_id->birth_object_id, sizeof( GUID ) );
|
&object_id->birth_object_id,sizeof(GUID));
|
||||||
memcpy( &indx.data.domain_id,
|
memcpy(&indx.data.domain_id,
|
||||||
&object_id->domain_id, sizeof( GUID ) );
|
&object_id->domain_id,sizeof(GUID));
|
||||||
ntfs_index_ctx_reinit( xo );
|
ntfs_index_ctx_reinit(xo);
|
||||||
return ( ntfs_ie_add( xo, ( INDEX_ENTRY* )&indx ) );
|
return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
@ -186,7 +182,7 @@ static int set_object_id_index( ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
* The index has to be freed and inode closed when not needed any more.
|
* The index has to be freed and inode closed when not needed any more.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ntfs_index_context *open_object_id_index( ntfs_volume *vol )
|
static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
|
||||||
{
|
{
|
||||||
u64 inum;
|
u64 inum;
|
||||||
ntfs_inode *ni;
|
ntfs_inode *ni;
|
||||||
@ -194,26 +190,22 @@ static ntfs_index_context *open_object_id_index( ntfs_volume *vol )
|
|||||||
ntfs_index_context *xo;
|
ntfs_index_context *xo;
|
||||||
|
|
||||||
/* do not use path_name_to inode - could reopen root */
|
/* do not use path_name_to inode - could reopen root */
|
||||||
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
dir_ni = ntfs_inode_open(vol, FILE_Extend);
|
||||||
ni = ( ntfs_inode* )NULL;
|
ni = (ntfs_inode*)NULL;
|
||||||
if ( dir_ni )
|
if (dir_ni) {
|
||||||
{
|
inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId");
|
||||||
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
|
if (inum != (u64)-1)
|
||||||
if ( inum != ( u64 ) - 1 )
|
ni = ntfs_inode_open(vol, inum);
|
||||||
ni = ntfs_inode_open( vol, inum );
|
ntfs_inode_close(dir_ni);
|
||||||
ntfs_inode_close( dir_ni );
|
|
||||||
}
|
}
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
xo = ntfs_index_ctx_get(ni, objid_index_name, 2);
|
||||||
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
|
if (!xo) {
|
||||||
if ( !xo )
|
ntfs_inode_close(ni);
|
||||||
{
|
|
||||||
ntfs_inode_close( ni );
|
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
xo = (ntfs_index_context*)NULL;
|
||||||
xo = ( ntfs_index_context* )NULL;
|
return (xo);
|
||||||
return ( xo );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
@ -226,9 +218,9 @@ static ntfs_index_context *open_object_id_index( ntfs_volume *vol )
|
|||||||
* -1 if no data could be merged. This is generally not an error
|
* -1 if no data could be merged. This is generally not an error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int merge_index_data( ntfs_inode *ni,
|
static int merge_index_data(ntfs_inode *ni,
|
||||||
const OBJECT_ID_ATTR *objectid_attr,
|
const OBJECT_ID_ATTR *objectid_attr,
|
||||||
OBJECT_ID_ATTR *full_objectid )
|
OBJECT_ID_ATTR *full_objectid)
|
||||||
{
|
{
|
||||||
OBJECT_ID_INDEX_KEY key;
|
OBJECT_ID_INDEX_KEY key;
|
||||||
struct OBJECT_ID_INDEX *entry;
|
struct OBJECT_ID_INDEX *entry;
|
||||||
@ -237,36 +229,33 @@ static int merge_index_data( ntfs_inode *ni,
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = -1;
|
res = -1;
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index(ni->vol);
|
||||||
if ( xo )
|
if (xo) {
|
||||||
{
|
memcpy(&key.object_id,objectid_attr,sizeof(GUID));
|
||||||
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
|
if (!ntfs_index_lookup(&key,
|
||||||
if ( !ntfs_index_lookup( &key,
|
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
entry = (struct OBJECT_ID_INDEX*)xo->entry;
|
||||||
{
|
|
||||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
|
||||||
/* make sure inode numbers match */
|
/* make sure inode numbers match */
|
||||||
if ( entry
|
if (entry
|
||||||
&& ( MREF( le64_to_cpu( entry->data.file_id ) )
|
&& (MREF(le64_to_cpu(entry->data.file_id))
|
||||||
== ni->mft_no ) )
|
== ni->mft_no)) {
|
||||||
{
|
memcpy(&full_objectid->birth_volume_id,
|
||||||
memcpy( &full_objectid->birth_volume_id,
|
|
||||||
&entry->data.birth_volume_id,
|
&entry->data.birth_volume_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
memcpy( &full_objectid->birth_object_id,
|
memcpy(&full_objectid->birth_object_id,
|
||||||
&entry->data.birth_object_id,
|
&entry->data.birth_object_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
memcpy( &full_objectid->domain_id,
|
memcpy(&full_objectid->domain_id,
|
||||||
&entry->data.domain_id,
|
&entry->data.domain_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xoni = xo->ni;
|
xoni = xo->ni;
|
||||||
ntfs_index_ctx_put( xo );
|
ntfs_index_ctx_put(xo);
|
||||||
ntfs_inode_close( xoni );
|
ntfs_inode_close(xoni);
|
||||||
}
|
}
|
||||||
return ( res );
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
@ -279,8 +268,8 @@ static int merge_index_data( ntfs_inode *ni,
|
|||||||
* -1 if failure, explained by errno
|
* -1 if failure, explained by errno
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int remove_object_id_index( ntfs_attr *na, ntfs_index_context *xo,
|
static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
||||||
OBJECT_ID_ATTR *old_attr )
|
OBJECT_ID_ATTR *old_attr)
|
||||||
{
|
{
|
||||||
OBJECT_ID_INDEX_KEY key;
|
OBJECT_ID_INDEX_KEY key;
|
||||||
struct OBJECT_ID_INDEX *entry;
|
struct OBJECT_ID_INDEX *entry;
|
||||||
@ -288,40 +277,35 @@ static int remove_object_id_index( ntfs_attr *na, ntfs_index_context *xo,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = na->data_size;
|
ret = na->data_size;
|
||||||
if ( ret )
|
if (ret) {
|
||||||
{
|
|
||||||
/* read the existing object id attribute */
|
/* read the existing object id attribute */
|
||||||
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
|
size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr);
|
||||||
if ( size >= ( s64 )sizeof( GUID ) )
|
if (size >= (s64)sizeof(GUID)) {
|
||||||
{
|
memcpy(&key.object_id,
|
||||||
memcpy( &key.object_id,
|
&old_attr->object_id,sizeof(GUID));
|
||||||
&old_attr->object_id, sizeof( GUID ) );
|
size = sizeof(GUID);
|
||||||
size = sizeof( GUID );
|
if (!ntfs_index_lookup(&key,
|
||||||
if ( !ntfs_index_lookup( &key,
|
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
entry = (struct OBJECT_ID_INDEX*)xo->entry;
|
||||||
{
|
memcpy(&old_attr->birth_volume_id,
|
||||||
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
|
||||||
memcpy( &old_attr->birth_volume_id,
|
|
||||||
&entry->data.birth_volume_id,
|
&entry->data.birth_volume_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
memcpy( &old_attr->birth_object_id,
|
memcpy(&old_attr->birth_object_id,
|
||||||
&entry->data.birth_object_id,
|
&entry->data.birth_object_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
memcpy( &old_attr->domain_id,
|
memcpy(&old_attr->domain_id,
|
||||||
&entry->data.domain_id,
|
&entry->data.domain_id,
|
||||||
sizeof( GUID ) );
|
sizeof(GUID));
|
||||||
size = sizeof( OBJECT_ID_ATTR );
|
size = sizeof(OBJECT_ID_ATTR);
|
||||||
if ( ntfs_index_rm( xo ) )
|
if (ntfs_index_rm(xo))
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = -1;
|
ret = -1;
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ( ret );
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
@ -339,8 +323,8 @@ static int remove_object_id_index( ntfs_attr *na, ntfs_index_context *xo,
|
|||||||
* If failed to insert the index, data is removed
|
* If failed to insert the index, data is removed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int update_object_id( ntfs_inode *ni, ntfs_index_context *xo,
|
static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
|
||||||
const OBJECT_ID_ATTR *value, size_t size )
|
const OBJECT_ID_ATTR *value, size_t size)
|
||||||
{
|
{
|
||||||
OBJECT_ID_ATTR old_attr;
|
OBJECT_ID_ATTR old_attr;
|
||||||
ntfs_attr *na;
|
ntfs_attr *na;
|
||||||
@ -350,53 +334,47 @@ static int update_object_id( ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
|
||||||
if ( na )
|
if (na) {
|
||||||
{
|
|
||||||
|
|
||||||
/* remove the existing index entry */
|
/* remove the existing index entry */
|
||||||
oldsize = remove_object_id_index( na, xo, &old_attr );
|
oldsize = remove_object_id_index(na,xo,&old_attr);
|
||||||
if ( oldsize < 0 )
|
if (oldsize < 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
/* resize attribute */
|
/* resize attribute */
|
||||||
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
|
res = ntfs_attr_truncate(na, (s64)sizeof(GUID));
|
||||||
/* write the object_id in attribute */
|
/* write the object_id in attribute */
|
||||||
if ( !res && value )
|
if (!res && value) {
|
||||||
{
|
written = (int)ntfs_attr_pwrite(na,
|
||||||
written = ( int )ntfs_attr_pwrite( na,
|
(s64)0, (s64)sizeof(GUID),
|
||||||
( s64 )0, ( s64 )sizeof( GUID ),
|
&value->object_id);
|
||||||
&value->object_id );
|
if (written != (s64)sizeof(GUID)) {
|
||||||
if ( written != ( s64 )sizeof( GUID ) )
|
ntfs_log_error("Failed to update "
|
||||||
{
|
"object id\n");
|
||||||
ntfs_log_error( "Failed to update "
|
|
||||||
"object id\n" );
|
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* write index part if provided */
|
/* write index part if provided */
|
||||||
if ( !res
|
if (!res
|
||||||
&& ( ( size < sizeof( OBJECT_ID_ATTR ) )
|
&& ((size < sizeof(OBJECT_ID_ATTR))
|
||||||
|| set_object_id_index( ni, xo, value ) ) )
|
|| set_object_id_index(ni,xo,value))) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* If cannot index, try to remove the object
|
* If cannot index, try to remove the object
|
||||||
* id and log the error. There will be an
|
* id and log the error. There will be an
|
||||||
* inconsistency if removal fails.
|
* inconsistency if removal fails.
|
||||||
*/
|
*/
|
||||||
ntfs_attr_rm( na );
|
ntfs_attr_rm(na);
|
||||||
ntfs_log_error( "Failed to index object id."
|
ntfs_log_error("Failed to index object id."
|
||||||
" Possible corruption.\n" );
|
" Possible corruption.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty(ni);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
res = -1;
|
res = -1;
|
||||||
return ( res );
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -406,41 +384,34 @@ static int update_object_id( ntfs_inode *ni, ntfs_index_context *xo,
|
|||||||
* -1 if adding failed (explained by errno)
|
* -1 if adding failed (explained by errno)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int add_object_id( ntfs_inode *ni, int flags )
|
static int add_object_id(ntfs_inode *ni, int flags)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
u8 dummy;
|
u8 dummy;
|
||||||
|
|
||||||
res = -1; /* default return */
|
res = -1; /* default return */
|
||||||
if ( !ntfs_attr_exist( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ) )
|
if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
|
||||||
{
|
if (!(flags & XATTR_REPLACE)) {
|
||||||
if ( !( flags & XATTR_REPLACE ) )
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* no object id attribute : add one,
|
* no object id attribute : add one,
|
||||||
* apparently, this does not feed the new value in
|
* apparently, this does not feed the new value in
|
||||||
* Note : NTFS version must be >= 3
|
* Note : NTFS version must be >= 3
|
||||||
*/
|
*/
|
||||||
if ( ni->vol->major_ver >= 3 )
|
if (ni->vol->major_ver >= 3) {
|
||||||
{
|
res = ntfs_attr_add(ni, AT_OBJECT_ID,
|
||||||
res = ntfs_attr_add( ni, AT_OBJECT_ID,
|
AT_UNNAMED, 0, &dummy, (s64)0);
|
||||||
AT_UNNAMED, 0, &dummy, ( s64 )0 );
|
NInoSetDirty(ni);
|
||||||
NInoSetDirty( ni );
|
} else
|
||||||
}
|
|
||||||
else
|
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
} else {
|
||||||
else
|
if (flags & XATTR_CREATE)
|
||||||
{
|
|
||||||
if ( flags & XATTR_CREATE )
|
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
else
|
else
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
return ( res );
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
@ -452,7 +423,7 @@ static int add_object_id( ntfs_inode *ni, int flags )
|
|||||||
* -1 if failure, explained by errno
|
* -1 if failure, explained by errno
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_delete_object_id_index( ntfs_inode *ni )
|
int ntfs_delete_object_id_index(ntfs_inode *ni)
|
||||||
{
|
{
|
||||||
ntfs_index_context *xo;
|
ntfs_index_context *xo;
|
||||||
ntfs_inode *xoni;
|
ntfs_inode *xoni;
|
||||||
@ -461,27 +432,25 @@ int ntfs_delete_object_id_index( ntfs_inode *ni )
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
|
||||||
if ( na )
|
if (na) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* read the existing object id
|
* read the existing object id
|
||||||
* and un-index it
|
* and un-index it
|
||||||
*/
|
*/
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index(ni->vol);
|
||||||
if ( xo )
|
if (xo) {
|
||||||
{
|
if (remove_object_id_index(na,xo,&old_attr) < 0)
|
||||||
if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
|
|
||||||
res = -1;
|
res = -1;
|
||||||
xoni = xo->ni;
|
xoni = xo->ni;
|
||||||
ntfs_index_entry_mark_dirty( xo );
|
ntfs_index_entry_mark_dirty(xo);
|
||||||
NInoSetDirty( xoni );
|
NInoSetDirty(xoni);
|
||||||
ntfs_index_ctx_put( xo );
|
ntfs_index_ctx_put(xo);
|
||||||
ntfs_inode_close( xoni );
|
ntfs_inode_close(xoni);
|
||||||
}
|
}
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
}
|
}
|
||||||
return ( res );
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
@ -496,7 +465,7 @@ int ntfs_delete_object_id_index( ntfs_inode *ni )
|
|||||||
* and the buffer is updated if it is long enough
|
* and the buffer is updated if it is long enough
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
OBJECT_ID_ATTR full_objectid;
|
OBJECT_ID_ATTR full_objectid;
|
||||||
OBJECT_ID_ATTR *objectid_attr;
|
OBJECT_ID_ATTR *objectid_attr;
|
||||||
@ -504,45 +473,37 @@ int ntfs_get_ntfs_object_id( ntfs_inode *ni, char *value, size_t size )
|
|||||||
int full_size;
|
int full_size;
|
||||||
|
|
||||||
full_size = 0; /* default to no data and some error to be defined */
|
full_size = 0; /* default to no data and some error to be defined */
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni,
|
||||||
objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni,
|
AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size);
|
||||||
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
|
if (objectid_attr) {
|
||||||
if ( objectid_attr )
|
|
||||||
{
|
|
||||||
/* restrict to only GUID present in attr */
|
/* restrict to only GUID present in attr */
|
||||||
if ( attr_size == sizeof( GUID ) )
|
if (attr_size == sizeof(GUID)) {
|
||||||
{
|
memcpy(&full_objectid.object_id,
|
||||||
memcpy( &full_objectid.object_id,
|
objectid_attr,sizeof(GUID));
|
||||||
objectid_attr, sizeof( GUID ) );
|
full_size = sizeof(GUID);
|
||||||
full_size = sizeof( GUID );
|
|
||||||
/* get data from index, if any */
|
/* get data from index, if any */
|
||||||
if ( !merge_index_data( ni, objectid_attr,
|
if (!merge_index_data(ni, objectid_attr,
|
||||||
&full_objectid ) )
|
&full_objectid)) {
|
||||||
{
|
full_size = sizeof(OBJECT_ID_ATTR);
|
||||||
full_size = sizeof( OBJECT_ID_ATTR );
|
|
||||||
}
|
}
|
||||||
if ( full_size <= ( s64 )size )
|
if (full_size <= (s64)size) {
|
||||||
{
|
if (value)
|
||||||
if ( value )
|
memcpy(value,&full_objectid,
|
||||||
memcpy( value, &full_objectid,
|
full_size);
|
||||||
full_size );
|
|
||||||
else
|
else
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* unexpected size, better return unsupported */
|
/* unexpected size, better return unsupported */
|
||||||
errno = EOPNOTSUPP;
|
errno = EOPNOTSUPP;
|
||||||
full_size = 0;
|
full_size = 0;
|
||||||
}
|
}
|
||||||
free( objectid_attr );
|
free(objectid_attr);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
}
|
}
|
||||||
return ( full_size ? ( int )full_size : -errno );
|
return (full_size ? (int)full_size : -errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -555,8 +516,8 @@ int ntfs_get_ntfs_object_id( ntfs_inode *ni, char *value, size_t size )
|
|||||||
* Returns 0, or -1 if there is a problem
|
* Returns 0, or -1 if there is a problem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_set_ntfs_object_id( ntfs_inode *ni,
|
int ntfs_set_ntfs_object_id(ntfs_inode *ni,
|
||||||
const char *value, size_t size, int flags )
|
const char *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
OBJECT_ID_INDEX_KEY key;
|
OBJECT_ID_INDEX_KEY key;
|
||||||
ntfs_inode *xoni;
|
ntfs_inode *xoni;
|
||||||
@ -564,49 +525,39 @@ int ntfs_set_ntfs_object_id( ntfs_inode *ni,
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if ( ni && value && ( size >= sizeof( GUID ) ) )
|
if (ni && value && (size >= sizeof(GUID))) {
|
||||||
{
|
xo = open_object_id_index(ni->vol);
|
||||||
xo = open_object_id_index( ni->vol );
|
if (xo) {
|
||||||
if ( xo )
|
|
||||||
{
|
|
||||||
/* make sure the GUID was not used somewhere */
|
/* make sure the GUID was not used somewhere */
|
||||||
memcpy( &key.object_id, value, sizeof( GUID ) );
|
memcpy(&key.object_id, value, sizeof(GUID));
|
||||||
if ( ntfs_index_lookup( &key,
|
if (ntfs_index_lookup(&key,
|
||||||
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
|
||||||
{
|
ntfs_index_ctx_reinit(xo);
|
||||||
ntfs_index_ctx_reinit( xo );
|
res = add_object_id(ni, flags);
|
||||||
res = add_object_id( ni, flags );
|
if (!res) {
|
||||||
if ( !res )
|
|
||||||
{
|
|
||||||
/* update value and index */
|
/* update value and index */
|
||||||
res = update_object_id( ni, xo,
|
res = update_object_id(ni,xo,
|
||||||
( const OBJECT_ID_ATTR* )value,
|
(const OBJECT_ID_ATTR*)value,
|
||||||
size );
|
size);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* GUID is present elsewhere */
|
/* GUID is present elsewhere */
|
||||||
res = -1;
|
res = -1;
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
}
|
}
|
||||||
xoni = xo->ni;
|
xoni = xo->ni;
|
||||||
ntfs_index_entry_mark_dirty( xo );
|
ntfs_index_entry_mark_dirty(xo);
|
||||||
NInoSetDirty( xoni );
|
NInoSetDirty(xoni);
|
||||||
ntfs_index_ctx_put( xo );
|
ntfs_index_ctx_put(xo);
|
||||||
ntfs_inode_close( xoni );
|
ntfs_inode_close(xoni);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
return ( res ? -1 : 0 );
|
return (res ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -615,7 +566,7 @@ int ntfs_set_ntfs_object_id( ntfs_inode *ni,
|
|||||||
* Returns 0, or -1 if there is a problem
|
* Returns 0, or -1 if there is a problem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ntfs_remove_ntfs_object_id( ntfs_inode *ni )
|
int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int olderrno;
|
int olderrno;
|
||||||
@ -626,32 +577,25 @@ int ntfs_remove_ntfs_object_id( ntfs_inode *ni )
|
|||||||
OBJECT_ID_ATTR old_attr;
|
OBJECT_ID_ATTR old_attr;
|
||||||
|
|
||||||
res = 0;
|
res = 0;
|
||||||
if ( ni )
|
if (ni) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* open and delete the object id
|
* open and delete the object id
|
||||||
*/
|
*/
|
||||||
na = ntfs_attr_open( ni, AT_OBJECT_ID,
|
na = ntfs_attr_open(ni, AT_OBJECT_ID,
|
||||||
AT_UNNAMED, 0 );
|
AT_UNNAMED,0);
|
||||||
if ( na )
|
if (na) {
|
||||||
{
|
|
||||||
/* first remove index (old object id needed) */
|
/* first remove index (old object id needed) */
|
||||||
xo = open_object_id_index( ni->vol );
|
xo = open_object_id_index(ni->vol);
|
||||||
if ( xo )
|
if (xo) {
|
||||||
{
|
oldsize = remove_object_id_index(na,xo,
|
||||||
oldsize = remove_object_id_index( na, xo,
|
&old_attr);
|
||||||
&old_attr );
|
if (oldsize < 0) {
|
||||||
if ( oldsize < 0 )
|
|
||||||
{
|
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
/* now remove attribute */
|
/* now remove attribute */
|
||||||
res = ntfs_attr_rm( na );
|
res = ntfs_attr_rm(na);
|
||||||
if ( res
|
if (res
|
||||||
&& ( oldsize > ( int )sizeof( GUID ) ) )
|
&& (oldsize > (int)sizeof(GUID))) {
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* If we could not remove the
|
* If we could not remove the
|
||||||
* attribute, try to restore the
|
* attribute, try to restore the
|
||||||
@ -659,39 +603,35 @@ int ntfs_remove_ntfs_object_id( ntfs_inode *ni )
|
|||||||
* will be an inconsistency if
|
* will be an inconsistency if
|
||||||
* the reindexing fails.
|
* the reindexing fails.
|
||||||
*/
|
*/
|
||||||
set_object_id_index( ni, xo,
|
set_object_id_index(ni, xo,
|
||||||
&old_attr );
|
&old_attr);
|
||||||
ntfs_log_error(
|
ntfs_log_error(
|
||||||
"Failed to remove object id."
|
"Failed to remove object id."
|
||||||
" Possible corruption.\n" );
|
" Possible corruption.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xoni = xo->ni;
|
xoni = xo->ni;
|
||||||
ntfs_index_entry_mark_dirty( xo );
|
ntfs_index_entry_mark_dirty(xo);
|
||||||
NInoSetDirty( xoni );
|
NInoSetDirty(xoni);
|
||||||
ntfs_index_ctx_put( xo );
|
ntfs_index_ctx_put(xo);
|
||||||
ntfs_inode_close( xoni );
|
ntfs_inode_close(xoni);
|
||||||
}
|
}
|
||||||
olderrno = errno;
|
olderrno = errno;
|
||||||
ntfs_attr_close( na );
|
ntfs_attr_close(na);
|
||||||
/* avoid errno pollution */
|
/* avoid errno pollution */
|
||||||
if ( errno == ENOENT )
|
if (errno == ENOENT)
|
||||||
errno = olderrno;
|
errno = olderrno;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = ENODATA;
|
errno = ENODATA;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
NInoSetDirty( ni );
|
NInoSetDirty(ni);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
return ( res ? -1 : 0 );
|
return (res ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
|
@ -24,12 +24,12 @@
|
|||||||
#ifndef OBJECT_ID_H
|
#ifndef OBJECT_ID_H
|
||||||
#define 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,
|
int ntfs_set_ntfs_object_id(ntfs_inode *ni, const char *value,
|
||||||
size_t size, int flags );
|
size_t size, int flags);
|
||||||
int ntfs_remove_ntfs_object_id( ntfs_inode *ni );
|
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 */
|
#endif /* OBJECT_ID_H */
|
||||||
|
@ -31,9 +31,8 @@
|
|||||||
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
|
#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 OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
|
||||||
|
|
||||||
/* default security sub-authorities */
|
/* default security sub-authorities */
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||||
DEFSECAUTH2 = 589793238,
|
DEFSECAUTH2 = 589793238,
|
||||||
DEFSECAUTH3 = 462843383,
|
DEFSECAUTH3 = 462843383,
|
||||||
@ -44,11 +43,11 @@ enum
|
|||||||
* Parameters for compression
|
* Parameters for compression
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* default option for compression */
|
/* default option for compression */
|
||||||
#define DEFAULT_COMPRESSION FALSE
|
#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
|
#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
|
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,16 +24,16 @@
|
|||||||
#ifndef REPARSE_H
|
#ifndef REPARSE_H
|
||||||
#define REPARSE_H
|
#define REPARSE_H
|
||||||
|
|
||||||
char *ntfs_make_symlink( ntfs_inode *ni, const char *mnt_point,
|
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||||
int *pattr_size );
|
int *pattr_size);
|
||||||
BOOL ntfs_possible_symlink( ntfs_inode *ni );
|
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,
|
int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value,
|
||||||
size_t size, int flags );
|
size_t size, int flags);
|
||||||
int ntfs_remove_ntfs_reparse_data( ntfs_inode *ni );
|
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 */
|
#endif /* REPARSE_H */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -43,48 +43,47 @@ typedef runlist_element runlist;
|
|||||||
* When lcn == -1 this means that the count vcns starting at vcn are not
|
* 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).
|
* physically allocated (i.e. this is a hole / data is sparse).
|
||||||
*/
|
*/
|
||||||
struct _runlist_element /* In memory vcn to lcn mapping structure element. */
|
struct _runlist_element {/* In memory vcn to lcn mapping structure element. */
|
||||||
{
|
|
||||||
VCN vcn; /* vcn = Starting virtual cluster number. */
|
VCN vcn; /* vcn = Starting virtual cluster number. */
|
||||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||||
s64 length; /* Run length in clusters. */
|
s64 length; /* Run length in clusters. */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern runlist_element *ntfs_rl_extend( ntfs_attr *na, runlist_element *rl,
|
extern runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
|
||||||
int more_entries );
|
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,
|
extern s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
|
||||||
const s64 pos, s64 count, void *b );
|
const s64 pos, s64 count, void *b);
|
||||||
extern s64 ntfs_rl_pwrite( const ntfs_volume *vol, const runlist_element *rl,
|
extern s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
|
||||||
s64 ofs, const s64 pos, s64 count, void *b );
|
s64 ofs, const s64 pos, s64 count, void *b);
|
||||||
|
|
||||||
extern runlist_element *ntfs_runlists_merge( runlist_element *drl,
|
extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
|
||||||
runlist_element *srl );
|
runlist_element *srl);
|
||||||
|
|
||||||
extern runlist_element *ntfs_mapping_pairs_decompress( const ntfs_volume *vol,
|
extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
|
||||||
const ATTR_RECORD *attr, runlist_element *old_rl );
|
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,
|
extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||||
const runlist_element *rl, const VCN start_vcn, int max_size );
|
const runlist_element *rl, const VCN start_vcn, int max_size);
|
||||||
|
|
||||||
extern int ntfs_write_significant_bytes( u8 *dst, const u8 *dst_max,
|
extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max,
|
||||||
const s64 n );
|
const s64 n);
|
||||||
|
|
||||||
extern int ntfs_mapping_pairs_build( const ntfs_volume *vol, u8 *dst,
|
extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||||
const int dst_len, const runlist_element *rl,
|
const int dst_len, const runlist_element *rl,
|
||||||
const VCN start_vcn, runlist_element const **stop_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 int ntfs_rl_sparse(runlist *rl);
|
||||||
extern s64 ntfs_rl_get_compressed_size( ntfs_volume *vol, runlist *rl );
|
extern s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl);
|
||||||
|
|
||||||
#ifdef NTFS_TEST
|
#ifdef NTFS_TEST
|
||||||
int test_rl_main( int argc, char *argv[] );
|
int test_rl_main(int argc, char *argv[]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* defined _NTFS_RUNLIST_H */
|
#endif /* defined _NTFS_RUNLIST_H */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -50,8 +50,7 @@ typedef u32 be32;
|
|||||||
* item in the mapping list
|
* item in the mapping list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct MAPPING
|
struct MAPPING {
|
||||||
{
|
|
||||||
struct MAPPING *next;
|
struct MAPPING *next;
|
||||||
int xid; /* linux id : uid or gid */
|
int xid; /* linux id : uid or gid */
|
||||||
SID *sid; /* Windows id : usid or gsid */
|
SID *sid; /* Windows id : usid or gsid */
|
||||||
@ -64,26 +63,24 @@ struct MAPPING
|
|||||||
* Note : this cache is not organized as a generic cache
|
* Note : this cache is not organized as a generic cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_PERMISSIONS
|
struct CACHED_PERMISSIONS {
|
||||||
{
|
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
le32 inh_fileid;
|
le32 inh_fileid;
|
||||||
le32 inh_dirid;
|
le32 inh_dirid;
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
struct POSIX_SECURITY *pxdesc;
|
struct POSIX_SECURITY *pxdesc;
|
||||||
unsigned int pxdescsize: 16;
|
unsigned int pxdescsize:16;
|
||||||
#endif
|
#endif
|
||||||
unsigned int mode: 12;
|
unsigned int mode:12;
|
||||||
unsigned int valid: 1;
|
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 {
|
||||||
{
|
|
||||||
struct CACHED_PERMISSIONS_LEGACY *next;
|
struct CACHED_PERMISSIONS_LEGACY *next;
|
||||||
struct CACHED_PERMISSIONS_LEGACY *previous;
|
struct CACHED_PERMISSIONS_LEGACY *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
@ -97,8 +94,7 @@ struct CACHED_PERMISSIONS_LEGACY
|
|||||||
* Entry in the securid cache
|
* Entry in the securid cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_SECURID
|
struct CACHED_SECURID {
|
||||||
{
|
|
||||||
struct CACHED_SECURID *next;
|
struct CACHED_SECURID *next;
|
||||||
struct CACHED_SECURID *previous;
|
struct CACHED_SECURID *previous;
|
||||||
void *variable;
|
void *variable;
|
||||||
@ -115,8 +111,7 @@ struct CACHED_SECURID
|
|||||||
* (has no cache structure by itself)
|
* (has no cache structure by itself)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct CACHED_PERMISSIONS_HEADER
|
struct CACHED_PERMISSIONS_HEADER {
|
||||||
{
|
|
||||||
unsigned int last;
|
unsigned int last;
|
||||||
/* statistics for permissions */
|
/* statistics for permissions */
|
||||||
unsigned long p_writes;
|
unsigned long p_writes;
|
||||||
@ -128,8 +123,7 @@ struct CACHED_PERMISSIONS_HEADER
|
|||||||
* The whole permissions cache
|
* The whole permissions cache
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct PERMISSIONS_CACHE
|
struct PERMISSIONS_CACHE {
|
||||||
{
|
|
||||||
struct CACHED_PERMISSIONS_HEADER head;
|
struct CACHED_PERMISSIONS_HEADER head;
|
||||||
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
|
||||||
} ;
|
} ;
|
||||||
@ -138,8 +132,7 @@ struct PERMISSIONS_CACHE
|
|||||||
* Security flags values
|
* Security flags values
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||||
@ -153,8 +146,7 @@ enum
|
|||||||
|
|
||||||
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
||||||
|
|
||||||
struct SECURITY_CONTEXT
|
struct SECURITY_CONTEXT {
|
||||||
{
|
|
||||||
ntfs_volume *vol;
|
ntfs_volume *vol;
|
||||||
struct MAPPING *mapping[MAPCOUNT];
|
struct MAPPING *mapping[MAPCOUNT];
|
||||||
struct PERMISSIONS_CACHE **pseccache;
|
struct PERMISSIONS_CACHE **pseccache;
|
||||||
@ -162,7 +154,7 @@ struct SECURITY_CONTEXT
|
|||||||
gid_t gid; /* gid of user requesting (not the mounter) */
|
gid_t gid; /* gid of user requesting (not the mounter) */
|
||||||
pid_t tid; /* thread id of thread requesting */
|
pid_t tid; /* thread id of thread requesting */
|
||||||
mode_t umask; /* umask of requesting thread */
|
mode_t umask; /* umask of requesting thread */
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
|
|
||||||
@ -170,23 +162,20 @@ struct SECURITY_CONTEXT
|
|||||||
* Posix ACL structures
|
* Posix ACL structures
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct POSIX_ACE
|
struct POSIX_ACE {
|
||||||
{
|
|
||||||
u16 tag;
|
u16 tag;
|
||||||
u16 perms;
|
u16 perms;
|
||||||
s32 id;
|
s32 id;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct POSIX_ACL
|
struct POSIX_ACL {
|
||||||
{
|
|
||||||
u8 version;
|
u8 version;
|
||||||
u8 flags;
|
u8 flags;
|
||||||
u16 filler;
|
u16 filler;
|
||||||
struct POSIX_ACE ace[0];
|
struct POSIX_ACE ace[0];
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
struct POSIX_SECURITY
|
struct POSIX_SECURITY {
|
||||||
{
|
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
int acccnt;
|
int acccnt;
|
||||||
int defcnt;
|
int defcnt;
|
||||||
@ -199,8 +188,7 @@ struct POSIX_SECURITY
|
|||||||
* Posix tags, cpu-endian 16 bits
|
* Posix tags, cpu-endian 16 bits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
POSIX_ACL_USER_OBJ = 1,
|
POSIX_ACL_USER_OBJ = 1,
|
||||||
POSIX_ACL_USER = 2,
|
POSIX_ACL_USER = 2,
|
||||||
POSIX_ACL_GROUP_OBJ = 4,
|
POSIX_ACL_GROUP_OBJ = 4,
|
||||||
@ -216,8 +204,7 @@ enum
|
|||||||
* Posix permissions, cpu-endian 16 bits
|
* Posix permissions, cpu-endian 16 bits
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
POSIX_PERM_X = 1,
|
POSIX_PERM_X = 1,
|
||||||
POSIX_PERM_W = 2,
|
POSIX_PERM_W = 2,
|
||||||
POSIX_PERM_R = 4,
|
POSIX_PERM_R = 4,
|
||||||
@ -228,8 +215,8 @@ enum
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern BOOL ntfs_guid_is_zero( const GUID *guid );
|
extern BOOL ntfs_guid_is_zero(const GUID *guid);
|
||||||
extern char *ntfs_guid_to_mbs( const GUID *guid, char *guid_str );
|
extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_sid_is_valid - determine if a SID is valid
|
* ntfs_sid_is_valid - determine if a SID is valid
|
||||||
@ -239,81 +226,81 @@ extern char *ntfs_guid_to_mbs( const GUID *guid, char *guid_str );
|
|||||||
*
|
*
|
||||||
* Return TRUE if it is valid and FALSE otherwise.
|
* 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 ||
|
if (!sid || sid->revision != SID_REVISION ||
|
||||||
sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES )
|
sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int ntfs_sid_to_mbs_size( const SID *sid );
|
extern int ntfs_sid_to_mbs_size(const SID *sid);
|
||||||
extern char *ntfs_sid_to_mbs( const SID *sid, char *sid_str,
|
extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
|
||||||
size_t sid_str_size );
|
size_t sid_str_size);
|
||||||
extern void ntfs_generate_guid( GUID *guid );
|
extern void ntfs_generate_guid(GUID *guid);
|
||||||
extern int ntfs_sd_add_everyone( ntfs_inode *ni );
|
extern int ntfs_sd_add_everyone(ntfs_inode *ni);
|
||||||
|
|
||||||
extern le32 ntfs_security_hash( const SECURITY_DESCRIPTOR_RELATIVE *sd,
|
extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd,
|
||||||
const u32 len );
|
const u32 len);
|
||||||
|
|
||||||
int ntfs_build_mapping( struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
||||||
BOOL allowdef );
|
BOOL allowdef);
|
||||||
int ntfs_get_owner_mode( struct SECURITY_CONTEXT *scx,
|
int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, struct stat* );
|
ntfs_inode *ni, struct stat*);
|
||||||
int ntfs_set_mode( struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode );
|
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 );
|
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
|
||||||
int ntfs_allowed_access( struct SECURITY_CONTEXT *scx,
|
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, int accesstype );
|
ntfs_inode *ni, int accesstype);
|
||||||
BOOL old_ntfs_allowed_dir_access( struct SECURITY_CONTEXT *scx,
|
BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
||||||
const char *path, int accesstype );
|
const char *path, int accesstype);
|
||||||
|
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
le32 ntfs_alloc_securid( struct SECURITY_CONTEXT *scx,
|
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
||||||
uid_t uid, gid_t gid, ntfs_inode *dir_ni,
|
uid_t uid, gid_t gid, ntfs_inode *dir_ni,
|
||||||
mode_t mode, BOOL isdir );
|
mode_t mode, BOOL isdir);
|
||||||
#else
|
#else
|
||||||
le32 ntfs_alloc_securid( struct SECURITY_CONTEXT *scx,
|
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
||||||
uid_t uid, gid_t gid, mode_t mode, BOOL isdir );
|
uid_t uid, gid_t gid, mode_t mode, BOOL isdir);
|
||||||
#endif
|
#endif
|
||||||
int ntfs_set_owner( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
uid_t uid, gid_t gid );
|
uid_t uid, gid_t gid);
|
||||||
int ntfs_set_ownmod( struct SECURITY_CONTEXT *scx,
|
int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode );
|
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
int ntfs_set_owner_mode( struct SECURITY_CONTEXT *scx,
|
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||||
mode_t mode, struct POSIX_SECURITY *pxdesc );
|
mode_t mode, struct POSIX_SECURITY *pxdesc);
|
||||||
#else
|
#else
|
||||||
int ntfs_set_owner_mode( struct SECURITY_CONTEXT *scx,
|
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode );
|
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
|
||||||
#endif
|
#endif
|
||||||
le32 ntfs_inherited_id( struct SECURITY_CONTEXT *scx,
|
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *dir_ni, BOOL fordir );
|
ntfs_inode *dir_ni, BOOL fordir);
|
||||||
int ntfs_open_secure( ntfs_volume *vol );
|
int ntfs_open_secure(ntfs_volume *vol);
|
||||||
void ntfs_close_secure( struct SECURITY_CONTEXT *scx );
|
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
|
||||||
|
|
||||||
#if POSIXACLS
|
#if POSIXACLS
|
||||||
|
|
||||||
int ntfs_set_inherited_posix( struct SECURITY_CONTEXT *scx,
|
int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
|
||||||
ntfs_inode *ni, uid_t uid, gid_t gid,
|
ntfs_inode *ni, uid_t uid, gid_t gid,
|
||||||
ntfs_inode *dir_ni, mode_t mode );
|
ntfs_inode *dir_ni, mode_t mode);
|
||||||
int ntfs_get_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
const char *name, char *value, size_t size );
|
const char *name, char *value, size_t size);
|
||||||
int ntfs_set_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
const char *name, const char *value, size_t size,
|
const char *name, const char *value, size_t size,
|
||||||
int flags );
|
int flags);
|
||||||
int ntfs_remove_posix_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
const char *name );
|
const char *name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ntfs_get_ntfs_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
char *value, size_t size );
|
char *value, size_t size);
|
||||||
int ntfs_set_ntfs_acl( struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||||
const char *value, size_t size, int flags );
|
const char *value, size_t size, int flags);
|
||||||
|
|
||||||
int ntfs_get_ntfs_attrib( ntfs_inode *ni, char *value, size_t size );
|
int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size);
|
||||||
int ntfs_set_ntfs_attrib( ntfs_inode *ni,
|
int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
||||||
const char *value, size_t size, int flags );
|
const char *value, size_t size, int flags);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -323,8 +310,7 @@ int ntfs_set_ntfs_attrib( ntfs_inode *ni,
|
|||||||
|
|
||||||
#define MAGIC_API 0x09042009
|
#define MAGIC_API 0x09042009
|
||||||
|
|
||||||
struct SECURITY_API
|
struct SECURITY_API {
|
||||||
{
|
|
||||||
u32 magic;
|
u32 magic;
|
||||||
struct SECURITY_CONTEXT security;
|
struct SECURITY_CONTEXT security;
|
||||||
struct PERMISSIONS_CACHE *seccache;
|
struct PERMISSIONS_CACHE *seccache;
|
||||||
@ -340,32 +326,32 @@ enum { OWNER_SECURITY_INFORMATION = 1,
|
|||||||
GROUP_SECURITY_INFORMATION = 2,
|
GROUP_SECURITY_INFORMATION = 2,
|
||||||
DACL_SECURITY_INFORMATION = 4,
|
DACL_SECURITY_INFORMATION = 4,
|
||||||
SACL_SECURITY_INFORMATION = 8
|
SACL_SECURITY_INFORMATION = 8
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
int ntfs_get_file_security( struct SECURITY_API *scapi,
|
int ntfs_get_file_security(struct SECURITY_API *scapi,
|
||||||
const char *path, u32 selection,
|
const char *path, u32 selection,
|
||||||
char *buf, u32 buflen, u32 *psize );
|
char *buf, u32 buflen, u32 *psize);
|
||||||
int ntfs_set_file_security( struct SECURITY_API *scapi,
|
int ntfs_set_file_security(struct SECURITY_API *scapi,
|
||||||
const char *path, u32 selection, const char *attr );
|
const char *path, u32 selection, const char *attr);
|
||||||
int ntfs_get_file_attributes( struct SECURITY_API *scapi,
|
int ntfs_get_file_attributes(struct SECURITY_API *scapi,
|
||||||
const char *path );
|
const char *path);
|
||||||
BOOL ntfs_set_file_attributes( struct SECURITY_API *scapi,
|
BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
|
||||||
const char *path, s32 attrib );
|
const char *path, s32 attrib);
|
||||||
BOOL ntfs_read_directory( struct SECURITY_API *scapi,
|
BOOL ntfs_read_directory(struct SECURITY_API *scapi,
|
||||||
const char *path, ntfs_filldir_t callback, void *context );
|
const char *path, ntfs_filldir_t callback, void *context);
|
||||||
int ntfs_read_sds( struct SECURITY_API *scapi,
|
int ntfs_read_sds(struct SECURITY_API *scapi,
|
||||||
char *buf, u32 size, u32 offset );
|
char *buf, u32 size, u32 offset);
|
||||||
INDEX_ENTRY *ntfs_read_sii( struct SECURITY_API *scapi,
|
INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
|
||||||
INDEX_ENTRY *entry );
|
INDEX_ENTRY *entry);
|
||||||
INDEX_ENTRY *ntfs_read_sdh( struct SECURITY_API *scapi,
|
INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
|
||||||
INDEX_ENTRY *entry );
|
INDEX_ENTRY *entry);
|
||||||
struct SECURITY_API *ntfs_initialize_file_security( const char *device,
|
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
||||||
int flags );
|
int flags);
|
||||||
BOOL ntfs_leave_file_security( struct SECURITY_API *scx );
|
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_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_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf);
|
||||||
int ntfs_get_user( struct SECURITY_API *scapi, const SID *usid );
|
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_group(struct SECURITY_API *scapi, const SID *gsid);
|
||||||
|
|
||||||
#endif /* defined _NTFS_SECURITY_H */
|
#endif /* defined _NTFS_SECURITY_H */
|
||||||
|
@ -92,8 +92,7 @@ typedef sle64 leLSN;
|
|||||||
/**
|
/**
|
||||||
* enum BOOL - These are just to make the code more readable...
|
* enum BOOL - These are just to make the code more readable...
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
FALSE = 0,
|
FALSE = 0,
|
||||||
#endif
|
#endif
|
||||||
@ -119,8 +118,7 @@ typedef enum
|
|||||||
/**
|
/**
|
||||||
* enum IGNORE_CASE_BOOL -
|
* enum IGNORE_CASE_BOOL -
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
CASE_SENSITIVE = 0,
|
CASE_SENSITIVE = 0,
|
||||||
IGNORE_CASE = 1,
|
IGNORE_CASE = 1,
|
||||||
} IGNORE_CASE_BOOL;
|
} IGNORE_CASE_BOOL;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,53 +26,53 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
|
||||||
extern BOOL ntfs_names_are_equal( const ntfschar *s1, size_t s1_len,
|
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 *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
|
||||||
const ntfschar *upcase, const u32 upcase_size );
|
const ntfschar *upcase, const u32 upcase_size);
|
||||||
|
|
||||||
extern int ntfs_names_full_collate( const ntfschar *name1, const u32 name1_len,
|
extern int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||||
const ntfschar *name2, const u32 name2_len,
|
const ntfschar *name2, const u32 name2_len,
|
||||||
const IGNORE_CASE_BOOL ic,
|
const IGNORE_CASE_BOOL ic,
|
||||||
const ntfschar *upcase, const u32 upcase_len );
|
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,
|
extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
||||||
const ntfschar *upcase, const u32 upcase_size );
|
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,
|
extern void ntfs_name_upcase(ntfschar *name, u32 name_len,
|
||||||
const ntfschar *upcase, const u32 upcase_len );
|
const ntfschar *upcase, const u32 upcase_len);
|
||||||
|
|
||||||
extern void ntfs_name_locase( ntfschar *name, u32 name_len,
|
extern void ntfs_name_locase(ntfschar *name, u32 name_len,
|
||||||
const ntfschar *locase, const u32 locase_len );
|
const ntfschar *locase, const u32 locase_len);
|
||||||
|
|
||||||
extern void ntfs_file_value_upcase( FILE_NAME_ATTR *file_name_attr,
|
extern void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
|
||||||
const ntfschar *upcase, const u32 upcase_len );
|
const ntfschar *upcase, const u32 upcase_len);
|
||||||
|
|
||||||
extern int ntfs_ucstombs( const ntfschar *ins, const int ins_len, char **outs,
|
extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||||
int outs_len );
|
int outs_len);
|
||||||
extern int ntfs_mbstoucs( const char *ins, ntfschar **outs );
|
extern int ntfs_mbstoucs(const char *ins, ntfschar **outs);
|
||||||
|
|
||||||
extern char *ntfs_uppercase_mbs( const char *low,
|
extern char *ntfs_uppercase_mbs(const char *low,
|
||||||
const ntfschar *upcase, u32 upcase_len );
|
const ntfschar *upcase, u32 upcase_len);
|
||||||
|
|
||||||
extern void ntfs_upcase_table_build( ntfschar *uc, u32 uc_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 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_forbidden_chars(const ntfschar *name, int len);
|
||||||
extern BOOL ntfs_collapsible_chars( ntfs_volume *vol,
|
extern BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||||
const ntfschar *shortname, int shortlen,
|
const ntfschar *shortname, int shortlen,
|
||||||
const ntfschar *longname, int longlen );
|
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__)
|
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||||
/**
|
/**
|
||||||
@ -92,7 +92,7 @@ extern int ntfs_set_char_encoding( const char *locale );
|
|||||||
* 1 means it is enabled.
|
* 1 means it is enabled.
|
||||||
* @return -1 if the argument was invalid or an error occurred, 0 if all went well.
|
* @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.
|
* Mac OS X only.
|
||||||
@ -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
|
* @return -1 if the normalization failed for some reason, otherwise the length of the
|
||||||
* normalized string stored in target.
|
* 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(__APPLE__) || defined(__DARWIN__) */
|
||||||
|
|
||||||
#endif /* defined _NTFS_UNISTR_H */
|
#endif /* defined _NTFS_UNISTR_H */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -74,17 +74,15 @@ typedef struct _ntfs_volume ntfs_volume;
|
|||||||
*
|
*
|
||||||
* Flags returned by the ntfs_check_if_mounted() function.
|
* Flags returned by the ntfs_check_if_mounted() function.
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NTFS_MF_MOUNTED = 1, /* Device is mounted. */
|
NTFS_MF_MOUNTED = 1, /* Device is mounted. */
|
||||||
NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
|
NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
|
||||||
NTFS_MF_READONLY = 4, /* Device is mounted read-only. */
|
NTFS_MF_READONLY = 4, /* Device is mounted read-only. */
|
||||||
} ntfs_mount_flags;
|
} 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
|
typedef enum {
|
||||||
{
|
|
||||||
NTFS_VOLUME_OK = 0,
|
NTFS_VOLUME_OK = 0,
|
||||||
NTFS_VOLUME_SYNTAX_ERROR = 11,
|
NTFS_VOLUME_SYNTAX_ERROR = 11,
|
||||||
NTFS_VOLUME_NOT_NTFS = 12,
|
NTFS_VOLUME_NOT_NTFS = 12,
|
||||||
@ -105,8 +103,7 @@ typedef enum
|
|||||||
*
|
*
|
||||||
* Defined bits for the state field in the ntfs_volume structure.
|
* Defined bits for the state field in the ntfs_volume structure.
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
NV_ReadOnly, /* 1: Volume is read-only. */
|
NV_ReadOnly, /* 1: Volume is read-only. */
|
||||||
NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
|
NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
|
||||||
NV_LogFileEmpty, /* 1: $logFile journal is empty. */
|
NV_LogFileEmpty, /* 1: $logFile journal is empty. */
|
||||||
@ -166,10 +163,8 @@ typedef enum
|
|||||||
/**
|
/**
|
||||||
* struct _ntfs_volume - structure describing an open volume in memory.
|
* struct _ntfs_volume - structure describing an open volume in memory.
|
||||||
*/
|
*/
|
||||||
struct _ntfs_volume
|
struct _ntfs_volume {
|
||||||
{
|
union {
|
||||||
union
|
|
||||||
{
|
|
||||||
struct ntfs_device *dev; /* NTFS device associated with
|
struct ntfs_device *dev; /* NTFS device associated with
|
||||||
the volume. */
|
the volume. */
|
||||||
void *sb; /* For kernel porting compatibility. */
|
void *sb; /* For kernel porting compatibility. */
|
||||||
@ -277,32 +272,32 @@ struct _ntfs_volume
|
|||||||
|
|
||||||
extern const char *ntfs_home;
|
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,
|
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||||
unsigned long flags );
|
unsigned long flags);
|
||||||
|
|
||||||
extern ntfs_volume *ntfs_device_mount( struct ntfs_device *dev,
|
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||||
unsigned long flags );
|
unsigned long flags);
|
||||||
|
|
||||||
extern ntfs_volume *ntfs_mount( const char *name, 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 int ntfs_umount(ntfs_volume *vol, const BOOL force);
|
||||||
|
|
||||||
extern int ntfs_version_is_supported( 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_volume_check_hiberfile(ntfs_volume *vol, int verbose);
|
||||||
extern int ntfs_logfile_reset( ntfs_volume *vol );
|
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 int ntfs_volume_error(int err);
|
||||||
extern void ntfs_mount_error( const char *vol, const char *mntpoint, 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,
|
extern int ntfs_set_shown_files(ntfs_volume *vol,
|
||||||
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files );
|
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files);
|
||||||
extern int ntfs_set_locale( void );
|
extern int ntfs_set_locale(void);
|
||||||
extern int ntfs_set_ignore_case( ntfs_volume *vol );
|
extern int ntfs_set_ignore_case(ntfs_volume *vol);
|
||||||
|
|
||||||
#endif /* defined _NTFS_VOLUME_H */
|
#endif /* defined _NTFS_VOLUME_H */
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ bool TitleSelector( char output[] )
|
|||||||
{
|
{
|
||||||
gprintf("TitleSelector()\n");
|
gprintf("TitleSelector()\n");
|
||||||
|
|
||||||
u32 num_titles;
|
s32 num_titles;
|
||||||
s32 r = -1;
|
s32 r = -1;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
u64 *titleList = NULL;
|
u64 *titleList = NULL;
|
||||||
@ -93,7 +93,7 @@ bool TitleSelector( char output[] )
|
|||||||
customOptionList options4( num_titles + 1 );
|
customOptionList options4( num_titles + 1 );
|
||||||
//write the titles on the option browser
|
//write the titles on the option browser
|
||||||
|
|
||||||
u32 i = 0;
|
s32 i = 0;
|
||||||
titles.SetType( 0x10001 );
|
titles.SetType( 0x10001 );
|
||||||
while ( i < num_titles )
|
while ( i < num_titles )
|
||||||
{
|
{
|
||||||
|
@ -96,10 +96,13 @@ int GameList::ReadGameList()
|
|||||||
return LoadUnfiltered();
|
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(char2 == 0)
|
||||||
if( char1 == 0 )return false;
|
return true;
|
||||||
|
if(char1 == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
return char2 > char1;
|
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_num1 = CFG_get_game_num( a->id );
|
||||||
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
||||||
int count1 = 0, count2 = 0;
|
int count1 = 0, count2 = 0;
|
||||||
|
|
||||||
if ( game_num1 )
|
if (game_num1)
|
||||||
count1 = game_num1->count;
|
count1 = game_num1->count;
|
||||||
if ( game_num2 )
|
if (game_num2)
|
||||||
count2 = game_num2->count;
|
count2 = game_num2->count;
|
||||||
|
|
||||||
if ( count1 == count2 )
|
if (count1 == count2)
|
||||||
return NameSortCallback( a, b );
|
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_num1 = CFG_get_game_num( a->id );
|
||||||
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
struct Game_NUM* game_num2 = CFG_get_game_num( b->id );
|
||||||
int fav1 = 0, fav2 = 0;
|
int fav1 = 0, fav2 = 0;
|
||||||
|
|
||||||
if ( game_num1 )
|
if (game_num1)
|
||||||
fav1 = game_num1->favorite;
|
fav1 = game_num1->favorite;
|
||||||
if ( game_num2 )
|
if (game_num2)
|
||||||
fav2 = game_num2->favorite;
|
fav2 = game_num2->favorite;
|
||||||
|
|
||||||
if ( fav1 == fav2 );
|
if (fav1 == fav2)
|
||||||
return NameSortCallback( a, b );
|
return NameSortCallback(a, b);
|
||||||
|
|
||||||
return ( fav1 > fav2 );
|
return (fav1 > fav2);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user