From dde61e109173a32bcbfd1baa2e565d59c58d0640 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 1 Jul 2006 11:14:08 +0000 Subject: [PATCH 001/289] ntfsinfo: cosmetic fix in SDS dumping --- ntfsprogs/ntfsinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 126aff6e..81a56575 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1016,7 +1016,8 @@ static ntfschar NTFS_DATA_SDS[5] = { const_cpu_to_le16('$'), static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) { SECURITY_DESCRIPTOR_RELATIVE *sd; - + + ntfs_log_verbose("\n"); ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", le32_to_cpu(sds->hash)); ntfs_log_verbose("\t\tSecurity id:\t\t %u\n", le32_to_cpu(sds->security_id)); From 5369c1961361818a39041b2f045963120d6bfe9c Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 13 Jul 2006 02:35:32 +0000 Subject: [PATCH 002/289] support missing owner and group in sd --- ntfsprogs/ntfsinfo.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 81a56575..5d774ec4 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -849,15 +849,21 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, /* TODO: parse the flags */ printf("%s\tFlags:\t\t\t 0x%0x\n", indent, sec_desc->control); - sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + - le32_to_cpu(sec_desc->owner)), NULL, 0); - printf("%s\tOwner SID:\t\t %s\n", indent, sid); - free(sid); + if (sec_desc->owner) { + sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + + le32_to_cpu(sec_desc->owner)), NULL, 0); + printf("%s\tOwner SID:\t\t %s\n", indent, sid); + free(sid); + } else + printf("%s\tOwner SID:\t\t missing\n", indent); - sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + - le32_to_cpu(sec_desc->group)), NULL, 0); - printf("%s\tGroup SID:\t\t %s\n", indent, sid); - free(sid); + if (sec_desc->group) { + sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + + le32_to_cpu(sec_desc->group)), NULL, 0); + printf("%s\tGroup SID:\t\t %s\n", indent, sid); + free(sid); + } else + printf("%s\tGroup SID:\t\t missing\n", indent); printf("%s\tSystem ACL:\t\t ", indent); if (sec_desc->control & SE_SACL_PRESENT) { From 035df31eaecb0aef091de2b6f75366f8cf881362 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 13 Jul 2006 02:49:07 +0000 Subject: [PATCH 003/289] move ROUND_{UP,DOWN} to support.h, make second parameter to be order in which we should power 2 (to prevent incorrect use) --- include/ntfs/rich.h | 4 +--- include/ntfs/support.h | 7 +++++++ libntfs/bitmap.c | 10 +++++----- libntfs/dir.c | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/ntfs/rich.h b/include/ntfs/rich.h index b40a7a4f..c0cb85b7 100644 --- a/include/ntfs/rich.h +++ b/include/ntfs/rich.h @@ -26,9 +26,7 @@ #include "attrib.h" #include "bitmap.h" -#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1)) -#define ROUND_DOWN(num,bound) ((num) & ~((bound)-1)) -#define ATTR_SIZE(s) ROUND_UP(s,8) +#define ATTR_SIZE(s) ROUND_UP(s, 3) ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft); diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 76114d6a..11844c31 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -60,6 +60,13 @@ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif +/* + * Round up and down @num to 2 in power of @order. + */ +#define ROUND_UP(num,order) (((num) + ((1 << order) - 1)) & \ + ~((1 << order) - 1)) +#define ROUND_DOWN(num,order) ((num) & ~((1 << order) - 1)) + /* * Simple bit operation macros. NOTE: These are NOT atomic. */ diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 4076ad90..25e7455a 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -401,9 +401,9 @@ int ntfs_bmp_add_data(struct ntfs_bmp *bmp, VCN vcn, u8 *data) return -1; ntfs_log_trace ("\n"); - old = ROUND_UP(bmp->count, 16); + old = ROUND_UP(bmp->count, 4); bmp->count++; - new = ROUND_UP(bmp->count, 16); + new = ROUND_UP(bmp->count, 4); if (old != new) { bmp->data = realloc(bmp->data, new * sizeof(*bmp->data)); @@ -513,8 +513,8 @@ int ntfs_bmp_set_range(struct ntfs_bmp *bmp, VCN vcn, s64 length, int value) vcn_finish = vcn + length - 1; //ntfs_log_debug("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish); - a = ROUND_DOWN(vcn_start, csib); - b = ROUND_DOWN(vcn_finish, csib) + 1; + a = ROUND_DOWN(vcn_start, bmp->vol->cluster_size_bits + 3); + b = ROUND_DOWN(vcn_finish, bmp->vol->cluster_size_bits + 3) + 1; //ntfs_log_debug("a = %lld, b = %lld\n", a, b); @@ -598,7 +598,7 @@ s64 ntfs_bmp_find_last_set(struct ntfs_bmp *bmp) // find cluster size of bmp byte_count = bmp->attr->data_size; - clust_count = ROUND_UP(byte_count, bmp->vol->cluster_size) >> bmp->vol->cluster_size_bits; + clust_count = ROUND_UP(byte_count, bmp->vol->cluster_size_bits) >> bmp->vol->cluster_size_bits; //ntfs_log_debug("bitmap = %lld bytes\n", byte_count); //ntfs_log_debug("bitmap = %lld buffers\n", clust_count); diff --git a/libntfs/dir.c b/libntfs/dir.c index aef26af0..95a47574 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1750,7 +1750,7 @@ int ntfs_dir_truncate(ntfs_volume *vol, struct ntfs_dir *dir) return 0; #if 0 - buf_count = ROUND_UP(dir->bitmap->attr->allocated_size, vol->cluster_size) >> vol->cluster_size_bits; + buf_count = ROUND_UP(dir->bitmap->attr->allocated_size, vol->cluster_size_bits) >> vol->cluster_size_bits; ntfs_log_debug("alloc = %lld bytes\n", dir->ialloc->allocated_size); ntfs_log_debug("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits); ntfs_log_debug("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3); From 2d137b69008ffb74504f60ac96f7ce6dbde50a13 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 13 Jul 2006 16:01:52 +0000 Subject: [PATCH 004/289] create SD in __ntfs_create --- ChangeLog | 9 ++++-- libntfs/dir.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 907dd932..0d3175fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +xx/xx/xxxx - x.xx.x - + + - ntfsmount now creates files and directories with security descriptor + that grant full access to everyone. (Yura) + 21/06/2006 - 1.13.1 - Various fixes. - Fix bug in ntfs_attr_pwrite() when we sometimes lose current run in @@ -18,13 +23,13 @@ compressed metadata image size by 10-25% and more importantly it eliminates non-interesting ntfscmp differences. (Szaka) - Change utils_parse_size() to use a base of 0 instead of 10 when - calling strtoll(). This automagically allows specification of + calling strtoll(). This automatically allows specification of numbers in hex (and octal if anyone is crazy enough to use that) in addition to decimal numbers on the command line options to most if not all utilities. (Anton) - Fix comparison of $MFT and $MFTMirr to not bail out when there are unused, invalid mft records which are the same in both $MFT and - $MFTMirr. Ported from kernel driver 2.1.27 release and aplied both + $MFTMirr. Ported from kernel driver 2.1.27 release and applied both to libntfs/volume.c mount related code and to ntfsprogs/ntfsfix.c's fixup code. (Anton) - Change ntfsinfo to dump the key data as well as the keys themselves diff --git a/libntfs/dir.c b/libntfs/dir.c index 95a47574..e9cd1e03 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1082,7 +1082,7 @@ err_out: * @type: type of the object to create * @dev: major and minor device numbers (obtained from makedev()) * @target: target in unicode (only for symlinks) - * @target_len: length of target in unicode charcters + * @target_len: length of target in unicode characters * * Internal, use ntfs_create{,_device,_symlink} wrappers instead. * @@ -1110,10 +1110,14 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, ntfschar *target, u8 target_len) { ntfs_inode *ni; - int rollback_data = 0; + int rollback_data = 0, rollback_sd = 0; FILE_NAME_ATTR *fn = NULL; STANDARD_INFORMATION *si = NULL; - int err, fn_len, si_len; + SECURITY_DESCRIPTOR_ATTR *sd = NULL; + ACL *acl; + ACCESS_ALLOWED_ACE *ace; + SID *sid; + int err, fn_len, si_len, sd_len; ntfs_log_trace("Entering.\n"); /* Sanity checks. */ @@ -1158,6 +1162,60 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, "attribute.\n"); goto err_out; } + /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ + /* + * Calculate security descriptor length. We have 2 sub-authorities in + * owner and group SIDs, but structure SID contain only one, so add + * 4 bytes to every SID. + */ + sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); + sd = calloc(1, sd_len); + if (!sd) { + err = errno; + ntfs_log_error("Not enough memory.\n"); + goto err_out; + } + sd->revision = 1; + sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; + sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); + sd->owner = cpu_to_le32((u8*)sid - (u8*)sd); + sid->revision = 1; + sid->sub_authority_count = 2; + sid->sub_authority[0] = cpu_to_le32(32); + sid->sub_authority[1] = cpu_to_le32(544); + sid->identifier_authority.value[5] = 5; + sid = (SID*)((u8*)sid + sizeof(SID) + 4); + sd->group = cpu_to_le32((u8*)sid - (u8*)sd); + sid->revision = 1; + sid->sub_authority_count = 2; + sid->sub_authority[0] = cpu_to_le32(32); + sid->sub_authority[1] = cpu_to_le32(544); + sid->identifier_authority.value[5] = 5; + acl = (ACL*)((u8*)sid + sizeof(SID) + 4); + sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd); + acl->revision = 2; + acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); + acl->ace_count = cpu_to_le16(1); + ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE)); + ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */ + ace->sid.revision = 1; + ace->sid.sub_authority_count = 1; + ace->sid.sub_authority[0] = 0; + ace->sid.identifier_authority.value[5] = 1; + /* Add SECURITY_DESCRIPTOR attribute to inode. */ + if (ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, + (u8*)sd, sd_len)) { + err = errno; + ntfs_log_error("Failed to add SECURITY_DESCRIPTOR " + "attribute.\n"); + goto err_out; + } + rollback_sd = 1; + /* Add DATA/INDEX_ROOT attribute. */ if (S_ISDIR(type)) { INDEX_ROOT *ir = NULL; INDEX_ENTRY *ie; @@ -1297,10 +1355,24 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, /* Done! */ free(fn); free(si); + free(sd); ntfs_log_trace("Done.\n"); return ni; err_out: ntfs_log_trace("Failed.\n"); + if (rollback_sd) { + ntfs_attr *na; + + na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); + if (!na) + ntfs_log_perror("Failed to open SD (0x50) attribute of " + " inode 0x%llx. Run chkdsk.\n", + (unsigned long long)ni->mft_no); + else if (ntfs_attr_rm(na)) + ntfs_log_perror("Failed to remove SD (0x50) attribute " + "of inode 0x%llx. Run chkdsk.\n", + (unsigned long long)ni->mft_no); + } if (rollback_data) { ntfs_attr *na; @@ -1330,6 +1402,7 @@ err_out: "Leaving inconsistent metadata. Run chkdsk.\n"); free(fn); free(si); + free(sd); errno = err; return NULL; } From 28a2b1f2b0b5cf5a6370fec573ab358c2649ca7b Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 17 Jul 2006 11:49:52 +0000 Subject: [PATCH 005/289] prepare to Szaka's code merge: remove not working Rich's index code --- configure.ac | 9 - include/ntfs/Makefile.am | 2 - include/ntfs/bitmap.h | 33 --- include/ntfs/dir.h | 33 --- include/ntfs/index.h | 17 -- include/ntfs/inode.h | 8 - include/ntfs/mft.h | 14 -- include/ntfs/volume.h | 12 -- libntfs/Makefile.am | 4 - libntfs/bitmap.c | 442 --------------------------------------- libntfs/dir.c | 440 -------------------------------------- libntfs/index.c | 275 ------------------------ libntfs/inode.c | 137 ------------ libntfs/mft.c | 380 --------------------------------- libntfs/volume.c | 365 -------------------------------- ntfsprogs/Makefile.am | 10 - ntfsprogs/utils.c | 5 - ntfsprogs/utils.h | 4 - 18 files changed, 2190 deletions(-) diff --git a/configure.ac b/configure.ac index b6eea183..a1975eee 100644 --- a/configure.ac +++ b/configure.ac @@ -149,15 +149,6 @@ AC_ARG_ENABLE(debug-logging, fi, ) -AC_ARG_ENABLE(rich, - AS_HELP_STRING(--enable-rich,enable Rich's "rm" test code), , - enable_rich=no -) -AM_CONDITIONAL(ENABLE_RICH, test "$enable_rich" = yes) -if test "$enable_rich" = "yes"; then - CFLAGS="$CFLAGS -DNTFS_RICH" -fi - # Use GNU extensions if available. AC_GNU_SOURCE diff --git a/include/ntfs/Makefile.am b/include/ntfs/Makefile.am index 2725ae93..1b9a0433 100644 --- a/include/ntfs/Makefile.am +++ b/include/ntfs/Makefile.am @@ -25,11 +25,9 @@ linux_ntfsinclude_HEADERS = \ mft.h \ mst.h \ ntfstime.h \ - rich.h \ runlist.h \ security.h \ support.h \ - tree.h \ types.h \ unistr.h \ version.h \ diff --git a/include/ntfs/bitmap.h b/include/ntfs/bitmap.h index c12a786a..f6d16f19 100644 --- a/include/ntfs/bitmap.h +++ b/include/ntfs/bitmap.h @@ -131,37 +131,4 @@ static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit) return ntfs_bitmap_clear_run(na, bit, 1); } - -#ifdef NTFS_RICH - -#include "layout.h" -#include "inode.h" - -/** - * struct ntfs_bmp - - * - * a cache for either dir/$BITMAP, $MFT/$BITMAP or $Bitmap/$DATA - */ -struct ntfs_bmp { - ntfs_volume *vol; - ntfs_attr *attr; - int count; - u8 **data; - VCN *data_vcn; -}; - - -int ntfs_bmp_rollback(struct ntfs_bmp *bmp); -int ntfs_bmp_commit(struct ntfs_bmp *bmp); -void ntfs_bmp_free(struct ntfs_bmp *bmp); -struct ntfs_bmp * ntfs_bmp_create(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len); -int ntfs_bmp_add_data(struct ntfs_bmp *bmp, VCN vcn, u8 *data); -u8 * ntfs_bmp_get_data(struct ntfs_bmp *bmp, VCN vcn); -int ntfs_bmp_set_range(struct ntfs_bmp *bmp, VCN vcn, s64 length, int value); -s64 ntfs_bmp_find_last_set(struct ntfs_bmp *bmp); -int ntfs_bmp_find_space(struct ntfs_bmp *bmp, LCN start, long size); - -#endif /* NTFS_RICH */ - #endif /* defined _NTFS_BITMAP_H */ - diff --git a/include/ntfs/dir.h b/include/ntfs/dir.h index 8e81a4ff..4b76c441 100644 --- a/include/ntfs/dir.h +++ b/include/ntfs/dir.h @@ -107,37 +107,4 @@ typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name, extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir); -#ifdef NTFS_RICH - -/** - * struct ntfs_dir - - */ -struct ntfs_dir { - ntfs_volume *vol; - struct ntfs_dir *parent; - ntfschar *name; - int name_len; - MFT_REF mft_num; - struct ntfs_dt *index; - struct ntfs_dir **children; - int child_count; - struct ntfs_bmp *bitmap; - ntfs_inode *inode; - ntfs_attr *iroot; - ntfs_attr *ialloc; - int index_size; -}; - - -int ntfs_dir_rollback(struct ntfs_dir *dir); -int ntfs_dir_truncate(ntfs_volume *vol, struct ntfs_dir *dir); -int ntfs_dir_commit(struct ntfs_dir *dir); -void ntfs_dir_free(struct ntfs_dir *dir); -struct ntfs_dir * ntfs_dir_create(ntfs_volume *vol, MFT_REF mft_num); -void ntfs_dir_add(struct ntfs_dir *parent, struct ntfs_dir *child); -struct ntfs_dir * ntfs_dir_find2(struct ntfs_dir *dir, ntfschar *name, int name_len); - -#endif /* NTFS_RICH */ - #endif /* defined _NTFS_DIR_H */ - diff --git a/include/ntfs/index.h b/include/ntfs/index.h index 2e558e44..10465dd8 100644 --- a/include/ntfs/index.h +++ b/include/ntfs/index.h @@ -129,21 +129,4 @@ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) ictx->ia_dirty = TRUE; } - -#ifdef NTFS_RICH - -#include "layout.h" - -void ntfs_ie_free(INDEX_ENTRY *ie); -INDEX_ENTRY * ntfs_ie_create(void); -VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie); -INDEX_ENTRY * ntfs_ie_copy(INDEX_ENTRY *ie); -INDEX_ENTRY * ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn); -INDEX_ENTRY * ntfs_ie_remove_vcn(INDEX_ENTRY *ie); -INDEX_ENTRY * ntfs_ie_set_name(INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype); -INDEX_ENTRY * ntfs_ie_remove_name(INDEX_ENTRY *ie); - -#endif /* NTFS_RICH */ - #endif /* _NTFS_INDEX_H */ - diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 032d0216..a7b431e3 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -187,12 +187,4 @@ extern int ntfs_inode_free_space(ntfs_inode *ni, int size); extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a); -#ifdef NTFS_RICH - -int ntfs_inode_close2(ntfs_inode *ni); -ntfs_inode * ntfs_inode_open2(ntfs_volume *vol, const MFT_REF mref); -ntfs_inode * ntfs_inode_open3(ntfs_volume *vol, const MFT_REF mref); - -#endif /* NTFS_RICH */ - #endif /* defined _NTFS_INODE_H */ diff --git a/include/ntfs/mft.h b/include/ntfs/mft.h index ce481c21..180f6153 100644 --- a/include/ntfs/mft.h +++ b/include/ntfs/mft.h @@ -113,18 +113,4 @@ extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni); extern int ntfs_mft_usn_dec(MFT_RECORD *mrec); -#ifdef NTFS_RICH - -#include "bitmap.h" -#include "dir.h" - -int ntfs_mft_remove_attr(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type); -ATTR_RECORD * ntfs_mft_add_attr(ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len); -int ntfs_mft_resize_resident(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len); -int ntfs_mft_free_space(struct ntfs_dir *dir); -int ntfs_mft_add_index(struct ntfs_dir *dir); - -#endif /* NTFS_RICH */ - #endif /* defined _NTFS_MFT_H */ - diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index c884f494..0ce254ca 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -228,16 +228,4 @@ extern int ntfs_logfile_reset(ntfs_volume *vol); extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags); -#ifdef NTFS_RICH - -int ntfs_volume_commit(ntfs_volume *vol); -int ntfs_volume_rollback(ntfs_volume *vol); -int ntfs_volume_umount2(ntfs_volume *vol, const BOOL force); -ntfs_volume * ntfs_volume_mount2(const char *device, unsigned long flags, BOOL force); -int utils_valid_device(const char *name, int force); -ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force); - -#endif /* NTFS_RICH */ - #endif /* defined _NTFS_VOLUME_H */ - diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index ac784c67..a4e25dbd 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -60,10 +60,6 @@ libntfs_la_SOURCES = \ version.c \ volume.c -if ENABLE_RICH -libntfs_la_SOURCES += rich.c tree.c -endif - if ENABLE_GNOME_VFS gnomevfsmoduleslibdir = $(libdir)/gnome-vfs-2.0/modules diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 25e7455a..40d8e85a 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -230,445 +230,3 @@ int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count) return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0); } - -#ifdef NTFS_RICH - -#include "layout.h" -#include "volume.h" -#include "rich.h" - -/** - * ntfs_bmp_rollback - Discard the in-memory bitmap changes - * @bmp: - * - * Description... - * - * Returns: - */ -int ntfs_bmp_rollback(struct ntfs_bmp *bmp) -{ - int i; - - if ((!bmp) || (bmp->count == 0)) - return 0; - - ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type); - - for (i = 0; i < bmp->count; i++) - free(bmp->data[i]); - - free(bmp->data); - free(bmp->data_vcn); - bmp->data = NULL; - bmp->data_vcn = NULL; - bmp->count = 0; - - return 0; -} - -/** - * ntfs_bmp_commit - Write the cached bitmap data to disk - * @bmp: - * - * Description... - * - * Returns: - */ -int ntfs_bmp_commit(struct ntfs_bmp *bmp) -{ - int i; - u32 cs; - u32 ws; // write size - - if (!bmp) - return 0; - if (bmp->count == 0) - return 0; - - ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type); -#if 0 - ntfs_log_debug("attr = 0x%02X\n", bmp->attr->type); - ntfs_log_debug("resident = %d\n", !NAttrNonResident(bmp->attr)); - ntfs_log_debug("\ta size = %lld\n", bmp->attr->allocated_size); - ntfs_log_debug("\td size = %lld\n", bmp->attr->data_size); - ntfs_log_debug("\ti size = %lld\n", bmp->attr->initialized_size); -#endif - - ntfs_log_debug("commit bmp inode %lld, 0x%02X (%sresident)\n", bmp->attr->ni->mft_no, bmp->attr->type, NAttrNonResident(bmp->attr) ? "non-" : ""); - - if (NAttrNonResident(bmp->attr)) { - cs = bmp->vol->cluster_size; - - // non-resident - for (i = 0; i < bmp->count; i++) { - if (((bmp->data_vcn[i]+1) * cs) < bmp->attr->data_size) - ws = cs; - else - ws = bmp->attr->data_size & (cs - 1); - //ntfs_log_debug("writing %d bytes\n", ws); - ntfs_attr_pwrite(bmp->attr, bmp->data_vcn[i] * cs, ws, bmp->data[i]); // XXX retval - ntfs_log_warning("\tntfs_attr_pwrite(vcn %lld)\n", bmp->data_vcn[i]); - } - } else { - // resident - ntfs_attr_pwrite(bmp->attr, bmp->data_vcn[0], bmp->attr->data_size, bmp->data[0]); // XXX retval - ntfs_log_warning("\tntfs_attr_pwrite resident (%lld)\n", bmp->attr->data_size); - } - - ntfs_bmp_rollback(bmp); - - return 0; -} - -/** - * ntfs_bmp_free - Destroy a bitmap object - * @bmp: - * - * Description... - * - * Returns: - */ -void ntfs_bmp_free(struct ntfs_bmp *bmp) -{ - if (!bmp) - return; - - ntfs_log_trace ("bmp %p, records %d, attr %lld/%02X\n", bmp, bmp->count, MREF(bmp->attr->ni->mft_no), bmp->attr->type); - - ntfs_bmp_rollback(bmp); - ntfs_attr_close(bmp->attr); - - free(bmp); -} - -/** - * ntfs_bmp_create - Create a representation of a bitmap - * @inode: - * @type: - * @name: - * @name_len: - * - * Description... - * - * Returns: - */ -struct ntfs_bmp * ntfs_bmp_create(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len) -{ - struct ntfs_bmp *bmp; - ntfs_attr *attr; - - if (!inode) - return NULL; - - ntfs_log_trace ("\n"); - attr = ntfs_attr_open(inode, type, name, name_len); - if (!attr) - return NULL; - - bmp = calloc(1, sizeof(*bmp)); - if (!bmp) { - ntfs_attr_close(attr); - return NULL; - } - - ntfs_log_critical("bmp = %p, attr = %p, inode = %p, attr->ni->mft_no = %lld\n", bmp, attr, inode, MREF(attr->ni->mft_no)); - bmp->vol = inode->vol; - bmp->attr = attr; - bmp->data = NULL; - bmp->data_vcn = NULL; - bmp->count = 0; - - return bmp; -} - -/** - * ntfs_bmp_add_data - Add a bitmap block to the current cache - * @bmp: - * @vcn: - * @data: - * - * Description... - * - * Returns: - */ -int ntfs_bmp_add_data(struct ntfs_bmp *bmp, VCN vcn, u8 *data) -{ - int i = 0; - int old; - int new; - - if (!bmp || !data) - return -1; - - ntfs_log_trace ("\n"); - old = ROUND_UP(bmp->count, 4); - bmp->count++; - new = ROUND_UP(bmp->count, 4); - - if (old != new) { - bmp->data = realloc(bmp->data, new * sizeof(*bmp->data)); - bmp->data_vcn = realloc(bmp->data_vcn , new * sizeof(*bmp->data_vcn)); - } - - for (i = 0; i < bmp->count-1; i++) - if (bmp->data_vcn[i] > vcn) - break; - - if ((bmp->count-i) > 0) { - memmove(&bmp->data[i+1], &bmp->data[i], (bmp->count-i) * sizeof(*bmp->data)); - memmove(&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof(*bmp->data_vcn)); - } - - bmp->data[i] = data; - bmp->data_vcn[i] = vcn; - - return bmp->count; -} - -/** - * ntfs_bmp_get_data - Ask for a bitmap block from the cache - * @bmp: - * @vcn: - * - * Description... - * - * Returns: - */ -u8 * ntfs_bmp_get_data(struct ntfs_bmp *bmp, VCN vcn) -{ - u8 *buffer; - int i; - int cs; - int cb; - - if (!bmp) - return NULL; - - ntfs_log_trace ("\n"); - cs = bmp->vol->cluster_size; - cb = bmp->vol->cluster_size_bits; - - // XXX range check against vol,attr - // never compressed, so data = init - - vcn >>= (cb + 3); // convert to bitmap clusters - - for (i = 0; i < bmp->count; i++) { - if (vcn == bmp->data_vcn[i]) { - //ntfs_log_debug("reusing bitmap cluster %lld\n", vcn); - return bmp->data[i]; - } - } - - buffer = calloc(1, cs); // XXX could be smaller if attr size < cluster size - if (!buffer) - return NULL; - - //ntfs_log_debug("loading from bitmap cluster %lld\n", vcn); - //ntfs_log_debug("loading from bitmap byte %lld\n", vcn<attr, vcn<vol->cluster_size << 3; - - vcn_start = vcn; - vcn_finish = vcn + length - 1; - - //ntfs_log_debug("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish); - a = ROUND_DOWN(vcn_start, bmp->vol->cluster_size_bits + 3); - b = ROUND_DOWN(vcn_finish, bmp->vol->cluster_size_bits + 3) + 1; - - //ntfs_log_debug("a = %lld, b = %lld\n", a, b); - - for (i = a; i < b; i += csib) { - //ntfs_log_debug("ntfs_bmp_get_data %lld\n", i); - buffer = ntfs_bmp_get_data(bmp, i); - if (!buffer) - return -1; - - block_start = i; - block_finish = block_start + csib - 1; - - mask_start = (0xFF << (vcn_start & 7)); - mask_finish = (0xFF >> (7 - (vcn_finish & 7))); - - if ((vcn_start >= block_start) && (vcn_start <= block_finish)) { - byte_start = (vcn_start - block_start) >> 3; - } else { - byte_start = 0; - mask_start = 0xFF; - } - - if ((vcn_finish >= block_start) && (vcn_finish <= block_finish)) { - byte_finish = (vcn_finish - block_start) >> 3; - } else { - byte_finish = bmp->vol->cluster_size - 1; - mask_finish = 0xFF; - } - - if ((byte_finish - byte_start) > 1) { - memset(buffer+byte_start+1, value, byte_finish-byte_start-1); - } else if (byte_finish == byte_start) { - mask_start &= mask_finish; - mask_finish = 0x00; - } - - if (value) { - buffer[byte_start] |= mask_start; - buffer[byte_finish] |= mask_finish; - } else { - buffer[byte_start] &= (~mask_start); - buffer[byte_finish] &= (~mask_finish); - } - } - -#if 1 - ntfs_log_debug("Modified: inode %lld, ", bmp->attr->ni->mft_no); - switch (bmp->attr->type) { - case AT_BITMAP: ntfs_log_debug("$BITMAP"); break; - case AT_DATA: ntfs_log_debug("$DATA"); break; - default: break; - } - ntfs_log_debug(" vcn %lld-%lld\n", vcn>>12, (vcn+length-1)>>12); -#endif - return 1; -} - -/** - * ntfs_bmp_find_last_set - Find the last set bit in the bitmap - * @bmp: - * - * Description... - * - * Returns: - */ -s64 ntfs_bmp_find_last_set(struct ntfs_bmp *bmp) -{ - s64 clust_count; - s64 byte_count; - s64 clust; - int byte; - int bit; - int note; - u8 *buffer; - - if (!bmp) - return -2; - - ntfs_log_trace ("\n"); - // find byte size of bmp - // find cluster size of bmp - - byte_count = bmp->attr->data_size; - clust_count = ROUND_UP(byte_count, bmp->vol->cluster_size_bits) >> bmp->vol->cluster_size_bits; - - //ntfs_log_debug("bitmap = %lld bytes\n", byte_count); - //ntfs_log_debug("bitmap = %lld buffers\n", clust_count); - - // for each cluster backwards - for (clust = clust_count-1; clust >= 0; clust--) { - //ntfs_log_debug("cluster %lld\n", clust); - //ntfs_log_debug("get vcn %lld\n", clust << (bmp->vol->cluster_size_bits + 3)); - buffer = ntfs_bmp_get_data(bmp, clust << (bmp->vol->cluster_size_bits + 3)); - //utils_dump_mem(buffer, 0, 8, DM_NO_ASCII); - if (!buffer) - return -2; - if ((clust == (clust_count-1) && ((byte_count % bmp->vol->cluster_size) != 0))) { - byte = byte_count % bmp->vol->cluster_size; - } else { - byte = bmp->vol->cluster_size; - } - //ntfs_log_debug("start byte = %d\n", byte); - // for each byte backward - for (byte--; byte >= 0; byte--) { - //ntfs_log_debug("\tbyte %d (%d)\n", byte, buffer[byte]); - // for each bit shift up - note = -1; - for (bit = 7; bit >= 0; bit--) { - //ntfs_log_debug("\t\tbit %d (%d)\n", (1<= 0) { - // if note, return value - //ntfs_log_debug("match %lld (c=%lld,b=%d,n=%d)\n", (((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note, clust, byte, note); - return ((((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note); - } - } - } - - return -1; -} - -/** - * ntfs_bmp_find_space - Find an unused block of bits in a bitmap - * @bmp: - * @start: - * @size: - * - * Description... - * - * Returns: - */ -int ntfs_bmp_find_space(struct ntfs_bmp *bmp, LCN start, long size) -{ - if (!bmp) - return 0; - - ntfs_log_trace ("\n"); - start = 0; - size = 0; - - /* - bmp find space - uncached bmp's - $Bitmap/$DATA free space on volume - dir/$BITMAP free index record - $MFT/$BITMAP free record in mft - */ - return 0; -} - - -#endif /* NTFS_RICH */ - diff --git a/libntfs/dir.c b/libntfs/dir.c index e9cd1e03..6eb6d082 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1756,443 +1756,3 @@ err_out: return -1; } - -#ifdef NTFS_RICH - -#include "layout.h" -#include "tree.h" -#include "bitmap.h" -#include "rich.h" - -/** - * ntfs_dir_rollback - Discard the in-memory directory changes - * @dir: - * - * Description... - * - * Returns: - */ -int ntfs_dir_rollback(struct ntfs_dir *dir) -{ - int i; - - if (!dir) - return -1; - - ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, - dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); - - if (ntfs_dt_rollback(dir->index) < 0) - return -1; - - if (ntfs_bmp_rollback(dir->bitmap) < 0) - return -1; - - for (i = 0; i < dir->child_count; i++) { - if (ntfs_dir_rollback(dir->children[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dir_truncate - Shrink an index allocation - * @vol: - * @dir: - * - * Description... - * - * Returns: - */ -int ntfs_dir_truncate(ntfs_volume *vol, struct ntfs_dir *dir) -{ - //int i; - //u8 *buffer; - //int buf_count; - s64 last_bit; - INDEX_ENTRY *ie; - - if (!vol || !dir) - return -1; - - ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, - dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); - - if ((dir->ialloc == NULL) || (dir->bitmap == NULL)) - return 0; - -#if 0 - buf_count = ROUND_UP(dir->bitmap->attr->allocated_size, vol->cluster_size_bits) >> vol->cluster_size_bits; - ntfs_log_debug("alloc = %lld bytes\n", dir->ialloc->allocated_size); - ntfs_log_debug("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits); - ntfs_log_debug("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3); - ntfs_log_debug("bitmap = %p\n", dir->bitmap); - ntfs_log_debug("bitmap = %lld bytes\n", dir->bitmap->attr->allocated_size); - ntfs_log_debug("bitmap = %d buffers\n", buf_count); -#endif - - last_bit = ntfs_bmp_find_last_set(dir->bitmap); - if (dir->ialloc->allocated_size == (dir->index_size * (last_bit + 1))) { - //ntfs_log_debug("nothing to do\n"); - return 0; - } - - ntfs_log_debug("Truncation needed\n"); - -#if 0 - ntfs_log_debug("\tlast bit = %lld\n", last_bit); - ntfs_log_debug("\tactual IALLOC size = %lld\n", dir->ialloc->allocated_size); - ntfs_log_debug("\tshould IALLOC size = %lld\n", dir->index_size * (last_bit + 1)); -#endif - - if ((dir->index_size * (last_bit + 1)) == 0) { - ntfs_log_debug("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); - //rollback all dts - //ntfs_dt_rollback(dir->index); - //dir->index = NULL; - // What about the ROOT dt? - - ie = ntfs_ie_copy(dir->index->children[0]); - if (!ie) { - ntfs_log_warning("IE copy failed\n"); - return -1; - } - - ie = ntfs_ie_remove_vcn(ie); - if (!ie) { - ntfs_log_warning("IE remove vcn failed\n"); - return -1; - } - - //utils_dump_mem(dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); ntfs_log_debug("\n"); - //utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS); ntfs_log_debug("\n"); - ntfs_dt_root_replace(dir->index, 0, dir->index->children[0], ie); - //utils_dump_mem(dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); ntfs_log_debug("\n"); - //ntfs_log_debug("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); - - ntfs_ie_free(ie); - ie = NULL; - - //index flags remove LARGE_INDEX - dir->index->header->flags = 0; - - //rollback dir's bmp - ntfs_bmp_free(dir->bitmap); - dir->bitmap = NULL; - - /* - for (i = 0; i < dir->index->child_count; i++) { - ntfs_dt_rollback(dir->index->sub_nodes[i]); - dir->index->sub_nodes[i] = NULL; - } - */ - - //ntfs_log_debug("dir->index->inodes[0] = %p\n", dir->index->inodes[0]); - - //remove 0xA0 attribute - ntfs_mft_remove_attr(vol->private_bmp2, dir->inode, AT_INDEX_ALLOCATION); - - //remove 0xB0 attribute - ntfs_mft_remove_attr(vol->private_bmp2, dir->inode, AT_BITMAP); - } else { - ntfs_log_warning("Cannot shrink directory\n"); - //ntfs_dir_shrink_alloc - //ntfs_dir_shrink_bitmap - //make bitmap resident? - } - - /* - * Remove - * dt -> dead - * bitmap updated - * rollback dead dts - * commit bitmap - * commit dts - * commit dir - */ - /* - * Reuse - * search for lowest dead - * update bitmap - * init dt - * remove from dead - * insert into tree - * init INDX - */ - -#if 0 - buffer = ntfs_bmp_get_data(dir->bitmap, 0); - if (!buffer) - return -1; - - utils_dump_mem(buffer, 0, 8, DM_NO_ASCII); - for (i = buf_count-1; i >= 0; i--) { - if (buffer[i]) { - ntfs_log_debug("alloc in use\n"); - return 0; - } - } -#endif - - // /$BITMAP($I30) - // /$INDEX_ALLOCATION($I30) - // $Bitmap - - // Find the highest set bit in the directory bitmap - // can we free any clusters of the alloc? - // if yes, resize attribute - - // Are *any* bits set? - // If not remove ialloc - - return 0; -} - -/** - * ntfs_dir_commit - Write to disk the in-memory directory changes - * @dir: - * - * Description... - * - * Returns: - */ -int ntfs_dir_commit(struct ntfs_dir *dir) -{ - int i; - - if (!dir) - return 0; - - ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, - dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); - - if (NInoDirty(dir->inode)) { - ntfs_inode_sync(dir->inode); - ntfs_log_warning("\tntfs_inode_sync %llu\n", dir->inode->mft_no); - } - - if (ntfs_dt_commit(dir->index) < 0) - return -1; - - if (ntfs_bmp_commit(dir->bitmap) < 0) - return -1; - - for (i = 0; i < dir->child_count; i++) { - if (ntfs_dir_commit(dir->children[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dir_free - Destroy a directory object - * @dir: - * - * Description... - * - * Returns: - */ -void ntfs_dir_free(struct ntfs_dir *dir) -{ - struct ntfs_dir *parent; - int i; - - if (!dir) - return; - - ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, - dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); - - ntfs_dir_rollback(dir); - - parent = dir->parent; - if (parent) { - for (i = 0; i < parent->child_count; i++) { - if (parent->children[i] == dir) { - parent->children[i] = NULL; - } - } - } - - ntfs_attr_close(dir->iroot); - ntfs_attr_close(dir->ialloc); - ntfs_inode_close2(dir->inode); - - ntfs_dt_free (dir->index); - ntfs_bmp_free(dir->bitmap); - - for (i = 0; i < dir->child_count; i++) - ntfs_dir_free(dir->children[i]); - - free(dir->name); - free(dir->children); - free(dir); -} - -/** - * ntfs_dir_create - Create a representation of a directory - * @vol: - * @mft_num: - * - * Description... - * - * Returns: - */ -struct ntfs_dir * ntfs_dir_create(ntfs_volume *vol, MFT_REF mft_num) -{ - struct ntfs_dir *dir = NULL; - ntfs_inode *inode = NULL; - ATTR_RECORD *rec = NULL; - INDEX_ROOT *ir = NULL; - FILE_NAME_ATTR *name = NULL; - - if (!vol) - return NULL; - - ntfs_log_trace ("inode %lld\n", MREF(mft_num)); - - inode = ntfs_inode_open2(vol, mft_num); - if (!inode) - return NULL; - - dir = calloc(1, sizeof(*dir)); - if (!dir) { - ntfs_inode_close2(inode); - return NULL; - } - - dir->inode = inode; - dir->iroot = ntfs_attr_open(inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4); - dir->ialloc = ntfs_attr_open(inode, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); - - if (!dir->iroot) { - ntfs_dir_free(dir); - return NULL; - } - - dir->vol = vol; - dir->parent = NULL; - dir->name = NULL; - dir->name_len = 0; - dir->index = NULL; - dir->children = NULL; - dir->child_count = 0; - dir->mft_num = mft_num; - - // This may not exist - dir->bitmap = ntfs_bmp_create(inode, AT_BITMAP, NTFS_INDEX_I30, 4); - - if (dir->iroot) { - rec = find_first_attribute(AT_INDEX_ROOT, inode->mrec); - ir = (INDEX_ROOT*) ((u8*)rec + rec->value_offset); - dir->index_size = ir->index_block_size; - ntfs_log_debug("dir size = %d\n", dir->index_size); - } else { - // XXX !iroot? - dir->index_size = 0; - } - - // Finally, find the dir's name - rec = find_first_attribute(AT_FILE_NAME, inode->mrec); - name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset); - - dir->name_len = name->file_name_length; - dir->name = malloc(sizeof(ntfschar) * dir->name_len); - memcpy(dir->name, name->file_name, sizeof(ntfschar) * dir->name_len); - - return dir; -} - -/** - * ntfs_dir_add - Add a directory to another as a child - * @parent: - * @child: - * - * Description... - * - * Returns: - */ -void ntfs_dir_add(struct ntfs_dir *parent, struct ntfs_dir *child) -{ - if (!parent || !child) - return; - - ntfs_log_trace ("parent %p, inode %lld, children %d\n", parent, - parent ? MREF(parent->mft_num) : 0, parent ? parent->child_count : 0); - ntfs_log_trace ("child %p, inode %lld, children %d\n", child, - child ? MREF(child->mft_num) : 0, child ? child->child_count : 0); - - parent->child_count++; - //ntfs_log_debug("child count = %d\n", parent->child_count); - parent->children = realloc(parent->children, parent->child_count * sizeof(struct ntfs_dir*)); - child->parent = parent; - - parent->children[parent->child_count-1] = child; -} - -/** - * ntfs_dir_find2 - Find a directory by name - * @dir: - * @name: - * @name_len: - * - * Description... - * - * Returns: - */ -struct ntfs_dir * ntfs_dir_find2(struct ntfs_dir *dir, ntfschar *name, int name_len) -{ - int i; - struct ntfs_dir *child = NULL; - struct ntfs_dt *dt = NULL; - int dt_num = 0; - INDEX_ENTRY *ie; - MFT_REF mft_num; - - if (!dir || !name) - return NULL; - - ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, - dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); - - if (!dir->index) { // XXX when will this happen? - ntfs_log_debug("ntfs_dir_find2 - directory has no index\n"); - return NULL; - } - - for (i = 0; i < dir->child_count; i++) { - if (0 == ntfs_names_collate(name, name_len, - dir->children[i]->name, - dir->children[i]->name_len, - 2, IGNORE_CASE, - dir->vol->upcase, - dir->vol->upcase_len)) - return dir->children[i]; - } - - dt = ntfs_dt_find2(dir->index, name, name_len, &dt_num); - if (!dt) { - ntfs_log_debug("can't find name in dir\n"); - return NULL; - } - - ie = dt->children[dt_num]; - - mft_num = ie->indexed_file; - - child = ntfs_dir_create(dir->vol, mft_num); - if (!child) - return NULL; - - child->index = ntfs_dt_create(child, NULL, -1); - - ntfs_dir_add(dir, child); - - return child; -} - - -#endif /* NTFS_RICH */ - diff --git a/libntfs/index.c b/libntfs/index.c index a33926f1..8fd78b47 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -660,280 +660,6 @@ err_out: return -1; } - -#ifdef NTFS_RICH - -#ifdef HAVE_STRING_H -#include -#endif -#include "rich.h" - -/** - * ntfs_ie_free - Destroy an index entry object - * @ie: - * - * Description... - * - * Returns: - */ -void ntfs_ie_free(INDEX_ENTRY *ie) -{ - ntfs_log_trace ("ie %p, inode %lld\n", ie, MREF(ie->indexed_file)); - free(ie); -} - -/** - * ntfs_ie_create - Create a representation of an directory index entry - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_create(void) -{ - int length; - INDEX_ENTRY *ie; - - ntfs_log_trace ("\n"); - length = 16; - ie = calloc(1, length); - if (!ie) - return NULL; - - ie->indexed_file = 0; - ie->length = length; - ie->key_length = 0; - ie->flags = INDEX_ENTRY_END; - ie->reserved = 0; - return ie; -} - -/** - * ntfs_ie_get_vcn - Get the VCN associated with an index entry - * @ie: - * - * Description... - * - * Returns: - */ -VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie) -{ - if (!ie) - return -1; - if (!(ie->flags & INDEX_ENTRY_NODE)) - return -1; - - ntfs_log_trace ("\n"); - return *((VCN*) ((u8*) ie + ie->length - 8)); -} - -/** - * ntfs_ie_copy - Create a copy of an index entry - * @ie: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_copy(INDEX_ENTRY *ie) -{ - INDEX_ENTRY *copy = NULL; - - if (!ie) - return NULL; - - ntfs_log_trace ("\n"); - copy = malloc(ie->length); - if (!copy) - return NULL; - memcpy(copy, ie, ie->length); - - return copy; -} - -/** - * ntfs_ie_set_vcn - Set VCN associated with an index entry - * @ie: - * @vcn: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) -{ - if (!ie) - return 0; - - ntfs_log_trace ("\n"); - if (!(ie->flags & INDEX_ENTRY_NODE)) { - ie->length += 8; - ie = realloc(ie, ie->length); - if (!ie) - return NULL; - - ie->flags |= INDEX_ENTRY_NODE; - } - - *((VCN*) ((u8*) ie + ie->length - 8)) = vcn; - return ie; -} - -/** - * ntfs_ie_remove_vcn - Remove the VCN associated with an index entry - * @ie: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_remove_vcn(INDEX_ENTRY *ie) -{ - if (!ie) - return NULL; - if (!(ie->flags & INDEX_ENTRY_NODE)) - return ie; - - ntfs_log_trace ("\n"); - ie->length -= 8; - ie->flags &= ~INDEX_ENTRY_NODE; - ie = realloc(ie, ie->length); - return ie; -} - -/** - * ntfs_ie_set_name - Associate a name with an index entry - * @ie: - * @name: - * @namelen: - * @nametype: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_set_name(INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype) -{ - FILE_NAME_ATTR *file; - int need; - BOOL wipe = FALSE; - VCN vcn = 0; - - if (!ie || !name) - return NULL; - - ntfs_log_trace ("\n"); - /* - * INDEX_ENTRY - * MFT_REF indexed_file; - * u16 length; - * u16 key_length; - * INDEX_ENTRY_FLAGS flags; - * u16 reserved; - * - * FILENAME - * MFT_REF parent_directory; - * s64 creation_time; - * s64 last_data_change_time; - * s64 last_mft_change_time; - * s64 last_access_time; - * s64 allocated_size; - * s64 data_size; - * FILE_ATTR_FLAGS file_attributes; - * u32 reserved; - * u8 file_name_length; - * FILE_NAME_TYPE_FLAGS file_name_type; - * ntfschar file_name[l]; - * u8 reserved[n] - * - * VCN vcn; - */ - - //ntfs_log_debug("key length = 0x%02X\n", ie->key_length); - //ntfs_log_debug("new name length = %d\n", namelen); - if (ie->key_length > 0) { - file = &ie->key.file_name; - //ntfs_log_debug("filename, length %d\n", file->file_name_length); - need = ATTR_SIZE(namelen * sizeof(ntfschar) + 2) - - ATTR_SIZE(file->file_name_length * sizeof(ntfschar) + 2); - } else { - //ntfs_log_debug("no filename\n"); - need = ATTR_SIZE(sizeof(FILE_NAME_ATTR) + (namelen * sizeof(ntfschar))); - wipe = TRUE; - } - - //ntfs_log_debug("need 0x%02X bytes\n", need); - - if (need != 0) { - if (ie->flags & INDEX_ENTRY_NODE) - vcn = ntfs_ie_get_vcn(ie); - - ie->length += need; - ie->key_length += need; - - //ntfs_log_debug("realloc 0x%02X\n", ie->length); - ie = realloc(ie, ie->length); - if (!ie) - return NULL; - - if (ie->flags & INDEX_ENTRY_NODE) - ie = ntfs_ie_set_vcn(ie, vcn); - - if (wipe) - memset(&ie->key.file_name, 0, sizeof(FILE_NAME_ATTR)); - if (need > 0) - memset((u8*)ie + ie->length - need, 0, need); - } - - memcpy(ie->key.file_name.file_name, name, namelen * sizeof(ntfschar)); - - ie->key.file_name.file_name_length = namelen; - ie->key.file_name.file_name_type = nametype; - ie->flags &= ~INDEX_ENTRY_END; - - //ntfs_log_debug("ie->length = 0x%02X\n", ie->length); - //ntfs_log_debug("ie->key_length = 0x%02X\n", ie->key_length); - - return ie; -} - -/** - * ntfs_ie_remove_name - Remove the name from an index-entry - * @ie: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_ie_remove_name(INDEX_ENTRY *ie) -{ - VCN vcn = 0; - - if (!ie) - return NULL; - if (ie->key_length == 0) - return ie; - - ntfs_log_trace ("\n"); - if (ie->flags & INDEX_ENTRY_NODE) - vcn = ntfs_ie_get_vcn(ie); - - ie->length -= ATTR_SIZE(ie->key_length); - ie->key_length = 0; - ie->flags |= INDEX_ENTRY_END; - - ie = realloc(ie, ie->length); - if (!ie) - return NULL; - - if (ie->flags & INDEX_ENTRY_NODE) - ie = ntfs_ie_set_vcn(ie, vcn); - return ie; -} - - -#endif /* NTFS_RICH */ - /** * ntfs_index_root_get - read the index root of an attribute * @ni: open ntfs inode in which the ntfs attribute resides @@ -979,4 +705,3 @@ out: return root; } - diff --git a/libntfs/inode.c b/libntfs/inode.c index 2fef1f6a..fbfaa1f1 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -1149,140 +1149,3 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) return ret; } -#ifdef NTFS_RICH - -#include "rich.h" - -/** - * ntfs_inode_close2 - Close an inode, freeing any resources - * @ni: - * - * Description... - * - * Returns: - */ -int ntfs_inode_close2(ntfs_inode *ni) -{ - if (!ni) - return 0; - - ntfs_log_trace ("inode %p, mft %lld, refcount %d\n", ni, MREF(ni->mft_no), ni->ref_count); - - ni->ref_count--; - if (ni->ref_count > 0) - return 0; - - // unlink - // ino->private_data - - // XXX temporary until we have commit/rollback - NInoClearDirty(ni); - - return ntfs_inode_close(ni); -} - -/** - * ntfs_inode_open2 - Open an inode and initialise it - * @vol: - * @mref: - * - * Description... - * - * Returns: - */ -ntfs_inode * ntfs_inode_open2(ntfs_volume *vol, const MFT_REF mref) -{ - ntfs_inode *ino = NULL; - struct ntfs_dir *dir; - - if (!vol) - return NULL; - - ntfs_log_trace ("\n"); - switch (mref) { - case FILE_Bitmap: ino = vol->lcnbmp_ni; break; - case FILE_MFT: ino = vol->mft_ni; break; - case FILE_MFTMirr: ino = vol->mftmirr_ni; break; - case FILE_Volume: ino = vol->vol_ni; break; - case FILE_root: - dir = vol->private_data; - if (dir) - ino = dir->inode; - break; - } - - if (ino) { - ntfs_log_debug("inode reuse %lld\n", mref); - ino->ref_count++; - return ino; - } - - ino = ntfs_inode_open(vol, mref); - if (!ino) - return NULL; - - /* - if (mref != FILE_root) - ntfs_inode_dir_map (ino); - */ - - // link - // ino->private_data - - ino->private_data = NULL; - ino->ref_count = 1; - - ntfs_log_debug("inode open %lld, 0x%llx\n", MREF(mref), mref); - return ino; -} - -/** - * ntfs_inode_open3 - Open an inode and initialise it - * @vol: - * @mref: - * - * Description... - * - * Returns: - */ -ntfs_inode * ntfs_inode_open3(ntfs_volume *vol, const MFT_REF mref) -{ - ntfs_inode *ino = NULL; - - if (!vol) - return NULL; - - ntfs_log_trace ("\n"); - ino = calloc(1, sizeof(*ino)); - if (!ino) - return NULL; - - ino->mrec = malloc(vol->mft_record_size); - if (!ino->mrec) { - free(ino); - return NULL; - } - - ino->mft_no = mref; - ino->vol = vol; - - ino->data_size = -1; - ino->allocated_size = -1; - - ino->private_data = NULL; - ino->ref_count = 1; - - if (1 != ntfs_attr_mst_pread(vol->mft_na, MREF(mref) * vol->mft_record_size, 1, vol->mft_record_size, ino->mrec)) { - //ntfs_inode_close2(ino); ??? - free(ino->mrec); - free(ino); - return NULL; - } - - NInoSetDirty(ino); - return ino; -} - - -#endif /* NTFS_RICH */ - diff --git a/libntfs/mft.c b/libntfs/mft.c index 302784bc..bc3be080 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -1555,386 +1555,6 @@ sync_rollback: return -1; } - -#ifdef NTFS_RICH - -#include "bitmap.h" -#include "dir.h" -#include "tree.h" -#include "index.h" -#include "rich.h" - -/** - * ntfs_mft_remove_attr - Remove an attribute from an MFT record - * @bmp: - * @inode: - * @type: - * - * Description... - * - * Returns: - */ -int ntfs_mft_remove_attr(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type) -{ - ATTR_RECORD *attr20, *attrXX; - MFT_RECORD *mft; - u8 *src, *dst; - int len; - - if (!inode) - return 1; - - ntfs_log_trace ("\n"); - attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, inode->mrec); - if (attr20) - return 1; - - ntfs_log_debug("remove inode %lld, attr 0x%02X\n", inode->mft_no, type); - - attrXX = find_first_attribute(type, inode->mrec); - if (!attrXX) - return 1; - - if (utils_free_non_residents3(bmp, inode, attrXX)) - return 1; - - // remove entry - // inode->mrec - - mft = inode->mrec; - //utils_dump_mem(mft, 0, mft->bytes_in_use, DM_DEFAULTS); ntfs_log_debug("\n"); - - //utils_dump_mem(attrXX, 0, attrXX->length, DM_DEFAULTS); ntfs_log_debug("\n"); - - //ntfs_log_debug("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft); - // memmove - - dst = (u8*) attrXX; - src = dst + attrXX->length; - len = (((u8*) mft + mft->bytes_in_use) - src); - - // fix mft header - mft->bytes_in_use -= attrXX->length; - -#if 0 - ntfs_log_debug("dst = 0x%02X, src = 0x%02X, len = 0x%02X\n", (dst - (u8*)mft), (src - (u8*)mft), len); - ntfs_log_debug("attr %02X, len = 0x%02X\n", attrXX->type, attrXX->length); - ntfs_log_debug("bytes in use = 0x%02X\n", mft->bytes_in_use); - ntfs_log_debug("\n"); -#endif - - memmove(dst, src, len); - //utils_dump_mem(mft, 0, mft->bytes_in_use, DM_DEFAULTS); ntfs_log_debug("\n"); - - NInoSetDirty(inode); - return 0; -} - -/** - * ntfs_mft_add_attr - Add an attribute to an MFT record - * @inode: - * @type: - * @data: - * @data_len: - * - * Description... - * - * Returns: - */ -ATTR_RECORD * ntfs_mft_add_attr(ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len) -{ - MFT_RECORD *mrec; - ATTR_RECORD *attr; - u8 *ptr; - u8 *src; - u8 *dst; - int len; - int attr_size; - - if (!inode) - return NULL; - if (!data) - return NULL; - - ntfs_log_trace ("inode %p, mft %lld, attr 0x%02x, len %d\n", inode, inode->mft_no, type, data_len); - attr_size = ATTR_SIZE(data_len); - - mrec = inode->mrec; - if (!mrec) - return NULL; - - if ((mrec->bytes_in_use + attr_size + 0x18) > mrec->bytes_allocated) { - ntfs_log_debug("attribute is too big to fit in the record\n"); - return NULL; - } - - ptr = (u8*) inode->mrec + mrec->attrs_offset; - while (1) { - attr = (ATTR_RECORD*) ptr; - - if (type < attr->type) - break; - - ptr += attr->length; - } - - //ntfs_log_debug("insert before attr 0x%02X\n", attr->type); - - len = ((u8*) mrec + mrec->bytes_in_use) - ((u8*) attr); - src = (u8*) attr; - dst = src + attr_size + 0x18; - - memmove(dst, src, len); - - src = data; - dst = (u8*) attr + 0x18; - len = data_len; - - // XXX wipe slack space after attr? - - memcpy(dst, src, len); - - mrec->bytes_in_use += attr_size + 0x18; - - memset(attr, 0, 0x18); - *(u32*)((u8*) attr + 0x00) = type; - *(u32*)((u8*) attr + 0x04) = attr_size + 0x18; - *(u16*)((u8*) attr + 0x0E) = mrec->next_attr_instance; - *(u32*)((u8*) attr + 0x10) = data_len; - *(u32*)((u8*) attr + 0x14) = 0x18; - - mrec->next_attr_instance++; - - return attr; -} - -/** - * ntfs_mft_resize_resident - Resize a resident attribute in an MFT record - * @inode: - * @type: - * @name: - * @name_len: - * @data: - * @data_len: - * - * Description... - * - * Returns: - */ -int ntfs_mft_resize_resident(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len) -{ - int mft_size; - int mft_usage; - int mft_free; - int attr_orig; - int attr_new; - u8 *src; - u8 *dst; - u8 *end; - int len; - ntfs_attr_search_ctx *ctx = NULL; - ATTR_RECORD *arec = NULL; - MFT_RECORD *mrec = NULL; - int res = -1; - - ntfs_log_trace ("\n"); - // XXX only works when attr is in base inode - - if ((!inode) || (!inode->mrec)) - return -1; - if ((!data) || (data_len < 0)) - return -1; - - mrec = inode->mrec; - ntfs_log_debug("inode = %lld\n", MREF(inode->mft_no)); - //utils_dump_mem(mrec, 0, 1024, DM_DEFAULTS); - - mft_size = mrec->bytes_allocated; - mft_usage = mrec->bytes_in_use; - mft_free = mft_size - mft_usage; - - //ntfs_log_debug("mft_size = %d\n", mft_size); - //ntfs_log_debug("mft_usage = %d\n", mft_usage); - //ntfs_log_debug("mft_free = %d\n", mft_free); - //ntfs_log_debug("\n"); - - ctx = ntfs_attr_get_search_ctx(inode, NULL); - if (!ctx) - goto done; - - ntfs_name_print(name, name_len); - ntfs_log_debug(" type = 0x%02x\n", type); - if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0) - goto done; - - arec = ctx->attr; - - if (arec->non_resident) { - ntfs_log_debug("attribute isn't resident\n"); - goto done; - } - - attr_orig = arec->value_length; - attr_new = data_len; - - ntfs_log_debug("attr orig = %d\n", attr_orig); - ntfs_log_debug("attr new = %d\n", attr_new); - //ntfs_log_debug("\n"); - - if ((attr_new - attr_orig + mft_usage) > mft_size) { - ntfs_log_debug("attribute won't fit into mft record\n"); - goto done; - } - - //ntfs_log_debug("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage)); - - src = (u8*)arec + arec->length; - dst = src + (attr_new - attr_orig); - end = (u8*)mrec + mft_usage; - len = end - src; - - //ntfs_log_debug("src = %d\n", src - (u8*)mrec); - //ntfs_log_debug("dst = %d\n", dst - (u8*)mrec); - //ntfs_log_debug("end = %d\n", end - (u8*)mrec); - //ntfs_log_debug("len = %d\n", len); - - if (src != dst) - memmove(dst, src, len); - - memcpy((u8*)arec + arec->value_offset, data, data_len); - - mrec->bytes_in_use += (attr_new - attr_orig); - arec->length += (attr_new - attr_orig); - arec->value_length += (attr_new - attr_orig); - - memset((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use); - - mft_usage += (attr_new - attr_orig); - //utils_dump_mem(mrec, 0, mft_size, DM_DEFAULTS); - res = 0; -done: - ntfs_attr_put_search_ctx(ctx); - return res; -} - -/** - * ntfs_mft_free_space - Calculate the free space (bytes) in an MFT record - * @dir: - * - * Description... - * - * Returns: - */ -int ntfs_mft_free_space(struct ntfs_dir *dir) -{ - int res = 0; - MFT_RECORD *mft; - - if ((!dir) || (!dir->inode)) - return -1; - - ntfs_log_trace ("\n"); - mft = (MFT_RECORD*) dir->inode->mrec; - - res = mft->bytes_allocated - mft->bytes_in_use; - - return res; -} - -/** - * ntfs_mft_add_index - Add an index (directory) to an MFT record - * @dir: - * - * Description... - * - * Returns: - */ -int ntfs_mft_add_index(struct ntfs_dir *dir) -{ - ntfs_volume *vol; - u8 *buffer = NULL; - ATTR_RECORD *attr = NULL; - struct ntfs_dt *dt = NULL; - INDEX_ENTRY *ie = NULL; - - if (!dir) - return 1; - if (dir->bitmap && dir->ialloc) - return 0; - if (dir->bitmap || dir->ialloc) - return 1; - if (dir->index_size < 512) - return 1; - - ntfs_log_trace ("\n"); - vol = dir->vol; - ntfs_log_debug("add two attrs to "); ntfs_name_print(dir->name, dir->name_len); ntfs_log_debug("\n"); - ntfs_log_debug("index size = %d\n", dir->index_size); - - buffer = malloc(dir->index_size); - if (!buffer) - return 1; - - dt = ntfs_dt_create(dir, dir->index, -1); - if (!dt) - return 1; - - dt->vcn = 0; // New alloc record - - ie = ntfs_ie_copy(dir->index->children[dir->index->child_count-1]); - ie = ntfs_ie_set_vcn(ie, dt->vcn); - - // can't replace ie yet, there may not be room - ntfs_ie_free(ie); - - ntfs_dt_transfer2(dir->index, dt, 0, dir->index->child_count - 1); - - ntfs_log_debug("root has %d children\n", dir->index->child_count); - ntfs_log_debug("node has %d children\n", dt->child_count); - - ntfs_dt_free(dt); - - // create a new dt - // attach dt to dir - // move entries into alloc - // shrink root - - // transfer keys to new node - // hook up root & alloc dts - - // need disk allocation before here - - // Index Allocation - memset(buffer, 0, 128); - attr = ntfs_mft_add_attr(dir->inode, AT_INDEX_ALLOCATION, buffer, 0x48); - - // Bitmap - memset(buffer, 0, 8); - buffer[0] = 0x01; - //ntfs_log_debug("inode = %p\n", dir->inode); - attr = ntfs_mft_add_attr(dir->inode, AT_BITMAP, buffer, 8); - - // attach alloc and bitmap to dir - // need to create ntfs_attr's for them - - // one indx record - // 8 bits of bitmap - - if (0) ntfs_bmp_find_space(NULL, 0, 0); - - //ntfs_log_debug("m1 = %lld\n", vol->mft_zone_start); - //ntfs_log_debug("m2 = %lld\n", vol->mft_zone_end); - //ntfs_log_debug("m3 = %lld\n", vol->mft_zone_pos); - //ntfs_log_debug("z1 = %lld\n", vol->data1_zone_pos); - //ntfs_log_debug("z2 = %lld\n", vol->data2_zone_pos); - - free(buffer); - return 0; -} - - -#endif /* NTFS_RICH */ - /** * ntfs_mft_usn_dec - Decrement USN by one * @mrec: pointer to an mft record diff --git a/libntfs/volume.c b/libntfs/volume.c index 9477a9cd..4b809dd5 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -1534,368 +1534,3 @@ err_out: return ret; } - -#ifdef NTFS_RICH - -#include "tree.h" -#include "rich.h" - -/** - * utils_valid_device - Perform some safety checks on the device before we start - * @name: Full pathname of the device/file to work with - * @force: Continue regardless of problems - * - * Check that the name refers to a device and that is isn't already mounted. - * These checks can be overridden by using the force option. - * - * Return: 1 Success, we can continue - * 0 Error, we cannot use this device - */ -int utils_valid_device(const char *name, int force) -{ - unsigned long mnt_flags = 0; - struct stat st; - -#ifdef __CYGWIN32__ - /* FIXME: This doesn't work for Cygwin, so just return success for now... */ - return 1; -#endif - if (!name) { - errno = EINVAL; - return 0; - } - ntfs_log_trace ("\n"); - - if (stat(name, &st) == -1) { - if (errno == ENOENT) { - ntfs_log_error("The device %s doesn't exist\n", name); - } else { - ntfs_log_perror("Error getting information about %s", name); - } - return 0; - } - - if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) { - ntfs_log_warning("%s is not a block device, " - "nor regular file.\n", name); - if (!force) { - ntfs_log_error("Use the force option to work with other" - " file types, for your own risk!\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } - - /* Make sure the file system is not mounted. */ - if (ntfs_check_if_mounted(name, &mnt_flags)) { - ntfs_log_perror("Failed to determine whether %s is mounted", name); - if (!force) { - ntfs_log_error("Use the force option to ignore this error.\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } else if (mnt_flags & NTFS_MF_MOUNTED) { - ntfs_log_warning("The device %s, is mounted.\n", name); - if (!force) { - ntfs_log_error("Use the force option to work a mounted filesystem.\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } - - return 1; -} - -/** - * utils_mount_volume - Mount an NTFS volume - * @device: - * @flags: - * @force: - * - * Description... - * - * Returns: - */ -ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force) -{ - ntfs_volume *vol; - - if (!device) { - errno = EINVAL; - return NULL; - } - ntfs_log_trace ("\n"); - - if (!utils_valid_device(device, force)) - return NULL; - - vol = ntfs_mount(device, flags); - if (!vol) { - int err; - - err = errno; - ntfs_log_perror("Couldn't mount device '%s'", device); - if (err == EPERM) - ntfs_log_error("Windows was hibernated. Try to mount " - "volume in windows, shut down and try " - "again.\n"); - if (err == EOPNOTSUPP) - ntfs_log_error("Windows did not shut down properly. " - "Try to mount volume in windows, " - "shut down and try again.\n"); - return NULL; - } - - if (vol->flags & VOLUME_IS_DIRTY) { - ntfs_log_warning("Volume is dirty.\n"); - if (!force) { - ntfs_log_error("Run chkdsk and try again, or use the " - "force option.\n"); - ntfs_umount(vol, FALSE); - return NULL; - } - ntfs_log_quiet("Forced to continue.\n"); - } - - return vol; -} - -/** - * ntfs_volume_commit - Write to disk the in-memory volume changes - * @vol: - * - * Description... - * - * Returns: - */ -int ntfs_volume_commit(ntfs_volume *vol) -{ - if (!vol) - return -1; - - ntfs_log_trace ("\n"); - ntfs_log_debug("commit volume\n"); - if (ntfs_bmp_commit(vol->private_bmp1) < 0) - return -1; - - if (ntfs_bmp_commit(vol->private_bmp2) < 0) - return -1; - - if (ntfs_dir_commit(vol->private_data) < 0) - return -1; - - return 0; -} - -/** - * ntfs_volume_rollback - Discard the in-memory volume changes - * @vol: - * - * Description... - * - * Returns: - */ -int ntfs_volume_rollback(ntfs_volume *vol) -{ - if (!vol) - return -1; - ntfs_log_trace ("\n"); - - if (ntfs_bmp_rollback(vol->private_bmp1) < 0) - return -1; - - if (ntfs_bmp_rollback(vol->private_bmp2) < 0) - return -1; - - if (ntfs_dir_rollback(vol->private_data) < 0) - return -1; - - return 0; -} - -/** - * ntfs_volume_umount2 - Unmount an NTFS volume, using the new directory support - * @vol: - * @force: - * - * Description... - * - * Returns: - */ -int ntfs_volume_umount2(ntfs_volume *vol, const BOOL force) -{ - struct ntfs_dir *dir; - struct ntfs_bmp *bmp; - - if (!vol) - return 0; - ntfs_log_trace ("\n"); - - ntfs_volume_rollback(vol); - - dir = (struct ntfs_dir *) vol->private_data; - vol->private_data = NULL; - ntfs_dir_free(dir); - - bmp = (struct ntfs_bmp *) vol->private_bmp1; - vol->private_bmp1 = NULL; - ntfs_bmp_free(bmp); - - bmp = (struct ntfs_bmp *) vol->private_bmp2; - vol->private_bmp2 = NULL; - ntfs_bmp_free(bmp); - - return ntfs_umount(vol, force); -} - -/** - * ntfs_volume_mount2 - Mount an NTFS volume, using the new directory support - * @device: - * @flags: - * @force: - * - * Description... - * - * Returns: - */ -ntfs_volume * ntfs_volume_mount2(const char *device, unsigned long flags, BOOL force) -{ - // XXX can we replace these and search by mft number? Hmm... NO. - // unless I have a recursive search for an MFT number - static ntfschar bmp[8] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('B'), - const_cpu_to_le16('i'), - const_cpu_to_le16('t'), - const_cpu_to_le16('m'), - const_cpu_to_le16('a'), - const_cpu_to_le16('p'), - const_cpu_to_le16(0) - }; - - static ntfschar mft[5] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('M'), - const_cpu_to_le16('F'), - const_cpu_to_le16('T'), - const_cpu_to_le16(0) - }; - - static ntfschar mftmirr[9] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('M'), - const_cpu_to_le16('F'), - const_cpu_to_le16('T'), - const_cpu_to_le16('M'), - const_cpu_to_le16('i'), - const_cpu_to_le16('r'), - const_cpu_to_le16('r'), - const_cpu_to_le16(0) - }; - - static ntfschar dot[2] = { - const_cpu_to_le16('.'), - const_cpu_to_le16(0) - }; - - ntfs_volume *vol; - struct ntfs_dir *dir; - struct ntfs_dt *root; - struct ntfs_dt *found; - int num; - - ntfs_log_trace ("\n"); - vol = utils_mount_volume(device, flags, force); - if (!vol) - return NULL; - - vol->lcnbmp_ni ->ref_count = 1; - vol->mft_ni ->ref_count = 1; - vol->mftmirr_ni->ref_count = 1; - - vol->lcnbmp_ni ->private_data = NULL; - vol->mft_ni ->private_data = NULL; - vol->mftmirr_ni->private_data = NULL; - - dir = ntfs_dir_create(vol, FILE_root); - if (!dir) { - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - - dir->index = ntfs_dt_create(dir, NULL, -1); - - root = dir->index; - - //$Bitmap - num = -1; - found = ntfs_dt_find2(root, bmp, (sizeof(bmp)/sizeof(ntfschar)) - 1, &num); - if ((!found) || (num < 0)) { - ntfs_log_debug("can't find $Bitmap\n"); - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - vol->lcnbmp_ni->ref_count++; - vol->lcnbmp_ni->private_data = found->dir; - found->inodes[num] = vol->lcnbmp_ni; - - //$MFT - num = -1; - found = ntfs_dt_find2(root, mft, (sizeof(mft)/sizeof(ntfschar)) - 1, &num); - if ((!found) || (num < 0)) { - ntfs_log_debug("can't find $MFT\n"); - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - vol->mft_ni->ref_count++; - vol->mft_ni->private_data = found->dir; - found->inodes[num] = vol->mft_ni; - - //$MFTMirr - num = -1; - found = ntfs_dt_find2(root, mftmirr, (sizeof(mftmirr)/sizeof(ntfschar)) - 1, &num); - if ((!found) || (num < 0)) { - ntfs_log_debug("can't find $MFTMirr\n"); - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - vol->mftmirr_ni->ref_count++; - vol->mftmirr_ni->private_data = found->dir; - found->inodes[num] = vol->mftmirr_ni; - - // root directory - num = -1; - found = ntfs_dt_find2(root, dot, (sizeof(dot)/sizeof(ntfschar)) - 1, &num); - if ((!found) || (num < 0)) { - ntfs_log_debug("can't find the root directory\n"); - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - - vol->private_data = found->dir; - found->inodes[num] = dir->inode; - dir->inode->private_data = found; - dir->inode->ref_count = 2; - - vol->private_bmp1 = ntfs_bmp_create(vol->mft_ni, AT_BITMAP, NULL, 0); - vol->private_bmp2 = ntfs_bmp_create(vol->lcnbmp_ni, AT_DATA, NULL, 0); - - if (!vol->private_bmp1 || !vol->private_bmp2) { - ntfs_log_debug("can't find the bitmaps\n"); - ntfs_volume_umount2(vol, FALSE); - vol = NULL; - goto done; - } - -done: - return vol; -} - - -#endif /* NTFS_RICH */ - diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 758cd104..5dbfb972 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -37,10 +37,6 @@ if ENABLE_CRYPTO EXTRA_PROGRAMS += ntfsdecrypt endif -if ENABLE_RICH -EXTRA_PROGRAMS += ntfsrm -endif - # Set the include path. AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs $(all_includes) @@ -101,12 +97,6 @@ ntfscmp_LDFLAGS = $(AM_LFLAGS) # We don't distribute these -if ENABLE_RICH -ntfsrm_SOURCES = ntfsrm.c ntfsrm.h utils.c utils.h -ntfsrm_LDADD = $(AM_LIBS) -ntfsrm_LDFLAGS = $(AM_LFLAGS) -endif - ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h ntfstruncate_LDADD = $(AM_LIBS) ntfstruncate_LDFLAGS = $(AM_LFLAGS) diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index ef432de4..64293596 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -98,7 +98,6 @@ int utils_set_locale(void) } } -#ifndef NTFS_RICH /** * utils_valid_device - Perform some safety checks on the device, before we start * @name: Full pathname of the device/file to work with @@ -210,8 +209,6 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL f return vol; } -#endif - /** * utils_parse_size - Convert a string representing a size * @value: String to be parsed @@ -333,7 +330,6 @@ int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale) return 1; } -#ifndef NTFS_RICH /** * find_attribute - Find an attribute of the given type * @type: An attribute type, e.g. AT_FILE_NAME @@ -403,7 +399,6 @@ ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft) return rec; } -#endif /** * utils_inode_get_name * diff --git a/ntfsprogs/utils.h b/ntfsprogs/utils.h index 480b03d0..02712c82 100644 --- a/ntfsprogs/utils.h +++ b/ntfsprogs/utils.h @@ -52,15 +52,11 @@ int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref); int utils_is_metadata(ntfs_inode *inode); void utils_dump_mem(void *buf, int start, int length, int flags); -#ifndef _NTFS_RICH_H_ ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft); -#endif -#if !(defined(_NTFS_VOLUME_H) && defined(NTFS_RICH)) int utils_valid_device(const char *name, int force); ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force); -#endif /** * defines... From 0d9446016975098e33d618a6e37a6477108dabd6 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 17 Jul 2006 11:55:29 +0000 Subject: [PATCH 006/289] be bit more verbose --- libntfs/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libntfs/dir.c b/libntfs/dir.c index 6eb6d082..a7ea2a25 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1530,6 +1530,8 @@ search: ntfs_attr_reinit_search_ctx(actx); goto search; } + ntfs_log_error("Failed to find requested filename in FILE_NAME " + "attributes that belong to this inode.\n"); goto err_out; } /* If deleting directory check it to be empty. */ From 9efb57918f2e897dd5b5edbfe0727ca64bc8c6ce Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 21 Jul 2006 22:04:44 +0000 Subject: [PATCH 007/289] Fix a logic error that made 'ls -ls' show the wrong file size for compressed and sparse files. --- libntfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libntfs/inode.c b/libntfs/inode.c index fbfaa1f1..c199bf80 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -200,7 +200,7 @@ get_size: if (ctx->attr->non_resident) { ni->data_size = sle64_to_cpu(ctx->attr->data_size); if (ctx->attr->flags & - (ATTR_IS_COMPRESSED & ATTR_IS_SPARSE)) + (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ni->allocated_size = sle64_to_cpu( ctx->attr->compressed_size); else From a1a13da74a917a536dbe96697116c9735ca24250 Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 21 Jul 2006 23:03:59 +0000 Subject: [PATCH 008/289] Commit mft extensions right away. Don't wait for a clean unmount, or you may face data loss. --- libntfs/mft.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libntfs/mft.c b/libntfs/mft.c index bc3be080..4c266b25 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -1356,8 +1356,11 @@ found_free_rec: if (mft_na->data_size > mft_na->allocated_size || mft_na->initialized_size > mft_na->data_size) NTFS_BUG("mft_na sanity checks failed"); - // BUG_ON(mft_na->initialized_size > mft_na->data_size); - // BUG_ON(mft_na->data_size > mft_na->allocated_size); + /* Sync MFT to disk now in order to minimize data-loss. */ + if (ntfs_inode_sync(mft_na->ni)) { + ntfs_log_debug("mft sync after extension failed. rolling back."); + goto undo_data_init; + } mft_rec_already_initialized: /* * We now have allocated and initialized the mft record. Need to read From ae37e54d8c2f8d7c4a713d33b7a4a7e186d4365b Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 21 Jul 2006 23:16:09 +0000 Subject: [PATCH 009/289] Avoid a double-free error. ntfs_empty_logfile() has no reason to close na/ni anyway, and is only called from ntfs_logfile_reset() which already closes them, so these lines can be safely removed. --- libntfs/logfile.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libntfs/logfile.c b/libntfs/logfile.c index a429ce68..a3bd1ab0 100644 --- a/libntfs/logfile.c +++ b/libntfs/logfile.c @@ -768,8 +768,6 @@ done: ntfs_log_trace("Done.\n"); return 0; io_error_exit: - ntfs_attr_close(na); - ntfs_inode_close(na->ni); errno = err; return -1; } From a3a318a8b4d21641f868526f05f61f1f41bc9dcc Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 22 Jul 2006 19:39:59 +0000 Subject: [PATCH 010/289] forgot "cvs delete" --- include/ntfs/rich.h | 38 - include/ntfs/tree.h | 82 -- libntfs/rich.c | 215 ---- libntfs/tree.c | 2366 ------------------------------------------- 4 files changed, 2701 deletions(-) delete mode 100644 include/ntfs/rich.h delete mode 100644 include/ntfs/tree.h delete mode 100644 libntfs/rich.c delete mode 100644 libntfs/tree.c diff --git a/include/ntfs/rich.h b/include/ntfs/rich.h deleted file mode 100644 index c0cb85b7..00000000 --- a/include/ntfs/rich.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * rich.h - Temporary junk file. Part of the Linux-NTFS project. - * - * Copyright (c) 2004-2005 Richard Russon - * - * This program/include file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program/include file is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS - * distribution in the file COPYING); if not, write to the Free Software - * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _NTFS_RICH_H_ -#define _NTFS_RICH_H_ - -#include "layout.h" -#include "attrib.h" -#include "bitmap.h" - -#define ATTR_SIZE(s) ROUND_UP(s, 3) - -ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); -ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft); -int utils_free_non_residents3(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr); -int utils_free_non_residents2(ntfs_inode *inode, struct ntfs_bmp *bmp); -void ntfs_name_print(ntfschar *name, int name_len); - -#endif /* _NTFS_RICH_H_ */ - diff --git a/include/ntfs/tree.h b/include/ntfs/tree.h deleted file mode 100644 index 4e2745c4..00000000 --- a/include/ntfs/tree.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * tree.h - Directory tree handling code. Part of the Linux-NTFS project. - * - * Copyright (c) 2004-2005 Richard Russon - * - * This program/include file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program/include file is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS - * distribution in the file COPYING); if not, write to the Free Software - * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _NTFS_TREE_H_ -#define _NTFS_TREE_H_ - -#include "layout.h" -#include "volume.h" - -struct ntfs_dir; - -/** - * struct ntfs_dt - - */ -struct ntfs_dt { - struct ntfs_dir *dir; - struct ntfs_dt *parent; - u8 *data; - int data_len; - int child_count; - INDEX_ENTRY **children; - struct ntfs_dt **sub_nodes; - ntfs_inode **inodes; - VCN vcn; - INDEX_HEADER *header; - BOOL changed; -}; - - -void ntfs_dt_free(struct ntfs_dt *dt); -int ntfs_dt_rollback(struct ntfs_dt *dt); -int ntfs_dt_commit(struct ntfs_dt *dt); -BOOL ntfs_dt_create_children2(struct ntfs_dt *dt, int count); -BOOL ntfs_dt_resize_children3(struct ntfs_dt *dt, int new); -int ntfs_dt_root_count(struct ntfs_dt *dt); -int ntfs_dt_alloc_count(struct ntfs_dt *dt); -int ntfs_dt_initialise2(ntfs_volume *vol, struct ntfs_dt *dt); -struct ntfs_dt * ntfs_dt_create(struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn); -MFT_REF ntfs_dt_find(struct ntfs_dt *dt, ntfschar *name, int name_len); -struct ntfs_dt * ntfs_dt_find2(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); -struct ntfs_dt * ntfs_dt_find3(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); -struct ntfs_dt * ntfs_dt_find4(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); -void ntfs_dt_find_all(struct ntfs_dt *dt); -int ntfs_dt_find_parent(struct ntfs_dt *dt); -BOOL ntfs_dt_isroot(struct ntfs_dt *dt); -int ntfs_dt_root_freespace(struct ntfs_dt *dt); -int ntfs_dt_alloc_freespace(struct ntfs_dt *dt); -int ntfs_dt_transfer(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count); -int ntfs_dt_alloc_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count); -INDEX_ENTRY * ntfs_dt_alloc_insert2(struct ntfs_dt *dt, int before, int count, int bytes); -int ntfs_dt_root_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count); -int ntfs_dt_alloc_remove2(struct ntfs_dt *dt, int start, int count); -int ntfs_dt_root_remove2(struct ntfs_dt *dt, int start, int count); -int ntfs_dt_transfer2(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count); -int ntfs_dt_root_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie); -BOOL ntfs_dt_alloc_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie); -BOOL ntfs_dt_root_remove(struct ntfs_dt *del, int del_num); -BOOL ntfs_dt_alloc_remove(struct ntfs_dt *del, int del_num); -int ntfs_dt_alloc_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child); -int ntfs_dt_root_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child); -int ntfs_dt_add2(INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded); - -#endif /* _NTFS_TREE_H_ */ - diff --git a/libntfs/rich.c b/libntfs/rich.c deleted file mode 100644 index 1921e9dc..00000000 --- a/libntfs/rich.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * rich.c - Temporary junk file. Part of the Linux-NTFS project. - * - * Copyright (c) 2004-2005 Richard Russon - * - * This program/include file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program/include file is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS - * distribution in the file COPYING); if not, write to the Free Software - * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef NTFS_RICH - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif - -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "rich.h" -#include "layout.h" -#include "logging.h" - -/** - * find_attribute - Find an attribute of the given type - * @type: An attribute type, e.g. AT_FILE_NAME - * @ctx: A search context, created using ntfs_get_attr_search_ctx - * - * Using the search context to keep track, find the first/next occurrence of a - * given attribute type. - * - * N.B. This will return a pointer into @mft. As long as the search context - * has been created without an inode, it won't overflow the buffer. - * - * Return: Pointer Success, an attribute was found - * NULL Error, no matching attributes were found - */ -ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) -{ - if (!ctx) { - errno = EINVAL; - return NULL; - } - - ntfs_log_trace ("\n"); - if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) { - ntfs_log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type); - return NULL; /* None / no more of that type */ - } - - ntfs_log_debug("find_attribute found an attribute of type: 0x%02x.\n", type); - return ctx->attr; -} - -/** - * find_first_attribute - Find the first attribute of a given type - * @type: An attribute type, e.g. AT_FILE_NAME - * @mft: A buffer containing a raw MFT record - * - * Search through a raw MFT record for an attribute of a given type. - * The return value is a pointer into the MFT record that was supplied. - * - * N.B. This will return a pointer into @mft. The pointer won't stray outside - * the buffer, since we created the search context without an inode. - * - * Return: Pointer Success, an attribute was found - * NULL Error, no matching attributes were found - */ -ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft) -{ - ntfs_attr_search_ctx *ctx; - ATTR_RECORD *rec; - - if (!mft) { - errno = EINVAL; - return NULL; - } - - ntfs_log_trace ("\n"); - ctx = ntfs_attr_get_search_ctx(NULL, mft); - if (!ctx) { - //XXX ntfs_log_error("Couldn't create a search context.\n"); - return NULL; - } - - rec = find_attribute(type, ctx); - ntfs_attr_put_search_ctx(ctx); - if (rec) - ntfs_log_debug("find_first_attribute: found attr of type 0x%02x.\n", type); - else - ntfs_log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type); - return rec; -} - -/** - * ntfs_name_print - Send a Unicode name to the debug log - * @name: - * @name_len: - * - * Description... - * - * Returns: - */ -void ntfs_name_print(ntfschar *name, int name_len) -{ - char *buffer = NULL; - - if (name_len) { - ntfs_ucstombs(name, name_len, &buffer, 0); - ntfs_log_debug("%s", buffer); - free(buffer); - } else { - ntfs_log_debug("!"); - } -} - -/** - * utils_free_non_residents3 - Free all the non-resident attributes of an inode - * @bmp: - * @inode: - * @attr: - * - * Description... - * - * Returns: - */ -int utils_free_non_residents3(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr) -{ - ntfs_attr *na; - runlist_element *rl; - LCN size; - LCN count; - - if (!bmp) - return 1; - if (!inode) - return 1; - if (!attr) - return 1; - if (!attr->non_resident) - return 0; - - ntfs_log_trace ("\n"); - na = ntfs_attr_open(inode, attr->type, NULL, 0); - if (!na) - return 1; - - ntfs_attr_map_whole_runlist(na); - rl = na->rl; - size = na->allocated_size >> inode->vol->cluster_size_bits; - for (count = 0; count < size; count += rl->length, rl++) { - if (ntfs_bmp_set_range(bmp, rl->lcn, rl->length, 0) < 0) { - ntfs_log_warning("set range : %lld - %lld FAILED\n", rl->lcn, rl->lcn+rl->length-1); - } - } - ntfs_attr_close(na); - - return 0; -} - -/** - * utils_free_non_residents2 - Find all the non-resident attributes of an inode - * @inode: - * @bmp: - * - * Description... - * - * Returns: - */ -int utils_free_non_residents2(ntfs_inode *inode, struct ntfs_bmp *bmp) -{ - ntfs_attr_search_ctx *ctx; - - if (!inode) - return -1; - if (!bmp) - return -1; - - ntfs_log_trace ("\n"); - ctx = ntfs_attr_get_search_ctx(NULL, inode->mrec); - if (!ctx) { - ntfs_log_info("can't create a search context\n"); - return -1; - } - - while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) { - utils_free_non_residents3(bmp, inode, ctx->attr); - } - - ntfs_attr_put_search_ctx(ctx); - return 0; -} - - -#endif /* NTFS_RICH */ - diff --git a/libntfs/tree.c b/libntfs/tree.c deleted file mode 100644 index 9dc5ef87..00000000 --- a/libntfs/tree.c +++ /dev/null @@ -1,2366 +0,0 @@ -/** - * tree.c - Directory tree handling code. Part of the Linux-NTFS project. - * - * Copyright (c) 2004-2005 Richard Russon - * - * This program/include file is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program/include file is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS - * distribution in the file COPYING); if not, write to the Free Software - * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef NTFS_RICH - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif - -#include "volume.h" -#include "dir.h" -#include "tree.h" -#include "bitmap.h" -#include "index.h" -#include "inode.h" -#include "logging.h" -#include "rich.h" - -/** - * ntfs_dt_free - Destroy a directory-tree object - * @dt: - * - * Description... - * - * Returns: - */ -void ntfs_dt_free(struct ntfs_dt *dt) -{ - int i; - - if (!dt) - return; - - ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num)); - - for (i = 0; i < dt->child_count; i++) { - ntfs_dt_free(dt->sub_nodes[i]); - ntfs_inode_close2(dt->inodes[i]); - } - - free(dt->sub_nodes); - free(dt->children); - free(dt->inodes); - free(dt->data); // XXX is this always ours? - free(dt); -} - -/** - * ntfs_dt_rollback - Discard the in-memory directory-tree changes - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_rollback(struct ntfs_dt *dt) -{ - int i; - - if (!dt) - return 0; - if (dt->child_count == 0) // No children or nothing mapped - return 0; - - ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num)); - - if (dt->changed) { - // We can't trust anything below us in the tree - for (i = 0; i < dt->child_count; i++) { - ntfs_dt_free(dt->sub_nodes[i]); - ntfs_inode_close2(dt->inodes[i]); - } - - dt->child_count = 0; - - free(dt->data); - free(dt->children); - free(dt->sub_nodes); - free(dt->inodes); - - dt->data = NULL; - dt->children = NULL; - dt->sub_nodes = NULL; - dt->inodes = NULL; - } else { - // This node is OK, check the su-nodes - for (i = 0; i < dt->child_count; i++) { - if (ntfs_dt_rollback(dt->sub_nodes[i])) { - ntfs_inode_close2(dt->inodes[i]); - // Child was changed so unmap it - dt->sub_nodes[i] = NULL; - dt->inodes[i] = NULL; - } - } - } - - return (dt->child_count == 0); -} - -/** - * ntfs_dt_commit - Write to disk the in-memory directory-tree changes - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_commit(struct ntfs_dt *dt) -{ - ntfs_volume *vol; - ntfs_attr *attr; - struct ntfs_dir *dir; - int i; - int size; - - if (!dt) - return 0; - - ntfs_log_trace ("dt %p, children %d, dir %lld\n", dt, dt->child_count, MREF(dt->dir->mft_num)); - - dir = dt->dir; - if (!dir) - return -1; - - vol = dir->vol; // cluster size - - if (dt->changed) { - if (dt->parent) { - ntfs_log_debug("commit dt (alloc)\n"); - attr = dt->dir->ialloc; - size = dt->dir->index_size; - //utils_dump_mem(dt->data, 0, size, DM_DEFAULTS); - ntfs_attr_mst_pwrite(attr, dt->vcn * vol->cluster_size, 1, size, dt->data); // XXX retval - } else { - ntfs_log_debug("commit dt (root)\n"); - attr = dt->dir->iroot; - size = dt->data_len; - //utils_dump_mem(dt->data, 0, size, DM_DEFAULTS); - ntfs_attr_pwrite(attr, 0, size, dt->data); // XXX retval - } - - ntfs_log_warning("\tntfs_attr_pwrite(vcn %lld)\n", dt->vcn); - - dt->changed = FALSE; - } else { - //ntfs_log_debug("\tdt is clean\n"); - } - - for (i = 0; i < dt->child_count; i++) { - if ((dt->inodes[i]) && (NInoDirty(dt->inodes[i]))) { - //utils_dump_mem(dt->inodes[i]->mrec, 0, vol->mft_record_size, DM_DEFAULTS); - ntfs_inode_sync(dt->inodes[i]); - ntfs_log_warning("\tntfs_inode_sync %llu\n", dt->inodes[i]->mft_no); - } - - if (ntfs_dt_commit(dt->sub_nodes[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dt_create_children2 - Allocate space for the directory-tree's children - * @dt: - * @count: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_create_children2(struct ntfs_dt *dt, int count) -{ - // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) - - int old = (dt->child_count + 0x1e) & ~0x1f; - int new = (count + 0x1f) & ~0x1f; - - if (old == new) - return TRUE; - - ntfs_log_trace ("\n"); - dt->children = realloc(dt->children, new * sizeof(*dt->children)); - dt->sub_nodes = realloc(dt->sub_nodes, new * sizeof(*dt->sub_nodes)); - dt->inodes = realloc(dt->inodes, new * sizeof(*dt->inodes)); - - if (!dt->children || !dt->sub_nodes || !dt->inodes) - return FALSE; // dt->child_count = -1 ? - - memset((u8*)dt->children + old, 0, (new - old) * sizeof(*dt->children)); - memset((u8*)dt->sub_nodes + old, 0, (new - old) * sizeof(*dt->sub_nodes)); - memset((u8*)dt->inodes + old, 0, (new - old) * sizeof(*dt->inodes)); - - return TRUE; -} - -/** - * ntfs_dt_resize_children3 - Resize a directory-tree's children arrays - * @dt: - * @new: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_resize_children3(struct ntfs_dt *dt, int new) -{ - int old; - - // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) - // XXX assumption: sizeof(*dt->children) == sizeof(*dt->sub_nodes) == sizeof(*dt->inodes) - // XXX put back blocking factor - - if (!dt) - return FALSE; - - old = dt->child_count; - if (old == new) - return TRUE; - - ntfs_log_trace ("dt %p, mft %lld, old %d, new %d\n", dt, MREF(dt->dir->mft_num), old, new); - dt->child_count = new; - - old *= sizeof(*dt->children); - new *= sizeof(*dt->children); - - dt->children = realloc(dt->children, new); - dt->sub_nodes = realloc(dt->sub_nodes, new); - dt->inodes = realloc(dt->inodes, new); - - if (!dt->children || !dt->sub_nodes || !dt->inodes) - return FALSE; - - if (new > old) { - memset((u8*)dt->children + old, 0, (new - old)); - memset((u8*)dt->sub_nodes + old, 0, (new - old)); - memset((u8*)dt->inodes + old, 0, (new - old)); - } - - return TRUE; -} - -/** - * ntfs_dt_root_count - Count the index entries in an index root - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_count(struct ntfs_dt *dt) -{ - u8 *buffer = NULL; - u8 *ptr = NULL; - VCN vcn; - s64 size = 0; - char *name = NULL; - - INDEX_ROOT *root; - INDEX_HEADER *header; - INDEX_ENTRY *entry; - - if (!dt) - return -1; - - ntfs_log_trace ("\n"); - buffer = dt->data; - size = dt->data_len; - - //utils_dump_mem(buffer, 0, size, DM_DEFAULTS); - - root = (INDEX_ROOT*) buffer; - if (root->type != AT_FILE_NAME) - return -1; - - header = (INDEX_HEADER*) (buffer + 0x10); - if (header->index_length > size) - return -1; - - dt->child_count = 0; - ptr = buffer + header->entries_offset + 0x10; - - while (ptr < (buffer + size)) { - entry = (INDEX_ENTRY*) ptr; - - ntfs_dt_resize_children3(dt, dt->child_count + 1); // XXX retval - - if (entry->flags & INDEX_ENTRY_NODE) { - vcn = ntfs_ie_get_vcn((INDEX_ENTRY*) ptr); - //ntfs_log_debug("VCN %lld\n", vcn); - } - - if (!(entry->flags & INDEX_ENTRY_END)) { - ntfs_ucstombs(entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); - //ntfs_log_debug("\tinode %8lld %s\n", MREF(entry->indexed_file), name); - free(name); - name = NULL; - } - - //ntfs_log_debug("CC[%d] = %p\n", dt->child_count-1, entry); - dt->children[dt->child_count-1] = entry; - - ptr += entry->length; - } - - //ntfs_log_debug("count = %d\n\n", dt->child_count); - - return dt->child_count; -} - -/** - * ntfs_dt_alloc_count - Count the index entries in an index allocation - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_alloc_count(struct ntfs_dt *dt) -{ - u8 *buffer = NULL; - u8 *ptr = NULL; - VCN vcn; - s64 size = 0; - char *name = NULL; - - INDEX_BLOCK *block; - INDEX_ENTRY *entry; - - if (!dt) - return -1; - - ntfs_log_trace ("\n"); - buffer = dt->data; - size = dt->data_len; - - //utils_dump_mem(buffer, 0, 128, DM_DEFAULTS); - - block = (INDEX_BLOCK*) buffer; - //ntfs_log_debug("INDX %lld\n", block->index_block_vcn); - - ptr = buffer + 0x18 + block->index.entries_offset; - - //ntfs_log_debug("block size %d\n", block->index.index_length); - dt->child_count = 0; - //ntfs_log_debug("start = 0x%02X, end = 0x%02X\n", 0x18 + block->index.entries_offset, 0x18 + block->index.index_length); - while (ptr < (buffer + 0x18 + block->index.index_length)) { - entry = (INDEX_ENTRY*) ptr; - - ntfs_dt_resize_children3(dt, dt->child_count + 1); // XXX retval - - if (entry->flags & INDEX_ENTRY_NODE) { - vcn = ntfs_ie_get_vcn((INDEX_ENTRY*) ptr); - //ntfs_log_debug("\tVCN %lld\n", vcn); - } - - dt->children[dt->child_count-1] = entry; - - if (entry->flags & INDEX_ENTRY_END) { - break; - } else { - ntfs_ucstombs(entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); - //ntfs_log_debug("\tinode %8lld %s\n", MREF(entry->indexed_file), name); - free(name); - name = NULL; - } - - ptr += entry->length; - } - //ntfs_log_debug("count = %d\n", dt->child_count); - - return dt->child_count; -} - -/** - * ntfs_dt_initialise2 - Setup a directory-tree object - * @vol: - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_initialise2(ntfs_volume *vol, struct ntfs_dt *dt) -{ - INDEX_ALLOCATION *alloc; - INDEX_ENTRY *entry; - - if (!vol) - return 1; - if (!dt) - return 1; - - ntfs_log_trace ("\n"); - memset(dt->data, 0, dt->data_len); - - alloc = (INDEX_ALLOCATION*) dt->data; - - alloc->magic = magic_INDX; - alloc->usa_ofs = 0x28; - alloc->usa_count = (dt->data_len >> vol->sector_size_bits) + 1; - alloc->lsn = 0; - alloc->index_block_vcn = 0; - - alloc->index.entries_offset = 0x28; - alloc->index.index_length = 0x10 + 0x28; - alloc->index.allocated_size = dt->data_len - 0x18; - alloc->index.flags = 0; - - entry = (INDEX_ENTRY*) (dt->data + 0x40); - - entry->indexed_file = 0; - entry->length = 0x10; - entry->key_length = 0; - entry->flags = INDEX_ENTRY_END; - - ntfs_dt_resize_children3(dt, 1); // XXX retval - - dt->children[0] = entry; - - return 0; -} - -/** - * ntfs_dt_create - Create a representation of a directory index - * @dir: - * @parent: - * @vcn: - * - * Description... - * - * Returns: - */ -struct ntfs_dt * ntfs_dt_create(struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn) -{ - struct ntfs_dt *dt = NULL; - //int i; - - if (!dir) - return NULL; - - dt = calloc(1, sizeof(*dt)); - if (!dt) - return NULL; - - ntfs_log_trace ("\n"); - dt->dir = dir; - dt->parent = parent; - dt->child_count = 0; - dt->children = NULL; - dt->sub_nodes = NULL; - dt->inodes = NULL; - dt->vcn = vcn; - dt->changed = FALSE; - - if (parent) { - //ntfs_log_debug("alloc a = %lld\n", dir->ialloc->allocated_size); - //ntfs_log_debug("alloc d = %lld\n", dir->ialloc->data_size); - //ntfs_log_debug("alloc i = %lld\n", dir->ialloc->initialized_size); - //ntfs_log_debug("vcn = %lld\n", vcn); - - dt->data_len = dt->dir->index_size; - //ntfs_log_debug("parent size = %d\n", dt->data_len); - dt->data = malloc(dt->data_len); - - if (vcn >= 0) { - //ntfs_log_debug("%lld\n", ntfs_attr_mst_pread(dir->ialloc, vcn*512, 1, dt->data_len, dt->data)); - ntfs_attr_mst_pread(dir->ialloc, vcn*512, 1, dt->data_len, dt->data); - } else { - ntfs_dt_initialise2(dir->vol, dt); - } - - //utils_dump_mem(dt->data, 0, dt->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - ntfs_dt_alloc_count(dt); - - dt->header = &((INDEX_BLOCK*)dt->data)->index; - //ntfs_log_debug("USA = %d\n", ((INDEX_BLOCK*)dt->data)->usa_count); - -#if 0 - for (i = 0; i < dt->child_count; i++) { - INDEX_ENTRY *ie = dt->children[i]; - - ntfs_log_debug("%d\n", ((u8*)ie) - dt->data); - if (ie->flags & INDEX_ENTRY_END) - ntfs_log_debug("IE (%d)\n", ie->length); - else - ntfs_log_debug("IE %lld (%d)\n", MREF(ie->key.file_name.parent_directory), ie->length); - utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS); - ntfs_log_debug("\n"); - } -#endif - } else { - //ntfs_log_debug("root a = %lld\n", dir->iroot->allocated_size); - //ntfs_log_debug("root d = %lld\n", dir->iroot->data_size); - //ntfs_log_debug("root i = %lld\n", dir->iroot->initialized_size); - - dt->data_len = dir->iroot->allocated_size; - dt->data = malloc(dt->data_len); - //ntfs_log_debug("%lld\n", ntfs_attr_pread(dir->iroot, 0, dt->data_len, dt->data)); - ntfs_attr_pread(dir->iroot, 0, dt->data_len, dt->data); - //utils_dump_mem(dt->data, 0, dt->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - ntfs_dt_root_count(dt); - - dt->header = &((INDEX_ROOT*)dt->data)->index; - //dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size; - //ntfs_log_debug("IBS = %d\n", ((INDEX_ROOT*)dt->data)->index_block_size); - -#if 0 - for (i = 0; i < dt->child_count; i++) { - INDEX_ENTRY *ie = dt->children[i]; - - ntfs_log_debug("%d\n", ((u8*)ie) - dt->data); - if (ie->flags & INDEX_ENTRY_END) - ntfs_log_debug("IE (%d)\n", ie->length); - else - ntfs_log_debug("IE %lld (%d)\n", MREF(ie->key.file_name.parent_directory), ie->length); - utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS); - ntfs_log_debug("\n"); - } -#endif - } - //ntfs_log_debug("index_header (%d,%d)\n", dt->header->index_length, dt->header->allocated_size); - - return dt; -} - -/** - * ntfs_dt_find - Find an index entry by name - * @dt: - * @name: - * @name_len: - * - * find dt by name, return MFT_REF - * maps dt's as necessary - */ -MFT_REF ntfs_dt_find(struct ntfs_dt *dt, ntfschar *name, int name_len) -{ - MFT_REF res = -1; - INDEX_ENTRY *ie; - struct ntfs_dt *sub; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return -1; - - ntfs_log_trace ("\n"); - /* - * State Children Action - * ------------------------------------------- - * collates after - keep searching - * match name - return MREF - * collates before no return -1 - * collates before yes map & recurse - * end marker no return -1 - * end marker yes map & recurse - */ - - //ntfs_log_debug("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n"); - r = ntfs_names_collate(name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //ntfs_log_debug("%d, %d\n", i, r); - - if (r == 1) { - //ntfs_log_debug("keep searching\n"); - continue; - } else if (r == 0) { - res = MREF(ie->indexed_file); - //ntfs_log_debug("match %lld\n", res); - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //ntfs_log_debug("map & recurse\n"); - //ntfs_log_debug("sub %p\n", dt->sub_nodes); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn(ie); - //ntfs_log_debug("vcn = %lld\n", vcn); - sub = ntfs_dt_create(dt->dir, dt, vcn); - dt->sub_nodes[i] = sub; - } - res = ntfs_dt_find(dt->sub_nodes[i], name, name_len); - } else { - //ntfs_log_debug("ENOENT\n"); - } - } else { - ntfs_log_debug("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find2 - Find an index entry by name - * @dt: - * @name: - * @name_len: - * @index_num: - * - * find dt by name, returns dt and index - * maps dt's as necessary - */ -struct ntfs_dt * ntfs_dt_find2(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - INDEX_ENTRY *ie; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return NULL; - ntfs_log_trace ("dt %p, mft %llu, name %p%d\n", dt, MREF(dt->dir->mft_num), name, name_len); - - //ntfs_log_debug("searching for: "); ntfs_name_print(name, name_len); ntfs_log_debug("\n"); - - //utils_dump_mem(dt->data, 0, 256, DM_DEFAULTS); - - // XXX default index_num to -1 - - /* - * State Children Action - * ------------------------------------------- - * collates after - keep searching - * match name - return MREF - * collates before no return -1 - * collates before yes map & recurse - * end marker no return -1 - * end marker yes map & recurse - */ - - //ntfs_log_debug("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n"); - //utils_dump_mem(name, 0, name_len * 2, DM_DEFAULTS); - //utils_dump_mem(ie->key.file_name.file_name, 0, ie->key.file_name.file_name_length * 2, DM_DEFAULTS); - r = ntfs_names_collate(name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //ntfs_log_debug("%d, %d\n", i, r); - - if (r == 1) { - //ntfs_log_debug("keep searching\n"); - continue; - } else if (r == 0) { - res = dt; - //ntfs_log_debug("match %p\n", res); - if (index_num) - *index_num = i; - } else if ((r == -1) && (ie->flags & INDEX_ENTRY_NODE)) { - //ntfs_log_debug("recurse\n"); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn(ie); - //ntfs_log_debug("vcn = %lld\n", vcn); - dt->sub_nodes[i] = ntfs_dt_create(dt->dir, dt, vcn); - } - res = ntfs_dt_find2(dt->sub_nodes[i], name, name_len, index_num); - } else { - //ntfs_log_debug("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find3 - Find an index entry by name - * @dt: - * @name: - * @name_len: - * @index_num: - * - * find dt by name, returns dt and index - * does not map new dt's - */ -struct ntfs_dt * ntfs_dt_find3(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - INDEX_ENTRY *ie; - int i; - int r; - - if (!dt || !name) - return NULL; - ntfs_log_trace ("\n"); - - //ntfs_log_debug("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n"); - r = ntfs_names_collate(name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //ntfs_log_debug("%d, %d\n", i, r); - - if (r == 1) { - //ntfs_log_debug("keep searching\n"); - continue; - } else if (r == 0) { - res = dt; - //ntfs_log_debug("match %p\n", res); - if (index_num) - *index_num = i; - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //ntfs_log_debug("recurse\n"); - res = ntfs_dt_find3(dt->sub_nodes[i], name, name_len, index_num); - } else { - //ntfs_log_debug("no match\n"); - res = dt; - if (index_num) - *index_num = i; - } - } else { - ntfs_log_debug("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find4 - Find an index entry by name - * @dt: - * @name: - * @name_len: - * @index_num: - * - * find successor to specified name, returns dt and index - * maps dt's as necessary - */ -struct ntfs_dt * ntfs_dt_find4(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - struct ntfs_dt *sub = NULL; - INDEX_ENTRY *ie; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return NULL; - ntfs_log_trace ("\n"); - - //ntfs_log_debug("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - //ntfs_log_debug("ie->flags = %d\n", ie->flags); - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //ntfs_log_debug("\t"); ntfs_name_print(ie->key.file_name.file_name, ie->key.file_name.file_name_length); ntfs_log_debug("\n"); - r = ntfs_names_collate(name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //ntfs_log_debug("%d, %d\n", i, r); - - if (r == 1) { - //ntfs_log_debug("keep searching\n"); - } else if (r == 0) { - //res = dt; - //ntfs_log_debug("match\n"); - // ignore - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //ntfs_log_debug("recurse\n"); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn(ie); - //ntfs_log_debug("vcn = %lld\n", vcn); - sub = ntfs_dt_create(dt->dir, dt, vcn); - dt->sub_nodes[i] = sub; - } - res = ntfs_dt_find4(dt->sub_nodes[i], name, name_len, index_num); - } else { - //ntfs_log_debug("no match\n"); - res = dt; - if (index_num) - *index_num = i; - } - break; - } else { - ntfs_log_debug("error collating name\n"); - } - //break; - } - - return res; -} - -/** - * ntfs_dt_find_all - Recurse the directory-tree, mapping all elements - * @dt: - * - * maps all dt's into memory - */ -void ntfs_dt_find_all(struct ntfs_dt *dt) -{ - INDEX_ENTRY *ie; - VCN vcn; - int i; - - if (!dt) - return; - ntfs_log_trace ("\n"); - - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_NODE) { - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn(ie); - dt->sub_nodes[i] = ntfs_dt_create(dt->dir, dt, vcn); - } - ntfs_dt_find_all(dt->sub_nodes[i]); - } - } -} - -/** - * ntfs_dt_find_parent - Find the index of ourself in the parent's array - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_find_parent(struct ntfs_dt *dt) -{ - int i; - struct ntfs_dt *parent; - - if (!dt) - return -1; - ntfs_log_trace ("\n"); - - parent = dt->parent; - if (!parent) - return -1; - - for (i = 0; i < parent->child_count; i++) - if (parent->sub_nodes[i] == dt) - return i; - - return -1; -} - -/** - * ntfs_dt_isroot - Does this directory-tree represent an index root - * @dt: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_isroot(struct ntfs_dt *dt) -{ - if (!dt) - return FALSE; - ntfs_log_trace ("\n"); - return (dt->parent == NULL); -} - -/** - * ntfs_dt_root_freespace - Give the free space (bytes) in an index root - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_freespace(struct ntfs_dt *dt) -{ - int recsize; - int inuse; - MFT_RECORD *mrec; - - if (!dt) - return -1; - ntfs_log_trace ("\n"); - - recsize = dt->dir->inode->vol->mft_record_size; - - mrec = (MFT_RECORD*) dt->dir->inode->mrec; - inuse = mrec->bytes_in_use; - - return recsize - inuse; -} - -/** - * ntfs_dt_alloc_freespace - Give the free space (bytes) in an index allocation - * @dt: - * - * Description... - * - * Returns: - */ -int ntfs_dt_alloc_freespace(struct ntfs_dt *dt) -{ - int recsize; - int inuse; - INDEX_BLOCK *block; - - if (!dt) - return -1; - ntfs_log_trace ("\n"); - - recsize = dt->dir->index_size; - - block = (INDEX_BLOCK*) dt->data; - inuse = block->index.index_length + 24; - - return recsize - inuse; -} - -/** - * ntfs_dt_transfer - Transfer several index entries between directory-trees - * @old: - * @new: - * @start: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_transfer(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) -{ - int i; - int need; - int space; - INDEX_ENTRY *mov_ie; - u8 *src; - u8 *dst; - int len; - int insert; - //FILE_NAME_ATTR *file; - ntfs_log_trace ("\n"); - - //XXX check len > 0 - - if (!old || !new) - return -1; - - if ((start < 0) || ((start+count) >= old->child_count)) - return -1; - - //ntfs_log_debug("\n"); - ntfs_log_debug("Transferring children\n"); - - need = 0; - for (i = start; i < (start+count+1); i++) { - mov_ie = old->children[i]; - need += mov_ie->length; - //file = &mov_ie->key.file_name; ntfs_log_debug("\ttrn name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n"); - } - - if (ntfs_dt_isroot(new)) - space = ntfs_dt_root_freespace(new); - else - space = ntfs_dt_alloc_freespace(new); - - // XXX if this is an index root, it'll go badly wrong - // restrict to allocs only? - - ntfs_log_debug("\tneed = %d\n", need); - ntfs_log_debug("\tspace = %d\n", space); - - if (space < need) - return -1; - - if (new->child_count == 1) { - i = -1; - } else { - ntfschar *n1, *n2; - int l1, l2; - - n1 = new->children[0]->key.file_name.file_name; - l1 = new->children[0]->key.file_name.file_name_length; - - n2 = old->children[start]->key.file_name.file_name; - l2 = old->children[start]->key.file_name.file_name_length; - - i = ntfs_names_collate(n1, l1, n2, l2, - 2, IGNORE_CASE, - old->dir->vol->upcase, - old->dir->vol->upcase_len); - } - - if ((i == 0) || (i == 2)) - return -1; - - // determine the insertion point - if (i == 1) - insert = 0; - else - insert = new->child_count-1; - - src = (u8*) new->children[insert]; - dst = src + need; - len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; - - //ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); - memmove(dst, src, len); - - dst = src; - src = (u8*) old->children[start]; - len = need; - - memcpy(dst, src, len); - - src = (u8*) old->children[start+count-1]; - dst = (u8*) old->children[start]; - len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; - - //ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); - memmove(dst, src, len); - - dst += len; - len = old->data + old->dir->index_size - dst; - - //ntfs_log_debug("dst = %d, len = %d\n", dst - old->data, len); - memset(dst, 0, len); - - if (!ntfs_dt_resize_children3(new, new->child_count + count)) - return -1; - - src = (u8*) &old->sub_nodes[start+count-1]; - dst = (u8*) &old->sub_nodes[start]; - len = (old->child_count - start - count + 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - src = (u8*) &new->sub_nodes[insert]; - dst = (u8*) &new->sub_nodes[insert+count-1]; - len = (new->child_count - insert - count + 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - if (!ntfs_dt_resize_children3(old, old->child_count - count)) - return -1; - - src = (u8*) new->children[0]; - for (i = 0; i < new->child_count; i++) { - new->children[i] = (INDEX_ENTRY*) src; - src += new->children[i]->length; - } - - src = (u8*) old->children[0]; - for (i = 0; i < old->child_count; i++) { - old->children[i] = (INDEX_ENTRY*) src; - src += old->children[i]->length; - } - - old->header->index_length -= need; - new->header->index_length += need; - - // resize children and sub_nodes - // memmove keys in new - // memcpy old to new - // memmove keys in old - // rebuild old/new children/sub_nodes without destroying tree - // update old/new headers - - old->changed = TRUE; - new->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); - - return 0; -} - -/** - * ntfs_dt_alloc_insert - Insert an index entry into an index allocation - * @dt: - * @first: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_alloc_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count) -{ - // XXX don't bother measuring, just subtract the children pointers - - int i; - int need; - INDEX_ENTRY *ie; - INDEX_ALLOCATION *alloc; - u8 *src; - u8 *dst; - int len; - - if (!dt) - return 1; - if (!first) - return 1; - ntfs_log_trace ("\n"); - - need = 0; - ie = first; - for (i = 0; i < count; i++) { - need += ie->length; - ie = (INDEX_ENTRY*) ((u8*)ie + ie->length); - } - - ntfs_log_debug("alloc insert %d bytes\n", need); - - alloc = (INDEX_ALLOCATION*) dt->data; - ntfs_log_debug("entries_offset = %d\n", alloc->index.entries_offset); - ntfs_log_debug("index_length = %d\n", alloc->index.index_length); - ntfs_log_debug("allocated_size = %d\n", alloc->index.allocated_size); - - ntfs_log_debug("insert has %d children\n", dt->child_count); - ntfs_log_debug("children = %p\n", dt->children); - //utils_dump_mem(dt->data, 0, 128, DM_DEFAULTS); - - ie = dt->children[dt->child_count-1]; - - ntfs_log_debug("last child = %p (%ld)\n", ie, (long)ie - (long)dt->data); - ntfs_log_debug("size = %d\n", ie->length); - - src = (u8*) ie; - dst = src + need; - len = ie->length; - - memmove(dst, src, len); - - src = (u8*) first; - dst = (u8*) ie; - len = need; - - memcpy(dst, src, len); - - // use create children - // measure need and update children list - // adjust headers - - //utils_dump_mem(dt->data, 0, 256, DM_DEFAULTS); - return 0; -} - -/** - * ntfs_dt_alloc_insert2 - Insert an index entry into an index allocation - * @dt: - * @before: - * @count: - * @bytes: - * - * Description... - * - * Returns: - */ -INDEX_ENTRY * ntfs_dt_alloc_insert2(struct ntfs_dt *dt, int before, int count, int bytes) -{ - int space; - u8 *src; - u8 *dst; - int len; - - // XXX don't bother measuring, just subtract the children pointers - - if (!dt) - return NULL; - if (before < 0) - return NULL; - if (count < 1) - return NULL; - if (bytes < 1) - return NULL; - ntfs_log_trace ("\n"); - - // check alloc has enough space - space = ntfs_dt_alloc_freespace(dt); - if (bytes > space) - return NULL; - - // move data - src = (u8*) dt->children[before]; - dst = src + bytes; - len = dt->header->index_length - ((int)dt->children[before] - (int)dt->data) + 24; - - //ntfs_log_debug("%d, %d, %d\n", (int)src - (int)dt->data, (int)dst - (int)dt->data, len); - - memmove(dst, src, len); - memset(dst, 0, bytes); - - // resize arrays - ntfs_dt_resize_children3(dt, dt->child_count + count); - - // move keys (children) - src = (u8*) (dt->children + before); - dst = src + (count * sizeof(u8*)); - len = (dt->child_count - count - before) * sizeof(u8*); - - memmove(dst, src, len); - memset(src, 0, count * sizeof(u8*)); - - // move keys (inodes) - src = (u8*) (dt->inodes + before); - dst = src + (count * sizeof(u8*)); - len = (dt->child_count - count - before) * sizeof(u8*); - - memmove(dst, src, len); - memset(src, 0, count * sizeof(u8*)); - - // move keys (sub_nodes) - src = (u8*) (dt->sub_nodes + before); - dst = src + (count * sizeof(u8*)); - len = (dt->child_count - count - before) * sizeof(u8*); - - memmove(dst, src, len); - memset(src, 0, count * sizeof(u8*)); - - return NULL; -} - -/** - * ntfs_dt_root_insert - Insert an index entry into an index root - * @dt: - * @first: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count) -{ - if (!dt) - return 1; - if (!first) - return 1; - ntfs_log_trace ("\n"); - - return count; -} - -/** - * ntfs_dt_alloc_remove2 - Remove an index entry from an index allocation - * @dt: - * @start: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_alloc_remove2(struct ntfs_dt *dt, int start, int count) -{ - int i; - int size; - - if (!dt) - return 1; - ntfs_log_trace ("\n"); - - size = 0; - for (i = start; i < (start+count); i++) { - size += dt->children[i]->length; - } - - return start + count; -} - -/** - * ntfs_dt_root_remove2 - Remove an index entry from an index root - * @dt: - * @start: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_remove2(struct ntfs_dt *dt, int start, int count) -{ - int i; - int size; - - if (!dt) - return -1; - if ((start < 0) || (start >= dt->child_count)) - return -1; - if ((count < 1) || ((start + count - 1) >= dt->child_count)) - return -1; - ntfs_log_trace ("\n"); - - ntfs_log_debug("s c/t %d %d/%d\n", start, count, dt->child_count); - - size = 0; - for (i = start; i < (start + count); i++) - size += dt->children[i]->length; - ntfs_log_debug("size1 = %d\n", size); - - size = (int) dt->children[start+count] - (int) dt->children[start]; - ntfs_log_debug("size2 = %d\n", size); - - size = (int) dt->children[start+count-1] - (int) dt->children[start] + dt->children[start+count-1]->length; - ntfs_log_debug("size3 = %d\n", size); - - // XXX what shall we do with the inodes? - // transfer them to the dir (commit them for now) - // are they _our_ responsibility? probably not - - // rearrange arrays - // shrink attribute - - ntfs_dt_resize_children3(dt, dt->child_count - count); - - ntfs_log_debug("ntfs_dt_root_remove2\n"); - return dt->child_count; -} - -/** - * ntfs_dt_transfer2 - Transfer several index entries between directory-trees - * @old: - * @new: - * @start: - * @count: - * - * Description... - * - * Returns: - */ -int ntfs_dt_transfer2(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) -{ - int i; - int need; - int space; - INDEX_ENTRY *mov_ie; - u8 *src; - u8 *dst; - int len; - int insert; - //FILE_NAME_ATTR *file; - - if (!old || !new) - return -1; - - if ((start < 0) || (count < 0)) - return -1; - - if ((start + count) >= old->child_count) - return -1; - ntfs_log_trace ("\n"); - - //ntfs_log_debug("\n"); - ntfs_log_debug("Transferring children\n"); - - need = 0; - for (i = start; i < (start+count); i++) { - mov_ie = old->children[i]; - need += mov_ie->length; - //file = &mov_ie->key.file_name; ntfs_log_debug("\ttrn name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n"); - } - - if (ntfs_dt_isroot(new)) - space = ntfs_dt_root_freespace(new); - else - space = ntfs_dt_alloc_freespace(new); - - ntfs_log_debug("\tneed = %d\n", need); - ntfs_log_debug("\tspace = %d\n", space); - - if (need > space) - return -1; - - if (ntfs_dt_isroot(new)) - ntfs_dt_root_insert(new, old->children[0], count); - else - ntfs_dt_alloc_insert2(new, 0, count, need); - - if (ntfs_dt_isroot(old)) - ntfs_dt_root_remove2(old, 0, count); - else - ntfs_dt_alloc_remove2(old, 0, count); - - if (1) return -1; - if (0) ntfs_dt_alloc_insert(NULL, NULL, 0); - - if (new->child_count == 1) { - i = -1; - } else { - ntfschar *n1, *n2; - int l1, l2; - - n1 = new->children[0]->key.file_name.file_name; - l1 = new->children[0]->key.file_name.file_name_length; - - n2 = old->children[start]->key.file_name.file_name; - l2 = old->children[start]->key.file_name.file_name_length; - - i = ntfs_names_collate(n1, l1, n2, l2, - 2, IGNORE_CASE, - old->dir->vol->upcase, - old->dir->vol->upcase_len); - } - - if ((i == 0) || (i == 2)) - return -1; - - // determine the insertion point - if (i == 1) - insert = 0; - else - insert = new->child_count-1; - - src = (u8*) new->children[insert]; - dst = src + need; - len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; - - //ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); - memmove(dst, src, len); - - dst = src; - src = (u8*) old->children[start]; - len = need; - - memcpy(dst, src, len); - - src = (u8*) old->children[start+count-1]; - dst = (u8*) old->children[start]; - len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; - - //ntfs_log_debug("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); - memmove(dst, src, len); - - dst += len; - len = old->data + old->dir->index_size - dst; - - //ntfs_log_debug("dst = %d, len = %d\n", dst - old->data, len); - memset(dst, 0, len); - - if (!ntfs_dt_resize_children3(new, new->child_count + count)) - return -1; - - src = (u8*) &old->sub_nodes[start+count-1]; - dst = (u8*) &old->sub_nodes[start]; - len = (old->child_count - start - count + 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - src = (u8*) &new->sub_nodes[insert]; - dst = (u8*) &new->sub_nodes[insert+count-1]; - len = (new->child_count - insert - count + 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - if (!ntfs_dt_resize_children3(old, old->child_count - count)) - return -1; - - src = (u8*) new->children[0]; - for (i = 0; i < new->child_count; i++) { - new->children[i] = (INDEX_ENTRY*) src; - src += new->children[i]->length; - } - - src = (u8*) old->children[0]; - for (i = 0; i < old->child_count; i++) { - old->children[i] = (INDEX_ENTRY*) src; - src += old->children[i]->length; - } - - old->header->index_length -= need; - new->header->index_length += need; - - // resize children and sub_nodes - // memmove keys in new - // memcpy old to new - // memmove keys in old - // rebuild old/new children/sub_nodes without destroying tree - // update old/new headers - - old->changed = TRUE; - new->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); - - return 0; -} - -/** - * ntfs_dt_root_replace - Replace an index entry in an index root - * @del: - * @del_num: - * @del_ie: - * @suc_ie: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) -{ - u8 *src; - u8 *dst; - u8 *attr; - int len; - int i; - - if (!del || !del_ie || !suc_ie) - return FALSE; - ntfs_log_trace ("\n"); - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - attr = malloc(del->data_len + suc_ie->length - del_ie->length); - - dst = attr; - src = del->data; - len = (u8*) del_ie - del->data; - - memcpy(dst, src, len); - - dst += len; - src = (u8*) suc_ie; - len = suc_ie->length; - - memcpy(dst, src, len); - - dst += len; - src = (u8*) del_ie + del_ie->length; - len = del->data_len + (del->data - (u8*) del_ie) - del_ie->length; - - memcpy(dst, src, len); - - src = (u8*) del->data; - dst = attr; - - len = suc_ie->length - del_ie->length; - free(del->data); - del->data = attr; - del->data_len += len; - del->header = (INDEX_HEADER*) (del->data + 0x10); - del->header->index_length += len; - del->header->allocated_size += len; - - ntfs_mft_resize_resident(del->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, del->data, del->data_len); - - //utils_dump_mem(attr, 0, del->data_len, DM_DEFAULTS); - - //ntfs_log_debug("\n"); - //ntfs_log_debug("Adjust children\n"); - //for (i = 0; i < del->child_count; i++) - // ntfs_log_debug("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); - //ntfs_log_debug("\n"); - - //ntfs_log_debug("src = %p, dst = %p, len = %d\n", src, dst, len); fflush (stdout); - - for (i = 0; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) (dst + ((u8*) del->children[i] - src)); - - for (i = del_num+1; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); - - //for (i = 0; i < del->child_count; i++) - // ntfs_log_debug("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); - //ntfs_log_debug("\n"); - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - del->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ROOT\n", del->dir->inode->mft_no); - return TRUE; -} - -/** - * ntfs_dt_alloc_replace - Replace an index entry in an index allocation - * @del: - * @del_num: - * @del_ie: - * @suc_ie: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_alloc_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) -{ - u8 *src; - u8 *dst; - int len; - int i; - - if (!del || !del_ie || !suc_ie) - return FALSE; - ntfs_log_trace ("\n"); - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - - src = (u8*) del_ie + del_ie->length; - dst = (u8*) del_ie + suc_ie->length; - len = del->header->index_length + 24 + (del->data - src); - //ntfs_log_debug("src = %d\n", src - del->data); - //ntfs_log_debug("dst = %d\n", dst - del->data); - //ntfs_log_debug("len = %d\n", len); - - if (src != dst) - memmove(dst, src, len); - - src = (u8*) suc_ie; - dst = (u8*) del_ie; - len = suc_ie->length; - - memcpy(dst, src, len); - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - - del->header->index_length += suc_ie->length - del_ie->length; - - dst = del->data + del->header->index_length + 24; - len = del->data_len - del->header->index_length - 24; - - memset(dst, 0, len); - - //for (i = 0; i < del->child_count; i++) - // ntfs_log_debug("Child %d %p\n", i, del->children[i]); - //ntfs_log_debug("\n"); - - len = suc_ie->length - del_ie->length; - //ntfs_log_debug("len = %d\n", len); - - for (i = del_num+1; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); - - //for (i = 0; i < del->child_count; i++) - // ntfs_log_debug("Child %d %p\n", i, del->children[i]); - //ntfs_log_debug("\n"); - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - - del->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); - return TRUE; -} - -/** - * ntfs_dt_root_remove - Remove an index entry from an index root - * @del: - * @del_num: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_root_remove(struct ntfs_dt *del, int del_num) -{ - INDEX_ENTRY *del_ie = NULL; - u8 *src; - u8 *dst; - u8 *old; - int len; - int del_len; - int i; - //int off; - - if (!del) - return FALSE; - ntfs_log_trace ("\n"); - - //utils_dump_mem(del->data, 0, del->header->index_length+16, DM_RED); - //ntfs_log_debug("\n"); - -#if 0 - off = (u8*) del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - ntfs_log_debug("%2d %4d ", i+1, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - ntfs_log_debug("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - ntfs_log_debug(" (%d)\n", del_ie->length); - } - ntfs_log_debug("total = %d\n", off); -#endif - - del_ie = del->children[del_num]; - del_len = del_ie->length; - - src = (u8*) del_ie + del_len; - dst = (u8*) del_ie; - len = del->header->index_length + 16 - (src - del->data); - - //ntfs_log_debug("src = %d\n", src - del->data); - //ntfs_log_debug("dst = %d\n", dst - del->data); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - del->data_len -= del_len; - del->child_count--; - - del->header->index_length = del->data_len - 16; - del->header->allocated_size = del->data_len - 16; - - ntfs_mft_resize_resident(del->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, del->data, del->data_len); - old = del->data; - del->data = realloc(del->data, del->data_len); - del->header = (INDEX_HEADER*) (del->data + 0x10); - - //utils_dump_mem(del->data, 0, del->data_len, DM_GREEN | DM_RED); - - src = (u8*) (&del->children[del_num+1]); - dst = (u8*) (&del->children[del_num]); - len = (del->child_count - del_num) * sizeof(INDEX_ENTRY*); - - //ntfs_log_debug("src = %d\n", src - (u8*) del->children); - //ntfs_log_debug("dst = %d\n", dst - (u8*) del->children); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - src = (u8*) (&del->sub_nodes[del_num+1]); - dst = (u8*) (&del->sub_nodes[del_num]); - len = (del->child_count - del_num) * sizeof(struct ntfs_dt*); - - //ntfs_log_debug("src = %d\n", src - (u8*) del->children); - //ntfs_log_debug("dst = %d\n", dst - (u8*) del->children); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - //ntfs_log_debug("del_num = %d\n", del_num); - for (i = 0; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - old + del->data); - for (i = del_num; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_len); - - if (!ntfs_dt_create_children2(del, del->child_count)) - return FALSE; - -#if 0 - off = (u8*) del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - ntfs_log_debug("%2d %4d ", i+1, off); - off += del_len; - - if (del_ie->flags & INDEX_ENTRY_END) { - ntfs_log_debug("END (%d)\n", del_len); - break; - } - - ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - ntfs_log_debug(" (%d)\n", del_len); - } - ntfs_log_debug("total = %d\n", off); -#endif - - //utils_dump_mem(del->data, 0, del->header->index_length+16, DM_DEFAULTS); - - del->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ROOT\n", del->dir->inode->mft_no); - return TRUE; -} - -/** - * ntfs_dt_alloc_remove - Remove an index entry from an index allocation - * @del: - * @del_num: - * - * Description... - * - * Returns: - */ -BOOL ntfs_dt_alloc_remove(struct ntfs_dt *del, int del_num) -{ - INDEX_ENTRY *del_ie = NULL; - u8 *dst; - u8 *src; - int len; - int i; - //int off; - - if (!del) - return FALSE; - ntfs_log_trace ("\n"); - -#if 0 - off = (u8*)del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - ntfs_log_debug("%2d %4d ", i, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - ntfs_log_debug("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - ntfs_log_debug(" (%d)\n", del_ie->length); - } - ntfs_log_debug("total = %d\n", off); - ntfs_log_debug("\n"); -#endif - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - del_ie = del->children[del_num]; - - src = (u8*) del_ie + del_ie->length; - dst = (u8*) del_ie; - len = del->header->index_length + 24 - (src - del->data); - - //ntfs_log_debug("src = %d\n", src - del->data); - //ntfs_log_debug("dst = %d\n", dst - del->data); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - del->header->index_length -= src - dst; - del->child_count--; - - dst += len; - len = del->data_len - del->header->index_length - 24; - - //ntfs_log_debug("dst = %d\n", dst - del->data); - //ntfs_log_debug("len = %d\n", len); - - memset(dst, 0, len); - - src = (u8*) (&del->children[del_num+1]); - dst = (u8*) (&del->children[del_num]); - len = (del->child_count - del_num) * sizeof(INDEX_ENTRY*); - - //ntfs_log_debug("src = %d\n", src - (u8*) del->children); - //ntfs_log_debug("dst = %d\n", dst - (u8*) del->children); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - src = (u8*) (&del->sub_nodes[del_num+1]); - dst = (u8*) (&del->sub_nodes[del_num]); - len = (del->child_count - del_num) * sizeof(struct ntfs_dt*); - - //ntfs_log_debug("src = %d\n", src - (u8*) del->children); - //ntfs_log_debug("dst = %d\n", dst - (u8*) del->children); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - //ntfs_log_debug("del_num = %d\n", del_num); - for (i = del_num; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_ie->length); - - if (!ntfs_dt_create_children2(del, del->child_count)) - return FALSE; - - //utils_dump_mem(del->data, 0, del->data_len, DM_DEFAULTS); - -#if 0 - off = (u8*)del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - ntfs_log_debug("%2d %4d ", i, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - ntfs_log_debug("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print(del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - ntfs_log_debug(" (%d)\n", del_ie->length); - } - ntfs_log_debug("total = %d\n", off); - ntfs_log_debug("\n"); -#endif - - del->changed = TRUE; - - ntfs_log_debug("Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n", del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); - - if (del->child_count < 2) { - ntfs_log_debug("indx is empty\n"); - ntfs_bmp_set_range(del->dir->bitmap, del->vcn, 1, 0); - } - - return TRUE; -} - -/** - * ntfs_dt_alloc_add - Add an index entry to an index allocation - * @parent: - * @index_num: - * @ie: - * @child: - * - * Description... - * - * Returns: - */ -int ntfs_dt_alloc_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) -{ - INDEX_BLOCK *block; - INDEX_ENTRY *entry; - int need; - int space; - u8 *src; - u8 *dst; - int len; - - if (!parent || !ie) - return 0; - ntfs_log_trace ("\n"); - - block = (INDEX_BLOCK*) parent->data; - - need = ie->length; - space = parent->data_len - block->index.index_length - 24; - - ntfs_log_debug("need %d, have %d\n", need, space); - if (need > space) { - ntfs_log_debug("no room\n"); - return 0; - } - - //utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - src = (u8*) parent->children[index_num]; - dst = src + need; - len = parent->data + parent->data_len - src - space; - //ntfs_log_debug("src = %d\n", src - parent->data); - //ntfs_log_debug("dst = %d\n", dst - parent->data); - //ntfs_log_debug("len = %d\n", len); - - memmove(dst, src, len); - - dst = src; - src = (u8*) ie; - len = need; - - memcpy(dst, src, len); - - block->index.index_length += len; - - dst = parent->data + block->index.index_length + 24; - len = parent->data_len - block->index.index_length - 24; - - memset(dst, 0, len); - - //realloc children, sub_nodes - ntfs_dt_create_children2(parent, parent->child_count + 1); - - // regen children pointers - parent->child_count = 0; - - src = parent->data + 0x18 + parent->header->entries_offset; - len = parent->data_len - 0x18 - parent->header->entries_offset; - - while (src < (parent->data + parent->data_len)) { - entry = (INDEX_ENTRY*) src; - - parent->children[parent->child_count] = entry; - parent->child_count++; - - if (entry->flags & INDEX_ENTRY_END) - break; - - src += entry->length; - } - ntfs_log_debug("count = %d\n", parent->child_count); - - src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; - dst = (u8*) &parent->sub_nodes[index_num]; - len = (parent->child_count - index_num - 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - //insert sub_node pointer - parent->sub_nodes[index_num] = child; - - //utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - return 0; -} - -/** - * ntfs_dt_root_add - Add an index entry to an index root - * @parent: - * @index_num: - * @ie: - * @child: - * - * Description... - * - * Returns: - */ -int ntfs_dt_root_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) -{ - INDEX_ROOT *root; - INDEX_ENTRY *entry; - int need; - int space; - u8 *attr; - u8 *src; - u8 *dst; - int len; - - if (!parent || !ie) - return -1; - ntfs_log_trace ("\n"); - - root = (INDEX_ROOT*) parent->data; - - //utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - need = ie->length; - space = ntfs_mft_free_space(parent->dir); - - ntfs_log_debug("need %d, have %d\n", need, space); - if (need > space) { - ntfs_log_debug("no room\n"); - return -1; - } - - attr = malloc(parent->data_len + need); - - src = parent->data; - dst = attr; - len = root->index.entries_offset + 16; - - memcpy(dst, src, len); - - dst += len; - src = (u8*) ie; - len = ie->length; - - memcpy(dst, src, len); - - dst += len; - src = (u8*) parent->children[index_num]; - len = parent->data + parent->data_len - src; - - memcpy(dst, src, len); - - free(parent->data); - parent->data = attr; - parent->data_len += need; - - ntfs_log_debug("parent data len = %d\n", parent->data_len); - - root = (INDEX_ROOT*) parent->data; - root->index.index_length = parent->data_len - 16; - root->index.allocated_size = parent->data_len - 16; - - //utils_dump_mem(parent->data, 0, parent->data_len, DM_DEFAULTS); - //ntfs_log_debug("\n"); - - ntfs_mft_resize_resident(parent->dir->inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4, parent->data, parent->data_len); - parent->changed = TRUE; - - //realloc children, sub_nodes - ntfs_dt_create_children2(parent, parent->child_count + 1); - - // regen children pointers - parent->child_count = 0; - - src = parent->data + 0x18 + parent->header->entries_offset; - len = parent->data_len - 0x18 - parent->header->entries_offset; - - // XXX can we rebase the children more simply? (in alloc_add too) - while (src < (parent->data + parent->data_len)) { - entry = (INDEX_ENTRY*) src; - - parent->children[parent->child_count] = entry; - parent->child_count++; - - if (entry->flags & INDEX_ENTRY_END) - break; - - src += entry->length; - } - ntfs_log_debug("count = %d\n", parent->child_count); - - src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; - dst = (u8*) &parent->sub_nodes[index_num]; - len = (parent->child_count - index_num - 1) * sizeof(struct ntfs_dt*); - - memmove(dst, src, len); - - //insert sub_node pointer - parent->sub_nodes[index_num] = child; - - return 0; -} - -/** - * ntfs_dt_add2 - Add an index entry to a directory-tree - * @ie: - * @suc: - * @suc_num: - * @ded: - * - * Description... - * - * Returns: - */ -int ntfs_dt_add2(INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded) -{ - int need; - int space; - int median; - struct ntfs_dt *new = NULL; - struct ntfs_dt *chl; - INDEX_ENTRY *med_ie = NULL; - //FILE_NAME_ATTR *file; - VCN vcn = 0; - //int i; - - if (!ie || !suc) - return -1; - ntfs_log_trace ("\n"); - - ntfs_log_debug("Add key to leaf\n"); - - //utils_dump_mem(suc->data, 0, suc->data_len, DM_DEFAULTS); - - chl = NULL; -ascend: - //XXX replace with while/break? - -#if 0 - for (; ded; ded = ded->sub_nodes[0]) { - ntfs_log_debug("\tded vcn = %lld\n", ded->vcn); - } -#endif - - /* - * ADD - * room in current node? - * yes, add, done - * no, split, ascend - */ - need = ie->length; - - if (ntfs_dt_isroot(suc)) - space = ntfs_dt_root_freespace(suc); - else - space = ntfs_dt_alloc_freespace(suc); - - ntfs_log_debug("\tneed %d\n", need); - ntfs_log_debug("\tspace %d\n", space); - - if (space >= need) { - //ntfs_log_critical("index = %d\n", suc_num); - //ntfs_log_debug("prev inode = %p\n", suc->inodes[suc_num-1]); - //ntfs_log_debug("curr inode = %p\n", suc->inodes[suc_num]); - ntfs_log_debug("count = %d\n", suc->child_count); - if (ntfs_dt_isroot(suc)) - ntfs_dt_root_add(suc, suc_num, ie, chl); - else - ntfs_dt_alloc_add(suc, suc_num, ie, chl); - ntfs_log_debug("count = %d\n", suc->child_count); - //goto done; - return suc_num; //XXX this is probably off-by-one - } - - /* - * SPLIT - * any dead? - * yes reuse - * no alloc - */ - if (ded) { - new = ded; - vcn = ded->vcn; - ded = ded->sub_nodes[0]; - ntfs_log_debug("\treusing vcn %lld\n", new->vcn); - } else { - ntfs_mft_add_index(suc->dir); - /* - * ALLOC - * any unused records? - * yes, enable first - * no, extend - */ - /* - * ENABLE - * modify bitmap - * init indx record - */ - /* - * EXTEND - * room in bitmap - * yes, do nothing - * no, extend bitmap - * extend alloc - */ - /* - * EXTEND BITMAP - * extend bitmap - * init bitmap - */ - } - - //ntfs_log_debug("\tnode has %d children\n", suc->child_count); - - // initialise new node - // XXX ntfs_dt_initialise(new, vcn); - - goto done; - - // find median key - median = (suc->child_count+1) / 2; - med_ie = ntfs_ie_copy(suc->children[median]); - //file = &med_ie->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n"); - - ntfs_ie_free(med_ie); - med_ie = NULL; - - //ntfs_log_debug("suc key count = %d\n", suc->child_count); - //ntfs_log_debug("new key count = %d\n", new->child_count); - - //ntfs_log_debug("median's child = %p\n", suc->sub_nodes[median]); - // need to pass the child when ascending - chl = suc->sub_nodes[median]; - - // transfer keys - if (ntfs_dt_transfer(suc, new, 0, median-1) < 0) - goto done; - - //ntfs_log_debug("suc key count = %d\n", suc->child_count); - //ntfs_log_debug("new key count = %d\n", new->child_count); - - //file = &suc->children[0]->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n"); - - // can this be a root node? - if (ntfs_dt_isroot(suc)) - ntfs_dt_root_remove(suc, 0); - else - ntfs_dt_alloc_remove(suc, 0); - - //file = &suc->children[0]->key.file_name; ntfs_log_debug("\tmed name: "); ntfs_name_print(file->file_name, file->file_name_length); ntfs_log_debug("\n"); - //ntfs_log_debug("suc key count = %d\n", suc->child_count); - //ntfs_log_debug("new key count = %d\n", new->child_count); - - // remove the median key - - // split when median has children - // median child given to new ! - // median child is new - // ascend - - med_ie = ntfs_ie_set_vcn(med_ie, new->vcn); - if (!med_ie) - goto done; - - //ntfs_log_debug("median child = %lld\n", ntfs_ie_get_vcn(med_ie)); - //ntfs_log_debug("new's vcn = %lld\n", new->vcn); - - // adjust parents - // attach new to median - // escape clause for root node? - // goto ascend - - // ie = insert - // child = child - // suc = successor - // suc_num = insert point - - ie = med_ie; - suc = suc->parent; - suc_num = 0; - - //ntfs_log_debug("\n"); - ntfs_log_debug("Ascend\n"); - goto ascend; -done: - return 0; -} - - -#endif /* NTFS_RICH */ - From c654fca276adb3e2282c91ca47e4fac1b36ec497 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 22 Jul 2006 20:41:07 +0000 Subject: [PATCH 011/289] fix CVS dir presense after "make dist" --- test/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Makefile.am b/test/Makefile.am index 8ea5ea5d..f16d5ea5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -57,3 +57,6 @@ testf: runlist diff -qs {runlist-data/,}frag$$i; \ done +dist-hook: + rm -rf `find $(distdir)/runlist-data -name CVS` + From 179966fb0c2ca65488912efb921b12c2c6c974f3 Mon Sep 17 00:00:00 2001 From: aia21 Date: Sun, 23 Jul 2006 21:43:08 +0000 Subject: [PATCH 012/289] Fix long standing stupendously stupid bug in libntfs/attrib.c:: ntfs_external_attr_find() and also port a bugfix from the advanced ntfs kernel driver to the same function. (Anton) --- ChangeLog | 3 +++ libntfs/attrib.c | 13 +++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0d3175fe..b18d8427 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ xx/xx/xxxx - x.xx.x - - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) + - Fix long standing stupendously stupid bug in libntfs/attrib.c:: + ntfs_external_attr_find() and also port a bugfix from the advanced + ntfs kernel driver to the same function. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 904aa20a..36b09eb7 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -2037,15 +2037,14 @@ is_enumeration: ctx->ntfs_ino = ni; ctx->mrec = ni->mrec; } - ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec + - le16_to_cpu(ctx->mrec->attrs_offset)); } + a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec + + le16_to_cpu(ctx->mrec->attrs_offset)); /* * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the * mft record containing the attribute represented by the * current al_entry. - */ - /* + * * We could call into ntfs_attr_find() to find the right * attribute in this mft record but this would be less * efficient and not quite accurate as ntfs_attr_find() ignores @@ -2054,9 +2053,7 @@ is_enumeration: * a proper match has been found in the attribute list entry * above, the comparison can now be optimized. So it is worth * re-implementing a simplified ntfs_attr_find() here. - */ - a = ctx->attr; - /* + * * Use a manual loop so we can still use break and continue * with the same meanings as above. */ @@ -2065,7 +2062,7 @@ do_next_attr_loop: le32_to_cpu(ctx->mrec->bytes_allocated)) break; if (a->type == AT_END) - continue; + break; if (!a->length) break; if (al_entry->instance != a->instance) From 858034e3227f6723b2f5f5ea67a26a9ebfad44df Mon Sep 17 00:00:00 2001 From: aia21 Date: Mon, 24 Jul 2006 08:48:40 +0000 Subject: [PATCH 013/289] Cvs checkin email test... --- NEWS | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 0f51ea3a..9dea75ff 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Current news ============ +Older news +========== + mkntfs now creates NTFS 3.1 (Windows XP) volumes by default. The old NTFS 1.2 format is now deprecated and whilst it can still be specified using a command line option, it will be removed in a future release. @@ -8,14 +11,3 @@ line option, it will be removed in a future release. ntfsmount can create/delete/move files and directories! It is not a full implementation, thus sometimes it will say 'Operation is not supported', nothing bad will happen to user data in this case. (Yura Pakhuchiy) - -Older news -========== - -Add new utility: ntfsmount. It is a FUSE module that uses on libntfs. So, -you need FUSE 2.3 to compile it. This module supports file overwrite including -changing the file size and can read/write/add/remove named data streams via -"file:stream" interface and list them via "ntfs.streams.list" extended -attribute (this only if xattr support is enabled). (Yura Pakhuchiy) - -Moved back from BitKeeper to CVS on SF.net. From 836159727561a2ada8dbf23b0d131f8b00702b82 Mon Sep 17 00:00:00 2001 From: aia21 Date: Mon, 24 Jul 2006 08:57:30 +0000 Subject: [PATCH 014/289] And another test... --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b18d8427..cbb2116b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -xx/xx/xxxx - x.xx.x - +xx/xx/xxxx - x.xx.x - . - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) From f3117bf03af3958df304f2c41e50b8bbeb3f198a Mon Sep 17 00:00:00 2001 From: aia21 Date: Mon, 24 Jul 2006 08:59:55 +0000 Subject: [PATCH 015/289] Hopefully final test. --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cbb2116b..c37d359a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -xx/xx/xxxx - x.xx.x - . +xx/xx/2006 - x.xx.x - . - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) From 0873318cbbedceaca53596802876e26f42b2141e Mon Sep 17 00:00:00 2001 From: aia21 Date: Thu, 27 Jul 2006 08:38:17 +0000 Subject: [PATCH 016/289] Yura uses ntfs_attr_lookup() in a way it never was anticipated to work so my fix broke his way of working. This is a middle ground where both should work. This still leaves a bug in collation of attribute list entries though which needs to be investigated and fixed... --- libntfs/attrib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 36b09eb7..f1860e85 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1,7 +1,7 @@ /** * attrib.c - Attribute handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2004-2006 Yura Pakhuchiy * @@ -2062,7 +2062,7 @@ do_next_attr_loop: le32_to_cpu(ctx->mrec->bytes_allocated)) break; if (a->type == AT_END) - break; + continue; if (!a->length) break; if (al_entry->instance != a->instance) From d5ce628f10939885dd33f1fd574e992fdd26157d Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 27 Jul 2006 18:12:23 +0000 Subject: [PATCH 017/289] commit some fix to runlsi handling code from ntfs-3g Rich/Anton can you please review it? --- libntfs/runlist.c | 74 +++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/libntfs/runlist.c b/libntfs/runlist.c index 130dda88..dd5fc043 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -3,6 +3,7 @@ * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon + * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2004 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or @@ -1580,73 +1581,64 @@ err_out: int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) { runlist *rl; - BOOL is_end; + BOOL is_end = FALSE; if (!arl || !*arl) { errno = EINVAL; + ntfs_log_perror("rl_truncate error: arl: %p *arl: %p", arl, *arl); return -1; } + rl = *arl; + if (start_vcn < rl->vcn) { - // FIXME: Eeek! BUG() - ntfs_log_trace("Eeek! start_vcn lies outside front of runlist! " - "Aborting.\n"); - errno = EIO; + errno = EINVAL; + ntfs_log_perror("Start_vcn lies outside front of runlist"); return -1; } + /* Find the starting vcn in the run list. */ while (rl->length) { if (start_vcn < rl[1].vcn) break; rl++; } + if (!rl->length) { - // FIXME: Weird, probably a BUG()! - ntfs_log_trace("Weird! Asking to truncate already truncated " - "runlist?!? Abort.\n"); - errno = EIO; - return -1; - } - if (start_vcn < rl->vcn) { - // FIXME: Eeek! BUG() - ntfs_log_trace("Eeek! start_vcn < rl->vcn! Aborting.\n"); errno = EIO; + ntfs_log_trace("Truncating already truncated runlist?\n"); return -1; } + + /* Truncate the run. */ + rl->length = start_vcn - rl->vcn; + + /* + * If a run was partially truncated, make the following runlist + * element a terminator instead of the truncated runlist + * element itself. + */ if (rl->length) { - is_end = FALSE; - /* Truncate the run. */ - rl->length = start_vcn - rl->vcn; - /* - * If a run was partially truncated, make the following runlist - * element a terminator instead of the truncated runlist - * element itself. - */ - if (rl->length) { - ++rl; - if (!rl->length) - is_end = TRUE; - rl->vcn = start_vcn; - rl->length = 0; - } - } else - is_end = TRUE; + ++rl; + if (!rl->length) + is_end = TRUE; + rl->vcn = start_vcn; + rl->length = 0; + } rl->lcn = (LCN)LCN_ENOENT; - /* Reallocate memory if necessary. */ - if (!is_end) { + /** + * Reallocate memory if necessary. + * FIXME: Below code is broken, because runlist allocations must be + * a multiply of 4096. The code caused crashes and corruptions. + */ +/* + if (!is_end) { size_t new_size = (rl - *arl + 1) * sizeof(runlist_element); rl = realloc(*arl, new_size); if (rl) *arl = rl; - else if (!new_size) - *arl = NULL; - else { - // FIXME: Eeek! - ntfs_log_trace("Eeek! Failed to reallocate runlist buffer! " - "Continuing regardless and returning success.\n"); - } } - /* Done! */ +*/ return 0; } From bb5991cb36bd049711f33abb3116cdb1526beb72 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 27 Jul 2006 18:44:08 +0000 Subject: [PATCH 018/289] Set vol->mft_ni->flags. (Szaka) --- libntfs/volume.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libntfs/volume.c b/libntfs/volume.c index 4b809dd5..a2fc9d98 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -2,8 +2,9 @@ * volume.c - NTFS volume handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2006 Anton Altaparmakov - * Copyright (c) 2002-2005 Szabolcs Szakacsits + * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2006 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -141,6 +142,7 @@ static int ntfs_mft_load(ntfs_volume *vol) MFT_RECORD *mb = NULL; ntfs_attr_search_ctx *ctx = NULL; ATTR_RECORD *a; + STANDARD_INFORMATION *std_info; int eo; /* Manually setup an ntfs_inode. */ @@ -214,6 +216,11 @@ static int ntfs_mft_load(ntfs_volume *vol) goto io_error_exit; } mft_has_no_attr_list: + /* Receive attributes from STANDARD_INFORMATION. */ + std_info = ntfs_attr_readall(vol->mft_ni, AT_STANDARD_INFORMATION, + AT_UNNAMED, 0, NULL); + vol->mft_ni->flags = std_info->file_attributes; + /* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */ /* Get an ntfs attribute for $MFT/$DATA and set it up, too. */ From 2338377ec368eb50f1c2896d035e3d3f4fed3934 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 28 Jul 2006 23:15:35 +0000 Subject: [PATCH 019/289] bit move verbose in ntfs_delete() --- libntfs/dir.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index a7ea2a25..e7859c2a 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1491,6 +1491,8 @@ search: errno = 0; fn = (FILE_NAME_ATTR*)((u8*)actx->attr + le16_to_cpu(actx->attr->value_offset)); + ntfs_log_trace("Found filename with instance number %d.\n", + le16_to_cpu(actx->attr->instance)); if (looking_for_dos_name) { if (fn->file_name_type == FILE_NAME_DOS) break; @@ -1513,6 +1515,8 @@ search: if (fn->file_name_type == FILE_NAME_WIN32) { looking_for_dos_name = TRUE; ntfs_attr_reinit_search_ctx(actx); + ntfs_log_trace("Restart search. " + "Looking for DOS name.\n"); continue; } if (fn->file_name_type == FILE_NAME_DOS) @@ -1528,6 +1532,7 @@ search: if (errno == ENOENT && case_sensitive_match) { case_sensitive_match = FALSE; ntfs_attr_reinit_search_ctx(actx); + ntfs_log_trace("Restart search. Ignore case."); goto search; } ntfs_log_error("Failed to find requested filename in FILE_NAME " @@ -1562,6 +1567,7 @@ search: } ntfs_attr_close(na); } + ntfs_log_trace("Found!\n"); /* Search for such FILE_NAME in index. */ ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); if (!ictx) @@ -1596,8 +1602,11 @@ search: looking_for_dos_name = FALSE; looking_for_win32_name = TRUE; ntfs_attr_reinit_search_ctx(actx); + ntfs_log_trace("DOS name deleted. " + "Now search for WIN32 name.\n"); goto search; - } + } else + ntfs_log_trace("Deleted.\n"); /* TODO: Update object id, quota and securiry indexes if required. */ /* * If hard link count is not equal to zero then we are done. In other @@ -1616,13 +1625,13 @@ search: if (!rl) { err = errno; ntfs_log_error("Failed to decompress runlist. " - "Leaving inconsistent metadata.\n"); + "Leaving damaged metadata.\n"); continue; } if (ntfs_cluster_free_from_rl(ni->vol, rl)) { err = errno; ntfs_log_error("Failed to free clusters. " - "Leaving inconsistent metadata.\n"); + "Leaving damaged metadata.\n"); continue; } free(rl); From 47a2ca115448f10ca6abcad040d259282c7774c8 Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 2 Aug 2006 01:33:54 +0000 Subject: [PATCH 020/289] 80 chars per line cleanup --- libntfs/attrib.c | 165 ++++++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 74 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index f1860e85..9d5c2307 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -207,10 +207,11 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, errno = eo; } else if (r < rl[i].length << vol->cluster_size_bits) { - ntfs_log_debug(ESTR ": Ran out of input data.\n"); + ntfs_log_debug(ESTR": Ran out of " + "input data.\n"); errno = EIO; } else { - ntfs_log_debug(ESTR ": unknown error\n"); + ntfs_log_debug(ESTR": unknown error\n"); errno = EIO; } #undef ESTR @@ -244,7 +245,8 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, ntfs_log_perror(ESTR); errno = eo; } else if (r < rl[i].length << vol->cluster_size_bits) { - ntfs_log_debug(ESTR ": Ran out of input data.\n"); + ntfs_log_debug(ESTR ": Ran out of " + "input data.\n"); errno = EIO; } else { ntfs_log_debug(ESTR ": unknown error\n"); @@ -555,8 +557,9 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) /* Are we in the first extent? */ if (!next_vcn) { if (a->lowest_vcn) { - ntfs_log_trace("First extent of attribute has non " - "zero lowest_vcn. Inode is corrupt.\n"); + ntfs_log_trace("First extent of attribute has " + "non zero lowest_vcn. " + "Inode is corrupt.\n"); errno = EIO; goto err_out; } @@ -586,7 +589,8 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) if (!a) { err = errno; if (err == ENOENT) - ntfs_log_trace("Attribute not found. Inode is corrupt.\n"); + ntfs_log_trace("Attribute not found. " + "Inode is corrupt.\n"); else ntfs_log_trace("Inode is corrupt.\n"); errno = err; @@ -596,7 +600,8 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) ntfs_log_trace("Failed to load the complete run list for the " "attribute. Bug or corrupt inode.\n"); ntfs_log_trace("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n", - (long long)highest_vcn, (long long)last_vcn - 1); + (long long)highest_vcn, + (long long)last_vcn - 1); errno = EIO; goto err_out; } @@ -767,8 +772,8 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) ntfs_volume *vol; runlist_element *rl; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " - "0x%llx.\n", (unsigned long long)na->ni->mft_no, + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, " + "count 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, (long long)pos, (long long)count); if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; @@ -888,8 +893,9 @@ res_err_out: to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs); retry: - ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, lcn 0x%llx, " - "ofs 0x%llx.\n", to_read, rl->vcn, rl->lcn, ofs); + ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, " + "lcn 0x%llx, ofs 0x%llx.\n", to_read, rl->vcn, + rl->lcn, ofs); br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + ofs, to_read, b); /* If everything ok, update progress counters and continue. */ @@ -1056,8 +1062,9 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) to_write, buf); if (written <= 0) { err = errno; - ntfs_log_trace("Failed to zero space between " - "initialized size and @pos.\n"); + ntfs_log_trace("Failed to zero space " + "between initialized " + "size and @pos.\n"); free(buf); errno = err; goto err_out; @@ -1175,7 +1182,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) /* The buffer is non zero, instantiate the hole. */ cur_vcn = rl->vcn; from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits); - ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n", + ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n", cur_vcn); /* * Map whole runlist to be able update mapping pairs @@ -1229,8 +1236,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) lcn_seek_from, DATA_ZONE); if (!rlc) { eo = errno; - ntfs_log_trace("Failed to allocate clusters for hole " - "instantiating.\n"); + ntfs_log_trace("Failed to allocate clusters " + "for hole instantiating.\n"); errno = eo; goto err_out; } @@ -1242,7 +1249,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) if (ntfs_cluster_free_from_rl(vol, rlc)) { ntfs_log_trace("Failed to free just " "allocated clusters. Leaving " - "inconstant metadata. Run chkdsk\n"); + "inconstant metadata. " + "Run chkdsk\n"); } errno = eo; goto err_out; @@ -1285,7 +1293,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) buf = malloc(ofs); if (!buf) { ntfs_log_trace("Not enough memory to " - "allocate %lld bytes.\n", ofs); + "allocate %lld " + "bytes.\n", ofs); errno = ENOMEM; goto err_out; } @@ -1294,7 +1303,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) vol->cluster_size_bits, ofs, buf) < 0) { eo = errno; - ntfs_log_trace("Failed to zero area.\n"); + ntfs_log_trace("Failed to zero " + "area.\n"); free(buf); errno = eo; goto err_out; @@ -1451,9 +1461,9 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, s64 br; u8 *end; - ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", - (unsigned long long)na->ni->mft_no, na->type, - (long long)pos); + ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, " + "pos 0x%llx.\n", (unsigned long long)na->ni->mft_no, + na->type, (long long)pos); if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { errno = EINVAL; return -1; @@ -1504,9 +1514,9 @@ s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, { s64 written, i; - ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", - (unsigned long long)na->ni->mft_no, na->type, - (long long)pos); + ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, " + "pos 0x%llx.\n", (unsigned long long)na->ni->mft_no, + na->type, (long long)pos); if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { errno = EINVAL; return -1; @@ -1913,8 +1923,9 @@ find_attr_list_attr: return rc; /* Not found?!? Absurd! Must be a bug... )-: */ - ntfs_log_trace("BUG! Attribute list attribute not found but " - "it exists! Returning error (EINVAL).\n"); + ntfs_log_trace("BUG! Attribute list attribute not " + "found but it exists! " + "Returning error (EINVAL).\n"); errno = EINVAL; return -1; } @@ -2031,7 +2042,8 @@ is_enumeration: ni = ntfs_extent_inode_open(base_ni, al_entry->mft_reference); if (!ni) { - ntfs_log_perror("Failed to map extent inode"); + ntfs_log_perror("Failed to map extent " + "inode"); break; } ctx->ntfs_ino = ni; @@ -2700,7 +2712,8 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, " "dataruns_size %d, flags 0x%x.\n", (long long) ni->mft_no, (unsigned) type, - (long long) lowest_vcn, dataruns_size, (unsigned) flags); + (long long) lowest_vcn, dataruns_size, + (unsigned) flags); if (!ni || dataruns_size <= 0 || (!name && name_len)) { errno = EINVAL; @@ -2712,7 +2725,8 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, if (errno == EPERM) ntfs_log_trace("Attribute can't be non resident.\n"); else - ntfs_log_trace("ntfs_attr_can_be_non_resident failed.\n"); + ntfs_log_trace("ntfs_attr_can_be_non_resident() " + "failed.\n"); errno = err; return -1; } @@ -2801,8 +2815,8 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, lowest_vcn, NULL, 0, ctx)) { err = errno; - ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant " - "metadata.\n"); + ntfs_log_trace("Attribute lookup failed. Probably leaving " + "inconstant metadata.\n"); ntfs_attr_put_search_ctx(ctx); errno = err; return -1; @@ -2852,12 +2866,12 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) /* Remove attribute itself. */ if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) { - ntfs_log_trace("Couldn't remove attribute record. Bug or damaged MFT " - "record.\n"); + ntfs_log_trace("Couldn't remove attribute record. " + "Bug or damaged MFT record.\n"); if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) if (ntfs_attrlist_entry_add(ni, ctx->attr)) - ntfs_log_trace("Rollback failed. Leaving inconstant " - "metadata.\n"); + ntfs_log_trace("Rollback failed. Leaving " + "inconstant metadata.\n"); err = EIO; return -1; } @@ -2924,8 +2938,9 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) al_rl = ntfs_mapping_pairs_decompress(base_ni->vol, ctx->attr, NULL); if (!al_rl) { - ntfs_log_trace("Couldn't decompress attribute list " - "runlist. Succeed anyway.\n"); + ntfs_log_trace("Couldn't decompress attribute " + "list runlist. Return success " + "anyway.\n"); return 0; } if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) { @@ -2942,8 +2957,8 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) * complain if it find MFT record with attribute list, * but without extents. */ - ntfs_log_trace("Couldn't remove attribute list. Succeed " - "anyway.\n"); + ntfs_log_trace("Couldn't remove attribute list. " + "Return success anyway.\n"); return 0; } } @@ -3001,7 +3016,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, if (ntfs_attr_size_bounds_check(ni->vol, type, size)) { err = errno; if (err == ERANGE) { - ntfs_log_trace("Size bounds check failed. Aborting...\n"); + ntfs_log_trace("Size bounds check failed.\n"); } else if (err == ENOENT) { ntfs_log_trace("Invalid attribute type. Aborting...\n"); err = EIO; @@ -3014,12 +3029,13 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, if (ntfs_attr_can_be_non_resident(ni->vol, type)) { if (errno != EPERM) { err = errno; - ntfs_log_trace("ntfs_attr_can_be_non_resident failed.\n"); + ntfs_log_trace("ntfs_attr_can_be_non_resident() " + "failed.\n"); goto err_out; } /* @val is mandatory. */ if (!val) { - ntfs_log_trace("val is mandatory for always resident " + ntfs_log_trace("@val is mandatory for always resident " "attributes.\n"); errno = EINVAL; return -1; @@ -3144,7 +3160,7 @@ add_attr_record: ntfs_log_trace("Failed to initialize just added attribute.\n"); if (ntfs_attr_rm(na)) { ntfs_log_trace("Failed to remove just added attribute. " - "Probably leaving inconstant metadata.\n"); + "Probably leaving damaged metadata.\n"); ntfs_attr_close(na); } goto err_out; @@ -3201,8 +3217,8 @@ int ntfs_attr_rm(ntfs_attr *na) if (ntfs_attr_map_whole_runlist(na)) return -1; if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { - ntfs_log_trace("Failed to free cluster allocation. Leaving " - "inconstant metadata.\n"); + ntfs_log_trace("Failed to free cluster allocation. " + "Leaving inconstant metadata.\n"); ret = -1; } } @@ -3214,15 +3230,15 @@ int ntfs_attr_rm(ntfs_attr *na) while (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (ntfs_attr_record_rm(ctx)) { - ntfs_log_trace("Failed to remove attribute extent. Leaving " - "inconstant metadata.\n"); + ntfs_log_trace("Failed to remove attribute extent. " + "Leaving inconstant metadata.\n"); ret = -1; } ntfs_attr_reinit_search_ctx(ctx); } if (errno != ENOENT) { - ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant " - "metadata.\n"); + ntfs_log_trace("Attribute lookup failed. " + "Probably leaving inconstant metadata.\n"); ret = -1; } @@ -3301,7 +3317,7 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, */ if (a->name_length && le16_to_cpu(a->name_offset) >= le16_to_cpu(a->value_offset)) { - ntfs_log_trace("Eeek! Name is placed after the attribute value. " + ntfs_log_trace("Name is placed after the attribute value. " "Corrupted inode. Run chkdsk. Aborting...\n"); errno = EIO; return -1; @@ -3311,7 +3327,7 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, new_size + 7) & ~7) < 0) { if (errno != ENOSPC) { int eo = errno; - ntfs_log_trace("Eeek! Attribute record resize failed. " + ntfs_log_trace("Attribute record resize failed. " "Aborting...\n"); errno = eo; } @@ -3352,8 +3368,8 @@ int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) return -1; } - ntfs_log_trace("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no " - "0x%llx, ni->mft_no 0x%llx.\n", + ntfs_log_trace("Entering for ctx->attr->type 0x%x, " + "ctx->ntfs_ino->mft_no 0x%llx, ni->mft_no 0x%llx.\n", (unsigned) le32_to_cpu(ctx->attr->type), (long long) ctx->ntfs_ino->mft_no, (long long) ni->mft_no); @@ -3362,8 +3378,8 @@ int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) return 0; if (!ctx->al_entry) { - ntfs_log_trace("Inode should contain attribute list to use this " - "function.\n"); + ntfs_log_trace("Inode should contain attribute list to use " + "this function.\n"); errno = EINVAL; return -1; } @@ -3460,8 +3476,8 @@ int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) base_ni = ctx->ntfs_ino; if (!NInoAttrList(base_ni)) { - ntfs_log_trace("Inode should contain attribute list to use this " - "function.\n"); + ntfs_log_trace("Inode should contain attribute list to use " + "this function.\n"); errno = EINVAL; return -1; } @@ -3564,7 +3580,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, */ if (a->name_length && le16_to_cpu(a->name_offset) >= le16_to_cpu(a->value_offset)) { - ntfs_log_trace("Eeek! Name is placed after the attribute value. " + ntfs_log_trace("Name is placed after the attribute value. " "Corrupted inode. Run chkdsk. Aborting...\n"); errno = EIO; return -1; @@ -3611,7 +3627,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, (u8*)a + le16_to_cpu(a->value_offset)); if (bw != le32_to_cpu(a->value_length)) { err = errno; - ntfs_log_debug("Eeek! Failed to write out attribute value " + ntfs_log_debug("Failed to write out attribute value " "(bw = %lli, errno = %i). " "Aborting...\n", (long long)bw, err); if (bw >= 0) @@ -3623,7 +3639,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); if (mp_size < 0) { err = errno; - ntfs_log_debug("Eeek! Failed to get size for mapping pairs array. " + ntfs_log_debug("Failed to get size for mapping pairs array. " "Aborting...\n"); goto cluster_free_err_out; } @@ -3641,7 +3657,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { err = errno; if (err != ENOSPC) { - ntfs_log_trace("Eeek! Failed to resize attribute record. " + ntfs_log_trace("Failed to resize attribute record. " "Aborting...\n"); } goto cluster_free_err_out; @@ -3695,7 +3711,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, cluster_free_err_out: if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0) - ntfs_log_trace("Eeek! Failed to release allocated clusters in error " + ntfs_log_trace("Failed to release allocated clusters in error " "code path. Leaving inconsistent metadata...\n"); NAttrClearNonResident(na); na->allocated_size = na->data_size; @@ -3775,8 +3791,8 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) /* Error! If not enough space, just continue. */ if (errno != ENOSPC) { err = errno; - ntfs_log_trace("Eeek! Failed to resize resident part of " - "attribute. Aborting...\n"); + ntfs_log_trace("Eeek! Failed to resize resident part " + "of attribute. Aborting...\n"); goto put_err_out; } } @@ -3843,8 +3859,9 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD, non_resident_end) + 8)) { err = errno; - ntfs_log_trace("Couldn't free space in the MFT record to " - "make attribute list non resident.\n"); + ntfs_log_trace("Couldn't free space in the MFT record " + "to make attribute list non " + "resident.\n"); errno = err; return -1; } @@ -3954,7 +3971,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) /* Should be called for the first extent of the attribute. */ if (sle64_to_cpu(a->lowest_vcn)) { - ntfs_log_trace("Eeek! Should be called for the first extent of the " + ntfs_log_trace("Should be called for the first extent of the " "attribute. Aborting...\n"); err = EINVAL; return -1; @@ -3962,7 +3979,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) /* Some preliminary sanity checking. */ if (!NAttrNonResident(na)) { - ntfs_log_trace("Eeek! Trying to make resident attribute resident. " + ntfs_log_trace("Trying to make resident attribute resident. " "Aborting...\n"); errno = EINVAL; return -1; @@ -3984,15 +4001,15 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) */ if (a->name_length && le16_to_cpu(a->name_offset) >= le16_to_cpu(a->mapping_pairs_offset)) { - ntfs_log_trace("Eeek! Damaged attribute. Name is placed after the " - "mapping pairs array. Run chkdsk. Aborting...\n"); + ntfs_log_trace("Damaged attribute. Name is placed after the " + "mapping pairs array. Run chkdsk. Aborting.\n"); errno = EIO; return -1; } if (NAttrCompressed(na) || NAttrEncrypted(na)) { - ntfs_log_trace("Making compressed or encrypted files resident is not " - "implemented yet.\n"); + ntfs_log_trace("Making compressed or encrypted files resident " + "is not implemented yet.\n"); errno = EOPNOTSUPP; return -1; } @@ -4827,7 +4844,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) DATA_ZONE); if (!rl) { err = errno; - ntfs_log_trace("Eeek! Cluster allocation failed.\n"); + ntfs_log_trace("Cluster allocation failed.\n"); errno = err; return -1; } From b86f4a41c1830e6346ba2aafd2ee179d3894177f Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 2 Aug 2006 03:11:12 +0000 Subject: [PATCH 021/289] introduce ntfs_[cm]alloc --- include/ntfs/support.h | 34 +++++++++++++++++++++++++++++-- ntfsprogs/mkntfs.c | 46 +++++++++++++++--------------------------- 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 11844c31..46786d08 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -1,7 +1,9 @@ /* - * support.h - Useful definitions and macros. Part of the Linux-NTFS project. + * support.h - Various useful things. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2006 Szabolcs Szakacsits + * Copyright (c) 2006 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -22,6 +24,10 @@ #ifndef _NTFS_SUPPORT_H #define _NTFS_SUPPORT_H +#include + +#include "logging.h" + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -88,5 +94,29 @@ old_state; \ }) -#endif /* defined _NTFS_SUPPORT_H */ +/** + * ntfs_calloc, ntfs_malloc + * + * Return a pointer to the allocated memory or NULL if the request fails. + */ +static inline void *ntfs_calloc(size_t size) +{ + void *p; + + p = calloc(1, size); + if (!p) + ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); + return p; +} +static inline void *ntfs_malloc(size_t size) +{ + void *p; + + p = malloc(size); + if (!p) + ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); + return p; +} + +#endif /* defined _NTFS_SUPPORT_H */ diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 2a6684f2..fe887c6f 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -529,20 +529,6 @@ static time_t mkntfs_time(void) return 0; } -/** - * mkntfs_calloc - */ -static void *ntfs_calloc(size_t nmemb, size_t size) -{ - void *p; - - p = calloc(nmemb, size); - if (!p) - ntfs_log_perror("Failed to calloc() %lld bytes", - (long long)nmemb * size); - return p; -} - /** * append_to_bad_blocks */ @@ -674,7 +660,7 @@ static s64 ntfs_rlwrite(struct ntfs_device *dev, const runlist *rl, } if (delta) { int eo; - char *b = ntfs_calloc(1, delta); + char *b = ntfs_calloc(delta); if (!b) return -1; bytes_written = mkntfs_write(dev, b, delta); @@ -2449,7 +2435,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, err = add_attr_bitmap(m, name, name_len, ic, bmp, sizeof(bmp)); if (err) goto err_out; - ia_val = ntfs_calloc(1, index_block_size); + ia_val = ntfs_calloc(index_block_size); if (!ia_val) { err = -errno; goto err_out; @@ -2801,10 +2787,10 @@ static int initialize_secure(char *sds, u32 sds_size, MFT_RECORD *m) sdh_size += sizeof(SDH_INDEX_KEY) + sizeof(SDH_INDEX_DATA); sii_size = sizeof(INDEX_ENTRY_HEADER); sii_size += sizeof(SII_INDEX_KEY) + sizeof(SII_INDEX_DATA); - idx_entry_sdh = ntfs_calloc(1, sizeof(INDEX_ENTRY)); + idx_entry_sdh = ntfs_calloc(sizeof(INDEX_ENTRY)); if (!idx_entry_sdh) return -errno; - idx_entry_sii = ntfs_calloc(1, sizeof(INDEX_ENTRY)); + idx_entry_sii = ntfs_calloc(sizeof(INDEX_ENTRY)); if (!idx_entry_sii) { free(idx_entry_sdh); return -errno; @@ -2876,7 +2862,7 @@ static int initialize_quota(MFT_RECORD *m) err = 0; /* q index entry num 1 */ q1_size = 0x48; - idx_entry_q1 = ntfs_calloc(1, q1_size); + idx_entry_q1 = ntfs_calloc(q1_size); if (!idx_entry_q1) return errno; idx_entry_q1->data_offset = const_cpu_to_le16(0x14); @@ -2905,7 +2891,7 @@ static int initialize_quota(MFT_RECORD *m) return err; /* q index entry num 2 */ q2_size = 0x58; - idx_entry_q2 = ntfs_calloc(1, q2_size); + idx_entry_q2 = ntfs_calloc(q2_size); if (!idx_entry_q2) return errno; idx_entry_q2->data_offset = const_cpu_to_le16(0x14); @@ -2941,7 +2927,7 @@ static int initialize_quota(MFT_RECORD *m) if (err) return err; o_size = 0x28; - idx_entry_o = ntfs_calloc(1, o_size); + idx_entry_o = ntfs_calloc(o_size); if (!idx_entry_o) return errno; idx_entry_o->data_offset = const_cpu_to_le16(0x20); @@ -3182,7 +3168,7 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, } /* Insert the index entry for file_name in @idx. */ idx_size = (fn_size + 7) & ~7; - idx_entry_new = ntfs_calloc(1, idx_size + 0x10); + idx_entry_new = ntfs_calloc(idx_size + 0x10); if (!idx_entry_new) return -errno; idx_entry_new->indexed_file = ref_file; @@ -3765,7 +3751,7 @@ static BOOL mkntfs_initialize_bitmaps(void) ~(g_vol->cluster_size - 1); ntfs_log_debug("g_lcn_bitmap_byte_size = %i, allocated = %llu\n", g_lcn_bitmap_byte_size, i); - g_lcn_bitmap = ntfs_calloc(1, g_lcn_bitmap_byte_size); + g_lcn_bitmap = ntfs_calloc(g_lcn_bitmap_byte_size); if (!g_lcn_bitmap) return FALSE; /* @@ -3794,7 +3780,7 @@ static BOOL mkntfs_initialize_bitmaps(void) g_mft_bitmap_byte_size = (g_mft_bitmap_byte_size + 7) & ~7; ntfs_log_debug("mft_bitmap_size = %i, g_mft_bitmap_byte_size = %i\n", mft_bitmap_size, g_mft_bitmap_byte_size); - g_mft_bitmap = ntfs_calloc(1, g_mft_bitmap_byte_size); + g_mft_bitmap = ntfs_calloc(g_mft_bitmap_byte_size); if (!g_mft_bitmap) return FALSE; /* Create runlist for mft bitmap. */ @@ -4585,7 +4571,7 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_verbose("Creating $Boot (mft record 7)\n"); m = (MFT_RECORD*)(g_buf + 7 * g_vol->mft_record_size); - bs = ntfs_calloc(1, 8192); + bs = ntfs_calloc(8192); if (!bs) return FALSE; memcpy(bs, boot_array, sizeof(boot_array)); @@ -4744,19 +4730,19 @@ static BOOL mkntfs_create_root_structures(void) if (g_vol->minor_ver == 0) { buf_sds_first_size = 0x1E0; buf_sds_size = 0x40000 + buf_sds_first_size; - buf_sds_init = ntfs_calloc(1, buf_sds_first_size); + buf_sds_init = ntfs_calloc(buf_sds_first_size); if (!buf_sds_init) return FALSE; init_secure_30(buf_sds_init); } else { buf_sds_first_size = 0xFC; buf_sds_size = 0x40000 + buf_sds_first_size; - buf_sds_init = ntfs_calloc(1, buf_sds_first_size); + buf_sds_init = ntfs_calloc(buf_sds_first_size); if (!buf_sds_init) return FALSE; init_secure_31(buf_sds_init); } - buf_sds = ntfs_calloc(1, buf_sds_size); + buf_sds = ntfs_calloc(buf_sds_size); if (!buf_sds) { free(buf_sds_init); return FALSE; @@ -4989,7 +4975,7 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) } init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); if (g_vol->major_ver < 3) { - g_vol->attrdef = ntfs_calloc(1, 36000); + g_vol->attrdef = ntfs_calloc(36000); if (g_vol->attrdef) { memcpy(g_vol->attrdef, attrdef_ntfs12_array, sizeof(attrdef_ntfs12_array)); @@ -5029,7 +5015,7 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) if (!mkntfs_initialize_rl_boot()) goto done; /* Allocate a buffer large enough to hold the mft. */ - g_buf = ntfs_calloc(1, g_mft_size); + g_buf = ntfs_calloc(g_mft_size); if (!g_buf) goto done; /* Create runlist for $BadClus, $DATA named stream $Bad. */ From 9d0f9aec4c437cf83b43432e92e66154d0735629 Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 2 Aug 2006 03:12:34 +0000 Subject: [PATCH 022/289] Add new API ntfs_attr_exist() that checks whether attribute with selected type and name already present in inode. (Szaka) --- ChangeLog | 3 +++ include/ntfs/attrib.h | 3 +++ libntfs/attrib.c | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/ChangeLog b/ChangeLog index c37d359a..ee87f32f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,9 +2,12 @@ xx/xx/2006 - x.xx.x - . - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) + - Fix typo that lead to incorrect sparse file size calculation. (Yuval) - Fix long standing stupendously stupid bug in libntfs/attrib.c:: ntfs_external_attr_find() and also port a bugfix from the advanced ntfs kernel driver to the same function. (Anton) + - Add new API ntfs_attr_exist() that checks whether attribute with + selected type and name already present in inode. (Szaka) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index 27b3a833..a1502c99 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -317,6 +317,9 @@ 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_exist(ntfs_inode *ni, const ATTR_TYPES type, + ntfschar *name, u32 name_len); + // FIXME / TODO: Above here the file is cleaned up. (AIA) /** * get_attribute_value_length - return the length of the value of an attribute diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 9d5c2307..3e4f83c2 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -3,6 +3,7 @@ * * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon + * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2004-2006 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or @@ -5057,3 +5058,24 @@ out: return ret; } +/** + * ntfs_attr_exist - FIXME: description + */ +int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, + u32 name_len) +{ + ntfs_attr_search_ctx *ctx; + int ret; + + ntfs_log_trace("Entering.\n"); + + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return 0; + + ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, + ctx); + + ntfs_attr_put_search_ctx(ctx); + return !ret; +} From 08689c171e1c1fa65e3e855927a22399b0ae6d63 Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 2 Aug 2006 03:55:41 +0000 Subject: [PATCH 023/289] Merge index code from ntfs-3g. Clean it a bit and fix adding index allocation when index root in the base mft record. --- ChangeLog | 2 + configure.ac | 2 +- include/ntfs/index.h | 59 +- include/ntfs/types.h | 7 + libntfs/index.c | 2059 ++++++++++++++++++++++++++++++++---------- 5 files changed, 1621 insertions(+), 508 deletions(-) diff --git a/ChangeLog b/ChangeLog index ee87f32f..b20f151a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ xx/xx/2006 - x.xx.x - . ntfs kernel driver to the same function. (Anton) - Add new API ntfs_attr_exist() that checks whether attribute with selected type and name already present in inode. (Szaka) + - Extend ntfs_index_{add_filename,rm} to support almost all cases of + index operations. (Szaka, Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/configure.ac b/configure.ac index a1975eee..d7056501 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ # AC_PREREQ(2.59) -AC_INIT([ntfsprogs],[1.13.1],[linux-ntfs-dev@lists.sourceforge.net]) +AC_INIT([ntfsprogs],[3.0.0-WIP],[linux-ntfs-dev@lists.sourceforge.net]) # # Before making a release, the LTVERSION string should be modified. diff --git a/include/ntfs/index.h b/include/ntfs/index.h index 10465dd8..ecd53cfc 100644 --- a/include/ntfs/index.h +++ b/include/ntfs/index.h @@ -1,9 +1,10 @@ /* * index.h - Defines for NTFS index handling. Part of the Linux-NTFS project. * - * Copyright (c) 2004 Anton Altaparmakov - * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2006 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -30,24 +31,32 @@ #include "inode.h" #include "mft.h" +#define VCN_INDEX_ROOT_PARENT ((VCN)-2) + +#define MAX_PARENT_VCN 32 + /** * struct ntfs_index_context - * @ni: inode containing the @entry described by this context * @name: name of the index described by this context * @name_len: length of the index name - * @entry: index entry (points into @ir or @ia) + * @entry: index entry (points into @ir or @ib) * @data: index entry data (points into @entry) * @data_len: length in bytes of @data - * @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ia + * @cr: + * @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ib * @ir: index root if @is_in_root or NULL otherwise * @actx: attribute search context if in root or NULL otherwise - * @ia: index block if @is_in_root is FALSE or NULL otherwise * @ia_na: opened INDEX_ALLOCATION attribute - * @ia_vcn: VCN from which @ia where read from - * @ia_dirty: TRUE if index block was changed + * @ib: index block if @is_in_root is FALSE or NULL otherwise + * @ib_vcn: VCN from which @ib where read from + * @ib_dirty: TRUE if index block was changed + * @parent_pos: parent entries' positions in the index block + * @parent_vcn: entry's parent nodes or VCN_INDEX_ROOT_PARENT for root + * @max_depth: number of the parent nodes + * @pindex: maximum it's the number of the parent nodes * @block_size: index block size - * @vcn_size: VCN size for this index block - * @vcn_size_bits: use instead of @vcn_size to speedup multiplication + * @vcn_size_bits: VCN size bits for this index block * * @ni is the inode this context belongs to. * @@ -56,13 +65,13 @@ * simply points into @entry. This is probably what the user is interested in. * * If @is_in_root is TRUE, @entry is in the index root attribute @ir described - * by the attribute search context @actx and inode @ni. @ia, @ia_vcn and - * @ia_dirty are undefined in this case. + * by the attribute search context @actx and inode @ni. @ib, @ib_vcn and + * @ib_dirty are undefined in this case. * - * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia - * and @ia_vcn point to the index allocation block and VCN where it's placed, + * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ib + * and @ib_vcn point to the index allocation block and VCN where it's placed, * respectively. @ir and @actx are NULL in this case. @ia_na is opened - * INDEX_ALLOCATION attribute. @ia_dirty is TRUE if index block was changed and + * INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and * FALSE otherwise. * * To obtain a context call ntfs_index_ctx_get(). @@ -81,15 +90,19 @@ typedef struct { INDEX_ENTRY *entry; void *data; u16 data_len; + COLLATION_RULES cr; BOOL is_in_root; INDEX_ROOT *ir; ntfs_attr_search_ctx *actx; - INDEX_ALLOCATION *ia; ntfs_attr *ia_na; - VCN ia_vcn; - BOOL ia_dirty; + INDEX_BLOCK *ib; + VCN ib_vcn; + BOOL ib_dirty; + int parent_pos[MAX_PARENT_VCN]; + VCN parent_vcn[MAX_PARENT_VCN]; + int max_depth; + int pindex; u32 block_size; - u32 vcn_size; u8 vcn_size_bits; } ntfs_index_context; @@ -107,6 +120,12 @@ extern int ntfs_index_rm(ntfs_index_context *ictx); extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); +extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie); + +char *ntfs_ie_filename_get(INDEX_ENTRY *ie); +void ntfs_ie_filename_dump(INDEX_ENTRY *ie); +void ntfs_ih_filename_dump(INDEX_HEADER *ih); + /** * ntfs_index_entry_mark_dirty - mark an index entry dirty * @ictx: ntfs index context describing the index entry @@ -118,7 +137,7 @@ extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); * hence the index root attribute, will be written out to disk later. * * If the index entry is in an index block belonging to the index allocation - * attribute, set ia_dirty to TRUE, thus index block will be updated during + * attribute, set ib_dirty to TRUE, thus index block will be updated during * ntfs_index_ctx_put. */ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) @@ -126,7 +145,7 @@ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) if (ictx->is_in_root) ntfs_inode_mark_dirty(ictx->actx->ntfs_ino); else - ictx->ia_dirty = TRUE; + ictx->ib_dirty = TRUE; } #endif /* _NTFS_INDEX_H */ diff --git a/include/ntfs/types.h b/include/ntfs/types.h index 4987d785..f4d7c771 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -3,6 +3,7 @@ * the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2006 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -114,5 +115,11 @@ typedef enum { IGNORE_CASE = 1, } IGNORE_CASE_BOOL; +#define STATUS_OK (0) +#define STATUS_ERROR (-1) +#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2) +#define STATUS_KEEP_SEARCHING (-3) +#define STATUS_NOT_FOUND (-4) + #endif /* defined _NTFS_TYPES_H */ diff --git a/libntfs/index.c b/libntfs/index.c index 8fd78b47..126af72e 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -2,8 +2,9 @@ * index.c - NTFS index handling. Part of the Linux-NTFS project. * * Copyright (c) 2004-2005 Anton Altaparmakov - * Copyright (c) 2005 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon + * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2006 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -42,6 +43,44 @@ #include "mst.h" #include "dir.h" #include "logging.h" +#include "bitmap.h" +#include "support.h" + +static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn) +{ + return vcn << icx->vcn_size_bits; +} + +static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos) +{ + return pos >> icx->vcn_size_bits; +} + +static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf) +{ + s64 ret; + + ntfs_log_trace("vcn: %lld\n", vcn); + + ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), + 1, icx->block_size, buf); + if (ret != 1) { + ntfs_log_perror("Failed to write index block %lld of inode " + "%llu", vcn, icx->ni->mft_no); + return STATUS_ERROR; + } + return STATUS_OK; +} + +static int ntfs_icx_ib_write(ntfs_index_context *icx) +{ + if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib)) + return STATUS_ERROR; + + icx->ib_dirty = FALSE; + + return STATUS_OK; +} /** * ntfs_index_ctx_get - allocate and initialize a new index context @@ -53,115 +92,528 @@ * Return NULL if allocation failed. */ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, - ntfschar *name, u32 name_len) + ntfschar *name, u32 name_len) { - ntfs_index_context *ictx; + ntfs_index_context *icx; + ntfs_log_trace("Entering.\n"); + if (!ni) { errno = EINVAL; return NULL; } if (ni->nr_extents == -1) ni = ni->base_ni; - ictx = malloc(sizeof(ntfs_index_context)); - if (ictx) - *ictx = (ntfs_index_context) { + icx = ntfs_calloc(sizeof(ntfs_index_context)); + if (icx) + *icx = (ntfs_index_context) { .ni = ni, .name = name, .name_len = name_len, }; - return ictx; + return icx; +} + +static void ntfs_index_ctx_free(ntfs_index_context *icx) +{ + ntfs_log_trace("Entering.\n"); + + if (!icx->entry) + return; + + if (icx->actx) + ntfs_attr_put_search_ctx(icx->actx); + + if (icx->is_in_root) { + if (icx->ia_na) + ntfs_attr_close(icx->ia_na); + return; + } + + if (icx->ib_dirty) { + /* FIXME: Error handling!!! */ + ntfs_ib_write(icx, icx->ib_vcn, icx->ib); + } + + free(icx->ib); + ntfs_attr_close(icx->ia_na); } /** * ntfs_index_ctx_put - release an index context - * @ictx: index context to free + * @icx: index context to free * - * Release the index context @ictx, releasing all associated resources. + * Release the index context @icx, releasing all associated resources. */ -void ntfs_index_ctx_put(ntfs_index_context *ictx) +void ntfs_index_ctx_put(ntfs_index_context *icx) { - if (ictx->entry) { - if (ictx->is_in_root) { - if (ictx->actx) - ntfs_attr_put_search_ctx(ictx->actx); - } else { - /* Write out index block it it's dirty. */ - if (ictx->ia_dirty) { - if (ntfs_attr_mst_pwrite(ictx->ia_na, - ictx->ia_vcn << - ictx->vcn_size_bits, - 1, ictx->block_size, - ictx->ia) != 1) - ntfs_log_error("Failed to write out " - "index block.\n"); - } - /* Free resources. */ - free(ictx->ia); - ntfs_attr_close(ictx->ia_na); - } - } - free(ictx); + ntfs_index_ctx_free(icx); + free(icx); } /** * ntfs_index_ctx_reinit - reinitialize an index context - * @ictx: index context to reinitialize + * @icx: index context to reinitialize * - * Reinitialize the index context @ictx so it can be used for ntfs_index_lookup. + * Reinitialize the index context @icx so it can be used for ntfs_index_lookup. */ -void ntfs_index_ctx_reinit(ntfs_index_context *ictx) +void ntfs_index_ctx_reinit(ntfs_index_context *icx) { - if (ictx->entry) { - if (ictx->is_in_root) { - if (ictx->actx) - ntfs_attr_put_search_ctx(ictx->actx); - } else { - /* Write out index block it it's dirty. */ - if (ictx->ia_dirty) { - if (ntfs_attr_mst_pwrite(ictx->ia_na, - ictx->ia_vcn << - ictx->vcn_size_bits, - 1, ictx->block_size, - ictx->ia) != 1) - ntfs_log_error("Failed to write out " - "index block.\n"); - } - /* Free resources. */ - free(ictx->ia); - ntfs_attr_close(ictx->ia_na); - } - } - *ictx = (ntfs_index_context) { - .ni = ictx->ni, - .name = ictx->name, - .name_len = ictx->name_len, + ntfs_log_trace("Entering.\n"); + + ntfs_index_ctx_free(icx); + + *icx = (ntfs_index_context) { + .ni = icx->ni, + .name = icx->name, + .name_len = icx->name_len, }; } +static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) +{ + return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); +} + +/** + * Get the subnode vcn to which the index entry refers. + */ +VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie) +{ + return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie)); +} + +static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih) +{ + return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset)); +} + +static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie) +{ + return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length)); +} + +static u8 *ntfs_ie_get_end(INDEX_HEADER *ih) +{ + /* FIXME: check if it isn't overflowing the index block size */ + return (u8 *)ih + le32_to_cpu(ih->index_length); +} + +static int ntfs_ie_end(INDEX_ENTRY *ie) +{ + return ie->flags & INDEX_ENTRY_END; +} + +/** + * Find the last entry in the index block + */ +static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) +{ + ntfs_log_trace("Entering.\n"); + + while ((char *)ie < ies_end && !ntfs_ie_end(ie)) + ie = ntfs_ie_get_next(ie); + return ie; +} + +static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) +{ + ntfs_log_trace("pos: %d\n", pos); + + INDEX_ENTRY *ie = ntfs_ie_get_first(ih); + + while (pos-- > 0) + ie = ntfs_ie_get_next(ie); + return ie; +} + +static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) +{ + ntfs_log_trace("Entering.\n"); + + INDEX_ENTRY *ie_prev = NULL; + INDEX_ENTRY *tmp = ntfs_ie_get_first(ih); + + while (tmp != ie) { + ie_prev = tmp; + tmp = ntfs_ie_get_next(tmp); + } + return ie_prev; +} + +char *ntfs_ie_filename_get(INDEX_ENTRY *ie) +{ + FILE_NAME_ATTR *fn; + char *name = NULL; + int name_len; + + fn = (FILE_NAME_ATTR *)&ie->key; + name_len = ntfs_ucstombs(fn->file_name, fn->file_name_length, &name, 0); + if (name_len < 0) { + ntfs_log_perror("ntfs_ucstombs"); + return NULL; + } else if (name_len > 0) + return name; + free(name); + return NULL; +} + +void ntfs_ie_filename_dump(INDEX_ENTRY *ie) +{ + char *s; + + s = ntfs_ie_filename_get(ie); + ntfs_log_debug("'%s' ", s); + free(s); +} + +void ntfs_ih_filename_dump(INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie; + + ntfs_log_trace("Entering.\n"); + + ie = ntfs_ie_get_first(ih); + while (!ntfs_ie_end(ie)) { + ntfs_ie_filename_dump(ie); + ie = ntfs_ie_get_next(ie); + } +} + +static int ntfs_ih_numof_entries(INDEX_HEADER *ih) +{ + int n; + INDEX_ENTRY *ie; + + ntfs_log_trace("Entering.\n"); + + ie = ntfs_ie_get_first(ih); + for (n = 0; !ntfs_ie_end(ie); n++) + ie = ntfs_ie_get_next(ie); + return n; +} + +static int ntfs_ih_one_entry(INDEX_HEADER *ih) +{ + return (ntfs_ih_numof_entries(ih) == 1); +} + +static int ntfs_ih_zero_entry(INDEX_HEADER *ih) +{ + return (ntfs_ih_numof_entries(ih) == 0); +} + +static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) +{ + u32 new_size; + + ntfs_log_trace("Entering.\n"); + + new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length); + ih->index_length = cpu_to_le32(new_size); + memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), + new_size - ((u8 *)ie - (u8 *)ih)); +} + +static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) +{ + *ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn); +} + +/** + * Insert @ie index entry at @pos entry. Used @ih values should be ok already. + */ +static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) +{ + int ie_size = le16_to_cpu(ie->length); + + ntfs_log_trace("Entering.\n"); + + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size); + memmove((u8 *)pos + ie_size, pos, + le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - + ie_size); + memcpy(pos, ie, ie_size); +} + +static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) +{ + INDEX_ENTRY *dup; + + ntfs_log_trace("Entering.\n"); + + dup = ntfs_malloc(ie->length); + if (dup) + memcpy(dup, ie, ie->length); + return dup; +} + +static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) +{ + INDEX_ENTRY *dup; + int size = ie->length; + + ntfs_log_trace("Entering.\n"); + + if (ie->flags & INDEX_ENTRY_NODE) + size -= sizeof(VCN); + + dup = ntfs_malloc(size); + if (dup) + memcpy(dup, ie, size); + + dup->flags &= ~INDEX_ENTRY_NODE; + dup->length = size; + return dup; +} + +static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) +{ + u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; + + ntfs_log_trace("Entering.\n"); + + if (!ntfs_is_indx_record(ib->magic)) { + + ntfs_log_error("Corrupt index block signature: vcn %lld inode " + "%llu\n", (long long)vcn, icx->ni->mft_no); + return -1; + } + + if (sle64_to_cpu(ib->index_block_vcn) != vcn) { + + ntfs_log_error("Corrupt index block: VCN (%lld) is different " + "from expected VCN (%lld) in inode %llu\n", + (long long) sle64_to_cpu(ib->index_block_vcn), + (long long)vcn, icx->ni->mft_no); + return -1; + } + + if (ib_size != icx->block_size) { + + ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " + "has a size (%u) differing from the index " + "specified size (%u)\n", (long long)vcn, + icx->ni->mft_no, ib_size, icx->block_size); + return -1; + } + return 0; +} + +static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, + u32 name_len, ntfs_attr_search_ctx **ctx) +{ + ATTR_RECORD *a; + INDEX_ROOT *ir = NULL; + + ntfs_log_trace("Entering.\n"); + + *ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!*ctx) { + ntfs_log_perror("Failed to get $INDEX_ROOT search context"); + return NULL; + } + + if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, + 0, NULL, 0, *ctx)) { + ntfs_log_perror("Failed to lookup $INDEX_ROOT"); + goto err_out; + } + + a = (*ctx)->attr; + if (a->non_resident) { + errno = EINVAL; + ntfs_log_perror("Non-resident $INDEX_ROOT detected"); + goto err_out; + } + + ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); +err_out: + if (!ir) + ntfs_attr_put_search_ctx(*ctx); + return ir; +} + +/** + * Find a key in the index block. + * + * Return values: + * STATUS_OK with errno set to ESUCCESS if we know for sure that the + * entry exists and @ie_out points to this entry. + * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the + * entry doesn't exist and @ie_out is the insertion point. + * STATUS_KEEP_SEARCHING if we can't answer the above question and + * @vcn will contain the node index block. + * STATUS_ERROR with errno set if on unexpected error during lookup. + */ +static int ntfs_ie_lookup(const void *key, const int key_len, + ntfs_index_context *icx, INDEX_HEADER *ih, + VCN *vcn, INDEX_ENTRY **ie_out) +{ + INDEX_ENTRY *ie; + u8 *index_end; + int rc, item = 0; + + ntfs_log_trace("Entering.\n"); + + index_end = ntfs_ie_get_end(ih); + + /* + * Loop until we exceed valid memory (corruption case) or until we + * reach the last entry. + */ + for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) { + /* Bounds checks. */ + if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || + (u8 *)ie + le16_to_cpu(ie->length) > index_end) { + errno = ERANGE; + ntfs_log_error("Index entry out of bounds in inode " + "%llu.\n", icx->ni->mft_no); + return STATUS_ERROR; + } + /* + * The last entry cannot contain a key. It can however contain + * a pointer to a child node in the B+tree so we just break out. + */ + if (ntfs_ie_end(ie)) + break; + /* + * Not a perfect match, need to do full blown collation so we + * know which way in the B+tree we have to go. + */ + rc = ntfs_collate(icx->ni->vol, icx->cr, key, key_len, &ie->key, + le16_to_cpu(ie->key_length)); + if (rc == NTFS_COLLATION_ERROR) { + ntfs_log_error("Collation error. Perhaps a filename " + "contains invalid characters?\n"); + errno = ERANGE; + return STATUS_ERROR; + } + /* + * If @key collates before the key of the current entry, there + * is definitely no such key in this index but we might need to + * descend into the B+tree so we just break out of the loop. + */ + if (rc == -1) + break; + + if (!rc) { + *ie_out = ie; + errno = 0; + icx->parent_pos[icx->pindex] = item; + return STATUS_OK; + } + + item++; + } + /* + * We have finished with this index block without success. Check for the + * presence of a child node and if not present return with errno ENOENT, + * otherwise we will keep searching in another index block. + */ + if (!(ie->flags & INDEX_ENTRY_NODE)) { + ntfs_log_debug("Index entry wasn't found.\n"); + *ie_out = ie; + errno = ENOENT; + return STATUS_NOT_FOUND; + } + + /* Get the starting vcn of the index_block holding the child node. */ + *vcn = ntfs_ie_get_vcn(ie); + if (*vcn < 0) { + errno = EINVAL; + ntfs_log_perror("Negative vcn in inode %llu\n", + icx->ni->mft_no); + return STATUS_ERROR; + } + + ntfs_log_trace("Parent entry number %d\n", item); + icx->parent_pos[icx->pindex] = item; + return STATUS_KEEP_SEARCHING; +} + +static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) +{ + ntfs_attr *na; + + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open index allocation of inode " + "%llu", ni->mft_no); + return NULL; + } + return na; +} + +static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) +{ + s64 pos, ret; + + ntfs_log_trace("vcn: %lld\n", vcn); + + pos = ntfs_ib_vcn_to_pos(icx, vcn); + + ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, + (u8 *)dst); + if (ret != 1) { + if (ret == -1) + ntfs_log_perror("Failed to read index block"); + else + ntfs_log_error("Failed to read full index block at " + "%lld\n", pos); + return -1; + } + + if (ntfs_ia_check(icx, dst, vcn)) + return -1; + return 0; +} + +static int ntfs_icx_parent_inc(ntfs_index_context *icx) +{ + icx->pindex++; + if (icx->pindex >= MAX_PARENT_VCN) { + errno = EOPNOTSUPP; + ntfs_log_perror("Index is over %d level deep", MAX_PARENT_VCN); + return STATUS_ERROR; + } + return STATUS_OK; +} + +static int ntfs_icx_parent_dec(ntfs_index_context *icx) +{ + icx->pindex--; + if (icx->pindex < 0) { + errno = EINVAL; + ntfs_log_perror("Corrupt index pointer (%d)", icx->pindex); + return STATUS_ERROR; + } + return STATUS_OK; +} + /** * ntfs_index_lookup - find a key in an index and return its index entry * @key: [IN] key for which to search in the index * @key_len: [IN] length of @key in bytes - * @ictx: [IN/OUT] context describing the index and the returned entry + * @icx: [IN/OUT] context describing the index and the returned entry * - * Before calling ntfs_index_lookup(), @ictx must have been obtained from a + * Before calling ntfs_index_lookup(), @icx must have been obtained from a * call to ntfs_index_ctx_get(). * - * Look for the @key in the index specified by the index lookup context @ictx. + * Look for the @key in the index specified by the index lookup context @icx. * ntfs_index_lookup() walks the contents of the index looking for the @key. * - * If the @key is found in the index, 0 is returned and @ictx is setup to - * describe the index entry containing the matching @key. @ictx->entry is the - * index entry and @ictx->data and @ictx->data_len are the index entry data and + * If the @key is found in the index, 0 is returned and @icx is setup to + * describe the index entry containing the matching @key. @icx->entry is the + * index entry and @icx->data and @icx->data_len are the index entry data and * its length in bytes, respectively. * * If the @key is not found in the index, -1 is returned, errno = ENOENT and - * @ictx is setup to describe the index entry whose key collates immediately + * @icx is setup to describe the index entry whose key collates immediately * after the search @key, i.e. this is the position in the index at which * an index entry with a key of @key would need to be inserted. * - * If an error occurs return -1, set errno to error code and @ictx is left + * If an error occurs return -1, set errno to error code and @icx is left * untouched. * * When finished with the entry and its data, call ntfs_index_ctx_put() to free @@ -172,297 +624,794 @@ void ntfs_index_ctx_reinit(ntfs_index_context *ictx) * to disk. */ int ntfs_index_lookup(const void *key, const int key_len, - ntfs_index_context *ictx) + ntfs_index_context *icx) { - COLLATION_RULES cr; - VCN vcn; - ntfs_inode *ni = ictx->ni; - ntfs_volume *vol = ni->vol; + VCN old_vcn, vcn; + ntfs_inode *ni = icx->ni; INDEX_ROOT *ir; INDEX_ENTRY *ie; - INDEX_ALLOCATION *ia = NULL; - u8 *index_end; + INDEX_BLOCK *ib = NULL; ntfs_attr_search_ctx *actx; - ntfs_attr *na = NULL; - int rc, err = 0; + int ret, err = 0; ntfs_log_trace("Entering.\n"); + if (!key || key_len <= 0) { errno = EINVAL; + ntfs_log_perror("key: %p key_len: %d", key, key_len); return -1; } - actx = ntfs_attr_get_search_ctx(ni, NULL); - if (!actx) { - err = ENOMEM; - goto err_out; + ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &actx); + if (!ir) { + if (errno == ENOENT) + errno = EIO; + return -1; + } + + icx->block_size = le32_to_cpu(ir->index_block_size); + if (icx->block_size < NTFS_BLOCK_SIZE) { + errno = EINVAL; + ntfs_log_perror("Index block size (%d) is smaller than the " + "sector size (%d)", icx->block_size, + NTFS_BLOCK_SIZE); + return -1; } - /* Find the index root attribute in the mft record. */ - err = ntfs_attr_lookup(AT_INDEX_ROOT, ictx->name, ictx->name_len, - CASE_SENSITIVE, 0, NULL, 0, actx); - if (err) { - if (errno == ENOENT) { - ntfs_log_error("Index root attribute missing in inode " - "0x%llx.\n", ni->mft_no); - err = EIO; - } else - err = errno; + if (ni->vol->cluster_size <= icx->block_size) + icx->vcn_size_bits = ni->vol->cluster_size_bits; + else + icx->vcn_size_bits = ni->vol->sector_size_bits; + + icx->cr = ir->collation_rule; + if (!ntfs_is_collation_rule_supported(icx->cr)) { + err = errno = EOPNOTSUPP; + ntfs_log_perror("Unknown collation rule 0x%x", + (unsigned)le32_to_cpu(icx->cr)); goto err_out; } - /* Get to the index root value (it has been verified in read_inode). */ - ir = (INDEX_ROOT*)((u8*)actx->attr + - le16_to_cpu(actx->attr->value_offset)); - index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); - /* Save index block size for future use. */ - ictx->block_size = le32_to_cpu(ir->index_block_size); - /* Determine the size of a vcn in the directory index. */ - if (vol->cluster_size <= ictx->block_size) { - ictx->vcn_size = vol->cluster_size; - ictx->vcn_size_bits = vol->cluster_size_bits; - } else { - ictx->vcn_size = vol->sector_size; - ictx->vcn_size_bits = vol->sector_size_bits; - } - /* Get collation rule type and validate it. */ - cr = ir->collation_rule; - if (!ntfs_is_collation_rule_supported(cr)) { - ntfs_log_error("Index uses unsupported collation rule 0x%x. " - "Aborting lookup.\n", (unsigned)le32_to_cpu(cr)); - err = EOPNOTSUPP; - goto err_out; - } - /* The first index entry. */ - ie = (INDEX_ENTRY*)((u8*)&ir->index + - le32_to_cpu(ir->index.entries_offset)); - /* - * Loop until we exceed valid memory (corruption case) or until we - * reach the last entry. + + old_vcn = VCN_INDEX_ROOT_PARENT; + /* + * FIXME: check for both ir and ib that the first index entry is + * within the index block. */ - for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { - /* Bounds checks. */ - if ((u8*)ie < (u8*)actx->mrec || (u8*)ie + - sizeof(INDEX_ENTRY_HEADER) > index_end || - (u8*)ie + le16_to_cpu(ie->length) > index_end) - goto idx_err_out; - /* - * The last entry cannot contain a key. It can however contain - * a pointer to a child node in the B+tree so we just break out. - */ - if (ie->flags & INDEX_ENTRY_END) - break; - /* If the keys match perfectly, we setup @ictx and return 0. */ - if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, - &ie->key, key_len)) { -ir_done: - ictx->is_in_root = TRUE; - ictx->actx = actx; - ictx->ia = NULL; - ictx->ir = ir; -done: - ictx->entry = ie; - ictx->data = (u8*)ie + offsetof(INDEX_ENTRY, key); - ictx->data_len = le16_to_cpu(ie->key_length); - ntfs_log_trace("Done.\n"); - if (err) { - errno = err; - return -1; - } - return 0; - } - /* - * Not a perfect match, need to do full blown collation so we - * know which way in the B+tree we have to go. - */ - rc = ntfs_collate(vol, cr, key, key_len, &ie->key, - le16_to_cpu(ie->key_length)); - if (rc == NTFS_COLLATION_ERROR) { - ntfs_log_error("Collation error. Probably filename " - "contain invalid characters.\n"); - err = ERANGE; - goto err_out; - } - /* - * If @key collates before the key of the current entry, there - * is definitely no such key in this index but we might need to - * descend into the B+tree so we just break out of the loop. - */ - if (rc == -1) - break; - /* - * A match should never happen as the memcmp() call should have - * caught it, but we still treat it correctly. - */ - if (!rc) - goto ir_done; - /* The keys are not equal, continue the search. */ - } - /* - * We have finished with this index without success. Check for the - * presence of a child node and if not present setup @ictx and return - * -1 with errno ENOENT. - */ - if (!(ie->flags & INDEX_ENTRY_NODE)) { - ntfs_log_debug("Entry not found.\n"); - err = ENOENT; - goto ir_done; - } /* Child node present, descend into it. */ - /* Get the starting vcn of the index_block holding the child node. */ - vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); - /* We are done with the index root. Release attribute search ctx. */ - ntfs_attr_put_search_ctx(actx); - actx = NULL; - /* Open INDEX_ALLOCATION. */ - na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, - ictx->name, ictx->name_len); - if (!na) { - ntfs_log_error("No index allocation attribute but index entry " - "requires one. Inode 0x%llx is corrupt or " - "library bug.\n", ni->mft_no); + ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie); + if (ret == STATUS_ERROR) { + err = errno; goto err_out; } - /* Allocate memory to store index block. */ - ia = malloc(ictx->block_size); - if (!ia) { - ntfs_log_error("Not enough memory to allocate buffer for index" - " allocation.\n"); - err = ENOMEM; - goto err_out; - } -descend_into_child_node: - ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); - /* Read index allocation block. */ - if (ntfs_attr_mst_pread(na, vcn << ictx->vcn_size_bits, 1, - ictx->block_size, ia) != 1) { - ntfs_log_error("Failed to read index allocation.\n"); - goto err_out; - } - /* Catch multi sector transfer fixup errors. */ - if (!ntfs_is_indx_record(ia->magic)) { - ntfs_log_error("Index record with vcn 0x%llx is corrupt. " - "Corrupt inode 0x%llx. Run chkdsk.\n", - (long long)vcn, ni->mft_no); - goto err_out; - } - if (sle64_to_cpu(ia->index_block_vcn) != vcn) { - ntfs_log_error("Actual VCN (0x%llx) of index buffer is " - "different from expected VCN (0x%llx). Inode " - "0x%llx is corrupt or driver bug.\n", - (unsigned long long) - sle64_to_cpu(ia->index_block_vcn), - (unsigned long long)vcn, ni->mft_no); - goto err_out; - } - if (le32_to_cpu(ia->index.allocated_size) + 0x18 != ictx->block_size) { - ntfs_log_error("Index buffer (VCN 0x%llx) of inode 0x%llx has " - "a size (%u) differing from the index " - "specified size (%u). Inode is corrupt or " - "driver bug.\n", (unsigned long long)vcn, - ni->mft_no, (unsigned) - le32_to_cpu(ia->index.allocated_size) + 0x18, - (unsigned)ictx->block_size); - goto err_out; - } - index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); - if (index_end > (u8*)ia + ictx->block_size) { - ntfs_log_error("Size of index buffer (VCN 0x%llx) of inode " - "0x%llx exceeds maximum size.\n", - (unsigned long long)vcn, ni->mft_no); - goto err_out; - } - /* The first index entry. */ - ie = (INDEX_ENTRY*)((u8*)&ia->index + - le32_to_cpu(ia->index.entries_offset)); - /* - * Iterate similar to above big loop but applied to index buffer, thus - * loop until we exceed valid memory (corruption case) or until we - * reach the last entry. - */ - for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { - /* Bounds checks. */ - if ((u8*)ie < (u8*)ia || (u8*)ie + - sizeof(INDEX_ENTRY_HEADER) > index_end || - (u8*)ie + le16_to_cpu(ie->length) > index_end) { - ntfs_log_error("Index entry out of bounds in inode " - "0x%llx.\n", ni->mft_no); - goto err_out; - } - /* - * The last entry cannot contain a key. It can however contain - * a pointer to a child node in the B+tree so we just break out. - */ - if (ie->flags & INDEX_ENTRY_END) - break; - /* If the keys match perfectly, we setup @ictx and return 0. */ - if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key, - &ie->key, key_len)) { -ia_done: - ictx->is_in_root = FALSE; - ictx->actx = NULL; - ictx->ia = ia; - ictx->ia_vcn = vcn; - ictx->ia_na = na; - goto done; - } - /* - * Not a perfect match, need to do full blown collation so we - * know which way in the B+tree we have to go. - */ - rc = ntfs_collate(vol, cr, key, key_len, &ie->key, - le16_to_cpu(ie->key_length)); - if (rc == NTFS_COLLATION_ERROR) { - ntfs_log_error("Collation error. Probably filename " - "contain invalid characters.\n"); - err = ERANGE; - goto err_out; - } - /* - * If @key collates before the key of the current entry, there - * is definitely no such key in this index but we might need to - * descend into the B+tree so we just break out of the loop. - */ - if (rc == -1) - break; - /* - * A match should never happen as the memcmp() call should have - * caught it, but we still treat it correctly. - */ - if (!rc) - goto ia_done; - /* The keys are not equal, continue the search. */ - } - /* - * We have finished with this index buffer without success. Check for - * the presence of a child node and if not present return ENOENT. - */ - if (!(ie->flags & INDEX_ENTRY_NODE)) { - ntfs_log_debug("Entry not found.\n"); - err = ENOENT; - goto ia_done; - } - if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { - ntfs_log_error("Index entry with child node found in a leaf " - "node in inode 0x%llx.\n", ni->mft_no); - goto err_out; + + icx->actx = actx; + icx->ir = ir; + + if (ret != STATUS_KEEP_SEARCHING) { + /* STATUS_OK or STATUS_NOT_FOUND */ + err = errno; + icx->is_in_root = TRUE; + icx->parent_vcn[icx->pindex] = old_vcn; + goto done; } + /* Child node present, descend into it. */ - vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8)); - if (vcn >= 0) - goto descend_into_child_node; - ntfs_log_error("Negative child node vcn in inode 0x%llx.\n", ni->mft_no); + icx->ia_na = ntfs_ia_open(icx, ni); + if (!icx->ia_na) + goto err_out; + + ib = ntfs_malloc(icx->block_size); + if (!ib) { + err = errno; + goto err_out; + } + +descend_into_child_node: + icx->parent_vcn[icx->pindex] = old_vcn; + if (ntfs_icx_parent_inc(icx)) { + err = errno; + goto err_out; + } + old_vcn = vcn; + + ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); + + if (ntfs_ib_read(icx, vcn, ib)) + goto err_out; + + ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie); + if (ret != STATUS_KEEP_SEARCHING) { + err = errno; + if (ret == STATUS_ERROR) + goto err_out; + + /* STATUS_OK or STATUS_NOT_FOUND */ + icx->is_in_root = FALSE; + icx->ib = ib; + icx->parent_vcn[icx->pindex] = icx->ib_vcn = vcn; + goto done; + } + + if ((ib->index.flags & NODE_MASK) == LEAF_NODE) { + ntfs_log_error("Index entry with child node found in a leaf " + "node in inode 0x%llx.\n", ni->mft_no); + goto err_out; + } + + goto descend_into_child_node; err_out: - if (na) - ntfs_attr_close(na); - free(ia); + if (icx->ia_na) { + ntfs_attr_close(icx->ia_na); + icx->ia_na = NULL; + } + free(ib); if (!err) err = EIO; if (actx) ntfs_attr_put_search_ctx(actx); errno = err; return -1; -idx_err_out: - ntfs_log_error("Corrupt index. Aborting lookup.\n"); - goto err_out; +done: + icx->entry = ie; + icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key); + icx->data_len = le16_to_cpu(ie->key_length); + icx->max_depth = icx->pindex; + ntfs_log_trace("Done.\n"); + if (err) { + errno = err; + return -1; + } + return 0; +} + +static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, int ib_size, + INDEX_HEADER_FLAGS node_type) +{ + INDEX_BLOCK *ib; + int ih_size = sizeof(INDEX_HEADER); + + ntfs_log_trace("Entering ib_vcn = %lld ib_size = %d\n", ib_vcn, + ib_size); + + ib = ntfs_calloc(ib_size); + if (!ib) + return NULL; + + ib->magic = magic_INDX; + ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); + ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); + /* Set USN to 1 */ + *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); + ib->lsn = cpu_to_le64(0); + + ib->index_block_vcn = cpu_to_sle64(ib_vcn); + + ib->index.entries_offset = cpu_to_le32((ih_size + + le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); + ib->index.index_length = 0; + ib->index.allocated_size = cpu_to_le32(ib_size - + (sizeof(INDEX_BLOCK) - ih_size)); + ib->index.flags = node_type; + return ib; +} + +/** + * Find the median by going through all the entries + */ +static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie, *ie_start; + u8 *ie_end; + int i = 0, median; + + ntfs_log_trace("Entering.\n"); + + ie = ie_start = ntfs_ie_get_first(ih); + ie_end = (u8 *)ntfs_ie_get_end(ih); + + while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { + ie = ntfs_ie_get_next(ie); + i++; + } + /* + * NOTE: this could be also the entry at the half of the index block. + */ + median = i / 2 - 1; + + ntfs_log_trace("Entries: %d median: %d\n", i, median); + + for (i = 0, ie = ie_start; i <= median; i++) + ie = ntfs_ie_get_next(ie); + + return ie; +} + +static s64 ntfs_ibm_vcn_to_pos(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ib_vcn_to_pos(icx, vcn) / icx->block_size; +} + +static s64 ntfs_ibm_pos_to_vcn(ntfs_index_context *icx, s64 pos) +{ + return ntfs_ib_pos_to_vcn(icx, pos * icx->block_size); +} + +static int ntfs_ibm_add(ntfs_index_context *icx) +{ + u8 bmp[8]; + + ntfs_log_trace("Entering.\n"); + + if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len)) + return STATUS_OK; + /* + * AT_BITMAP must be at least 8 bytes. + */ + memset(bmp, 0, sizeof(bmp)); + if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len, + bmp, sizeof(bmp))) { + ntfs_log_perror("Failed to add AT_BITMAP"); + return STATUS_ERROR; + } + return STATUS_OK; +} + +static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) +{ + u8 byte; + s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn); + u32 bpos = pos / 8; + u32 bit = 1 << (pos % 8); + ntfs_attr *na; + int ret = STATUS_ERROR; + + ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn); + + na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open $BITMAP attribute"); + return -1; + } + + if (set) { + if (na->data_size < bpos + 1) { + if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) { + ntfs_log_perror("Failed to truncate AT_BITMAP"); + goto err_na; + } + } + } + + if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { + ntfs_log_perror("Failed to read $BITMAP"); + goto err_na; + } + + if (set) + byte |= bit; + else + byte &= ~bit; + + if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { + ntfs_log_perror("Failed to write $Bitmap"); + goto err_na; + } + + ret = STATUS_OK; +err_na: + ntfs_attr_close(na); + return ret; +} + + +static int ntfs_ibm_set(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ibm_modify(icx, vcn, 1); +} + +static int ntfs_ibm_clear(ntfs_index_context *icx, VCN vcn) +{ + return ntfs_ibm_modify(icx, vcn, 0); +} + +static VCN ntfs_ibm_get_free(ntfs_index_context *icx) +{ + u8 *bm; + int bit; + s64 vcn, byte, size; + + ntfs_log_trace("Entering.\n"); + + bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len, + &size); + if (!bm) + return (VCN)-1; + + for (byte = 0; byte < size; byte++) { + + if (bm[byte] == 255) + continue; + + for (bit = 0; bit < 8; bit++) { + if (!(bm[byte] & (1 << bit))) { + vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit); + goto out; + } + } + } + + vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); +out: + ntfs_log_trace("allocated vcn: %lld\n", vcn); + + if (ntfs_ibm_set(icx, vcn)) + vcn = (VCN)-1; + + free(bm); + return vcn; +} + +static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) +{ + INDEX_BLOCK *ib; + INDEX_ENTRY *ie_last; + char *ies_start, *ies_end; + int i; + + ntfs_log_trace("Entering.\n"); + + ib = ntfs_ib_alloc(ib_vcn, ir->index_block_size, LEAF_NODE); + if (!ib) + return NULL; + + ies_start = (char *)ntfs_ie_get_first(&ir->index); + ies_end = (char *)ntfs_ie_get_end(&ir->index); + + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + /* + * Copy all entries, including the termination entry + * as well, which can never have any data. + */ + i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); + memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); + + ib->index.flags = ir->index.flags; + ib->index.index_length = cpu_to_le32(i + + le32_to_cpu(ib->index.entries_offset)); + /* + * Move the index root termination entry forward + */ + if ((char *)ie_last > ies_start) { + memmove(ies_start, (char *)ie_last, le16_to_cpu( + ie_last->length)); + ie_last = (INDEX_ENTRY *)ies_start; + } + return ib; +} + +static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, + INDEX_BLOCK *dst, INDEX_ENTRY *median, VCN new_vcn) +{ + u8 *ies_end; + INDEX_ENTRY *ie_head; /* first entry after the median */ + int tail_size; + + ntfs_log_trace("Entering.\n"); + + ie_head = ntfs_ie_get_next(median); + + ies_end = (u8 *)ntfs_ie_get_end(&src->index); + tail_size = ies_end - (u8 *)ie_head; + memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); + + dst->index.index_length = cpu_to_le32(tail_size + + le32_to_cpu(dst->index.entries_offset)); + + if (ntfs_ib_write(icx, new_vcn, dst)) + return STATUS_ERROR; + + return STATUS_OK; +} + +static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, + INDEX_ENTRY *ie) +{ + char *ies_start, *ies_end; + INDEX_ENTRY *ie_last; + + ntfs_log_trace("Entering.\n"); + + ies_start = (char *)ntfs_ie_get_first(&src->index); + ies_end = (char *)ntfs_ie_get_end(&src->index); + + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + if (ie_last->flags & INDEX_ENTRY_NODE) + ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); + + memcpy(ie, ie_last, ie_last->length); + + src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + + ie->length + le32_to_cpu(src->index.entries_offset)); + + if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src)) + return STATUS_ERROR; + + return STATUS_OK; +} + +static int ntfs_ia_add(ntfs_index_context *icx) +{ + ntfs_log_trace("Entering.\n"); + + if (ntfs_ibm_add(icx)) + return -1; + + if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, + icx->name_len)) { + if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name, + icx->name_len, NULL, 0)) { + ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION"); + return -1; + } + } + + icx->ia_na = ntfs_ia_open(icx, icx->ni); + if (!icx->ia_na) + return -1; + return 0; +} + +static int ntfs_ir_reparent(ntfs_index_context *icx) +{ + ntfs_attr_search_ctx *ctx; + INDEX_ROOT *ir; + INDEX_ENTRY *ie; + INDEX_BLOCK *ib = NULL; + VCN new_ib_vcn; + int ret = STATUS_ERROR; + + ntfs_log_trace("Entering.\n"); + + if (!(icx->ia_na)) + if (ntfs_ia_add(icx)) + return -1; + + ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); + if (!ir) + return -1; + + new_ib_vcn = ntfs_ibm_get_free(icx); + if (new_ib_vcn == -1) + goto err_out; + + ib = ntfs_ir_to_ia(ir, new_ib_vcn); + if (ib == NULL) { + ntfs_log_perror("Failed to create AT_INDEX_ALLOCATION"); + goto err_out; + } + + ie = ntfs_ie_get_first(&ir->index); + ie->flags |= INDEX_ENTRY_NODE; + ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)); + ntfs_ie_set_vcn(ie, new_ib_vcn); + + ir->index.flags = LARGE_INDEX; + ir->index.index_length = cpu_to_le32(le32_to_cpu( + ir->index.entries_offset) + le16_to_cpu(ie->length)); + ir->index.allocated_size = ir->index.index_length; + + if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + + le32_to_cpu(ir->index.allocated_size))) + /* FIXME: revert bitmap, index root */ + goto err_out; + ntfs_inode_mark_dirty(ctx->ntfs_ino); + + if (ntfs_ib_write(icx, new_ib_vcn, ib)) + goto err_out; + + ret = STATUS_OK; +err_out: + ntfs_attr_put_search_ctx(ctx); + free(ib); + return ret; +} + +/** + * ntfs_ir_truncate - Truncate index root attribute + * + * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR. + */ +static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) +{ + ntfs_attr *na; + int ret; + + ntfs_log_trace("Entering.\n"); + + na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len); + if (!na) { + ntfs_log_perror("Failed to open INDEX_ROOT"); + return STATUS_ERROR; + } + /* + * INDEX_ROOT must be resident and its entries can be moved to + * INDEX_BLOCK, so ENOSPC isn't a real error. + */ + ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); + if (ret == STATUS_OK) { + ntfs_attr_search_ctx *ctx; + + icx->ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, + &ctx); + if (!icx->ir) + return STATUS_ERROR; + + icx->ir->index.allocated_size = cpu_to_le16(data_size); + + ntfs_attr_put_search_ctx(ctx); + } else { + if (errno != ENOSPC && errno != EOVERFLOW) + ntfs_log_trace("Failed to truncate INDEX_ROOT"); + if (errno == EOVERFLOW) + ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; + } + + ntfs_attr_close(na); + return ret; +} + +/** + * ntfs_ir_make_space - Make more space for the index root attribute + * + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return STATUS_ERROR. + */ +static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) +{ + int ret; + + ntfs_log_trace("Entering.\n"); + + ret = ntfs_ir_truncate(icx, data_size); + if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { + ret = ntfs_ir_reparent(icx); + if (ret == STATUS_OK) + ret = STATUS_KEEP_SEARCHING; + else + ntfs_log_perror("Failed to nodify INDEX_ROOT"); + } + return ret; +} + +/* + * NOTE: 'ie' must be a copy of a real index entry. + */ +static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) +{ + INDEX_ENTRY *p, *old = *ie; + + old->length += sizeof(VCN); + p = realloc(old, old->length); + if (!p) + return STATUS_ERROR; + + p->flags |= INDEX_ENTRY_NODE; + *ie = p; + return STATUS_OK; +} + +static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, + int pos) +{ + INDEX_ENTRY *ie_node, *ie; + int ret = STATUS_ERROR; + VCN old_vcn; + + ntfs_log_trace("Entering.\n"); + + ie = ntfs_ie_dup(orig_ie); + if (!ie) + return STATUS_ERROR; + + if (!(ie->flags & INDEX_ENTRY_NODE)) + if (ntfs_ie_add_vcn(&ie)) + goto out; + + ie_node = ntfs_ie_get_by_pos(ih, pos); + old_vcn = ntfs_ie_get_vcn(ie_node); + ntfs_ie_set_vcn(ie_node, new_vcn); + + ntfs_ie_insert(ih, ie, ie_node); + ntfs_ie_set_vcn(ie_node, old_vcn); + ret = STATUS_OK; +out: + free(ie); + return ret; +} + +static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx) +{ + return icx->parent_vcn[icx->pindex]; +} + +static VCN ntfs_icx_parent_pos(ntfs_index_context *icx) +{ + return icx->parent_pos[icx->pindex]; +} + +static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, + VCN new_vcn) +{ + u32 new_size; + int ret; + + ntfs_log_trace("Entering.\n"); + + new_size = le16_to_cpu(icx->ir->index.index_length) + median->length; + if (!(median->flags & INDEX_ENTRY_NODE)) + new_size += sizeof(VCN); + + ret = ntfs_ir_make_space(icx, new_size); + if (ret != STATUS_OK) + return ret; + + return ntfs_ih_insert(&icx->ir->index, median, new_vcn, + ntfs_icx_parent_pos(icx)); +} + +static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); + +/** + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return STATUS_ERROR. + */ +static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) +{ + INDEX_BLOCK *ib; + u32 idx_size, allocated_size; + int err = STATUS_ERROR; + VCN old_vcn; + + ntfs_log_trace("Entering.\n"); + + ib = ntfs_malloc(icx->block_size); + if (!ib) + return -1; + + old_vcn = ntfs_icx_parent_vcn(icx); + + if (ntfs_ib_read(icx, old_vcn, ib)) + goto err_out; + + idx_size = le16_to_cpu(ib->index.index_length); + allocated_size = le16_to_cpu(ib->index.allocated_size); + /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ + if (idx_size + ie->length + sizeof(VCN) > allocated_size) { + err = ntfs_ib_split(icx, ib); + if (err == STATUS_OK) + err = STATUS_KEEP_SEARCHING; + goto err_out; + } + + if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) + goto err_out; + + if (ntfs_ib_write(icx, old_vcn, ib)) + goto err_out; + + err = STATUS_OK; +err_out: + free(ib); + return err; +} + +/** + * ntfs_ib_split - Split index allocation attribute + * + * On success return STATUS_OK or STATUS_KEEP_SEARCHING. + * On error return is STATUS_ERROR. + */ +static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) +{ + INDEX_BLOCK *ib_new; + INDEX_ENTRY *median; + VCN new_vcn; + int ret, err = STATUS_ERROR; + + ntfs_log_trace("Entering.\n"); + + if (ntfs_icx_parent_dec(icx)) + return STATUS_ERROR; + + median = ntfs_ie_get_median(&ib->index); + new_vcn = ntfs_ibm_get_free(icx); + if (new_vcn == -1) + return STATUS_ERROR; + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + ret = ntfs_ir_insert_median(icx, median, new_vcn); + else + ret = ntfs_ib_insert(icx, median, new_vcn); + + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + + if (ret != STATUS_OK) { + ntfs_ibm_clear(icx, new_vcn); + return ret; + } + + ib_new = ntfs_ib_alloc(new_vcn, icx->block_size, + ib->index.flags & NODE_MASK); + if (!ib_new) + return STATUS_ERROR; + + if (ntfs_ib_copy_tail(icx, ib, ib_new, median, new_vcn)) + goto free_ib_new; + + if (ntfs_ib_cut_tail(icx, ib, median)) + goto free_ib_new; + + err = STATUS_OK; +free_ib_new: + free(ib_new); + return err; +} + +static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) +{ + char *fn; + INDEX_HEADER *ih; + int allocated_size, new_size; + int ret = STATUS_ERROR; + + fn = ntfs_ie_filename_get(ie); + ntfs_log_trace("file: '%s'\n", fn); + + while (1) { + if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), + icx)) { + errno = EEXIST; + ntfs_log_error("Index already have such entry.\n"); + goto err_out; + } + if (errno != ENOENT) { + ntfs_log_perror("Failed to find place for new entry"); + goto err_out; + } + + if (icx->is_in_root) + ih = &icx->ir->index; + else + ih = &icx->ib->index; + + allocated_size = le16_to_cpu(ih->allocated_size); + new_size = le16_to_cpu(ih->index_length) + + le16_to_cpu(ie->length); + + if (new_size <= allocated_size) + break; + + ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", + allocated_size, new_size); + + if (icx->is_in_root) { + if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) + goto err_out; + } else { + if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) + goto err_out; + } + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + ntfs_index_ctx_reinit(icx); + } + + ntfs_ie_insert(ih, ie, icx->entry); + ntfs_index_entry_mark_dirty(icx); + + ret = STATUS_OK; +err_out: + free(fn); + ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); + return ret; } /** @@ -471,192 +1420,339 @@ idx_err_out: * @fn: FILE_NAME attribute to add * @mref: reference of the inode which @fn describes * - * NOTE: This function does not support all cases, so it can fail with - * EOPNOTSUPP error code. - * * Return 0 on success or -1 on error with errno set to the error code. */ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) { - ntfs_index_context *ictx; INDEX_ENTRY *ie; - INDEX_HEADER *ih; - int err, fn_size, ie_size, allocated_size = 0; + ntfs_index_context *icx; + int fn_size, ie_size, ret = -1; ntfs_log_trace("Entering.\n"); + if (!ni || !fn) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; return -1; } - ictx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); - if (!ictx) - return -1; + fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR); ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; -retry: - /* Find place where insert new entry. */ - if (!ntfs_index_lookup(fn, fn_size, ictx)) { - err = EEXIST; - ntfs_log_error("Index already have such entry.\n"); - goto err_out; - } - if (errno != ENOENT) { - err = errno; - ntfs_log_error("Failed to find place where to insert new entry.\n"); - goto err_out; - } - /* Some setup. */ - if (ictx->is_in_root) - ih = &ictx->ir->index; - else - ih = &ictx->ia->index; - if (!allocated_size) - allocated_size = le16_to_cpu(ih->allocated_size); - /* Check whether we have enough space in the index. */ - if (le16_to_cpu(ih->index_length) + ie_size > allocated_size) { - /* If we in the index root try to resize it. */ - if (ictx->is_in_root) { - ntfs_attr *na; + + ie = ntfs_calloc(ie_size); + if (!ie) + return -1; - allocated_size = le16_to_cpu(ih->index_length) + - ie_size; - na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name, - ictx->name_len); - if (!na) { - err = errno; - ntfs_log_error("Failed to open INDEX_ROOT.\n"); - goto err_out; - } - if (ntfs_attr_truncate(na, allocated_size + offsetof( - INDEX_ROOT, index))) { - err = EOPNOTSUPP; - ntfs_attr_close(na); - ntfs_log_debug("Failed to truncate " - "INDEX_ROOT.\n"); - goto err_out; - } - ntfs_attr_close(na); - ntfs_index_ctx_reinit(ictx); - goto retry; - } - ntfs_log_debug("Not implemented case.\n"); - err = EOPNOTSUPP; - goto err_out; - } - /* Update allocated size if we in INDEX_ROOT. */ - if (ictx->is_in_root) - ih->allocated_size = cpu_to_le16(allocated_size); - /* Create entry. */ - ie = calloc(1, ie_size); - if (!ie) { - err = errno; - goto err_out; - } ie->indexed_file = cpu_to_le64(mref); - ie->length = cpu_to_le16(ie_size); - ie->key_length = cpu_to_le16(fn_size); + ie->length = cpu_to_le16(ie_size); + ie->key_length = cpu_to_le16(fn_size); memcpy(&ie->key, fn, fn_size); - /* Update index length, move following entries forard and copy entry. */ - ih->index_length = cpu_to_le16(le16_to_cpu(ih->index_length) + ie_size); - memmove((u8*)ictx->entry + ie_size, ictx->entry, - le16_to_cpu(ih->index_length) - - ((u8*)ictx->entry - (u8*)ih) - ie_size); - memcpy(ictx->entry, ie, ie_size); - /* Done! */ - ntfs_index_entry_mark_dirty(ictx); - ntfs_index_ctx_put(ictx); + + icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); + if (!icx) + goto out; + + ret = ntfs_ie_add(icx, ie); + + ntfs_index_ctx_put(icx); +out: free(ie); - ntfs_log_trace("Done.\n"); - return 0; -err_out: - ntfs_log_trace("Failed.\n"); - ntfs_index_ctx_put(ictx); - errno = err; - return -1; + return ret; +} + +static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, + INDEX_ENTRY *ie, INDEX_BLOCK *ib) +{ + INDEX_ENTRY *ie_roam; + int ret = STATUS_ERROR; + + ntfs_log_trace("Entering.\n"); + + ie_roam = ntfs_ie_dup_novcn(ie); + if (!ie_roam) + return STATUS_ERROR; + + ntfs_ie_delete(ih, ie); + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + else + if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib)) + goto out; + + ntfs_index_ctx_reinit(icx); + + ret = ntfs_ie_add(icx, ie_roam); +out: + free(ie_roam); + return ret; +} + +/** + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is the only one there. + */ +static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) +{ + INDEX_ENTRY *ie; + + ntfs_log_trace("Entering.\n"); + + ie = ntfs_ie_get_first(ih); + ie->flags &= ~INDEX_ENTRY_NODE; + ie->length -= sizeof(VCN); + + ih->index_length -= sizeof(VCN); + ih->flags &= ~LARGE_INDEX; + + /* Not fatal error */ + ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); + + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + ntfs_index_ctx_reinit(icx); +} + +/** + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is not the only one there. + */ +static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, + INDEX_BLOCK *ib) +{ + INDEX_ENTRY *ie, *ie_prev; + + ntfs_log_trace("Entering.\n"); + + ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); + ie_prev = ntfs_ie_prev(ih, ie); + + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); + return ntfs_ih_takeout(icx, ih, ie_prev, ib); +} + +static int ntfs_index_rm_leaf(ntfs_index_context *icx) +{ + INDEX_BLOCK *ib = NULL; + INDEX_HEADER *parent_ih; + INDEX_ENTRY *ie; + int ret = STATUS_ERROR; + + ntfs_log_trace("pindex: %d\n", icx->pindex); + + if (ntfs_icx_parent_dec(icx)) + return STATUS_ERROR; + + if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) + return STATUS_ERROR; + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) + parent_ih = &icx->ir->index; + else { + ib = ntfs_malloc(icx->block_size); + if (!ib) + return STATUS_ERROR; + + if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) + goto out; + + parent_ih = &ib->index; + } + + ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); + if (!ntfs_ie_end(ie)) { + ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); + goto out; + } + + if (ntfs_ih_zero_entry(parent_ih)) { + + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { + ntfs_ir_leafify(icx, parent_ih); + goto ok; + } + + ret = ntfs_index_rm_leaf(icx); + goto out; + } + + if (ntfs_ih_reparent_end(icx, parent_ih, ib)) + goto out; +ok: + ret = STATUS_OK; +out: + free(ib); + return ret; +} + +static int ntfs_index_rm_node(ntfs_index_context *icx) +{ + int entry_pos; + VCN vcn; + INDEX_BLOCK *ib = NULL; + INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry; + INDEX_HEADER *ih; + u32 new_size; + int delta, ret = STATUS_ERROR; + + ntfs_log_trace("Entering.\n"); + + if (!icx->ia_na) { + icx->ia_na = ntfs_ia_open(icx, icx->ni); + if (!icx->ia_na) + return STATUS_ERROR; + } + + ib = ntfs_malloc(icx->block_size); + if (!ib) + return STATUS_ERROR; + + ie_succ = ntfs_ie_get_next(icx->entry); + entry_pos = icx->parent_pos[icx->pindex]++; +descend: + vcn = ntfs_ie_get_vcn(ie_succ); + if (ntfs_ib_read(icx, vcn, ib)) + goto out; + + ie_succ = ntfs_ie_get_first(&ib->index); + + if (ntfs_icx_parent_inc(icx)) + goto out; + + icx->parent_vcn[icx->pindex] = vcn; + icx->parent_pos[icx->pindex] = 0; + + if ((ib->index.flags & NODE_MASK) == INDEX_NODE) + goto descend; + + if (ntfs_ih_zero_entry(&ib->index)) { + errno = EOPNOTSUPP; + ntfs_log_perror("Failed to find any entry in an index block. " + "Please run chkdsk."); + goto out; + } + + ie = ntfs_ie_dup(ie_succ); + if (!ie) + goto out; + + if (ntfs_ie_add_vcn(&ie)) + goto out2; + + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry)); + + if (icx->is_in_root) + ih = &icx->ir->index; + else + ih = &icx->ib->index; + + delta = ie->length - icx->entry->length; + new_size = le32_to_cpu(ih->index_length) + delta; + if (delta > 0) { + if (icx->is_in_root) { + if (ntfs_ir_truncate(icx, new_size)) { + errno = EOPNOTSUPP; + ntfs_log_perror("Denied to truncate INDEX_ROOT" + " during entry removal"); + goto out2; + } + + ih = &icx->ir->index; + entry = ntfs_ie_get_by_pos(ih, entry_pos); + + } else if (new_size > ih->allocated_size) { + errno = EOPNOTSUPP; + ntfs_log_perror("Denied to split INDEX_BLOCK during " + "entry removal"); + goto out2; + } + } + + ntfs_ie_delete(ih, entry); + ntfs_ie_insert(ih, ie, entry); + + if (icx->is_in_root) { + if (ntfs_ir_truncate(icx, new_size)) + goto out2; + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); + } else + if (ntfs_icx_ib_write(icx)) + goto out2; + + ntfs_ie_delete(&ib->index, ie_succ); + + if (ntfs_ih_zero_entry(&ib->index)) { + if (ntfs_index_rm_leaf(icx)) + goto out2; + } else + if (ntfs_ib_write(icx, vcn, ib)) + goto out2; + + ret = STATUS_OK; +out2: + free(ie); +out: + free(ib); + return ret; } /** * ntfs_index_rm - remove entry from the index - * @ictx: index context describing entry to delete + * @icx: index context describing entry to delete * - * Delete entry described by @ictx from the index. NOTE: This function does not - * support all cases, so it can fail with EOPNOTSUPP error code. In any case - * index context is always reinitialized after use of this function, so it can - * be used for index lookup once again. + * Delete entry described by @icx from the index. Index context is always + * reinitialized after use of this function, so it can be used for index + * lookup once again. * * Return 0 on success or -1 on error with errno set to the error code. */ -int ntfs_index_rm(ntfs_index_context *ictx) +int ntfs_index_rm(ntfs_index_context *icx) { INDEX_HEADER *ih; - u32 new_index_length; int err; ntfs_log_trace("Entering.\n"); - if (!ictx || (!ictx->ia && !ictx->ir) || - ictx->entry->flags & INDEX_ENTRY_END) { + + if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { ntfs_log_error("Invalid arguments.\n"); - err = EINVAL; + errno = EINVAL; goto err_out; } - if (ictx->is_in_root) - ih = &ictx->ir->index; + if (icx->is_in_root) + ih = &icx->ir->index; else - ih = &ictx->ia->index; - /* Don't support deletion of entries with subnodes yet. */ - if (ictx->entry->flags & INDEX_ENTRY_NODE) { - err = EOPNOTSUPP; - goto err_out; - } - /* Calculate new length of the index. */ - new_index_length = le32_to_cpu(ih->index_length) - - le16_to_cpu(ictx->entry->length); - /* Don't support deletion of the last entry in the allocation block. */ - if (!ictx->is_in_root && (new_index_length <= - le32_to_cpu(ih->entries_offset) + - sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN))) { - err = EOPNOTSUPP; - goto err_out; - } - /* Update index length and remove index entry. */ - ih->index_length = cpu_to_le32(new_index_length); - if (ictx->is_in_root) - ih->allocated_size = ih->index_length; - memmove(ictx->entry, (u8*)ictx->entry + le16_to_cpu( - ictx->entry->length), new_index_length - - ((u8*)ictx->entry - (u8*)ih)); - ntfs_index_entry_mark_dirty(ictx); - /* Resize INDEX_ROOT attribute. */ - if (ictx->is_in_root) { - ntfs_attr *na; + ih = &icx->ib->index; + + if (icx->entry->flags & INDEX_ENTRY_NODE) { + + if (ntfs_index_rm_node(icx)) + goto err_out; - na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name, - ictx->name_len); - if (!na) { - err = errno; - ntfs_log_error("Failed to open INDEX_ROOT attribute. " - "Leaving inconsistent metadata.\n"); + } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { + + ntfs_ie_delete(ih, icx->entry); + + if (icx->is_in_root) { + err = ntfs_ir_truncate(icx, + le32_to_cpu(ih->index_length)); + if (err != STATUS_OK) + goto err_out; + } else + if (ntfs_icx_ib_write(icx)) + goto err_out; + } else { + if (ntfs_index_rm_leaf(icx)) goto err_out; - } - if (ntfs_attr_truncate(na, new_index_length + offsetof( - INDEX_ROOT, index))) { - err = errno; - ntfs_log_error("Failed to truncate INDEX_ROOT " - "attribute. Leaving inconsistent " - "metadata.\n"); - goto err_out; - } - ntfs_attr_close(na); } - ntfs_index_ctx_reinit(ictx); + + ntfs_index_ctx_reinit(icx); ntfs_log_trace("Done.\n"); return 0; err_out: - ntfs_index_ctx_reinit(ictx); - ntfs_log_trace("Failed.\n"); + err = errno; + ntfs_index_ctx_reinit(icx); errno = err; + ntfs_log_trace("Failed.\n"); return -1; } @@ -680,23 +1776,12 @@ INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr) name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); - ctx = ntfs_attr_get_search_ctx(ni, NULL); - if (!ctx) { - ntfs_log_perror("ntfs_get_search_ctx failed"); + if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) return NULL; - } - if (ntfs_attr_lookup(AT_INDEX_ROOT, name, attr->name_length, 0, 0, NULL, - 0, ctx)) { - ntfs_log_perror("ntfs_attr_lookup failed"); + root = ntfs_malloc(sizeof(INDEX_ROOT)); + if (!root) goto out; - } - - root = malloc(sizeof(INDEX_ROOT)); - if (!root) { - ntfs_log_perror("malloc failed"); - goto out; - } *root = *((INDEX_ROOT *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset))); From 70aef8d69cf297b27ca1bec8471eb95419129a0f Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 2 Aug 2006 03:57:40 +0000 Subject: [PATCH 024/289] Prevent index root to be moved out from base mft record --- libntfs/attrib.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 3e4f83c2..cf4f157e 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -3731,9 +3731,13 @@ cluster_free_err_out: * * On success return 0 and on error return -1 with errno set to the error code. * The following error codes are defined: - * ENOMEM - Not enough memory to complete operation. - * ERANGE - @newsize is not valid for the attribute type of @na. - * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. + * ENOMEM - Not enough memory to complete operation. + * ERANGE - @newsize is not valid for the attribute type of @na. + * ENOSPC - There is no enough space on the volume to allocate + * new clusters or in base mft to resize $ATTRIBUTE_LIST. + * EOVERFLOW - Resident attribute can not become non resident and + * already filled whole MFT record, but had not reached + * @newsize bytes length. */ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) { @@ -3883,6 +3887,22 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) goto put_err_out; } + /* + * Force index allocation creation instead of moving out index root + * from the base MFT record. + */ + if (na->type == AT_INDEX_ROOT && na->data_size > sizeof(INDEX_ROOT) + + sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)) { + INDEX_ROOT *ir; + + ir = (INDEX_ROOT*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + if (!(ir->index.flags & LARGE_INDEX)) { + err = EOVERFLOW; + goto put_err_out; + } + } + /* * Check whether attribute is already single in the this MFT record. * 8 added for the attribute terminator. @@ -3890,7 +3910,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) if (le32_to_cpu(ctx->mrec->bytes_in_use) == le16_to_cpu(ctx->mrec->attrs_offset) + le32_to_cpu(ctx->attr->length) + 8) { - err = ENOSPC; + err = EOVERFLOW; goto put_err_out; } @@ -4960,8 +4980,15 @@ put_err_out: * * On success return 0 and on error return -1 with errno set to the error code. * The following error codes are defined: - * EINVAL - Invalid arguments were passed to the function. - * EOPNOTSUPP - The desired resize is not implemented yet. + * EINVAL - Invalid arguments were passed to the function. + * EACCES - Attribute is encrypted. + * ERANGE - @newsize is not valid for the attribute type of @na. + * ENOSPC - There is no enough space on the volume to allocate + * new clusters or in base mft to resize $ATTRIBUTE_LIST. + * EOVERFLOW - Resident attribute can not become non resident and + * already filled whole MFT record, but had not reached + * @newsize bytes length. + * EOPNOTSUPP - The desired resize is not implemented yet. */ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) { From aea6c7ea4fbe3be7a05cd9a9f7e1fa43937658e5 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 2 Aug 2006 11:19:39 +0000 Subject: [PATCH 025/289] Change version to 1.13.2-WIP not 3.0.0-WIP and bump libntfs version to reflect incompatible source and binary interface changes... --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d7056501..0941bf39 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ # AC_PREREQ(2.59) -AC_INIT([ntfsprogs],[3.0.0-WIP],[linux-ntfs-dev@lists.sourceforge.net]) +AC_INIT([ntfsprogs],[1.13.2-WIP],[linux-ntfs-dev@lists.sourceforge.net]) # # Before making a release, the LTVERSION string should be modified. @@ -50,7 +50,7 @@ AC_INIT([ntfsprogs],[3.0.0-WIP],[linux-ntfs-dev@lists.sourceforge.net]) # # - If the interface is the same as the previous version, change to C:R+1:A # -LTVERSION_LIBNTFS="9:0:0" +LTVERSION_LIBNTFS="10:0:0" AC_SUBST(LTVERSION_LIBNTFS) AC_CANONICAL_HOST([]) From 1493070b8e5834ed9581467b1d29c1d9d7109d8e Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 3 Aug 2006 02:49:00 +0000 Subject: [PATCH 026/289] Fix include order. Thanks, Yuval! --- include/ntfs/support.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 46786d08..7b9aa351 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -24,10 +24,6 @@ #ifndef _NTFS_SUPPORT_H #define _NTFS_SUPPORT_H -#include - -#include "logging.h" - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -36,6 +32,12 @@ #include #endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "logging.h" + /* * Our mailing list. Use this define to prevent typos in email address. */ From a00ee0238890cf4e687b6f35a7aebb08326ee111 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 3 Aug 2006 04:30:41 +0000 Subject: [PATCH 027/289] had not noticed lack of externs :( --- include/ntfs/index.h | 6 +++--- libntfs/attrib.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ntfs/index.h b/include/ntfs/index.h index ecd53cfc..7de05e60 100644 --- a/include/ntfs/index.h +++ b/include/ntfs/index.h @@ -122,9 +122,9 @@ extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr); extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie); -char *ntfs_ie_filename_get(INDEX_ENTRY *ie); -void ntfs_ie_filename_dump(INDEX_ENTRY *ie); -void ntfs_ih_filename_dump(INDEX_HEADER *ih); +extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie); +extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie); +extern void ntfs_ih_filename_dump(INDEX_HEADER *ih); /** * ntfs_index_entry_mark_dirty - mark an index entry dirty diff --git a/libntfs/attrib.c b/libntfs/attrib.c index cf4f157e..2f18a810 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -4991,7 +4991,7 @@ put_err_out: * EOPNOTSUPP - The desired resize is not implemented yet. */ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) -{ +{ int ret; if (!na || newsize < 0 || From 600b5d4fa607a9e085fcf50a5a320af31086aba1 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 13:38:38 +0000 Subject: [PATCH 028/289] fix mkntfs_get_page_size() declaration --- ntfsprogs/mkntfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index fe887c6f..60f74ecf 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -3425,7 +3425,7 @@ done: /** * mkntfs_get_page_size - detect the system's memory page size. */ -static long mkntfs_get_page_size() +static long mkntfs_get_page_size(void) { long page_size; #ifdef _SC_PAGESIZE From 64a319948b9fb400a470a0470fe5937e4301f5b6 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 13:46:40 +0000 Subject: [PATCH 029/289] convert all malloc,calloc to ntfs_{malloc,calloc} --- ntfsprogs/mkntfs.c | 67 +++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 60f74ecf..a7230d91 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -146,6 +146,7 @@ #include "attrdef.h" #include "version.h" #include "logging.h" +#include "support.h" #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS #error "No default device io operations! Cannot build mkntfs. \ @@ -2028,7 +2029,7 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, le16_to_cpu(ctx->attr->value_offset)); i = (strlen(file_name) + 1) * sizeof(ntfschar); fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = malloc(fn_size); + fn = ntfs_malloc(fn_size); if (!fn) { ntfs_attr_put_search_ctx(ctx); return -errno; @@ -2237,7 +2238,7 @@ static int add_attr_index_root(MFT_RECORD *m, const char *name, int err, val_len; val_len = sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER); - r = malloc(val_len); + r = ntfs_malloc(val_len); if (!r) return -errno; r->type = (indexed_attr_type == AT_FILE_NAME) ? AT_FILE_NAME : 0; @@ -3105,7 +3106,7 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, /* Create the file_name attribute. */ i = (strlen(file_name) + 1) * sizeof(ntfschar); fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = malloc(fn_size); + fn = ntfs_malloc(fn_size); if (!fn) return -errno; fn->parent_directory = ref_parent; @@ -3220,7 +3221,7 @@ static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, /* Create the file_name attribute. */ i = (strlen(file_name) + 1) * sizeof(ntfschar); fn_size = sizeof(FILE_NAME_ATTR) + i; - fn = malloc(fn_size); + fn = ntfs_malloc(fn_size); if (!fn) return -errno; fn->parent_directory = ref_parent; @@ -3784,11 +3785,10 @@ static BOOL mkntfs_initialize_bitmaps(void) if (!g_mft_bitmap) return FALSE; /* Create runlist for mft bitmap. */ - g_rl_mft_bmp = malloc(2 * sizeof(runlist)); - if (!g_rl_mft_bmp) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_mft_bmp = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_mft_bmp) return FALSE; - } + g_rl_mft_bmp[0].vcn = 0LL; /* Mft bitmap is right after $Boot's data. */ i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; @@ -3850,11 +3850,10 @@ static BOOL mkntfs_initialize_rl_mft(void) */ g_mft_zone_end += g_mft_lcn; /* Create runlist for mft. */ - g_rl_mft = malloc(2 * sizeof(runlist)); - if (!g_rl_mft) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_mft = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_mft) return FALSE; - } + g_rl_mft[0].vcn = 0LL; g_rl_mft[0].lcn = g_mft_lcn; /* rounded up division by cluster size */ @@ -3872,11 +3871,10 @@ static BOOL mkntfs_initialize_rl_mft(void) ntfs_log_debug("$MFTMirr logical cluster number = 0x%llx\n", g_mftmirr_lcn); /* Create runlist for mft mirror. */ - g_rl_mftmirr = malloc(2 * sizeof(runlist)); - if (!g_rl_mftmirr) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_mftmirr = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_mftmirr) return FALSE; - } + g_rl_mftmirr[0].vcn = 0LL; g_rl_mftmirr[0].lcn = g_mftmirr_lcn; /* @@ -3909,11 +3907,10 @@ static BOOL mkntfs_initialize_rl_logfile(void) u64 volume_size; /* Create runlist for log file. */ - g_rl_logfile = malloc(2 * sizeof(runlist)); - if (!g_rl_logfile) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_logfile = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_logfile) return FALSE; - } + volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; @@ -3994,11 +3991,10 @@ static BOOL mkntfs_initialize_rl_boot(void) { int i, j; /* Create runlist for $Boot. */ - g_rl_boot = malloc(2 * sizeof(runlist)); - if (!g_rl_boot) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_boot = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_boot) return FALSE; - } + g_rl_boot[0].vcn = 0LL; g_rl_boot[0].lcn = 0LL; /* @@ -4022,11 +4018,10 @@ static BOOL mkntfs_initialize_rl_boot(void) static BOOL mkntfs_initialize_rl_bad(void) { /* Create runlist for $BadClus, $DATA named stream $Bad. */ - g_rl_bad = malloc(2 * sizeof(runlist)); - if (!g_rl_bad) { - ntfs_log_perror("Failed to allocate internal buffer"); + g_rl_bad = ntfs_malloc(2 * sizeof(runlist)); + if (!g_rl_bad) return FALSE; - } + g_rl_bad[0].vcn = 0LL; g_rl_bad[0].lcn = -1LL; /* @@ -4496,11 +4491,10 @@ static BOOL mkntfs_create_root_structures(void) /* dump_mft_record(m); */ ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); m = (MFT_RECORD*)(g_buf + 2 * g_vol->mft_record_size); - buf_log = malloc(g_logfile_size); - if (!buf_log) { - ntfs_log_perror("Failed to allocate internal buffer"); + buf_log = ntfs_malloc(g_logfile_size); + if (!buf_log) return FALSE; - } + memset(buf_log, -1, g_logfile_size); err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_logfile, buf_log, g_logfile_size); @@ -4968,11 +4962,10 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) g_vol->cluster_size = opts.cluster_size; /* Length is in unicode characters. */ g_vol->upcase_len = 65536; - g_vol->upcase = malloc(g_vol->upcase_len * sizeof(ntfschar)); - if (!g_vol->upcase) { - ntfs_log_perror("Could not create upcase structure"); + g_vol->upcase = ntfs_malloc(g_vol->upcase_len * sizeof(ntfschar)); + if (!g_vol->upcase) goto done; - } + init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); if (g_vol->major_ver < 3) { g_vol->attrdef = ntfs_calloc(36000); @@ -4982,7 +4975,7 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) g_vol->attrdef_len = 36000; } } else { - g_vol->attrdef = malloc(sizeof(attrdef_ntfs3x_array)); + g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); if (g_vol->attrdef) { memcpy(g_vol->attrdef, attrdef_ntfs3x_array, sizeof(attrdef_ntfs3x_array)); From c41b7a65a1baf7dbfa39fc7585e91c7c403c9e81 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 14:17:02 +0000 Subject: [PATCH 030/289] upgrade_to_large_index(): fix double freeing ctx in certain error situation --- ntfsprogs/mkntfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index a7230d91..28d52d55 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -2424,7 +2424,6 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, err = -EINVAL; goto err_out; } - ntfs_attr_put_search_ctx(ctx); r = (INDEX_ROOT*)((char*)a + le16_to_cpu(a->value_offset)); re_end = (char*)r + le32_to_cpu(a->value_length); re_start = (char*)&r->index + le32_to_cpu(r->index.entries_offset); @@ -2520,6 +2519,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, goto err_out; } *idx = ia_val; + ntfs_attr_put_search_ctx(ctx); return 0; err_out: ntfs_attr_put_search_ctx(ctx); From 0dae4a9c77ee469877e9dca57ddd9849efd564d7 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 14:34:07 +0000 Subject: [PATCH 031/289] fix missing error outputs --- ntfsprogs/ntfsclone.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 2694265c..4e79ad8f 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -717,6 +717,7 @@ static void wipe_index_entry_timestams(INDEX_ENTRY *e) { s64 timestamp = utc2ntfs(0); + /* FIXME: can fall into infinite loop if corrupted */ while (!(e->flags & INDEX_ENTRY_END)) { e->key.file_name.creation_time = timestamp; @@ -743,7 +744,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) indexr = ntfs_index_root_get(ni, attr); if (!indexr) { - ntfs_log_perror("Failed to read $INDEX_ROOT attribute"); + perr_printf("Failed to read $INDEX_ROOT attribute"); return; } @@ -755,22 +756,22 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); if (!byte) { - ntfs_log_perror("Failed to read $BITMAP attribute"); + perr_printf("Failed to read $BITMAP attribute"); goto out_indexr; } na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, name, name_len); if (!na) { - ntfs_log_perror("Failed to open $INDEX_ALLOCATION attribute"); + perr_printf("Failed to open $INDEX_ALLOCATION attribute"); goto out_bitmap; } tmp_indexa = indexa = malloc(na->data_size); if (!tmp_indexa) { - ntfs_log_perror("malloc failed"); + perr_printf("malloc failed"); goto out_na; } if (ntfs_attr_pread(na, 0, na->data_size, indexa) != na->data_size) { - ntfs_log_perror("Failed to read $INDEX_ALLOCATION attribute"); + perr_printf("Failed to read $INDEX_ALLOCATION attribute"); goto out_indexa; } @@ -779,7 +780,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) if (*byte & (1 << bit)) { if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa, indexr->index_block_size)) { - ntfs_log_perror("Damaged INDX record"); + perr_printf("Damaged INDX record"); goto out_indexa; } entry = (INDEX_ENTRY *)((u8 *)tmp_indexa + le32_to_cpu( @@ -792,7 +793,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)tmp_indexa, indexr->index_block_size)) { - ntfs_log_perror("INDX write fixup failed"); + perr_printf("INDX write fixup failed"); goto out_indexa; } } @@ -806,7 +807,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) } if (ntfs_rl_pwrite(vol, na->rl, 0, na->data_size, indexa) != na->data_size) - ntfs_log_perror("ntfs_rl_pwrite failed"); + perr_printf("ntfs_rl_pwrite failed"); out_indexa: free(indexa); out_na: From bd659977c224973f74e498cd3f6fe9c4a6e70b63 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 14:40:28 +0000 Subject: [PATCH 032/289] don't create image files with executable bit set --- ntfsprogs/ntfsclone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 4e79ad8f..fdf80f3c 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1671,7 +1671,7 @@ int main(int argc, char **argv) flags |= O_EXCL; } - if ((fd_out = open(opt.output, flags, S_IRWXU)) == -1) + if ((fd_out = open(opt.output, flags, S_IRUSR | S_IWUSR)) == -1) perr_exit("Opening file '%s' failed", opt.output); if (!opt.save_image) From d727768a805f29f8c1cb61da4fec111c41286f99 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 14:49:35 +0000 Subject: [PATCH 033/289] convert all malloc,calloc to ntfs_{malloc,calloc} --- ntfsprogs/ntfsclone.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index fdf80f3c..f7a2f6e7 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -629,7 +629,8 @@ static void clone_ntfs(u64 nr_clusters) else Printf("Cloning NTFS ...\n"); - if ((buf = calloc(1, csize)) == NULL) + buf = ntfs_calloc(csize); + if (!buf) perr_exit("clone_ntfs"); progress_init(&progress, p_counter, nr_clusters, 100); @@ -765,11 +766,10 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) perr_printf("Failed to open $INDEX_ALLOCATION attribute"); goto out_bitmap; } - tmp_indexa = indexa = malloc(na->data_size); - if (!tmp_indexa) { - perr_printf("malloc failed"); + tmp_indexa = indexa = ntfs_malloc(na->data_size); + if (!tmp_indexa) goto out_na; - } + if (ntfs_attr_pread(na, 0, na->data_size, indexa) != na->data_size) { perr_printf("Failed to read $INDEX_ALLOCATION attribute"); goto out_indexa; @@ -1158,7 +1158,7 @@ static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk) /* FIXME: Terrible kludge for libntfs not being able to return a deleted MFT record as inode */ - ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode)); + ni = ntfs_calloc(sizeof(ntfs_inode)); if (!ni) perr_exit("walk_clusters"); @@ -1239,7 +1239,8 @@ static void setup_lcn_bitmap(void) /* Determine lcn bitmap byte size and allocate it. */ lcn_bitmap.size = rounded_up_division(vol->nr_clusters, 8); - if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size))) + lcn_bitmap.bm = ntfs_calloc(lcn_bitmap.size); + if (!lcn_bitmap.bm) perr_exit("Failed to allocate internal buffer"); bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap); From 58699ef91b6daa8b448a1410378c98fcdb5505e5 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 14:52:19 +0000 Subject: [PATCH 034/289] more detailed error messages --- ntfsprogs/ntfsclone.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index f7a2f6e7..08797213 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -745,7 +745,8 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) indexr = ntfs_index_root_get(ni, attr); if (!indexr) { - perr_printf("Failed to read $INDEX_ROOT attribute"); + perr_printf("Failed to read $INDEX_ROOT attribute of inode " + "%lld", ni->mft_no); return; } @@ -807,7 +808,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) } if (ntfs_rl_pwrite(vol, na->rl, 0, na->data_size, indexa) != na->data_size) - perr_printf("ntfs_rl_pwrite failed"); + perr_printf("ntfs_rl_pwrite failed for inode %lld", ni->mft_no); out_indexa: free(indexa); out_na: From 5c0ce5407ee89aa87d9c32d09e5234d8eec6dd74 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 15:00:27 +0000 Subject: [PATCH 035/289] metadata cloning: write out extent records --- ntfsprogs/ntfsclone.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 08797213..17131b44 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1137,6 +1137,21 @@ static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) perr_exit("ntfs_mft_record_write"); } +static void mft_inode_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) +{ + s32 i; + + mft_record_write_with_same_usn(volume, ni); + + if (ni->nr_extents <= 0) + return; + + for (i = 0; i < ni->nr_extents; ++i) { + ntfs_inode *eni = ni->extent_nis[i]; + mft_record_write_with_same_usn(volume, eni); + } +} + static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk) { s64 inode = 0; @@ -1208,7 +1223,7 @@ static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk) out: if (wipe) { wipe_unused_mft_data(ni); - mft_record_write_with_same_usn(volume, ni); + mft_inode_write_with_same_usn(volume, ni); } if (ntfs_inode_close(ni)) From 39b9061d8be10bfbbc81e0655c3b24dda4a9bfa2 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 15:15:08 +0000 Subject: [PATCH 036/289] wipe_index_allocation_timestamps(): don't try to dump empty ia --- ntfsprogs/ntfsclone.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 17131b44..ec362fcf 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -767,6 +767,10 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) perr_printf("Failed to open $INDEX_ALLOCATION attribute"); goto out_bitmap; } + + if (!na->data_size) + goto out_na; + tmp_indexa = indexa = ntfs_malloc(na->data_size); if (!tmp_indexa) goto out_na; From 6ae2cece3c9763e36d1a78bfed04581372bd4f35 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 15:50:12 +0000 Subject: [PATCH 037/289] fine grained AT_INDEX_ALLOCATION comparison --- ntfsprogs/ntfscmp.c | 129 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 120 insertions(+), 9 deletions(-) diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 777208ea..c6d738ae 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -18,7 +18,9 @@ #include #include "utils.h" +#include "mst.h" #include "version.h" +#include "support.h" static const char *EXEC_NAME = "ntfscmp"; @@ -464,6 +466,118 @@ static void print_ctx(ntfs_attr_search_ctx *ctx) free_name(&name); } +static void print_differ(ntfs_attr *na) +{ + print_na(na); + printf("content: DIFFER\n"); +} + +static int cmp_buffer(u8 *buf1, u8 *buf2, long long int size, ntfs_attr *na) +{ + if (memcmp(buf1, buf2, size)) { + print_differ(na); + return -1; + } + return 0; +} + +struct cmp_ia { + INDEX_ALLOCATION *ia; + INDEX_ALLOCATION *tmp_ia; + u8 *bitmap; + u8 *byte; + s64 bm_size; +}; + +static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia) +{ + cia->bitmap = ntfs_attr_readall(na->ni, AT_BITMAP, na->name, + na->name_len, &cia->bm_size); + if (!cia->bitmap) { + perr_println("Failed to readall BITMAP"); + return -1; + } + cia->byte = cia->bitmap; + + cia->tmp_ia = cia->ia = ntfs_malloc(na->data_size); + if (!cia->tmp_ia) + goto free_bm; + + if (ntfs_attr_pread(na, 0, na->data_size, cia->ia) != na->data_size) { + perr_println("Failed to pread INDEX_ALLOCATION"); + goto free_ia; + } + + return 0; +free_ia: + free(cia->ia); +free_bm: + free(cia->bitmap); + return -1; +} + +static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) +{ + struct cmp_ia cia1, cia2; + int bit, ret1, ret2; + u32 ib_size; + + if (setup_cmp_ia(na1, &cia1)) + return; + if (setup_cmp_ia(na2, &cia2)) + return; + /* + * FIXME: ia can be the same even if the bitmap sizes are different. + */ + if (cia1.bm_size != cia1.bm_size) + goto out; + + if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1)) + goto out; + + if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1)) + goto out; + + ib_size = cia1.ia->index.allocated_size + 0x18; + + bit = 0; + while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) { + if (*cia1.byte & (1 << bit)) { + ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia1.tmp_ia, + ib_size); + ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia2.tmp_ia, + ib_size); + if (ret1 != ret2) { + print_differ(na1); + goto out; + } + + if (ret1 == -1) + continue; + + if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18, + ((u8 *)cia2.tmp_ia) + 0x18, + cia1.ia->index.index_length, na1)) + goto out; + } + + cia1.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia1.tmp_ia + ib_size); + cia2.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia2.tmp_ia + ib_size); + + bit++; + if (bit > 7) { + bit = 0; + cia1.byte++; + } + } +out: + free(cia1.ia); + free(cia2.ia); + free(cia1.bitmap); + free(cia2.bitmap); + return; +} + static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2) { s64 pos; @@ -502,15 +616,9 @@ static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2) printf("%lld != %lld\n", pos + count1, na1->data_size); exit(1); } - - if (memcmp(buf1, buf2, count1)) { - print_na(na1); - printf("content"); - if (opt.verbose) - printf(" (len = %lld)", count1); - printf(": DIFFER\n"); + + if (cmp_buffer(buf1, buf2, count1, na1)) return; - } } err_printf("%s read overrun: ", __FUNCTION__); @@ -575,7 +683,10 @@ static void cmp_attribute(ntfs_attr_search_ctx *ctx1, return; } - cmp_attribute_data(na1, na2); + if (na1->type == AT_INDEX_ALLOCATION) + cmp_index_allocation(na1, na2); + else + cmp_attribute_data(na1, na2); close_attribs: ntfs_attr_close(na1); From c4a3f8b3e92fb186c69ae5641f44ba0e344f4488 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 16:06:57 +0000 Subject: [PATCH 038/289] convert all malloc,calloc to ntfs_{malloc,calloc} --- ntfsprogs/ntfsresize.c | 17 ++++++++++------- ntfsprogs/utils.c | 7 +++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 1ad39cd1..0a9b032c 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -1203,8 +1203,9 @@ static void replace_attribute_runlist(ntfs_volume *vol, a->length += l; } - if (!(mp = calloc(1, mp_size))) - perr_exit("Couldn't get memory"); + mp = ntfs_calloc(mp_size); + if (!mp) + perr_exit("ntfsc_calloc couldn't get memory"); if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl, 0, NULL)) perr_exit("ntfs_mapping_pairs_build"); @@ -1468,8 +1469,9 @@ static void rl_split_run(runlist **rl, int run, s64 pos) size_head = run * sizeof(runlist_element); size_tail = (items - run - 1) * sizeof(runlist_element); - if (!(rl_new = (runlist *)malloc(new_size))) - perr_exit("malloc"); + rl_new = ntfs_malloc(new_size); + if (!rl_new) + perr_exit("ntfs_malloc"); rle_new = rl_new + run; rle = *rl + run; @@ -1719,9 +1721,9 @@ static void relocate_inodes(ntfs_resize_t *resize) progress_init(&resize->progress, 0, resize->relocations, resize->progress.flags); resize->relocations = 0; - resize->mrec = (MFT_RECORD *)malloc(resize->vol->mft_record_size); + resize->mrec = ntfs_malloc(resize->vol->mft_record_size); if (!resize->mrec) - perr_exit("malloc failed"); + perr_exit("ntfs_malloc failed"); nr_mft_records = resize->vol->mft_na->initialized_size >> resize->vol->mft_record_size_bits; @@ -2119,7 +2121,8 @@ static int setup_lcn_bitmap(struct bitmap *bm, s64 nr_clusters) /* Determine lcn bitmap byte size and allocate it. */ bm->size = rounded_up_division(nr_clusters, 8); - if (!(bm->bm = (unsigned char *)calloc(1, bm->size))) + bm->bm = ntfs_calloc(bm->size); + if (!bm->bm) return -1; bitmap_file_data_fixup(nr_clusters, bm); diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 64293596..6032a3fe 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -421,7 +421,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize) FILE_NAME_ATTR *attr; int name_space; MFT_REF parent = FILE_root; - char *names[max_path + 1];// XXX malloc? and make max bigger? + char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger? int i, len, offset = 0; if (!inode || !buffer) { @@ -465,7 +465,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize) &names[i], 0) < 0) { char *temp; ntfs_log_error("Couldn't translate filename to current locale.\n"); - temp = malloc(30); + temp = ntfs_malloc(30); if (!temp) return 0; snprintf(temp, 30, "", (unsigned @@ -965,10 +965,9 @@ int mft_next_record(struct mft_search_ctx *ctx) ctx->inode->mft_no = ctx->mft_num; ctx->inode->vol = ctx->vol; - ctx->inode->mrec = malloc(ctx->vol->mft_record_size); + ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size); if (!ctx->inode->mrec) { free(ctx->inode); // == ntfs_inode_close - ntfs_log_error("Out of memory. Aborting.\n"); return -1; } From beb044b03654a34db5a8800eaecc88d7b2cc7ac3 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:23:01 +0000 Subject: [PATCH 039/289] rename 'Flags:' fields to be unique --- ntfsprogs/ntfsinfo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 5d774ec4..38077c80 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -847,7 +847,7 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); /* TODO: parse the flags */ - printf("%s\tFlags:\t\t\t 0x%0x\n", indent, sec_desc->control); + printf("%s\tControl:\t\t 0x%0x\n", indent, sec_desc->control); if (sec_desc->owner) { sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + @@ -988,7 +988,7 @@ static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) printf("\tVolume Version:\t\t %d.%d\n", vol_information->major_ver, vol_information->minor_ver); - printf("\tFlags:\t\t\t "); + printf("\tVolume Flags:\t\t "); if (vol_information->flags & VOLUME_IS_DIRTY) printf("DIRTY "); if (vol_information->flags & VOLUME_RESIZE_LOG_FILE) @@ -1129,7 +1129,7 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) } /* TODO: parse the flags */ - printf("\tFlags:\t\t\t 0x%04hx\n",le16_to_cpu(a->flags)); + printf("\tAttribute flags:\t 0x%04hx\n",le16_to_cpu(a->flags)); printf("\tAttribute instance:\t %u\n", le16_to_cpu(a->instance)); /* Resident attribute */ @@ -1367,7 +1367,7 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) le16_to_cpu(entry->length)); ntfs_log_verbose("\t\tKey length:\t\t %u\n", le16_to_cpu(entry->key_length)); - ntfs_log_verbose("\t\tFlags:\t\t\t 0x%02x\n", + ntfs_log_verbose("\t\tIndex entry flags:\t 0x%02x\n", le16_to_cpu(entry->flags)); if (entry->flags & INDEX_ENTRY_NODE) @@ -1508,7 +1508,7 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) (unsigned int)le32_to_cpu(index_root->index.index_length)); /* the flags are 8bit long, no need for byte-order handling */ - printf("\tFlags:\t\t\t 0x%02x\n",index_root->index.flags); + printf("\tIndex header flags:\t 0x%02x\n",index_root->index.flags); entry = (INDEX_ENTRY *)((u8 *)index_root + le32_to_cpu(index_root->index.entries_offset) + 0x10); @@ -1702,7 +1702,7 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) ea = (EA_ATTR*)((u8*)attr + le16_to_cpu(attr->value_offset)); } while (1) { - printf("\n\tFlags:\t\t "); + printf("\n\tEA flags:\t\t "); if (ea->flags) { if (ea->flags == NEED_EA) printf("NEED_EA\n"); From a5bb7301ec348836518693a965d1d59bd296931d Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:35:05 +0000 Subject: [PATCH 040/289] add ntfs_dump_index_header(); dump full ia INDEX_HEADER --- ntfsprogs/ntfsinfo.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 38077c80..4a7382e1 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1471,6 +1471,19 @@ static void ntfs_dump_index_attr_type(INDEX_ATTR_TYPE type) printf("\n"); } +static void ntfs_dump_index_header(const char *indent, INDEX_HEADER *idx) +{ + printf("%sEntries Offset:\t\t %u\n", indent, + (unsigned int)le32_to_cpu(idx->entries_offset)); + printf("%sIndex Size:\t\t %u\n", indent, + (unsigned int)le32_to_cpu(idx->index_length)); + printf("%sAllocated Size:\t\t %u\n", indent, + (unsigned int)le32_to_cpu(idx->allocated_size)); + printf("%sIndex header flags:\t 0x%02x\n", indent, idx->flags); + + /* FIXME: there are 3 reserved bytes here */ +} + /** * ntfs_dump_attr_index_root() * @@ -1501,14 +1514,7 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) printf("\tClusters Per Block:\t %u\n", index_root->clusters_per_index_block); - /* index header starts here */ - printf("\tAllocated Size:\t\t %u\n", - (unsigned int)le32_to_cpu(index_root->index.allocated_size)); - printf("\tUsed Size:\t\t %u\n", - (unsigned int)le32_to_cpu(index_root->index.index_length)); - - /* the flags are 8bit long, no need for byte-order handling */ - printf("\tIndex header flags:\t 0x%02x\n",index_root->index.flags); + ntfs_dump_index_header("\t", &index_root->index); entry = (INDEX_ENTRY *)((u8 *)index_root + le32_to_cpu(index_root->index.entries_offset) + 0x10); @@ -1582,15 +1588,10 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) } entry = (INDEX_ENTRY *)((u8 *)tmp_alloc + le32_to_cpu( tmp_alloc->index.entries_offset) + 0x18); - ntfs_log_verbose("\tDumping index block (VCN 0x%llx, " - "used %u/%u, flags 0x%02x):\n", - le64_to_cpu(tmp_alloc->index_block_vcn), - (unsigned int)le32_to_cpu(tmp_alloc-> - index.index_length), (unsigned int) - le32_to_cpu(tmp_alloc->index. - allocated_size), - tmp_alloc->index.flags); + ntfs_log_verbose("\tDumping index block (VCN %lld):\n", + le64_to_cpu(tmp_alloc->index_block_vcn)); if (opts.verbose) { + ntfs_dump_index_header("\t\t", &tmp_alloc->index); ntfs_dump_usa_lsn("\t\t", (MFT_RECORD *)tmp_alloc); printf("\n"); From b51d98dd90ae8c7c1aa4b8540b2891bdac282ba0 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:39:35 +0000 Subject: [PATCH 041/289] add ntfs_dump_index_block() and use it --- ntfsprogs/ntfsinfo.c | 65 ++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 4a7382e1..579275d2 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1518,7 +1518,7 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) entry = (INDEX_ENTRY *)((u8 *)index_root + le32_to_cpu(index_root->index.entries_offset) + 0x10); - ntfs_log_verbose("\tDumping index block:\n"); + ntfs_log_verbose("\tDumping index root:\n"); printf("\tIndex entries total:\t %d\n", ntfs_dump_index_entries(entry, type)); } @@ -1535,6 +1535,34 @@ static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) (long long int)sle64_to_cpu(mrec->lsn)); } + +static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, + u32 ib_size) +{ + INDEX_ENTRY *entry; + + if (ntfs_mst_post_read_fixup((NTFS_RECORD *)ib, ib_size)) { + ntfs_log_perror("Damaged INDX record"); + return -1; + } + ntfs_log_verbose("\tDumping index block:\n"); + if (opts.verbose) + ntfs_dump_usa_lsn("\t\t", (MFT_RECORD *)ib); + + ntfs_log_verbose("\t\tNode VCN:\t\t %lld\n", + le64_to_cpu(ib->index_block_vcn)); + + entry = (INDEX_ENTRY *)((u8 *)ib + + le32_to_cpu(ib->index.entries_offset) + 0x18); + + if (opts.verbose) { + ntfs_dump_index_header("\t\t", &ib->index); + printf("\n"); + } + + return ntfs_dump_index_entries(entry, type); +} + /** * ntfs_dump_attr_index_allocation() * @@ -1543,8 +1571,7 @@ static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) { INDEX_ALLOCATION *allocation, *tmp_alloc; - INDEX_ENTRY *entry; - INDEX_ROOT *index_root; + INDEX_ROOT *ir; INDEX_ATTR_TYPE type; int total_entries = 0; int total_indx_blocks = 0; @@ -1554,13 +1581,13 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) u32 name_len; s64 data_size; - index_root = ntfs_index_root_get(ni, attr); - if (!index_root) { + ir = ntfs_index_root_get(ni, attr); + if (!ir) { ntfs_log_perror("Failed to read $INDEX_ROOT attribute"); return; } - type = get_index_attr_type(ni, attr, index_root); + type = get_index_attr_type(ni, attr, ir); name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); name_len = attr->name_length; @@ -1581,26 +1608,18 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) bit = 0; while ((u8 *)tmp_alloc < (u8 *)allocation + data_size) { if (*byte & (1 << bit)) { - if (ntfs_mst_post_read_fixup((NTFS_RECORD *) tmp_alloc, - index_root->index_block_size)) { - ntfs_log_perror("Damaged INDX record"); + int entries; + + entries = ntfs_dump_index_block(tmp_alloc, type, + ir->index_block_size); + if (entries == -1) goto out_allocation; - } - entry = (INDEX_ENTRY *)((u8 *)tmp_alloc + le32_to_cpu( - tmp_alloc->index.entries_offset) + 0x18); - ntfs_log_verbose("\tDumping index block (VCN %lld):\n", - le64_to_cpu(tmp_alloc->index_block_vcn)); - if (opts.verbose) { - ntfs_dump_index_header("\t\t", &tmp_alloc->index); - ntfs_dump_usa_lsn("\t\t", - (MFT_RECORD *)tmp_alloc); - printf("\n"); - } - total_entries += ntfs_dump_index_entries(entry, type); + + total_entries += entries; total_indx_blocks++; } tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + - index_root->index_block_size); + ir->index_block_size); bit++; if (bit > 7) { bit = 0; @@ -1614,7 +1633,7 @@ out_allocation: out_bitmap: free(bitmap); out_index_root: - free(index_root); + free(ir); } /** From 10e6070b1826e4f263b2f48b15987c5c3b427cc5 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:40:35 +0000 Subject: [PATCH 042/289] fix output indenting --- ntfsprogs/ntfsinfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 579275d2..d9bb02d8 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1525,9 +1525,9 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) { - printf("%sUpd. Seq. Array Offset:\t %hu\n", indent, + printf("%sUpd. Seq. Array Off.:\t %hu\n", indent, le16_to_cpu(mrec->usa_ofs)); - printf("%sUpd. Seq. Array Count: \t %hu\n", indent, + printf("%sUpd. Seq. Array Count:\t %hu\n", indent, le16_to_cpu(mrec->usa_count)); printf("%sUpd. Seq. Number:\t %hu\n", indent, *(u16 *)((u8 *)mrec + le16_to_cpu(mrec->usa_ofs))); @@ -1839,7 +1839,7 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) printf("Dumping Inode #%llu\n",(long long)inode->mft_no); ntfs_dump_usa_lsn("", inode->mrec); - printf("MFT Record Seq. Number:\t %hu\n", + printf("MFT Record Seq. Numb.:\t %hu\n", (short unsigned int)le16_to_cpu(inode->mrec->sequence_number)); printf("Number of Hard Links:\t %hu\n", le16_to_cpu(inode->mrec->link_count)); From 89ded2378c05397095f7819bd786125df6426f41 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:41:13 +0000 Subject: [PATCH 043/289] make stdout line buffered --- ntfsprogs/ntfsinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index d9bb02d8..2e7985f0 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1987,6 +1987,8 @@ int main(int argc, char **argv) { ntfs_volume *vol; + setlinebuf(stdout); + ntfs_log_set_handler(ntfs_log_handler_outerr); if (!parse_options(argc, argv)) From 0573a8ff53f9f20af71998453a79ff99c87c6b0b Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:43:12 +0000 Subject: [PATCH 044/289] fix segfaults when SDS has absolute security descriptor --- ntfsprogs/ntfsinfo.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 2e7985f0..c31b19e1 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -847,8 +847,20 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); /* TODO: parse the flags */ - printf("%s\tControl:\t\t 0x%0x\n", indent, sec_desc->control); + printf("%s\tControl:\t\t 0x%04x\n", indent, sec_desc->control); + if (~sec_desc->control & SE_SELF_RELATIVE) { + + SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)sec_desc; + + printf("%s\tOwner SID pointer:\t %p\n", indent, sd->owner); + printf("%s\tGroup SID pointer:\t %p\n", indent, sd->group); + printf("%s\tSACL pointer:\t\t %p\n", indent, sd->sacl); + printf("%s\tDACL pointer:\t\t %p\n", indent, sd->dacl); + + return; + } + if (sec_desc->owner) { sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + le32_to_cpu(sec_desc->owner)), NULL, 0); From 0fce94937b477aad7dfa03ea4f80864a30d85a91 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:44:46 +0000 Subject: [PATCH 045/289] redirect stderr to /dev/null if --debug isn't used in debug mode --- ntfsprogs/ntfsinfo.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index c31b19e1..73d8e873 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -85,12 +85,12 @@ static struct options { const char *device; /* Device/File to work with */ const char *filename; /* Resolve this filename to mft number */ s64 inode; /* Info for this inode */ + int debug; /* Debug output */ int quiet; /* Less output */ int verbose; /* Extra output */ int force; /* Override common sense */ int notime; /* Don't report timestamps at all */ int mft; /* Dump information about the volume as well */ - u8 padding[4]; /* Unused: padding to 64 bit. */ } opts; /** @@ -135,7 +135,11 @@ static void usage(void) " -q, --quiet Less output\n" " -v, --verbose More output\n" " -V, --version Display version information\n" - " -h, --help Display this help\n\n", + " -h, --help Display this help\n" +#ifdef DEBUG + " -d, --debug Show debug information\n" +#endif + "\n", EXEC_NAME); printf("%s%s\n", ntfs_bugs, ntfs_home); } @@ -151,8 +155,11 @@ static void usage(void) */ static int parse_options(int argc, char *argv[]) { - static const char *sopt = "-:fhi:F:mqtTvV"; + static const char *sopt = "-:dfhi:F:mqtTvV"; static const struct option lopt[] = { +#ifdef DEBUG + { "debug", no_argument, NULL, 'd' }, +#endif { "force", no_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "inode", required_argument, NULL, 'i' }, @@ -177,8 +184,6 @@ static int parse_options(int argc, char *argv[]) opts.filename = NULL; while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - ntfs_log_trace("optind=%d; c='%c' optarg=\"%s\".\n", optind, c, - optarg); switch (c) { case 1: if (!opts.device) @@ -186,6 +191,9 @@ static int parse_options(int argc, char *argv[]) else err++; break; + case 'd': + opts.debug++; + break; case 'i': if ((opts.inode != -1) || (!utils_parse_size(optarg, &opts.inode, FALSE))) { @@ -293,6 +301,14 @@ static int parse_options(int argc, char *argv[]) } +#ifdef DEBUG + if (!opts.debug) + if (!freopen("/dev/null", "w", stderr)) { + ntfs_log_perror("Failed to freopen stderr to /dev/null"); + exit(1); + } +#endif + if (ver) version(); if (help || err) @@ -1983,8 +1999,6 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) /* close all data-structures we used */ ntfs_attr_put_search_ctx(ctx); ntfs_inode_close(inode); - - /* happily exit */ } /** @@ -2003,14 +2017,18 @@ int main(int argc, char **argv) ntfs_log_set_handler(ntfs_log_handler_outerr); - if (!parse_options(argc, argv)) - return 1; + if (!parse_options(argc, argv)) { + printf("Failed to parse command line options\n"); + exit(1); + } utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); - if (!vol) - return 1; + if (!vol) { + printf("Failed to open '%s': %s\n", opts.device, strerror(errno)); + exit(1); + } /* * if opts.mft is not 0, then we will print out information about From 3c06d7d9c535f986d6477959181c13e64c2504a8 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:45:57 +0000 Subject: [PATCH 046/289] ntfs_dump_attr_index_allocation(): don't return if an INDX is corrupt --- ntfsprogs/ntfsinfo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 73d8e873..996ee9bb 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1640,11 +1640,10 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) entries = ntfs_dump_index_block(tmp_alloc, type, ir->index_block_size); - if (entries == -1) - goto out_allocation; - - total_entries += entries; - total_indx_blocks++; + if (entries != -1) { + total_entries += entries; + total_indx_blocks++; + } } tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + ir->index_block_size); @@ -1654,9 +1653,10 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) byte++; } } + printf("\tIndex entries total:\t %d\n", total_entries); printf("\tINDX blocks total:\t %d\n", total_indx_blocks); -out_allocation: + free(allocation); out_bitmap: free(bitmap); From 952926725dedb78a6e41dcad64bb88b2a53c49d7 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:46:22 +0000 Subject: [PATCH 047/289] ntfs_dump_attr_index_allocation(): dump number of entries per block too --- ntfsprogs/ntfsinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 996ee9bb..35c5d020 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1643,6 +1643,7 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) if (entries != -1) { total_entries += entries; total_indx_blocks++; + printf("\tIndex entries:\t\t %d\n", entries); } } tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + From 2daa9f3c9428b98944d76ad4c2ec83a3922ea384 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:48:31 +0000 Subject: [PATCH 048/289] add ntfs_dump_bytes(); ntfs_dump_attr_list(): dump ATTR_LIST_ENTRY paddings --- ntfsprogs/ntfsinfo.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 35c5d020..8486cafb 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -603,6 +603,15 @@ static void ntfs_dump_attr_standard_information(ATTR_RECORD *attr) (unsigned int)value_length); } } + +static void ntfs_dump_bytes(u8 *buf, int start, int stop) +{ + int i; + + for (i = start; i < stop; i++) { + printf("%02x ", buf[i]); + } +} /** * ntfs_dump_attr_list() @@ -663,6 +672,10 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) ntfs_log_perror("ntfs_ucstombs failed"); } else printf("unnamed\n"); + printf("\t\tPadding:\t"); + ntfs_dump_bytes((u8 *)entry, entry->name_offset + + 2 * entry->name_length, entry->length); + printf("\n"); } free(value); printf("\tEnd of attribute list reached.\n"); From 074b02536632632c4ec279aed010b5617390351e Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:51:55 +0000 Subject: [PATCH 049/289] ntfs_dump_index_entries(): cleanup subnode VCN calculation --- ntfsprogs/ntfsinfo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 8486cafb..af1fdc8f 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1413,8 +1413,7 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) if (entry->flags & INDEX_ENTRY_NODE) ntfs_log_verbose("\t\tSubnode VCN:\t\t 0x%llx\n", - sle64_to_cpu(*(VCN*)((u8*)entry + - le16_to_cpu(entry->length) - sizeof(VCN)))); + ntfs_ie_get_vcn(entry); if (entry->flags & INDEX_ENTRY_END) break; From af055de0c4b3e2c3f26d51b06b0d236fa662fd81 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:56:25 +0000 Subject: [PATCH 050/289] fix missing bracket in the former patch --- ntfsprogs/ntfsinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index af1fdc8f..3117254b 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1413,7 +1413,7 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) if (entry->flags & INDEX_ENTRY_NODE) ntfs_log_verbose("\t\tSubnode VCN:\t\t 0x%llx\n", - ntfs_ie_get_vcn(entry); + ntfs_ie_get_vcn(entry)); if (entry->flags & INDEX_ENTRY_END) break; From 551812d8bcdbc1db40390dd3fb31bc0252d6151c Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:57:37 +0000 Subject: [PATCH 051/289] use MFT_RECORD *mrec during dumps --- ntfsprogs/ntfsinfo.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 3117254b..2cdc7f72 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1875,17 +1875,18 @@ static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) */ static void ntfs_dump_inode_general_info(ntfs_inode *inode) { - u16 inode_flags = inode->mrec->flags; + MFT_RECORD *mrec = inode->mrec; + u16 inode_flags = mrec->flags; printf("Dumping Inode #%llu\n",(long long)inode->mft_no); - ntfs_dump_usa_lsn("", inode->mrec); + ntfs_dump_usa_lsn("", mrec); printf("MFT Record Seq. Numb.:\t %hu\n", - (short unsigned int)le16_to_cpu(inode->mrec->sequence_number)); + (short unsigned int)le16_to_cpu(mrec->sequence_number)); printf("Number of Hard Links:\t %hu\n", - le16_to_cpu(inode->mrec->link_count)); + le16_to_cpu(mrec->link_count)); printf("Attribute Offset:\t %hu\n", - le16_to_cpu(inode->mrec->attrs_offset)); + le16_to_cpu(mrec->attrs_offset)); printf("MFT Record Flags:\t "); if (inode_flags) { @@ -1914,16 +1915,16 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) printf("\n"); printf("Bytes Used:\t\t %u bytes\n", - (unsigned int)le32_to_cpu(inode->mrec->bytes_in_use)); + (unsigned int)le32_to_cpu(mrec->bytes_in_use)); printf("Bytes Allocated:\t %u bytes\n", - (unsigned int)le32_to_cpu(inode->mrec->bytes_allocated)); + (unsigned int)le32_to_cpu(mrec->bytes_allocated)); - if (inode->mrec->base_mft_record) { + if (mrec->base_mft_record) { printf("Base MFT Record:\t %llu\n", - MREF_LE(inode->mrec->base_mft_record)); + MREF_LE(mrec->base_mft_record)); } printf("Next Attribute Instance: %hu\n", - le16_to_cpu(inode->mrec->next_attr_instance)); + le16_to_cpu(mrec->next_attr_instance)); } /** From babfacfbd240ec97a8b4fc08f63ce9917fe9a868 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:58:21 +0000 Subject: [PATCH 052/289] dump padding between the Update Sequence Array and the first attribute --- ntfsprogs/ntfsinfo.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 2cdc7f72..eceae655 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1925,6 +1925,12 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) } printf("Next Attribute Instance: %hu\n", le16_to_cpu(mrec->next_attr_instance)); + + printf("MFT Padding:\t"); + ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + + 2 * le16_to_cpu(mrec->usa_count), + le16_to_cpu(mrec->attrs_offset)); + printf("\n"); } /** From a89dce7b385ac96879d58b0cd4506cdcf1ecf514 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 18:59:56 +0000 Subject: [PATCH 053/289] convert all malloc() to ntfs_malloc() --- ntfsprogs/ntfsinfo.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index eceae655..ef69b0ce 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -78,6 +78,7 @@ #include "dir.h" #include "ntfstime.h" #include "version.h" +#include "support.h" static const char *EXEC_NAME = "ntfsinfo"; @@ -630,11 +631,10 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) ntfs_log_perror("ntfs_get_attribute_value_length failed"); return; } - value = malloc(l); - if (!value) { - ntfs_log_perror("malloc failed"); + value = ntfs_malloc(l); + if (!value) return; - } + l = ntfs_get_attribute_value(vol, attr, value); if (!l) { ntfs_log_perror("ntfs_get_attribute_value failed"); @@ -949,9 +949,8 @@ static void ntfs_dump_attr_security_descriptor(ATTR_RECORD *attr, ntfs_volume *v s64 data_size, bytes_read; data_size = sle64_to_cpu(attr->data_size); - sec_desc_attr = malloc(data_size); + sec_desc_attr = ntfs_malloc(data_size); if (!sec_desc_attr) { - ntfs_log_perror("malloc failed"); free(rl); return; } @@ -1737,9 +1736,8 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) if (rl) { s64 bytes_read; - buf = malloc(data_size); + buf = ntfs_malloc(data_size); if (!buf) { - ntfs_log_perror("malloc failed"); free(rl); return; } From 3664395e5fa6580aa4fddea74171374f7dcf3b5a Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 19:02:30 +0000 Subject: [PATCH 054/289] ntfs_dump_flags(): dump FILE_ATTR_DIRECTORY --- ntfsprogs/ntfsinfo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index ef69b0ce..f5089273 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -463,6 +463,10 @@ static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, u32 flags) printf(" SYSTEM"); flags &= ~FILE_ATTR_SYSTEM; } + if (flags & FILE_ATTR_DIRECTORY) { + printf(" DIRECTORY"); + flags &= ~FILE_ATTR_DIRECTORY; + } if (flags & FILE_ATTR_ARCHIVE) { printf(" ARCHIVE"); flags &= ~FILE_ATTR_ARCHIVE; From cccf6fd94d7e4e58dc715f09916d71b6344950a6 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 19:09:22 +0000 Subject: [PATCH 055/289] Dump all VCN's in the same numeral system --- ntfsprogs/ntfsinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index f5089273..d5be5043 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1415,7 +1415,7 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) le16_to_cpu(entry->flags)); if (entry->flags & INDEX_ENTRY_NODE) - ntfs_log_verbose("\t\tSubnode VCN:\t\t 0x%llx\n", + ntfs_log_verbose("\t\tSubnode VCN:\t\t %lld\n", ntfs_ie_get_vcn(entry)); if (entry->flags & INDEX_ENTRY_END) break; From 2bb9a9a9134682392057141c4a106db6de9137ff Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 13 Aug 2006 19:48:08 +0000 Subject: [PATCH 056/289] fixes & improvements to ntfsclone, ntfscmp, ntfsinfo during ntfs-3g development --- ChangeLog | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b20f151a..e2fab7b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,35 @@ xx/xx/2006 - x.xx.x - . - Add new API ntfs_attr_exist() that checks whether attribute with selected type and name already present in inode. (Szaka) - Extend ntfs_index_{add_filename,rm} to support almost all cases of - index operations. (Szaka, Yura) + index operations. (Szaka) + - Support index operations when index root is in the base mft record. + (Yura) + - calloc/malloc -> ntfs_{calloc,malloc} conversions. (Szaka) + - ntfsclone: don't create image files with executable bit set. (Szaka) + - ntfsclone: metadata cloning: write out extent records. (Szaka) + - ntfsclone: fix sometimes missing error messages and be more + detailed. (Szaka) + - ntfsclone: fix crash in wipe_index_allocation_timestamps(): don't + dump empty index allocation attribute. (Szaka) + - ntfscmp: fine grained AT_INDEX_ALLOCATION comparison. (Szaka) + - ntfsinfo: rename 'Flags:' fields to be unique. (Szaka) + - ntfsinfo: add ntfs_dump_index_header(); dump full index attribute + INDEX_HEADER. (Szaka) + - ntfsinfo: add ntfs_dump_index_block() and use it. (Szaka) + - ntfsinfo: fix output indenting. (Szaka) + - ntfsinfo: make stdout line buffered. (Szaka) + - ntfsinfo: fix segfaults when SDS has absolute security descriptor. + (Szaka) + - ntfsinfo: redirect stderr to /dev/null if --debug isn't used in + debug mode. (Szaka) + - ntfsinfo: fix segfaults on corrupt index blocks. (Szaka) + - ntfsinfo: dump number of entries per block in index allocation + attributes. (Szaka) + - ntfsinfo: dump ATTR_LIST_ENTRY padding in verbose mode. (Szaka) + - ntfsinfo: dump all VCN's in the same numeral system. (Szaka) + - ntfsinfo: dump the FILE_ATTR_DIRECTORY flag. (Szaka) + - ntfsinfo: dump padding between the Update Sequence Array and the + first attribute in verbose mode. (Szaka) 21/06/2006 - 1.13.1 - Various fixes. From 5a36ead2f41e07b01e33457fcbd2d40a42eecfc1 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 14 Aug 2006 03:52:09 +0000 Subject: [PATCH 057/289] fix endianness in ntfsinfo preparation fix to index code btw, Szaka, you really should consider installing some cross-compiler for BE systems and qemu to test your changes. --- ChangeLog | 1 + ntfsprogs/ntfsinfo.c | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index e2fab7b6..f7c1b8cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ xx/xx/2006 - x.xx.x - . - ntfsinfo: dump the FILE_ATTR_DIRECTORY flag. (Szaka) - ntfsinfo: dump padding between the Update Sequence Array and the first attribute in verbose mode. (Szaka) + - ntfsinfo: Fix endianness. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index d5be5043..ebb69cec 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -6,7 +6,7 @@ * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2004-2005 Yuval Fledel - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2006 Yura Pakhuchiy * Copyright (c) 2005 Cristian Klein * * This utility will dump a file's attributes. @@ -113,7 +113,7 @@ static void version(void) printf(" 2003-2006 Szabolcs Szakacsits\n"); printf(" 2003 Leonard NorrgÃ¥rd\n"); printf(" 2004-2005 Yuval Fledel\n"); - printf(" 2004-2005 Yura Pakhuchiy\n"); + printf(" 2004-2006 Yura Pakhuchiy\n"); printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -678,7 +678,8 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) printf("unnamed\n"); printf("\t\tPadding:\t"); ntfs_dump_bytes((u8 *)entry, entry->name_offset + - 2 * entry->name_length, entry->length); + sizeof(ntfschar) * entry->name_length, + le16_to_cpu(entry->length)); printf("\n"); } free(value); @@ -831,7 +832,10 @@ static void ntfs_dump_acl(const char *prefix, ACL *acl) printf("%sRevision\t %u\n", prefix, acl->revision); - /* don't recalc le16_to_cpu every iteration (minor speedup on big-endians */ + /* + * Do not recalculate le16_to_cpu every iteration (minor speedup on + * big-endian machines. + */ ace_count = le16_to_cpu(acl->ace_count); /* initialize 'ace' to the first ace (if any) */ @@ -859,7 +863,7 @@ static void ntfs_dump_acl(const char *prefix, ACL *acl) } printf("%sACE:\t\t type:%s flags:0x%x access:0x%x\n", prefix, - ace_type, (unsigned int)le16_to_cpu(ace->flags), + ace_type, (unsigned int)ace->flags, (unsigned int)le32_to_cpu(ace->mask)); /* get a SID string */ sid = ntfs_sid_to_mbs(&ace->sid, NULL, 0); @@ -867,7 +871,8 @@ static void ntfs_dump_acl(const char *prefix, ACL *acl) free(sid); /* proceed to next ACE */ - ace = (ACCESS_ALLOWED_ACE *)(((char *)ace) + le32_to_cpu(ace->size)); + ace = (ACCESS_ALLOWED_ACE *)(((char *)ace) + + le32_to_cpu(ace->size)); } } @@ -880,7 +885,8 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); /* TODO: parse the flags */ - printf("%s\tControl:\t\t 0x%04x\n", indent, sec_desc->control); + printf("%s\tControl:\t\t 0x%04x\n", indent, + le16_to_cpu(sec_desc->control)); if (~sec_desc->control & SE_SELF_RELATIVE) { @@ -1153,12 +1159,13 @@ static const char *get_attribute_type_name(u32 type) static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) { printf("Dumping attribute %s (%#02x)\n", - get_attribute_type_name(a->type), a->type); + get_attribute_type_name(a->type), le32_to_cpu(a->type)); ntfs_log_verbose("\tAttribute length:\t %u\n", le32_to_cpu(a->length)); printf("\tResident: \t\t %s\n", a->non_resident ? "No" : "Yes"); ntfs_log_verbose("\tName length:\t\t %u\n", a->name_length); - ntfs_log_verbose("\tName offset:\t\t %u\n", le16_to_cpu(a->name_offset)); + ntfs_log_verbose("\tName offset:\t\t %u\n", + le16_to_cpu(a->name_offset)); /* Dump the attribute (stream) name */ if (a->name_length) { @@ -1573,7 +1580,7 @@ static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) printf("%sUpd. Seq. Array Count:\t %hu\n", indent, le16_to_cpu(mrec->usa_count)); printf("%sUpd. Seq. Number:\t %hu\n", indent, - *(u16 *)((u8 *)mrec + le16_to_cpu(mrec->usa_ofs))); + le16_to_cpup((u16 *)((u8 *)mrec + le16_to_cpu(mrec->usa_ofs)))); printf("%sLogFile Seq. Number:\t 0x%llx\n", indent, (long long int)sle64_to_cpu(mrec->lsn)); } @@ -1654,7 +1661,8 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) int entries; entries = ntfs_dump_index_block(tmp_alloc, type, - ir->index_block_size); + le32_to_cpu( + ir->index_block_size)); if (entries != -1) { total_entries += entries; total_indx_blocks++; @@ -1662,7 +1670,8 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) } } tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + - ir->index_block_size); + le32_to_cpu( + ir->index_block_size)); bit++; if (bit > 7) { bit = 0; From d15ed62ae402330a44a79fe55c5ec3746fb149ea Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 14 Aug 2006 03:52:56 +0000 Subject: [PATCH 058/289] a bit of cleanups --- libntfs/attrib.c | 2 +- libntfs/dir.c | 3 ++- ntfsprogs/ntfscp.c | 39 ++++++++++----------------------------- 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 2f18a810..cf4f157e 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -4991,7 +4991,7 @@ put_err_out: * EOPNOTSUPP - The desired resize is not implemented yet. */ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) -{ +{ int ret; if (!na || newsize < 0 || diff --git a/libntfs/dir.c b/libntfs/dir.c index e7859c2a..d49a2772 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -549,7 +549,8 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, len = ntfs_mbstoucs(p, &unicode, MAX_PATH); if (len < 0) { - ntfs_log_debug("Couldn't convert name to Unicode: %s.\n", p); + ntfs_log_debug("Couldn't convert name to Unicode: " + "%s.\n", p); err = EILSEQ; goto close; } diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index f8e703e3..90c754a3 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -1,7 +1,7 @@ /** * ntfscp - Part of the Linux-NTFS project. * - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2006 Yura Pakhuchiy * Copyright (c) 2005 Anton Altaparmakov * * This utility will overwrite files on NTFS volume. @@ -81,7 +81,7 @@ static void version(void) { ntfs_log_info("\n%s v%s (libntfs %s) - Overwrite files on NTFS " "volume.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2004-2005 Yura Pakhuchiy\n"); + ntfs_log_info("Copyright (c) 2004-2006 Yura Pakhuchiy\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -355,37 +355,18 @@ int main(int argc, char *argv[]) ntfs_log_perror("ERROR: Couldn't open destination file"); goto close_src; } - if ((le16_to_cpu(out->mrec->flags) & MFT_RECORD_IS_DIRECTORY) && - !opts.inode){ - /* + if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { + /* * @out is directory and it was specified by pathname, add - * filename to path and reopen inode. + * filename to path and try once again. */ - char *filename, *new_dest_file; + char *filename; + ntfs_inode *out_tmp; - /* - * FIXME: There should exist more beautiful way to get filename. - * Not sure that it will work in windows, but I don't think that - * someone will use ntfscp under windows. - */ - filename = strrchr(opts.src_file, '/'); - if (filename) - filename++; - else - filename = opts.src_file; - /* Add 2 bytes for '/' and null-terminator. */ - new_dest_file = malloc(strlen(opts.dest_file) + - strlen(filename) + 2); - if (!new_dest_file) { - ntfs_log_perror("ERROR: malloc() failed"); - goto close_dst; - } - strcpy(new_dest_file, opts.dest_file); - strcat(new_dest_file, "/"); - strcat(new_dest_file, filename); + filename = basename(opts.src_file); + out_tmp = ntfs_pathname_to_inode(vol, out, filename); ntfs_inode_close(out); - out = ntfs_pathname_to_inode(vol, NULL, new_dest_file); - free(new_dest_file); + out = out_tmp; if (!out) { ntfs_log_perror("ERROR: Failed to open destination " "file"); From a36323bc62a44b849de48214effb8f5e9e5065b6 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 16 Aug 2006 08:14:22 +0000 Subject: [PATCH 059/289] Make ntfsinfo more resilient to corrupt metadata. Otherwise it can cause an infinite loop... --- ntfsprogs/ntfsinfo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index ebb69cec..8cbe12e9 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1443,6 +1443,10 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) ntfs_dump_index_data(entry, type); break; } + if (!entry->length) { + ntfs_log_verbose("\tWARNING: Corrupt index entry, skipping this index block.\n"); + break; + } entry = (INDEX_ENTRY *)((u8 *)entry + le16_to_cpu(entry->length)); numb_entries++; From 280c74470f1e7ec55060ca4910571bfe62c71d13 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 16 Aug 2006 09:24:19 +0000 Subject: [PATCH 060/289] Print both decimal and hexadecimal in ntfsinfo. (This follows several patches where we kept switching things from decimal to hex to decimal because different people apparently use different number systems in their heads. I am on the hex front myself so I added hex output which was taken out recently by Szaka so he probably is on the dec front... In any case having both should make us all happy...) --- ChangeLog | 4 + ntfsprogs/ntfsinfo.c | 505 ++++++++++++++++++++++++++++--------------- 2 files changed, 330 insertions(+), 179 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7c1b8cd..05e094ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,6 +39,10 @@ xx/xx/2006 - x.xx.x - . - ntfsinfo: dump padding between the Update Sequence Array and the first attribute in verbose mode. (Szaka) - ntfsinfo: Fix endianness. (Yura) + - ntfsinfo: Make more resilient to corrupt index entries in an index + node. (Anton) + - ntfsinfo: Print in both decimal and hexadecimal where it makes sense + and is useful. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 8cbe12e9..f95f919a 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -521,7 +521,8 @@ static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, u32 flags) } if (flags) printf(" UNKNOWN: 0x%08x", (unsigned int)le32_to_cpu(flags)); - printf("\n"); + /* Print all the flags in hex. */ + printf(" (0x%08x)\n", (unsigned)le32_to_cpu(flags)); } /** @@ -593,19 +594,27 @@ static void ntfs_dump_attr_standard_information(ATTR_RECORD *attr) le32_to_cpu(standard_attr->version_number)); printf("\tClass ID:\t\t %u \n", (unsigned int)le32_to_cpu(standard_attr->class_id)); - printf("\tUser ID:\t\t %u \n", + printf("\tUser ID:\t\t %u (0x%x)\n", + (unsigned int)le32_to_cpu(standard_attr->owner_id), (unsigned int)le32_to_cpu(standard_attr->owner_id)); - printf("\tSecurity ID:\t\t %u \n", + printf("\tSecurity ID:\t\t %u (0x%x)\n", + (unsigned int)le32_to_cpu(standard_attr->security_id), (unsigned int)le32_to_cpu(standard_attr->security_id)); - printf("\tQuota charged:\t\t %llu \n", (unsigned long long) + printf("\tQuota charged:\t\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(standard_attr->quota_charged), + (unsigned long long) le64_to_cpu(standard_attr->quota_charged)); - printf("\tUpdate Sequence Number:\t %llu \n", + printf("\tUpdate Sequence Number:\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(standard_attr->usn), (unsigned long long) le64_to_cpu(standard_attr->usn)); } else { - printf("\tSize of STANDARD_INFORMATION is %u. It should be " - "either 72 or 48, something is wrong...\n", - (unsigned int)value_length); + printf("\tSize of STANDARD_INFORMATION is %u (0x%x). It " + "should be either 72 or 48, something is " + "wrong...\n", (unsigned int)value_length, + (unsigned)value_length); } } @@ -652,15 +661,27 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) printf("\n"); printf("\t\tAttribute type:\t0x%x\n", (unsigned int)le32_to_cpu(entry->type)); - printf("\t\tRecord length:\t%u\n", - le16_to_cpu(entry->length)); - printf("\t\tName length:\t%u\n", entry->name_length); - printf("\t\tName offset:\t%u\n", entry->name_offset); - printf("\t\tStarting VCN:\t%lld\n", + printf("\t\tRecord length:\t%u (0x%x)\n", + (unsigned)le16_to_cpu(entry->length), + (unsigned)le16_to_cpu(entry->length)); + printf("\t\tName length:\t%u (0x%x)\n", + (unsigned)entry->name_length, + (unsigned)entry->name_length); + printf("\t\tName offset:\t%u (0x%x)\n", + (unsigned)entry->name_offset, + (unsigned)entry->name_offset); + printf("\t\tStarting VCN:\t%lld (0x%llx)\n", + (long long)sle64_to_cpu(entry->lowest_vcn), + (unsigned long long) sle64_to_cpu(entry->lowest_vcn)); - printf("\t\tMFT reference:\t%lld\n", + printf("\t\tMFT reference:\t%lld (0x%llx)\n", + (unsigned long long) + MREF_LE(entry->mft_reference), + (unsigned long long) MREF_LE(entry->mft_reference)); - printf("\t\tInstance:\t%u\n", le16_to_cpu(entry->instance)); + printf("\t\tInstance:\t%u (0x%x)\n", + (unsigned)le16_to_cpu(entry->instance), + (unsigned)le16_to_cpu(entry->instance)); printf("\t\tName:\t\t"); if (entry->name_length) { char *name = NULL; @@ -692,8 +713,9 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) static void ntfs_dump_filename(const char *indent, FILE_NAME_ATTR *file_name_attr) { - printf("%sParent directory:\t %lld\n", indent, - (long long)MREF_LE(file_name_attr->parent_directory)); + printf("%sParent directory:\t %lld (0x%llx)\n", indent, + (long long)MREF_LE(file_name_attr->parent_directory), + (long long)MREF_LE(file_name_attr->parent_directory)); /* time stuff */ if (!opts.notime) { char *ntfs_time_str; @@ -715,22 +737,32 @@ static void ntfs_dump_filename(const char *indent, printf("%sLast Accessed Time:\t %s", indent, ntfs_time_str); } /* other basic stuff about the file */ - printf("%sAllocated Size:\t\t %lld\n", indent, (long long) + printf("%sAllocated Size:\t\t %lld (0x%llx)\n", indent, (long long) + sle64_to_cpu(file_name_attr->allocated_size), + (unsigned long long) sle64_to_cpu(file_name_attr->allocated_size)); - printf("%sData Size:\t\t %lld\n", indent, - (long long)sle64_to_cpu(file_name_attr->data_size)); - printf("%sFilename Length:\t %d\n", indent, + printf("%sData Size:\t\t %lld (0x%llx)\n", indent, + (long long)sle64_to_cpu(file_name_attr->data_size), + (unsigned long long) + sle64_to_cpu(file_name_attr->data_size)); + printf("%sFilename Length:\t %d (0x%x)\n", indent, + (unsigned)file_name_attr->file_name_length, (unsigned)file_name_attr->file_name_length); ntfs_dump_flags(indent, AT_FILE_NAME, file_name_attr->file_attributes); if (file_name_attr->file_attributes & FILE_ATTR_REPARSE_POINT && - file_name_attr->reserved) + file_name_attr->reparse_point_tag) printf("%sReparse point tag:\t 0x%x\n", indent, (unsigned) le32_to_cpu(file_name_attr->reparse_point_tag)); else if (file_name_attr->reparse_point_tag) { - printf("%sEA Length:\t\t %d\n", indent, (unsigned) + printf("%sEA Length:\t\t %d (0x%x)\n", indent, (unsigned) + le16_to_cpu(file_name_attr->packed_ea_size), + (unsigned) le16_to_cpu(file_name_attr->packed_ea_size)); if (file_name_attr->reserved) - printf("%sReserved:\t\t %d\n", indent, (unsigned) + printf("%sReserved:\t\t %d (0x%x)\n", indent, + (unsigned) + le16_to_cpu(file_name_attr->reserved), + (unsigned) le16_to_cpu(file_name_attr->reserved)); } /* The filename. */ @@ -1056,9 +1088,10 @@ static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) if (vol_information->flags & VOLUME_MODIFIED_BY_CHKDSK) printf("MOD_BY_CHKDSK "); if (vol_information->flags & VOLUME_FLAGS_MASK) { - printf("\n"); + printf("(0x%04x)\n", + (unsigned)le16_to_cpu(vol_information->flags)); } else { - printf("none set\n"); + printf("none set (0x0000)\n"); } if (vol_information->flags & (0xFFFF - VOLUME_FLAGS_MASK)) printf("\t\t\t\t Unknown Flags: 0x%04x\n", @@ -1075,10 +1108,15 @@ static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) ntfs_log_verbose("\n"); ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", le32_to_cpu(sds->hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u\n", - le32_to_cpu(sds->security_id)); - ntfs_log_verbose("\t\tOffset:\t\t\t %llu\n", le64_to_cpu(sds->offset)); - ntfs_log_verbose("\t\tLength:\t\t\t %u\n", le32_to_cpu(sds->length)); + ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(sds->security_id), + (unsigned)le32_to_cpu(sds->security_id)); + ntfs_log_verbose("\t\tOffset:\t\t\t %llu (0x%llx)\n", + (unsigned long long)le64_to_cpu(sds->offset), + (unsigned long long)le64_to_cpu(sds->offset)); + ntfs_log_verbose("\t\tLength:\t\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(sds->length), + (unsigned)le32_to_cpu(sds->length)); sd = (SECURITY_DESCRIPTOR_RELATIVE *)((char *)sds + sizeof(SECURITY_DESCRIPTOR_HEADER)); @@ -1158,14 +1196,19 @@ static const char *get_attribute_type_name(u32 type) static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) { - printf("Dumping attribute %s (%#02x)\n", - get_attribute_type_name(a->type), le32_to_cpu(a->type)); + printf("Dumping attribute %s (0x%x)\n", + get_attribute_type_name(a->type), + (unsigned)le32_to_cpu(a->type)); - ntfs_log_verbose("\tAttribute length:\t %u\n", le32_to_cpu(a->length)); + ntfs_log_verbose("\tAttribute length:\t %u (0x%x)\n", + (unsigned)le32_to_cpu(a->length), + (unsigned)le32_to_cpu(a->length)); printf("\tResident: \t\t %s\n", a->non_resident ? "No" : "Yes"); - ntfs_log_verbose("\tName length:\t\t %u\n", a->name_length); - ntfs_log_verbose("\tName offset:\t\t %u\n", - le16_to_cpu(a->name_offset)); + ntfs_log_verbose("\tName length:\t\t %u (0x%x)\n", + (unsigned)a->name_length, (unsigned)a->name_length); + ntfs_log_verbose("\tName offset:\t\t %u (0x%x)\n", + (unsigned)le16_to_cpu(a->name_offset), + (unsigned)le16_to_cpu(a->name_offset)); /* Dump the attribute (stream) name */ if (a->name_length) { @@ -1180,47 +1223,69 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) } /* TODO: parse the flags */ - printf("\tAttribute flags:\t 0x%04hx\n",le16_to_cpu(a->flags)); - printf("\tAttribute instance:\t %u\n", le16_to_cpu(a->instance)); + printf("\tAttribute flags:\t 0x%04x\n", + (unsigned)le16_to_cpu(a->flags)); + printf("\tAttribute instance:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(a->instance), + (unsigned)le16_to_cpu(a->instance)); /* Resident attribute */ if (!a->non_resident) { - printf("\tData size:\t\t %u\n", - (unsigned int)le32_to_cpu(a->value_length)); - ntfs_log_verbose("\tData offset:\t\t %u\n", - (unsigned int)le16_to_cpu(a->value_offset)); + printf("\tData size:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(a->value_length), + (unsigned)le32_to_cpu(a->value_length)); + ntfs_log_verbose("\tData offset:\t\t %u (0x%x)\n", + (unsigned)le16_to_cpu(a->value_offset), + (unsigned)le16_to_cpu(a->value_offset)); /* TODO: parse the flags */ - printf("\tResident flags:\t\t 0x%02hhx\n", a->resident_flags); - ntfs_log_verbose("\tReservedR:\t\t %d\n", a->reservedR); + printf("\tResident flags:\t\t 0x%02x\n", + (unsigned)a->resident_flags); + ntfs_log_verbose("\tReservedR:\t\t %d (0x%x)\n", + (unsigned)a->reservedR, (unsigned)a->reservedR); return; } /* Non-resident attribute */ - ntfs_log_verbose("\tLowest VCN\t\t %lld\n", - (long long)sle64_to_cpu(a->lowest_vcn)); - ntfs_log_verbose("\tHighest VCN:\t\t %lld\n", - (long long)sle64_to_cpu(a->highest_vcn)); - ntfs_log_verbose("\tMapping pairs offset:\t %u\n", - le16_to_cpu(a->mapping_pairs_offset)); - printf("\tCompression unit:\t %u\n", a->compression_unit); + ntfs_log_verbose("\tLowest VCN\t\t %lld (0x%llx)\n", + (long long)sle64_to_cpu(a->lowest_vcn), + (unsigned long long)sle64_to_cpu(a->lowest_vcn)); + ntfs_log_verbose("\tHighest VCN:\t\t %lld (0x%llx)\n", + (long long)sle64_to_cpu(a->highest_vcn), + (unsigned long long)sle64_to_cpu(a->highest_vcn)); + ntfs_log_verbose("\tMapping pairs offset:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(a->mapping_pairs_offset), + (unsigned)le16_to_cpu(a->mapping_pairs_offset)); + printf("\tCompression unit:\t %u (0x%x)\n", + (unsigned)a->compression_unit, + (unsigned)a->compression_unit); /* TODO: dump the 5 reserved bytes here in verbose mode */ if (!a->lowest_vcn) { - printf("\tData size:\t\t %llu\n", - (long long)le64_to_cpu(a->data_size)); - printf("\tAllocated size:\t\t %llu\n", - (long long)le64_to_cpu(a->allocated_size)); - printf("\tInitialized size:\t %llu\n", - (long long)le64_to_cpu(a->initialized_size)); - if (a->compression_unit || (a->flags & ATTR_IS_COMPRESSED)) - printf("\tCompressed size:\t %llu\n", - (long long)le64_to_cpu(a->compressed_size)); + printf("\tData size:\t\t %llu (0x%llx)\n", + (long long)sle64_to_cpu(a->data_size), + (unsigned long long)sle64_to_cpu(a->data_size)); + printf("\tAllocated size:\t\t %llu (0x%llx)\n", + (long long)sle64_to_cpu(a->allocated_size), + (unsigned long long) + sle64_to_cpu(a->allocated_size)); + printf("\tInitialized size:\t %llu (0x%llx)\n", + (long long)sle64_to_cpu(a->initialized_size), + (unsigned long long) + sle64_to_cpu(a->initialized_size)); + if (a->compression_unit || a->flags & ATTR_IS_COMPRESSED || + a->flags & ATTR_IS_SPARSE) + printf("\tCompressed size:\t %llu (0x%llx)\n", + (signed long long) + sle64_to_cpu(a->compressed_size), + (signed long long) + sle64_to_cpu(a->compressed_size)); } if (opts.verbose) { runlist *rl = ntfs_mapping_pairs_decompress(vol, a, 0); if (rl) { runlist *rlc = rl; + // TODO: Switch this to properly aligned hex... printf("\tRunlist:\tVCN\t\tLCN\t\tLength\n"); while (rlc->length) { printf("\t\t\t%lld\t\t%lld\t\t%lld\n", @@ -1262,24 +1327,33 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) switch (type) { case INDEX_ATTR_SECURE_SII: - ntfs_log_verbose("\t\tKey security id:\t %u\n", - le32_to_cpu(entry->key.sii.security_id)); + ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", + (unsigned) + le32_to_cpu(entry->key.sii.security_id), + (unsigned) + le32_to_cpu(entry->key.sii.security_id)); break; case INDEX_ATTR_SECURE_SDH: ntfs_log_verbose("\t\tKey hash:\t\t 0x%08x\n", - le32_to_cpu(entry->key.sdh.hash)); - ntfs_log_verbose("\t\tKey security id:\t %u\n", - le32_to_cpu(entry->key.sdh.security_id)); + (unsigned)le32_to_cpu(entry->key.sdh.hash)); + ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", + (unsigned) + le32_to_cpu(entry->key.sdh.security_id), + (unsigned) + le32_to_cpu(entry->key.sdh.security_id)); break; case INDEX_ATTR_OBJID_O: ntfs_guid_to_mbs(&entry->key.object_id, printable_GUID); ntfs_log_verbose("\t\tKey GUID:\t\t %s\n", printable_GUID); break; case INDEX_ATTR_REPARSE_R: - ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08x\n", - le32_to_cpu(entry->key.reparse.reparse_tag)); - ntfs_log_verbose("\t\tKey file id:\t\t %llu\n", - le64_to_cpu(entry->key.reparse.file_id)); + ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08x\n", (unsigned) + le32_to_cpu(entry->key.reparse.reparse_tag)); + ntfs_log_verbose("\t\tKey file id:\t\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(entry->key.reparse.file_id), + (unsigned long long) + le64_to_cpu(entry->key.reparse.file_id)); break; case INDEX_ATTR_QUOTA_O: sid = ntfs_sid_to_mbs(&entry->key.sid, NULL, 0); @@ -1287,21 +1361,22 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) free(sid); break; case INDEX_ATTR_QUOTA_Q: - ntfs_log_verbose("\t\tKey owner id:\t\t %u\n", - le32_to_cpu(entry->key.owner_id)); + ntfs_log_verbose("\t\tKey owner id:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(entry->key.owner_id), + (unsigned)le32_to_cpu(entry->key.owner_id)); break; default: ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - le32_to_cpu(type)); + le32_to_cpu(type)); break; } } typedef union { - SII_INDEX_DATA sii; /* $SII index data in $Secure */ - SDH_INDEX_DATA sdh; /* $SDH index data in $Secure */ - QUOTA_O_INDEX_DATA quota_o; /* $O index data in $Quota */ - QUOTA_CONTROL_ENTRY quota_q; /* $Q index data in $Quota */ + SII_INDEX_DATA sii; /* $SII index data in $Secure */ + SDH_INDEX_DATA sdh; /* $SDH index data in $Secure */ + QUOTA_O_INDEX_DATA quota_o; /* $O index data in $Quota */ + QUOTA_CONTROL_ENTRY quota_q; /* $Q index data in $Quota */ } __attribute__((__packed__)) INDEX_ENTRY_DATA; static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) @@ -1313,23 +1388,33 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) switch (type) { case INDEX_ATTR_SECURE_SII: ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", - le32_to_cpu(data->sii.hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u\n", - le32_to_cpu(data->sii.security_id)); - ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu\n", - le64_to_cpu(data->sii.offset)); - ntfs_log_verbose("\t\tLength in $SDS:\t\t %u\n", - le32_to_cpu(data->sii.length)); + (unsigned)le32_to_cpu(data->sii.hash)); + ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->sii.security_id), + (unsigned)le32_to_cpu(data->sii.security_id)); + ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->sii.offset), + (unsigned long long) + le64_to_cpu(data->sii.offset)); + ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->sii.length), + (unsigned)le32_to_cpu(data->sii.length)); break; case INDEX_ATTR_SECURE_SDH: ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", - le32_to_cpu(data->sdh.hash)); - ntfs_log_verbose("\t\tSecurity id:\t\t %u\n", - le32_to_cpu(data->sdh.security_id)); - ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu\n", - le64_to_cpu(data->sdh.offset)); - ntfs_log_verbose("\t\tLength in $SDS:\t\t %u\n", - le32_to_cpu(data->sdh.length)); + (unsigned)le32_to_cpu(data->sdh.hash)); + ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->sdh.security_id), + (unsigned)le32_to_cpu(data->sdh.security_id)); + ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->sdh.offset), + (unsigned long long) + le64_to_cpu(data->sdh.offset)); + ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->sdh.length), + (unsigned)le32_to_cpu(data->sdh.length)); ntfs_log_verbose("\t\tUnknown (padding):\t 0x%08x\n", le32_to_cpu(data->sdh.reserved_II)); break; @@ -1362,27 +1447,41 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) /* TODO */ break; case INDEX_ATTR_QUOTA_O: - ntfs_log_verbose("\t\tOwner id:\t\t %u\n", - le32_to_cpu(data->quota_o.owner_id)); - ntfs_log_verbose("\t\tUnknown:\t\t %u\n", - le32_to_cpu(data->quota_o.unknown)); + ntfs_log_verbose("\t\tOwner id:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->quota_o.owner_id), + (unsigned)le32_to_cpu(data->quota_o.owner_id)); + ntfs_log_verbose("\t\tUnknown:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(data->quota_o.unknown), + (unsigned)le32_to_cpu(data->quota_o.unknown)); break; case INDEX_ATTR_QUOTA_Q: ntfs_log_verbose("\t\tVersion:\t\t %u\n", - le32_to_cpu(data->quota_q.version)); + (unsigned)le32_to_cpu(data->quota_q.version)); ntfs_log_verbose("\t\tQuota flags:\t\t 0x%08x\n", - le32_to_cpu(data->quota_q.flags)); - ntfs_log_verbose("\t\tBytes used:\t\t %llu\n", - le64_to_cpu(data->quota_q.bytes_used)); + (unsigned)le32_to_cpu(data->quota_q.flags)); + ntfs_log_verbose("\t\tBytes used:\t\t %llu (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->quota_q.bytes_used), + (unsigned long long) + le64_to_cpu(data->quota_q.bytes_used)); ntfs_log_verbose("\t\tLast changed:\t\t %s", - ntfsinfo_time_to_str( - data->quota_q.change_time)); - ntfs_log_verbose("\t\tThreshold:\t\t %lld\n", - le64_to_cpu(data->quota_q.threshold)); - ntfs_log_verbose("\t\tLimit:\t\t\t %lld\n", - le64_to_cpu(data->quota_q.limit)); - ntfs_log_verbose("\t\tExceeded time:\t\t %lld\n", - le64_to_cpu(data->quota_q.exceeded_time)); + ntfsinfo_time_to_str( + data->quota_q.change_time)); + ntfs_log_verbose("\t\tThreshold:\t\t %lld (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->quota_q.threshold), + (unsigned long long) + le64_to_cpu(data->quota_q.threshold)); + ntfs_log_verbose("\t\tLimit:\t\t\t %lld (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->quota_q.limit), + (unsigned long long) + le64_to_cpu(data->quota_q.limit)); + ntfs_log_verbose("\t\tExceeded time:\t\t %lld (0x%llx)\n", + (unsigned long long) + le64_to_cpu(data->quota_q.exceeded_time), + (unsigned long long) + le64_to_cpu(data->quota_q.exceeded_time)); if (entry->data_length > 48) { char *sid; sid = ntfs_sid_to_mbs(&data->quota_q.sid, NULL, 0); @@ -1392,7 +1491,7 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) break; default: ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - le32_to_cpu(type)); + (unsigned)le32_to_cpu(type)); break; } } @@ -1414,41 +1513,54 @@ static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) numb_entries++; continue; } - ntfs_log_verbose("\t\tEntry length:\t\t %u\n", - le16_to_cpu(entry->length)); - ntfs_log_verbose("\t\tKey length:\t\t %u\n", - le16_to_cpu(entry->key_length)); + ntfs_log_verbose("\t\tEntry length:\t\t %u (0x%x)\n", + (unsigned)le16_to_cpu(entry->length), + (unsigned)le16_to_cpu(entry->length)); + ntfs_log_verbose("\t\tKey length:\t\t %u (0x%x)\n", + (unsigned)le16_to_cpu(entry->key_length), + (unsigned)le16_to_cpu(entry->key_length)); ntfs_log_verbose("\t\tIndex entry flags:\t 0x%02x\n", - le16_to_cpu(entry->flags)); + (unsigned)le16_to_cpu(entry->flags)); if (entry->flags & INDEX_ENTRY_NODE) - ntfs_log_verbose("\t\tSubnode VCN:\t\t %lld\n", + ntfs_log_verbose("\t\tSubnode VCN:\t\t %lld (0x%llx)\n", + ntfs_ie_get_vcn(entry), ntfs_ie_get_vcn(entry)); if (entry->flags & INDEX_ENTRY_END) break; switch (type) { case INDEX_ATTR_DIRECTORY_I30: - ntfs_log_verbose("\t\tFILE record number:\t %llu\n", + ntfs_log_verbose("\t\tFILE record number:\t %llu " + "(0x%llx)\n", (unsigned long long) + MREF_LE(entry->indexed_file), + (unsigned long long) MREF_LE(entry->indexed_file)); ntfs_dump_filename("\t\t", &entry->key.file_name); break; default: - ntfs_log_verbose("\t\tData offset:\t\t %u\n", - le16_to_cpu(entry->data_offset)); - ntfs_log_verbose("\t\tData length:\t\t %u\n", - le16_to_cpu(entry->data_length)); + ntfs_log_verbose("\t\tData offset:\t\t %u (0x%x)\n", + (unsigned) + le16_to_cpu(entry->data_offset), + (unsigned) + le16_to_cpu(entry->data_offset)); + ntfs_log_verbose("\t\tData length:\t\t %u (0x%x)\n", + (unsigned) + le16_to_cpu(entry->data_length), + (unsigned) + le16_to_cpu(entry->data_length)); ntfs_dump_index_key(entry, type); ntfs_log_verbose("\t\tKey Data:\n"); ntfs_dump_index_data(entry, type); break; } if (!entry->length) { - ntfs_log_verbose("\tWARNING: Corrupt index entry, skipping this index block.\n"); + ntfs_log_verbose("\tWARNING: Corrupt index entry, " + "skipping the remainder of this index " + "block.\n"); break; } - entry = (INDEX_ENTRY *)((u8 *)entry + - le16_to_cpu(entry->length)); + entry = (INDEX_ENTRY*)((u8*)entry + le16_to_cpu(entry->length)); numb_entries++; ntfs_log_verbose("\n"); } @@ -1527,12 +1639,15 @@ static void ntfs_dump_index_attr_type(INDEX_ATTR_TYPE type) static void ntfs_dump_index_header(const char *indent, INDEX_HEADER *idx) { - printf("%sEntries Offset:\t\t %u\n", indent, - (unsigned int)le32_to_cpu(idx->entries_offset)); - printf("%sIndex Size:\t\t %u\n", indent, - (unsigned int)le32_to_cpu(idx->index_length)); - printf("%sAllocated Size:\t\t %u\n", indent, - (unsigned int)le32_to_cpu(idx->allocated_size)); + printf("%sEntries Offset:\t\t %u (0x%x)\n", indent, + (unsigned)le32_to_cpu(idx->entries_offset), + (unsigned)le32_to_cpu(idx->entries_offset)); + printf("%sIndex Size:\t\t %u (0x%x)\n", indent, + (unsigned)le32_to_cpu(idx->index_length), + (unsigned)le32_to_cpu(idx->index_length)); + printf("%sAllocated Size:\t\t %u (0x%x)\n", indent, + (unsigned)le32_to_cpu(idx->allocated_size), + (unsigned)le32_to_cpu(idx->allocated_size)); printf("%sIndex header flags:\t 0x%02x\n", indent, idx->flags); /* FIXME: there are 3 reserved bytes here */ @@ -1557,20 +1672,23 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) ntfs_dump_index_attr_type(type); /* collation rule dumping */ - printf("\tCollation Rule:\t\t %u\n", - (unsigned int)le32_to_cpu(index_root->collation_rule)); + printf("\tCollation Rule:\t\t %u (0x%x)\n", + (unsigned)le32_to_cpu(index_root->collation_rule), + (unsigned)le32_to_cpu(index_root->collation_rule)); /* COLLATION_BINARY, COLLATION_FILE_NAME, COLLATION_UNICODE_STRING, COLLATION_NTOFS_ULONG, COLLATION_NTOFS_SID, COLLATION_NTOFS_SECURITY_HASH, COLLATION_NTOFS_ULONGS */ - printf("\tIndex Block Size:\t %u\n", - (unsigned int)le32_to_cpu(index_root->index_block_size)); - printf("\tClusters Per Block:\t %u\n", - index_root->clusters_per_index_block); + printf("\tIndex Block Size:\t %u (0x%x)\n", + (unsigned)le32_to_cpu(index_root->index_block_size), + (unsigned)le32_to_cpu(index_root->index_block_size)); + printf("\tClusters Per Block:\t %u (0x%x)\n", + (unsigned)index_root->clusters_per_index_block, + (unsigned)index_root->clusters_per_index_block); ntfs_dump_index_header("\t", &index_root->index); - entry = (INDEX_ENTRY *)((u8 *)index_root + + entry = (INDEX_ENTRY*)((u8*)index_root + le32_to_cpu(index_root->index.entries_offset) + 0x10); ntfs_log_verbose("\tDumping index root:\n"); printf("\tIndex entries total:\t %d\n", @@ -1579,34 +1697,40 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) { - printf("%sUpd. Seq. Array Off.:\t %hu\n", indent, - le16_to_cpu(mrec->usa_ofs)); - printf("%sUpd. Seq. Array Count:\t %hu\n", indent, - le16_to_cpu(mrec->usa_count)); - printf("%sUpd. Seq. Number:\t %hu\n", indent, - le16_to_cpup((u16 *)((u8 *)mrec + le16_to_cpu(mrec->usa_ofs)))); + printf("%sUpd. Seq. Array Off.:\t %u (0x%x)\n", indent, + (unsigned)le16_to_cpu(mrec->usa_ofs), + (unsigned)le16_to_cpu(mrec->usa_ofs)); + printf("%sUpd. Seq. Array Count:\t %u (0x%x)\n", indent, + (unsigned)le16_to_cpu(mrec->usa_count), + (unsigned)le16_to_cpu(mrec->usa_count)); + printf("%sUpd. Seq. Number:\t %u (0x%x)\n", indent, + (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + + le16_to_cpu(mrec->usa_ofs))), + (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + + le16_to_cpu(mrec->usa_ofs)))); printf("%sLogFile Seq. Number:\t 0x%llx\n", indent, - (long long int)sle64_to_cpu(mrec->lsn)); + (unsigned long long)sle64_to_cpu(mrec->lsn)); } static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, - u32 ib_size) + u32 ib_size) { INDEX_ENTRY *entry; - if (ntfs_mst_post_read_fixup((NTFS_RECORD *)ib, ib_size)) { + if (ntfs_mst_post_read_fixup((NTFS_RECORD*)ib, ib_size)) { ntfs_log_perror("Damaged INDX record"); return -1; } ntfs_log_verbose("\tDumping index block:\n"); if (opts.verbose) - ntfs_dump_usa_lsn("\t\t", (MFT_RECORD *)ib); + ntfs_dump_usa_lsn("\t\t", (MFT_RECORD*)ib); - ntfs_log_verbose("\t\tNode VCN:\t\t %lld\n", - le64_to_cpu(ib->index_block_vcn)); + ntfs_log_verbose("\t\tNode VCN:\t\t %lld (0x%llx)\n", + (unsigned long long)sle64_to_cpu(ib->index_block_vcn), + (unsigned long long)sle64_to_cpu(ib->index_block_vcn)); - entry = (INDEX_ENTRY *)((u8 *)ib + + entry = (INDEX_ENTRY*)((u8*)ib + le32_to_cpu(ib->index.entries_offset) + 0x18); if (opts.verbose) { @@ -1724,10 +1848,14 @@ static void ntfs_dump_attr_ea_information(ATTR_RECORD *attr) ea_info = (EA_INFORMATION*)((u8*)attr + le16_to_cpu(attr->value_offset)); - printf("\tPacked EA length:\t %u\n", le16_to_cpu(ea_info->ea_length)); - printf("\tNEED_EA count:\t\t %u\n", - le16_to_cpu(ea_info->need_ea_count)); - printf("\tUnpacked EA length:\t %u\n", + printf("\tPacked EA length:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(ea_info->ea_length), + (unsigned)le16_to_cpu(ea_info->ea_length)); + printf("\tNEED_EA count:\t\t %u (0x%x)\n", + (unsigned)le16_to_cpu(ea_info->need_ea_count), + (unsigned)le16_to_cpu(ea_info->need_ea_count)); + printf("\tUnpacked EA length:\t %u (0x%x)\n", + (unsigned)le32_to_cpu(ea_info->ea_query_length), (unsigned)le32_to_cpu(ea_info->ea_query_length)); } @@ -1783,12 +1911,16 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) if (ea->flags == NEED_EA) printf("NEED_EA\n"); else - printf("Unknown (0x%02x)\n", ea->flags); + printf("Unknown (0x%02x)\n", + (unsigned)ea->flags); } else printf("NONE\n"); - printf("\tName length:\t %d\n", ea->name_length); - printf("\tValue length:\t %d\n", - le16_to_cpu(ea->value_length)); + printf("\tName length:\t %d (0x%x)\n", + (unsigned)ea->name_length, + (unsigned)ea->name_length); + printf("\tValue length:\t %d (0x%x)\n", + (unsigned)le16_to_cpu(ea->value_length), + (unsigned)le16_to_cpu(ea->value_length)); printf("\tName:\t\t '%s'\n", ea->name); printf("\tValue:\t\t "); if (ea->name_length == 11 && @@ -1880,8 +2012,8 @@ static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) /* hex dump */ printf("\tDumping some of the attribute data:\n"); ntfs_hex_dump((u8*)attr + le16_to_cpu(attr->value_offset), - (le16_to_cpu(attr->value_length)>128)?128 - :le16_to_cpu(attr->value_length)); + (le16_to_cpu(attr->value_length)>128)? + 128 : le16_to_cpu(attr->value_length)); } } @@ -1893,15 +2025,20 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) MFT_RECORD *mrec = inode->mrec; u16 inode_flags = mrec->flags; - printf("Dumping Inode #%llu\n",(long long)inode->mft_no); + printf("Dumping Inode %llu (0x%llx)\n", + (long long)inode->mft_no, + (unsigned long long)inode->mft_no); ntfs_dump_usa_lsn("", mrec); - printf("MFT Record Seq. Numb.:\t %hu\n", - (short unsigned int)le16_to_cpu(mrec->sequence_number)); - printf("Number of Hard Links:\t %hu\n", - le16_to_cpu(mrec->link_count)); - printf("Attribute Offset:\t %hu\n", - le16_to_cpu(mrec->attrs_offset)); + printf("MFT Record Seq. Numb.:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(mrec->sequence_number), + (unsigned)le16_to_cpu(mrec->sequence_number)); + printf("Number of Hard Links:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(mrec->link_count), + (unsigned)le16_to_cpu(mrec->link_count)); + printf("Attribute Offset:\t %u (0x%x)\n", + (unsigned)le16_to_cpu(mrec->attrs_offset), + (unsigned)le16_to_cpu(mrec->attrs_offset)); printf("MFT Record Flags:\t "); if (inode_flags) { @@ -1923,23 +2060,29 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) inode_flags &= ~MFT_RECORD_IS_VIEW_INDEX; } if (inode_flags) - printf("UNKNOWN: 0x%04hx", inode_flags); + printf("UNKNOWN: 0x%04x", (unsigned)inode_flags); } else { printf("none"); } printf("\n"); - printf("Bytes Used:\t\t %u bytes\n", - (unsigned int)le32_to_cpu(mrec->bytes_in_use)); - printf("Bytes Allocated:\t %u bytes\n", - (unsigned int)le32_to_cpu(mrec->bytes_allocated)); + printf("Bytes Used:\t\t %u (0x%x) bytes\n", + (unsigned)le32_to_cpu(mrec->bytes_in_use), + (unsigned)le32_to_cpu(mrec->bytes_in_use)); + printf("Bytes Allocated:\t %u (0x%x) bytes\n", + (unsigned)le32_to_cpu(mrec->bytes_allocated), + (unsigned)le32_to_cpu(mrec->bytes_allocated)); if (mrec->base_mft_record) { - printf("Base MFT Record:\t %llu\n", - MREF_LE(mrec->base_mft_record)); + printf("Base MFT Record:\t %llu (0x%llx)\n", + (unsigned long long) + MREF_LE(mrec->base_mft_record), + (unsigned long long) + MREF_LE(mrec->base_mft_record)); } - printf("Next Attribute Instance: %hu\n", - le16_to_cpu(mrec->next_attr_instance)); + printf("Next Attribute Instance: %u (0x%x)\n", + (unsigned)le16_to_cpu(mrec->next_attr_instance), + (unsigned)le16_to_cpu(mrec->next_attr_instance)); printf("MFT Padding:\t"); ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + @@ -1962,8 +2105,9 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) if (ctx->attr->type == AT_END || ctx->attr->type == AT_UNUSED) { printf("Weird: %s attribute type was found, please " - "report this.\n", - get_attribute_type_name(ctx->attr->type)); + "report this.\n", + get_attribute_type_name( + ctx->attr->type)); continue; } @@ -1983,7 +2127,8 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) ntfs_dump_attr_object_id(ctx->attr, inode->vol); break; case AT_SECURITY_DESCRIPTOR: - ntfs_dump_attr_security_descriptor(ctx->attr, inode->vol); + ntfs_dump_attr_security_descriptor(ctx->attr, + inode->vol); break; case AT_VOLUME_NAME: ntfs_dump_attr_volume_name(ctx->attr); @@ -2026,7 +2171,7 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) /* if we exited the loop before we're done - notify the user */ if (errno != ENOENT) { ntfs_log_perror("ntfsinfo error: stopped before finished " - "enumerating attributes"); + "enumerating attributes"); } else { printf("End of inode reached\n"); } @@ -2061,7 +2206,8 @@ int main(int argc, char **argv) vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); if (!vol) { - printf("Failed to open '%s': %s\n", opts.device, strerror(errno)); + printf("Failed to open '%s': %s\n", opts.device, + strerror(errno)); exit(1); } @@ -2076,7 +2222,8 @@ int main(int argc, char **argv) ntfs_inode *inode; /* obtain the inode */ if (opts.filename) { - inode = ntfs_pathname_to_inode(vol, NULL, opts.filename); + inode = ntfs_pathname_to_inode(vol, NULL, + opts.filename); } else { inode = ntfs_inode_open(vol, MK_MREF(opts.inode, 0)); } From 5128685d88bccf0537b48189158b0098eb8cd50b Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 23 Aug 2006 10:18:34 +0000 Subject: [PATCH 061/289] - ntfsclone: Define endianness safe image format. (Anton) - ntfsclone: Redefine image format version number to be the image format version and not the NTFS version of the imaged volume which is totally useless. (Anton) --- ChangeLog | 4 +++ ntfsprogs/ntfsclone.c | 75 ++++++++++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 05e094ec..7712afd4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,10 @@ xx/xx/2006 - x.xx.x - . node. (Anton) - ntfsinfo: Print in both decimal and hexadecimal where it makes sense and is useful. (Anton) + - ntfsclone: Define endianness safe image format. (Anton) + - ntfsclone: Redefine image format version number to be the image + format version and not the NTFS version of the imaged volume which is + totally useless. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index ec362fcf..9f7b34cb 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -2,7 +2,7 @@ * ntfsclone - Part of the Linux-NTFS project. * * Copyright (c) 2003-2006 Szabolcs Szakacsits - * Copyright (c) 2004-2005 Anton Altaparmakov + * Copyright (c) 2004-2006 Anton Altaparmakov * Special image format support copyright (c) 2004 Per Olofsson * * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. @@ -157,6 +157,20 @@ unsigned int wiped_timestamp_data = 0; #define IMAGE_MAGIC "\0ntfsclone-image" #define IMAGE_MAGIC_SIZE 16 +/* This is the first endianness safe format version. */ +#define NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE 10 +#define NTFSCLONE_IMG_VER_MINOR_ENDIANNESS_SAFE 0 + +/* + * Set the version to 10.0 to avoid colisions with old ntfsclone which + * stupidly used the volume version as the image version... )-: I hope NTFS + * never reaches version 10.0 and if it does one day I hope no-one is using + * such an old ntfsclone by then... + */ +#define NTFSCLONE_IMG_VER_MAJOR 10 +#define NTFSCLONE_IMG_VER_MINOR 0 + +/* All values are in little endian. */ struct { char magic[IMAGE_MAGIC_SIZE]; u8 major_ver; @@ -527,7 +541,7 @@ static void copy_cluster(int rescue, u64 rescue_lcn) { char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ /* vol is NULL if opt.restore_image is set */ - u32 csize = image_hdr.cluster_size; + u32 csize = le32_to_cpu(image_hdr.cluster_size); void *fd = (void *)&fd_in; off_t rescue_pos; @@ -679,7 +693,7 @@ static void write_empty_clusters(s32 csize, s64 count, static void restore_image(void) { s64 pos = 0, count; - s32 csize = image_hdr.cluster_size; + s32 csize = le32_to_cpu(image_hdr.cluster_size); char cmd; u64 p_counter = 0; struct progress_bar progress; @@ -687,9 +701,11 @@ static void restore_image(void) Printf("Restoring NTFS from image ...\n"); progress_init(&progress, p_counter, opt.std_out ? - image_hdr.nr_clusters : image_hdr.inuse, 100); + sle64_to_cpu(image_hdr.nr_clusters) : + sle64_to_cpu(image_hdr.inuse), + 100); - while (pos < image_hdr.nr_clusters) { + while (pos < sle64_to_cpu(image_hdr.nr_clusters)) { if (read_all(&fd_in, &cmd, sizeof(cmd)) == -1) perr_exit("read_all"); @@ -1297,15 +1313,17 @@ static void print_disk_usage(u32 cluster_size, s64 nr_clusters, s64 inuse) static void print_image_info(void) { Printf("NTFS volume version: %d.%d\n", - image_hdr.major_ver, image_hdr.minor_ver); + image_hdr.major_ver, image_hdr.minor_ver); Printf("Cluster size : %u bytes\n", - (unsigned int)image_hdr.cluster_size); + (unsigned)le32_to_cpu(image_hdr.cluster_size)); print_volume_size("Image volume size ", - image_hdr.nr_clusters * image_hdr.cluster_size); - Printf("Image device size : %lld bytes\n", image_hdr.device_size); - print_disk_usage(image_hdr.cluster_size, - image_hdr.nr_clusters, - image_hdr.inuse); + sle64_to_cpu(image_hdr.nr_clusters) * + le32_to_cpu(image_hdr.cluster_size)); + Printf("Image device size : %lld bytes\n", + sle64_to_cpu(image_hdr.device_size)); + print_disk_usage(le32_to_cpu(image_hdr.cluster_size), + sle64_to_cpu(image_hdr.nr_clusters), + sle64_to_cpu(image_hdr.inuse)); } static void check_if_mounted(const char *device, unsigned long new_mntflag) @@ -1495,14 +1513,24 @@ static s64 open_image(void) if ((fd_in = open(opt.volume, O_RDONLY)) == -1) perr_exit("failed to open image"); } - if (read_all(&fd_in, &image_hdr, sizeof(image_hdr)) == -1) perr_exit("read_all"); - if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0) err_exit("Input file is not an image! (invalid magic)\n"); - - return image_hdr.device_size; + if (image_hdr.major_ver < NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE) { + Printf("Old image format detected. Byteswapping on big " + "endian architectures. If the image was " + "created on a little endian architecture it " + "will not work. Use a more recent version " + "of ntfsclone to recreate the image.\n"); + image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR; + image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR; + image_hdr.cluster_size = cpu_to_le32(image_hdr.cluster_size); + image_hdr.device_size = cpu_to_sle64(image_hdr.device_size); + image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters); + image_hdr.inuse = cpu_to_sle64(image_hdr.inuse); + } + return sle64_to_cpu(image_hdr.device_size); } static s64 open_volume(void) @@ -1528,12 +1556,12 @@ static s64 open_volume(void) static void initialise_image_hdr(s64 device_size, s64 inuse) { memcpy(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); - image_hdr.major_ver = vol->major_ver; - image_hdr.minor_ver = vol->minor_ver; - image_hdr.cluster_size = vol->cluster_size; - image_hdr.device_size = device_size; - image_hdr.nr_clusters = vol->nr_clusters; - image_hdr.inuse = inuse; + image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR; + image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR; + image_hdr.cluster_size = cpu_to_le32(vol->cluster_size); + image_hdr.device_size = cpu_to_sle64(device_size); + image_hdr.nr_clusters = cpu_to_sle64(vol->nr_clusters); + image_hdr.inuse = cpu_to_sle64(inuse); } static void check_output_device(s64 input_size) @@ -1672,7 +1700,8 @@ int main(int argc, char **argv) if (opt.restore_image) { device_size = open_image(); - ntfs_size = image_hdr.nr_clusters * image_hdr.cluster_size; + ntfs_size = sle64_to_cpu(image_hdr.nr_clusters) * + le32_to_cpu(image_hdr.cluster_size); } else { device_size = open_volume(); ntfs_size = vol->nr_clusters * vol->cluster_size; From cb35fe2fea85882dfc57821a95ef6c161d15f28f Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 23 Aug 2006 11:22:07 +0000 Subject: [PATCH 062/289] Make ntfsclone image format extensible. (Anton) --- ChangeLog | 1 + ntfsprogs/ntfsclone.c | 70 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7712afd4..a8dcb007 100644 --- a/ChangeLog +++ b/ChangeLog @@ -47,6 +47,7 @@ xx/xx/2006 - x.xx.x - . - ntfsclone: Redefine image format version number to be the image format version and not the NTFS version of the imaged volume which is totally useless. (Anton) + - ntfsclone: Make ntfsclone image format extensible. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 9f7b34cb..7e304437 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -166,6 +166,10 @@ unsigned int wiped_timestamp_data = 0; * stupidly used the volume version as the image version... )-: I hope NTFS * never reaches version 10.0 and if it does one day I hope no-one is using * such an old ntfsclone by then... + * + * NOTE: Only bump the minor version if the image format and header are still + * backwards compatible. Otherwise always bump the major version. If in + * doubt, bump the major version. */ #define NTFSCLONE_IMG_VER_MAJOR 10 #define NTFSCLONE_IMG_VER_MINOR 0 @@ -179,8 +183,12 @@ struct { s64 device_size; s64 nr_clusters; s64 inuse; + u32 offset_to_image_data; /* From start of image_hdr. */ } __attribute__((__packed__)) image_hdr; +#define NTFSCLONE_IMG_HEADER_SIZE_OLD \ + (offsetof(typeof(image_hdr), offset_to_image_data)) + #define NTFS_MBYTE (1000 * 1000) #define ERR_PREFIX "ERROR" @@ -650,7 +658,8 @@ static void clone_ntfs(u64 nr_clusters) progress_init(&progress, p_counter, nr_clusters, 100); if (opt.save_image) { - if (write_all(&fd_out, &image_hdr, sizeof(image_hdr)) == -1) + if (write_all(&fd_out, &image_hdr, + image_hdr.offset_to_image_data) == -1) perr_exit("write_all"); } @@ -1296,14 +1305,15 @@ static void print_volume_size(const char *str, s64 bytes) } -static void print_disk_usage(u32 cluster_size, s64 nr_clusters, s64 inuse) +static void print_disk_usage(char *spacer, u32 cluster_size, s64 nr_clusters, + s64 inuse) { s64 total, used; total = nr_clusters * cluster_size; used = inuse * cluster_size; - Printf("Space in use : %lld MB (%.1f%%) ", + Printf("Space in use %s: %lld MB (%.1f%%) ", spacer, (long long)rounded_up_division(used, NTFS_MBYTE), 100.0 * ((float)used / total)); @@ -1312,18 +1322,21 @@ static void print_disk_usage(u32 cluster_size, s64 nr_clusters, s64 inuse) static void print_image_info(void) { - Printf("NTFS volume version: %d.%d\n", + Printf("Ntfsclone image version: %d.%d\n", image_hdr.major_ver, image_hdr.minor_ver); - Printf("Cluster size : %u bytes\n", + Printf("Cluster size : %u bytes\n", (unsigned)le32_to_cpu(image_hdr.cluster_size)); - print_volume_size("Image volume size ", + print_volume_size("Image volume size ", sle64_to_cpu(image_hdr.nr_clusters) * le32_to_cpu(image_hdr.cluster_size)); - Printf("Image device size : %lld bytes\n", + Printf("Image device size : %lld bytes\n", sle64_to_cpu(image_hdr.device_size)); - print_disk_usage(le32_to_cpu(image_hdr.cluster_size), + print_disk_usage(" ", le32_to_cpu(image_hdr.cluster_size), sle64_to_cpu(image_hdr.nr_clusters), sle64_to_cpu(image_hdr.inuse)); + Printf("Offset to image data : %u (0x%x) bytes\n", + (unsigned)le32_to_cpu(image_hdr.offset_to_image_data), + (unsigned)le32_to_cpu(image_hdr.offset_to_image_data)); } static void check_if_mounted(const char *device, unsigned long new_mntflag) @@ -1513,7 +1526,7 @@ static s64 open_image(void) if ((fd_in = open(opt.volume, O_RDONLY)) == -1) perr_exit("failed to open image"); } - if (read_all(&fd_in, &image_hdr, sizeof(image_hdr)) == -1) + if (read_all(&fd_in, &image_hdr, NTFSCLONE_IMG_HEADER_SIZE_OLD) == -1) perr_exit("read_all"); if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0) err_exit("Input file is not an image! (invalid magic)\n"); @@ -1529,6 +1542,41 @@ static s64 open_image(void) image_hdr.device_size = cpu_to_sle64(image_hdr.device_size); image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters); image_hdr.inuse = cpu_to_sle64(image_hdr.inuse); + image_hdr.offset_to_image_data = + const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); + } else { + typeof(image_hdr.offset_to_image_data) offset_to_image_data; + int delta; + + if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR) + err_exit("Do not know how to handle image format " + "version %d.%d. Please obtain a " + "newer version of ntfsclone.\n", + image_hdr.major_ver, + image_hdr.minor_ver); + /* Read the image header data offset. */ + if (read_all(&fd_in, &offset_to_image_data, + sizeof(offset_to_image_data)) == -1) + perr_exit("read_all"); + image_hdr.offset_to_image_data = + le32_to_cpu(offset_to_image_data); + /* + * Read any fields from the header that we have not read yet so + * that the input stream is positioned correctly. This means + * we can support future minor versions that just extend the + * header in a backwards compatible way. + */ + delta = offset_to_image_data - (NTFSCLONE_IMG_HEADER_SIZE_OLD + + sizeof(image_hdr.offset_to_image_data)); + if (delta > 0) { + char *dummy_buf; + + dummy_buf = malloc(delta); + if (!dummy_buf) + perr_exit("malloc dummy_buffer"); + if (read_all(&fd_in, dummy_buf, delta) == -1) + perr_exit("read_all"); + } } return sle64_to_cpu(image_hdr.device_size); } @@ -1562,6 +1610,8 @@ static void initialise_image_hdr(s64 device_size, s64 inuse) image_hdr.device_size = cpu_to_sle64(device_size); image_hdr.nr_clusters = cpu_to_sle64(vol->nr_clusters); image_hdr.inuse = cpu_to_sle64(inuse); + image_hdr.offset_to_image_data = cpu_to_le32((sizeof(image_hdr) + 7) & + ~7); } static void check_output_device(s64 input_size) @@ -1741,7 +1791,7 @@ int main(int argc, char **argv) walk_clusters(vol, &backup_clusters); compare_bitmaps(&lcn_bitmap); - print_disk_usage(vol->cluster_size, vol->nr_clusters, image.inuse); + print_disk_usage("", vol->cluster_size, vol->nr_clusters, image.inuse); check_dest_free_space(vol->cluster_size * image.inuse); From 35dcfaac9e106a10c7204ed64ba06a841dd27bc4 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 23 Aug 2006 11:58:55 +0000 Subject: [PATCH 063/289] Fix endianness problems in both image restore and image create (and in metadata cloning as well). (Anton) --- ChangeLog | 1 + ntfsprogs/ntfsclone.c | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index a8dcb007..ff16d516 100644 --- a/ChangeLog +++ b/ChangeLog @@ -48,6 +48,7 @@ xx/xx/2006 - x.xx.x - . format version and not the NTFS version of the imaged volume which is totally useless. (Anton) - ntfsclone: Make ntfsclone image format extensible. (Anton) + - ntfsclone: Fix endianness problems. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 7e304437..5ee7ec21 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -611,10 +611,12 @@ static void lseek_to_cluster(s64 lcn) static void image_skip_clusters(s64 count) { if (opt.save_image && count > 0) { + typeof(count) count_buf; char buff[1 + sizeof(count)]; buff[0] = 0; - memcpy(buff + 1, &count, sizeof(count)); + count_buf = cpu_to_sle64(count); + memcpy(buff + 1, &count_buf, sizeof(count_buf)); if (write_all(&fd_out, buff, sizeof(buff)) == -1) perr_exit("write_all"); @@ -721,12 +723,13 @@ static void restore_image(void) if (cmd == 0) { if (read_all(&fd_in, &count, sizeof(count)) == -1) perr_exit("read_all"); + count = sle64_to_cpu(count); if (opt.std_out) write_empty_clusters(csize, count, &progress, &p_counter); else { - if (lseek(fd_out, count * csize, SEEK_CUR) - == (off_t)-1) + if (lseek(fd_out, count * csize, SEEK_CUR) == + (off_t)-1) perr_exit("restore_image: lseek"); } pos += count; @@ -809,7 +812,8 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) while ((u8 *)tmp_indexa < (u8 *)indexa + na->data_size) { if (*byte & (1 << bit)) { if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa, - indexr->index_block_size)) { + le32_to_cpu( + indexr->index_block_size))) { perr_printf("Damaged INDX record"); goto out_indexa; } @@ -822,13 +826,14 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) perr_exit("ntfs_mft_usn_dec"); if (ntfs_mst_pre_write_fixup((NTFS_RECORD *)tmp_indexa, - indexr->index_block_size)) { + le32_to_cpu( + indexr->index_block_size))) { perr_printf("INDX write fixup failed"); goto out_indexa; } } tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa + - indexr->index_block_size); + le32_to_cpu(indexr->index_block_size)); bit++; if (bit > 7) { bit = 0; @@ -877,7 +882,7 @@ static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp) QUOTA_CONTROL_ENTRY *quota_q; quota_q = (QUOTA_CONTROL_ENTRY *)((u8 *)entry + - entry->data_offset); + le16_to_cpu(entry->data_offset)); /* * FIXME: no guarantee it's indeed /$Extend/$Quota:$Q. * For now, as a minimal safeguard, we check only for @@ -896,7 +901,7 @@ static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp) #define WIPE_TIMESTAMPS(atype, attr, timestamp) \ do { \ atype *ats; \ - ats = (atype *)((char *)(attr) + (attr)->value_offset); \ + ats = (atype *)((char *)(attr) + le16_to_cpu((attr)->value_offset)); \ \ ats->creation_time = (timestamp); \ ats->last_data_change_time = (timestamp); \ From 2afc70711a1a6ee0427f6f56e48108e300ac205c Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 23 Aug 2006 13:21:04 +0000 Subject: [PATCH 064/289] Forgot to not apply endianness swapping for old style images when restoring... --- ntfsprogs/ntfsclone.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 5ee7ec21..e2c3f680 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -154,6 +154,8 @@ unsigned int wiped_unused_mft = 0; unsigned int wiped_resident_data = 0; unsigned int wiped_timestamp_data = 0; +static BOOL image_is_host_endian = FALSE; + #define IMAGE_MAGIC "\0ntfsclone-image" #define IMAGE_MAGIC_SIZE 16 @@ -723,7 +725,8 @@ static void restore_image(void) if (cmd == 0) { if (read_all(&fd_in, &count, sizeof(count)) == -1) perr_exit("read_all"); - count = sle64_to_cpu(count); + if (!image_is_host_endian) + count = sle64_to_cpu(count); if (opt.std_out) write_empty_clusters(csize, count, &progress, &p_counter); @@ -1549,6 +1552,7 @@ static s64 open_image(void) image_hdr.inuse = cpu_to_sle64(image_hdr.inuse); image_hdr.offset_to_image_data = const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); + image_is_host_endian = TRUE; } else { typeof(image_hdr.offset_to_image_data) offset_to_image_data; int delta; From a117a21941469ebae5f4059fa2a7ba3d2711bda3 Mon Sep 17 00:00:00 2001 From: uvman Date: Mon, 25 Sep 2006 16:58:38 +0000 Subject: [PATCH 065/289] Comment documentation fixes. --- libntfs/dir.c | 8 +++----- libntfs/index.c | 14 ++++++++++---- libntfs/logging.c | 3 +-- libntfs/unistr.c | 2 +- ntfsprogs/mkntfs.c | 8 +++++--- ntfsprogs/ntfsdecrypt.c | 6 ++++-- ntfsprogs/ntfsmove.c | 6 ++++-- ntfsprogs/sd.c | 1 + 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index d49a2772..6bab6938 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -600,8 +600,7 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), const_cpu_to_le16('\0') }; /* - * union index_union - - * More helpers for ntfs_readdir(). + * union index_union - Helper for ntfs_readdir(). */ typedef union { INDEX_ROOT *ir; @@ -609,8 +608,7 @@ typedef union { } index_union __attribute__((__transparent_union__)); /** - * enum INDEX_TYPE - - * More helpers for ntfs_readdir(). + * enum INDEX_TYPE - Helper for ntfs_readdir(). */ typedef enum { INDEX_TYPE_ROOT, /* index root */ @@ -1446,7 +1444,7 @@ ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, /** * ntfs_delete - delete file or directory from ntfs volume - * @ni: ntfs inode for object to delte + * @ni: ntfs inode for object to delete * @dir_ni: ntfs inode for directory in which delete object * @name: unicode name of the object to delete * @name_len: length of the name in unicode characters diff --git a/libntfs/index.c b/libntfs/index.c index 126af72e..700bcf20 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -1261,6 +1261,8 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); /** + * ntfs_ib_insert - insert an index block to an index context. + * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return STATUS_ERROR. */ @@ -1490,8 +1492,10 @@ out: } /** - * Used if an empty index block to be deleted has END entry as the parent - * in the INDEX_ROOT which is the only one there. + * ntfs_ir_leafify - + * + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is the only one there. */ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) { @@ -1514,8 +1518,10 @@ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) } /** - * Used if an empty index block to be deleted has END entry as the parent - * in the INDEX_ROOT which is not the only one there. + * ntfs_ih_reparent_end - + * + * Used if an empty index block to be deleted has END entry as the parent + * in the INDEX_ROOT which is not the only one there. */ static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, INDEX_BLOCK *ib) diff --git a/libntfs/logging.c b/libntfs/logging.c index c79128a6..137aac9d 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -69,8 +69,7 @@ struct ntfs_logging { }; /** - * ntfs_log - * This struct controls all the logging within the library and tools. + * ntfs_log - This struct controls all the logging in the library and tools. */ static struct ntfs_logging ntfs_log = { #ifdef DEBUG diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 906a850d..db91b785 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -741,7 +741,7 @@ ntfschar *ntfs_str2ucs(const char *s, int *len) /** * ntfs_ucsfree - free memory allocated by ntfs_str2ucs() - * @ucs input string to be freed + * @ucs: input string to be freed * * Free memory at @ucs and which was allocated by ntfs_str2ucs. * diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 28d52d55..dcadf7b0 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -585,9 +585,10 @@ static long long mkntfs_write(struct ntfs_device *dev, } /** - * ntfs_rlwrite - Write to disk the clusters contained in the runlist @rl - * taking the data from @val. Take @val_len bytes from @val and pad the - * rest with zeroes. + * ntfs_rlwrite - Write data to disk on clusters found in a runlist. + * + * Write to disk the clusters contained in the runlist @rl taking the data + * from @val. Take @val_len bytes from @val and pad the rest with zeroes. * * If the @rl specifies a completely sparse file, @val is allowed to be NULL. * @@ -1478,6 +1479,7 @@ static int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, /** * insert_positioned_attr_in_mft_record + * * Create a non-resident attribute with a predefined on disk location * specified by the runlist @rl. The clusters specified by @rl are assumed to * be allocated already. diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 31ebf2da..4e21a525 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -1189,8 +1189,10 @@ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) } /** - * ntfs_cat_decrypt - * TODO: + * ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout. + * @inode: An encrypted file's inode structure, as obtained by + * ntfs_inode_open(). + * @fek: A file encryption key. As obtained by ntfs_inode_fek_get(). */ static int ntfs_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek) { diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index 050a8586..e590802d 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -746,7 +746,8 @@ static s64 move_datarun(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, } /** - * move_attribute + * move_attribute - + * * > 0 Bytes moved / size to be moved * = 0 Nothing to do * < 0 Error @@ -791,7 +792,8 @@ static s64 move_attribute(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, } /** - * move_file + * move_file - + * * > 0 Bytes moved / size to be moved * = 0 Nothing to do * < 0 Error diff --git a/ntfsprogs/sd.c b/ntfsprogs/sd.c index 0e4ce809..69437210 100644 --- a/ntfsprogs/sd.c +++ b/ntfsprogs/sd.c @@ -202,6 +202,7 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) /** * init_root_sd_31 (ERSO) + * * creates the security_descriptor for the root folder on ntfs 3.1. * It is very long; lots of ACE's at first, then large pieces of zeroes; * the owner user/group is near the end. On a partition created with From 8cfa94abc3c690402422b6cf1af434e47aa98fd2 Mon Sep 17 00:00:00 2001 From: uvman Date: Mon, 25 Sep 2006 17:03:48 +0000 Subject: [PATCH 066/289] Remove code that was already marked as broken and commented out. --- libntfs/runlist.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/libntfs/runlist.c b/libntfs/runlist.c index dd5fc043..a6203777 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -1581,7 +1581,6 @@ err_out: int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) { runlist *rl; - BOOL is_end = FALSE; if (!arl || !*arl) { errno = EINVAL; @@ -1620,25 +1619,10 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) */ if (rl->length) { ++rl; - if (!rl->length) - is_end = TRUE; rl->vcn = start_vcn; rl->length = 0; } rl->lcn = (LCN)LCN_ENOENT; - /** - * Reallocate memory if necessary. - * FIXME: Below code is broken, because runlist allocations must be - * a multiply of 4096. The code caused crashes and corruptions. - */ -/* - if (!is_end) { - size_t new_size = (rl - *arl + 1) * sizeof(runlist_element); - rl = realloc(*arl, new_size); - if (rl) - *arl = rl; - } -*/ return 0; } From b7b4c986334e98e26d20344df091bd77e20060aa Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 4 Oct 2006 00:47:04 +0000 Subject: [PATCH 067/289] Hil: Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). --- ntfsprogs/ntfscp.c | 154 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 138 insertions(+), 16 deletions(-) diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 90c754a3..c96024b2 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004-2006 Yura Pakhuchiy * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2006 Hil Liao * * This utility will overwrite files on NTFS volume. * @@ -43,6 +44,9 @@ #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_LIBGEN_H +#include +#endif #include "types.h" #include "attrib.h" @@ -270,6 +274,34 @@ static void signal_handler(int arg __attribute__((unused))) caught_terminate++; } +/** + * Create a regular file under the given directory inode + * + * It is a wrapper function to ntfs_create(...) + * + * Return: the created file inode + */ +static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni, + const char *filename) +{ + ntfschar *ufilename; + /* inode to the file that is being created */ + ntfs_inode *ni; + int ufilename_len; + + /* ntfs_mbstoucs(...) will allocate memory for ufilename if it's NULL */ + ufilename = NULL; + ufilename_len = ntfs_mbstoucs(filename, &ufilename, 0); + if (ufilename_len == -1) { + ntfs_log_perror("ERROR: Failed to convert '%s' to unicode", + filename); + return NULL; + } + ni = ntfs_create(dir_ni, ufilename, ufilename_len, S_IFREG); + free(ufilename); + return ni; +} + /** * main - Begin here * @@ -352,26 +384,116 @@ int main(int argc, char *argv[]) } else out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file); if (!out) { - ntfs_log_perror("ERROR: Couldn't open destination file"); - goto close_src; - } - if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { - /* - * @out is directory and it was specified by pathname, add - * filename to path and try once again. - */ + /* copy the file if the dest_file's parent dir can be opened */ + char *parent_dirname; char *filename; - ntfs_inode *out_tmp; + ntfs_inode *dir_ni; + ntfs_inode *ni; + int dest_path_len; + char *dirname_last_whack; - filename = basename(opts.src_file); - out_tmp = ntfs_pathname_to_inode(vol, out, filename); - ntfs_inode_close(out); - out = out_tmp; - if (!out) { - ntfs_log_perror("ERROR: Failed to open destination " - "file"); + filename = basename(opts.dest_file); + dest_path_len = strlen(opts.dest_file); + parent_dirname = strdup(opts.dest_file); + if (!parent_dirname) { + ntfs_log_perror("strdup() failed"); goto close_src; } + dirname_last_whack = strrchr(parent_dirname, '/'); + if (dirname_last_whack) { + dirname_last_whack[1] = '\0'; + dir_ni = ntfs_pathname_to_inode(vol, NULL, + parent_dirname); + } else { + ntfs_log_verbose("Target path does not contain '/'. " + "Using root directory as parent.\n"); + dir_ni = ntfs_inode_open(vol, FILE_root); + } + if (dir_ni) { + if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + /* Remove the last '/' for estetic reasons. */ + dirname_last_whack[0] = '\0'; + ntfs_log_error("The file '%s' already exists " + "and is not a directory. " + "Aborting.\n", parent_dirname); + free(parent_dirname); + ntfs_inode_close(dir_ni); + goto close_src; + } + ntfs_log_verbose("Creating a new file '%s' under '%s'" + "\n", filename, parent_dirname); + ni = ntfs_new_file(dir_ni, filename); + ntfs_inode_close(dir_ni); + if (!ni) { + ntfs_log_perror("Failed to create '%s' under " + "'%s'", filename, + parent_dirname); + free(parent_dirname); + goto close_src; + } + out = ni; + } else { + ntfs_log_perror("ERROR: Couldn't open '%s'", + parent_dirname); + free(parent_dirname); + goto close_src; + } + free(parent_dirname); + } + /* the destination file is a path */ + if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { + char *filename; + char *overwrite_filename; + int overwrite_filename_len; + /* inode to the file that is being created */ + ntfs_inode *ni; + /* inode to the directory to create the file */ + ntfs_inode *dir_ni; + int filename_len; + int dest_dirname_len; + + filename = basename(opts.src_file); + dir_ni = out; + filename_len = strlen(filename); + dest_dirname_len = strlen(opts.dest_file); + overwrite_filename_len = filename_len+dest_dirname_len+2; + overwrite_filename = malloc(overwrite_filename_len); + if (!overwrite_filename) { + ntfs_log_perror("ERROR: Failed to allocate %i bytes " + "memory for the overwrite filename", + overwrite_filename_len); + ntfs_inode_close(out); + goto close_src; + } + strcpy(overwrite_filename, opts.dest_file); + /* add '/' in the end of dest_dirname if there is not one there */ + if (opts.dest_file[dest_dirname_len-1] != '/') { + strcat(overwrite_filename, "/"); + } + strcat(overwrite_filename, filename); + ni = ntfs_pathname_to_inode(vol, NULL, overwrite_filename); + /* Does a file with the same name exist in the dest dir? */ + if (ni) { + ntfs_log_verbose("Destination path has a file with " + "the same name\nOverwriting the file " + "'%s'\n", overwrite_filename); + ntfs_inode_close(out); + out = ni; + } else { + ntfs_log_verbose("Creating a new file '%s' under '%s'\n", + filename, opts.dest_file); + ni = ntfs_new_file(dir_ni, filename); + ntfs_inode_close(dir_ni); + if (!ni) { + ntfs_log_perror("ERROR: Failed to create the " + "destination file under '%s'", + opts.dest_file); + free(overwrite_filename); + goto close_src; + } + out = ni; + } + free(overwrite_filename); } attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len); From 911c577e074b204dc8a9922d9c4668a63e46b1a7 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 4 Oct 2006 20:57:03 +0000 Subject: [PATCH 068/289] Hil: Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index ff16d516..41c50399 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,8 @@ xx/xx/2006 - x.xx.x - . totally useless. (Anton) - ntfsclone: Make ntfsclone image format extensible. (Anton) - ntfsclone: Fix endianness problems. (Anton) + - Allow ntfscp to create the destination file if it does not already + exists by calling ntfs_create(). (Hil) 21/06/2006 - 1.13.1 - Various fixes. From 0c86fccdc9950436c0b76a64051ea4942f4621c6 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 10 Oct 2006 10:29:11 +0000 Subject: [PATCH 069/289] Fix GUID to string conversion to follow documentation (details: it is not little endian at all, it is a binary sequence)... See remarks section at: http://windowssdk.msdn.microsoft.com/en-us/library/96ff78dc.aspx --- include/ntfs/layout.h | 24 ++++++++++++++++-------- libntfs/security.c | 17 ++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 9db8066c..330743dc 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -1142,16 +1142,24 @@ typedef struct { * implementation of the distributed computing environment (DCE) universally * unique identifier (UUID). * - * Example of a GUID: + * Example of a GUID in string format: * 1F010768-5A73-BC91-0010-A52216A7227B + * And the same in binary: + * 1F0107685A73BC910010A52216A7227B */ -typedef struct { - u32 data1; /* The first eight hexadecimal digits of the GUID. */ - u16 data2; /* The first group of four hexadecimal digits. */ - u16 data3; /* The second group of four hexadecimal digits. */ - u8 data4[8]; /* The first two bytes are the third group of four - hexadecimal digits. The remaining six bytes are the - final 12 hexadecimal digits. */ +typedef union { + struct { + u32 data1; /* The first eight hexadecimal digits of the + GUID. */ + u16 data2; /* The first group of four hexadecimal + digits. */ + u16 data3; /* The second group of four hexadecimal + digits. */ + u8 data4[8]; /* The first two bytes are the third group of + four hexadecimal digits. The remaining six + bytes are the final 12 hexadecimal digits. */ + }; + u8 raw[16]; /* Raw binary for ease of access. */ } __attribute__((__packed__)) GUID; /** diff --git a/libntfs/security.c b/libntfs/security.c index 62f9bedd..3af48726 100644 --- a/libntfs/security.c +++ b/libntfs/security.c @@ -43,8 +43,7 @@ /* * The zero GUID. */ -static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0), - const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } }; +static const GUID __zero_guid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; const GUID *const zero_guid = &__zero_guid; /** @@ -90,13 +89,13 @@ char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) if (!_guid_str) return _guid_str; } - res = snprintf(_guid_str, 37, - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - (unsigned int)le32_to_cpu(guid->data1), - le16_to_cpu(guid->data2), le16_to_cpu(guid->data3), - guid->data4[0], guid->data4[1], - guid->data4[2], guid->data4[3], guid->data4[4], - guid->data4[5], guid->data4[6], guid->data4[7]); + res = snprintf(_guid_str, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", guid->raw[0], + guid->raw[1], guid->raw[2], guid->raw[3], guid->raw[4], + guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8], + guid->raw[9], guid->raw[10], guid->raw[11], + guid->raw[12], guid->raw[13], guid->raw[14], + guid->raw[15], guid->raw[16]); if (res == 36) return _guid_str; if (!guid_str) From 9aa76186f3dcd300fa7275b18a27981d8b8b10b6 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 10 Oct 2006 10:29:53 +0000 Subject: [PATCH 070/289] Update ChangeLog... --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 41c50399..37c8b63b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -51,6 +51,7 @@ xx/xx/2006 - x.xx.x - . - ntfsclone: Fix endianness problems. (Anton) - Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). (Hil) + - Fix GUID to string conversion. (Anton) 21/06/2006 - 1.13.1 - Various fixes. From acb04c0435ea24ca1fc66381acfcb834ffbeb9d1 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 18 Oct 2006 14:41:41 +0000 Subject: [PATCH 071/289] Remove unneeded padding. The compiler will pad if it wan't to. --- ntfsprogs/ntfsclone.c | 1 - ntfsprogs/ntfscluster.h | 1 - ntfsprogs/ntfscmp.c | 1 - ntfsprogs/ntfsmove.h | 1 - ntfsprogs/ntfsresize.c | 2 -- ntfsprogs/ntfsundelete.h | 4 ---- 6 files changed, 10 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index e2c3f680..9bf498c9 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -116,7 +116,6 @@ struct { struct bitmap { s64 size; u8 *bm; - u8 padding[4]; /* Unused: padding to 64 bit. */ }; struct progress_bar { diff --git a/ntfsprogs/ntfscluster.h b/ntfsprogs/ntfscluster.h index fbc6c1d3..5a3d6b3c 100644 --- a/ntfsprogs/ntfscluster.h +++ b/ntfsprogs/ntfscluster.h @@ -56,7 +56,6 @@ struct match { ATTR_TYPES type; /* Attribute type */ ntfschar *name; /* Attribute name */ int name_len; /* Length of attribute name */ - u8 padding[4]; /* Unused: padding to 64 bit. */ }; #endif /* _NTFSCLUSTER_H_ */ diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index c6d738ae..ae9fc548 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -57,7 +57,6 @@ struct progress_bar { int resolution; int flags; float unit; - u8 padding[4]; /* Unused: padding to 64 bit. */ }; /* WARNING: don't modify the text, external tools grep for it */ diff --git a/ntfsprogs/ntfsmove.h b/ntfsprogs/ntfsmove.h index 1aeeef2a..ffc1519a 100644 --- a/ntfsprogs/ntfsmove.h +++ b/ntfsprogs/ntfsmove.h @@ -39,7 +39,6 @@ struct options { int verbose; /* Extra output */ int noaction; /* Do not write to disk */ int nodirty; /* Do not mark volume dirty */ - u8 padding[4]; /* Unused: alignment to 64 bit. */ }; #endif /* _NTFSMOVE_H_ */ diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 0a9b032c..838add66 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -140,7 +140,6 @@ struct { struct bitmap { s64 size; u8 *bm; - u8 padding[4]; /* Unused: padding to 64 bit. */ }; #define NTFS_PROGBAR 0x0001 @@ -152,7 +151,6 @@ struct progress_bar { int resolution; int flags; float unit; - u8 padding[4]; /* Unused: padding to 64 bit. */ }; struct llcn_t { diff --git a/ntfsprogs/ntfsundelete.h b/ntfsprogs/ntfsundelete.h index f4b0271a..177f5eec 100644 --- a/ntfsprogs/ntfsundelete.h +++ b/ntfsprogs/ntfsundelete.h @@ -57,7 +57,6 @@ struct options { s64 mft_begin; /* Range for mft copy */ s64 mft_end; char fillbyte; /* Use for unrecoverable sections */ - char padding[7]; /* Unused: padding to 64 bit. */ }; struct filename { @@ -75,7 +74,6 @@ struct filename { FILE_NAME_TYPE_FLAGS name_space; long long parent_mref; char *parent_name; - char padding[7]; /* Unused: padding to 64 bit. */ }; struct data { @@ -93,7 +91,6 @@ struct data { runlist_element *runlist; /* Decoded data runs */ int percent; /* Amount potentially recoverable */ void *data; /* If resident, a pointer to the data */ - char padding[4]; /* Unused: padding to 64 bit. */ }; struct ufile { @@ -107,7 +104,6 @@ struct ufile { int attr_list; /* MFT record may be one of many */ int directory; /* MFT record represents a directory */ MFT_RECORD *mft; /* Raw MFT record */ - char padding[4]; /* Unused: padding to 64 bit. */ }; #endif /* _NTFSUNDELETE_H_ */ From 6efbbabba68a7c8ff7e9ffd19b20492e436454a9 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 18 Oct 2006 14:43:04 +0000 Subject: [PATCH 072/289] Spelling fix. --- ntfsprogs/ntfsresize.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 838add66..9f6a0367 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -801,11 +801,9 @@ static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck) lcn_length); for (j = 0; j < lcn_length; j++) { - u64 k = (u64)lcn + j; if (k >= (u64)vol->nr_clusters) { - long long outsiders = lcn_length - j; fsck->outsider += outsiders; @@ -821,7 +819,7 @@ static void build_lcn_usage_bitmap(ntfs_volume *vol, ntfsck_t *fsck) if (ntfs_bit_get_and_set(lcn_bitmap->bm, k, 1)) { if (++fsck->multi_ref <= 10 || opt.verbose) printf("Cluster %lld is referenced " - "multiply times!\n", + "multiple times!\n", (long long)k); continue; } From cc12bccc05ce212222e2b23fe6ccb746273bb89d Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 18 Oct 2006 14:44:23 +0000 Subject: [PATCH 073/289] Allow reusing ntfs_device after close. --- libntfs/win32_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index c7a3e8e8..5cfcbec9 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -1113,11 +1113,13 @@ static int ntfs_device_win32_close(struct ntfs_device *dev) } rvl = CloseHandle(fd->handle); free(fd); + fd = NULL; if (!rvl) { errno = ntfs_w32error_to_errno(GetLastError()); ntfs_log_trace("CloseHandle() failed.\n"); return -1; } + NDevClearOpen(dev); return 0; } From 49559ce57c036d8440ee02376804442a9bf0462d Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 20 Oct 2006 19:53:50 +0000 Subject: [PATCH 074/289] fix a silly bug. --- libntfs/security.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/security.c b/libntfs/security.c index 3af48726..7496bc0e 100644 --- a/libntfs/security.c +++ b/libntfs/security.c @@ -43,7 +43,7 @@ /* * The zero GUID. */ -static const GUID __zero_guid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; +static const GUID __zero_guid = { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }; const GUID *const zero_guid = &__zero_guid; /** @@ -95,7 +95,7 @@ char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8], guid->raw[9], guid->raw[10], guid->raw[11], guid->raw[12], guid->raw[13], guid->raw[14], - guid->raw[15], guid->raw[16]); + guid->raw[15]); if (res == 36) return _guid_str; if (!guid_str) From 3d56b14bca3b1e62fd8ce4ac3676917766b86771 Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 20 Oct 2006 19:54:22 +0000 Subject: [PATCH 075/289] fix a packing bug --- include/ntfs/layout.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 330743dc..68ebca72 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -1158,7 +1158,7 @@ typedef union { u8 data4[8]; /* The first two bytes are the third group of four hexadecimal digits. The remaining six bytes are the final 12 hexadecimal digits. */ - }; + } __attribute__((__packed__)); u8 raw[16]; /* Raw binary for ease of access. */ } __attribute__((__packed__)) GUID; From ff289408c50983c097c29a5fa54a263118eb1110 Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 20 Oct 2006 19:55:50 +0000 Subject: [PATCH 076/289] fix for large sector sizes --- ntfsprogs/mkntfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index dcadf7b0..14b0f7cb 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -4245,6 +4245,8 @@ static int create_backup_boot_sector(u8 *buff) size = 512; if (size < opts.sector_size) size = opts.sector_size; + if (size < opts.cluster_size) + size = opts.cluster_size; if (g_vol->dev->d_ops->seek(g_vol->dev, (opts.num_sectors + 1) * opts.sector_size - size, SEEK_SET) == (off_t)-1) { ntfs_log_perror("Seek failed"); From 7b6f7e98d489d879d304c85e6bc9b5fadc1122c9 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 22 Oct 2006 00:23:29 +0000 Subject: [PATCH 077/289] Remove saving and restoring errno around logging calls as these will not change errno anyway. Remove save/restore only if the saved value will not be used. --- libntfs/attrib.c | 98 ++++++++++++------------------------------------ libntfs/dir.c | 4 +- libntfs/inode.c | 2 - 3 files changed, 24 insertions(+), 80 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index cf4f157e..89d1e4ba 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -588,13 +588,11 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) } } if (!a) { - err = errno; - if (err == ENOENT) + if (errno == ENOENT) ntfs_log_trace("Attribute not found. " "Inode is corrupt.\n"); else ntfs_log_trace("Inode is corrupt.\n"); - errno = err; goto err_out; } if (highest_vcn && highest_vcn != last_vcn - 1) { @@ -1050,9 +1048,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) buf = malloc(NTFS_BUF_SIZE); if (!buf) { - err = errno; ntfs_log_trace("Not enough memory.\n"); - errno = err; goto err_out; } memset(buf, 0, NTFS_BUF_SIZE); @@ -2594,12 +2590,10 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, } if (ntfs_attr_can_be_resident(ni->vol, type)) { - err = errno; if (errno == EPERM) ntfs_log_trace("Attribute can't be resident.\n"); else ntfs_log_trace("ntfs_attr_can_be_resident failed.\n"); - errno = err; return -1; } @@ -2722,13 +2716,11 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, } if (ntfs_attr_can_be_non_resident(ni->vol, type)) { - err = errno; if (errno == EPERM) ntfs_log_trace("Attribute can't be non resident.\n"); else ntfs_log_trace("ntfs_attr_can_be_non_resident() " "failed.\n"); - errno = err; return -1; } @@ -2884,10 +2876,8 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) */ if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) { if (ntfs_attrlist_entry_rm(ctx)) { - err = errno; ntfs_log_trace("Couldn't delete record from " "$ATTRIBUTE_LIST.\n"); - errno = err; return -1; } } @@ -3015,14 +3005,12 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, /* Check the attribute type and the size. */ if (ntfs_attr_size_bounds_check(ni->vol, type, size)) { - err = errno; - if (err == ERANGE) { + if (errno == ERANGE) { ntfs_log_trace("Size bounds check failed.\n"); - } else if (err == ENOENT) { + } else if (errno == ENOENT) { ntfs_log_trace("Invalid attribute type. Aborting...\n"); - err = EIO; + errno = EIO; } - errno = err; return -1; } @@ -3389,9 +3377,7 @@ int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) a = ctx->attr; nctx = ntfs_attr_get_search_ctx(ni, NULL); if (!nctx) { - err = errno; ntfs_log_trace("Couldn't obtain search context.\n"); - errno = err; return -1; } /* @@ -3459,7 +3445,7 @@ int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) { ntfs_inode *base_ni, *ni; MFT_RECORD *m; - int i, err; + int i; if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) { ntfs_log_trace("Invalid arguments passed.\n"); @@ -3484,9 +3470,7 @@ int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) } if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) { - err = errno; ntfs_log_trace("Couldn't attach extent inode.\n"); - errno = err; return -1; } @@ -3518,15 +3502,11 @@ int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) */ ni = ntfs_mft_record_alloc(base_ni->vol, base_ni); if (!ni) { - err = errno; ntfs_log_trace("Couldn't allocate new MFT record.\n"); - errno = err; return -1; } if (ntfs_attr_record_move_to(ctx, ni)) { - err = errno; ntfs_log_trace("Couldn't move attribute to new MFT record.\n"); - errno = err; return -1; } return 0; @@ -3558,7 +3538,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, ntfs_volume *vol = na->ni->vol; ATTR_REC *a = ctx->attr; runlist *rl; - int mp_size, mp_ofs, name_ofs, arec_size, err; + int mp_size, mp_ofs, name_ofs, arec_size; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long long)na->ni->mft_no, na->type); @@ -3596,11 +3576,8 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, vol->cluster_size_bits, -1, DATA_ZONE); if (!rl) { if (errno != ENOSPC) { - int eo = errno; - ntfs_log_trace("Eeek! Failed to allocate " "cluster(s). Aborting...\n"); - errno = eo; } return -1; } @@ -3627,19 +3604,17 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length), (u8*)a + le16_to_cpu(a->value_offset)); if (bw != le32_to_cpu(a->value_length)) { - err = errno; ntfs_log_debug("Failed to write out attribute value " "(bw = %lli, errno = %i). " - "Aborting...\n", (long long)bw, err); + "Aborting...\n", (long long)bw, errno); if (bw >= 0) - err = EIO; + errno = EIO; goto cluster_free_err_out; } } /* Determine the size of the mapping pairs array. */ mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); if (mp_size < 0) { - err = errno; ntfs_log_debug("Failed to get size for mapping pairs array. " "Aborting...\n"); goto cluster_free_err_out; @@ -3656,8 +3631,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, /* Resize the resident part of the attribute record. */ if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { - err = errno; - if (err != ENOSPC) { + if (errno != ENOSPC) { ntfs_log_trace("Failed to resize attribute record. " "Aborting...\n"); } @@ -3697,13 +3671,11 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, /* Generate the mapping pairs array in the attribute record. */ if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs, rl, 0, NULL) < 0) { - err = errno; // FIXME: Eeek! We need rollback! (AIA) ntfs_log_trace("Eeek! Failed to build mapping pairs. Leaving " "corrupt attribute record on disk. In memory " "runlist is still intact! Error code is %i. " - "FIXME: Need to rollback instead!\n", err); - errno = err; + "FIXME: Need to rollback instead!\n", errno); return -1; } @@ -3718,7 +3690,6 @@ cluster_free_err_out: na->allocated_size = na->data_size; na->rl = NULL; free(rl); - errno = err; return -1; } @@ -3984,7 +3955,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) { ntfs_volume *vol = na->ni->vol; ATTR_REC *a = ctx->attr; - int name_ofs, val_ofs, err = EIO; + int name_ofs, val_ofs; s64 arec_size, bytes_read; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long @@ -3994,7 +3965,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) if (sle64_to_cpu(a->lowest_vcn)) { ntfs_log_trace("Should be called for the first extent of the " "attribute. Aborting...\n"); - err = EINVAL; + errno = EINVAL; return -1; } @@ -4095,12 +4066,11 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size, (u8*)a + val_ofs); if (bytes_read != na->initialized_size) { - if (bytes_read < 0) - err = errno; + if (bytes_read >= 0) + errno = EIO; ntfs_log_trace("Eeek! Failed to read attribute data. Leaving " "inconstant metadata. Run chkdsk. " "Aborting...\n"); - errno = err; return -1; } @@ -4117,7 +4087,6 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) * record is in a transiently corrupted state at this moment in time. */ if (ntfs_cluster_free(vol, na, 0, -1) < 0) { - err = errno; ntfs_log_perror("Eeek! Failed to release allocated clusters"); ntfs_log_trace("Ignoring error and leaving behind wasted " "clusters.\n"); @@ -4198,9 +4167,7 @@ retry: ctx = ntfs_attr_get_search_ctx(base_ni, NULL); if (!ctx) { - err = errno; ntfs_log_trace("Couldn't get search context.\n"); - errno = err; return -1; } @@ -4434,10 +4401,8 @@ retry: if (!NInoAttrList(base_ni)) { ntfs_attr_put_search_ctx(ctx); if (ntfs_inode_add_attrlist(base_ni)) { - err = errno; ntfs_log_trace("Couldn't add attribute " "list.\n"); - errno = err; return -1; } goto retry; @@ -4634,13 +4599,11 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) * against @newsize and fail if @newsize is too small. */ if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { - err = errno; - if (err == ERANGE) { + if (errno == ERANGE) { ntfs_log_trace("Eeek! Size bounds check failed. " "Aborting...\n"); - } else if (err == ENOENT) - err = EIO; - errno = err; + } else if (errno == ENOENT) + errno = EIO; return -1; } @@ -4653,20 +4616,16 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) */ if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) { if (ntfs_attr_map_whole_runlist(na)) { - err = errno; ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " "failed.\n"); - errno = err; return -1; } /* Deallocate all clusters starting with the first free one. */ nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn, -1); if (nr_freed_clusters < 0) { - err = errno; ntfs_log_trace("Eeek! Freeing of clusters failed. " "Aborting...\n"); - errno = err; return -1; } @@ -4688,11 +4647,9 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) na->allocated_size = first_free_vcn << vol->cluster_size_bits; /* Write mapping pairs for new runlist. */ if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { - err = errno; ntfs_log_trace("Eeek! Mapping pairs update failed. " "Leaving inconstant metadata. " "Run chkdsk.\n"); - errno = err; return -1; } } @@ -4700,9 +4657,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) /* Get the first attribute record. */ ctx = ntfs_attr_get_search_ctx(na->ni, NULL); if (!ctx) { - err = errno; ntfs_log_trace("Couldn't get attribute search context.\n"); - errno = err; return -1; } if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, @@ -4785,13 +4740,11 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) * against @newsize and fail if @newsize is too big. */ if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { - err = errno; - if (err == ERANGE) { + if (errno == ERANGE) { ntfs_log_trace("Eeek! Size bounds check failed. " "Aborting...\n"); - } else if (err == ENOENT) - err = EIO; - errno = err; + } else if (errno == ENOENT) + errno = EIO; return -1; } @@ -4806,10 +4759,8 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) */ if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) { if (ntfs_attr_map_whole_runlist(na)) { - err = errno; ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " "failed.\n"); - errno = err; return -1; } @@ -4864,9 +4815,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) vol->cluster_size_bits), lcn_seek_from, DATA_ZONE); if (!rl) { - err = errno; ntfs_log_trace("Cluster allocation failed.\n"); - errno = err; return -1; } } @@ -4897,13 +4846,12 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) ctx = ntfs_attr_get_search_ctx(na->ni, NULL); if (!ctx) { - err = errno; ntfs_log_trace("Failed to get search context.\n"); if (na->allocated_size == org_alloc_size) { - errno = err; return -1; - } else - goto rollback; + } + err = errno; + goto rollback; } if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, diff --git a/libntfs/dir.c b/libntfs/dir.c index 6bab6938..fca14268 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1128,10 +1128,8 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, /* Allocate MFT record for new file. */ ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); if (!ni) { - err = errno; ntfs_log_error("Failed to allocate new MFT record: %s.\n", - strerror(err)); - errno = err; + strerror(errno)); return NULL; } /* diff --git a/libntfs/inode.c b/libntfs/inode.c index c199bf80..58356765 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -971,9 +971,7 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size) ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { - err = errno; ntfs_log_trace("Failed to get attribute search context.\n"); - errno = err; return -1; } From 480fdb14d567c328ab52d92f42ffb12220d567a7 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 22 Oct 2006 01:11:48 +0000 Subject: [PATCH 078/289] One more errno save/restore. --- libntfs/attrib.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 89d1e4ba..73769cc6 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -3834,11 +3834,9 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) ntfs_attr_put_search_ctx(ctx); if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD, non_resident_end) + 8)) { - err = errno; ntfs_log_trace("Couldn't free space in the MFT record " "to make attribute list non " "resident.\n"); - errno = err; return -1; } return ntfs_resident_attr_resize(na, newsize); From c55aea3ad4da031c3ae0ebb53ec8c2e3990c5e02 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 25 Oct 2006 16:49:00 +0000 Subject: [PATCH 079/289] Use le32 conversion macros for u32 variables of INDEX_HEADER. (zhanglinbao2000, Yuval) --- ChangeLog | 2 ++ libntfs/index.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 37c8b63b..c781019c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,6 +52,8 @@ xx/xx/2006 - x.xx.x - . - Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). (Hil) - Fix GUID to string conversion. (Anton) + - Fix some byte-order conversion for u32 variables that used le16 + conversion macros. (zhanglinbao, Yuval) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/index.c b/libntfs/index.c index 700bcf20..dde8763b 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -1145,7 +1145,7 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) if (!icx->ir) return STATUS_ERROR; - icx->ir->index.allocated_size = cpu_to_le16(data_size); + icx->ir->index.allocated_size = cpu_to_le32(data_size); ntfs_attr_put_search_ctx(ctx); } else { @@ -1246,7 +1246,7 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, ntfs_log_trace("Entering.\n"); - new_size = le16_to_cpu(icx->ir->index.index_length) + median->length; + new_size = le32_to_cpu(icx->ir->index.index_length) + median->length; if (!(median->flags & INDEX_ENTRY_NODE)) new_size += sizeof(VCN); @@ -1284,8 +1284,8 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) if (ntfs_ib_read(icx, old_vcn, ib)) goto err_out; - idx_size = le16_to_cpu(ib->index.index_length); - allocated_size = le16_to_cpu(ib->index.allocated_size); + idx_size = le32_to_cpu(ib->index.index_length); + allocated_size = le32_to_cpu(ib->index.allocated_size); /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ if (idx_size + ie->length + sizeof(VCN) > allocated_size) { err = ntfs_ib_split(icx, ib); @@ -1385,8 +1385,8 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) else ih = &icx->ib->index; - allocated_size = le16_to_cpu(ih->allocated_size); - new_size = le16_to_cpu(ih->index_length) + + allocated_size = le32_to_cpu(ih->allocated_size); + new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); if (new_size <= allocated_size) From fc7553ad2be6e86ec7707a318ceeef68e27cee82 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 25 Oct 2006 18:57:15 +0000 Subject: [PATCH 080/289] [Inconstant,Damaged] metadata -> Inconsistent metadata --- ChangeLog | 3 ++- libntfs/attrib.c | 29 +++++++++++++++-------------- libntfs/dir.c | 6 ++++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index c781019c..20562846 100644 --- a/ChangeLog +++ b/ChangeLog @@ -53,7 +53,8 @@ xx/xx/2006 - x.xx.x - . exists by calling ntfs_create(). (Hil) - Fix GUID to string conversion. (Anton) - Fix some byte-order conversion for u32 variables that used le16 - conversion macros. (zhanglinbao, Yuval) + conversion macros. (zhanglinbao, Yuval) + - Spelling mistake fixes in debug logging strings. (Yuval) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 73769cc6..ddb3d9b5 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1246,7 +1246,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) if (ntfs_cluster_free_from_rl(vol, rlc)) { ntfs_log_trace("Failed to free just " "allocated clusters. Leaving " - "inconstant metadata. " + "inconsistent metadata. " "Run chkdsk\n"); } errno = eo; @@ -2809,11 +2809,10 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, lowest_vcn, NULL, 0, ctx)) { err = errno; ntfs_log_trace("Attribute lookup failed. Probably leaving " - "inconstant metadata.\n"); + "inconsistent metadata.\n"); ntfs_attr_put_search_ctx(ctx); errno = err; return -1; - } offset = (u8*)ctx->attr - (u8*)ctx->mrec; ntfs_attr_put_search_ctx(ctx); @@ -2864,7 +2863,7 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) if (ntfs_attrlist_entry_add(ni, ctx->attr)) ntfs_log_trace("Rollback failed. Leaving " - "inconstant metadata.\n"); + "inconsistent metadata.\n"); err = EIO; return -1; } @@ -3149,7 +3148,8 @@ add_attr_record: ntfs_log_trace("Failed to initialize just added attribute.\n"); if (ntfs_attr_rm(na)) { ntfs_log_trace("Failed to remove just added attribute. " - "Probably leaving damaged metadata.\n"); + "Probably leaving inconsistent " + "metadata.\n"); ntfs_attr_close(na); } goto err_out; @@ -3170,7 +3170,7 @@ free_err_out: le32_to_cpu(attr_ni->mrec->attrs_offset) == 8) { if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) { ntfs_log_trace("Failed to free MFT record. Leaving " - "inconstant metadata.\n"); + "inconsistent metadata.\n"); } } err_out: @@ -3207,7 +3207,7 @@ int ntfs_attr_rm(ntfs_attr *na) return -1; if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { ntfs_log_trace("Failed to free cluster allocation. " - "Leaving inconstant metadata.\n"); + "Leaving inconsistent metadata.\n"); ret = -1; } } @@ -3220,14 +3220,14 @@ int ntfs_attr_rm(ntfs_attr *na) CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (ntfs_attr_record_rm(ctx)) { ntfs_log_trace("Failed to remove attribute extent. " - "Leaving inconstant metadata.\n"); + "Leaving inconsistent metadata.\n"); ret = -1; } ntfs_attr_reinit_search_ctx(ctx); } if (errno != ENOENT) { ntfs_log_trace("Attribute lookup failed. " - "Probably leaving inconstant metadata.\n"); + "Probably leaving inconsistent metadata.\n"); ret = -1; } @@ -4067,7 +4067,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) if (bytes_read >= 0) errno = EIO; ntfs_log_trace("Eeek! Failed to read attribute data. Leaving " - "inconstant metadata. Run chkdsk. " + "inconsistent metadata. Run chkdsk. " "Aborting...\n"); return -1; } @@ -4327,8 +4327,9 @@ retry: na->ni->vol, na->rl); if (new_compr_size == -1) { err = errno; - ntfs_log_trace("BUG! Leaving inconstant" - " metadata.\n"); + ntfs_log_trace("BUG! Leaving " + "inconsistent " + "metadata.\n"); goto put_err_out; } na->compressed_size = new_compr_size; @@ -4646,7 +4647,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) /* Write mapping pairs for new runlist. */ if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { ntfs_log_trace("Eeek! Mapping pairs update failed. " - "Leaving inconstant metadata. " + "Leaving inconsistent metadata. " "Run chkdsk.\n"); return -1; } @@ -4664,7 +4665,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) if (err == ENOENT) err = EIO; ntfs_log_trace("Eeek! Lookup of first attribute extent failed. " - "Leaving inconstant metadata.\n"); + "Leaving inconsistent metadata.\n"); goto put_err_out; } diff --git a/libntfs/dir.c b/libntfs/dir.c index fca14268..44ce5b90 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1622,13 +1622,15 @@ search: if (!rl) { err = errno; ntfs_log_error("Failed to decompress runlist. " - "Leaving damaged metadata.\n"); + "Leaving inconsistent " + "metadata.\n"); continue; } if (ntfs_cluster_free_from_rl(ni->vol, rl)) { err = errno; ntfs_log_error("Failed to free clusters. " - "Leaving damaged metadata.\n"); + "Leaving inconsistent " + "metadata.\n"); continue; } free(rl); From ca2fb9a46739dd51601e4f07bd9ac363bd07a11f Mon Sep 17 00:00:00 2001 From: uvman Date: Thu, 26 Oct 2006 19:10:05 +0000 Subject: [PATCH 081/289] Remove inline keywords from static non-one-liners of '.c' files. --- ChangeLog | 1 + include/ntfs/runlist.h | 5 ----- libntfs/attrib.c | 4 ++-- libntfs/bitmap.c | 2 +- libntfs/compress.c | 2 +- libntfs/device.c | 2 +- libntfs/dir.c | 2 +- libntfs/inode.c | 4 ++-- libntfs/runlist.c | 16 ++++++++-------- libntfs/win32_io.c | 10 +++++----- 10 files changed, 22 insertions(+), 26 deletions(-) diff --git a/ChangeLog b/ChangeLog index 20562846..f246d794 100644 --- a/ChangeLog +++ b/ChangeLog @@ -55,6 +55,7 @@ xx/xx/2006 - x.xx.x - . - Fix some byte-order conversion for u32 variables that used le16 conversion macros. (zhanglinbao, Yuval) - Spelling mistake fixes in debug logging strings. (Yuval) + - Remove inline keywords from static non-one-liners. (Szaka, Yuval) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/runlist.h b/include/ntfs/runlist.h index 726a28dc..0d066598 100644 --- a/include/ntfs/runlist.h +++ b/include/ntfs/runlist.h @@ -62,14 +62,9 @@ extern runlist_element *ntfs_runlists_merge(runlist_element *drl, extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, const ATTR_RECORD *attr, runlist_element *old_rl); -extern int ntfs_get_nr_significant_bytes(const s64 n); - extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, const runlist_element *rl, const VCN start_vcn); -extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, - const s64 n); - extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst, const int dst_len, const runlist_element *rl, const VCN start_vcn, VCN *const stop_vcn); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index ddb3d9b5..815dfc98 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -274,7 +274,7 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, * * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. */ -static __inline__ void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, +static void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, const u32 name_len) { na->rl = NULL; @@ -2264,7 +2264,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, * * Initialize the attribute search context @ctx with @ni and @mrec. */ -static __inline__ void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, +static void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, ntfs_inode *ni, MFT_RECORD *mrec) { if (!mrec) diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 40d8e85a..6b1fc15a 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -55,7 +55,7 @@ * * On success return 0 and on error return -1 with errno set to the error code. */ -static __inline__ int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, +static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, s64 count, int value) { s64 bufsize, br; diff --git a/libntfs/compress.c b/libntfs/compress.c index 737186e3..62d1f7f2 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -261,7 +261,7 @@ return_overflow: * code. Might be a bit confusing to debug but there really should never be * errors coming from here. */ -static __inline__ BOOL ntfs_is_cb_compressed(ntfs_attr *na, +static BOOL ntfs_is_cb_compressed(ntfs_attr *na, runlist_element *rl, VCN cb_start_vcn, int cb_clusters) { /* diff --git a/libntfs/device.c b/libntfs/device.c index 23d2c511..b4af89a4 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -469,7 +469,7 @@ s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, * * Return 0 if it is valid and -1 if it is not valid. */ -static inline int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs) +static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs) { char ch; diff --git a/libntfs/dir.c b/libntfs/dir.c index 44ce5b90..a76b61cd 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -629,7 +629,7 @@ typedef enum { * Pass information specifying the current directory entry @ie to the @filldir * callback. */ -static inline int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, +static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir) { diff --git a/libntfs/inode.c b/libntfs/inode.c index 58356765..2b1b9336 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -57,7 +57,7 @@ * * Returns: */ -static __inline__ ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) +static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) { ntfs_inode *ni; @@ -88,7 +88,7 @@ ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol) * * Returns: */ -static __inline__ int __ntfs_inode_release(ntfs_inode *ni) +static int __ntfs_inode_release(ntfs_inode *ni) { if (NInoDirty(ni)) ntfs_log_debug("Eeek. Discarding dirty inode!\n"); diff --git a/libntfs/runlist.c b/libntfs/runlist.c index a6203777..adcae4d3 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -100,7 +100,7 @@ static __inline__ void ntfs_rl_mc(runlist_element *dstbase, int dst, * On success, return a pointer to the newly allocated, or recycled, memory. * On error, return NULL with errno set to the error code. */ -static __inline__ runlist_element *ntfs_rl_realloc(runlist_element *rl, +static runlist_element *ntfs_rl_realloc(runlist_element *rl, int old_size, int new_size) { old_size = (old_size * sizeof(runlist_element) + 0xfff) & ~0xfff; @@ -121,7 +121,7 @@ static __inline__ runlist_element *ntfs_rl_realloc(runlist_element *rl, * Return: TRUE Success, the runlists can be merged. * FALSE Failure, the runlists cannot be merged. */ -static __inline__ BOOL ntfs_rl_are_mergeable(runlist_element *dst, +static BOOL ntfs_rl_are_mergeable(runlist_element *dst, runlist_element *src) { if (!dst || !src) { @@ -182,7 +182,7 @@ static __inline__ void __ntfs_rl_merge(runlist_element *dst, * On error, return NULL, with errno set to the error code. Both runlists are * left unmodified. */ -static __inline__ runlist_element *ntfs_rl_append(runlist_element *dst, +static runlist_element *ntfs_rl_append(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { BOOL right = FALSE; /* Right end of @src needs merging */ @@ -249,7 +249,7 @@ static __inline__ runlist_element *ntfs_rl_append(runlist_element *dst, * On error, return NULL, with errno set to the error code. Both runlists are * left unmodified. */ -static __inline__ runlist_element *ntfs_rl_insert(runlist_element *dst, +static runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { BOOL left = FALSE; /* Left end of @src needs merging */ @@ -345,7 +345,7 @@ static __inline__ runlist_element *ntfs_rl_insert(runlist_element *dst, * On error, return NULL, with errno set to the error code. Both runlists are * left unmodified. */ -static __inline__ runlist_element *ntfs_rl_replace(runlist_element *dst, +static runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { signed delta; @@ -432,7 +432,7 @@ static __inline__ runlist_element *ntfs_rl_replace(runlist_element *dst, * On error, return NULL, with errno set to the error code. Both runlists are * left unmodified. */ -static __inline__ runlist_element *ntfs_rl_split(runlist_element *dst, +static runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { if (!dst || !src) { @@ -1220,7 +1220,7 @@ rl_err_out: * * Return the number of bytes written. This function cannot fail. */ -__inline__ int ntfs_get_nr_significant_bytes(const s64 n) +static int ntfs_get_nr_significant_bytes(const s64 n) { s64 l = n; int i; @@ -1363,7 +1363,7 @@ err_out: * Return the number of bytes written on success. On error, i.e. the * destination buffer @dst is too small, return -1 with errno set ENOSPC. */ -__inline__ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, +static int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n) { s64 l = n; diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index 5cfcbec9..752df435 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -222,7 +222,7 @@ static void ntfs_device_win32_init_imports(void) * * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. */ -static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags) +static int ntfs_device_unix_status_flags_to_win32(int flags) { int win_mode; @@ -508,7 +508,7 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd) * Return 0 if o.k. * -1 if not, and errno set. */ -static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, +static int ntfs_device_win32_open_file(char *filename, win32_fd *fd, int flags) { HANDLE handle; @@ -538,7 +538,7 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, * return 0 if o.k. * -1 if not, and errno set. */ -static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, +static int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, int flags) { HANDLE handle; @@ -1360,7 +1360,7 @@ static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) * Return 0 if o.k. * -1 if not, and errno set. Note if error fd->handle is trashed. */ -static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, +static int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, struct hd_geometry *argp) { win32_fd *fd = (win32_fd *)dev->d_private; @@ -1382,7 +1382,7 @@ static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, * Return 0 if o.k. * -1 if not, and errno set. Note if error fd->handle is trashed. */ -static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) +static int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) { win32_fd *fd = (win32_fd *)dev->d_private; DWORD bytesReturned; From bd1837335b6b33e0b8db5ee8a9cca83790b501e9 Mon Sep 17 00:00:00 2001 From: uvman Date: Thu, 26 Oct 2006 20:45:28 +0000 Subject: [PATCH 082/289] trace output updates. (Szaka, Yuval) --- libntfs/attrib.c | 21 ++++++++++++++------- libntfs/dir.c | 11 +++++++++++ ntfsprogs/utils.c | 4 ++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 815dfc98..eb57bfee 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1625,7 +1625,7 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, ntfschar *upcase; u32 upcase_len; - ntfs_log_trace("Entering.\n"); + ntfs_log_trace("Entering for attribute type 0x%x.\n", type); if (ctx->ntfs_ino) { vol = ctx->ntfs_ino->vol; @@ -2461,6 +2461,7 @@ int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type) return -1; /* Check the flags and return the result. */ if (ad->flags & ATTR_DEF_RESIDENT) { + ntfs_log_trace("Attribute can't be non-resident\n"); errno = EPERM; return -1; } @@ -2497,6 +2498,8 @@ int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type) } if (type != AT_INDEX_ALLOCATION) return 0; + + ntfs_log_trace("Attribute can't be resident\n"); errno = EPERM; return -1; } @@ -2543,6 +2546,7 @@ int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size) biu = le32_to_cpu(m->bytes_in_use); /* Do we have enough space? */ if (biu + size > le32_to_cpu(m->bytes_allocated)) { + ntfs_log_trace("Not enough space in the MFT record\n"); errno = ENOSPC; return -1; } @@ -2929,7 +2933,7 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) ctx->attr, NULL); if (!al_rl) { ntfs_log_trace("Couldn't decompress attribute " - "list runlist. Return success " + "list runlist. Succeed " "anyway.\n"); return 0; } @@ -2948,7 +2952,7 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) * but without extents. */ ntfs_log_trace("Couldn't remove attribute list. " - "Return success anyway.\n"); + "Succeed anyway.\n"); return 0; } } @@ -3717,8 +3721,9 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) ntfs_inode *ni; int err; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long - long)na->ni->mft_no, na->type); + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, new size %lld.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize); /* Get the attribute record that needs modification. */ ctx = ntfs_attr_get_search_ctx(na->ni, NULL); @@ -4012,6 +4017,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) /* Sanity check the size before we start modifying the attribute. */ if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) + arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) { + ntfs_log_trace("Not enough space to make attribute resident\n"); errno = ENOSPC; return -1; } @@ -4588,8 +4594,9 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) s64 nr_freed_clusters; int err; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long - long)na->ni->mft_no, na->type); + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, newsize %lld.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize); vol = na->ni->vol; diff --git a/libntfs/dir.c b/libntfs/dir.c index a76b61cd..b1c3110e 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -515,6 +515,8 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, return NULL; } + ntfs_log_trace("Path: '%s'\n", pathname); + if (parent) { ni = parent; } else { @@ -636,6 +638,8 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, FILE_NAME_ATTR *fn = &ie->key.file_name; unsigned dt_type; + ntfs_log_trace("Entering.\n"); + /* Advance the position even if going to skip the entry. */ if (index_type == INDEX_TYPE_ALLOCATION) *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu( @@ -680,6 +684,8 @@ static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni) FILE_NAME_ATTR *fn; int eo; + ntfs_log_trace("Entering.\n"); + if (!ni) { errno = EINVAL; return ERR_MREF(-1); @@ -749,6 +755,8 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, u32 index_block_size, index_vcn_size; u8 index_block_size_bits, index_vcn_size_bits; + ntfs_log_trace("Entering.\n"); + if (!dir_ni || !pos || !filldir) { errno = EINVAL; return -1; @@ -1119,6 +1127,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, int err, fn_len, si_len, sd_len; ntfs_log_trace("Entering.\n"); + /* Sanity checks. */ if (!dir_ni || !name || !name_len) { ntfs_log_error("Invalid arguments.\n"); @@ -1462,6 +1471,7 @@ int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) int err = 0; ntfs_log_trace("Entering.\n"); + if (!ni || !dir_ni || !name || !name_len) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; @@ -1694,6 +1704,7 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) int fn_len, err; ntfs_log_trace("Entering.\n"); + if (!ni || !dir_ni || !name || !name_len || ni->mft_no == dir_ni->mft_no) { err = errno; diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 6032a3fe..c23b2ca0 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -668,15 +668,15 @@ int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref) { static u8 buffer[512]; static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */ - int byte, bit; + ntfs_log_trace("Entering.\n"); + if (!vol) { errno = EINVAL; return -1; } - ntfs_log_trace("entering\n"); /* Does mref lie in the section of $Bitmap we already have cached? */ if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref + (sizeof(buffer) << 3)))) { From 8ddea064b9d085df009f2d8ce2eccf5be63466fa Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 27 Oct 2006 09:04:08 +0000 Subject: [PATCH 083/289] Revert 1.13 commit from Yuval: Gratuitous API/ABI change. --- include/ntfs/runlist.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/ntfs/runlist.h b/include/ntfs/runlist.h index 0d066598..726a28dc 100644 --- a/include/ntfs/runlist.h +++ b/include/ntfs/runlist.h @@ -62,9 +62,14 @@ extern runlist_element *ntfs_runlists_merge(runlist_element *drl, extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, const ATTR_RECORD *attr, runlist_element *old_rl); +extern int ntfs_get_nr_significant_bytes(const s64 n); + extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, const runlist_element *rl, const VCN start_vcn); +extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, + const s64 n); + extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst, const int dst_len, const runlist_element *rl, const VCN start_vcn, VCN *const stop_vcn); From 880529ee5ae8ee00e618925760473db23b100226 Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 27 Oct 2006 09:05:56 +0000 Subject: [PATCH 084/289] Revert part of 1.71: Gratuituous API/ABI change. --- libntfs/runlist.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libntfs/runlist.c b/libntfs/runlist.c index adcae4d3..6c9ccf0d 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -1220,7 +1220,7 @@ rl_err_out: * * Return the number of bytes written. This function cannot fail. */ -static int ntfs_get_nr_significant_bytes(const s64 n) +int ntfs_get_nr_significant_bytes(const s64 n) { s64 l = n; int i; @@ -1363,8 +1363,7 @@ err_out: * Return the number of bytes written on success. On error, i.e. the * destination buffer @dst is too small, return -1 with errno set ENOSPC. */ -static int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, - const s64 n) +int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n) { s64 l = n; int i; From ff55ecb5130e17ac97b1a5bd087d4632a20a0976 Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 27 Oct 2006 12:24:29 +0000 Subject: [PATCH 085/289] Whitespace cleanup --- include/ntfs/layout.h | 12 +- include/ntfs/list.h | 2 +- include/ntfs/support.h | 6 +- libntfs/attrib.c | 18 +- libntfs/dir.c | 4 +- libntfs/index.c | 452 ++++++++++++++++++++--------------------- libntfs/inode.c | 4 +- libntfs/runlist.c | 12 +- libntfs/unistr.c | 4 +- libntfs/unix_io.c | 2 +- libntfs/volume.c | 4 +- ntfsprogs/mkntfs.c | 20 +- ntfsprogs/ntfsclone.c | 26 +-- ntfsprogs/ntfscmp.c | 28 +-- ntfsprogs/ntfsinfo.c | 98 +++++---- ntfsprogs/ntfsresize.c | 2 +- 16 files changed, 346 insertions(+), 348 deletions(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 68ebca72..39e4c934 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -244,7 +244,7 @@ typedef enum { * * These are the so far known MFT_RECORD_* flags (16-bit) which contain * information about the mft record in which they are present. - * + * * MFT_RECORD_IS_4 exists on all $Extend sub-files. * It seems that it marks it is a metadata file with MFT record >24, however, * it is unknown if it is limited to metadata files only. @@ -480,7 +480,7 @@ typedef struct { * Each attribute type has a corresponding attribute name (Unicode string of * maximum 64 character length) as described by the attribute definitions * present in the data attribute of the $AttrDef system file. - * + * * On NTFS 3.0 volumes the names are just as the types are named in the below * enum exchanging AT_ for the dollar sign ($). If that isn't a revealing * choice of symbol... (-; @@ -867,15 +867,15 @@ typedef enum { * This is a copy of the MFT_RECORD_IS_DIRECTORY bit from the mft * record, telling us whether this is a directory or not, i.e. whether * it has an index root attribute named "$I30" or not. - * - * This flag is only present in the FILE_NAME attribute (in the + * + * This flag is only present in the FILE_NAME attribute (in the * file_attributes field). */ FILE_ATTR_I30_INDEX_PRESENT = const_cpu_to_le32(0x10000000), - + /** * FILE_ATTR_VIEW_INDEX_PRESENT - Does have a non-directory index? - * + * * This is a copy of the MFT_RECORD_IS_VIEW_INDEX bit from the mft * record, telling us whether this file has a view index present (eg. * object id index, quota index, one of the security indexes and the diff --git a/include/ntfs/list.h b/include/ntfs/list.h index 9af28aa5..e3c77442 100644 --- a/include/ntfs/list.h +++ b/include/ntfs/list.h @@ -24,7 +24,7 @@ /** * struct list_head - Simple doubly linked list implementation. - * + * * Copied from Linux kernel 2.4.2-ac18 into Linux-NTFS (with minor * modifications). - AIA * diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 7b9aa351..10eab345 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -98,13 +98,13 @@ /** * ntfs_calloc, ntfs_malloc - * + * * Return a pointer to the allocated memory or NULL if the request fails. */ static inline void *ntfs_calloc(size_t size) { void *p; - + p = calloc(1, size); if (!p) ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); @@ -114,7 +114,7 @@ static inline void *ntfs_calloc(size_t size) static inline void *ntfs_malloc(size_t size) { void *p; - + p = malloc(size); if (!p) ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index eb57bfee..e6b8f48f 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -3861,7 +3861,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) goto put_err_out; } - /* + /* * Force index allocation creation instead of moving out index root * from the base MFT record. */ @@ -4988,21 +4988,21 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) ntfs_inode_update_time(na->ni); return ret; } - + /** * ntfs_attr_readall - read the entire data from an ntfs attribute * @ni: open ntfs inode in which the ntfs attribute resides * @type: attribute type * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL * @name_len: length of attribute @name in Unicode characters (if @name given) - * @data_size: if non-NULL then store here the data size + * @data_size: if non-NULL then store here the data size * * This function will read the entire content of an ntfs attribute. * If @name is AT_UNNAMED then look specifically for an unnamed attribute. - * If @name is NULL then the attribute could be either named or not. + * If @name is NULL then the attribute could be either named or not. * In both those cases @name_len is not used at all. * - * On success a buffer is allocated with the content of the attribute + * On success a buffer is allocated with the content of the attribute * and which needs to be freed when it's not needed anymore. If the * @data_size parameter is non-NULL then the data size is set there. * @@ -5014,7 +5014,7 @@ void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, ntfs_attr *na; void *data, *ret = NULL; s64 size; - + na = ntfs_attr_open(ni, type, name, name_len); if (!na) { ntfs_log_perror("ntfs_attr_open failed"); @@ -5047,13 +5047,13 @@ int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, { ntfs_attr_search_ctx *ctx; int ret; - + ntfs_log_trace("Entering.\n"); - + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return 0; - + ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); diff --git a/libntfs/dir.c b/libntfs/dir.c index b1c3110e..87b60684 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1175,7 +1175,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, * 4 bytes to every SID. */ sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + - sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); sd = calloc(1, sd_len); if (!sd) { err = errno; @@ -1191,7 +1191,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, sid->sub_authority[0] = cpu_to_le32(32); sid->sub_authority[1] = cpu_to_le32(544); sid->identifier_authority.value[5] = 5; - sid = (SID*)((u8*)sid + sizeof(SID) + 4); + sid = (SID*)((u8*)sid + sizeof(SID) + 4); sd->group = cpu_to_le32((u8*)sid - (u8*)sd); sid->revision = 1; sid->sub_authority_count = 2; diff --git a/libntfs/index.c b/libntfs/index.c index dde8763b..0a5712f1 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -59,9 +59,9 @@ static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos) static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf) { s64 ret; - + ntfs_log_trace("vcn: %lld\n", vcn); - + ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), 1, icx->block_size, buf); if (ret != 1) { @@ -76,9 +76,9 @@ static int ntfs_icx_ib_write(ntfs_index_context *icx) { if (ntfs_ib_write(icx, icx->ib_vcn, icx->ib)) return STATUS_ERROR; - + icx->ib_dirty = FALSE; - + return STATUS_OK; } @@ -97,7 +97,7 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, ntfs_index_context *icx; ntfs_log_trace("Entering.\n"); - + if (!ni) { errno = EINVAL; return NULL; @@ -117,7 +117,7 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, static void ntfs_index_ctx_free(ntfs_index_context *icx) { ntfs_log_trace("Entering.\n"); - + if (!icx->entry) return; @@ -134,7 +134,7 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx) /* FIXME: Error handling!!! */ ntfs_ib_write(icx, icx->ib_vcn, icx->ib); } - + free(icx->ib); ntfs_attr_close(icx->ia_na); } @@ -160,9 +160,9 @@ void ntfs_index_ctx_put(ntfs_index_context *icx) void ntfs_index_ctx_reinit(ntfs_index_context *icx) { ntfs_log_trace("Entering.\n"); - + ntfs_index_ctx_free(icx); - + *icx = (ntfs_index_context) { .ni = icx->ni, .name = icx->name, @@ -204,13 +204,13 @@ static int ntfs_ie_end(INDEX_ENTRY *ie) return ie->flags & INDEX_ENTRY_END; } -/** +/** * Find the last entry in the index block */ static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) { ntfs_log_trace("Entering.\n"); - + while ((char *)ie < ies_end && !ntfs_ie_end(ie)) ie = ntfs_ie_get_next(ie); return ie; @@ -219,9 +219,9 @@ static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) { ntfs_log_trace("pos: %d\n", pos); - + INDEX_ENTRY *ie = ntfs_ie_get_first(ih); - + while (pos-- > 0) ie = ntfs_ie_get_next(ie); return ie; @@ -230,10 +230,10 @@ static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) { ntfs_log_trace("Entering.\n"); - + INDEX_ENTRY *ie_prev = NULL; INDEX_ENTRY *tmp = ntfs_ie_get_first(ih); - + while (tmp != ie) { ie_prev = tmp; tmp = ntfs_ie_get_next(tmp); @@ -270,9 +270,9 @@ void ntfs_ie_filename_dump(INDEX_ENTRY *ie) void ntfs_ih_filename_dump(INDEX_HEADER *ih) { INDEX_ENTRY *ie; - + ntfs_log_trace("Entering.\n"); - + ie = ntfs_ie_get_first(ih); while (!ntfs_ie_end(ie)) { ntfs_ie_filename_dump(ie); @@ -284,9 +284,9 @@ static int ntfs_ih_numof_entries(INDEX_HEADER *ih) { int n; INDEX_ENTRY *ie; - + ntfs_log_trace("Entering.\n"); - + ie = ntfs_ie_get_first(ih); for (n = 0; !ntfs_ie_end(ie); n++) ie = ntfs_ie_get_next(ie); @@ -306,9 +306,9 @@ static int ntfs_ih_zero_entry(INDEX_HEADER *ih) static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) { u32 new_size; - + ntfs_log_trace("Entering.\n"); - + new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length); ih->index_length = cpu_to_le32(new_size); memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), @@ -326,9 +326,9 @@ static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) { int ie_size = le16_to_cpu(ie->length); - + ntfs_log_trace("Entering.\n"); - + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size); memmove((u8 *)pos + ie_size, pos, le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - @@ -339,9 +339,9 @@ static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) { INDEX_ENTRY *dup; - + ntfs_log_trace("Entering.\n"); - + dup = ntfs_malloc(ie->length); if (dup) memcpy(dup, ie, ie->length); @@ -352,16 +352,16 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) { INDEX_ENTRY *dup; int size = ie->length; - + ntfs_log_trace("Entering.\n"); - + if (ie->flags & INDEX_ENTRY_NODE) size -= sizeof(VCN); - + dup = ntfs_malloc(size); if (dup) memcpy(dup, ie, size); - + dup->flags &= ~INDEX_ENTRY_NODE; dup->length = size; return dup; @@ -370,30 +370,30 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) { u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; - + ntfs_log_trace("Entering.\n"); - + if (!ntfs_is_indx_record(ib->magic)) { - + ntfs_log_error("Corrupt index block signature: vcn %lld inode " "%llu\n", (long long)vcn, icx->ni->mft_no); return -1; } - + if (sle64_to_cpu(ib->index_block_vcn) != vcn) { - + ntfs_log_error("Corrupt index block: VCN (%lld) is different " "from expected VCN (%lld) in inode %llu\n", (long long) sle64_to_cpu(ib->index_block_vcn), (long long)vcn, icx->ni->mft_no); return -1; } - + if (ib_size != icx->block_size) { - + ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " "has a size (%u) differing from the index " - "specified size (%u)\n", (long long)vcn, + "specified size (%u)\n", (long long)vcn, icx->ni->mft_no, ib_size, icx->block_size); return -1; } @@ -407,26 +407,26 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, INDEX_ROOT *ir = NULL; ntfs_log_trace("Entering.\n"); - + *ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!*ctx) { ntfs_log_perror("Failed to get $INDEX_ROOT search context"); return NULL; } - - if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, + + if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, 0, NULL, 0, *ctx)) { ntfs_log_perror("Failed to lookup $INDEX_ROOT"); goto err_out; } - + a = (*ctx)->attr; if (a->non_resident) { errno = EINVAL; ntfs_log_perror("Non-resident $INDEX_ROOT detected"); goto err_out; } - + ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); err_out: if (!ir) @@ -434,11 +434,11 @@ err_out: return ir; } -/** +/** * Find a key in the index block. - * + * * Return values: - * STATUS_OK with errno set to ESUCCESS if we know for sure that the + * STATUS_OK with errno set to ESUCCESS if we know for sure that the * entry exists and @ie_out points to this entry. * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the * entry doesn't exist and @ie_out is the insertion point. @@ -453,11 +453,11 @@ static int ntfs_ie_lookup(const void *key, const int key_len, INDEX_ENTRY *ie; u8 *index_end; int rc, item = 0; - + ntfs_log_trace("Entering.\n"); - + index_end = ntfs_ie_get_end(ih); - + /* * Loop until we exceed valid memory (corruption case) or until we * reach the last entry. @@ -496,14 +496,14 @@ static int ntfs_ie_lookup(const void *key, const int key_len, */ if (rc == -1) break; - + if (!rc) { *ie_out = ie; errno = 0; icx->parent_pos[icx->pindex] = item; return STATUS_OK; } - + item++; } /* @@ -517,7 +517,7 @@ static int ntfs_ie_lookup(const void *key, const int key_len, errno = ENOENT; return STATUS_NOT_FOUND; } - + /* Get the starting vcn of the index_block holding the child node. */ *vcn = ntfs_ie_get_vcn(ie); if (*vcn < 0) { @@ -535,7 +535,7 @@ static int ntfs_ie_lookup(const void *key, const int key_len, static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) { ntfs_attr *na; - + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open index allocation of inode " @@ -550,7 +550,7 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) s64 pos, ret; ntfs_log_trace("vcn: %lld\n", vcn); - + pos = ntfs_ib_vcn_to_pos(icx, vcn); ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, @@ -558,12 +558,12 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) if (ret != 1) { if (ret == -1) ntfs_log_perror("Failed to read index block"); - else + else ntfs_log_error("Failed to read full index block at " "%lld\n", pos); return -1; } - + if (ntfs_ia_check(icx, dst, vcn)) return -1; return 0; @@ -590,7 +590,7 @@ static int ntfs_icx_parent_dec(ntfs_index_context *icx) } return STATUS_OK; } - + /** * ntfs_index_lookup - find a key in an index and return its index entry * @key: [IN] key for which to search in the index @@ -635,7 +635,7 @@ int ntfs_index_lookup(const void *key, const int key_len, int ret, err = 0; ntfs_log_trace("Entering.\n"); - + if (!key || key_len <= 0) { errno = EINVAL; ntfs_log_perror("key: %p key_len: %d", key, key_len); @@ -648,7 +648,7 @@ int ntfs_index_lookup(const void *key, const int key_len, errno = EIO; return -1; } - + icx->block_size = le32_to_cpu(ir->index_block_size); if (icx->block_size < NTFS_BLOCK_SIZE) { errno = EINVAL; @@ -662,17 +662,17 @@ int ntfs_index_lookup(const void *key, const int key_len, icx->vcn_size_bits = ni->vol->cluster_size_bits; else icx->vcn_size_bits = ni->vol->sector_size_bits; - + icx->cr = ir->collation_rule; if (!ntfs_is_collation_rule_supported(icx->cr)) { err = errno = EOPNOTSUPP; - ntfs_log_perror("Unknown collation rule 0x%x", + ntfs_log_perror("Unknown collation rule 0x%x", (unsigned)le32_to_cpu(icx->cr)); goto err_out; } - + old_vcn = VCN_INDEX_ROOT_PARENT; - /* + /* * FIXME: check for both ir and ib that the first index entry is * within the index block. */ @@ -681,10 +681,10 @@ int ntfs_index_lookup(const void *key, const int key_len, err = errno; goto err_out; } - + icx->actx = actx; icx->ir = ir; - + if (ret != STATUS_KEEP_SEARCHING) { /* STATUS_OK or STATUS_NOT_FOUND */ err = errno; @@ -692,18 +692,18 @@ int ntfs_index_lookup(const void *key, const int key_len, icx->parent_vcn[icx->pindex] = old_vcn; goto done; } - + /* Child node present, descend into it. */ icx->ia_na = ntfs_ia_open(icx, ni); if (!icx->ia_na) goto err_out; - + ib = ntfs_malloc(icx->block_size); if (!ib) { err = errno; goto err_out; } - + descend_into_child_node: icx->parent_vcn[icx->pindex] = old_vcn; if (ntfs_icx_parent_inc(icx)) { @@ -713,16 +713,16 @@ descend_into_child_node: old_vcn = vcn; ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); - + if (ntfs_ib_read(icx, vcn, ib)) goto err_out; - + ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie); if (ret != STATUS_KEEP_SEARCHING) { err = errno; if (ret == STATUS_ERROR) goto err_out; - + /* STATUS_OK or STATUS_NOT_FOUND */ icx->is_in_root = FALSE; icx->ib = ib; @@ -735,7 +735,7 @@ descend_into_child_node: "node in inode 0x%llx.\n", ni->mft_no); goto err_out; } - + goto descend_into_child_node; err_out: if (icx->ia_na) { @@ -762,38 +762,38 @@ done: return 0; } -static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, int ib_size, +static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, int ib_size, INDEX_HEADER_FLAGS node_type) { INDEX_BLOCK *ib; int ih_size = sizeof(INDEX_HEADER); - + ntfs_log_trace("Entering ib_vcn = %lld ib_size = %d\n", ib_vcn, ib_size); - + ib = ntfs_calloc(ib_size); if (!ib) return NULL; - + ib->magic = magic_INDX; ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); /* Set USN to 1 */ *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); ib->lsn = cpu_to_le64(0); - + ib->index_block_vcn = cpu_to_sle64(ib_vcn); - + ib->index.entries_offset = cpu_to_le32((ih_size + le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); ib->index.index_length = 0; - ib->index.allocated_size = cpu_to_le32(ib_size - + ib->index.allocated_size = cpu_to_le32(ib_size - (sizeof(INDEX_BLOCK) - ih_size)); ib->index.flags = node_type; return ib; -} +} -/** +/** * Find the median by going through all the entries */ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) @@ -801,12 +801,12 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) INDEX_ENTRY *ie, *ie_start; u8 *ie_end; int i = 0, median; - + ntfs_log_trace("Entering.\n"); - + ie = ie_start = ntfs_ie_get_first(ih); ie_end = (u8 *)ntfs_ie_get_end(ih); - + while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { ie = ntfs_ie_get_next(ie); i++; @@ -815,12 +815,12 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) * NOTE: this could be also the entry at the half of the index block. */ median = i / 2 - 1; - + ntfs_log_trace("Entries: %d median: %d\n", i, median); - + for (i = 0, ie = ie_start; i <= median; i++) ie = ntfs_ie_get_next(ie); - + return ie; } @@ -839,7 +839,7 @@ static int ntfs_ibm_add(ntfs_index_context *icx) u8 bmp[8]; ntfs_log_trace("Entering.\n"); - + if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len)) return STATUS_OK; /* @@ -864,7 +864,7 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) int ret = STATUS_ERROR; ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn); - + na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open $BITMAP attribute"); @@ -879,17 +879,17 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) } } } - + if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { ntfs_log_perror("Failed to read $BITMAP"); goto err_na; } - if (set) + if (set) byte |= bit; else byte &= ~bit; - + if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { ntfs_log_perror("Failed to write $Bitmap"); goto err_na; @@ -919,17 +919,17 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx) s64 vcn, byte, size; ntfs_log_trace("Entering.\n"); - + bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len, &size); if (!bm) return (VCN)-1; - + for (byte = 0; byte < size; byte++) { - + if (bm[byte] == 255) continue; - + for (bit = 0; bit < 8; bit++) { if (!(bm[byte] & (1 << bit))) { vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit); @@ -937,14 +937,14 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx) } } } - + vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); -out: +out: ntfs_log_trace("allocated vcn: %lld\n", vcn); if (ntfs_ibm_set(icx, vcn)) vcn = (VCN)-1; - + free(bm); return vcn; } @@ -955,28 +955,28 @@ static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) INDEX_ENTRY *ie_last; char *ies_start, *ies_end; int i; - + ntfs_log_trace("Entering.\n"); - + ib = ntfs_ib_alloc(ib_vcn, ir->index_block_size, LEAF_NODE); if (!ib) return NULL; - + ies_start = (char *)ntfs_ie_get_first(&ir->index); ies_end = (char *)ntfs_ie_get_end(&ir->index); - + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); - /* + /* * Copy all entries, including the termination entry * as well, which can never have any data. */ i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); - + ib->index.flags = ir->index.flags; ib->index.index_length = cpu_to_le32(i + le32_to_cpu(ib->index.entries_offset)); - /* + /* * Move the index root termination entry forward */ if ((char *)ie_last > ies_start) { @@ -987,27 +987,27 @@ static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) return ib; } -static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, +static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, INDEX_BLOCK *dst, INDEX_ENTRY *median, VCN new_vcn) { u8 *ies_end; INDEX_ENTRY *ie_head; /* first entry after the median */ int tail_size; - + ntfs_log_trace("Entering.\n"); - + ie_head = ntfs_ie_get_next(median); - + ies_end = (u8 *)ntfs_ie_get_end(&src->index); tail_size = ies_end - (u8 *)ie_head; memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); - + dst->index.index_length = cpu_to_le32(tail_size + le32_to_cpu(dst->index.entries_offset)); - + if (ntfs_ib_write(icx, new_vcn, dst)) return STATUS_ERROR; - + return STATUS_OK; } @@ -1016,34 +1016,34 @@ static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, { char *ies_start, *ies_end; INDEX_ENTRY *ie_last; - + ntfs_log_trace("Entering.\n"); - + ies_start = (char *)ntfs_ie_get_first(&src->index); ies_end = (char *)ntfs_ie_get_end(&src->index); - + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); if (ie_last->flags & INDEX_ENTRY_NODE) ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); - + memcpy(ie, ie_last, ie_last->length); - - src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + + + src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + ie->length + le32_to_cpu(src->index.entries_offset)); - + if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src)) return STATUS_ERROR; - + return STATUS_OK; } - + static int ntfs_ia_add(ntfs_index_context *icx) { ntfs_log_trace("Entering.\n"); if (ntfs_ibm_add(icx)) return -1; - + if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) { if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name, @@ -1052,7 +1052,7 @@ static int ntfs_ia_add(ntfs_index_context *icx) return -1; } } - + icx->ia_na = ntfs_ia_open(icx, icx->ni); if (!icx->ia_na) return -1; @@ -1117,23 +1117,23 @@ err_out: /** * ntfs_ir_truncate - Truncate index root attribute - * + * * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR. */ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) -{ +{ ntfs_attr *na; int ret; ntfs_log_trace("Entering.\n"); - + na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open INDEX_ROOT"); return STATUS_ERROR; } /* - * INDEX_ROOT must be resident and its entries can be moved to + * INDEX_ROOT must be resident and its entries can be moved to * INDEX_BLOCK, so ENOSPC isn't a real error. */ ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); @@ -1144,7 +1144,7 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) &ctx); if (!icx->ir) return STATUS_ERROR; - + icx->ir->index.allocated_size = cpu_to_le32(data_size); ntfs_attr_put_search_ctx(ctx); @@ -1158,19 +1158,19 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) ntfs_attr_close(na); return ret; } - + /** * ntfs_ir_make_space - Make more space for the index root attribute - * + * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return STATUS_ERROR. */ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) -{ +{ int ret; ntfs_log_trace("Entering.\n"); - + ret = ntfs_ir_truncate(icx, data_size); if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { ret = ntfs_ir_reparent(icx); @@ -1178,7 +1178,7 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) ret = STATUS_KEEP_SEARCHING; else ntfs_log_perror("Failed to nodify INDEX_ROOT"); - } + } return ret; } @@ -1188,30 +1188,30 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) { INDEX_ENTRY *p, *old = *ie; - + old->length += sizeof(VCN); p = realloc(old, old->length); if (!p) return STATUS_ERROR; - + p->flags |= INDEX_ENTRY_NODE; *ie = p; return STATUS_OK; } -static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, +static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, int pos) { INDEX_ENTRY *ie_node, *ie; int ret = STATUS_ERROR; VCN old_vcn; - + ntfs_log_trace("Entering.\n"); - + ie = ntfs_ie_dup(orig_ie); if (!ie) return STATUS_ERROR; - + if (!(ie->flags & INDEX_ENTRY_NODE)) if (ntfs_ie_add_vcn(&ie)) goto out; @@ -1219,11 +1219,11 @@ static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, ie_node = ntfs_ie_get_by_pos(ih, pos); old_vcn = ntfs_ie_get_vcn(ie_node); ntfs_ie_set_vcn(ie_node, new_vcn); - + ntfs_ie_insert(ih, ie, ie_node); ntfs_ie_set_vcn(ie_node, old_vcn); ret = STATUS_OK; -out: +out: free(ie); return ret; } @@ -1243,9 +1243,9 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, { u32 new_size; int ret; - + ntfs_log_trace("Entering.\n"); - + new_size = le32_to_cpu(icx->ir->index.index_length) + median->length; if (!(median->flags & INDEX_ENTRY_NODE)) new_size += sizeof(VCN); @@ -1254,7 +1254,7 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, if (ret != STATUS_OK) return ret; - return ntfs_ih_insert(&icx->ir->index, median, new_vcn, + return ntfs_ih_insert(&icx->ir->index, median, new_vcn, ntfs_icx_parent_pos(icx)); } @@ -1267,20 +1267,20 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); * On error return STATUS_ERROR. */ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) -{ +{ INDEX_BLOCK *ib; u32 idx_size, allocated_size; int err = STATUS_ERROR; VCN old_vcn; ntfs_log_trace("Entering.\n"); - + ib = ntfs_malloc(icx->block_size); if (!ib) return -1; - + old_vcn = ntfs_icx_parent_vcn(icx); - + if (ntfs_ib_read(icx, old_vcn, ib)) goto err_out; @@ -1293,65 +1293,65 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) err = STATUS_KEEP_SEARCHING; goto err_out; } - + if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) goto err_out; - + if (ntfs_ib_write(icx, old_vcn, ib)) goto err_out; - + err = STATUS_OK; -err_out: +err_out: free(ib); return err; } /** * ntfs_ib_split - Split index allocation attribute - * + * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return is STATUS_ERROR. */ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) -{ +{ INDEX_BLOCK *ib_new; INDEX_ENTRY *median; VCN new_vcn; int ret, err = STATUS_ERROR; ntfs_log_trace("Entering.\n"); - + if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; - + median = ntfs_ie_get_median(&ib->index); new_vcn = ntfs_ibm_get_free(icx); if (new_vcn == -1) return STATUS_ERROR; - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) ret = ntfs_ir_insert_median(icx, median, new_vcn); else ret = ntfs_ib_insert(icx, median, new_vcn); - + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); - + if (ret != STATUS_OK) { ntfs_ibm_clear(icx, new_vcn); return ret; } - - ib_new = ntfs_ib_alloc(new_vcn, icx->block_size, + + ib_new = ntfs_ib_alloc(new_vcn, icx->block_size, ib->index.flags & NODE_MASK); if (!ib_new) return STATUS_ERROR; - + if (ntfs_ib_copy_tail(icx, ib, ib_new, median, new_vcn)) goto free_ib_new; - + if (ntfs_ib_cut_tail(icx, ib, median)) goto free_ib_new; - + err = STATUS_OK; free_ib_new: free(ib_new); @@ -1364,10 +1364,10 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) INDEX_HEADER *ih; int allocated_size, new_size; int ret = STATUS_ERROR; - + fn = ntfs_ie_filename_get(ie); ntfs_log_trace("file: '%s'\n", fn); - + while (1) { if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { @@ -1379,22 +1379,22 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) ntfs_log_perror("Failed to find place for new entry"); goto err_out; } - + if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; - + allocated_size = le32_to_cpu(ih->allocated_size); new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); - + if (new_size <= allocated_size) break; - + ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", allocated_size, new_size); - + if (icx->is_in_root) { if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) goto err_out; @@ -1405,10 +1405,10 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } - + ntfs_ie_insert(ih, ie, icx->entry); ntfs_index_entry_mark_dirty(icx); - + ret = STATUS_OK; err_out: free(fn); @@ -1431,17 +1431,17 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) int fn_size, ie_size, ret = -1; ntfs_log_trace("Entering.\n"); - + if (!ni || !fn) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; return -1; } - + fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR); ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; - + ie = ntfs_calloc(ie_size); if (!ie) return -1; @@ -1450,13 +1450,13 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) ie->length = cpu_to_le16(ie_size); ie->key_length = cpu_to_le16(fn_size); memcpy(&ie->key, fn, fn_size); - + icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); if (!icx) goto out; - + ret = ntfs_ie_add(icx, ie); - + ntfs_index_ctx_put(icx); out: free(ie); @@ -1468,9 +1468,9 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, { INDEX_ENTRY *ie_roam; int ret = STATUS_ERROR; - + ntfs_log_trace("Entering.\n"); - + ie_roam = ntfs_ie_dup_novcn(ie); if (!ie_roam) return STATUS_ERROR; @@ -1482,7 +1482,7 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, else if (ntfs_ib_write(icx, ntfs_icx_parent_vcn(icx), ib)) goto out; - + ntfs_index_ctx_reinit(icx); ret = ntfs_ie_add(icx, ie_roam); @@ -1493,26 +1493,26 @@ out: /** * ntfs_ir_leafify - - * + * * Used if an empty index block to be deleted has END entry as the parent * in the INDEX_ROOT which is the only one there. */ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) { INDEX_ENTRY *ie; - + ntfs_log_trace("Entering.\n"); - + ie = ntfs_ie_get_first(ih); ie->flags &= ~INDEX_ENTRY_NODE; ie->length -= sizeof(VCN); - + ih->index_length -= sizeof(VCN); ih->flags &= ~LARGE_INDEX; - + /* Not fatal error */ ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); - + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } @@ -1520,19 +1520,19 @@ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) /** * ntfs_ih_reparent_end - * - * Used if an empty index block to be deleted has END entry as the parent + * Used if an empty index block to be deleted has END entry as the parent * in the INDEX_ROOT which is not the only one there. */ static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, INDEX_BLOCK *ib) { INDEX_ENTRY *ie, *ie_prev; - + ntfs_log_trace("Entering.\n"); - + ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); ie_prev = ntfs_ie_prev(ih, ie); - + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); return ntfs_ih_takeout(icx, ih, ie_prev, ib); } @@ -1543,48 +1543,48 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx) INDEX_HEADER *parent_ih; INDEX_ENTRY *ie; int ret = STATUS_ERROR; - + ntfs_log_trace("pindex: %d\n", icx->pindex); - + if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) return STATUS_ERROR; - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) parent_ih = &icx->ir->index; else { ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; - + if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) goto out; - + parent_ih = &ib->index; } - + ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); if (!ntfs_ie_end(ie)) { ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); goto out; } - + if (ntfs_ih_zero_entry(parent_ih)) { - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { ntfs_ir_leafify(icx, parent_ih); goto ok; } - + ret = ntfs_index_rm_leaf(icx); goto out; } - + if (ntfs_ih_reparent_end(icx, parent_ih, ib)) goto out; -ok: +ok: ret = STATUS_OK; out: free(ib); @@ -1602,7 +1602,7 @@ static int ntfs_index_rm_node(ntfs_index_context *icx) int delta, ret = STATUS_ERROR; ntfs_log_trace("Entering.\n"); - + if (!icx->ia_na) { icx->ia_na = ntfs_ia_open(icx, icx->ni); if (!icx->ia_na) @@ -1612,19 +1612,19 @@ static int ntfs_index_rm_node(ntfs_index_context *icx) ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; - + ie_succ = ntfs_ie_get_next(icx->entry); entry_pos = icx->parent_pos[icx->pindex]++; descend: vcn = ntfs_ie_get_vcn(ie_succ); if (ntfs_ib_read(icx, vcn, ib)) goto out; - + ie_succ = ntfs_ie_get_first(&ib->index); if (ntfs_icx_parent_inc(icx)) goto out; - + icx->parent_vcn[icx->pindex] = vcn; icx->parent_pos[icx->pindex] = 0; @@ -1641,7 +1641,7 @@ descend: ie = ntfs_ie_dup(ie_succ); if (!ie) goto out; - + if (ntfs_ie_add_vcn(&ie)) goto out2; @@ -1662,10 +1662,10 @@ descend: " during entry removal"); goto out2; } - + ih = &icx->ir->index; entry = ntfs_ie_get_by_pos(ih, entry_pos); - + } else if (new_size > ih->allocated_size) { errno = EOPNOTSUPP; ntfs_log_perror("Denied to split INDEX_BLOCK during " @@ -1676,7 +1676,7 @@ descend: ntfs_ie_delete(ih, entry); ntfs_ie_insert(ih, ie, entry); - + if (icx->is_in_root) { if (ntfs_ir_truncate(icx, new_size)) goto out2; @@ -1684,13 +1684,13 @@ descend: } else if (ntfs_icx_ib_write(icx)) goto out2; - + ntfs_ie_delete(&ib->index, ie_succ); - + if (ntfs_ih_zero_entry(&ib->index)) { if (ntfs_index_rm_leaf(icx)) goto out2; - } else + } else if (ntfs_ib_write(icx, vcn, ib)) goto out2; @@ -1706,8 +1706,8 @@ out: * ntfs_index_rm - remove entry from the index * @icx: index context describing entry to delete * - * Delete entry described by @icx from the index. Index context is always - * reinitialized after use of this function, so it can be used for index + * Delete entry described by @icx from the index. Index context is always + * reinitialized after use of this function, so it can be used for index * lookup once again. * * Return 0 on success or -1 on error with errno set to the error code. @@ -1718,7 +1718,7 @@ int ntfs_index_rm(ntfs_index_context *icx) int err; ntfs_log_trace("Entering.\n"); - + if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; @@ -1728,16 +1728,16 @@ int ntfs_index_rm(ntfs_index_context *icx) ih = &icx->ir->index; else ih = &icx->ib->index; - + if (icx->entry->flags & INDEX_ENTRY_NODE) { - + if (ntfs_index_rm_node(icx)) goto err_out; } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { - + ntfs_ie_delete(ih, icx->entry); - + if (icx->is_in_root) { err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); @@ -1750,7 +1750,7 @@ int ntfs_index_rm(ntfs_index_context *icx) if (ntfs_index_rm_leaf(icx)) goto err_out; } - + ntfs_index_ctx_reinit(icx); ntfs_log_trace("Done.\n"); return 0; @@ -1765,7 +1765,7 @@ err_out: /** * ntfs_index_root_get - read the index root of an attribute * @ni: open ntfs inode in which the ntfs attribute resides - * @attr: attribute for which we want its index root + * @attr: attribute for which we want its index root * * This function will read the related index root an ntfs attribute. * @@ -1784,14 +1784,14 @@ INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr) if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) return NULL; - + root = ntfs_malloc(sizeof(INDEX_ROOT)); if (!root) goto out; - + *root = *((INDEX_ROOT *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset))); -out: +out: ntfs_attr_put_search_ctx(ctx); return root; } diff --git a/libntfs/inode.c b/libntfs/inode.c index 2b1b9336..020cf1f2 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -1111,7 +1111,7 @@ void ntfs_inode_update_time(ntfs_inode *ni) * Check if the mft record given by @mft_no and @attr contains the bad sector * list. Please note that mft record numbers describing $Badclus extent inodes * will not match the current $Badclus:$Bad check. - * + * * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. * On error return -1 with errno set to the error code. */ @@ -1125,7 +1125,7 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) errno = EINVAL; return -1; } - + if (mft_no != FILE_BadClus) return 0; diff --git a/libntfs/runlist.c b/libntfs/runlist.c index 6c9ccf0d..31a21aea 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -1586,31 +1586,31 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) ntfs_log_perror("rl_truncate error: arl: %p *arl: %p", arl, *arl); return -1; } - + rl = *arl; - + if (start_vcn < rl->vcn) { errno = EINVAL; ntfs_log_perror("Start_vcn lies outside front of runlist"); return -1; } - + /* Find the starting vcn in the run list. */ while (rl->length) { if (start_vcn < rl[1].vcn) break; rl++; } - + if (!rl->length) { errno = EIO; ntfs_log_trace("Truncating already truncated runlist?\n"); return -1; } - + /* Truncate the run. */ rl->length = start_vcn - rl->vcn; - + /* * If a run was partially truncated, make the following runlist * element a terminator instead of the truncated runlist diff --git a/libntfs/unistr.c b/libntfs/unistr.c index db91b785..0660351d 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -708,12 +708,12 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) * @len: length of output buffer in Unicode characters * * Convert the input @s string into the corresponding little endian, - * 2-byte Unicode string. The length of the converted string is less + * 2-byte Unicode string. The length of the converted string is less * or equal to the maximum length allowed by the NTFS format (255). * * If @s is NULL then return AT_UNNAMED. * - * On success the function returns the Unicode string in an allocated + * On success the function returns the Unicode string in an allocated * buffer and the caller is responsible to free it when it's not needed * anymore. * diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index ee8d35db..028b3779 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -91,7 +91,7 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) /* * Open the device/file obtaining the file descriptor for exclusive * access (but only if mounting r/w). - */ + */ if ((flags & O_RDWR) == O_RDWR) flags |= O_EXCL; *(int*)dev->d_private = open(dev->d_name, flags); diff --git a/libntfs/volume.c b/libntfs/volume.c index a2fc9d98..3658016f 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -217,7 +217,7 @@ static int ntfs_mft_load(ntfs_volume *vol) } mft_has_no_attr_list: /* Receive attributes from STANDARD_INFORMATION. */ - std_info = ntfs_attr_readall(vol->mft_ni, AT_STANDARD_INFORMATION, + std_info = ntfs_attr_readall(vol->mft_ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL); vol->mft_ni->flags = std_info->file_attributes; @@ -815,7 +815,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) ntfs_log_perror("Failed to read $MFTMirr"); else { ntfs_log_debug("Failed to read $MFTMirr, unexpected " - "length (%d != %lld).\n", + "length (%d != %lld).\n", vol->mftmirr_size, l); errno = EIO; } diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 14b0f7cb..8212c27c 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -2861,7 +2861,7 @@ static int initialize_quota(MFT_RECORD *m) INDEX_ENTRY *idx_entry_o, *idx_entry_q1, *idx_entry_q2; QUOTA_O_INDEX_DATA *idx_entry_o_data; QUOTA_CONTROL_ENTRY *idx_entry_q1_data, *idx_entry_q2_data; - + err = 0; /* q index entry num 1 */ q1_size = 0x48; @@ -3790,7 +3790,7 @@ static BOOL mkntfs_initialize_bitmaps(void) g_rl_mft_bmp = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_mft_bmp) return FALSE; - + g_rl_mft_bmp[0].vcn = 0LL; /* Mft bitmap is right after $Boot's data. */ i = (8192 + g_vol->cluster_size - 1) / g_vol->cluster_size; @@ -3855,7 +3855,7 @@ static BOOL mkntfs_initialize_rl_mft(void) g_rl_mft = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_mft) return FALSE; - + g_rl_mft[0].vcn = 0LL; g_rl_mft[0].lcn = g_mft_lcn; /* rounded up division by cluster size */ @@ -3876,7 +3876,7 @@ static BOOL mkntfs_initialize_rl_mft(void) g_rl_mftmirr = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_mftmirr) return FALSE; - + g_rl_mftmirr[0].vcn = 0LL; g_rl_mftmirr[0].lcn = g_mftmirr_lcn; /* @@ -3912,7 +3912,7 @@ static BOOL mkntfs_initialize_rl_logfile(void) g_rl_logfile = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_logfile) return FALSE; - + volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; @@ -3935,7 +3935,7 @@ static BOOL mkntfs_initialize_rl_logfile(void) g_logfile_size = (volume_size / 100) & ~(g_vol->cluster_size - 1); } else { - /* + /* * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but * the "200" divider below apparently approximates "100" or * some other value as the volume size decreases. For example: @@ -3996,7 +3996,7 @@ static BOOL mkntfs_initialize_rl_boot(void) g_rl_boot = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_boot) return FALSE; - + g_rl_boot[0].vcn = 0LL; g_rl_boot[0].lcn = 0LL; /* @@ -4023,7 +4023,7 @@ static BOOL mkntfs_initialize_rl_bad(void) g_rl_bad = ntfs_malloc(2 * sizeof(runlist)); if (!g_rl_bad) return FALSE; - + g_rl_bad[0].vcn = 0LL; g_rl_bad[0].lcn = -1LL; /* @@ -4498,7 +4498,7 @@ static BOOL mkntfs_create_root_structures(void) buf_log = ntfs_malloc(g_logfile_size); if (!buf_log) return FALSE; - + memset(buf_log, -1, g_logfile_size); err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_logfile, buf_log, g_logfile_size); @@ -4969,7 +4969,7 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) g_vol->upcase = ntfs_malloc(g_vol->upcase_len * sizeof(ntfschar)); if (!g_vol->upcase) goto done; - + init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); if (g_vol->major_ver < 3) { g_vol->attrdef = ntfs_calloc(36000); diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 9bf498c9..715915f0 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -755,9 +755,9 @@ static void wipe_index_entry_timestams(INDEX_ENTRY *e) e->key.file_name.last_data_change_time = timestamp; e->key.file_name.last_mft_change_time = timestamp; e->key.file_name.last_access_time = timestamp; - + wiped_timestamp_data += 32; - + e = (INDEX_ENTRY *)((u8 *)e + le16_to_cpu(e->length)); } } @@ -785,7 +785,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); name_len = attr->name_length; - + byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); if (!byte) { perr_printf("Failed to read $BITMAP attribute"); @@ -812,7 +812,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) bit = 0; while ((u8 *)tmp_indexa < (u8 *)indexa + na->data_size) { - if (*byte & (1 << bit)) { + if (*byte & (1 << bit)) { if (ntfs_mst_post_read_fixup((NTFS_RECORD *)tmp_indexa, le32_to_cpu( indexr->index_block_size))) { @@ -834,7 +834,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) goto out_indexa; } } - tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa + + tmp_indexa = (INDEX_ALLOCATION *)((u8 *)tmp_indexa + le32_to_cpu(indexr->index_block_size)); bit++; if (bit > 7) { @@ -842,7 +842,7 @@ static void wipe_index_allocation_timestamps(ntfs_inode *ni, ATTR_RECORD *attr) byte++; } } - + if (ntfs_rl_pwrite(vol, na->rl, 0, na->data_size, indexa) != na->data_size) perr_printf("ntfs_rl_pwrite failed for inode %lld", ni->mft_no); out_indexa: @@ -924,7 +924,7 @@ static void wipe_timestamps(ntfs_walk_clusters_ctx *image) else if (a->type == AT_STANDARD_INFORMATION) WIPE_TIMESTAMPS(STANDARD_INFORMATION, a, timestamp); - + else if (a->type == AT_INDEX_ROOT) wipe_index_root_timestamps(a, timestamp); } @@ -1168,7 +1168,7 @@ static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) { if (ntfs_mft_usn_dec(ni->mrec)) perr_exit("ntfs_mft_usn_dec"); - + if (ntfs_mft_record_write(volume, ni->mft_no, ni->mrec)) perr_exit("ntfs_mft_record_write"); } @@ -1176,12 +1176,12 @@ static void mft_record_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) static void mft_inode_write_with_same_usn(ntfs_volume *volume, ntfs_inode *ni) { s32 i; - + mft_record_write_with_same_usn(volume, ni); - + if (ni->nr_extents <= 0) return; - + for (i = 0; i < ni->nr_extents; ++i) { ntfs_inode *eni = ni->extent_nis[i]; mft_record_write_with_same_usn(volume, eni); @@ -1719,7 +1719,7 @@ static void check_dest_free_space(u64 src_bytes) if (opt.metadata || opt.blkdev_out || opt.std_out) return; - /* + /* * TODO: save_image needs a bit more space than src_bytes * due to the free space encoding overhead. */ @@ -1732,7 +1732,7 @@ static void check_dest_free_space(u64 src_bytes) dest_bytes = (u64)stvfs.f_frsize * stvfs.f_bfree; if (!dest_bytes) dest_bytes = (u64)stvfs.f_bsize * stvfs.f_bfree; - + if (dest_bytes < src_bytes) err_exit("Destination doesn't have enough free space: " "%llu MB < %llu MB\n", diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index ae9fc548..6b8cd1f2 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -496,7 +496,7 @@ static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia) perr_println("Failed to readall BITMAP"); return -1; } - cia->byte = cia->bitmap; + cia->byte = cia->bitmap; cia->tmp_ia = cia->ia = ntfs_malloc(na->data_size); if (!cia->tmp_ia) @@ -506,7 +506,7 @@ static int setup_cmp_ia(ntfs_attr *na, struct cmp_ia *cia) perr_println("Failed to pread INDEX_ALLOCATION"); goto free_ia; } - + return 0; free_ia: free(cia->ia); @@ -520,28 +520,28 @@ static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) struct cmp_ia cia1, cia2; int bit, ret1, ret2; u32 ib_size; - + if (setup_cmp_ia(na1, &cia1)) return; if (setup_cmp_ia(na2, &cia2)) return; - /* + /* * FIXME: ia can be the same even if the bitmap sizes are different. */ if (cia1.bm_size != cia1.bm_size) goto out; - + if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1)) goto out; - + if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1)) goto out; ib_size = cia1.ia->index.allocated_size + 0x18; - + bit = 0; while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) { - if (*cia1.byte & (1 << bit)) { + if (*cia1.byte & (1 << bit)) { ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia1.tmp_ia, ib_size); ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia2.tmp_ia, @@ -550,19 +550,19 @@ static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) print_differ(na1); goto out; } - + if (ret1 == -1) continue; - - if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18, + + if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18, ((u8 *)cia2.tmp_ia) + 0x18, cia1.ia->index.index_length, na1)) goto out; } - + cia1.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia1.tmp_ia + ib_size); cia2.tmp_ia = (INDEX_ALLOCATION *)((u8 *)cia2.tmp_ia + ib_size); - + bit++; if (bit > 7) { bit = 0; @@ -615,7 +615,7 @@ static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2) printf("%lld != %lld\n", pos + count1, na1->data_size); exit(1); } - + if (cmp_buffer(buf1, buf2, count1, na1)) return; } diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index f95f919a..58fdc473 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -617,7 +617,7 @@ static void ntfs_dump_attr_standard_information(ATTR_RECORD *attr) (unsigned)value_length); } } - + static void ntfs_dump_bytes(u8 *buf, int start, int stop) { int i; @@ -647,7 +647,7 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) value = ntfs_malloc(l); if (!value) return; - + l = ntfs_get_attribute_value(vol, attr, value); if (!l) { ntfs_log_perror("ntfs_get_attribute_value failed"); @@ -698,7 +698,7 @@ static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) } else printf("unnamed\n"); printf("\t\tPadding:\t"); - ntfs_dump_bytes((u8 *)entry, entry->name_offset + + ntfs_dump_bytes((u8 *)entry, entry->name_offset + sizeof(ntfschar) * entry->name_length, le16_to_cpu(entry->length)); printf("\n"); @@ -864,7 +864,7 @@ static void ntfs_dump_acl(const char *prefix, ACL *acl) printf("%sRevision\t %u\n", prefix, acl->revision); - /* + /* * Do not recalculate le16_to_cpu every iteration (minor speedup on * big-endian machines. */ @@ -913,7 +913,7 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, const char *indent) { char *sid; - + printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); /* TODO: parse the flags */ @@ -921,17 +921,16 @@ static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, le16_to_cpu(sec_desc->control)); if (~sec_desc->control & SE_SELF_RELATIVE) { - SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)sec_desc; - + printf("%s\tOwner SID pointer:\t %p\n", indent, sd->owner); printf("%s\tGroup SID pointer:\t %p\n", indent, sd->group); printf("%s\tSACL pointer:\t\t %p\n", indent, sd->sacl); printf("%s\tDACL pointer:\t\t %p\n", indent, sd->dacl); - + return; } - + if (sec_desc->owner) { sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + le32_to_cpu(sec_desc->owner)), NULL, 0); @@ -1017,8 +1016,8 @@ static void ntfs_dump_attr_security_descriptor(ATTR_RECORD *attr, ntfs_volume *v } ntfs_dump_security_descriptor(sec_desc_attr, ""); - - if (attr->non_resident) + + if (attr->non_resident) free(sec_desc_attr); } @@ -1099,7 +1098,7 @@ static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) } static ntfschar NTFS_DATA_SDS[5] = { const_cpu_to_le16('$'), - const_cpu_to_le16('S'), const_cpu_to_le16('D'), + const_cpu_to_le16('S'), const_cpu_to_le16('D'), const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) @@ -1117,10 +1116,10 @@ static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) ntfs_log_verbose("\t\tLength:\t\t\t %u (0x%x)\n", (unsigned)le32_to_cpu(sds->length), (unsigned)le32_to_cpu(sds->length)); - + sd = (SECURITY_DESCRIPTOR_RELATIVE *)((char *)sds + sizeof(SECURITY_DESCRIPTOR_HEADER)); - + ntfs_dump_security_descriptor(sd, "\t"); } @@ -1131,22 +1130,22 @@ static void ntfs_dump_sds(ATTR_RECORD *attr, ntfs_inode *ni) int name_len; s64 data_size; u64 inode; - + inode = ni->mft_no; if (ni->nr_extents < 0) inode = ni->base_ni->mft_no; if (FILE_Secure != inode) return; - + name_len = attr->name_length; if (!name_len) return; - + name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); if (!ntfs_names_are_equal(NTFS_DATA_SDS, sizeof(NTFS_DATA_SDS) / 2 - 1, name, name_len, 0, NULL, 0)) return; - + sd = sds = ntfs_attr_readall(ni, AT_DATA, name, name_len, &data_size); if (!sd) { ntfs_log_perror("Failed to read $SDS attribute"); @@ -1156,10 +1155,10 @@ static void ntfs_dump_sds(ATTR_RECORD *attr, ntfs_inode *ni) * FIXME: The right way is based on the indexes, so we couldn't * miss real entries. For now, dump until it makes sense. */ - while (sd->length && sd->hash && + while (sd->length && sd->hash && le64_to_cpu(sd->offset) < (u64)data_size && le32_to_cpu(sd->length) < (u64)data_size && - le64_to_cpu(sd->offset) + + le64_to_cpu(sd->offset) + le32_to_cpu(sd->length) < (u64)data_size) { ntfs_dump_sds_entry(sd); sd = (SECURITY_DESCRIPTOR_HEADER *)((char*)sd + @@ -1193,10 +1192,10 @@ static const char *get_attribute_type_name(u32 type) return "$UNKNOWN"; } - + static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) { - printf("Dumping attribute %s (0x%x)\n", + printf("Dumping attribute %s (0x%x)\n", get_attribute_type_name(a->type), (unsigned)le32_to_cpu(a->type)); @@ -1274,7 +1273,7 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) sle64_to_cpu(a->initialized_size)); if (a->compression_unit || a->flags & ATTR_IS_COMPRESSED || a->flags & ATTR_IS_SPARSE) - printf("\tCompressed size:\t %llu (0x%llx)\n", + printf("\tCompressed size:\t %llu (0x%llx)\n", (signed long long) sle64_to_cpu(a->compressed_size), (signed long long) @@ -1324,7 +1323,7 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) { char *sid; char printable_GUID[37]; - + switch (type) { case INDEX_ATTR_SECURE_SII: ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", @@ -1382,9 +1381,9 @@ typedef union { static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) { INDEX_ENTRY_DATA *data; - + data = (INDEX_ENTRY_DATA *)((u8 *)entry + entry->data_offset); - + switch (type) { case INDEX_ATTR_SECURE_SII: ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", @@ -1580,7 +1579,7 @@ static INDEX_ATTR_TYPE get_index_attr_type(ntfs_inode *ni, ATTR_RECORD *attr, if (!attr->name_length) return INDEX_ATTR_UNKNOWN; - + if (index_root->type) { if (index_root->type == AT_FILE_NAME) return INDEX_ATTR_DIRECTORY_I30; @@ -1590,12 +1589,12 @@ static INDEX_ATTR_TYPE get_index_attr_type(ntfs_inode *ni, ATTR_RECORD *attr, index_root->type); return INDEX_ATTR_UNKNOWN; } - + if (utils_is_metadata(ni) <= 0) return INDEX_ATTR_UNKNOWN; if (utils_inode_get_name(ni, file_name, sizeof(file_name)) <= 0) return INDEX_ATTR_UNKNOWN; - + if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SDH)) return INDEX_ATTR_SECURE_SDH; else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SII)) @@ -1612,7 +1611,7 @@ static INDEX_ATTR_TYPE get_index_attr_type(ntfs_inode *ni, ATTR_RECORD *attr, else if (!strcmp(file_name, "/$Extend/$ObjId")) return INDEX_ATTR_OBJID_O; } - + return INDEX_ATTR_UNKNOWN; } @@ -1649,7 +1648,7 @@ static void ntfs_dump_index_header(const char *indent, INDEX_HEADER *idx) (unsigned)le32_to_cpu(idx->allocated_size), (unsigned)le32_to_cpu(idx->allocated_size)); printf("%sIndex header flags:\t 0x%02x\n", indent, idx->flags); - + /* FIXME: there are 3 reserved bytes here */ } @@ -1670,7 +1669,7 @@ static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) type = get_index_attr_type(ni, attr, index_root); printf("\tIndexed Attr Type:\t "); ntfs_dump_index_attr_type(type); - + /* collation rule dumping */ printf("\tCollation Rule:\t\t %u (0x%x)\n", (unsigned)le32_to_cpu(index_root->collation_rule), @@ -1717,7 +1716,7 @@ static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, u32 ib_size) { INDEX_ENTRY *entry; - + if (ntfs_mst_post_read_fixup((NTFS_RECORD*)ib, ib_size)) { ntfs_log_perror("Damaged INDX record"); return -1; @@ -1729,15 +1728,15 @@ static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, ntfs_log_verbose("\t\tNode VCN:\t\t %lld (0x%llx)\n", (unsigned long long)sle64_to_cpu(ib->index_block_vcn), (unsigned long long)sle64_to_cpu(ib->index_block_vcn)); - - entry = (INDEX_ENTRY*)((u8*)ib + + + entry = (INDEX_ENTRY*)((u8*)ib + le32_to_cpu(ib->index.entries_offset) + 0x18); - + if (opts.verbose) { ntfs_dump_index_header("\t\t", &ib->index); printf("\n"); } - + return ntfs_dump_index_entries(entry, type); } @@ -1764,19 +1763,19 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) ntfs_log_perror("Failed to read $INDEX_ROOT attribute"); return; } - + type = get_index_attr_type(ni, attr, ir); - + name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); name_len = attr->name_length; - + byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); if (!byte) { ntfs_log_perror("Failed to read $BITMAP attribute"); goto out_index_root; } - tmp_alloc = allocation = ntfs_attr_readall(ni, AT_INDEX_ALLOCATION, + tmp_alloc = allocation = ntfs_attr_readall(ni, AT_INDEX_ALLOCATION, name, name_len, &data_size); if (!tmp_alloc) { ntfs_log_perror("Failed to read $INDEX_ALLOCATION attribute"); @@ -1787,7 +1786,7 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) while ((u8 *)tmp_alloc < (u8 *)allocation + data_size) { if (*byte & (1 << bit)) { int entries; - + entries = ntfs_dump_index_block(tmp_alloc, type, le32_to_cpu( ir->index_block_size)); @@ -1797,7 +1796,7 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) printf("\tIndex entries:\t\t %d\n", entries); } } - tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + + tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + le32_to_cpu( ir->index_block_size)); bit++; @@ -1809,7 +1808,7 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) printf("\tIndex entries total:\t %d\n", total_entries); printf("\tINDX blocks total:\t %d\n", total_indx_blocks); - + free(allocation); out_bitmap: free(bitmap); @@ -2083,9 +2082,9 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) printf("Next Attribute Instance: %u (0x%x)\n", (unsigned)le16_to_cpu(mrec->next_attr_instance), (unsigned)le16_to_cpu(mrec->next_attr_instance)); - + printf("MFT Padding:\t"); - ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + + ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + 2 * le16_to_cpu(mrec->usa_count), le16_to_cpu(mrec->attrs_offset)); printf("\n"); @@ -2102,7 +2101,6 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) see ntfs_attr_lookup documentation for detailed explanation */ ctx = ntfs_attr_get_search_ctx(inode, NULL); while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { - if (ctx->attr->type == AT_END || ctx->attr->type == AT_UNUSED) { printf("Weird: %s attribute type was found, please " "report this.\n", @@ -2110,9 +2108,9 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) ctx->attr->type)); continue; } - + ntfs_dump_attribute_header(ctx->attr, inode->vol); - + switch (ctx->attr->type) { case AT_STANDARD_INFORMATION: ntfs_dump_attr_standard_information(ctx->attr); @@ -2194,7 +2192,7 @@ int main(int argc, char **argv) ntfs_volume *vol; setlinebuf(stdout); - + ntfs_log_set_handler(ntfs_log_handler_outerr); if (!parse_options(argc, argv)) { diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 9f6a0367..1c592ab2 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2028,7 +2028,7 @@ static int check_bad_sectors(ntfs_volume *vol) if (!ctx->attr->non_resident) err_exit("Resident attribute in $BadClust! Please report to " "%s\n", NTFS_DEV_LIST); - /* + /* * FIXME: The below would be partial for non-base records in the * not yet supported multi-record case. Alternatively use audited * ntfs_attr_truncate after an umount & mount. From 83d70bb9b75d2ac872924a3093fd07f2b3c2b793 Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 27 Oct 2006 13:00:08 +0000 Subject: [PATCH 086/289] Change contact address to -dev. Add Mario to project members. Add zhanglinbao to CREDITS for his big-endiness testing and fixes. Add my mail address. anti-spam changes (if it helps nowdays). Misc changes. (Yuval, Szaka) --- AUTHORS | 16 +++++++++------- CREDITS | 4 ++-- autogen.sh | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index f507a1ab..dd8a1815 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,10 +1,12 @@ -ntfsprogs is written and maintained by Anton Altaparmakov . +ntfsprogs is written and maintained by the Linux-NTFS project, you can contact +us at . -Current active developers on the project are (in alphabetical order): +Current active project members are (in alphabetical order): -Anton Altaparmakov -Yuval Fledel (no email address on request) -Yura Pakhuchiy -Richard Russon -Szakacsits Szabolcs +Anton Altaparmakov +Mario Emmenlauer +Yuval Fledel +Yura Pakhuchiy +Richard Russon +Szabolcs Szakacsits diff --git a/CREDITS b/CREDITS index b42c7dc7..471d1cbb 100644 --- a/CREDITS +++ b/CREDITS @@ -3,8 +3,8 @@ project. The list is sorted alphabetically, so please keep it this way! -Please let me know (email Anton Altaparmakov ) if you believe -someone is missing or if you prefer to not be listed. +Please contact if you believe someone is +missing or if you prefer not to be listed. Alexei Alexandrov diff --git a/autogen.sh b/autogen.sh index b4d0a559..150e902d 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Run this to generate all the initial makefiles, etc. +# Run this to generate configure, Makefile.in's, etc if test "$srcdir" == ""; then srcdir=. From 57d1067a22e08964fb44124676236fa9b95d8651 Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 27 Oct 2006 13:06:11 +0000 Subject: [PATCH 087/289] Oops, edited the wrong file. Add zhanglinbao to CREDITS for his big-endiness testing and fixes. Add my mail address. anti-spam changes (if it helps nowdays). Misc changes. (Yuval) --- CREDITS | 57 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/CREDITS b/CREDITS index 471d1cbb..3c6c6df1 100644 --- a/CREDITS +++ b/CREDITS @@ -6,34 +6,33 @@ The list is sorted alphabetically, so please keep it this way! Please contact if you believe someone is missing or if you prefer not to be listed. +Alexei Alexandrov +Anton Altaparmakov +Albert D. Cahalan +Russ Christensen +Pete Curran +Mario Emmenlauer +Andras Erdei +Matthew J. Fanto +Yuval Fledel +Marcin GibuÅ‚a +Christophe Grenier +Ian Jackson +Carmelo Kintana +Jan Kratochvil +Lode Leroy +David Martínez Moreno +Giang Nguyen +Leonard NorrgÃ¥rd +Holger Ohmacht +Per Olofsson +Yura Pakhuchiy +Yuri Per +Richard Russon +Erik Sørnes +Szabolcs Szakacsits +zhanglinbao -Alexei Alexandrov -Anton Altaparmakov -Albert D. Cahalan -Russ Christensen -Pete Curran -Mario Emmenlauer -Andras Erdei -Matthew J. Fanto -Yuval Fledel (no email address on request) -Marcin GibuÅ‚a -Christophe Grenier -Ian Jackson -Carmelo Kintana -Jan Kratochvil -Lode Leroy -David Martínez Moreno -Giang Nguyen -Leonard NorrgÃ¥rd -Holger Ohmacht -Per Olofsson -Yura Pakhuchiy -Yuri Per -Richard Russon -Erik Sørnes -Szabolcs Szakacsits - -Also, various code snippets and especially the autoconf/automake automated -configuration, compilation and installation system have been ripped shamelessly -from numerous different GNU and Gnome utilities and libraries so "Many thanks!" +Configuration, compilation and installation system are originally based on +numerous different GNU and Gnome utilities and libraries so "Many thanks!" to all the people who have participated in their creation! From b1583bdce6ce9103b92e113ef010ac1db6ed5432 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 27 Oct 2006 14:15:32 +0000 Subject: [PATCH 088/289] Fix several memleaks --- libntfs/dir.c | 2 ++ libntfs/volume.c | 1 + ntfsprogs/ntfsmount.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 87b60684..f54f79cb 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1261,6 +1261,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, ntfs_log_error("Failed to add INDEX_ROOT attribute.\n"); goto err_out; } + free(ir); } else { INTX_FILE *data; int data_len; @@ -1312,6 +1313,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, (u8*)data, data_len)) { err = errno; + free(data); ntfs_log_error("Failed to add DATA attribute.\n"); goto err_out; } diff --git a/libntfs/volume.c b/libntfs/volume.c index 3658016f..d899d2f0 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -220,6 +220,7 @@ mft_has_no_attr_list: std_info = ntfs_attr_readall(vol->mft_ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL); vol->mft_ni->flags = std_info->file_attributes; + free(std_info); /* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */ diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 4a4f6621..b5b60475 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1800,6 +1800,7 @@ int main(int argc, char *argv[]) /* Mount volume. */ if (ntfs_fuse_mount(opts.device)) { ntfs_fuse_destroy(); + free(parsed_options); return 4; } /* Create filesystem. */ @@ -1814,12 +1815,12 @@ int main(int argc, char *argv[]) #else ffd = fuse_mount(opts.mnt_point, parsed_options); #endif + free(parsed_options); if (ffd == -1) { ntfs_log_error("fuse_mount failed.\n"); ntfs_fuse_destroy(); return 5; } - free(parsed_options); #if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL); From ab3519cbcdc045d77945a45f937e8877e0fabe2e Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 27 Oct 2006 14:18:02 +0000 Subject: [PATCH 089/289] Always instantiate holes --- libntfs/attrib.c | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index e6b8f48f..814599e7 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1131,52 +1131,16 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) LCN lcn_seek_from = -1; runlist *rlc; VCN cur_vcn, from_vcn; - s64 t; - int cnt; if (rl->lcn != (LCN)LCN_HOLE) { errno = EIO; goto rl_err_out; } - /* - * It is a hole. Check if the data buffer is zero in - * this region and if not instantiate the hole. - */ + to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); - written = to_write / sizeof(unsigned long); - eo = 0; - for (t = 0; t < written; t++) { - if (((const unsigned long*)b)[t]) { - eo = 1; - break; - } - } - cnt = to_write & (sizeof(unsigned long) - 1); - if (cnt && !eo) { - int i; - const u8 *b2; - - b2 = (const u8*)b + (to_write & - ~(sizeof(unsigned long) - 1)); - for (i = 0; i < cnt; i++) { - if (b2[i]) { - eo = 1; - break; - } - } - } - if (!eo) { - /* - * The buffer region is zero, update progress - * counters and proceed with next run. - */ - total += to_write; - count -= to_write; - b = (const u8*)b + to_write; - continue; - } - /* The buffer is non zero, instantiate the hole. */ + + /* Instantiate the hole. */ cur_vcn = rl->vcn; from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits); ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n", From 11c38fa46defbce9b4c0ccdb3b9cda82e99aa0fc Mon Sep 17 00:00:00 2001 From: uvman Date: Fri, 27 Oct 2006 21:21:20 +0000 Subject: [PATCH 090/289] Anton is still the maintainer. --- AUTHORS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index dd8a1815..e7aae7e0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,6 +1,6 @@ -ntfsprogs is written and maintained by the Linux-NTFS project, you can contact -us at . +ntfsprogs is written by the Linux-NTFS project (www.linux-ntfs.org) and +maintained by Anton Altaparmakov . Current active project members are (in alphabetical order): From 08db1a719bc795c172132d63bc57edb4a7abb877 Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:06:49 +0000 Subject: [PATCH 091/289] Aid basic static code checkers to see that ctx can not be null in this code path. --- libntfs/attrib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 814599e7..dd01e49c 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1352,7 +1352,7 @@ err_out: err = 1; } else ntfs_attr_reinit_search_ctx(ctx); - if (!err) { + if (ctx) { err = ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, ctx); if (!err) { From 8fd26af3fb7192dcdaf7059f1715afa355b9f681 Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:08:24 +0000 Subject: [PATCH 092/289] Fix memleak. Remove dead code. --- libntfs/attrib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index dd01e49c..daf4fa3c 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -78,8 +78,6 @@ s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a) return sle64_to_cpu(a->data_size); else return (s64)le32_to_cpu(a->value_length); - errno = EINVAL; - return 0; } /** @@ -254,6 +252,7 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, errno = EIO; } #undef ESTR + free(rl); return 0; } total += r; From 2991c40d90f7f767b1e5143db1d61d35f4e4418f Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:11:25 +0000 Subject: [PATCH 093/289] Remove double-commenting. Why use C++-style comments for multilines anyway? --- include/ntfs/layout.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 39e4c934..db1c79d4 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -2352,18 +2352,18 @@ typedef struct { the index. */ } __attribute__((__packed__)) key; /* The (optional) index data is inserted here when creating. */ - // VCN vcn; /* If INDEX_ENTRY_NODE bit in flags is set, the last - // eight bytes of this index entry contain the virtual - // cluster number of the index block that holds the - // entries immediately preceding the current entry (the - // vcn references the corresponding cluster in the data - // of the non-resident index allocation attribute). If - // the key_length is zero, then the vcn immediately - // follows the INDEX_ENTRY_HEADER. Regardless of - // key_length, the address of the 8-byte boundary - // aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by - // (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN), - // where sizeof(VCN) can be hardcoded as 8 if wanted. */ + /* VCN vcn; */ /* If INDEX_ENTRY_NODE bit in flags is set, the last + eight bytes of this index entry contain the virtual + cluster number of the index block that holds the + entries immediately preceding the current entry (the + vcn references the corresponding cluster in the data + of the non-resident index allocation attribute). If + the key_length is zero, then the vcn immediately + follows the INDEX_ENTRY_HEADER. Regardless of + key_length, the address of the 8-byte boundary + aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by + (char*)ie + le16_to_cpu(ie->length) - sizeof(VCN), + where sizeof(VCN) can be hardcoded as 8 if wanted. */ } __attribute__((__packed__)) INDEX_ENTRY; /** From c59a3aedbdba830d241692f633f707b0fbcbed26 Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:15:44 +0000 Subject: [PATCH 094/289] memmove() already deals with overlap, is optimized, is ANSI C and only takes one line to call. --- libntfs/compress.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/libntfs/compress.c b/libntfs/compress.c index 62d1f7f2..e960af98 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -166,7 +166,7 @@ do_next_tag: tag = *cb++; /* Parse the eight tokens described by the tag. */ for (token = 0; token < 8; token++, tag >>= 1) { - u16 lg, pt, length, max_non_overlap; + u16 lg, pt, length; register u16 i; u8 *dest_back_addr; @@ -214,27 +214,8 @@ do_next_tag: /* Verify destination is in range. */ if (dest + length > dest_sb_end) goto return_overflow; - /* The number of non-overlapping bytes. */ - max_non_overlap = dest - dest_back_addr; - if (length <= max_non_overlap) { - /* The byte sequence doesn't overlap, just copy it. */ - memcpy(dest, dest_back_addr, length); - /* Advance destination pointer. */ - dest += length; - } else { - /* - * The byte sequence does overlap, copy non-overlapping - * part and then do a slow byte by byte copy for the - * overlapping part. Also, advance the destination - * pointer. - */ - memcpy(dest, dest_back_addr, max_non_overlap); - dest += max_non_overlap; - dest_back_addr += max_non_overlap; - length -= max_non_overlap; - while (length--) - *dest++ = *dest_back_addr++; - } + /* memmove() is safe with overlapping blocks. */ + memmove(dest, dest_back_addr, length); /* Advance source position and continue with the next token. */ cb += 2; } From f51136ac9de1c9bb7943939f0ed66813ad90c331 Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:35:56 +0000 Subject: [PATCH 095/289] Forgot to advance the dest buffer (shame on me) --- libntfs/compress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libntfs/compress.c b/libntfs/compress.c index e960af98..779c4944 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -216,6 +216,7 @@ do_next_tag: goto return_overflow; /* memmove() is safe with overlapping blocks. */ memmove(dest, dest_back_addr, length); + dest += length; /* Advance source position and continue with the next token. */ cb += 2; } From 5c4b9c1056f2313f145463794284dbd35eb73cec Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:40:11 +0000 Subject: [PATCH 096/289] C99 declarations before code fixes. --- libntfs/index.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index 0a5712f1..4dd1cd97 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -218,9 +218,11 @@ static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) { + INDEX_ENTRY *ie; + ntfs_log_trace("pos: %d\n", pos); - INDEX_ENTRY *ie = ntfs_ie_get_first(ih); + ie = ntfs_ie_get_first(ih); while (pos-- > 0) ie = ntfs_ie_get_next(ie); @@ -229,10 +231,12 @@ static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) { + INDEX_ENTRY *ie_prev, *tmp; + ntfs_log_trace("Entering.\n"); - INDEX_ENTRY *ie_prev = NULL; - INDEX_ENTRY *tmp = ntfs_ie_get_first(ih); + ie_prev = NULL; + tmp = ntfs_ie_get_first(ih); while (tmp != ie) { ie_prev = tmp; From 15eb2c38a6d7157d81fb3aeb4c30ba5f66097c5d Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:41:41 +0000 Subject: [PATCH 097/289] constify string argument. --- ntfsprogs/ntfsclone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 715915f0..08dc6ad2 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1312,8 +1312,8 @@ static void print_volume_size(const char *str, s64 bytes) } -static void print_disk_usage(char *spacer, u32 cluster_size, s64 nr_clusters, - s64 inuse) +static void print_disk_usage(const char *spacer, u32 cluster_size, + s64 nr_clusters, s64 inuse) { s64 total, used; From 87d87073c78c5ec5df473f1cca5bf124060d3472 Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:45:22 +0000 Subject: [PATCH 098/289] The periodic 'int is not neccessarily 32bit' fixes. --- include/ntfs/logging.h | 34 +++++++++++++++++----------------- libntfs/index.c | 7 ++++--- ntfsprogs/mkntfs.c | 16 ++++++++++------ ntfsprogs/ntfsinfo.c | 11 ++++++----- 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/include/ntfs/logging.h b/include/ntfs/logging.h index 0a66dbb3..982f90f2 100644 --- a/include/ntfs/logging.h +++ b/include/ntfs/logging.h @@ -65,25 +65,25 @@ int ntfs_log_redirect(const char *function, const char *file, int line, __attribute__((format(printf, 6, 7))); /* Logging levels - Determine what gets logged */ -#define NTFS_LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */ -#define NTFS_LOG_LEVEL_TRACE (1 << 1) /* Entering function x() */ -#define NTFS_LOG_LEVEL_QUIET (1 << 2) /* Quietable output */ -#define NTFS_LOG_LEVEL_INFO (1 << 3) /* Volume needs defragmenting */ -#define NTFS_LOG_LEVEL_VERBOSE (1 << 4) /* Forced to continue */ -#define NTFS_LOG_LEVEL_PROGRESS (1 << 5) /* 54% complete */ -#define NTFS_LOG_LEVEL_WARNING (1 << 6) /* You should backup before starting */ -#define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */ -#define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */ -#define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */ -#define NTFS_LOG_LEVEL_REASON (1 << 10) /* Human readable reason for failure */ +#define NTFS_LOG_LEVEL_DEBUG ((u32)1 << 0) /* x = 42 */ +#define NTFS_LOG_LEVEL_TRACE ((u32)1 << 1) /* Entering function x() */ +#define NTFS_LOG_LEVEL_QUIET ((u32)1 << 2) /* Quietable output */ +#define NTFS_LOG_LEVEL_INFO ((u32)1 << 3) /* Volume needs defragmenting */ +#define NTFS_LOG_LEVEL_VERBOSE ((u32)1 << 4) /* Forced to continue */ +#define NTFS_LOG_LEVEL_PROGRESS ((u32)1 << 5) /* 54% complete */ +#define NTFS_LOG_LEVEL_WARNING ((u32)1 << 6) /* You should backup before starting */ +#define NTFS_LOG_LEVEL_ERROR ((u32)1 << 7) /* Operation failed, no damage done */ +#define NTFS_LOG_LEVEL_PERROR ((u32)1 << 8) /* Message : standard error description */ +#define NTFS_LOG_LEVEL_CRITICAL ((u32)1 << 9) /* Operation failed,damage may have occurred */ +#define NTFS_LOG_LEVEL_REASON ((u32)1 << 10) /* Human readable reason for failure */ /* Logging style flags - Manage the style of the output */ -#define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */ -#define NTFS_LOG_FLAG_FILENAME (1 << 1) /* Show the file origin of the message */ -#define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */ -#define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */ -#define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */ -#define NTFS_LOG_FLAG_COLOUR (1 << 5) /* Colour highlight some messages */ +#define NTFS_LOG_FLAG_PREFIX ((u32)1 << 0) /* Prefix messages with "ERROR: ", etc */ +#define NTFS_LOG_FLAG_FILENAME ((u32)1 << 1) /* Show the file origin of the message */ +#define NTFS_LOG_FLAG_LINE ((u32)1 << 2) /* Show the line number of the message */ +#define NTFS_LOG_FLAG_FUNCTION ((u32)1 << 3) /* Show the function name containing the message */ +#define NTFS_LOG_FLAG_ONLYNAME ((u32)1 << 4) /* Only display the filename, not the pathname */ +#define NTFS_LOG_FLAG_COLOUR ((u32)1 << 5) /* Colour highlight some messages */ /* Macros to simplify logging. One for each level defined above. * Note, if NTFS_DISABLE_DEBUG_LOGGING is defined, then ntfs_log_debug/trace have no effect. diff --git a/libntfs/index.c b/libntfs/index.c index 4dd1cd97..8b301f31 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -398,7 +398,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " "has a size (%u) differing from the index " "specified size (%u)\n", (long long)vcn, - icx->ni->mft_no, ib_size, icx->block_size); + icx->ni->mft_no, (unsigned)ib_size, + (unsigned)icx->block_size); return -1; } return 0; @@ -656,8 +657,8 @@ int ntfs_index_lookup(const void *key, const int key_len, icx->block_size = le32_to_cpu(ir->index_block_size); if (icx->block_size < NTFS_BLOCK_SIZE) { errno = EINVAL; - ntfs_log_perror("Index block size (%d) is smaller than the " - "sector size (%d)", icx->block_size, + ntfs_log_perror("Index block size (%u) is smaller than the " + "sector size (%d)", (unsigned)icx->block_size, NTFS_BLOCK_SIZE); return -1; } diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 8212c27c..70904b2f 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -779,9 +779,12 @@ static void dump_resident_attr_val(ATTR_TYPES type, char *val, u32 val_len) return; case AT_INDEX_ROOT: /* TODO */ - printf("collation_rule %u\n", le32_to_cpu(((INDEX_ROOT*)val)->collation_rule)); - printf("index.entries_offset %u\n", le32_to_cpu(((INDEX_ROOT*)val)->index.entries_offset)); - printf("index.index_length %u\n", le32_to_cpu(((INDEX_ROOT*)val)->index.index_length)); + printf("collation_rule %u\n", (unsigned)le32_to_cpu + (((INDEX_ROOT*)val)->collation_rule)); + printf("index.entries_offset %u\n", (unsigned)le32_to_cpu + (((INDEX_ROOT*)val)->index.entries_offset)); + printf("index.index_length %u\n", (unsigned)le32_to_cpu + (((INDEX_ROOT*)val)->index.index_length)); printf("%s\n", todo); return; case AT_INDEX_ALLOCATION: @@ -3615,8 +3618,8 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) return FALSE; } } - ntfs_log_quiet("Cluster size has been automatically set to %d " - "bytes.\n", vol->cluster_size); + ntfs_log_quiet("Cluster size has been automatically set to %u " + "bytes.\n", (unsigned)vol->cluster_size); } /* Validate cluster size. */ if (vol->cluster_size & (vol->cluster_size - 1)) { @@ -3723,7 +3726,8 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) ntfs_log_warning("Index record size (%u bytes) exceeds system " "page size (%li bytes). You will not be able " "to mount this volume using the NTFS kernel " - "driver.\n", vol->indx_record_size, page_size); + "driver.\n", (unsigned)vol->indx_record_size, + page_size); vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; ntfs_log_debug("index record size = %u bytes\n", (unsigned)vol->indx_record_size); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 58fdc473..5e356694 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1106,7 +1106,8 @@ static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) SECURITY_DESCRIPTOR_RELATIVE *sd; ntfs_log_verbose("\n"); - ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", le32_to_cpu(sds->hash)); + ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", + (unsigned)le32_to_cpu(sds->hash)); ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", (unsigned)le32_to_cpu(sds->security_id), (unsigned)le32_to_cpu(sds->security_id)); @@ -1366,7 +1367,7 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) break; default: ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - le32_to_cpu(type)); + (unsigned)le32_to_cpu(type)); break; } } @@ -1415,7 +1416,7 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) (unsigned)le32_to_cpu(data->sdh.length), (unsigned)le32_to_cpu(data->sdh.length)); ntfs_log_verbose("\t\tUnknown (padding):\t 0x%08x\n", - le32_to_cpu(data->sdh.reserved_II)); + (unsigned)le32_to_cpu(data->sdh.reserved_II)); break; case INDEX_ATTR_OBJID_O: { OBJ_ID_INDEX_DATA *object_id_data; @@ -1925,8 +1926,8 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) if (ea->name_length == 11 && !strncmp((const char*)"SETFILEBITS", (const char*)ea->name, 11)) - printf("0%o\n", le32_to_cpu(*(le32*)(ea->value + - ea->name_length + 1))); + printf("0%o\n", (unsigned)le32_to_cpu(*(le32*) + (ea->value + ea->name_length + 1))); else printf("'%s'\n", ea->value + ea->name_length + 1); if (ea->next_entry_offset) From b8ecbf7b946f95e820340910de25c83623988c6a Mon Sep 17 00:00:00 2001 From: uvman Date: Sat, 28 Oct 2006 23:46:30 +0000 Subject: [PATCH 099/289] Spelling fix. --- include/ntfs/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index f4d7c771..89f07871 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -79,7 +79,7 @@ typedef sle64 leLSN; /* * Cygwin has a collision between our BOOL and 's - * As long as this file will be included after were fine. + * As long as this file will be included after we're fine. */ #ifndef _WINDEF_H /** From fe1405393f7da9bf10459230d3241767018dcb47 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 29 Oct 2006 00:01:17 +0000 Subject: [PATCH 100/289] Change ntfs_collate()'s signature to size_t's. Move ntfs_is_collation_rule_supported to the .c file and rewrite it to be shorter. --- include/ntfs/collate.h | 33 +++-------------------- libntfs/collate.c | 60 +++++++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 50 deletions(-) diff --git a/include/ntfs/collate.h b/include/ntfs/collate.h index 2191ba59..1c00ebd7 100644 --- a/include/ntfs/collate.h +++ b/include/ntfs/collate.h @@ -27,37 +27,12 @@ #include "types.h" #include "volume.h" -#define NTFS_COLLATION_ERROR -2 +#define NTFS_COLLATION_ERROR (-2) -/** - * ntfs_is_collation_rule_supported - - * @cr: - * - * Description... - * - * Returns: - */ -static inline BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr) -{ - int i; - - /* - * FIXME: At the moment we only support COLLATION_BINARY, - * COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return false - * for everything else. - */ - if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG && - cr != COLLATION_FILE_NAME) - return FALSE; - i = le32_to_cpu(cr); - if (((i >= 0) && (i <= 0x02)) || - ((i >= 0x10) && (i <= 0x13))) - return TRUE; - return FALSE; -} +extern BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr); extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr, - const void *data1, const int data1_len, - const void *data2, const int data2_len); + const void *data1, size_t data1_len, + const void *data2, size_t data2_len); #endif /* _NTFS_COLLATE_H */ diff --git a/libntfs/collate.c b/libntfs/collate.c index 2cab50f3..a63c405d 100644 --- a/libntfs/collate.c +++ b/libntfs/collate.c @@ -46,8 +46,8 @@ * Returns: */ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)), - const void *data1, const int data1_len, - const void *data2, const int data2_len) + const void *data1, size_t data1_len, + const void *data2, size_t data2_len) { int rc; @@ -76,8 +76,8 @@ static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)), * Returns: */ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)), - const void *data1, const int data1_len, - const void *data2, const int data2_len) + const void *data1, size_t data1_len, + const void *data2, size_t data2_len) { int rc; u32 d1, d2; @@ -114,8 +114,8 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)), * Returns: */ static int ntfs_collate_file_name(ntfs_volume *vol, - const void *data1, const int data1_len __attribute__((unused)), - const void *data2, const int data2_len __attribute__((unused))) + const void *data1, size_t data1_len __attribute__((unused)), + const void *data2, size_t data2_len __attribute__((unused))) { int rc; @@ -130,8 +130,8 @@ static int ntfs_collate_file_name(ntfs_volume *vol, return rc; } -typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, const int, - const void *, const int); +typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, size_t, + const void *, size_t); static ntfs_collate_func_t ntfs_do_collate0x0[3] = { ntfs_collate_binary, @@ -146,6 +146,31 @@ static ntfs_collate_func_t ntfs_do_collate0x1[4] = { NULL/*ntfs_collate_ntofs_ulongs*/, }; +/** + * ntfs_is_collation_rule_supported - Check if a collation rule is implemented. + * @cr: The to-be-checked collation rule + * + * Use this function to know if @cr is supported by libntfs. + * + * 7 collation rules are known to be supported by NTFS as defined + * in layout.h. However, libntfs only support 3 of them ATM. + * + * Return TRUE if @cr is supported. FALSE otherwise. + */ +BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr) +{ + return (cr == COLLATION_BINARY || cr == COLLATION_NTOFS_ULONG || + cr == COLLATION_FILE_NAME); + /* + * FIXME: At the moment we only support COLLATION_BINARY, + * COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME. + * The correct future implementation of this function should be: + * + * u32 i = le32_to_cpu(cr); + * return ((i <= 0x02) || ((i >= 0x10) && (i <= 0x13))); + */ +} + /** * ntfs_collate - collate two data items using a specified collation rule * @vol: ntfs volume to which the data items belong @@ -165,27 +190,20 @@ static ntfs_collate_func_t ntfs_do_collate0x1[4] = { * Return NTFS_COLLATION_ERROR if error occurred. */ int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr, - const void *data1, const int data1_len, - const void *data2, const int data2_len) + const void *data1, size_t data1_len, + const void *data2, size_t data2_len) { - int i; + u32 i; ntfs_log_trace("Entering.\n"); - if (!vol || !data1 || !data2 || data1_len < 0 || data2_len < 0) { + if (!vol || !data1 || !data2) { ntfs_log_error("Invalid arguments passed.\n"); return NTFS_COLLATION_ERROR; } - /* - * FIXME: At the moment we only support COLLATION_BINARY, - * COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return error - * for everything else. - */ - if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG && - cr != COLLATION_FILE_NAME) + + if (!ntfs_is_collation_rule_supported(cr)) goto err; i = le32_to_cpu(cr); - if (i < 0) - goto err; if (i <= 0x02) return ntfs_do_collate0x0[i](vol, data1, data1_len, data2, data2_len); From aa5ee310d023ea7687aa789de2b6f90aff443a22 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 29 Oct 2006 00:09:23 +0000 Subject: [PATCH 101/289] Changelog entries for non-trivial commits of the last hour. --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index f246d794..28774ef5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -56,6 +56,12 @@ xx/xx/2006 - x.xx.x - . conversion macros. (zhanglinbao, Yuval) - Spelling mistake fixes in debug logging strings. (Yuval) - Remove inline keywords from static non-one-liners. (Szaka, Yuval) + - Memory leak fixes. (Yura, Yuval) + - Use memmove() in compress.c for moving overlapping blocks instead + of copying bytes manually. (Yuval) + - Change ntfs_collate()'s signature to take size_t's. (Yuval) + - Move ntfs_is_collation_rule_supported() from collate.h to collate.c + and rewrite it to be clearer. (Yuval) 21/06/2006 - 1.13.1 - Various fixes. From 561cb42743a1345193ef0c2dbc66529b21a39095 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 29 Oct 2006 00:55:45 +0000 Subject: [PATCH 102/289] Move ntfs_index_entry_mark_dirty() from index.h to index.c. (Szaka) --- ChangeLog | 3 ++- include/ntfs/index.h | 22 +--------------------- libntfs/index.c | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 28774ef5..16e86185 100644 --- a/ChangeLog +++ b/ChangeLog @@ -54,7 +54,7 @@ xx/xx/2006 - x.xx.x - . - Fix GUID to string conversion. (Anton) - Fix some byte-order conversion for u32 variables that used le16 conversion macros. (zhanglinbao, Yuval) - - Spelling mistake fixes in debug logging strings. (Yuval) + - Spelling mistake fixes. (Yuval) - Remove inline keywords from static non-one-liners. (Szaka, Yuval) - Memory leak fixes. (Yura, Yuval) - Use memmove() in compress.c for moving overlapping blocks instead @@ -62,6 +62,7 @@ xx/xx/2006 - x.xx.x - . - Change ntfs_collate()'s signature to take size_t's. (Yuval) - Move ntfs_is_collation_rule_supported() from collate.h to collate.c and rewrite it to be clearer. (Yuval) + - Move ntfs_index_entry_mark_dirty() to index.c. (Szaka) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/index.h b/include/ntfs/index.h index 7de05e60..75e23e2a 100644 --- a/include/ntfs/index.h +++ b/include/ntfs/index.h @@ -126,26 +126,6 @@ extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie); extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie); extern void ntfs_ih_filename_dump(INDEX_HEADER *ih); -/** - * ntfs_index_entry_mark_dirty - mark an index entry dirty - * @ictx: ntfs index context describing the index entry - * - * Mark the index entry described by the index entry context @ictx dirty. - * - * If the index entry is in the index root attribute, simply mark the inode - * containing the index root attribute dirty. This ensures the mftrecord, and - * hence the index root attribute, will be written out to disk later. - * - * If the index entry is in an index block belonging to the index allocation - * attribute, set ib_dirty to TRUE, thus index block will be updated during - * ntfs_index_ctx_put. - */ -static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) -{ - if (ictx->is_in_root) - ntfs_inode_mark_dirty(ictx->actx->ntfs_ino); - else - ictx->ib_dirty = TRUE; -} +extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx); #endif /* _NTFS_INDEX_H */ diff --git a/libntfs/index.c b/libntfs/index.c index 8b301f31..90d2c5cd 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -46,6 +46,28 @@ #include "bitmap.h" #include "support.h" +/** + * ntfs_index_entry_mark_dirty - mark an index entry dirty + * @ictx: ntfs index context describing the index entry + * + * Mark the index entry described by the index entry context @ictx dirty. + * + * If the index entry is in the index root attribute, simply mark the inode + * containing the index root attribute dirty. This ensures the mftrecord, and + * hence the index root attribute, will be written out to disk later. + * + * If the index entry is in an index block belonging to the index allocation + * attribute, set ib_dirty to TRUE, thus index block will be updated during + * ntfs_index_ctx_put. + */ +void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) +{ + if (ictx->is_in_root) + ntfs_inode_mark_dirty(ictx->actx->ntfs_ino); + else + ictx->ib_dirty = TRUE; +} + static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn) { return vcn << icx->vcn_size_bits; From 036e748cb96ce7d763a684c546ce32f70a2b99fb Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 29 Oct 2006 08:59:21 +0000 Subject: [PATCH 103/289] I was assuming memmove() would copy byte by byte if it detects a smaller than word gap. Anton pointed out that it doesn't, glibc sources confirm, the C99 standard claims otherwise. Revert the compress.c patch as implementation is more important than specification. --- ChangeLog | 2 -- libntfs/compress.c | 26 ++++++++++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 16e86185..25261c40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,8 +57,6 @@ xx/xx/2006 - x.xx.x - . - Spelling mistake fixes. (Yuval) - Remove inline keywords from static non-one-liners. (Szaka, Yuval) - Memory leak fixes. (Yura, Yuval) - - Use memmove() in compress.c for moving overlapping blocks instead - of copying bytes manually. (Yuval) - Change ntfs_collate()'s signature to take size_t's. (Yuval) - Move ntfs_is_collation_rule_supported() from collate.h to collate.c and rewrite it to be clearer. (Yuval) diff --git a/libntfs/compress.c b/libntfs/compress.c index 779c4944..62d1f7f2 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -166,7 +166,7 @@ do_next_tag: tag = *cb++; /* Parse the eight tokens described by the tag. */ for (token = 0; token < 8; token++, tag >>= 1) { - u16 lg, pt, length; + u16 lg, pt, length, max_non_overlap; register u16 i; u8 *dest_back_addr; @@ -214,9 +214,27 @@ do_next_tag: /* Verify destination is in range. */ if (dest + length > dest_sb_end) goto return_overflow; - /* memmove() is safe with overlapping blocks. */ - memmove(dest, dest_back_addr, length); - dest += length; + /* The number of non-overlapping bytes. */ + max_non_overlap = dest - dest_back_addr; + if (length <= max_non_overlap) { + /* The byte sequence doesn't overlap, just copy it. */ + memcpy(dest, dest_back_addr, length); + /* Advance destination pointer. */ + dest += length; + } else { + /* + * The byte sequence does overlap, copy non-overlapping + * part and then do a slow byte by byte copy for the + * overlapping part. Also, advance the destination + * pointer. + */ + memcpy(dest, dest_back_addr, max_non_overlap); + dest += max_non_overlap; + dest_back_addr += max_non_overlap; + length -= max_non_overlap; + while (length--) + *dest++ = *dest_back_addr++; + } /* Advance source position and continue with the next token. */ cb += 2; } From 22108e36a1b420cf7e2a7eb506b39275dbc6664e Mon Sep 17 00:00:00 2001 From: uvman Date: Mon, 30 Oct 2006 13:29:45 +0000 Subject: [PATCH 104/289] More big-endiness fixes. (zhanglinbao, Yuval) --- ChangeLog | 3 +-- libntfs/index.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 25261c40..42d45149 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,8 +52,7 @@ xx/xx/2006 - x.xx.x - . - Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). (Hil) - Fix GUID to string conversion. (Anton) - - Fix some byte-order conversion for u32 variables that used le16 - conversion macros. (zhanglinbao, Yuval) + - Multiple big-endiness fixes. (zhanglinbao, Yuval) - Spelling mistake fixes. (Yuval) - Remove inline keywords from static non-one-liners. (Szaka, Yuval) - Memory leak fixes. (Yura, Yuval) diff --git a/libntfs/index.c b/libntfs/index.c index 90d2c5cd..e5b834bd 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -789,7 +789,7 @@ done: return 0; } -static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, int ib_size, +static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, INDEX_HEADER_FLAGS node_type) { INDEX_BLOCK *ib; @@ -985,8 +985,8 @@ static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) ntfs_log_trace("Entering.\n"); - ib = ntfs_ib_alloc(ib_vcn, ir->index_block_size, LEAF_NODE); - if (!ib) + if (!(ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), + LEAF_NODE))) return NULL; ies_start = (char *)ntfs_ie_get_first(&ir->index); From 3e3196133c160de42d928819d64a5f8ef9a6187b Mon Sep 17 00:00:00 2001 From: uvman Date: Mon, 30 Oct 2006 13:43:09 +0000 Subject: [PATCH 105/289] Avoid a memory leak on the error code path. --- libntfs/dir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index f54f79cb..e5a20e91 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1376,10 +1376,12 @@ err_out: ntfs_log_perror("Failed to open SD (0x50) attribute of " " inode 0x%llx. Run chkdsk.\n", (unsigned long long)ni->mft_no); - else if (ntfs_attr_rm(na)) + else if (ntfs_attr_rm(na)) { ntfs_log_perror("Failed to remove SD (0x50) attribute " "of inode 0x%llx. Run chkdsk.\n", (unsigned long long)ni->mft_no); + ntfs_attr_close(na); + } } if (rollback_data) { ntfs_attr *na; From f6d6db57db1f9614e2e1399fe63c68dc9d6f76a1 Mon Sep 17 00:00:00 2001 From: uvman Date: Mon, 30 Oct 2006 19:40:56 +0000 Subject: [PATCH 106/289] Fix wrong error logic that would lead to segfault when malloc fails. --- libntfs/index.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index e5b834bd..d38b074b 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -385,11 +385,11 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) size -= sizeof(VCN); dup = ntfs_malloc(size); - if (dup) + if (dup) { memcpy(dup, ie, size); - - dup->flags &= ~INDEX_ENTRY_NODE; - dup->length = size; + dup->flags &= ~INDEX_ENTRY_NODE; + dup->length = size; + } return dup; } From 1b1a135bbde73135a80b4a41056a588830e86e83 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 30 Oct 2006 23:23:40 +0000 Subject: [PATCH 107/289] one more endian bug in ntfsinfo --- ChangeLog | 2 +- ntfsprogs/ntfsinfo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42d45149..ff4743e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -192,7 +192,7 @@ xx/xx/2006 - x.xx.x - . - New APIs (dir.[ch]): ntfs_create_device() for Interix block and character devices creation. - ntfs_crate_symlink() for Interix symbolic links creation. (Yura) + ntfs_create_symlink() for Interix symbolic links creation. (Yura) - Teach ntfs_create() to create Interix FIFOs and sockets. (Yura) - Fix the -u option in ntfsundelete. Instead of a confusing optional parameter, there's a new option -i with a required parameter. (Rich) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 5e356694..8a0b46a9 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -904,7 +904,7 @@ static void ntfs_dump_acl(const char *prefix, ACL *acl) /* proceed to next ACE */ ace = (ACCESS_ALLOWED_ACE *)(((char *)ace) + - le32_to_cpu(ace->size)); + le16_to_cpu(ace->size)); } } From 483522ec1f66d5ea54944e2d68d9122d26b97be2 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 1 Nov 2006 12:31:11 +0000 Subject: [PATCH 108/289] Introduce misc.c - Proud home of functions with no other home, starting with ntfs_[mc]alloc. (Szaka) --- ChangeLog | 1 + include/ntfs/support.h | 25 ----------------- libntfs/Makefile.am | 1 + libntfs/misc.c | 63 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 libntfs/misc.c diff --git a/ChangeLog b/ChangeLog index ff4743e4..ba70d549 100644 --- a/ChangeLog +++ b/ChangeLog @@ -60,6 +60,7 @@ xx/xx/2006 - x.xx.x - . - Move ntfs_is_collation_rule_supported() from collate.h to collate.c and rewrite it to be clearer. (Yuval) - Move ntfs_index_entry_mark_dirty() to index.c. (Szaka) + - Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 10eab345..20644747 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -96,29 +96,4 @@ old_state; \ }) -/** - * ntfs_calloc, ntfs_malloc - * - * Return a pointer to the allocated memory or NULL if the request fails. - */ -static inline void *ntfs_calloc(size_t size) -{ - void *p; - - p = calloc(1, size); - if (!p) - ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); - return p; -} - -static inline void *ntfs_malloc(size_t size) -{ - void *p; - - p = malloc(size); - if (!p) - ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); - return p; -} - #endif /* defined _NTFS_SUPPORT_H */ diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index a4e25dbd..072719b8 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -52,6 +52,7 @@ libntfs_la_SOURCES = \ lcnalloc.c \ logfile.c \ logging.c \ + misc.c \ mft.c \ mst.c \ runlist.c \ diff --git a/libntfs/misc.c b/libntfs/misc.c new file mode 100644 index 00000000..b709d305 --- /dev/null +++ b/libntfs/misc.c @@ -0,0 +1,63 @@ +/** + * mft.c - Miscellaneous functions. Part of the Linux-NTFS project. + * + * Copyright (c) 2006 Szabolcs Szakacsits + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "support.h" +#include "logging.h" + +/** + * ntfs_calloc - A logging supported calloc(3) + * + * Return a pointer to the allocated memory or NULL if the request fails. + * Memory is initialized with zeros. + */ +void *ntfs_calloc(size_t size) +{ + void *p; + + p = calloc(1, size); + if (!p) + ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); + return p; +} + +/** + * ntfs_malloc - A logging supported malloc(3) + * + * Return a pointer to the allocated memory or NULL if the request fails. + * Memory is uninitialized. + */ +void *ntfs_malloc(size_t size) +{ + void *p; + + p = malloc(size); + if (!p) + ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); + return p; +} From 7d585a03277d9581a11821554d11d227b8815d9b Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 1 Nov 2006 13:30:40 +0000 Subject: [PATCH 109/289] Change callers of malloc() to ntfs_malloc() (Szaka). Fix compilition (Yuval). --- ChangeLog | 1 + include/ntfs/support.h | 4 ++++ libntfs/attrib.c | 33 +++++++++++--------------- libntfs/bitmap.c | 4 ++-- libntfs/compress.c | 6 +++-- libntfs/device.c | 2 +- libntfs/dir.c | 20 +++++----------- libntfs/inode.c | 4 ++-- libntfs/lcnalloc.c | 4 ++-- libntfs/logfile.c | 13 ++++------ libntfs/mft.c | 22 +++++++---------- libntfs/runlist.c | 14 +++++++---- libntfs/security.c | 4 ++-- libntfs/unistr.c | 8 +++---- libntfs/unix_io.c | 2 +- libntfs/volume.c | 54 ++++++++++++++++-------------------------- ntfsprogs/ntfsmount.c | 24 +++++++++---------- 17 files changed, 98 insertions(+), 121 deletions(-) diff --git a/ChangeLog b/ChangeLog index ba70d549..1b2fe665 100644 --- a/ChangeLog +++ b/ChangeLog @@ -61,6 +61,7 @@ xx/xx/2006 - x.xx.x - . and rewrite it to be clearer. (Yuval) - Move ntfs_index_entry_mark_dirty() to index.c. (Szaka) - Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka) + - Change malloc() calls to ntfs_malloc(). (Szaka) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/support.h b/include/ntfs/support.h index 20644747..dcd5de81 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -96,4 +96,8 @@ old_state; \ }) +/* Memory allocation with logging. */ +extern void *ntfs_calloc(size_t size); +extern void *ntfs_malloc(size_t size); + #endif /* defined _NTFS_SUPPORT_H */ diff --git a/libntfs/attrib.c b/libntfs/attrib.c index daf4fa3c..02aa3faa 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -56,6 +56,7 @@ #include "compress.h" #include "bitmap.h" #include "logging.h" +#include "support.h" ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') }; @@ -175,11 +176,10 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, * going to overflow in the same fashion. * Temporary fix: same as above. */ - intbuf = malloc(rl[i].length << vol->cluster_size_bits); + intbuf = ntfs_malloc(rl[i].length << + vol->cluster_size_bits); if (!intbuf) { int eo = errno; - ntfs_log_perror("Couldn't allocate memory for " - "internal buffer."); free(rl); errno = eo; return 0; @@ -1043,13 +1043,11 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) /* If write starts beyond initialized_size, zero the gap. */ if (pos > na->initialized_size) { char *buf; - int err; - buf = malloc(NTFS_BUF_SIZE); - if (!buf) { - ntfs_log_trace("Not enough memory.\n"); + buf = ntfs_malloc(NTFS_BUF_SIZE); + if (!buf) goto err_out; - } + memset(buf, 0, NTFS_BUF_SIZE); ofs = na->initialized_size; while (ofs < pos) { @@ -1057,7 +1055,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) written = ntfs_rl_pwrite(vol, na->rl, ofs, to_write, buf); if (written <= 0) { - err = errno; + int err = errno; ntfs_log_trace("Failed to zero space " "between initialized " "size and @pos.\n"); @@ -2294,7 +2292,7 @@ ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) errno = EINVAL; return NULL; } - ctx = malloc(sizeof(ntfs_attr_search_ctx)); + ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx)); if (ctx) ntfs_attr_init_search_ctx(ctx, ni, mrec); return ctx; @@ -4738,12 +4736,10 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) * sparse runs instead of real allocation of clusters. */ if (na->type == AT_DATA && vol->major_ver >= 3) { - rl = malloc(0x1000); - if (!rl) { - ntfs_log_trace("Not enough memory.\n"); - err = ENOMEM; + rl = ntfs_malloc(0x1000); + if (!rl) return -1; - } + rl[0].vcn = (na->allocated_size >> vol->cluster_size_bits); rl[0].lcn = LCN_HOLE; @@ -4983,11 +4979,10 @@ void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, ntfs_log_perror("ntfs_attr_open failed"); return NULL; } - data = malloc(na->data_size); - if (!data) { - ntfs_log_perror("malloc failed"); + data = ntfs_malloc(na->data_size); + if (!data) goto out; - } + size = ntfs_attr_pread(na, 0, na->data_size, data); if (size != na->data_size) { ntfs_log_perror("ntfs_attr_pread failed"); diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 6b1fc15a..57713c0b 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -78,10 +78,10 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, if (bufsize > 8192) bufsize = 8192; - /* Allocate memory. */ - buf = (u8*)malloc(bufsize); + buf = (u8*)ntfs_malloc(bufsize); if (!buf) return -1; + /* Depending on @value, zero or set all bits in the allocated buffer. */ memset(buf, value ? 0xff : 0, bufsize); diff --git a/libntfs/compress.c b/libntfs/compress.c index 62d1f7f2..ed04c3e8 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -375,12 +375,14 @@ s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b) cb_size = na->compression_block_size; cb_size_mask = cb_size - 1UL; cb_clusters = na->compression_block_clusters; + /* Need a temporary buffer for each loaded compression block. */ - cb = malloc(cb_size); + cb = ntfs_malloc(cb_size); if (!cb) return -1; + /* Need a temporary buffer for each uncompressed block. */ - dest = malloc(cb_size); + dest = ntfs_malloc(cb_size); if (!dest) { err = errno; free(cb); diff --git a/libntfs/device.c b/libntfs/device.c index b4af89a4..c732f8cc 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -111,7 +111,7 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state, return NULL; } - dev = (struct ntfs_device *)malloc(sizeof(struct ntfs_device)); + dev = (struct ntfs_device *)ntfs_malloc(sizeof(struct ntfs_device)); if (dev) { if (!(dev->d_name = strdup(name))) { int eo = errno; diff --git a/libntfs/dir.c b/libntfs/dir.c index e5a20e91..e8a6d177 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1270,12 +1270,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, case S_IFBLK: case S_IFCHR: data_len = offsetof(INTX_FILE, device_end); - data = malloc(data_len); + data = ntfs_malloc(data_len); if (!data) { err = errno; - ntfs_log_error("Not enough memory for " - "content of DATA " - "attribute.\n"); goto err_out; } data->major = cpu_to_le64(major(dev)); @@ -1288,12 +1285,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, case S_IFLNK: data_len = sizeof(INTX_FILE_TYPES) + target_len * sizeof(ntfschar); - data = malloc(data_len); + data = ntfs_malloc(data_len); if (!data) { err = errno; - ntfs_log_error("Not enough memory for " - "content of DATA " - "attribute.\n"); goto err_out; } data->magic = INTX_SYMBOLIC_LINK; @@ -1322,10 +1316,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, } /* Create FILE_NAME attribute. */ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); - fn = calloc(1, fn_len); + fn = ntfs_calloc(fn_len); if (!fn) { err = errno; - ntfs_log_error("Not enough memory.\n"); goto err_out; } fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, @@ -1711,16 +1704,15 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) if (!ni || !dir_ni || !name || !name_len || ni->mft_no == dir_ni->mft_no) { - err = errno; - ntfs_log_error("Invalid arguments.\n"); + err = EINVAL; + ntfs_log_perror("ntfs_link wrong arguments"); goto err_out; } /* Create FILE_NAME attribute. */ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); - fn = calloc(1, fn_len); + fn = ntfs_calloc(fn_len); if (!fn) { err = errno; - ntfs_log_error("Not enough memory.\n"); goto err_out; } fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, diff --git a/libntfs/inode.c b/libntfs/inode.c index 020cf1f2..87710354 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -180,7 +180,7 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) goto put_err_out; } ni->attr_list_size = l; - ni->attr_list = malloc(ni->attr_list_size); + ni->attr_list = ntfs_malloc(ni->attr_list_size); if (!ni->attr_list) goto put_err_out; l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list); @@ -393,7 +393,7 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) if (!(base_ni->nr_extents & 3)) { i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); - extent_nis = (ntfs_inode**)malloc(i); + extent_nis = (ntfs_inode**)ntfs_malloc(i); if (!extent_nis) goto err_out; if (base_ni->nr_extents) { diff --git a/libntfs/lcnalloc.c b/libntfs/lcnalloc.c index d8bc95eb..9fad9a80 100644 --- a/libntfs/lcnalloc.c +++ b/libntfs/lcnalloc.c @@ -122,7 +122,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, /* Return empty runlist if @count == 0 */ if (!count) { - rl = malloc(0x1000); + rl = ntfs_malloc(0x1000); if (!rl) return NULL; rl[0].vcn = start_vcn; @@ -132,7 +132,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, } /* Allocate memory. */ - buf = (u8*)malloc(8192); + buf = (u8*)ntfs_malloc(8192); if (!buf) return NULL; /* diff --git a/libntfs/logfile.c b/libntfs/logfile.c index a3bd1ab0..db179d77 100644 --- a/libntfs/logfile.c +++ b/libntfs/logfile.c @@ -371,12 +371,9 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na, * Allocate a buffer to store the whole restart page so we can multi * sector transfer deprotect it. */ - trp = malloc(le32_to_cpu(rp->system_page_size)); - if (!trp) { - ntfs_log_error("Failed to allocate memory for $LogFile " - "restart page buffer.\n"); + trp = ntfs_malloc(le32_to_cpu(rp->system_page_size)); + if (!trp) return ENOMEM; - } /* * Read the whole of the restart page into the buffer. If it fits * completely inside @rp, just copy it from there. Otherwise read it @@ -500,11 +497,9 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp) return FALSE; } /* Allocate memory for restart page. */ - kaddr = malloc(NTFS_BLOCK_SIZE); - if (!kaddr) { - ntfs_log_error("Not enough memory.\n"); + kaddr = ntfs_malloc(NTFS_BLOCK_SIZE); + if (!kaddr) return FALSE; - } /* * Read through the file looking for a restart page. Since the restart * page header is at the beginning of a page we only need to search at diff --git a/libntfs/mft.c b/libntfs/mft.c index 4c266b25..b2572d9b 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -158,7 +158,7 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, cnt = vol->mftmirr_size - m; if (cnt > count) cnt = count; - bmirr = malloc(cnt * vol->mft_record_size); + bmirr = ntfs_malloc(cnt * vol->mft_record_size); if (!bmirr) return -1; memcpy(bmirr, b, cnt * vol->mft_record_size); @@ -240,7 +240,7 @@ int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref, } m = *mrec; if (!m) { - m = (MFT_RECORD*)malloc(vol->mft_record_size); + m = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size); if (!m) return -1; } @@ -367,7 +367,7 @@ int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref) errno = EINVAL; return -1; } - m = malloc(vol->mft_record_size); + m = ntfs_calloc(vol->mft_record_size); if (!m) return -1; if (ntfs_mft_record_layout(vol, mref, m)) { @@ -459,9 +459,10 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni) } } pass_start = data_pos; - buf = (u8*)malloc(PAGE_SIZE); + buf = (u8*)ntfs_malloc(PAGE_SIZE); if (!buf) return -1; + ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, " "pass_end 0x%llx, data_pos 0x%llx.\n", pass, (long long)pass_start, (long long)pass_end, @@ -1368,12 +1369,10 @@ mft_rec_already_initialized: * is not zero as well as the update sequence number if it is not zero * or -1 (0xffff). */ - m = (MFT_RECORD*)malloc(vol->mft_record_size); - if (!m) { - ntfs_log_error("Failed to allocate buffer for mft " - "record.\n"); + m = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size); + if (!m) goto undo_mftbmp_alloc; - } + if (ntfs_mft_record_read(vol, bit, m)) { err = errno; ntfs_log_error("Failed to read mft record.\n"); @@ -1437,12 +1436,9 @@ mft_rec_already_initialized: int i; i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); - extent_nis = (ntfs_inode**)malloc(i); + extent_nis = (ntfs_inode**)ntfs_malloc(i); if (!extent_nis) { err = errno; - ntfs_log_error("Failed to allocate " - "buffer for extent inodes " - "array.\n"); free(m); free(ni); errno = err; diff --git a/libntfs/runlist.c b/libntfs/runlist.c index 31a21aea..709ae1bd 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -766,7 +766,8 @@ runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, /* Current position in runlist array. */ rlpos = 0; /* Allocate first 4kiB block and set current runlist size to 4kiB. */ - rl = malloc(rlsize = 0x1000); + rlsize = 0x1000; + rl = ntfs_malloc(rlsize); if (!rl) return NULL; /* Insert unmapped starting element if necessary. */ @@ -1824,7 +1825,10 @@ static runlist_element * test_rl_pure_src(BOOL contig, BOOL multi, int vcn, int else fudge = 999; - result = malloc(4096); + result = ntfs_malloc(4096); + if (!result) + return NULL; + if (multi) { MKRL(result+0, vcn + (0*len/4), fudge + vcn + 1000 + (0*len/4), len / 4) MKRL(result+1, vcn + (1*len/4), fudge + vcn + 1000 + (1*len/4), len / 4) @@ -2042,9 +2046,9 @@ static void test_rl_frag_combine(ntfs_volume *vol, ATTR_RECORD *attr1, ATTR_RECO static void test_rl_frag(char *test) { ntfs_volume vol; - ATTR_RECORD *attr1 = malloc(1024); - ATTR_RECORD *attr2 = malloc(1024); - ATTR_RECORD *attr3 = malloc(1024); + ATTR_RECORD *attr1 = ntfs_malloc(1024); + ATTR_RECORD *attr2 = ntfs_malloc(1024); + ATTR_RECORD *attr3 = ntfs_malloc(1024); if (!attr1 || !attr2 || !attr3) goto out; diff --git a/libntfs/security.c b/libntfs/security.c index 7496bc0e..55f123ff 100644 --- a/libntfs/security.c +++ b/libntfs/security.c @@ -85,7 +85,7 @@ char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str) } _guid_str = guid_str; if (!_guid_str) { - _guid_str = malloc(37); + _guid_str = ntfs_malloc(37); if (!_guid_str) return _guid_str; } @@ -201,7 +201,7 @@ char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size) cnt = ntfs_sid_to_mbs_size(sid); if (cnt < 0) return NULL; - s = malloc(cnt); + s = ntfs_malloc(cnt); if (!s) return s; sid_str = s; diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 0660351d..8ed054e9 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -299,7 +299,7 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen) u32 len; len = ntfs_ucsnlen(s, maxlen); - dst = malloc((len + 1) * sizeof(ntfschar)); + dst = ntfs_malloc((len + 1) * sizeof(ntfschar)); if (dst) { memcpy(dst, s, len * sizeof(ntfschar)); dst[len] = cpu_to_le16(L'\0'); @@ -419,7 +419,7 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, } if (!mbs) { mbs_len = (ins_len + 1) * MB_CUR_MAX; - mbs = (char*)malloc(mbs_len); + mbs = (char*)ntfs_malloc(mbs_len); if (!mbs) return -1; } @@ -436,7 +436,7 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, errno = ENAMETOOLONG; return -1; } - tc = (char*)malloc((mbs_len + 64) & ~63); + tc = (char*)ntfs_malloc((mbs_len + 64) & ~63); if (!tc) goto err_out; memcpy(tc, mbs, mbs_len); @@ -562,7 +562,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len) ins_len++; if (!ucs) { ucs_len = ins_len; - ucs = (ntfschar*)malloc(ucs_len * sizeof(ntfschar)); + ucs = (ntfschar*)ntfs_malloc(ucs_len * sizeof(ntfschar)); if (!ucs) return -1; } diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index 028b3779..4080147d 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -86,7 +86,7 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) errno = EBUSY; return -1; } - if (!(dev->d_private = malloc(sizeof(int)))) + if (!(dev->d_private = ntfs_malloc(sizeof(int)))) return -1; /* * Open the device/file obtaining the file descriptor for exclusive diff --git a/libntfs/volume.c b/libntfs/volume.c index d899d2f0..4930e73d 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -147,7 +147,7 @@ static int ntfs_mft_load(ntfs_volume *vol) /* Manually setup an ntfs_inode. */ vol->mft_ni = ntfs_inode_allocate(vol); - mb = (MFT_RECORD*)malloc(vol->mft_record_size); + mb = (MFT_RECORD*)ntfs_malloc(vol->mft_record_size); if (!vol->mft_ni || !mb) { ntfs_log_perror("Error allocating memory for $MFT"); goto error_exit; @@ -198,12 +198,10 @@ static int ntfs_mft_load(ntfs_volume *vol) goto io_error_exit; } vol->mft_ni->attr_list_size = l; - vol->mft_ni->attr_list = malloc(l); - if (!vol->mft_ni->attr_list) { - ntfs_log_debug("Error: failed to allocate buffer for attribute " - "list.\n"); + vol->mft_ni->attr_list = ntfs_malloc(l); + if (!vol->mft_ni->attr_list) goto error_exit; - } + l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list); if (!l) { ntfs_log_debug("Error: failed to get value of " @@ -421,20 +419,20 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) return NULL; } - /* Allocate the boot sector structure. */ - if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR)))) + if (!(bs = (NTFS_BOOT_SECTOR *)ntfs_malloc(sizeof(NTFS_BOOT_SECTOR)))) return NULL; + /* Allocate the volume structure. */ vol = ntfs_volume_alloc(); if (!vol) goto error_exit; /* Create the default upcase table. */ vol->upcase_len = 65536; - vol->upcase = (ntfschar*)malloc(vol->upcase_len * sizeof(ntfschar)); - if (!vol->upcase) { - ntfs_log_perror("Error allocating memory for upcase table."); + vol->upcase = (ntfschar*)ntfs_malloc(vol->upcase_len * + sizeof(ntfschar)); + if (!vol->upcase) goto error_exit; - } + ntfs_upcase_table_build(vol->upcase, vol->upcase_len * sizeof(ntfschar)); if (flags & MS_RDONLY) @@ -697,11 +695,9 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol) return -1; } - buf = malloc(NTFS_HIBERFILE_HEADER_SIZE); - if (!buf) { - ntfs_log_perror("Error allocating memory for hiberfile.sys header"); + buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE); + if (!buf) goto out; - } na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { @@ -790,12 +786,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) } /* Load data from $MFT and $MFTMirr and compare the contents. */ - m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); - m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); - if (!m || !m2) { - ntfs_log_perror("Failed to allocate memory"); + m = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); + m2 = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); + if (!m || !m2) goto error_exit; - } l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size, vol->mft_record_size, m); @@ -932,10 +926,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) vol->upcase_len = na->data_size >> 1; /* Throw away default table. */ free(vol->upcase); - vol->upcase = (ntfschar*)malloc(na->data_size); + vol->upcase = (ntfschar*)ntfs_malloc(na->data_size); if (!vol->upcase) { ntfs_log_debug(FAILED); - ntfs_log_debug("Not enough memory to load $UpCase.\n"); goto error_exit; } } @@ -1026,11 +1019,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) * Treat this the same way as if the attribute was present but * had zero length. */ - vol->vol_name = malloc(1); + vol->vol_name = ntfs_malloc(1); if (!vol->vol_name) { ntfs_log_debug(FAILED); - ntfs_log_debug("Error: Unable to allocate memory for volume " - "name!\n"); goto error_exit; } vol->vol_name[0] = '\0'; @@ -1057,11 +1048,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) "to current locale"); ntfs_log_debug("Forcing name into ASCII by replacing " "non-ASCII characters with underscores.\n"); - vol->vol_name = malloc(u + 1); + vol->vol_name = ntfs_malloc(u + 1); if (!vol->vol_name) { ntfs_log_debug(FAILED); - ntfs_log_debug("Error: Unable to allocate memory for " - "volume name!\n"); goto error_exit; } for (j = 0; j < (s32)u; j++) { @@ -1100,10 +1089,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) goto error_exit; } vol->attrdef_len = na->data_size; - vol->attrdef = (ATTR_DEF*)malloc(na->data_size); + vol->attrdef = (ATTR_DEF*)ntfs_malloc(na->data_size); if (!vol->attrdef) { ntfs_log_debug(FAILED); - ntfs_log_debug("Not enough memory to load $AttrDef.\n"); goto error_exit; } /* Read in the $DATA attribute value into the buffer. */ @@ -1303,10 +1291,10 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) FILE *f; int err = 0; - real_file = malloc(PATH_MAX + 1); + real_file = ntfs_malloc(PATH_MAX + 1); if (!real_file) return -1; - real_fsname = malloc(PATH_MAX + 1); + real_fsname = ntfs_malloc(PATH_MAX + 1); if (!real_fsname) { err = errno; goto exit; diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index b5b60475..88c38b81 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -67,6 +67,7 @@ #include "utils.h" #include "version.h" #include "ntfstime.h" +#include "misc.h" #ifndef PATH_MAX #define PATH_MAX 4096 @@ -148,7 +149,7 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) if (!(ctx->state & NF_FreeMFTOutdate)) return ctx->free_mft; - buf = malloc(vol->cluster_size); + buf = ntfs_malloc(vol->cluster_size); if (!buf) return -ENOMEM; while (1) { @@ -180,7 +181,7 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) if (!(ctx->state & NF_FreeClustersOutdate)) return ctx->free_clusters; - buf = malloc(vol->cluster_size); + buf = ntfs_malloc(vol->cluster_size); if (!buf) return -ENOMEM; while (1) { @@ -378,7 +379,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) !stream_name_len) { INTX_FILE *intx_file; - intx_file = malloc(na->data_size); + intx_file = ntfs_malloc(na->data_size); if (!intx_file) { res = -errno; ntfs_attr_close(na); @@ -474,7 +475,7 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) goto exit; } /* Receive file content. */ - intx_file = malloc(na->data_size); + intx_file = ntfs_malloc(na->data_size); if (!intx_file) { res = -errno; goto exit; @@ -1400,11 +1401,10 @@ static struct fuse_operations ntfs_fuse_oper = { static int ntfs_fuse_init(void) { - ctx = malloc(sizeof(ntfs_fuse_context_t)); - if (!ctx) { - ntfs_log_perror("malloc failed"); + ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t)); + if (!ctx) return -1; - } + *ctx = (ntfs_fuse_context_t) { .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .uid = geteuid(), @@ -1458,11 +1458,11 @@ static char *parse_mount_options(const char *org_options) * +1 for null-terminator. * +PATH_MAX for resolved by realpath() device name. */ - ret = malloc(strlen(def_opts) + strlen(org_options) + 9 + PATH_MAX); - if (!ret) { - ntfs_log_perror("malloc failed"); + ret = ntfs_malloc(strlen(def_opts) + strlen(org_options) + PATH_MAX + + 9); + if (!ret) return NULL; - } + *ret = 0; options = strdup(org_options); if (!options) { From 1598a68d67d94039a1944a3da773777546e72019 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 1 Nov 2006 14:05:09 +0000 Subject: [PATCH 110/289] Fix compilation on environments that one can not assign to "va_list args" (e.g. Debian Alpha). Do so by removing the unused log_reason code. Originally, Szaka asked FlatCap for it but never used it. I've asked Szaka if he is going to use it but he did not reply. I got an implicit answer in the form of ntfs-3g commit. Therefore, commit an updated version of the patch I've sent the Debian package maintainer. --- include/ntfs/logging.h | 2 -- libntfs/logging.c | 52 ++++-------------------------------------- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/include/ntfs/logging.h b/include/ntfs/logging.h index 982f90f2..d30d545c 100644 --- a/include/ntfs/logging.h +++ b/include/ntfs/logging.h @@ -75,7 +75,6 @@ int ntfs_log_redirect(const char *function, const char *file, int line, #define NTFS_LOG_LEVEL_ERROR ((u32)1 << 7) /* Operation failed, no damage done */ #define NTFS_LOG_LEVEL_PERROR ((u32)1 << 8) /* Message : standard error description */ #define NTFS_LOG_LEVEL_CRITICAL ((u32)1 << 9) /* Operation failed,damage may have occurred */ -#define NTFS_LOG_LEVEL_REASON ((u32)1 << 10) /* Human readable reason for failure */ /* Logging style flags - Manage the style of the output */ #define NTFS_LOG_FLAG_PREFIX ((u32)1 << 0) /* Prefix messages with "ERROR: ", etc */ @@ -96,7 +95,6 @@ int ntfs_log_redirect(const char *function, const char *file, int line, #define ntfs_log_quiet(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_QUIET,NULL,FORMAT,##ARGS) #define ntfs_log_verbose(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,FORMAT,##ARGS) #define ntfs_log_warning(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,FORMAT,##ARGS) -#define ntfs_log_reason(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_REASON,NULL,FORMAT,##ARGS) /* By default debug and trace messages are compiled into the program, * but not displayed. diff --git a/libntfs/logging.c b/libntfs/logging.c index 137aac9d..6e9a6f43 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -77,7 +77,7 @@ static struct ntfs_logging ntfs_log = { #endif NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | - NTFS_LOG_LEVEL_REASON | NTFS_LOG_LEVEL_PROGRESS, + NTFS_LOG_LEVEL_PROGRESS, NTFS_LOG_FLAG_ONLYNAME, #ifdef DEBUG ntfs_log_handler_outerr @@ -346,26 +346,9 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)), const char *file, __attribute__((unused)) int line, u32 level, void *data __attribute__((unused)), const char *format, va_list args) { - const int reason_size = 128; - static char *reason = NULL; int ret = 0; int olderr = errno; - if (level == NTFS_LOG_LEVEL_REASON) { - if (!reason) - reason = malloc(reason_size); - if (reason) { - memset(reason, 0, reason_size); - return vsnprintf(reason, reason_size, format, args); - } else { - /* Rather than call ourselves, just drop through */ - level = NTFS_LOG_LEVEL_PERROR; - format = "Couldn't create reason"; - args = NULL; - olderr = errno; - } - } - if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) && (strchr(file, PATH_SEP))) /* Abbreviate the filename */ file = strrchr(file, PATH_SEP) + 1; @@ -385,12 +368,8 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)), ret += vfprintf(stream, format, args); - if (level & NTFS_LOG_LEVEL_PERROR) { - if (reason) - ret += fprintf(stream, " : %s\n", reason); - else - ret += fprintf(stream, " : %s\n", strerror(olderr)); - } + if (level & NTFS_LOG_LEVEL_PERROR) + ret += fprintf(stream, ": %s\n", strerror(olderr)); #endif vsyslog(LOG_NOTICE, format, args); ret = 1; /* FIXME: caclulate how many bytes had been written. */ @@ -424,8 +403,6 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)), int ntfs_log_handler_fprintf(const char *function, const char *file, int line, u32 level, void *data, const char *format, va_list args) { - const int reason_size = 128; - static char *reason = NULL; int ret = 0; int olderr = errno; FILE *stream; @@ -436,21 +413,6 @@ int ntfs_log_handler_fprintf(const char *function, const char *file, return 0; /* If it's NULL, we can't do anything. */ stream = (FILE*)data; - if (level == NTFS_LOG_LEVEL_REASON) { - if (!reason) - reason = malloc(reason_size); - if (reason) { - memset(reason, 0, reason_size); - return vsnprintf(reason, reason_size, format, args); - } else { - /* Rather than call ourselves, just drop through */ - level = NTFS_LOG_LEVEL_PERROR; - format = "Couldn't create reason"; - args = NULL; - olderr = errno; - } - } - if (ntfs_log.flags & NTFS_LOG_FLAG_COLOUR) { /* Pick a colour determined by the log level */ switch (level) { @@ -500,12 +462,8 @@ int ntfs_log_handler_fprintf(const char *function, const char *file, ret += vfprintf(stream, format, args); - if (level & NTFS_LOG_LEVEL_PERROR) { - if (reason) - ret += fprintf(stream, " : %s\n", reason); - else - ret += fprintf(stream, " : %s\n", strerror(olderr)); - } + if (level & NTFS_LOG_LEVEL_PERROR) + ret += fprintf(stream, ": %s\n", strerror(olderr)); if (col_suffix) ret += fprintf(stream, col_suffix); From be6b5ce977d800b25ca7a9b70eb1da7a706440a2 Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 1 Nov 2006 20:20:18 +0000 Subject: [PATCH 111/289] Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka) --- ChangeLog | 1 + libntfs/attrib.c | 324 +++++++++++++++++++++++------------------------ 2 files changed, 161 insertions(+), 164 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b2fe665..6d3cdc6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,7 @@ xx/xx/2006 - x.xx.x - . - Move ntfs_index_entry_mark_dirty() to index.c. (Szaka) - Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka) - Change malloc() calls to ntfs_malloc(). (Szaka) + - Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 02aa3faa..8db56067 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -921,6 +921,154 @@ rl_err_out: return -1; } +static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, + runlist_element **rl, VCN *update_from) +{ + s64 to_write; + ntfs_volume *vol = na->ni->vol; + int eo, ret = -1; + runlist *rlc; + LCN lcn_seek_from = -1; + VCN cur_vcn, from_vcn; + + to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs); + + /* Instantiate the hole. */ + cur_vcn = (*rl)->vcn; + from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); + ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n", cur_vcn); + /* + * Map whole runlist to be able update mapping pairs + * later. + */ + if (ntfs_attr_map_whole_runlist(na)) + goto err_out; + /* + * Restore @*rl, it probably get lost during runlist + * mapping. + */ + *rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!*rl) { + ntfs_log_error("Failed to find run after mapping runlist. " + "Please report to %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + /* + * Search backwards to find the best lcn to start + * seek from. + */ + rlc = *rl; + while (rlc->vcn) { + rlc--; + if (rlc->lcn >= 0) { + lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn); + break; + } + } + if (lcn_seek_from == -1) { + /* Backwards search failed, search forwards. */ + rlc = *rl; + while (rlc->length) { + rlc++; + if (rlc->lcn >= 0) { + lcn_seek_from = rlc->lcn - + (rlc->vcn - from_vcn); + break; + } + } + } + /* Allocate clusters to instantiate the hole. */ + rlc = ntfs_cluster_alloc(vol, from_vcn, + ((*ofs + to_write - 1) >> + vol->cluster_size_bits) + 1 + + (*rl)->vcn - from_vcn, + lcn_seek_from, DATA_ZONE); + if (!rlc) { + ntfs_log_perror("Hole filling cluster allocation failed"); + goto err_out; + } + /* Merge runlists. */ + *rl = ntfs_runlists_merge(na->rl, rlc); + if (!*rl) { + eo = errno; + ntfs_log_trace("Failed to merge runlists.\n"); + if (ntfs_cluster_free_from_rl(vol, rlc)) { + ntfs_log_trace("Failed to free just " + "allocated clusters. Leaving " + "inconsistent metadata. " + "Run chkdsk\n"); + } + errno = eo; + goto err_out; + } + na->rl = *rl; + if (*update_from == -1) + *update_from = from_vcn; + *rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!*rl) { + /* + * It's definitely a BUG, if we failed to find @cur_vcn, because + * we missed it during instantiating of the hole. + */ + ntfs_log_error("BUG! Failed to find run after hole " + "instantiating. Please report to the %s.\n", + NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + /* If leaved part of the hole go to the next run. */ + if ((*rl)->lcn < 0) + (*rl)++; + /* Now LCN shoudn't be less than 0. */ + if ((*rl)->lcn < 0) { + ntfs_log_error("BUG! LCN is lesser than 0. " + "Please report to the %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + if (*ofs) { + /* + * Need to clear region between start of + * @cur_vcn cluster and @*ofs. + */ + char *buf; + + buf = ntfs_malloc(*ofs); + if (!buf) { + errno = ENOMEM; + goto err_out; + } + memset(buf, 0, *ofs); + if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << + vol->cluster_size_bits, *ofs, buf) < 0) { + eo = errno; + ntfs_log_perror("Failed to zero area"); + free(buf); + errno = eo; + goto err_out; + } + free(buf); + } + if ((*rl)->vcn < cur_vcn) { + /* + * Clusters that replaced hole are merged with + * previous run, so we need to update offset. + */ + *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits; + } + if ((*rl)->vcn > cur_vcn) { + /* + * We left part of the hole, so we need to update the offset. + */ + *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits; + } + + ret = 0; +err_out: + return ret; +} + /** * ntfs_attr_pwrite - positioned write to an ntfs attribute * @na: ntfs attribute to write to @@ -942,7 +1090,8 @@ rl_err_out: */ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) { - s64 written, to_write, ofs, total, old_initialized_size, old_data_size; + s64 written, to_write, ofs, old_initialized_size, old_data_size; + s64 total = 0; VCN update_from = -1; ntfs_volume *vol; ntfs_attr_search_ctx *ctx = NULL; @@ -951,8 +1100,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) struct { unsigned int undo_initialized_size : 1; unsigned int undo_data_size : 1; - unsigned int update_mapping_pairs : 1; - } need_to = { 0, 0, 0 }; + } need_to = { 0, 0 }; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos, @@ -1028,7 +1176,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) ntfs_attr_put_search_ctx(ctx); return count; } - total = 0; + /* Handle writes beyond initialized_size. */ if (pos + count > na->initialized_size) { if (ntfs_attr_map_whole_runlist(na)) @@ -1125,174 +1273,22 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) goto rl_err_out; } if (rl->lcn < (LCN)0) { - LCN lcn_seek_from = -1; - runlist *rlc; - VCN cur_vcn, from_vcn; - if (rl->lcn != (LCN)LCN_HOLE) { errno = EIO; goto rl_err_out; } - - to_write = min(count, (rl->length << - vol->cluster_size_bits) - ofs); - - /* Instantiate the hole. */ - cur_vcn = rl->vcn; - from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits); - ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n", - cur_vcn); - /* - * Map whole runlist to be able update mapping pairs - * later. - */ - if (ntfs_attr_map_whole_runlist(na)) - goto err_out; - /* - * Restore @rl, it probably get lost during runlist - * mapping. - */ - rl = ntfs_attr_find_vcn(na, cur_vcn); - if (!rl) { - ntfs_log_error("BUG! Failed to find run after " - "mapping whole runlist. Please " - "report to the %s.\n", - NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - /* - * Search backwards to find the best lcn to start - * seek from. - */ - rlc = rl; - while (rlc->vcn) { - rlc--; - if (rlc->lcn >= 0) { - lcn_seek_from = rlc->lcn + - (from_vcn - rlc->vcn); - break; - } - } - if (lcn_seek_from == -1) { - /* Backwards search failed, search forwards. */ - rlc = rl; - while (rlc->length) { - rlc++; - if (rlc->lcn >= 0) { - lcn_seek_from = rlc->lcn - - (rlc->vcn - from_vcn); - break; - } - } - } - /* Allocate clusters to instantiate the hole. */ - rlc = ntfs_cluster_alloc(vol, from_vcn, - ((ofs + to_write - 1) >> - vol->cluster_size_bits) + 1 + - rl->vcn - from_vcn, - lcn_seek_from, DATA_ZONE); - if (!rlc) { - eo = errno; - ntfs_log_trace("Failed to allocate clusters " - "for hole instantiating.\n"); - errno = eo; - goto err_out; - } - /* Merge runlists. */ - rl = ntfs_runlists_merge(na->rl, rlc); - if (!rl) { - eo = errno; - ntfs_log_trace("Failed to merge runlists.\n"); - if (ntfs_cluster_free_from_rl(vol, rlc)) { - ntfs_log_trace("Failed to free just " - "allocated clusters. Leaving " - "inconsistent metadata. " - "Run chkdsk\n"); - } - errno = eo; - goto err_out; - } - na->rl = rl; - need_to.update_mapping_pairs = 1; - if (update_from == -1) - update_from = from_vcn; - rl = ntfs_attr_find_vcn(na, cur_vcn); - if (!rl) { - /* - * It's definitely a BUG, if we failed to find - * @cur_vcn, because we missed it during - * instantiating of the hole. - */ - ntfs_log_error("BUG! Failed to find run after " - "instantiating. Please report " - "to the %s.\n", NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - /* If leaved part of the hole go to the next run. */ - if (rl->lcn < 0) - rl++; - /* Now LCN shoudn't be less than 0. */ - if (rl->lcn < 0) { - ntfs_log_error("BUG! LCN is lesser than 0. " - "Please report to the %s.\n", - NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - if (ofs) { - /* - * Need to clear region between start of - * @cur_vcn cluster and @ofs. - */ - char *buf; - buf = malloc(ofs); - if (!buf) { - ntfs_log_trace("Not enough memory to " - "allocate %lld " - "bytes.\n", ofs); - errno = ENOMEM; - goto err_out; - } - memset(buf, 0, ofs); - if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << - vol->cluster_size_bits, - ofs, buf) < 0) { - eo = errno; - ntfs_log_trace("Failed to zero " - "area.\n"); - free(buf); - errno = eo; - goto err_out; - } - free(buf); - } - if (rl->vcn < cur_vcn) { - /* - * Clusters that replaced hole are merged with - * previous run, so we need to update offset. - */ - ofs += (cur_vcn - rl->vcn) << - vol->cluster_size_bits; - } - if (rl->vcn > cur_vcn) { - /* - * We left part of the hole, so update we need - * to update offset - */ - ofs -= (rl->vcn - cur_vcn) << - vol->cluster_size_bits; - } + if (ntfs_attr_fill_hole(na, count, &ofs, &rl, + &update_from)) + goto err_out; } + /* It is a real lcn, write it to the volume. */ to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); retry: - ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx," - " ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn, - ofs); + ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " + "%lld.\n", to_write, rl->vcn, rl->lcn, ofs); if (!NVolReadOnly(vol)) written = ntfs_pwrite(vol->dev, (rl->lcn << vol->cluster_size_bits) + ofs, @@ -1317,7 +1313,7 @@ done: if (ctx) ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ - if (need_to.update_mapping_pairs) + if (update_from != -1) ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); /* Finally, return the number of bytes written. */ return total; @@ -1375,7 +1371,7 @@ err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ - if (need_to.update_mapping_pairs) + if (update_from != -1) ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); /* Restore original data_size if needed. */ if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) From 76fc32ed873b4c3c92a89a093d6eede43bfeb8fd Mon Sep 17 00:00:00 2001 From: uvman Date: Wed, 1 Nov 2006 22:37:31 +0000 Subject: [PATCH 112/289] Fix a memleak. (Szaka) --- libntfs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index e8a6d177..f96fb32d 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1594,7 +1594,7 @@ search: /* Remove FILE_NAME from index. */ if (ntfs_index_rm(ictx)) goto err_out; - ictx = NULL; + /* Remove FILE_NAME from inode. */ if (ntfs_attr_record_rm(actx)) goto err_out; From 116a467dc073c62b0946dfaccfb5104865acb0c7 Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 5 Nov 2006 14:42:46 +0000 Subject: [PATCH 113/289] * fix ntfsmount build * fix ntfsinfo output --- ntfsprogs/ntfsinfo.c | 3 ++- ntfsprogs/ntfsmount.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 8a0b46a9..41ba6304 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1794,7 +1794,8 @@ static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) if (entries != -1) { total_entries += entries; total_indx_blocks++; - printf("\tIndex entries:\t\t %d\n", entries); + ntfs_log_verbose("\tIndex entries:\t\t %d\n", + entries); } } tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 88c38b81..bcdd9b8d 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -67,7 +67,7 @@ #include "utils.h" #include "version.h" #include "ntfstime.h" -#include "misc.h" +#include "support.h" #ifndef PATH_MAX #define PATH_MAX 4096 From c65bacb25b91491490b98131f99fc859d02ab1b5 Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 5 Nov 2006 21:40:57 +0000 Subject: [PATCH 114/289] ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount lookup problem and allows to drop compatibility code. --- ChangeLog | 4 +++- configure.ac | 26 ++++---------------------- ntfsprogs/ntfsmount.c | 30 ------------------------------ 3 files changed, 7 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6d3cdc6b..49f8e2a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -52,7 +52,7 @@ xx/xx/2006 - x.xx.x - . - Allow ntfscp to create the destination file if it does not already exists by calling ntfs_create(). (Hil) - Fix GUID to string conversion. (Anton) - - Multiple big-endiness fixes. (zhanglinbao, Yuval) + - Multiple big-endianness fixes. (zhanglinbao, Yuval) - Spelling mistake fixes. (Yuval) - Remove inline keywords from static non-one-liners. (Szaka, Yuval) - Memory leak fixes. (Yura, Yuval) @@ -63,6 +63,8 @@ xx/xx/2006 - x.xx.x - . - Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka) - Change malloc() calls to ntfs_malloc(). (Szaka) - Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka) + - ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount + lookup problem and allows to drop compatibility code. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/configure.ac b/configure.ac index 0941bf39..2c743ae6 100644 --- a/configure.ac +++ b/configure.ac @@ -195,31 +195,13 @@ AM_CONDITIONAL(ENABLE_GNOME_VFS, $compile_gnome_vfs) # Autodetect whether to build FUSE module or not. compile_fuse_module=false if test "$enable_fuse_module" != "no"; then - case "$target_os" in - linux*) - PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.3.0, [ compile_fuse_module=true ], - if test "$enable_fuse_module" = "yes"; then - AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.3.0.]) - else - AC_MSG_WARN([ntfsmount requires FUSE version >= 2.3.0.]) - fi - );; - freebsd*) - PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.5.0, [ compile_fuse_module=true ], - if test "$enable_fuse_module" = "yes"; then - AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.5.0 under FreeBSD.]) - else - AC_MSG_WARN([ntfsmount requires FUSE version >= 2.5.0 under FreeBSD.]) - fi - );; - *) + PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.6.0, [ compile_fuse_module=true ], if test "$enable_fuse_module" = "yes"; then - AC_MSG_ERROR([ntfsmount can be built only under Linux and FreeBSD.]) + AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.6.0.]) else - AC_MSG_WARN([ntfsmount can be built only under Linux and FreeBSD.]) + AC_MSG_WARN([ntfsmount requires FUSE version >= 2.6.0.]) fi - ;; - esac + ) fi AM_CONDITIONAL(ENABLE_FUSE_MODULE, $compile_fuse_module) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index bcdd9b8d..9901202a 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -223,11 +223,7 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) * Returns 0 on success or -errno on error. */ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) struct statvfs *sfs) -#else - struct statfs *sfs) -#endif { long size; ntfs_volume *vol; @@ -237,9 +233,7 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), return -ENODEV; /* Optimal transfer block size. */ sfs->f_bsize = vol->cluster_size; -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) sfs->f_frsize = vol->cluster_size; -#endif /* * Total data blocks in file system in units of f_bsize and since * inodes are also stored in data blocs ($MFT is a file) this is just @@ -260,11 +254,7 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), size = 0; sfs->f_ffree = size; /* Maximum length of filenames. */ -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) sfs->f_namemax = NTFS_MAX_NAME_LEN; -#else - sfs->f_namelen = NTFS_MAX_NAME_LEN; -#endif return 0; } @@ -1774,9 +1764,7 @@ static int parse_options(int argc, char *argv[]) int main(int argc, char *argv[]) { char *parsed_options; -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); -#endif struct fuse *fh; int ffd = 0; @@ -1804,7 +1792,6 @@ int main(int argc, char *argv[]) return 4; } /* Create filesystem. */ -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) if ((fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1 || fuse_opt_add_arg(&margs, parsed_options) == -1)) @@ -1812,16 +1799,12 @@ int main(int argc, char *argv[]) if (ffd != -1) ffd = fuse_mount(opts.mnt_point, &margs); fuse_opt_free_args(&margs); -#else - ffd = fuse_mount(opts.mnt_point, parsed_options); -#endif free(parsed_options); if (ffd == -1) { ntfs_log_error("fuse_mount failed.\n"); ntfs_fuse_destroy(); return 5; } -#if defined(FUSE_VERSION) && (FUSE_VERSION >= 25) fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL); if (fuse_opt_add_arg(&margs, "") == -1 || @@ -1838,19 +1821,6 @@ int main(int argc, char *argv[]) fh = fuse_new(ffd, &margs , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper)); fuse_opt_free_args(&margs); -#else - if (!ctx->debug && !ctx->no_detach) { - if (fuse_is_lib_option("kernel_cache")) - fh = fuse_new(ffd, "use_ino,kernel_cache", - &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper)); - else - fh = fuse_new(ffd, "use_ino", &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper)); - } else - fh = fuse_new(ffd, "debug,use_ino" , &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper)); -#endif if (!fh) { ntfs_log_error("fuse_new failed.\n"); close(ffd); From 45e3b4acd0a07136b1fdbaad9c18c5662f741d45 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 6 Nov 2006 12:51:44 +0000 Subject: [PATCH 115/289] upgrade to FUSE 2.6 API --- ntfsprogs/Makefile.am | 2 +- ntfsprogs/ntfsmount.c | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 5dbfb972..680bf860 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -88,7 +88,7 @@ if ENABLE_FUSE_MODULE ntfsmount_SOURCES = ntfsmount.c utils.c utils.h ntfsmount_LDADD = $(AM_LIBS) $(FUSE_MODULE_LIBS) ntfsmount_LDFLAGS = $(AM_LFLAGS) -ntfsmount_CFLAGS = $(FUSE_MODULE_CFLAGS) -DFUSE_USE_VERSION=25 +ntfsmount_CFLAGS = $(FUSE_MODULE_CFLAGS) -DFUSE_USE_VERSION=26 endif ntfscmp_SOURCES = ntfscmp.c utils.c utils.h diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 9901202a..5aefa6a5 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1766,7 +1766,7 @@ int main(int argc, char *argv[]) char *parsed_options; struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); struct fuse *fh; - int ffd = 0; + struct fuse_chan *fch; utils_set_locale(); ntfs_log_set_handler(ntfs_log_handler_stderr); @@ -1792,15 +1792,14 @@ int main(int argc, char *argv[]) return 4; } /* Create filesystem. */ - if ((fuse_opt_add_arg(&margs, "") == -1 || + fch = NULL; + if (!(fuse_opt_add_arg(&margs, "") == -1 || fuse_opt_add_arg(&margs, "-o") == -1 || - fuse_opt_add_arg(&margs, parsed_options) == -1)) - ffd = -1; - if (ffd != -1) - ffd = fuse_mount(opts.mnt_point, &margs); + fuse_opt_add_arg(&margs, parsed_options))) + fch = fuse_mount(opts.mnt_point, &margs); fuse_opt_free_args(&margs); free(parsed_options); - if (ffd == -1) { + if (!fch) { ntfs_log_error("fuse_mount failed.\n"); ntfs_fuse_destroy(); return 5; @@ -1818,13 +1817,12 @@ int main(int argc, char *argv[]) fh = NULL; } if (fh) - fh = fuse_new(ffd, &margs , &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper)); + fh = fuse_new(fch, &margs , &ntfs_fuse_oper, + sizeof(ntfs_fuse_oper), NULL); fuse_opt_free_args(&margs); if (!fh) { ntfs_log_error("fuse_new failed.\n"); - close(ffd); - fuse_unmount(opts.mnt_point); + fuse_unmount(opts.mnt_point, fch); ntfs_fuse_destroy(); return 6; } @@ -1846,9 +1844,8 @@ int main(int argc, char *argv[]) /* Main loop. */ fuse_loop(fh); /* Destroy. */ + fuse_unmount(opts.mnt_point, fch); fuse_destroy(fh); - close(ffd); - fuse_unmount(opts.mnt_point); ntfs_fuse_destroy(); return 0; } From d556675a2924a4ba55014d48d813c593c31f7596 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 6 Nov 2006 17:11:02 +0000 Subject: [PATCH 116/289] Fix typo and build with disabled error handling --- libntfs/mft.c | 2 -- libntfs/misc.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libntfs/mft.c b/libntfs/mft.c index b2572d9b..67b720e9 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -386,9 +386,7 @@ int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref) return 0; } -#ifndef NTFS_DISABLE_DEBUG_LOGGING static const char *es = " Leaving inconsistent metadata. Run chkdsk."; -#endif /** * ntfs_ffz - Find the first unset (zero) bit in a word diff --git a/libntfs/misc.c b/libntfs/misc.c index b709d305..5cdf2da4 100644 --- a/libntfs/misc.c +++ b/libntfs/misc.c @@ -1,5 +1,5 @@ /** - * mft.c - Miscellaneous functions. Part of the Linux-NTFS project. + * misc.c - Miscellaneous functions. Part of the Linux-NTFS project. * * Copyright (c) 2006 Szabolcs Szakacsits * From 025f07a26927bd3673172d46cba9d9efe8cb59d3 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 7 Nov 2006 10:37:25 +0000 Subject: [PATCH 117/289] Make a little nicer. --- libntfs/attrib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 8db56067..21c89db6 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -77,8 +77,7 @@ s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a) errno = 0; if (a->non_resident) return sle64_to_cpu(a->data_size); - else - return (s64)le32_to_cpu(a->value_length); + return (s64)le32_to_cpu(a->value_length); } /** From f2e1ff96d21d7a91ec443ca72e1385de80103731 Mon Sep 17 00:00:00 2001 From: yura Date: Thu, 9 Nov 2006 21:19:11 +0000 Subject: [PATCH 118/289] Spent really a lot of time applying various "optimizations" from ntfs-3g and finally figured out that ntfs-3g is faster than ntfsmount only because of 3 reasons: 1) turned on noatime option by default 2) ntfs-3g builds without debug output by default 3) the only real optimization: almost always add resident attributes. However by accident patch in ntfs-3g for 3) breaks several code paths (why I am not surprised?), thus I rewrote whole ntfs_attr_add() logic. --- .cvsignore | 1 + ChangeLog | 1 + include/ntfs/support.h | 6 +-- libntfs/attrib.c | 85 ++++++++++++++++++++++++++---------------- libntfs/inode.c | 13 ++++--- 5 files changed, 66 insertions(+), 40 deletions(-) diff --git a/.cvsignore b/.cvsignore index acc1a924..2474e039 100644 --- a/.cvsignore +++ b/.cvsignore @@ -22,3 +22,4 @@ stamp-h.in ltconfig missing INSTALL +cscope.out diff --git a/ChangeLog b/ChangeLog index 49f8e2a9..3077b4e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -65,6 +65,7 @@ xx/xx/2006 - x.xx.x - . - Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka) - ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount lookup problem and allows to drop compatibility code. (Yura) + - Rewrite ntfs_attr_add() algorithm. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/support.h b/include/ntfs/support.h index dcd5de81..57725ff0 100644 --- a/include/ntfs/support.h +++ b/include/ntfs/support.h @@ -71,9 +71,9 @@ /* * Round up and down @num to 2 in power of @order. */ -#define ROUND_UP(num,order) (((num) + ((1 << order) - 1)) & \ - ~((1 << order) - 1)) -#define ROUND_DOWN(num,order) ((num) & ~((1 << order) - 1)) +#define ROUND_UP(num,order) (((num) + ((1 << (order)) - 1)) & \ + ~((1 << (order)) - 1)) +#define ROUND_DOWN(num,order) ((num) & ~((1 << (order)) - 1)) /* * Simple bit operation macros. NOTE: These are NOT atomic. diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 21c89db6..a0b7d812 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -2946,7 +2946,8 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, { u32 attr_rec_size; int err, i, offset; - BOOL is_resident; + BOOL is_resident = TRUE; + BOOL always_non_resident = FALSE, always_resident = FALSE; ntfs_inode *attr_ni; ntfs_attr *na; @@ -2993,38 +2994,29 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, errno = ERANGE; return -1; } + always_resident = TRUE; } - /* - * Determine resident or not will be new attribute. We add 8 to size in - * non resident case for mapping pairs. - */ - if (!ntfs_attr_can_be_resident(ni->vol, type)) { - /* Attribute can be resident. */ - is_resident = TRUE; - /* Check if it is better to make attribute non resident. */ - if (!ntfs_attr_can_be_non_resident(ni->vol, type) && - offsetof(ATTR_RECORD, resident_end) + size >= - offsetof(ATTR_RECORD, non_resident_end) + 8) - /* Make it non resident. */ - is_resident = FALSE; - } else { + /* Check whether attribute can be resident. */ + if (ntfs_attr_can_be_resident(ni->vol, type)) { if (errno != EPERM) { err = errno; - ntfs_log_trace("ntfs_attr_can_be_resident failed.\n"); + ntfs_log_trace("ntfs_attr_can_be_resident() failed.\n"); goto err_out; } - /* Attribute can't be resident. */ is_resident = FALSE; + always_non_resident = TRUE; } + +retry: /* Calculate attribute record size. */ if (is_resident) attr_rec_size = offsetof(ATTR_RECORD, resident_end) + - ((name_len * sizeof(ntfschar) + 7) & ~7) + - ((size + 7) & ~7); - else + ROUND_UP(name_len * sizeof(ntfschar), 3) + + ROUND_UP(size, 3); + else /* We add 8 for space for mapping pairs. */ attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) + - ((name_len * sizeof(ntfschar) + 7) & ~7) + 8; + ROUND_UP(name_len * sizeof(ntfschar), 3) + 8; /* * If we have enough free space for the new attribute in the base MFT @@ -3050,6 +3042,20 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, goto add_attr_record; } + /* + * If failed to find space for resident attribute, then try to find + * space for non resident one. + */ + if (is_resident && !always_resident) { + is_resident = FALSE; + goto retry; + } + + /* + * FIXME: Try to make other attributes non-resident here. Factor out + * code from ntfs_resident_attr_resize. + */ + /* There is no extent that contain enough space for new attribute. */ if (!NInoAttrList(ni)) { /* Add attribute list not present, add it and retry. */ @@ -3060,7 +3066,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, } return ntfs_attr_add(ni, type, name, name_len, val, size); } - /* Allocate new extent. */ + /* Allocate new extent for attribute. */ attr_ni = ntfs_mft_record_alloc(ni->vol, ni); if (!attr_ni) { err = errno; @@ -3068,6 +3074,21 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, goto err_out; } + /* + * Determine resident or not will be attribute using heuristics and + * calculate attribute record size. FIXME: small code duplication here. + */ + if (always_resident || (!always_non_resident && size < 256)) { + is_resident = TRUE; + attr_rec_size = offsetof(ATTR_RECORD, resident_end) + + ROUND_UP(name_len * sizeof(ntfschar), 3) + + ROUND_UP(size, 3); + } else { /* We add 8 for space for mapping pairs. */ + is_resident = FALSE; + attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) + + ROUND_UP(name_len * sizeof(ntfschar), 3) + 8; + } + add_attr_record: if (is_resident) { /* Add resident attribute. */ @@ -3698,14 +3719,14 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { err = errno; if (err == ERANGE) { - ntfs_log_trace("Eeek! Size bounds check failed. " + ntfs_log_trace("Size bounds check failed. " "Aborting...\n"); } else if (err == ENOENT) err = EIO; goto put_err_out; } /* - * If @newsize is bigger than the mft record we need to make the + * If @newsize is bigger than the MFT record we need to make the * attribute non-resident if the attribute type supports it. If it is * smaller we can go ahead and attempt the resize. */ @@ -3715,7 +3736,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) newsize)) { /* Update attribute size everywhere. */ na->data_size = na->initialized_size = newsize; - na->allocated_size = (newsize + 7) & ~7; + na->allocated_size = ROUND_UP(newsize, 3); if (NAttrCompressed(na) || NAttrSparse(na)) na->compressed_size = na->allocated_size; if (na->type == AT_DATA && na->name == AT_UNNAMED) { @@ -3728,12 +3749,12 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) /* Error! If not enough space, just continue. */ if (errno != ENOSPC) { err = errno; - ntfs_log_trace("Eeek! Failed to resize resident part " + ntfs_log_trace("Failed to resize resident part " "of attribute. Aborting...\n"); goto put_err_out; } } - /* There is not enough space in the mft record to perform the resize. */ + /* There is not enough space in the MFT record to perform the resize. */ /* Make the attribute non-resident if possible. */ if (!ntfs_attr_make_non_resident(na, ctx)) { @@ -3743,7 +3764,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) return ntfs_attr_truncate(na, newsize); } else if (errno != ENOSPC && errno != EPERM) { err = errno; - ntfs_log_trace("Eeek! Failed to make attribute non-resident. " + ntfs_log_trace("Failed to make attribute non-resident. " "Aborting...\n"); goto put_err_out; } @@ -3763,8 +3784,8 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) * pairs will take 8 bytes. */ if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD, - compressed_size) + ((a->name_length * - sizeof(ntfschar) + 7) & ~7) + 8) + compressed_size) + ROUND_UP(a->name_length * + sizeof(ntfschar), 3) + 8) continue; tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a + @@ -3804,7 +3825,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) } /* - * Move the attribute to a new mft record, creating an attribute list + * Move the attribute to a new MFT record, creating an attribute list * attribute or modifying it if it is already present. */ @@ -3855,7 +3876,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) return -1; return ntfs_resident_attr_resize(na, newsize); } - /* Allocate new mft record. */ + /* Allocate new MFT record. */ ni = ntfs_mft_record_alloc(vol, ni); if (!ni) { err = errno; diff --git a/libntfs/inode.c b/libntfs/inode.c index 87710354..1f96c982 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -354,7 +354,8 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) errno = EINVAL; return NULL; } - ntfs_log_trace("Opening extent inode 0x%llx (base mft record 0x%llx).\n", + ntfs_log_trace("Opening extent inode 0x%llx " + "(base MFT record 0x%llx).\n", (unsigned long long)mft_no, (unsigned long long)base_ni->mft_no); /* Is the extent inode already open and attached to the base inode? */ @@ -370,8 +371,9 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) seq_no = MSEQNO_LE(mref); if (seq_no && seq_no != le16_to_cpu( ni->mrec->sequence_number)) { - ntfs_log_debug("Found stale extent mft reference! " - "Corrupt file system. Run chkdsk.\n"); + ntfs_log_debug("Found stale extent mft " + "reference! Corrupt file " + "system. Run chkdsk.\n"); errno = EIO; return NULL; } @@ -440,7 +442,7 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni) return 0; if (!ni->attr_list) { - ntfs_log_trace("Corrupt in-memory struct.\n"); + ntfs_log_trace("Corrupted in-memory structure.\n"); errno = EINVAL; return -1; } @@ -453,7 +455,8 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni) prev_attached != MREF_LE(ale->mft_reference)) { if (!ntfs_extent_inode_open(ni, MREF_LE(ale->mft_reference))) { - ntfs_log_trace("Couldn't attach extent inode.\n"); + ntfs_log_trace("Couldn't attach extent " + "inode.\n"); return -1; } prev_attached = MREF_LE(ale->mft_reference); From 28f24fbc2ce0968c4f3484b6eecad27758ca66bc Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 10 Nov 2006 16:07:45 +0000 Subject: [PATCH 119/289] revert factoring out ntfs_attr_fill_hole(), agree that it should be refactored, but passing all args as pointers and changing them there (especially update_from that changes only inside new function, but rollback depends on it in pwrite) --- ChangeLog | 1 - libntfs/attrib.c | 324 ++++++++++++++++++++++++----------------------- 2 files changed, 164 insertions(+), 161 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3077b4e8..765e5efa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,7 +62,6 @@ xx/xx/2006 - x.xx.x - . - Move ntfs_index_entry_mark_dirty() to index.c. (Szaka) - Introduce misc.c. Move ntfs_[mc]alloc there. (Szaka) - Change malloc() calls to ntfs_malloc(). (Szaka) - - Factor ntfs_attr_fill_hole() out of ntfs_attr_pwrite(). (Szaka) - ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount lookup problem and allows to drop compatibility code. (Yura) - Rewrite ntfs_attr_add() algorithm. (Yura) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index a0b7d812..0ac4bd8f 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -920,154 +920,6 @@ rl_err_out: return -1; } -static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, - runlist_element **rl, VCN *update_from) -{ - s64 to_write; - ntfs_volume *vol = na->ni->vol; - int eo, ret = -1; - runlist *rlc; - LCN lcn_seek_from = -1; - VCN cur_vcn, from_vcn; - - to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs); - - /* Instantiate the hole. */ - cur_vcn = (*rl)->vcn; - from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); - ntfs_log_trace("Instantiate the hole with vcn 0x%llx.\n", cur_vcn); - /* - * Map whole runlist to be able update mapping pairs - * later. - */ - if (ntfs_attr_map_whole_runlist(na)) - goto err_out; - /* - * Restore @*rl, it probably get lost during runlist - * mapping. - */ - *rl = ntfs_attr_find_vcn(na, cur_vcn); - if (!*rl) { - ntfs_log_error("Failed to find run after mapping runlist. " - "Please report to %s.\n", NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - /* - * Search backwards to find the best lcn to start - * seek from. - */ - rlc = *rl; - while (rlc->vcn) { - rlc--; - if (rlc->lcn >= 0) { - lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn); - break; - } - } - if (lcn_seek_from == -1) { - /* Backwards search failed, search forwards. */ - rlc = *rl; - while (rlc->length) { - rlc++; - if (rlc->lcn >= 0) { - lcn_seek_from = rlc->lcn - - (rlc->vcn - from_vcn); - break; - } - } - } - /* Allocate clusters to instantiate the hole. */ - rlc = ntfs_cluster_alloc(vol, from_vcn, - ((*ofs + to_write - 1) >> - vol->cluster_size_bits) + 1 + - (*rl)->vcn - from_vcn, - lcn_seek_from, DATA_ZONE); - if (!rlc) { - ntfs_log_perror("Hole filling cluster allocation failed"); - goto err_out; - } - /* Merge runlists. */ - *rl = ntfs_runlists_merge(na->rl, rlc); - if (!*rl) { - eo = errno; - ntfs_log_trace("Failed to merge runlists.\n"); - if (ntfs_cluster_free_from_rl(vol, rlc)) { - ntfs_log_trace("Failed to free just " - "allocated clusters. Leaving " - "inconsistent metadata. " - "Run chkdsk\n"); - } - errno = eo; - goto err_out; - } - na->rl = *rl; - if (*update_from == -1) - *update_from = from_vcn; - *rl = ntfs_attr_find_vcn(na, cur_vcn); - if (!*rl) { - /* - * It's definitely a BUG, if we failed to find @cur_vcn, because - * we missed it during instantiating of the hole. - */ - ntfs_log_error("BUG! Failed to find run after hole " - "instantiating. Please report to the %s.\n", - NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - /* If leaved part of the hole go to the next run. */ - if ((*rl)->lcn < 0) - (*rl)++; - /* Now LCN shoudn't be less than 0. */ - if ((*rl)->lcn < 0) { - ntfs_log_error("BUG! LCN is lesser than 0. " - "Please report to the %s.\n", NTFS_DEV_LIST); - errno = EIO; - goto err_out; - } - if (*ofs) { - /* - * Need to clear region between start of - * @cur_vcn cluster and @*ofs. - */ - char *buf; - - buf = ntfs_malloc(*ofs); - if (!buf) { - errno = ENOMEM; - goto err_out; - } - memset(buf, 0, *ofs); - if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << - vol->cluster_size_bits, *ofs, buf) < 0) { - eo = errno; - ntfs_log_perror("Failed to zero area"); - free(buf); - errno = eo; - goto err_out; - } - free(buf); - } - if ((*rl)->vcn < cur_vcn) { - /* - * Clusters that replaced hole are merged with - * previous run, so we need to update offset. - */ - *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits; - } - if ((*rl)->vcn > cur_vcn) { - /* - * We left part of the hole, so we need to update the offset. - */ - *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits; - } - - ret = 0; -err_out: - return ret; -} - /** * ntfs_attr_pwrite - positioned write to an ntfs attribute * @na: ntfs attribute to write to @@ -1089,8 +941,7 @@ err_out: */ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) { - s64 written, to_write, ofs, old_initialized_size, old_data_size; - s64 total = 0; + s64 written, to_write, ofs, total, old_initialized_size, old_data_size; VCN update_from = -1; ntfs_volume *vol; ntfs_attr_search_ctx *ctx = NULL; @@ -1099,7 +950,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) struct { unsigned int undo_initialized_size : 1; unsigned int undo_data_size : 1; - } need_to = { 0, 0 }; + unsigned int update_mapping_pairs : 1; + } need_to = { 0, 0, 0 }; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos, @@ -1175,7 +1027,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) ntfs_attr_put_search_ctx(ctx); return count; } - + total = 0; /* Handle writes beyond initialized_size. */ if (pos + count > na->initialized_size) { if (ntfs_attr_map_whole_runlist(na)) @@ -1272,22 +1124,174 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) goto rl_err_out; } if (rl->lcn < (LCN)0) { + LCN lcn_seek_from = -1; + runlist *rlc; + VCN cur_vcn, from_vcn; + if (rl->lcn != (LCN)LCN_HOLE) { errno = EIO; goto rl_err_out; } - - if (ntfs_attr_fill_hole(na, count, &ofs, &rl, - &update_from)) + + to_write = min(count, (rl->length << + vol->cluster_size_bits) - ofs); + + /* Instantiate the hole. */ + cur_vcn = rl->vcn; + from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits); + ntfs_log_trace("Instantiate hole with vcn 0x%llx.\n", + cur_vcn); + /* + * Map whole runlist to be able update mapping pairs + * later. + */ + if (ntfs_attr_map_whole_runlist(na)) goto err_out; - } + /* + * Restore @rl, it probably get lost during runlist + * mapping. + */ + rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!rl) { + ntfs_log_error("BUG! Failed to find run after " + "mapping whole runlist. Please " + "report to the %s.\n", + NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + /* + * Search backwards to find the best lcn to start + * seek from. + */ + rlc = rl; + while (rlc->vcn) { + rlc--; + if (rlc->lcn >= 0) { + lcn_seek_from = rlc->lcn + + (from_vcn - rlc->vcn); + break; + } + } + if (lcn_seek_from == -1) { + /* Backwards search failed, search forwards. */ + rlc = rl; + while (rlc->length) { + rlc++; + if (rlc->lcn >= 0) { + lcn_seek_from = rlc->lcn - + (rlc->vcn - from_vcn); + break; + } + } + } + /* Allocate clusters to instantiate the hole. */ + rlc = ntfs_cluster_alloc(vol, from_vcn, + ((ofs + to_write - 1) >> + vol->cluster_size_bits) + 1 + + rl->vcn - from_vcn, + lcn_seek_from, DATA_ZONE); + if (!rlc) { + eo = errno; + ntfs_log_trace("Failed to allocate clusters " + "for hole instantiating.\n"); + errno = eo; + goto err_out; + } + /* Merge runlists. */ + rl = ntfs_runlists_merge(na->rl, rlc); + if (!rl) { + eo = errno; + ntfs_log_trace("Failed to merge runlists.\n"); + if (ntfs_cluster_free_from_rl(vol, rlc)) { + ntfs_log_trace("Failed to free just " + "allocated clusters. Leaving " + "inconsistent metadata. " + "Run chkdsk\n"); + } + errno = eo; + goto err_out; + } + na->rl = rl; + need_to.update_mapping_pairs = 1; + if (update_from == -1) + update_from = from_vcn; + rl = ntfs_attr_find_vcn(na, cur_vcn); + if (!rl) { + /* + * It's definitely a BUG, if we failed to find + * @cur_vcn, because we missed it during + * instantiating of the hole. + */ + ntfs_log_error("BUG! Failed to find run after " + "instantiating. Please report " + "to the %s.\n", NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + /* If leaved part of the hole go to the next run. */ + if (rl->lcn < 0) + rl++; + /* Now LCN shoudn't be less than 0. */ + if (rl->lcn < 0) { + ntfs_log_error("BUG! LCN is lesser than 0. " + "Please report to the %s.\n", + NTFS_DEV_LIST); + errno = EIO; + goto err_out; + } + if (ofs) { + /* + * Need to clear region between start of + * @cur_vcn cluster and @ofs. + */ + char *buf; + buf = malloc(ofs); + if (!buf) { + ntfs_log_trace("Not enough memory to " + "allocate %lld " + "bytes.\n", ofs); + errno = ENOMEM; + goto err_out; + } + memset(buf, 0, ofs); + if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << + vol->cluster_size_bits, + ofs, buf) < 0) { + eo = errno; + ntfs_log_trace("Failed to zero " + "area.\n"); + free(buf); + errno = eo; + goto err_out; + } + free(buf); + } + if (rl->vcn < cur_vcn) { + /* + * Clusters that replaced hole are merged with + * previous run, so we need to update offset. + */ + ofs += (cur_vcn - rl->vcn) << + vol->cluster_size_bits; + } + if (rl->vcn > cur_vcn) { + /* + * We left part of the hole, so update we need + * to update offset + */ + ofs -= (rl->vcn - cur_vcn) << + vol->cluster_size_bits; + } + } /* It is a real lcn, write it to the volume. */ to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); retry: - ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " - "%lld.\n", to_write, rl->vcn, rl->lcn, ofs); + ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx," + " ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn, + ofs); if (!NVolReadOnly(vol)) written = ntfs_pwrite(vol->dev, (rl->lcn << vol->cluster_size_bits) + ofs, @@ -1312,7 +1316,7 @@ done: if (ctx) ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ - if (update_from != -1) + if (need_to.update_mapping_pairs) ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); /* Finally, return the number of bytes written. */ return total; @@ -1370,7 +1374,7 @@ err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ - if (update_from != -1) + if (need_to.update_mapping_pairs) ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); /* Restore original data_size if needed. */ if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) From cb5f0a1e9429130b8f78f59c7855fe89e8117d98 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 10 Nov 2006 17:23:12 +0000 Subject: [PATCH 120/289] * fmask=0111 and dmask=0 by default * bit more nice mount messages --- ntfsprogs/ntfsmount.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 5aefa6a5..2492b197 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1399,8 +1399,8 @@ static int ntfs_fuse_init(void) .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .uid = geteuid(), .gid = getegid(), - .fmask = 0177, - .dmask = 0077, + .fmask = 0111, + .dmask = 0, .streams = NF_STREAMS_INTERFACE_NONE, }; return 0; @@ -1837,8 +1837,8 @@ int main(int argc, char *argv[]) } ntfs_log_info("Version %s (libntfs %s)\n", VERSION, ntfs_libntfs_version()); - ntfs_log_info("Mounted %s (%s, label \"%s\", volume version %d.%d)\n", - opts.device, (ctx->ro) ? "RO" : "RW", + ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS version %d.%d)\n", + opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", ctx->vol->vol_name, ctx->vol->major_ver, ctx->vol->minor_ver); /* Main loop. */ From cb27c9f616f312b2bb69b82f60777dd607c990e7 Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 12 Nov 2006 22:46:50 +0000 Subject: [PATCH 121/289] * Rename MS_{RDONLY,NOATIME} to NTFS_MNT_{RDONLY,NOATIME}. * Introduce NTFS_MNT_CASE_SENSITIVE. --- ChangeLog | 4 +- include/ntfs/volume.h | 38 +++++------ libntfs/dir.c | 119 +++++++++++++++++++---------------- libntfs/gnome-vfs-method.c | 3 +- libntfs/volume.c | 66 ++++++++++--------- ntfsprogs/ntfscat.c | 2 +- ntfsprogs/ntfsclone.c | 4 +- ntfsprogs/ntfscluster.c | 2 +- ntfsprogs/ntfscmp.c | 2 +- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsdecrypt.c | 2 +- ntfsprogs/ntfsdump_logfile.c | 2 +- ntfsprogs/ntfsinfo.c | 2 +- ntfsprogs/ntfslabel.c | 4 +- ntfsprogs/ntfsls.c | 2 +- ntfsprogs/ntfsmftalloc.c | 2 +- ntfsprogs/ntfsmount.c | 5 +- ntfsprogs/ntfsmove.c | 2 +- ntfsprogs/ntfsresize.c | 6 +- ntfsprogs/ntfsrm.c | 2 +- ntfsprogs/ntfstruncate.c | 2 +- ntfsprogs/ntfsundelete.c | 2 +- ntfsprogs/ntfswipe.c | 2 +- 23 files changed, 147 insertions(+), 130 deletions(-) diff --git a/ChangeLog b/ChangeLog index 765e5efa..04476d83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -64,7 +64,9 @@ xx/xx/2006 - x.xx.x - . - Change malloc() calls to ntfs_malloc(). (Szaka) - ntfsmount: require FUSE version >= 2.6.0 for build. Fixes fusermount lookup problem and allows to drop compatibility code. (Yura) - - Rewrite ntfs_attr_add() algorithm. (Yura) + - Rewrite ntfs_attr_add() algorithm to be faster and cleverer. (Yura) + - Rename MS_{RDONLY,NOATIME} to NTFS_MNT_{RDONLY,NOATIME}. Introduce + NTFS_MNT_CASE_SENSITIVE. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 0ce254ca..ba8cf3e3 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -41,25 +41,6 @@ #include #endif -/* - * Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY and MS_NOATIME, - * so we define them ourselves. - */ -#ifndef MS_RDONLY -#define MS_RDONLY 1 -#endif -/* - * Solaris defines MS_RDONLY but not MS_NOATIME thus we need to carefully - * define MS_NOATIME. - */ -#ifndef MS_NOATIME -#if (MS_RDONLY != 1) -# define MS_NOATIME 1 -#else -# define MS_NOATIME 2 -#endif -#endif - /* Forward declaration */ typedef struct _ntfs_volume ntfs_volume; @@ -72,13 +53,24 @@ typedef struct _ntfs_volume ntfs_volume; /** * enum ntfs_mount_flags - * + * Flags for the ntfs_mount() function. + */ +typedef enum { + NTFS_MNT_RDONLY = 1, + NTFS_MNT_NOATIME = 2, + NTFS_MNT_CASE_SENSITIVE = 4, +} ntfs_mount_flags; + +/** + * enum ntfs_mounted_flags - + * * Flags returned by the ntfs_check_if_mounted() function. */ typedef enum { NTFS_MF_MOUNTED = 1, /* Device is mounted. */ NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */ NTFS_MF_READONLY = 4, /* Device is mounted read-only. */ -} ntfs_mount_flags; +} ntfs_mounted_flags; extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags); @@ -214,13 +206,13 @@ struct _ntfs_volume { extern ntfs_volume *ntfs_volume_alloc(void); extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, - unsigned long flags); + ntfs_mount_flags flags); extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, - unsigned long flags); + ntfs_mount_flags flags); extern int ntfs_device_umount(ntfs_volume *vol, const BOOL force); -extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags); +extern ntfs_volume *ntfs_mount(const char *name, ntfs_mount_flags flags); extern int ntfs_umount(ntfs_volume *vol, const BOOL force); extern int ntfs_version_is_supported(ntfs_volume *vol); diff --git a/libntfs/dir.c b/libntfs/dir.c index f96fb32d..d92581ae 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -126,10 +126,11 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, return -1; /* Find the index root attribute in the mft record. */ - if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, - 0, ctx)) { - ntfs_log_perror("Index root attribute missing in directory inode " - "0x%llx", (unsigned long long)dir_ni->mft_no); + if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + ntfs_log_perror("Index root attribute missing in directory " + "inode 0x%llx", (unsigned long long)dir_ni-> + mft_no); goto put_err_out; } /* Get to the index root value. */ @@ -263,9 +264,9 @@ found_it: /* Open the index allocation attribute. */ ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (!ia_na) { - ntfs_log_perror("Failed to open index allocation attribute. Directory " - "inode 0x%llx is corrupt or driver bug", - (unsigned long long)dir_ni->mft_no); + ntfs_log_perror("Failed to open index allocation attribute. " + "Directory inode 0x%llx is corrupt or driver " + "bug", (unsigned long long)dir_ni->mft_no); goto put_err_out; } @@ -302,28 +303,30 @@ descend_into_child_node: } if (sle64_to_cpu(ia->index_block_vcn) != vcn) { - ntfs_log_debug("Actual VCN (0x%llx) of index buffer is different " - "from expected VCN (0x%llx).\n", + ntfs_log_debug("Actual VCN (0x%llx) of index buffer is " + "different from expected VCN (0x%llx).\n", (long long)sle64_to_cpu(ia->index_block_vcn), (long long)vcn); errno = EIO; goto close_err_out; } if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { - ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode 0x%llx " - "has a size (%u) differing from the directory " - "specified size (%u).\n", (long long)vcn, - (unsigned long long)dir_ni->mft_no, - (unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18, - (unsigned)index_block_size); + ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode " + "0x%llx has a size (%u) differing from the " + "directory specified size (%u).\n", + (long long)vcn, (unsigned long long)dir_ni-> + mft_no, (unsigned)le32_to_cpu(ia->index. + allocated_size) + 0x18, (unsigned) + index_block_size); errno = EIO; goto close_err_out; } index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); if (index_end > (u8*)ia + index_block_size) { - ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode " - "0x%llx exceeds maximum size.\n", - (long long)vcn, (unsigned long long)dir_ni->mft_no); + ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory " + "inode 0x%llx exceeds maximum size.\n", + (long long)vcn, (unsigned long long)dir_ni-> + mft_no); errno = EIO; goto close_err_out; } @@ -444,8 +447,9 @@ found_it2: */ if (ie->flags & INDEX_ENTRY_NODE) { if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { - ntfs_log_debug("Index entry with child node found in a leaf " - "node in directory inode 0x%llx.\n", + ntfs_log_debug("Index entry with child node found in a " + "leaf node in directory inode " + "0x%llx.\n", (unsigned long long)dir_ni->mft_no); errno = EIO; goto close_err_out; @@ -455,7 +459,8 @@ found_it2: if (vcn >= 0) goto descend_into_child_node; ntfs_log_debug("Negative child node vcn in directory inode " - "0x%llx.\n", (unsigned long long)dir_ni->mft_no); + "0x%llx.\n", (unsigned long long)dir_ni-> + mft_no); errno = EIO; goto close_err_out; } @@ -700,8 +705,9 @@ static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni) goto err_out; } if (ctx->attr->non_resident) { - ntfs_log_debug("File name attribute must be resident. Corrupt inode " - "0x%llx.\n", (unsigned long long)ni->mft_no); + ntfs_log_debug("File name attribute must be resident. " + "Corrupt inode 0x%llx.\n", + (unsigned long long)ni->mft_no); goto io_err_out; } fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + @@ -824,10 +830,11 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, /* Get the offset into the index root attribute. */ ir_pos = (int)*pos; /* Find the index root attribute in the mft record. */ - if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL, - 0, ctx)) { - ntfs_log_debug("Index root attribute missing in directory inode " - "0x%llx.\n", (unsigned long long)dir_ni->mft_no); + if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + ntfs_log_debug("Index root attribute missing in directory " + "inode 0x%llx.\n", (unsigned long long)dir_ni-> + mft_no); goto dir_err_out; } /* Get to the index root value. */ @@ -868,7 +875,8 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * or signals an error (both covered by the rc test). */ for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { - ntfs_log_debug("In index root, offset 0x%x.\n", (u8*)ie - (u8*)ir); + ntfs_log_debug("In index root, offset 0x%x.\n", + (u8*)ie - (u8*)ir); /* Bounds checks. */ if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || @@ -965,7 +973,8 @@ find_next_index_buffer: if (br != bmp_buf_size) { if (br != -1) errno = EIO; - ntfs_log_perror("Failed to read from index bitmap attribute"); + ntfs_log_perror("Failed to read from index bitmap " + "attribute"); goto err_out; } } @@ -985,18 +994,19 @@ find_next_index_buffer: ia_start = ia_pos & ~(s64)(index_block_size - 1); if (sle64_to_cpu(ia->index_block_vcn) != ia_start >> index_vcn_size_bits) { - ntfs_log_debug("Actual VCN (0x%llx) of index buffer is different " - "from expected VCN (0x%llx) in inode 0x%llx.\n", + ntfs_log_debug("Actual VCN (0x%llx) of index buffer is " + "different from expected VCN (0x%llx) in " + "inode 0x%llx.\n", (long long)sle64_to_cpu(ia->index_block_vcn), (long long)ia_start >> index_vcn_size_bits, (unsigned long long)dir_ni->mft_no); goto dir_err_out; } if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) { - ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode 0x%llx " - "has a size (%u) differing from the directory " - "specified size (%u).\n", (long long)ia_start >> - index_vcn_size_bits, + ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode " + "0x%llx has a size (%u) differing from the " + "directory specified size (%u).\n", + (long long)ia_start >> index_vcn_size_bits, (unsigned long long)dir_ni->mft_no, (unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18, (unsigned)index_block_size); @@ -1004,8 +1014,8 @@ find_next_index_buffer: } index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); if (index_end > (u8*)ia + index_block_size) { - ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode " - "0x%llx exceeds maximum size.\n", + ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory " + "inode 0x%llx exceeds maximum size.\n", (long long)ia_start >> index_vcn_size_bits, (unsigned long long)dir_ni->mft_no); goto dir_err_out; @@ -1026,8 +1036,9 @@ find_next_index_buffer: sizeof(INDEX_ENTRY_HEADER) > index_end || (u8*)ie + le16_to_cpu(ie->key_length) > index_end) { - ntfs_log_debug("Index entry out of bounds in directory inode " - "0x%llx.\n", (unsigned long long)dir_ni->mft_no); + ntfs_log_debug("Index entry out of bounds in directory " + "inode 0x%llx.\n", (unsigned long long) + dir_ni->mft_no); goto dir_err_out; } /* The last entry cannot contain a name. */ @@ -1058,10 +1069,11 @@ done: ntfs_attr_close(ia_na); #ifdef DEBUG if (!rc) - ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos); + ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", + (long long)*pos); else - ntfs_log_debug("filldir returned %i, *pos 0x%llx, returning 0.\n", - rc, (long long)*pos); + ntfs_log_debug("filldir returned %i, *pos 0x%llx, " + "returning 0.\n", rc, (long long)*pos); #endif return 0; dir_err_out: @@ -1483,8 +1495,8 @@ int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) * WIN32_AND_DOS namespace, then simply remove it from index and inode. * If filename in DOS or in WIN32 namespace, then remove DOS name first, * only then remove WIN32 name. Mark WIN32 name as POSIX name to prevent - * chkdsk to complain about DOS name absentation, in case if DOS name - * had been successfully deleted, but WIN32 name removing failed. + * chkdsk to complain about DOS name absence in case if DOS name had + * been successfully deleted, but WIN32 name remove failed. */ actx = ntfs_attr_get_search_ctx(ni, NULL); if (!actx) @@ -1530,10 +1542,11 @@ search: } if (errno) { /* - * If case sensitive search failed, then try once again - * ignoring case. + * If case sensitive search failed and volume mounted case + * insensitive, then try once again ignoring case. */ - if (errno == ENOENT && case_sensitive_match) { + if (errno == ENOENT && !NVolCaseSensitive(ni->vol) && + case_sensitive_match) { case_sensitive_match = FALSE; ntfs_attr_reinit_search_ctx(actx); ntfs_log_trace("Restart search. Ignore case."); @@ -1556,7 +1569,7 @@ search: /* * Do not allow non-empty directory deletion if hard links count * is 1 (always) or 2 (in case if filename in DOS namespace, - * because we delete it first in filen which have both WIN32 and + * because we delete it first in file which have both WIN32 and * DOS names). */ if ((na->data_size != sizeof(INDEX_ROOT) + sizeof( @@ -1598,7 +1611,7 @@ search: /* Remove FILE_NAME from inode. */ if (ntfs_attr_record_rm(actx)) goto err_out; - /* Decerement hard link count. */ + /* Decrement hard link count. */ ni->mrec->link_count = cpu_to_le16(le16_to_cpu( ni->mrec->link_count) - 1); ntfs_inode_mark_dirty(ni); @@ -1611,7 +1624,7 @@ search: goto search; } else ntfs_log_trace("Deleted.\n"); - /* TODO: Update object id, quota and securiry indexes if required. */ + /* TODO: Update object id, quota and security indexes if required. */ /* * If hard link count is not equal to zero then we are done. In other * case there are no reference to this inode left, so we should free all @@ -1687,8 +1700,8 @@ err_out: * @name: unicode name of the new link * @name_len: length of the name in unicode characters * - * NOTE: At present we allow creating hardlinks to directories, we use them - * in a temporary state during rename. But it's defenitely bad idea to have + * NOTE: At present we allow creating hard links to directories, we use them + * in a temporary state during rename. But it's definitely bad idea to have * hard links to directories as a result of operation. * FIXME: Create internal __ntfs_link that allows hard links to a directories * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link. @@ -1705,7 +1718,7 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) if (!ni || !dir_ni || !name || !name_len || ni->mft_no == dir_ni->mft_no) { err = EINVAL; - ntfs_log_perror("ntfs_link wrong arguments"); + ntfs_log_error("Invalid arguments."); goto err_out; } /* Create FILE_NAME attribute. */ diff --git a/libntfs/gnome-vfs-method.c b/libntfs/gnome-vfs-method.c index 28e5d8b7..523fa3d9 100644 --- a/libntfs/gnome-vfs-method.c +++ b/libntfs/gnome-vfs-method.c @@ -162,7 +162,8 @@ static GnomeVFSResult libntfs_gnomevfs_uri_parent_init( return GNOME_VFS_ERROR_INVALID_URI; } - if (!(volume = ntfs_mount(uri->parent->text, MS_RDONLY))) { + if (!(volume = ntfs_mount(uri->parent->text, + NTFS_MNT_RDONLY))) { g_free(uri_parent_string); return GNOME_VFS_ERROR_WRONG_FORMAT; } diff --git a/libntfs/volume.c b/libntfs/volume.c index 4930e73d..9f1fe896 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -117,7 +117,7 @@ static void __ntfs_volume_release(ntfs_volume *v) if (NDevDirty(dev)) dev->d_ops->sync(dev); if (dev->d_ops->close(dev)) - ntfs_log_perror("Eeek! Failed to close the device. Error: "); + ntfs_log_perror("Failed to close the device. Error: "); } free(v->vol_name); free(v->upcase); @@ -399,7 +399,8 @@ error_exit: * Return the allocated volume structure on success and NULL on error with * errno set to the error code. */ -ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) +ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, + ntfs_mount_flags flags) { LCN mft_zone_size, mft_lcn; s64 br; @@ -435,10 +436,12 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) ntfs_upcase_table_build(vol->upcase, vol->upcase_len * sizeof(ntfschar)); - if (flags & MS_RDONLY) + if (flags & NTFS_MNT_RDONLY) NVolSetReadOnly(vol); - if (flags & MS_NOATIME) + if (flags & NTFS_MNT_NOATIME) NVolSetNoATime(vol); + if (flags & NTFS_MNT_CASE_SENSITIVE) + NVolSetCaseSensitive(vol); ntfs_log_debug("Reading bootsector... "); if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { ntfs_log_debug(FAILED); @@ -746,11 +749,13 @@ out: * This function mounts an ntfs volume. @dev should describe the device which * to mount as the ntfs volume. * - * @flags is an optional second parameter. The same flags are used as for - * the mount system call (man 2 mount). Currently only the following flags + * @flags is an optional second parameter. Some flags are similar to flags used + * as for the mount system call (man 2 mount). Currently the following flags * are implemented: - * MS_RDONLY - mount volume read-only - * MS_NOATIME - do not update access time + * NTFS_MNT_RDONLY - mount volume read-only + * NTFS_MNT_NOATIME - do not update access time + * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if + * they are not in POSIX namespace * * The function opens the device @dev and verifies that it contains a valid * bootsector. Then, it allocates an ntfs_volume structure and initializes @@ -761,7 +766,7 @@ out: * Return the allocated volume structure on success and NULL on error with * errno set to the error code. */ -ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) +ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) { s64 l; #ifndef NTFS_DISABLE_DEBUG_LOGGING @@ -936,8 +941,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); if (l != na->data_size) { ntfs_log_debug(FAILED); - ntfs_log_debug("Amount of data read does not correspond to expected " - "length!\n"); + ntfs_log_debug("Amount of data read does not correspond to " + "expected length!\n"); errno = EIO; goto error_exit; } @@ -990,8 +995,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) le16_to_cpu(a->value_offset) + le32_to_cpu( a->value_length) > le32_to_cpu(a->length)) { ntfs_log_debug(FAILED); - ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION in $Volume is " - "corrupt!\n"); + ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION in " + "$Volume is corrupt!\n"); errno = EIO; goto error_exit; } @@ -1009,9 +1014,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) ctx)) { if (errno != ENOENT) { ntfs_log_debug(FAILED); - ntfs_log_debug("Error: Lookup of $VOLUME_NAME attribute in " - "$Volume failed. This probably means " - "something is corrupt. Run chkdsk.\n"); + ntfs_log_debug("Error: Lookup of $VOLUME_NAME " + "attribute in $Volume failed. " + "This probably means something is " + "corrupt. Run chkdsk.\n"); goto error_exit; } /* @@ -1044,8 +1050,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) */ vol->vol_name = NULL; if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) { - ntfs_log_perror("Error: Volume name could not be converted " - "to current locale"); + ntfs_log_perror("Error: Volume name could not be " + "converted to current locale"); ntfs_log_debug("Forcing name into ASCII by replacing " "non-ASCII characters with underscores.\n"); vol->vol_name = ntfs_malloc(u + 1); @@ -1083,8 +1089,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) /* Check we don't overflow 32-bits. */ if (na->data_size > 0xffffffffLL) { ntfs_log_debug(FAILED); - ntfs_log_debug("Error: Attribute definition table is too big (max " - "32-bit allowed).\n"); + ntfs_log_debug("Error: Attribute definition table is too big " + "(max 32-bit allowed).\n"); errno = EINVAL; goto error_exit; } @@ -1098,8 +1104,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) l = ntfs_attr_pread(na, 0, na->data_size, vol->attrdef); if (l != na->data_size) { ntfs_log_debug(FAILED); - ntfs_log_debug("Amount of data read does not correspond to expected " - "length!\n"); + ntfs_log_debug("Amount of data read does not correspond to " + "expected length!\n"); errno = EIO; goto error_exit; } @@ -1112,7 +1118,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags) * Check for dirty logfile and hibernated Windows. * We care only about read-write mounts. */ - if (!(flags & MS_RDONLY)) { + if (!(flags & NTFS_MNT_RDONLY)) { if (ntfs_volume_check_logfile(vol) < 0) goto error_exit; if (ntfs_volume_check_hiberfile(vol) < 0) @@ -1141,11 +1147,13 @@ error_exit: * This function mounts an ntfs volume. @name should contain the name of the * device/file to mount as the ntfs volume. * - * @flags is an optional second parameter. The same flags are used as for - * the mount system call (man 2 mount). Currently only the following flags + * @flags is an optional second parameter. Some flags are similar to flags used + * as for the mount system call (man 2 mount). Currently the following flags * are implemented: - * MS_RDONLY - mount volume read-only - * MS_NOATIME - do not update access time + * NTFS_MNT_RDONLY - mount volume read-only + * NTFS_MNT_NOATIME - do not update access time + * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if + * they are not in POSIX namespace * * The function opens the device or file @name and verifies that it contains a * valid bootsector. Then, it allocates an ntfs_volume structure and initializes @@ -1160,7 +1168,7 @@ error_exit: * soon as the function returns. */ ntfs_volume *ntfs_mount(const char *name __attribute__((unused)), - unsigned long flags __attribute__((unused))) + ntfs_mount_flags flags __attribute__((unused))) { #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS struct ntfs_device *dev; @@ -1378,7 +1386,7 @@ int ntfs_check_if_mounted(const char *file __attribute__((unused)), * Version 1.1 and 1.2 are used by Windows NT3.x and NT4. * Version 2.x is used by Windows 2000 Betas. * Version 3.0 is used by Windows 2000. - * Version 3.1 is used by Windows XP, Windows Server 2003 and Longhorn. + * Version 3.1 is used by Windows XP, Windows Server 2003 and Vista. * * Return 0 if NTFS version is supported otherwise -1 with errno set. * diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index b744237a..d584bd4f 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -399,7 +399,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) { ntfs_log_perror("ERROR: couldn't mount volume"); return 1; diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 08dc6ad2..474fa881 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1593,7 +1593,7 @@ static s64 open_volume(void) { s64 device_size; - mount_volume(MS_RDONLY); + mount_volume(NTFS_MNT_RDONLY); device_size = ntfs_device_size_get(vol->dev, 1); if (device_size <= 0) @@ -1825,7 +1825,7 @@ int main(int argc, char **argv) /* 'force' again mount for dirty volumes (e.g. after resize). FIXME: use mount flags to avoid potential side-effects in future */ opt.force++; - mount_volume(MS_NOATIME); + mount_volume(NTFS_MNT_NOATIME); free(lcn_bitmap.bm); setup_lcn_bitmap(); diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index d7c13f8a..d72f5e8f 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -492,7 +492,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) return 1; diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 6b8cd1f2..53361dc6 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -939,7 +939,7 @@ static ntfs_volume *mount_volume(const char *volume) "You must 'umount' it first.\n", volume); } - vol = ntfs_mount(volume, MS_RDONLY); + vol = ntfs_mount(volume, NTFS_MNT_RDONLY); if (vol == NULL) { int err = errno; diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index c96024b2..74d327cd 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -344,7 +344,7 @@ int main(int argc, char *argv[]) } if (opts.noaction) - flags = MS_RDONLY; + flags = NTFS_MNT_RDONLY; vol = utils_mount_volume(opts.device, flags, opts.force); if (!vol) { diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 4e21a525..1db17ee9 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -1315,7 +1315,7 @@ int main(int argc, char *argv[]) return 1; } /* Mount the ntfs volume. */ - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) { ntfs_log_error("Failed to mount ntfs volume. Aborting.\n"); ntfs_rsa_private_key_release(rsa_key); diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index d6500379..2597dcfd 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -197,7 +197,7 @@ static int logfile_open(BOOL is_volume, const char *filename, ntfs_inode *ni; ntfs_attr *na; - vol = ntfs_mount(filename, MS_RDONLY); + vol = ntfs_mount(filename, NTFS_MNT_RDONLY); if (!vol) log_err_exit(NULL, "Failed to mount %s: %s\n", filename, strerror(errno)); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 41ba6304..d8754524 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -2204,7 +2204,7 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) { printf("Failed to open '%s': %s\n", opts.device, strerror(errno)); diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index f219eb6a..2d1eccae 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -394,8 +394,8 @@ int main(int argc, char **argv) if (!opts.label) opts.noaction++; - vol = utils_mount_volume(opts.device, opts.noaction ? MS_RDONLY : 0, - opts.force); + vol = utils_mount_volume(opts.device, opts.noaction ? + NTFS_MNT_RDONLY : 0, opts.force); if (!vol) return 1; diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c index 40f291b6..a5c6cc20 100644 --- a/ntfsprogs/ntfsls.c +++ b/ntfsprogs/ntfsls.c @@ -651,7 +651,7 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) { // FIXME: Print error... (AIA) return 2; diff --git a/ntfsprogs/ntfsmftalloc.c b/ntfsprogs/ntfsmftalloc.c index c10899e9..81699857 100644 --- a/ntfsprogs/ntfsmftalloc.c +++ b/ntfsprogs/ntfsmftalloc.c @@ -313,7 +313,7 @@ int main(int argc, char **argv) /* Mount the device. */ if (opts.no_action) { ntfs_log_quiet("Running in READ-ONLY mode!\n"); - ul = MS_RDONLY; + ul = NTFS_MNT_RDONLY; } else ul = 0; vol = ntfs_mount(dev_name, ul); diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 2492b197..61381242 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1410,8 +1410,9 @@ static int ntfs_fuse_mount(const char *device) { ntfs_volume *vol; - vol = utils_mount_volume(device, ((ctx->ro) ? MS_RDONLY : 0) | - ((ctx->noatime) ? MS_NOATIME : 0), ctx->force); + vol = utils_mount_volume(device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | + ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) | + NTFS_MNT_CASE_SENSITIVE, ctx->force); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index e590802d..c7e1bc2b 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -875,7 +875,7 @@ int main(int argc, char *argv[]) utils_set_locale(); if (opts.noaction) - flags |= MS_RDONLY; + flags |= NTFS_MNT_RDONLY; vol = utils_mount_volume(opts.device, flags, opts.force); if (!vol) { diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 1c592ab2..47d59aae 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -484,7 +484,7 @@ static int parse_options(int argc, char **argv) opt.info++; break; case 'n': - opt.ro_flag = MS_RDONLY; + opt.ro_flag = NTFS_MNT_RDONLY; break; case 'P': opt.show_progress = 0; @@ -520,7 +520,7 @@ static int parse_options(int argc, char **argv) err++; } if (opt.info) { - opt.ro_flag = MS_RDONLY; + opt.ro_flag = NTFS_MNT_RDONLY; if (opt.bytes) { printf(NERR_PREFIX "Options --info and --size " "can't be used together.\n"); @@ -2237,7 +2237,7 @@ static ntfs_volume *mount_volume(void) "You must 'umount' it first.\n", opt.volume); } - if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | MS_NOATIME))) { + if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_NOATIME))) { int err = errno; diff --git a/ntfsprogs/ntfsrm.c b/ntfsprogs/ntfsrm.c index c121eae1..9f48e64b 100644 --- a/ntfsprogs/ntfsrm.c +++ b/ntfsprogs/ntfsrm.c @@ -1027,7 +1027,7 @@ int main(int argc, char *argv[]) #endif if (opts.noaction) - flags |= MS_RDONLY; + flags |= NTFS_MNT_RDONLY; //ntfs_log_set_levels (NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE); //ntfs_log_set_levels (NTFS_LOG_LEVEL_DEBUG); diff --git a/ntfsprogs/ntfstruncate.c b/ntfsprogs/ntfstruncate.c index c771c04c..69c20beb 100644 --- a/ntfsprogs/ntfstruncate.c +++ b/ntfsprogs/ntfstruncate.c @@ -738,7 +738,7 @@ int main(int argc, char **argv) /* Mount the device. */ if (opts.no_action) { ntfs_log_quiet("Running in READ-ONLY mode!\n"); - ul = MS_RDONLY; + ul = NTFS_MNT_RDONLY; } else ul = 0; vol = ntfs_mount(dev_name, ul); diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index b18d149b..4718a96a 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -2123,7 +2123,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) return 1; diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index da713ca0..3f66f92d 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1340,7 +1340,7 @@ int main(int argc, char *argv[]) print_summary(); if (opts.info || opts.noaction) - flags = MS_RDONLY; + flags = NTFS_MNT_RDONLY; vol = utils_mount_volume(opts.device, flags, opts.force); if (!vol) From 9635a4793e5b2babcf4e7ef2ebcde7e78995ecf3 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 13 Nov 2006 15:38:43 +0000 Subject: [PATCH 122/289] Disable debug logging by default (seriously increase speed) --- configure.ac | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 2c743ae6..c2a14622 100644 --- a/configure.ac +++ b/configure.ac @@ -143,11 +143,12 @@ AH_TEMPLATE([NTFS_DISABLE_DEBUG_LOGGING], [Define this if you want to compile out the debug log messages. This will reduce the size of the binaries.]) AC_ARG_ENABLE(debug-logging, - AS_HELP_STRING(--disable-debug-logging,Remove debug logging from the code), - if test "$enable_debug_logging" == "no"; then - AC_DEFINE(NTFS_DISABLE_DEBUG_LOGGING) - fi, + AS_HELP_STRING(--enable-debug-logging,Add debug logging to the code),, + enable_debug_logging=no ) +if test "$enable_debug_logging" == "no"; then + AC_DEFINE(NTFS_DISABLE_DEBUG_LOGGING) +fi # Use GNU extensions if available. AC_GNU_SOURCE From 0ac08318a65e4e136635bfc5dc23d4cee3a09137 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 13 Nov 2006 17:01:53 +0000 Subject: [PATCH 123/289] use nice error messages from ntfs-3g --- ntfsprogs/ntfsmount.c | 5 +- ntfsprogs/utils.c | 107 ++++++++++++++++++++++++++---------------- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 61381242..b9cdd38b 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1697,7 +1697,10 @@ static int parse_options(int argc, char *argv[]) if (argv[optind - 1][0] != '/') { if (!realpath(argv[optind - 1], opts.device)) { - ntfs_log_perror("realpath"); + ntfs_log_perror("Failed to " + "access %s", + argv[optind - + 1]); free(opts.device); opts.device = NULL; err++; diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index c23b2ca0..978fbc5e 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -81,6 +81,41 @@ const char *ntfs_gpl = "This program is free software, released under the GNU " "\"COPYING\" distributed with this program, or online at:\n" "http://www.gnu.org/copyleft/gpl.html\n"; +static const char *invalid_ntfs_msg = +"The device '%s' doesn't have a valid NTFS.\n" +"Maybe you selected the wrong device? Or the whole disk instead of a\n" +"partition (e.g. /dev/hda, not /dev/hda1)? Or the other way around?\n"; + +static const char *corrupt_volume_msg = +"NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n" +"The usage of the /f parameter is very IMPORTANT! No modification was\n" +"made to NTFS by this software.\n"; + +static const char *hibernated_volume_msg = +"The NTFS partition is hibernated. Please resume Windows and turned it \n" +"off properly, so mounting could be done safely.\n"; + +static const char *unclean_journal_msg = +"Mount is denied because the NTFS journal file is unclean. Choices are:\n" +" A) Shutdown Windows properly.\n" +" B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n" +" notification area before disconnecting the device.\n" +" C) Use 'Eject' from Windows Explorer to safely remove the device.\n" +" D) If you ran chkdsk previously then boot Windows again which will\n" +" automatically initialize the journal.\n" +" E) Run 'ntfsfix' on Linux which will reset the NTFS journal.\n" +" Then submit force option (WARNING: This solution it not recommended).\n" +" F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n"; + +static const char *opened_volume_msg = +"Mount is denied because the NTFS volume is already exclusively opened.\n" +"The volume may be already mounted, or another software may use it which\n" +"could be identified for example by the help of the 'fuser' command.\n"; + +static const char *dirty_volume_msg = +"Volume is scheduled for check.\n" +"Please boot into Windows TWICE, or use the 'force' option.\n"; + /** * utils_set_locale */ @@ -91,7 +126,8 @@ int utils_set_locale(void) locale = setlocale(LC_ALL, ""); if (!locale) { locale = setlocale(LC_ALL, NULL); - ntfs_log_error("Failed to set locale, using default '%s'.\n", locale); + ntfs_log_error("Failed to set locale, using default '%s'.\n", + locale); return 1; } else { return 0; @@ -99,7 +135,7 @@ int utils_set_locale(void) } /** - * utils_valid_device - Perform some safety checks on the device, before we start + * utils_valid_device - Perform some safety checks on the device, before start * @name: Full pathname of the device/file to work with * @force: Continue regardless of problems * @@ -115,7 +151,7 @@ int utils_valid_device(const char *name, int force) struct stat st; #ifdef __CYGWIN32__ - /* FIXME: This doesn't work for Cygwin, so just return success for now... */ + /* FIXME: This doesn't work for Cygwin, so just return success. */ return 1; #endif if (!name) { @@ -124,37 +160,30 @@ int utils_valid_device(const char *name, int force) } if (stat(name, &st) == -1) { - if (errno == ENOENT) { + if (errno == ENOENT) ntfs_log_error("The device %s doesn't exist\n", name); - } else { - ntfs_log_perror("Error getting information about %s", name); - } + else + ntfs_log_perror("Error getting information about %s", + name); return 0; } - if (!S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode)) { - ntfs_log_warning("%s is not a block device, " - "nor regular file.\n", name); - if (!force) { - ntfs_log_error("Use the force option to work with other" - " file types, for your own risk!\n"); - return 0; - } - ntfs_log_warning("Forced to continue.\n"); - } - /* Make sure the file system is not mounted. */ if (ntfs_check_if_mounted(name, &mnt_flags)) { - ntfs_log_perror("Failed to determine whether %s is mounted", name); + ntfs_log_perror("Failed to determine whether %s is mounted", + name); if (!force) { - ntfs_log_error("Use the force option to ignore this error.\n"); + ntfs_log_error("Use the force option to ignore this " + "error.\n"); return 0; } ntfs_log_warning("Forced to continue.\n"); } else if (mnt_flags & NTFS_MF_MOUNTED) { - ntfs_log_warning("The device %s, is mounted.\n", name); if (!force) { - ntfs_log_error("Use the force option to work a mounted filesystem.\n"); + ntfs_log_error("%s", opened_volume_msg); + ntfs_log_error("You can use force option to avoid this " + "check, but this is not recommended\n" + "and may lead to data corruption.\n"); return 0; } ntfs_log_warning("Forced to continue.\n"); @@ -166,7 +195,8 @@ int utils_valid_device(const char *name, int force) /** * utils_mount_volume - Mount an NTFS volume */ -ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force) +ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, + BOOL force) { ntfs_volume *vol; @@ -180,32 +210,29 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL f vol = ntfs_mount(device, flags); if (!vol) { - int err; - - err = errno; - ntfs_log_perror("Couldn't mount device '%s'", device); - if (err == EPERM) - ntfs_log_error("Windows was hibernated. Try to mount " - "volume in windows, shut down and try " - "again.\n"); - if (err == EOPNOTSUPP) - ntfs_log_error("Windows did not shut down properly. " - "Try to mount volume in windows, " - "shut down and try again.\n"); + ntfs_log_perror("Failed to mount '%s'", device); + if (errno == EINVAL) + ntfs_log_error(invalid_ntfs_msg, device); + else if (errno == EIO) + ntfs_log_error("%s", corrupt_volume_msg); + else if (errno == EPERM) + ntfs_log_error("%s", hibernated_volume_msg); + else if (errno == EOPNOTSUPP) + ntfs_log_error("%s", unclean_journal_msg); + else if (errno == EBUSY) + ntfs_log_error("%s", opened_volume_msg); return NULL; } if (vol->flags & VOLUME_IS_DIRTY) { - ntfs_log_warning("Volume is dirty.\n"); if (!force) { - ntfs_log_error("Run chkdsk and try again, or use the " - "force option.\n"); + ntfs_log_error("%s", dirty_volume_msg); ntfs_umount(vol, FALSE); return NULL; } - ntfs_log_warning("Forced to continue.\n"); + ntfs_log_error("WARNING: Dirty volume mount was forced by the " + "'force' mount option.\n"); } - return vol; } From 7d1016fe978320643a9d8b8eab7ad759a0af220e Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 15 Nov 2006 23:15:17 +0000 Subject: [PATCH 124/289] Treat filenames in POSIX namespace as case insensitive in case of case insensitive mounts. --- ChangeLog | 2 ++ libntfs/dir.c | 49 ++++++++++++------------------------------- ntfsprogs/ntfsmount.c | 4 ++-- 3 files changed, 17 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04476d83..bfca64af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -67,6 +67,8 @@ xx/xx/2006 - x.xx.x - . - Rewrite ntfs_attr_add() algorithm to be faster and cleverer. (Yura) - Rename MS_{RDONLY,NOATIME} to NTFS_MNT_{RDONLY,NOATIME}. Introduce NTFS_MNT_CASE_SENSITIVE. (Yura) + - Treat filenames in POSIX namespace as case insensitive in case of + case insensitive mounts. (Anton, Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/dir.c b/libntfs/dir.c index d92581ae..3468500f 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -186,28 +186,17 @@ found_it: } /* * For a case insensitive mount, we also perform a case - * insensitive comparison (provided the file name is not in the - * POSIX namespace). If the comparison matches, we cache the - * mft reference in mref. + * insensitive comparison. If the comparison matches, we cache + * the mft reference in mref. Use first case insensitive match + * in case if no name matches case sensitive, but several names + * matches case insensitive. */ - if (!NVolCaseSensitive(vol) && - ie->key.file_name.file_name_type && + if (!mref && !NVolCaseSensitive(vol) && ntfs_names_are_equal(uname, uname_len, (ntfschar*)&ie->key.file_name.file_name, ie->key.file_name.file_name_length, - IGNORE_CASE, vol->upcase, vol->upcase_len)) { - /* Only one case insensitive matching name allowed. */ - if (mref) { - ntfs_log_error("Found already cached mft " - "reference in phase 1. Please " - "run chkdsk and if that doesn't" - " find any errors please report" - " you saw this message to %s\n", - NTFS_DEV_LIST); - goto put_err_out; - } + IGNORE_CASE, vol->upcase, vol->upcase_len)) mref = le64_to_cpu(ie->indexed_file); - } /* * Not a perfect match, need to do full blown collation so we * know which way in the B+tree we have to go. @@ -381,28 +370,17 @@ found_it2: } /* * For a case insensitive mount, we also perform a case - * insensitive comparison (provided the file name is not in the - * POSIX namespace). If the comparison matches, we cache the - * mft reference in mref. + * insensitive comparison. If the comparison matches, we cache + * the mft reference in mref. Use first case insensitive match + * in case if no name matches case sensitive, but several names + * matches case insensitive. */ - if (!NVolCaseSensitive(vol) && - ie->key.file_name.file_name_type && + if (!mref && !NVolCaseSensitive(vol) && ntfs_names_are_equal(uname, uname_len, (ntfschar*)&ie->key.file_name.file_name, ie->key.file_name.file_name_length, - IGNORE_CASE, vol->upcase, vol->upcase_len)) { - /* Only one case insensitive matching name allowed. */ - if (mref) { - ntfs_log_error("Found already cached mft " - "reference in phase 2. Please " - "run chkdsk and if that doesn't" - " find any errors please report" - " you saw this message to %s\n", - NTFS_DEV_LIST); - goto close_err_out; - } + IGNORE_CASE, vol->upcase, vol->upcase_len)) mref = le64_to_cpu(ie->indexed_file); - } /* * Not a perfect match, need to do full blown collation so we * know which way in the B+tree we have to go. @@ -1524,8 +1502,7 @@ search: if (dir_ni->mft_no == MREF_LE(fn->parent_directory) && ntfs_names_are_equal(fn->file_name, fn->file_name_length, name, - name_len, (fn->file_name_type == - FILE_NAME_POSIX || case_sensitive_match) ? + name_len, case_sensitive_match ? CASE_SENSITIVE : IGNORE_CASE, ni->vol->upcase, ni->vol->upcase_len)) { if (fn->file_name_type == FILE_NAME_WIN32) { diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index b9cdd38b..b7a1b3bc 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1411,8 +1411,8 @@ static int ntfs_fuse_mount(const char *device) ntfs_volume *vol; vol = utils_mount_volume(device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | - ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) | - NTFS_MNT_CASE_SENSITIVE, ctx->force); + ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) /*| + NTFS_MNT_CASE_SENSITIVE*/, ctx->force); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; From 188cbd9a41dbaccdfefe7414d6ac58c16d55277c Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 17 Nov 2006 22:14:55 +0000 Subject: [PATCH 125/289] use optarg instead of argv[optind - 1] --- ntfsprogs/ntfsmount.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index b7a1b3bc..9aef6de8 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1694,22 +1694,20 @@ static int parse_options(int argc, char *argv[]) break; } /* We don't want relative path in /etc/mtab. */ - if (argv[optind - 1][0] != '/') { - if (!realpath(argv[optind - 1], - opts.device)) { + if (optarg[0] != '/') { + if (!realpath(optarg, opts.device)) { ntfs_log_perror("Failed to " "access %s", - argv[optind - - 1]); + optarg); free(opts.device); opts.device = NULL; err++; break; } } else - strcpy(opts.device, argv[optind - 1]); + strcpy(opts.device, optarg); } else if (!opts.mnt_point) - opts.mnt_point = argv[optind - 1]; + opts.mnt_point = optarg; else { ntfs_log_error("You must specify exactly one " "device and exactly one mount " @@ -1719,7 +1717,7 @@ static int parse_options(int argc, char *argv[]) break; case 'o': if (!opts.options) - opts.options = argv[optind - 1]; + opts.options = optarg; else { ntfs_log_error("You must specify exactly one " "set of options.\n"); @@ -1737,8 +1735,7 @@ static int parse_options(int argc, char *argv[]) opts.verbose++; break; default: - ntfs_log_error("Unknown option '%s'.\n", - argv[optind - 1]); + ntfs_log_error("Unknown option '%s'.\n", optarg); err++; break; } From 18dec0543d51c557f2e04b27c359013e7c3f7f38 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 17 Nov 2006 22:35:21 +0000 Subject: [PATCH 126/289] add support for read errors in free disk space calculation (szaka) --- ntfsprogs/ntfsmount.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 9aef6de8..25605e69 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -151,13 +151,13 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) return ctx->free_mft; buf = ntfs_malloc(vol->cluster_size); if (!buf) - return -ENOMEM; + return -errno; while (1) { int i, j; br = ntfs_attr_pread(vol->mftbmp_na, total, vol->cluster_size, buf); - if (!br) + if (br <= 0) break; total += br; for (i = 0; i < br; i++) @@ -166,7 +166,7 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) nr_free++; } free(buf); - if (!total) + if (!total || br < 0) return -errno; ctx->free_mft = nr_free; ctx->state &= ~(NF_FreeMFTOutdate); @@ -183,13 +183,13 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) return ctx->free_clusters; buf = ntfs_malloc(vol->cluster_size); if (!buf) - return -ENOMEM; + return -errno; while (1) { int i, j; br = ntfs_attr_pread(vol->lcnbmp_na, total, vol->cluster_size, buf); - if (!br) + if (br <= 0) break; total += br; for (i = 0; i < br; i++) @@ -198,7 +198,7 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) nr_free++; } free(buf); - if (!total) + if (!total || br < 0) return -errno; ctx->free_clusters = nr_free; ctx->state &= ~(NF_FreeClustersOutdate); From b33658bc611537db87144c0b9b677b6271e0bec8 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 17 Nov 2006 22:51:29 +0000 Subject: [PATCH 127/289] cleanups --- libntfs/dir.c | 2 +- libntfs/unistr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 3468500f..c6b562f1 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -522,7 +522,7 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, p = ascii; /* Remove leading /'s. */ - while (p && *p && *p == PATH_SEP) + while (p && *p == PATH_SEP) p++; while (p && *p) { /* Find the end of the first token. */ diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 8ed054e9..9f802674 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -727,7 +727,7 @@ ntfschar *ntfs_str2ucs(const char *s, int *len) ntfs_log_perror("Couldn't convert '%s' to Unicode", s); return NULL; } - if (*len > 0xff) { + if (*len > NTFS_MAX_NAME_LEN) { free(ucs); errno = ENAMETOOLONG; return NULL; From f7fe727b093c19daf9e676cb187eb4b821e4a828 Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 19 Nov 2006 20:19:18 +0000 Subject: [PATCH 128/289] 80 chars lines long fixes --- libntfs/bootsect.c | 16 ++++++++++------ libntfs/volume.c | 7 ++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libntfs/bootsect.c b/libntfs/bootsect.c index 93d95ff4..6f4a3558 100644 --- a/libntfs/bootsect.c +++ b/libntfs/bootsect.c @@ -56,7 +56,8 @@ * * Return TRUE if @b contains a valid ntfs boot sector and FALSE if not. */ -BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, const BOOL silent __attribute__((unused))) +BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, + const BOOL silent __attribute__((unused))) { u32 i; @@ -148,10 +149,10 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, const BOOL silent __attribute ntfs_log_debug("OK\n"); if (b->end_of_sector_marker != cpu_to_le16(0xaa55)) - ntfs_log_debug("Warning: Bootsector has invalid end of sector marker.\n"); + ntfs_log_debug("Warning: Bootsector has invalid end of sector " + "marker.\n"); ntfs_log_debug("Bootsector check completed successfully.\n"); - return TRUE; not_ntfs: ntfs_log_debug("FAILED\n"); @@ -187,7 +188,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) * ntfs_boot_sector_is_ntfs but in this way we can just do this once. */ sectors_per_cluster = bs->bpb.sectors_per_cluster; - ntfs_log_debug("NumberOfSectors = %lli\n", sle64_to_cpu(bs->number_of_sectors)); + ntfs_log_debug("NumberOfSectors = %lli\n", + sle64_to_cpu(bs->number_of_sectors)); ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster); if (sectors_per_cluster & (sectors_per_cluster - 1)) { ntfs_log_debug("Error: %s is not a valid NTFS partition! " @@ -244,7 +246,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) return -1; } vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; - ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size); + ntfs_log_debug("MftRecordSize = 0x%x\n", + (unsigned)vol->mft_record_size); ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits); /* Same as above for INDX record. */ c = bs->clusters_per_index_record; @@ -254,7 +257,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) else vol->indx_record_size = c << vol->cluster_size_bits; vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1; - ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size); + ntfs_log_debug("INDXRecordSize = 0x%x\n", + (unsigned)vol->indx_record_size); ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits); /* * Work out the size of the MFT mirror in number of mft records. If the diff --git a/libntfs/volume.c b/libntfs/volume.c index 9f1fe896..e004dea9 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -457,8 +457,8 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, if (br != -1) errno = EINVAL; if (!br) - ntfs_log_debug("Error: partition is smaller than bootsector " - "size. Weird!\n"); + ntfs_log_debug("Error: partition is smaller than " + "bootsector size. Weird!\n"); else ntfs_log_perror("Error reading bootsector"); goto error_exit; @@ -528,7 +528,8 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, vol->cluster_size; if (vol->mft_zone_start <= mft_lcn) vol->mft_zone_start = 0; - ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start); + ntfs_log_debug("mft_zone_start = 0x%llx\n", + (long long)vol->mft_zone_start); /* * Need to cap the mft zone on non-standard volumes so that it does From ef66794423f7e6cdab9fc496da33b9c0554d206b Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 20 Nov 2006 15:59:14 +0000 Subject: [PATCH 129/289] cleanups --- libntfs/volume.c | 62 ++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/libntfs/volume.c b/libntfs/volume.c index e004dea9..792ba2c6 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -117,7 +117,7 @@ static void __ntfs_volume_release(ntfs_volume *v) if (NDevDirty(dev)) dev->d_ops->sync(dev); if (dev->d_ops->close(dev)) - ntfs_log_perror("Failed to close the device. Error: "); + ntfs_log_perror("Failed to close the device"); } free(v->vol_name); free(v->upcase); @@ -164,12 +164,12 @@ static int ntfs_mft_load(ntfs_volume *vol) goto error_exit; } if (ntfs_is_baad_record(mb->magic)) { - ntfs_log_debug("Error: Incomplete multi sector transfer detected in " + ntfs_log_error("Incomplete multi sector transfer detected in " "$MFT.\n"); goto io_error_exit; } if (!ntfs_is_mft_record(mb->magic)) { - ntfs_log_debug("Error: $MFT has invalid magic.\n"); + ntfs_log_error("$MFT has invalid magic.\n"); goto io_error_exit; } ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL); @@ -179,14 +179,14 @@ static int ntfs_mft_load(ntfs_volume *vol) } if (p2n(ctx->attr) < p2n(mb) || (char*)ctx->attr > (char*)mb + vol->mft_record_size) { - ntfs_log_debug("Error: $MFT is corrupt.\n"); + ntfs_log_error("$MFT is corrupt.\n"); goto io_error_exit; } /* Find the $ATTRIBUTE_LIST attribute in $MFT if present. */ if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) { - ntfs_log_debug("Error: $MFT has corrupt attribute list.\n"); + ntfs_log_error("$MFT has corrupt attribute list.\n"); goto io_error_exit; } goto mft_has_no_attr_list; @@ -194,7 +194,7 @@ static int ntfs_mft_load(ntfs_volume *vol) NInoSetAttrList(vol->mft_ni); l = ntfs_get_attribute_value_length(ctx->attr); if (l <= 0 || l > 0x40000) { - ntfs_log_debug("Error: $MFT/$ATTRIBUTE_LIST has invalid length.\n"); + ntfs_log_error("$MFT/$ATTRIBUTE_LIST has invalid length.\n"); goto io_error_exit; } vol->mft_ni->attr_list_size = l; @@ -204,13 +204,13 @@ static int ntfs_mft_load(ntfs_volume *vol) l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list); if (!l) { - ntfs_log_debug("Error: failed to get value of " + ntfs_log_error("Failed to get value of " "$MFT/$ATTRIBUTE_LIST.\n"); goto io_error_exit; } if (l != vol->mft_ni->attr_list_size) { - ntfs_log_debug("Error: got unexpected amount of data when reading " - "$MFT/$ATTRIBUTE_LIST.\n"); + ntfs_log_error("Got unexpected amount of data when " + "reading $MFT/$ATTRIBUTE_LIST.\n"); goto io_error_exit; } mft_has_no_attr_list: @@ -240,17 +240,18 @@ mft_has_no_attr_list: a = ctx->attr; /* $MFT must be non-resident. */ if (!a->non_resident) { - ntfs_log_debug("$MFT must be non-resident but a resident " - "extent was found. $MFT is corrupt. Run " - "chkdsk.\n"); + ntfs_log_error("$MFT must be non-resident but a " + "resident extent was found. $MFT is " + "corrupt. Run chkdsk.\n"); goto io_error_exit; } /* $MFT must be uncompressed and unencrypted. */ if (a->flags & ATTR_COMPRESSION_MASK || a->flags & ATTR_IS_ENCRYPTED) { - ntfs_log_debug("$MFT must be uncompressed and unencrypted " - "but a compressed/encrypted extent was " - "found. $MFT is corrupt. Run chkdsk.\n"); + ntfs_log_error("$MFT must be uncompressed and " + "unencrypted but a compressed/encrypted" + " extent was found. $MFT is corrupt. " + "Run chkdsk.\n"); goto io_error_exit; } /* @@ -261,7 +262,8 @@ mft_has_no_attr_list: */ nrl = ntfs_mapping_pairs_decompress(vol, a, vol->mft_na->rl); if (!nrl) { - ntfs_log_perror("ntfs_mapping_pairs_decompress() failed"); + ntfs_log_perror("ntfs_mapping_pairs_decompress() " + "failed"); goto error_exit; } vol->mft_na->rl = nrl; @@ -276,21 +278,22 @@ mft_has_no_attr_list: /* Avoid endless loops due to corruption. */ if (next_vcn < sle64_to_cpu(a->lowest_vcn)) { - ntfs_log_debug("$MFT has corrupt attribute list attribute. " - "Run chkdsk.\n"); + ntfs_log_error("$MFT has corrupt attribute list " + "attribute. Run chkdsk.\n"); goto io_error_exit; } } if (!a) { - ntfs_log_debug("$MFT/$DATA attribute not found. $MFT is corrupt. Run " - "chkdsk.\n"); + ntfs_log_error("$MFT/$DATA attribute not found. " + "$MFT is corrupt. Run chkdsk.\n"); goto io_error_exit; } if (highest_vcn && highest_vcn != last_vcn - 1) { - ntfs_log_debug("Failed to load the complete runlist for $MFT/$DATA. " - "Bug or corrupt $MFT. Run chkdsk.\n"); - ntfs_log_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx\n", - (long long)highest_vcn, (long long)last_vcn - 1); + ntfs_log_error("Failed to load the complete runlist for " + "$MFT/$DATA. Bug or corrupt $MFT. " + "Run chkdsk.\n highest_vcn = 0x%llx, " + "last_vcn - 1 = 0x%llx\n", (long long) + highest_vcn, (long long)last_vcn - 1); goto io_error_exit; } /* Done with the $Mft mft record. */ @@ -319,6 +322,7 @@ error_exit: ntfs_inode_close(vol->mft_ni); vol->mft_ni = NULL; } + ntfs_log_error("Failed.\n"); errno = eo; return -1; } @@ -345,7 +349,8 @@ static int ntfs_mftmirr_load(ntfs_volume *vol) return -1; } /* Get an ntfs attribute for $MFTMirr/$DATA, too. */ - vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0); + vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, + AT_UNNAMED, 0); if (!vol->mftmirr_na) { ntfs_log_perror("Failed to open $MFTMirr/$DATA"); goto error_exit; @@ -1501,14 +1506,14 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) } if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { - ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION was not found " + ntfs_log_error("Attribute $VOLUME_INFORMATION was not found " "in $Volume!\n"); goto err_out; } a = ctx->attr; /* Sanity check. */ if (a->non_resident) { - ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION must be " + ntfs_log_error("Attribute $VOLUME_INFORMATION must be " "resident (and it isn't)!\n"); errno = EIO; goto err_out; @@ -1520,7 +1525,7 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) le32_to_cpu(ctx->mrec->bytes_in_use) || le16_to_cpu(a->value_offset) + le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) { - ntfs_log_debug("Error: Attribute $VOLUME_INFORMATION in $Volume is " + ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is " "corrupt!\n"); errno = EIO; goto err_out; @@ -1536,6 +1541,7 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) ret = 0; /* success */ err_out: ntfs_attr_put_search_ctx(ctx); + ntfs_log_error("Failed.\n"); return ret; } From a604622314292c7ae60e6186585a584d3d4a3af5 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 20 Nov 2006 16:21:57 +0000 Subject: [PATCH 130/289] Windows cares only about first 4 records in $MFTMirr and ignores everything beyond them. Update libntfs behaviour to be like in windows. Leave @mftmirr_size for case if will want to change something in the future. --- ChangeLog | 3 +++ libntfs/bootsect.c | 13 +++---------- libntfs/mft.c | 2 +- libntfs/volume.c | 38 ++++++++++++++------------------------ 4 files changed, 21 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index bfca64af..6114778b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -69,6 +69,9 @@ xx/xx/2006 - x.xx.x - . NTFS_MNT_CASE_SENSITIVE. (Yura) - Treat filenames in POSIX namespace as case insensitive in case of case insensitive mounts. (Anton, Yura) + - Windows cares only about first 4 records in $MFTMirr and ignores + everything beyond them. Update libntfs behaviour to be like in + windows. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/bootsect.c b/libntfs/bootsect.c index 6f4a3558..f2bafb4e 100644 --- a/libntfs/bootsect.c +++ b/libntfs/bootsect.c @@ -261,16 +261,9 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) (unsigned)vol->indx_record_size); ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits); /* - * Work out the size of the MFT mirror in number of mft records. If the - * cluster size is less than or equal to the size taken by four mft - * records, the mft mirror stores the first four mft records. If the - * cluster size is bigger than the size taken by four mft records, the - * mft mirror contains as many mft records as will fit into one - * cluster. + * Windows cares only about first 4 records in $MFTMirr and inores + * everything beyend them. */ - if (vol->cluster_size <= 4 * vol->mft_record_size) - vol->mftmirr_size = 4; - else - vol->mftmirr_size = vol->cluster_size / vol->mft_record_size; + vol->mftmirr_size = 4; return 0; } diff --git a/libntfs/mft.c b/libntfs/mft.c index 67b720e9..6ba963a6 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -169,7 +169,7 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, if (bw != -1) errno = EIO; if (bw >= 0) - ntfs_log_debug("Error: partial write while writing $Mft " + ntfs_log_error("Partial write while writing $Mft " "record(s)!\n"); else ntfs_log_perror("Error writing $Mft record(s)"); diff --git a/libntfs/volume.c b/libntfs/volume.c index 792ba2c6..3417bdf6 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -340,8 +340,7 @@ error_exit: */ static int ntfs_mftmirr_load(ntfs_volume *vol) { - int i; - runlist_element rl[2]; + int err; vol->mftmirr_ni = ntfs_inode_open(vol, FILE_MFTMirr); if (!vol->mftmirr_ni) { @@ -359,36 +358,27 @@ static int ntfs_mftmirr_load(ntfs_volume *vol) ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA"); goto error_exit; } - /* Construct the mft mirror runlist. */ - rl[0].vcn = 0; - rl[0].lcn = vol->mftmirr_lcn; - rl[0].length = (vol->mftmirr_size * vol->mft_record_size + - vol->cluster_size - 1) / vol->cluster_size; - rl[1].vcn = rl[0].length; - rl[1].lcn = LCN_ENOENT; - rl[1].length = 0; - /* Compare the two runlists. They must be identical. */ - i = 0; - do { - if (rl[i].vcn != vol->mftmirr_na->rl[i].vcn || - rl[i].lcn != vol->mftmirr_na->rl[i].lcn || - rl[i].length != vol->mftmirr_na->rl[i].length) { - ntfs_log_debug("Error: $MFTMirr location mismatch! Run " - "chkdsk.\n"); - errno = EIO; - goto error_exit; - } - } while (rl[i++].length); + /* Check $MFTMirr runlist. */ + if (vol->mftmirr_na->rl[0].lcn != vol->mftmirr_lcn || + vol->mftmirr_na->rl[0].length < (vol->mftmirr_size * + vol->mft_record_size + vol->cluster_size - 1) / + vol->cluster_size) { + ntfs_log_error("$MFTMirr location mismatch or first 4 records " + "are fragmented. Run chkdsk.\n"); + errno = EIO; + goto error_exit; + + } return 0; error_exit: - i = errno; + err = errno; if (vol->mftmirr_na) { ntfs_attr_close(vol->mftmirr_na); vol->mftmirr_na = NULL; } ntfs_inode_close(vol->mftmirr_ni); vol->mftmirr_ni = NULL; - errno = i; + errno = err; return -1; } From 0da86b6723c4514c320e6e1ce8291b1e5dc6489b Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 20 Nov 2006 17:30:13 +0000 Subject: [PATCH 131/289] port from ntfs-3g fixes to error cases in index code --- libntfs/index.c | 82 ++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index d38b074b..2103bb21 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -976,7 +976,7 @@ out: return vcn; } -static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) +static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) { INDEX_BLOCK *ib; INDEX_ENTRY *ie_last; @@ -1003,26 +1003,42 @@ static INDEX_BLOCK *ntfs_ir_to_ia(INDEX_ROOT *ir, VCN ib_vcn) ib->index.flags = ir->index.flags; ib->index.index_length = cpu_to_le32(i + le32_to_cpu(ib->index.entries_offset)); - /* - * Move the index root termination entry forward - */ + return ib; +} + +static void ntfs_ir_nill(INDEX_ROOT *ir) +{ + INDEX_ENTRY *ie_last; + char *ies_start, *ies_end; + + ntfs_log_trace("Entering\n"); + /* TODO: This function could be much simpler. */ + ies_start = (char *)ntfs_ie_get_first(&ir->index); + ies_end = (char *)ntfs_ie_get_end(&ir->index); + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); + /* Move the index root termination entry forward. */ if ((char *)ie_last > ies_start) { memmove(ies_start, (char *)ie_last, le16_to_cpu( ie_last->length)); ie_last = (INDEX_ENTRY *)ies_start; } - return ib; } static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, - INDEX_BLOCK *dst, INDEX_ENTRY *median, VCN new_vcn) + INDEX_ENTRY *median, VCN new_vcn) { u8 *ies_end; INDEX_ENTRY *ie_head; /* first entry after the median */ - int tail_size; + int tail_size, ret; + INDEX_BLOCK *dst; ntfs_log_trace("Entering.\n"); + dst = ntfs_ib_alloc(new_vcn, icx->block_size, + src->index.flags & NODE_MASK); + if (!dst) + return STATUS_ERROR; + ie_head = ntfs_ie_get_next(median); ies_end = (u8 *)ntfs_ie_get_end(&src->index); @@ -1032,10 +1048,10 @@ static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, dst->index.index_length = cpu_to_le32(tail_size + le32_to_cpu(dst->index.entries_offset)); - if (ntfs_ib_write(icx, new_vcn, dst)) - return STATUS_ERROR; + ret = ntfs_ib_write(icx, new_vcn, dst); - return STATUS_OK; + free(dst); + return ret; } static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, @@ -1109,11 +1125,16 @@ static int ntfs_ir_reparent(ntfs_index_context *icx) if (new_ib_vcn == -1) goto err_out; - ib = ntfs_ir_to_ia(ir, new_ib_vcn); - if (ib == NULL) { - ntfs_log_perror("Failed to create AT_INDEX_ALLOCATION"); - goto err_out; - } + ib = ntfs_ir_to_ib(ir, new_ib_vcn); + if (ib == NULL) { + ntfs_log_perror("Failed to move index root to index block"); + goto clear_bmp; + } + + if (ntfs_ib_write(icx, new_ib_vcn, ib)) + goto clear_bmp; + + ntfs_ir_nill(ir); ie = ntfs_ie_get_first(&ir->index); ie->flags |= INDEX_ENTRY_NODE; @@ -1132,14 +1153,14 @@ static int ntfs_ir_reparent(ntfs_index_context *icx) goto err_out; ntfs_inode_mark_dirty(ctx->ntfs_ino); - if (ntfs_ib_write(icx, new_ib_vcn, ib)) - goto err_out; - ret = STATUS_OK; err_out: ntfs_attr_put_search_ctx(ctx); free(ib); return ret; +clear_bmp: + ntfs_ibm_clear(icx, new_ib_vcn); + goto err_out; } /** @@ -1341,10 +1362,9 @@ err_out: */ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) { - INDEX_BLOCK *ib_new; INDEX_ENTRY *median; VCN new_vcn; - int ret, err = STATUS_ERROR; + int ret; ntfs_log_trace("Entering.\n"); @@ -1356,6 +1376,11 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) if (new_vcn == -1) return STATUS_ERROR; + if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { + ntfs_ibm_clear(icx, new_vcn); + return STATUS_ERROR; + } + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) ret = ntfs_ir_insert_median(icx, median, new_vcn); else @@ -1368,21 +1393,8 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) return ret; } - ib_new = ntfs_ib_alloc(new_vcn, icx->block_size, - ib->index.flags & NODE_MASK); - if (!ib_new) - return STATUS_ERROR; - - if (ntfs_ib_copy_tail(icx, ib, ib_new, median, new_vcn)) - goto free_ib_new; - - if (ntfs_ib_cut_tail(icx, ib, median)) - goto free_ib_new; - - err = STATUS_OK; -free_ib_new: - free(ib_new); - return err; + ret = ntfs_ib_cut_tail(icx, ib, median); + return ret; } static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) From c14589175f6700bc38049bca40b5863bedf0cede Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 20 Nov 2006 17:44:36 +0000 Subject: [PATCH 132/289] apply latest fixes from ntfs-3g to enddianess now everything should work on BE machines! --- libntfs/index.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index 2103bb21..a977200b 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -368,16 +368,16 @@ static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) ntfs_log_trace("Entering.\n"); - dup = ntfs_malloc(ie->length); - if (dup) - memcpy(dup, ie, ie->length); + dup = ntfs_malloc(le16_to_cpu(ie->length)); + if (dup) + memcpy(dup, ie, le16_to_cpu(ie->length)); return dup; } static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) { INDEX_ENTRY *dup; - int size = ie->length; + int size = le16_to_cpu(ie->length); ntfs_log_trace("Entering.\n"); @@ -388,7 +388,7 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) if (dup) { memcpy(dup, ie, size); dup->flags &= ~INDEX_ENTRY_NODE; - dup->length = size; + dup->length = cpu_to_le16(size); } return dup; } @@ -795,7 +795,7 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, INDEX_BLOCK *ib; int ih_size = sizeof(INDEX_HEADER); - ntfs_log_trace("Entering ib_vcn = %lld ib_size = %d\n", ib_vcn, + ntfs_log_trace("Entering ib_vcn = %lld ib_size = %u\n", ib_vcn, ib_size); ib = ntfs_calloc(ib_size); @@ -1069,10 +1069,11 @@ static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *src, if (ie_last->flags & INDEX_ENTRY_NODE) ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); - memcpy(ie, ie_last, ie_last->length); - - src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + - ie->length + le32_to_cpu(src->index.entries_offset)); + memcpy(ie, ie_last, le16_to_cpu(ie_last->length)); + + src->index.index_length = cpu_to_le32(((char *)ie - ies_start) + + le16_to_cpu(ie->length) + + le32_to_cpu(src->index.entries_offset)); if (ntfs_ib_write(icx, icx->parent_vcn[icx->pindex + 1], src)) return STATUS_ERROR; @@ -1237,8 +1238,8 @@ static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) { INDEX_ENTRY *p, *old = *ie; - old->length += sizeof(VCN); - p = realloc(old, old->length); + old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN)); + p = realloc(old, le16_to_cpu(old->length)); if (!p) return STATUS_ERROR; @@ -1294,7 +1295,8 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, ntfs_log_trace("Entering.\n"); - new_size = le32_to_cpu(icx->ir->index.index_length) + median->length; + new_size = le32_to_cpu(icx->ir->index.index_length) + + le16_to_cpu(median->length); if (!(median->flags & INDEX_ENTRY_NODE)) new_size += sizeof(VCN); @@ -1335,7 +1337,7 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) idx_size = le32_to_cpu(ib->index.index_length); allocated_size = le32_to_cpu(ib->index.allocated_size); /* FIXME: sizeof(VCN) should be included only if ie has no VCN */ - if (idx_size + ie->length + sizeof(VCN) > allocated_size) { + if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) { err = ntfs_ib_split(icx, ib); if (err == STATUS_OK) err = STATUS_KEEP_SEARCHING; @@ -1544,9 +1546,10 @@ static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) ie = ntfs_ie_get_first(ih); ie->flags &= ~INDEX_ENTRY_NODE; - ie->length -= sizeof(VCN); - - ih->index_length -= sizeof(VCN); + ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN)); + + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - + sizeof(VCN)); ih->flags &= ~LARGE_INDEX; /* Not fatal error */ @@ -1691,7 +1694,7 @@ descend: else ih = &icx->ib->index; - delta = ie->length - icx->entry->length; + delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length); new_size = le32_to_cpu(ih->index_length) + delta; if (delta > 0) { if (icx->is_in_root) { @@ -1701,11 +1704,9 @@ descend: " during entry removal"); goto out2; } - ih = &icx->ir->index; entry = ntfs_ie_get_by_pos(ih, entry_pos); - - } else if (new_size > ih->allocated_size) { + } else if (new_size > le32_to_cpu(ih->allocated_size)) { errno = EOPNOTSUPP; ntfs_log_perror("Denied to split INDEX_BLOCK during " "entry removal"); From b538578ab788bc5be5598608495ed86f83ea6efe Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 21 Nov 2006 15:31:09 +0000 Subject: [PATCH 133/289] Fix free clusters and MFT records calculation --- ChangeLog | 1 + ntfsprogs/ntfsmount.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6114778b..c5c243bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -72,6 +72,7 @@ xx/xx/2006 - x.xx.x - . - Windows cares only about first 4 records in $MFTMirr and ignores everything beyond them. Update libntfs behaviour to be like in windows. (Yura) + - Fix free clusters and MFT records calculation. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 25605e69..11f14d6d 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -141,10 +141,9 @@ static __inline__ int ntfs_fuse_is_named_data_stream(const char *path) return 0; } -static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) +static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free) { u8 *buf; - long nr_free = 0; s64 br, total = 0; if (!(ctx->state & NF_FreeMFTOutdate)) @@ -162,8 +161,8 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) total += br; for (i = 0; i < br; i++) for (j = 0; j < 8; j++) - if (!((buf[i] >> j) & 1)) - nr_free++; + if ((buf[i] >> j) & 1) + nr_free--; } free(buf); if (!total || br < 0) @@ -176,7 +175,7 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol) static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) { u8 *buf; - long nr_free = 0; + long nr_free = vol->nr_clusters; s64 br, total = 0; if (!(ctx->state & NF_FreeClustersOutdate)) @@ -194,8 +193,8 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) total += br; for (i = 0; i < br; i++) for (j = 0; j < 8; j++) - if (!((buf[i] >> j) & 1)) - nr_free++; + if ((buf[i] >> j) & 1) + nr_free--; } free(buf); if (!total || br < 0) @@ -247,9 +246,10 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), /* Free blocks avail to non-superuser, same as above on NTFS. */ sfs->f_bavail = sfs->f_bfree = size; /* Number of inodes in file system (at this point in time). */ - sfs->f_files = vol->mft_na->data_size >> vol->mft_record_size_bits; + size = vol->mft_na->data_size >> vol->mft_record_size_bits; + sfs->f_files = size; /* Free inodes in fs (based on current total count). */ - size = ntfs_fuse_get_nr_free_mft_records(vol); + size = ntfs_fuse_get_nr_free_mft_records(vol, size); if (size < 0) size = 0; sfs->f_ffree = size; From 4adc3817c61082df14219d4243e1a9c28fc1cf47 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 21 Nov 2006 15:40:56 +0000 Subject: [PATCH 134/289] ntfsmount: always accept {f,d,}mask in octal to be as mount command --- ntfsprogs/ntfsmount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 11f14d6d..2fbdf358 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1506,7 +1506,7 @@ static char *parse_mount_options(const char *org_options) "value.\n"); goto err_exit; } - sscanf(val, "%i", &ctx->fmask); + sscanf(val, "%o", &ctx->fmask); ctx->dmask = ctx->fmask; } else if (!strcmp(opt, "fmask")) { if (!val) { @@ -1514,14 +1514,14 @@ static char *parse_mount_options(const char *org_options) "value.\n"); goto err_exit; } - sscanf(val, "%i", &ctx->fmask); + sscanf(val, "%o", &ctx->fmask); } else if (!strcmp(opt, "dmask")) { if (!val) { ntfs_log_error("'dmask' option should have " "value.\n"); goto err_exit; } - sscanf(val, "%i", &ctx->dmask); + sscanf(val, "%o", &ctx->dmask); } else if (!strcmp(opt, "uid")) { if (!val) { ntfs_log_error("'uid' option should have " From 05a034e423b748ae1d34ba522459695672f11d8d Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 21 Nov 2006 16:24:37 +0000 Subject: [PATCH 135/289] fix st_blocks calculation --- ChangeLog | 3 ++- ntfsprogs/ntfsmount.c | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index c5c243bc..755d6724 100644 --- a/ChangeLog +++ b/ChangeLog @@ -72,7 +72,8 @@ xx/xx/2006 - x.xx.x - . - Windows cares only about first 4 records in $MFTMirr and ignores everything beyond them. Update libntfs behaviour to be like in windows. (Yura) - - Fix free clusters and MFT records calculation. (Yura) + - ntfsmount: Fix free clusters and MFT records calculation. (Yura) + - ntfsmount: Fix st_blocks calculation. (Yuval, Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 2fbdf358..b25bb6b9 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -322,8 +322,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (na) { stbuf->st_size = na->data_size; - stbuf->st_blocks = na->allocated_size >> - vol->sector_size_bits; + stbuf->st_blocks = na->allocated_size >> 9; ntfs_attr_close(na); } else { stbuf->st_size = 0; @@ -334,7 +333,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) /* Regular or Interix (INTX) file. */ stbuf->st_mode = S_IFREG; stbuf->st_size = ni->data_size; - stbuf->st_blocks = ni->allocated_size >> vol->sector_size_bits; + stbuf->st_blocks = ni->allocated_size >> 9; stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { na = ntfs_attr_open(ni, AT_DATA, stream_name, @@ -346,8 +345,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } if (stream_name_len) { stbuf->st_size = na->data_size; - stbuf->st_blocks = na->allocated_size >> - vol->sector_size_bits; + stbuf->st_blocks = ni->allocated_size >> 9; } /* Check whether it's Interix FIFO or socket. */ if (!(ni->flags & FILE_ATTR_HIDDEN) && From 18c8f75c7b2f4b6075d4d9690549d0d98bfb259f Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 22 Nov 2006 18:28:13 +0000 Subject: [PATCH 136/289] make ntfs_attr_rm to always close attribute (both on success and failure) --- libntfs/attrib.c | 15 +++++++++------ libntfs/dir.c | 4 +--- ntfsprogs/ntfsmount.c | 8 ++------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 0ac4bd8f..1b9f89e5 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -3131,12 +3131,10 @@ add_attr_record: (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) { err = errno; ntfs_log_trace("Failed to initialize just added attribute.\n"); - if (ntfs_attr_rm(na)) { + if (ntfs_attr_rm(na)) ntfs_log_trace("Failed to remove just added attribute. " "Probably leaving inconsistent " "metadata.\n"); - ntfs_attr_close(na); - } goto err_out; } ntfs_attr_close(na); @@ -3168,7 +3166,8 @@ err_out: * @na: opened ntfs attribute to delete * * Remove attribute and all it's extents from ntfs inode. If attribute was non - * resident also free all clusters allocated by attribute. + * resident also free all clusters allocated by attribute. This function always + * closes @na upon exit (both on success and failure). * * Return 0 on success or -1 on error with errno set to the error code. */ @@ -3188,8 +3187,10 @@ int ntfs_attr_rm(ntfs_attr *na) /* Free cluster allocation. */ if (NAttrNonResident(na)) { - if (ntfs_attr_map_whole_runlist(na)) + if (ntfs_attr_map_whole_runlist(na)) { + ntfs_attr_close(na); return -1; + } if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { ntfs_log_trace("Failed to free cluster allocation. " "Leaving inconsistent metadata.\n"); @@ -3199,8 +3200,10 @@ int ntfs_attr_rm(ntfs_attr *na) /* Search for attribute extents and remove them all. */ ctx = ntfs_attr_get_search_ctx(na->ni, NULL); - if (!ctx) + if (!ctx) { + ntfs_attr_close(na); return -1; + } while (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (ntfs_attr_record_rm(ctx)) { diff --git a/libntfs/dir.c b/libntfs/dir.c index c6b562f1..2ef06ab6 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1359,12 +1359,10 @@ err_out: ntfs_log_perror("Failed to open SD (0x50) attribute of " " inode 0x%llx. Run chkdsk.\n", (unsigned long long)ni->mft_no); - else if (ntfs_attr_rm(na)) { + else if (ntfs_attr_rm(na)) ntfs_log_perror("Failed to remove SD (0x50) attribute " "of inode 0x%llx. Run chkdsk.\n", (unsigned long long)ni->mft_no); - ntfs_attr_close(na); - } } if (rollback_data) { ntfs_attr *na; diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index b25bb6b9..17eccb41 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -981,10 +981,8 @@ static int ntfs_fuse_rm_stream(const char *path, ntfschar *stream_name, res = -errno; goto exit; } - if (ntfs_attr_rm(na)) { + if (ntfs_attr_rm(na)) res = -errno; - ntfs_attr_close(na); - } exit: if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode"); @@ -1322,7 +1320,6 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) ntfschar *lename = NULL; int res = 0, lename_len; - if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || @@ -1347,8 +1344,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) ntfs_fuse_mark_free_space_outdated(); if (ntfs_attr_rm(na)) res = -errno; - else - na = NULL; + na = NULL; exit: if (na) ntfs_attr_close(na); From 668780d84da737c35a1e87763995b738aae6bf42 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 14:28:47 +0000 Subject: [PATCH 137/289] bot more verbose debug --- libntfs/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libntfs/inode.c b/libntfs/inode.c index 1f96c982..a82ebdc0 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -456,7 +456,9 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni) if (!ntfs_extent_inode_open(ni, MREF_LE(ale->mft_reference))) { ntfs_log_trace("Couldn't attach extent " - "inode.\n"); + "inode (attr type 0x%x " + "references to it).\n", + le32_to_cpu(ale->type)); return -1; } prev_attached = MREF_LE(ale->mft_reference); From 4b7868ddc23c89df6fbe43b0da488b1f56101637 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 14:57:54 +0000 Subject: [PATCH 138/289] ntfsmount: Umount volume in DESTROY. This is guarantees that all data would be s ynced before umount return for volumes mounted with blkdev option. Thanks to Miklos for information about blkdev. --- ChangeLog | 3 +++ ntfsprogs/ntfsmount.c | 33 +++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 755d6724..fedec596 100644 --- a/ChangeLog +++ b/ChangeLog @@ -74,6 +74,9 @@ xx/xx/2006 - x.xx.x - . windows. (Yura) - ntfsmount: Fix free clusters and MFT records calculation. (Yura) - ntfsmount: Fix st_blocks calculation. (Yuval, Yura) + - ntfsmount: Umount volume in DESTROY. This is guarantees that all + data would be synced before umount return for volumes mounted with + blkdev option. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 17eccb41..1a0e15fd 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1356,6 +1356,18 @@ exit: #endif /* HAVE_SETXATTR */ +static void ntfs_fuse_destroy(void *priv __attribute__((unused))) +{ + if (ctx->vol) { + ntfs_log_info("Unmounting %s (%s)\n", opts.device, + ctx->vol->vol_name); + if (ntfs_umount(ctx->vol, FALSE)) + ntfs_log_perror("Failed to unmount volume"); + } + free(ctx); + free(opts.device); +} + static struct fuse_operations ntfs_fuse_oper = { .getattr = ntfs_fuse_getattr, .readlink = ntfs_fuse_readlink, @@ -1375,6 +1387,7 @@ static struct fuse_operations ntfs_fuse_oper = { .mkdir = ntfs_fuse_mkdir, .rmdir = ntfs_fuse_rmdir, .utime = ntfs_fuse_utime, + .destroy = ntfs_fuse_destroy, #ifdef HAVE_SETXATTR .getxattr = ntfs_fuse_getxattr, .setxattr = ntfs_fuse_setxattr, @@ -1415,17 +1428,6 @@ static int ntfs_fuse_mount(const char *device) return 0; } -static void ntfs_fuse_destroy(void) -{ - if (ctx->vol) { - ntfs_log_info("Unmounting %s (%s)\n", opts.device, - ctx->vol->vol_name); - if (ntfs_umount(ctx->vol, FALSE)) - ntfs_log_perror("Failed to unmount volume"); - } - free(ctx); - free(opts.device); -} static void signal_handler(int arg __attribute__((unused))) { @@ -1776,13 +1778,13 @@ int main(int argc, char *argv[]) parsed_options = parse_mount_options((opts.options) ? opts.options : ""); if (!parsed_options) { - ntfs_fuse_destroy(); + ntfs_fuse_destroy(NULL); return 3; } /* Mount volume. */ if (ntfs_fuse_mount(opts.device)) { - ntfs_fuse_destroy(); + ntfs_fuse_destroy(NULL); free(parsed_options); return 4; } @@ -1796,7 +1798,7 @@ int main(int argc, char *argv[]) free(parsed_options); if (!fch) { ntfs_log_error("fuse_mount failed.\n"); - ntfs_fuse_destroy(); + ntfs_fuse_destroy(NULL); return 5; } fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ @@ -1818,7 +1820,7 @@ int main(int argc, char *argv[]) if (!fh) { ntfs_log_error("fuse_new failed.\n"); fuse_unmount(opts.mnt_point, fch); - ntfs_fuse_destroy(); + ntfs_fuse_destroy(NULL); return 6; } if (!ctx->debug && !ctx->no_detach) { @@ -1841,6 +1843,5 @@ int main(int argc, char *argv[]) /* Destroy. */ fuse_unmount(opts.mnt_point, fch); fuse_destroy(fh); - ntfs_fuse_destroy(); return 0; } From 8df298aec278a3e6fc76c416d1d4ab8d430febfa Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 17:37:37 +0000 Subject: [PATCH 139/289] Introduce MNT_NTFS_NOT_EXCLUSIVE mount option that tells libntfs do not open volume exclusively. Useful if libntfs user cares about this himself, eg. FUSE with blkdev option. --- ChangeLog | 3 +++ include/ntfs/volume.h | 1 + libntfs/unix_io.c | 15 +++++---------- libntfs/volume.c | 6 +++++- ntfsprogs/ntfsmount.c | 5 +++-- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index fedec596..140e561e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,6 +77,9 @@ xx/xx/2006 - x.xx.x - . - ntfsmount: Umount volume in DESTROY. This is guarantees that all data would be synced before umount return for volumes mounted with blkdev option. (Yura) + - Introduce MNT_NTFS_NOT_EXCLUSIVE mount option that tells libntfs do + not open volume exclusively. Useful if libntfs user cares about this + himself, eg. FUSE with blkdev option. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index ba8cf3e3..96ace852 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -59,6 +59,7 @@ typedef enum { NTFS_MNT_RDONLY = 1, NTFS_MNT_NOATIME = 2, NTFS_MNT_CASE_SENSITIVE = 4, + NTFS_MNT_NOT_EXCLUSIVE = 8, } ntfs_mount_flags; /** diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index 4080147d..048791e0 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -88,12 +88,6 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) } if (!(dev->d_private = ntfs_malloc(sizeof(int)))) return -1; - /* - * Open the device/file obtaining the file descriptor for exclusive - * access (but only if mounting r/w). - */ - if ((flags & O_RDWR) == O_RDWR) - flags |= O_EXCL; *(int*)dev->d_private = open(dev->d_name, flags); if (*(int*)dev->d_private == -1) { err = errno; @@ -112,11 +106,12 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) flk.l_start = flk.l_len = 0LL; if (fcntl(DEV_FD(dev), F_SETLK, &flk)) { err = errno; - ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s for %s\n", - dev->d_name, NDevReadOnly(dev) ? "reading" : "writing"); + ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s " + "for %s\n", dev->d_name, NDevReadOnly(dev) ? + "reading" : "writing"); if (close(DEV_FD(dev))) - ntfs_log_perror("ntfs_device_unix_io_open: Warning: Could not " - "close %s", dev->d_name); + ntfs_log_perror("ntfs_device_unix_io_open: Warning: " + "Could not close %s", dev->d_name); goto err_out; } /* Determine if device is a block device or not, ignoring errors. */ diff --git a/libntfs/volume.c b/libntfs/volume.c index 3417bdf6..3901853e 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -438,7 +438,9 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, if (flags & NTFS_MNT_CASE_SENSITIVE) NVolSetCaseSensitive(vol); ntfs_log_debug("Reading bootsector... "); - if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { + if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY : + ((flags & NTFS_MNT_NOT_EXCLUSIVE) ? O_RDWR : + (O_RDWR | O_EXCL)))) { ntfs_log_debug(FAILED); ntfs_log_perror("Error opening partition device"); goto error_exit; @@ -752,6 +754,7 @@ out: * NTFS_MNT_NOATIME - do not update access time * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if * they are not in POSIX namespace + * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively * * The function opens the device @dev and verifies that it contains a valid * bootsector. Then, it allocates an ntfs_volume structure and initializes @@ -1150,6 +1153,7 @@ error_exit: * NTFS_MNT_NOATIME - do not update access time * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if * they are not in POSIX namespace + * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively * * The function opens the device or file @name and verifies that it contains a * valid bootsector. Then, it allocates an ntfs_volume structure and initializes diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 1a0e15fd..75c5500e 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1418,8 +1418,9 @@ static int ntfs_fuse_mount(const char *device) ntfs_volume *vol; vol = utils_mount_volume(device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | - ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) /*| - NTFS_MNT_CASE_SENSITIVE*/, ctx->force); + ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) | + NTFS_MNT_NOT_EXCLUSIVE /*| NTFS_MNT_CASE_SENSITIVE*/, + ctx->force); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; From 3cd59df400c03b4954619c840dfffe40fc70bed9 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 18:38:47 +0000 Subject: [PATCH 140/289] bit more nice error messages --- ntfsprogs/ntfsinfo.c | 3 +-- ntfsprogs/utils.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index d8754524..91e34f0a 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -2206,8 +2206,7 @@ int main(int argc, char **argv) vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); if (!vol) { - printf("Failed to open '%s': %s\n", opts.device, - strerror(errno)); + printf("Failed to open '%s'.\n", opts.device); exit(1); } diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 978fbc5e..8ae69a7d 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -96,7 +96,7 @@ static const char *hibernated_volume_msg = "off properly, so mounting could be done safely.\n"; static const char *unclean_journal_msg = -"Mount is denied because the NTFS journal file is unclean. Choices are:\n" +"Access is denied because the NTFS journal file is unclean. Choices are:\n" " A) Shutdown Windows properly.\n" " B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n" " notification area before disconnecting the device.\n" @@ -108,7 +108,7 @@ static const char *unclean_journal_msg = " F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n"; static const char *opened_volume_msg = -"Mount is denied because the NTFS volume is already exclusively opened.\n" +"Access is denied because the NTFS volume is already exclusively opened.\n" "The volume may be already mounted, or another software may use it which\n" "could be identified for example by the help of the 'fuser' command.\n"; From f12f4aefb79c1015e7a5e6e0f29fdbc45d3025be Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 21:10:35 +0000 Subject: [PATCH 141/289] ntfs_log_error("Failed.\n") is evil. TODO: Implement ntfs_log_errortrace --- libntfs/dir.c | 4 ++-- libntfs/volume.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 2ef06ab6..4f08956c 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1657,7 +1657,7 @@ out: if (ni) ntfs_inode_close(ni); if (err) { - ntfs_log_error("Failed.\n"); + ntfs_log_error("%s(): Failed.\n", __FUNCTION__); errno = err; return -1; } @@ -1755,7 +1755,7 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) rollback_failed: ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n"); err_out: - ntfs_log_error("Failed.\n"); + ntfs_log_error("%s(): Failed.\n", __FUNCTION__); free(fn); errno = err; return -1; diff --git a/libntfs/volume.c b/libntfs/volume.c index 3901853e..d9eb75ef 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -322,7 +322,7 @@ error_exit: ntfs_inode_close(vol->mft_ni); vol->mft_ni = NULL; } - ntfs_log_error("Failed.\n"); + ntfs_log_error("%s(): Failed.\n", __FUNCTION__); errno = eo; return -1; } @@ -1535,7 +1535,7 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) ret = 0; /* success */ err_out: ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("Failed.\n"); + ntfs_log_error("%s(): Failed.\n", __FUNCTION__); return ret; } From f738f39bdf92f65a3ee2b325844c6fae2c141de3 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 21:35:39 +0000 Subject: [PATCH 142/289] oops, introduced stupiedness during one of recent cleanups --- libntfs/volume.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libntfs/volume.c b/libntfs/volume.c index d9eb75ef..e3d08c17 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -1535,7 +1535,8 @@ int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) ret = 0; /* success */ err_out: ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("%s(): Failed.\n", __FUNCTION__); + if (ret) + ntfs_log_error("%s(): Failed.\n", __FUNCTION__); return ret; } From fbfbe3b48ea4b3d0ad238f8d8868c146316316b0 Mon Sep 17 00:00:00 2001 From: yura Date: Sat, 25 Nov 2006 21:44:35 +0000 Subject: [PATCH 143/289] force distro developers to fix their broken init scripts --- ntfsprogs/ntfsmount.c | 17 ++++++++++++++++- ntfsprogs/utils.c | 7 ++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 75c5500e..67f89ccc 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -101,6 +101,7 @@ typedef struct { BOOL debug; BOOL noatime; BOOL no_detach; + BOOL leave_dirty; } ntfs_fuse_context_t; typedef enum { @@ -1359,6 +1360,10 @@ exit: static void ntfs_fuse_destroy(void *priv __attribute__((unused))) { if (ctx->vol) { + if (!ctx->leave_dirty && ntfs_volume_write_flags(ctx->vol, + ctx->vol->flags & ~VOLUME_IS_DIRTY)) + ntfs_log_error("Failed to clear volume dirty flag. " + "OK, leave it, chkdsk will handle.\n"); ntfs_log_info("Unmounting %s (%s)\n", opts.device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) @@ -1426,10 +1431,20 @@ static int ntfs_fuse_mount(const char *device) return -1; } ctx->vol = vol; + if (vol->flags & VOLUME_IS_DIRTY) + ctx->leave_dirty = TRUE; + else { + if (ntfs_volume_write_flags(vol, vol->flags | + VOLUME_IS_DIRTY)) { + ntfs_log_perror("Failed to set temporary dirty flag"); + ntfs_umount(vol, FALSE); + ctx->vol = NULL; + return -1; + } + } return 0; } - static void signal_handler(int arg __attribute__((unused))) { fuse_exit((fuse_get_context())->fuse); diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 8ae69a7d..807d789e 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -114,7 +114,12 @@ static const char *opened_volume_msg = static const char *dirty_volume_msg = "Volume is scheduled for check.\n" -"Please boot into Windows TWICE, or use the 'force' option.\n"; +"Please boot into Windows TWICE, or use the 'force' option.\n" +"NOTE: If you had not scheduled check and last time accessed this volume\n" +"using ntfsmount and shutdown system properly, then init scripts in your\n" +"distribution are broken. Please report to your distribution developers\n" +"(NOT to us!) that init scripts kill ntfsmount or mount.ntfs-fuse during\n" +"shutdown instead of proper umount.\n"; /** * utils_set_locale From 5302d23f7bf303be59a554fd63d4b2581199a8c5 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 28 Nov 2006 10:09:56 +0000 Subject: [PATCH 144/289] - Empty the journal at mount time. (Anton) - Set the volume dirty bit at mount time (if it is not set already and clear it again at umount time but only if it was not set to start with. (Anton) --- ChangeLog | 4 ++ include/ntfs/volume.h | 16 ++++++++ libntfs/volume.c | 35 ++++++++++++++++-- ntfsprogs/ntfscat.c | 14 +++++-- ntfsprogs/ntfscat.h | 1 + ntfsprogs/ntfsclone.c | 14 ++++--- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsdump_logfile.c | 2 +- ntfsprogs/ntfsfix.c | 72 +++++++----------------------------- ntfsprogs/ntfsinfo.c | 2 +- ntfsprogs/ntfsmount.c | 16 -------- ntfsprogs/ntfsmove.c | 5 +-- ntfsprogs/ntfsresize.c | 29 +++------------ ntfsprogs/ntfswipe.c | 2 +- ntfsprogs/utils.c | 2 +- 15 files changed, 96 insertions(+), 120 deletions(-) diff --git a/ChangeLog b/ChangeLog index 140e561e..c08c0adc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -80,6 +80,10 @@ xx/xx/2006 - x.xx.x - . - Introduce MNT_NTFS_NOT_EXCLUSIVE mount option that tells libntfs do not open volume exclusively. Useful if libntfs user cares about this himself, eg. FUSE with blkdev option. (Yura) + - Empty the journal at mount time. (Anton) + - Set the volume dirty bit at mount time (if it is not set already and + clear it again at umount time but only if it was not set to start + with. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 96ace852..ef79e3b9 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -60,6 +60,10 @@ typedef enum { NTFS_MNT_NOATIME = 2, NTFS_MNT_CASE_SENSITIVE = 4, NTFS_MNT_NOT_EXCLUSIVE = 8, + NTFS_MNT_FORENSIC = 16, /* Mount for forensic purposes, i.e. do + not do any writing at all during the + mount, i.e. no journal emptying, no + dirty bit setting, etc. */ } ntfs_mount_flags; /** @@ -85,6 +89,10 @@ typedef enum { NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */ NV_LogFileEmpty, /* 1: $logFile journal is empty. */ NV_NoATime, /* 1: Do not update access time. */ + NV_WasDirty, /* 1: Volume was marked dirty before we mounted + it. */ + NV_ForensicMount, /* 1: Mount is forensic, i.e. no modifications + are to be done by mount/umount. */ } ntfs_volume_state_bits; #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) @@ -107,6 +115,14 @@ typedef enum { #define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime) #define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime) +#define NVolWasDirty(nv) test_nvol_flag(nv, WasDirty) +#define NVolSetWasDirty(nv) set_nvol_flag(nv, WasDirty) +#define NVolClearWasDirty(nv) clear_nvol_flag(nv, WasDirty) + +#define NVolForensicMount(nv) test_nvol_flag(nv, ForensicMount) +#define NVolSetForensicMount(nv) set_nvol_flag(nv, ForensicMount) +#define NVolClearForensicMount(nv) clear_nvol_flag(nv, ForensicMount) + /* * NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 2.x is used by Windows 2000 Beta diff --git a/libntfs/volume.c b/libntfs/volume.c index e3d08c17..77cc3c75 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -89,6 +89,14 @@ ntfs_volume *ntfs_volume_alloc(void) */ static void __ntfs_volume_release(ntfs_volume *v) { + /* + * Clear the dirty bit if it was not set before we mounted and this is + * not a forensic mount. + */ + if (!NVolReadOnly(v) && !NVolWasDirty(v) && !NVolForensicMount(v)) { + v->flags &= ~VOLUME_IS_DIRTY; + (void)ntfs_volume_write_flags(v, v->flags); + } if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni)) ntfs_inode_sync(v->lcnbmp_ni); if (v->vol_ni) @@ -788,7 +796,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) ntfs_log_perror("Failed to startup volume"); return NULL; } - + /* Record whether this is a forensic mount. */ + if (flags & NTFS_MNT_FORENSIC) + NVolSetForensicMount(vol); /* Load data from $MFT and $MFTMirr and compare the contents. */ m = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); m2 = (u8*)ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); @@ -1002,9 +1012,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) /* Setup vol from the volume information attribute value. */ vol->major_ver = vinf->major_ver; vol->minor_ver = vinf->minor_ver; - /* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are - defined using cpu_to_le16() macro and hence are consistent. */ + /* + * Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are defined + * using cpu_to_le16() macro and hence are consistent. + */ vol->flags = vinf->flags; + /* Record whether the volume was dirty or not. */ + if (vol->flags & VOLUME_IS_DIRTY) + NVolSetWasDirty(vol); /* * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup. */ @@ -1116,12 +1131,26 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) /* * Check for dirty logfile and hibernated Windows. * We care only about read-write mounts. + * + * If all is ok, reset the logfile and set the dirty bit on the volume. + * + * But do not do that if this is a FORENSIC mount. */ if (!(flags & NTFS_MNT_RDONLY)) { if (ntfs_volume_check_logfile(vol) < 0) goto error_exit; if (ntfs_volume_check_hiberfile(vol) < 0) goto error_exit; + if (!NVolForensicMount(vol)) { + if (ntfs_logfile_reset(vol) < 0) + goto error_exit; + if (!NVolWasDirty(vol)) { + vol->flags |= VOLUME_IS_DIRTY; + if (ntfs_volume_write_flags(vol, vol->flags) < + 0) + goto error_exit; + } + } } return vol; diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index d584bd4f..57d2af69 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -86,7 +86,8 @@ static void usage(void) " -q, --quiet Less output\n" " -V, --version Version information\n" " -v, --verbose More output\n\n", - //" -r --raw Display the compressed or encrypted file", +// Does not work for compressed files at present so leave undocumented... +// " -r --raw Display the raw data (e.g. for compressed or encrypted file)", EXEC_NAME); ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); } @@ -156,7 +157,7 @@ static int parse_attribute(const char *value, ATTR_TYPES *attr) */ static int parse_options(int argc, char **argv) { - static const char *sopt = "-a:fh?i:n:qVv"; + static const char *sopt = "-a:fh?i:n:qVvr"; static const struct option lopt[] = { { "attribute", required_argument, NULL, 'a' }, { "attribute-name", required_argument, NULL, 'n' }, @@ -166,6 +167,7 @@ static int parse_options(int argc, char **argv) { "quiet", no_argument, NULL, 'q' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, + { "raw", no_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } }; @@ -247,6 +249,9 @@ static int parse_options(int argc, char **argv) opts.verbose++; ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); break; + case 'r': + opts.raw = TRUE; + break; default: ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); err++; @@ -349,10 +354,11 @@ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, offset = 0; for (;;) { - if (block_size > 0) { + if (!opts.raw && block_size > 0) { // These types have fixup bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer); - bytes_read *= block_size; + if (bytes_read > 0) + bytes_read *= block_size; } else { bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer); } diff --git a/ntfsprogs/ntfscat.h b/ntfsprogs/ntfscat.h index 75b2b068..cf474b48 100644 --- a/ntfsprogs/ntfscat.h +++ b/ntfsprogs/ntfscat.h @@ -38,6 +38,7 @@ struct options { int force; /* Override common sense */ int quiet; /* Less output */ int verbose; /* Extra output */ + BOOL raw; /* Raw data output */ }; #endif /* _NTFSCAT_H_ */ diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 474fa881..54d3a5e0 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1388,7 +1388,7 @@ static void mount_volume(unsigned long new_mntflag) exit(1); } - if (vol->flags & VOLUME_IS_DIRTY) + if (NVolWasDirty(vol)) if (opt.force-- <= 0) err_exit(dirty_volume_msg, opt.volume); @@ -1538,17 +1538,18 @@ static s64 open_image(void) if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0) err_exit("Input file is not an image! (invalid magic)\n"); if (image_hdr.major_ver < NTFSCLONE_IMG_VER_MAJOR_ENDIANNESS_SAFE) { - Printf("Old image format detected. Byteswapping on big " - "endian architectures. If the image was " - "created on a little endian architecture it " - "will not work. Use a more recent version " - "of ntfsclone to recreate the image.\n"); image_hdr.major_ver = NTFSCLONE_IMG_VER_MAJOR; image_hdr.minor_ver = NTFSCLONE_IMG_VER_MINOR; +#if (__BYTE_ORDER == __BIG_ENDIAN) + Printf("Old image format detected. If the image was created " + "on a little endian architecture it will not " + "work. Use a more recent version of " + "ntfsclone to recreate the image.\n"); image_hdr.cluster_size = cpu_to_le32(image_hdr.cluster_size); image_hdr.device_size = cpu_to_sle64(image_hdr.device_size); image_hdr.nr_clusters = cpu_to_sle64(image_hdr.nr_clusters); image_hdr.inuse = cpu_to_sle64(image_hdr.inuse); +#endif image_hdr.offset_to_image_data = const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); image_is_host_endian = TRUE; @@ -1764,6 +1765,7 @@ int main(int argc, char **argv) device_size = open_volume(); ntfs_size = vol->nr_clusters * vol->cluster_size; } + // FIXME: This needs to be the cluster size... ntfs_size += 512; /* add backup boot sector */ if (opt.std_out) { diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 74d327cd..c53ca0fe 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -352,7 +352,7 @@ int main(int argc, char *argv[]) return 1; } - if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force)) + if (NVolWasDirty(vol) && !opts.force) goto umount; { diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index 2597dcfd..f636ca93 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -197,7 +197,7 @@ static int logfile_open(BOOL is_volume, const char *filename, ntfs_inode *ni; ntfs_attr *na; - vol = ntfs_mount(filename, NTFS_MNT_RDONLY); + vol = ntfs_mount(filename, NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC); if (!vol) log_err_exit(NULL, "Failed to mount %s: %s\n", filename, strerror(errno)); diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 71a3d3a0..28354ade 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -82,8 +82,6 @@ switch if you want to be able to build the NTFS utilities." static const char *EXEC_NAME = "ntfsfix"; static const char *OK = "OK\n"; static const char *FAILED = "FAILED\n"; -static BOOL vol_is_dirty = FALSE; -static BOOL journal_is_empty = FALSE; struct { char *volume; @@ -247,9 +245,8 @@ static int set_dirty_flag(ntfs_volume *vol) { u16 flags; - if (vol_is_dirty == TRUE) + if (NVolWasDirty(vol)) return 0; - ntfs_log_info("Setting required flags on partition... "); /* * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run @@ -264,37 +261,9 @@ static int set_dirty_flag(ntfs_volume *vol) ntfs_log_error("Error setting volume flags.\n"); return -1; } + vol->flags = flags; ntfs_log_info(OK); - vol_is_dirty = TRUE; - return 0; -} - -/** - * set_dirty_flag_mount - */ -static int set_dirty_flag_mount(ntfs_volume *vol) -{ - u16 flags; - - if (vol_is_dirty == TRUE) - return 0; - - ntfs_log_info("Setting required flags on partition... "); - /* - * Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run - * and fix it for us. - */ - flags = vol->flags | VOLUME_IS_DIRTY; - /* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */ - if (vol->major_ver >= 2) - flags |= VOLUME_MOUNTED_ON_NT4; - if (ntfs_volume_write_flags(vol, flags)) { - ntfs_log_info(FAILED); - ntfs_log_error("Error setting volume flags.\n"); - return -1; - } - ntfs_log_info(OK); - vol_is_dirty = TRUE; + NVolSetWasDirty(vol); return 0; } @@ -303,9 +272,8 @@ static int set_dirty_flag_mount(ntfs_volume *vol) */ static int empty_journal(ntfs_volume *vol) { - if (journal_is_empty == TRUE) + if (NVolLogFileEmpty(vol)) return 0; - ntfs_log_info("Going to empty the journal ($LogFile)... "); if (ntfs_logfile_reset(vol)) { ntfs_log_info(FAILED); @@ -313,7 +281,6 @@ static int empty_journal(ntfs_volume *vol) return -1; } ntfs_log_info(OK); - journal_is_empty = TRUE; return 0; } @@ -475,13 +442,13 @@ static int fix_mount(void) ntfs_log_info("Attempting to correct errors... "); - dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, NULL); + dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, + NULL); if (!dev) { ntfs_log_info(FAILED); ntfs_log_perror("Failed to allocate device"); return -1; } - vol = ntfs_volume_startup(dev, 0); if (!vol) { ntfs_log_info(FAILED); @@ -490,17 +457,12 @@ static int fix_mount(void) ntfs_device_free(dev); return -1; } - if (fix_mftmirr(vol) < 0) goto error_exit; - - /* FIXME: Will this fail? Probably... */ if (set_dirty_flag(vol) < 0) goto error_exit; - if (empty_journal(vol) < 0) goto error_exit; - ret = 0; error_exit: /* ntfs_umount() will invoke ntfs_device_free() for us. */ @@ -550,7 +512,8 @@ int main(int argc, char **argv) exit(1); } } - + /* So the unmount does not clear it again. */ + NVolSetWasDirty(vol); /* Check NTFS version is ok for us (in $Volume) */ ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver, vol->minor_ver); @@ -558,22 +521,13 @@ int main(int argc, char **argv) ntfs_log_error("Error: Unknown NTFS version.\n"); goto error_exit; } - - if (set_dirty_flag_mount(vol) < 0) - goto error_exit; - - if (empty_journal(vol) < 0) - goto error_exit; - if (vol->major_ver >= 3) { - /* FIXME: If on NTFS 3.0+, check for presence of the usn journal and - disable it (if present) as Win2k might be unhappy otherwise and Bad - Things(TM) could happen depending on what applications are actually - using it for. */ + /* + * FIXME: If on NTFS 3.0+, check for presence of the usn + * journal and stamp it if present. + */ } - - /* FIXME: Should we be marking the quota out of date, too? */ - + /* FIXME: We should be marking the quota out of date, too. */ /* That's all for now! */ ntfs_log_info("NTFS partition %s was processed successfully.\n", vol->dev->d_name); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 91e34f0a..2fbd77c5 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1288,7 +1288,7 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) // TODO: Switch this to properly aligned hex... printf("\tRunlist:\tVCN\t\tLCN\t\tLength\n"); while (rlc->length) { - printf("\t\t\t%lld\t\t%lld\t\t%lld\n", + printf("\t\t\t0x%llx\t\t0x%llx\t\t0x%llx\n", rlc->vcn, rlc->lcn, rlc->length); rlc++; } diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 67f89ccc..16f089f8 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -101,7 +101,6 @@ typedef struct { BOOL debug; BOOL noatime; BOOL no_detach; - BOOL leave_dirty; } ntfs_fuse_context_t; typedef enum { @@ -1360,10 +1359,6 @@ exit: static void ntfs_fuse_destroy(void *priv __attribute__((unused))) { if (ctx->vol) { - if (!ctx->leave_dirty && ntfs_volume_write_flags(ctx->vol, - ctx->vol->flags & ~VOLUME_IS_DIRTY)) - ntfs_log_error("Failed to clear volume dirty flag. " - "OK, leave it, chkdsk will handle.\n"); ntfs_log_info("Unmounting %s (%s)\n", opts.device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) @@ -1431,17 +1426,6 @@ static int ntfs_fuse_mount(const char *device) return -1; } ctx->vol = vol; - if (vol->flags & VOLUME_IS_DIRTY) - ctx->leave_dirty = TRUE; - else { - if (ntfs_volume_write_flags(vol, vol->flags | - VOLUME_IS_DIRTY)) { - ntfs_log_perror("Failed to set temporary dirty flag"); - ntfs_umount(vol, FALSE); - ctx->vol = NULL; - return -1; - } - } return 0; } diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index c7e1bc2b..bda2b88c 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -891,10 +891,7 @@ int main(int argc, char *argv[]) count = move_file(vol, inode, opts.location, 0); if ((count > 0) && (!opts.nodirty)) { - if (ntfs_volume_write_flags(vol, vol->flags | VOLUME_IS_DIRTY) < - 0) { - ntfs_log_error("Couldn't mark volume dirty\n"); - } + NVolSetWasDirty(vol); ntfs_log_info("Relocated %lld bytes\n", count); } if (count >= 0) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 47d59aae..719febfe 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2255,7 +2255,7 @@ static ntfs_volume *mount_volume(void) exit(1); } - if (vol->flags & VOLUME_IS_DIRTY) + if (NVolWasDirty(vol)) if (opt.force-- <= 0) err_exit("Volume is scheduled for check.\nRun chkdsk /f" " and please try again, or see option -f.\n"); @@ -2279,32 +2279,16 @@ static ntfs_volume *mount_volume(void) /** * prepare_volume_fixup * - * Set the volume's dirty flag and wipe the filesystem journal. When Windows - * boots it will automatically run chkdsk to check for any problems. If the - * read-only command line option was given, this function will do nothing. + * Make sure the volume's dirty flag does not get cleared at umount time. When + * Windows boots it will automatically run chkdsk to check for any problems. + * If the read-only command line option was given, this function will do + * nothing. */ static void prepare_volume_fixup(ntfs_volume *vol) { - u16 flags; - - flags = vol->flags | VOLUME_IS_DIRTY; - if (vol->major_ver >= 2) - flags |= VOLUME_MOUNTED_ON_NT4; - printf("Schedule chkdsk for NTFS consistency check at Windows " "boot time ...\n"); - - if (ntfs_volume_write_flags(vol, flags)) - perr_exit("Failed to set $Volume dirty"); - - if (vol->dev->d_ops->sync(vol->dev) == -1) - perr_exit("Failed to sync device"); - - printf("Resetting $LogFile ... (this might take a while)\n"); - - if (ntfs_logfile_reset(vol)) - perr_exit("Failed to reset $LogFile"); - + NVolSetWasDirty(vol); if (vol->dev->d_ops->sync(vol->dev) == -1) perr_exit("Failed to sync device"); } @@ -2470,7 +2454,6 @@ int main(int argc, char **argv) proceed_question(); } - /* FIXME: performance - relocate logfile here if it's needed */ prepare_volume_fixup(vol); if (resize.relocations) diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index 3f66f92d..78acc94b 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1346,7 +1346,7 @@ int main(int argc, char *argv[]) if (!vol) goto free; - if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force)) + if (NVolWasDirty(vol) && !opts.force) goto umount; if (opts.info) { diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 807d789e..f2bc43ad 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -229,7 +229,7 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, return NULL; } - if (vol->flags & VOLUME_IS_DIRTY) { + if (NVolWasDirty(vol)) { if (!force) { ntfs_log_error("%s", dirty_volume_msg); ntfs_umount(vol, FALSE); From a32aa26d0b145a58b3fd0836ce936afc2202ad00 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 28 Nov 2006 11:00:52 +0000 Subject: [PATCH 145/289] - Fix ntfsresize to unmount the volume when finished/exiting so it does not leave the volume in an inconsistent state. Somewhat crude solution using atexit() but it works... (Anton) --- ChangeLog | 6 ++++++ ntfsprogs/ntfsresize.c | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index c08c0adc..9678bbaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -84,6 +84,12 @@ xx/xx/2006 - x.xx.x - . - Set the volume dirty bit at mount time (if it is not set already and clear it again at umount time but only if it was not set to start with. (Anton) + - Introduce NTFS_MNT_FORENSIC mount option for logfile dumping for + example otherwise the logfile gets wiped out by the mount attempt if + it is not read-only. (Anton) + - Fix ntfsresize to unmount the volume when finished/exiting so it does + not leave the volume in an inconsistent state. Somewhat crude + solution using atexit() but it works... (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 719febfe..19b4b450 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2359,6 +2359,13 @@ static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck) compare_bitmaps(vol, &fsck->lcn_bitmap); } +static ntfs_volume *g_vol; + +static void ntfsresize_atexit(void) { + if (g_vol && ntfs_umount(g_vol, 0) < 0) + perror("Failed to unmount volume"); +} + int main(int argc, char **argv) { ntfsck_t fsck; @@ -2377,8 +2384,12 @@ int main(int argc, char **argv) utils_set_locale(); - if ((vol = mount_volume()) == NULL) + g_vol = NULL; + if (atexit(ntfsresize_atexit)) + err_exit("Failed to register exit handler!"); + if (!(vol = mount_volume())) err_exit("Couldn't open volume '%s'!\n", opt.volume); + g_vol = vol; device_size = ntfs_device_size_get(vol->dev, vol->sector_size); device_size *= vol->sector_size; From f40bef7246936a727e4f35d02f5acbf71c918f4d Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 28 Nov 2006 13:45:42 +0000 Subject: [PATCH 146/289] Disable unmounting at the point of no return when we start doing serious modifications to the volume. Hopefully Szaka will be happy now. (-: --- ntfsprogs/ntfsresize.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 19b4b450..ac009d27 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -215,6 +215,9 @@ s64 max_free_cluster_range = 0; #define NTFS_MAX_CLUSTER_SIZE (65536) +/* Global volume variable pointer for atexit() unmount purposes. */ +static ntfs_volume *g_vol; + static s64 rounded_up_division(s64 numer, s64 denom) { return (numer + (denom - 1)) / denom; @@ -2291,6 +2294,11 @@ static void prepare_volume_fixup(ntfs_volume *vol) NVolSetWasDirty(vol); if (vol->dev->d_ops->sync(vol->dev) == -1) perr_exit("Failed to sync device"); + /* + * We are starting to do irreversible volume changes now, thus we no + * longer consider it safe to perform a unmount of the volume. + */ + g_vol = NULL; } @@ -2359,8 +2367,6 @@ static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck) compare_bitmaps(vol, &fsck->lcn_bitmap); } -static ntfs_volume *g_vol; - static void ntfsresize_atexit(void) { if (g_vol && ntfs_umount(g_vol, 0) < 0) perror("Failed to unmount volume"); From fb407797096625368b2dec7b3012014cedfe1add Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 1 Dec 2006 16:04:56 +0000 Subject: [PATCH 147/289] Force using FUSE 2.6.1 that have proper error message in case of missing fuseblk --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index c2a14622..c2e83e4e 100644 --- a/configure.ac +++ b/configure.ac @@ -196,11 +196,11 @@ AM_CONDITIONAL(ENABLE_GNOME_VFS, $compile_gnome_vfs) # Autodetect whether to build FUSE module or not. compile_fuse_module=false if test "$enable_fuse_module" != "no"; then - PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.6.0, [ compile_fuse_module=true ], + PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.6.1, [ compile_fuse_module=true ], if test "$enable_fuse_module" = "yes"; then - AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.6.0.]) + AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.6.1.]) else - AC_MSG_WARN([ntfsmount requires FUSE version >= 2.6.0.]) + AC_MSG_WARN([ntfsmount requires FUSE version >= 2.6.1.]) fi ) fi From 0089670e1c5db65faed54916cfc935526844f265 Mon Sep 17 00:00:00 2001 From: aia21 Date: Sun, 3 Dec 2006 08:59:57 +0000 Subject: [PATCH 148/289] Use NTFS_MNT_FORENSIC with ntfsresize to restore old behaviour as it is documented, i.e. that ntfsresize does not do any modifciations until you say so. Also reinstate code to do the journal emptying and setting of dirty flag on the volume because of it. However update the code so that those things are only done if they were not already the case. --- ntfsprogs/ntfsresize.c | 60 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index ac009d27..62e28bb6 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -215,9 +215,6 @@ s64 max_free_cluster_range = 0; #define NTFS_MAX_CLUSTER_SIZE (65536) -/* Global volume variable pointer for atexit() unmount purposes. */ -static ntfs_volume *g_vol; - static s64 rounded_up_division(s64 numer, s64 denom) { return (numer + (denom - 1)) / denom; @@ -2239,9 +2236,13 @@ static ntfs_volume *mount_volume(void) err_exit("Device '%s' is mounted. " "You must 'umount' it first.\n", opt.volume); } - - if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_NOATIME))) { - + /* + * Pass NTFS_MNT_FORENSIC so that the mount process does not modify the + * volume at all. We will do the logfile emptying and dirty setting + * later if needed. + */ + if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_NOATIME | + NTFS_MNT_FORENSIC))) { int err = errno; perr_printf("Opening '%s' as NTFS failed", opt.volume); @@ -2282,26 +2283,33 @@ static ntfs_volume *mount_volume(void) /** * prepare_volume_fixup * - * Make sure the volume's dirty flag does not get cleared at umount time. When - * Windows boots it will automatically run chkdsk to check for any problems. - * If the read-only command line option was given, this function will do - * nothing. + * Set the volume's dirty flag and wipe the filesystem journal. When Windows + * boots it will automatically run chkdsk to check for any problems. If the + * read-only command line option was given, this function will do nothing. */ static void prepare_volume_fixup(ntfs_volume *vol) { - printf("Schedule chkdsk for NTFS consistency check at Windows " - "boot time ...\n"); - NVolSetWasDirty(vol); - if (vol->dev->d_ops->sync(vol->dev) == -1) - perr_exit("Failed to sync device"); - /* - * We are starting to do irreversible volume changes now, thus we no - * longer consider it safe to perform a unmount of the volume. - */ - g_vol = NULL; + /* No need to schedule chkdsk if it is already scheduled. */ + if (!NVolWasDirty(vol)) { + printf("Schedule chkdsk for NTFS consistency check at Windows " + "boot time ...\n"); + vol->flags |= VOLUME_IS_DIRTY; + if (ntfs_volume_write_flags(vol, vol->flags)) + perr_exit("Failed to set the volume dirty"); + NVolSetWasDirty(vol); + if (vol->dev->d_ops->sync(vol->dev) == -1) + perr_exit("Failed to sync device"); + } + /* No need to empty the journal if it is already empty. */ + if (!NVolLogFileEmpty(vol)) { + printf("Resetting $LogFile ... (this might take a while)\n"); + if (ntfs_logfile_reset(vol)) + perr_exit("Failed to reset $LogFile"); + if (vol->dev->d_ops->sync(vol->dev) == -1) + perr_exit("Failed to sync device"); + } } - static void set_disk_usage_constraint(ntfs_resize_t *resize) { /* last lcn for a filled up volume (no empty space) */ @@ -2367,11 +2375,6 @@ static void check_cluster_allocation(ntfs_volume *vol, ntfsck_t *fsck) compare_bitmaps(vol, &fsck->lcn_bitmap); } -static void ntfsresize_atexit(void) { - if (g_vol && ntfs_umount(g_vol, 0) < 0) - perror("Failed to unmount volume"); -} - int main(int argc, char **argv) { ntfsck_t fsck; @@ -2390,12 +2393,8 @@ int main(int argc, char **argv) utils_set_locale(); - g_vol = NULL; - if (atexit(ntfsresize_atexit)) - err_exit("Failed to register exit handler!"); if (!(vol = mount_volume())) err_exit("Couldn't open volume '%s'!\n", opt.volume); - g_vol = vol; device_size = ntfs_device_size_get(vol->dev, vol->sector_size); device_size *= vol->sector_size; @@ -2471,6 +2470,7 @@ int main(int argc, char **argv) proceed_question(); } + /* FIXME: performance - relocate logfile here if it's needed */ prepare_volume_fixup(vol); if (resize.relocations) From 33ffbb2af7516fd3cd4825265048ab0a5110c76d Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 3 Dec 2006 14:19:29 +0000 Subject: [PATCH 149/289] rename --enable-fuse-module to more clear --enable-ntfsmount and cleanup autotools scripts a bit --- ChangeLog | 3 +++ configure.ac | 16 ++++++++-------- ntfsprogs/Makefile.am | 14 +++++++------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9678bbaf..e9446cbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -90,6 +90,9 @@ xx/xx/2006 - x.xx.x - . - Fix ntfsresize to unmount the volume when finished/exiting so it does not leave the volume in an inconsistent state. Somewhat crude solution using atexit() but it works... (Anton) + - Raise FUSE dependence to 2.6.1 (the most stable and featured ATM), + rename --enable-fuse-module to more clear --enable-ntfsmount and + cleanup autotools scripts a bit. 21/06/2006 - 1.13.1 - Various fixes. diff --git a/configure.ac b/configure.ac index c2e83e4e..ddded1e8 100644 --- a/configure.ac +++ b/configure.ac @@ -106,10 +106,10 @@ AC_ARG_ENABLE(gnome-vfs, enable_gnome_vfs=auto ) -AC_ARG_ENABLE(fuse-module, - AS_HELP_STRING(--disable-fuse-module,omit FUSE 'libntfs' interface +AC_ARG_ENABLE(ntfsmount, + AS_HELP_STRING(--disable-ntfsmount,omit userspace NTFS driver (default=detect)), , - enable_fuse_module=auto + enable_ntfsmount=auto ) AC_ARG_ENABLE(crypto, @@ -194,17 +194,17 @@ fi AM_CONDITIONAL(ENABLE_GNOME_VFS, $compile_gnome_vfs) # Autodetect whether to build FUSE module or not. -compile_fuse_module=false -if test "$enable_fuse_module" != "no"; then - PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.6.1, [ compile_fuse_module=true ], - if test "$enable_fuse_module" = "yes"; then +compile_ntfsmount=false +if test "$enable_ntfsmount" != "no"; then + PKG_CHECK_MODULES(FUSE, fuse >= 2.6.1, [ compile_ntfsmount=true ], + if test "$enable_ntfsmount" = "yes"; then AC_MSG_ERROR([ntfsmount requires FUSE version >= 2.6.1.]) else AC_MSG_WARN([ntfsmount requires FUSE version >= 2.6.1.]) fi ) fi -AM_CONDITIONAL(ENABLE_FUSE_MODULE, $compile_fuse_module) +AM_CONDITIONAL(ENABLE_FUSE, $compile_ntfsmount) # Autodetect whether we can build crypto stuff or not. compile_crypto=false diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 680bf860..000f2501 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -29,7 +29,7 @@ MAINTAINERCLEANFILES = Makefile.in linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs -if ENABLE_FUSE_MODULE +if ENABLE_FUSE bin_PROGRAMS += ntfsmount endif @@ -84,11 +84,11 @@ ntfscp_SOURCES = ntfscp.c utils.c utils.h ntfscp_LDADD = $(AM_LIBS) ntfscp_LDFLAGS = $(AM_LFLAGS) -if ENABLE_FUSE_MODULE +if ENABLE_FUSE ntfsmount_SOURCES = ntfsmount.c utils.c utils.h -ntfsmount_LDADD = $(AM_LIBS) $(FUSE_MODULE_LIBS) +ntfsmount_LDADD = $(AM_LIBS) $(FUSE_LIBS) ntfsmount_LDFLAGS = $(AM_LFLAGS) -ntfsmount_CFLAGS = $(FUSE_MODULE_CFLAGS) -DFUSE_USE_VERSION=26 +ntfsmount_CFLAGS = $(FUSE_CFLAGS) -DFUSE_USE_VERSION=26 endif ntfscmp_SOURCES = ntfscmp.c utils.c utils.h @@ -140,21 +140,21 @@ extras: libs $(EXTRA_PROGRAMS) install-exec-hook: $(INSTALL) -d $(DESTDIR)/sbin $(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs -if ENABLE_FUSE_MODULE +if ENABLE_FUSE $(LN_S) -f $(bindir)/ntfsmount $(DESTDIR)/sbin/mount.ntfs-fuse endif install-data-hook: $(INSTALL) -d $(DESTDIR)$(man8dir) $(LN_S) -f mkntfs.8 $(DESTDIR)$(man8dir)/mkfs.ntfs.8 -if ENABLE_FUSE_MODULE +if ENABLE_FUSE $(LN_S) -f ntfsmount.8 $(DESTDIR)$(man8dir)/mount.ntfs-fuse.8 endif uninstall-local: $(RM) -f $(DESTDIR)/sbin/mkfs.ntfs $(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8 -if ENABLE_FUSE_MODULE +if ENABLE_FUSE $(RM) -f $(DESTDIR)/sbin/mount.ntfs-fuse $(RM) -f $(DESTDIR)$(man8dir)/mount.ntfs-fuse.8 endif From 3cd5cb9c8a6e6282cbcbe23f32daccab041bd647 Mon Sep 17 00:00:00 2001 From: szaka Date: Sun, 3 Dec 2006 18:26:58 +0000 Subject: [PATCH 150/289] Don't check free space if output file is FIFO (Andree Leidenfrost) --- ChangeLog | 2 ++ ntfsprogs/ntfsclone.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/ChangeLog b/ChangeLog index e9446cbb..f7791c20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -93,6 +93,8 @@ xx/xx/2006 - x.xx.x - . - Raise FUSE dependence to 2.6.1 (the most stable and featured ATM), rename --enable-fuse-module to more clear --enable-ntfsmount and cleanup autotools scripts a bit. + - ntfsclone: don't check free space if output file is FIFO (Andree + Leidenfrost) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 54d3a5e0..82044e5b 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1717,6 +1717,7 @@ static void check_dest_free_space(u64 src_bytes) { u64 dest_bytes; struct statvfs stvfs; + struct stat stat; if (opt.metadata || opt.blkdev_out || opt.std_out) return; @@ -1729,6 +1730,13 @@ static void check_dest_free_space(u64 src_bytes) strerror(errno)); return; } + + /* If file is a FIFO then there is no point in checking the size. */ + if (!fstat(fd_out, &stat)) { + if (S_ISFIFO(stat.st_mode)) + return; + } else + Printf("WARNING: fstat failed: %s\n", strerror(errno)); dest_bytes = (u64)stvfs.f_frsize * stvfs.f_bfree; if (!dest_bytes) From c475778b47d87c709d20b1d98518fc8b8920ed3d Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 6 Dec 2006 18:50:13 +0000 Subject: [PATCH 151/289] Turn ntfs_pathname_to_inode() into ntfs_pathname_to_inode_num() which returns ntfs inode number instead of opened inode itself. Reimplement ntfs_pathname_to_inode() as wrapper to new API. --- ChangeLog | 17 +++++---- include/ntfs/dir.h | 2 ++ libntfs/dir.c | 84 ++++++++++++++++++++++++++----------------- ntfsprogs/ntfsmount.c | 2 +- 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7791c20..99c29c35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,8 +10,8 @@ xx/xx/2006 - x.xx.x - . selected type and name already present in inode. (Szaka) - Extend ntfs_index_{add_filename,rm} to support almost all cases of index operations. (Szaka) - - Support index operations when index root is in the base mft record. - (Yura) + - Support index operations when index root is in the base MFT + record. (Yura) - calloc/malloc -> ntfs_{calloc,malloc} conversions. (Szaka) - ntfsclone: don't create image files with executable bit set. (Szaka) - ntfsclone: metadata cloning: write out extent records. (Szaka) @@ -26,8 +26,8 @@ xx/xx/2006 - x.xx.x - . - ntfsinfo: add ntfs_dump_index_block() and use it. (Szaka) - ntfsinfo: fix output indenting. (Szaka) - ntfsinfo: make stdout line buffered. (Szaka) - - ntfsinfo: fix segfaults when SDS has absolute security descriptor. - (Szaka) + - ntfsinfo: fix segfaults when SDS has absolute security + descriptor. (Szaka) - ntfsinfo: redirect stderr to /dev/null if --debug isn't used in debug mode. (Szaka) - ntfsinfo: fix segfaults on corrupt index blocks. (Szaka) @@ -86,15 +86,18 @@ xx/xx/2006 - x.xx.x - . with. (Anton) - Introduce NTFS_MNT_FORENSIC mount option for logfile dumping for example otherwise the logfile gets wiped out by the mount attempt if - it is not read-only. (Anton) + it is not read-only. (Anton) - Fix ntfsresize to unmount the volume when finished/exiting so it does not leave the volume in an inconsistent state. Somewhat crude solution using atexit() but it works... (Anton) - Raise FUSE dependence to 2.6.1 (the most stable and featured ATM), rename --enable-fuse-module to more clear --enable-ntfsmount and - cleanup autotools scripts a bit. - - ntfsclone: don't check free space if output file is FIFO (Andree + cleanup autotools scripts a bit. (Yura) + - ntfsclone: don't check free space if output file is FIFO. (Andree Leidenfrost) + - Turn ntfs_pathname_to_inode() into ntfs_pathname_to_inode_num() which + returns ntfs inode number instead of opened inode itself. + Reimplement ntfs_pathname_to_inode() as wrapper to new API. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/dir.h b/include/ntfs/dir.h index 4b76c441..600bb3a3 100644 --- a/include/ntfs/dir.h +++ b/include/ntfs/dir.h @@ -65,6 +65,8 @@ extern ntfschar NTFS_INDEX_R[3]; extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname, const int uname_len); +extern u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, + const char *pathname); extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname); diff --git a/libntfs/dir.c b/libntfs/dir.c index 4f08956c..b25e7ea5 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -470,7 +470,8 @@ close_err_out: } /** - * ntfs_pathname_to_inode - Find the inode which represents the given pathname + * ntfs_pathname_to_inode_num - find the inode number which represents the + * given pathname * @vol: An ntfs volume obtained from ntfs_mount * @parent: A directory inode to begin the search (may be NULL) * @pathname: Pathname to be located @@ -479,43 +480,35 @@ close_err_out: * splits the path and then descends the directory tree. If @parent is NULL, * then the root directory '.' will be used as the base for the search. * - * Return: inode Success, the pathname was valid - * NULL Error, the pathname was invalid, or some other error occurred + * Return: -1 Error, the pathname was invalid, or some other error occurred + * else Success, the pathname was valid */ -ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, +u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, const char *pathname) { - u64 inum; + u64 inum, result = (u64)-1; int len, err = 0; char *p, *q; - ntfs_inode *ni; - ntfs_inode *result = NULL; + ntfs_inode *ni = NULL; ntfschar *unicode = NULL; char *ascii = NULL; if (!vol || !pathname) { - errno = EINVAL; - return NULL; + err = EINVAL; + goto close; } ntfs_log_trace("Path: '%s'\n", pathname); if (parent) { ni = parent; - } else { - ni = ntfs_inode_open(vol, FILE_root); - if (!ni) { - ntfs_log_debug("Couldn't open the inode of the root " - "directory.\n"); - err = EIO; - goto close; - } - } + } else + inum = FILE_root; unicode = calloc(1, MAX_PATH); ascii = strdup(pathname); if (!unicode || !ascii) { - ntfs_log_debug("Out of memory.\n"); + ntfs_log_error("Out of memory.\n"); err = ENOMEM; goto close; } @@ -525,10 +518,20 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, while (p && *p == PATH_SEP) p++; while (p && *p) { + if (!ni) { + ni = ntfs_inode_open(vol, inum); + if (!ni) { + ntfs_log_debug("Cannot open inode %llu.\n", + (unsigned long long)inum); + err = EIO; + goto close; + } + } + /* Find the end of the first token. */ q = strchr(p, PATH_SEP); if (q != NULL) { - *q = '\0'; + *q = 0; q++; } @@ -547,26 +550,17 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, err = ENOENT; goto close; } + inum = MREF(inum); if (ni != parent) ntfs_inode_close(ni); - - inum = MREF(inum); - ni = ntfs_inode_open(vol, inum); - if (!ni) { - ntfs_log_debug("Cannot open inode %llu: %s.\n", - (unsigned long long)inum, p); - err = EIO; - goto close; - } + ni = NULL; p = q; - while (p && *p && *p == PATH_SEP) + while (p && *p == PATH_SEP) p++; } - - result = ni; - ni = NULL; + result = inum; close: if (ni && (ni != parent)) ntfs_inode_close(ni); @@ -577,6 +571,30 @@ close: return result; } +/** + * ntfs_pathname_to_inode - Find the inode which represents the given pathname + * @vol: An ntfs volume obtained from ntfs_mount + * @parent: A directory inode to begin the search (may be NULL) + * @pathname: Pathname to be located + * + * Take an ASCII pathname and find the inode that represents it. The function + * splits the path and then descends the directory tree. If @parent is NULL, + * then the root directory '.' will be used as the base for the search. + * + * Return: inode Success, the pathname was valid + * NULL Error, the pathname was invalid, or some other error occurred + */ +ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, + const char *pathname) +{ + u64 inum; + + inum = ntfs_pathname_to_inode_num(vol, parent, pathname); + if (inum == (u64)-1) + return NULL; + return ntfs_inode_open(vol, inum); +} + /* * The little endian Unicode string ".." for ntfs_readdir(). */ diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 16f089f8..54470d89 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -4,7 +4,7 @@ * Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel * - * NTFS module for FUSE. + * Userspace NTFS driver. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 82747f3c4738fa278c2ed963451642f3bc455a86 Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 6 Dec 2006 19:51:59 +0000 Subject: [PATCH 152/289] ntfsmount: fix rename if destination already exists. --- ChangeLog | 1 + ntfsprogs/ntfsmount.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/ChangeLog b/ChangeLog index 99c29c35..93a547de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -98,6 +98,7 @@ xx/xx/2006 - x.xx.x - . - Turn ntfs_pathname_to_inode() into ntfs_pathname_to_inode_num() which returns ntfs inode number instead of opened inode itself. Reimplement ntfs_pathname_to_inode() as wrapper to new API. (Yura) + - ntfsmount: fix rename if destination already exists. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 54470d89..39387123 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1013,9 +1013,36 @@ static int ntfs_fuse_unlink(const char *org_path) static int ntfs_fuse_rename(const char *old_path, const char *new_path) { int ret; + u64 inum_new, inum_old; + /* Check whether destination already exists. */ + if ((inum_new = ntfs_pathname_to_inode_num(ctx->vol, NULL, new_path)) != + (u64)-1) { + if (errno != ENOENT) + return -errno; + /* + * If source and destination belongs to the same inode, then + * just unlink source if mount is case sensitive or return + * -EINVAL if mount is case insensitive, because of a lot of + * brain damaged cases here. Anyway coreutils is broken for + * case sensitive filesystems. + * + * If source and destination belongs to different inodes, then + * unlink current destination, so we can create link to source. + */ + inum_old = ntfs_pathname_to_inode_num(ctx->vol, NULL, old_path); + if (inum_old == inum_new) { + if (NVolCaseSensitive(ctx->vol)) + goto unlink; + else + return -EINVAL; + } else + if ((ret = ntfs_fuse_unlink(new_path))) + return ret; + } if ((ret = ntfs_fuse_link(old_path, new_path))) return ret; +unlink: if ((ret = ntfs_fuse_unlink(old_path))) { ntfs_fuse_unlink(new_path); return ret; From 8640540b539b59a8aaa66fae9b7aef0f39e9a0af Mon Sep 17 00:00:00 2001 From: aia21 Date: Sat, 9 Dec 2006 11:27:37 +0000 Subject: [PATCH 153/289] Warn about VOLUME_MOUNTED_ON_NT4 wrt Vista in layout.h and do not set the flag in ntfsfix. --- ChangeLog | 8 ++++---- include/ntfs/layout.h | 3 +++ ntfsprogs/ntfsfix.c | 3 --- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93a547de..53d84111 100644 --- a/ChangeLog +++ b/ChangeLog @@ -86,10 +86,8 @@ xx/xx/2006 - x.xx.x - . with. (Anton) - Introduce NTFS_MNT_FORENSIC mount option for logfile dumping for example otherwise the logfile gets wiped out by the mount attempt if - it is not read-only. (Anton) - - Fix ntfsresize to unmount the volume when finished/exiting so it does - not leave the volume in an inconsistent state. Somewhat crude - solution using atexit() but it works... (Anton) + it is not read-only. Also use it for ntfsresize as it wishes to do + its own logfile emptying and volume dirtying. (Anton) - Raise FUSE dependence to 2.6.1 (the most stable and featured ATM), rename --enable-fuse-module to more clear --enable-ntfsmount and cleanup autotools scripts a bit. (Yura) @@ -99,6 +97,8 @@ xx/xx/2006 - x.xx.x - . returns ntfs inode number instead of opened inode itself. Reimplement ntfs_pathname_to_inode() as wrapper to new API. (Yura) - ntfsmount: fix rename if destination already exists. (Yura) + - ntfsfix: do not set VOLUME_MOUNTED_ON_NT4 flag as it causes Vista to + not boot any more. 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index db1c79d4..486340c3 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -1989,6 +1989,9 @@ typedef struct { /** * enum VOLUME_FLAGS - Possible flags for the volume (16-bit). + * + * WARNING: Setting VOLUME_MOUNTED_ON_NT4 on a Volume causes Windows Vista to + * fail to boot (it hangs on a black screen). */ typedef enum { VOLUME_IS_DIRTY = const_cpu_to_le16(0x0001), diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 28354ade..50efe8ac 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -253,9 +253,6 @@ static int set_dirty_flag(ntfs_volume *vol) * and fix it for us. */ flags = vol->flags | VOLUME_IS_DIRTY; - /* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */ - if (vol->major_ver >= 2) - flags |= VOLUME_MOUNTED_ON_NT4; if (OLD_ntfs_volume_set_flags(vol, flags)) { ntfs_log_info(FAILED); ntfs_log_error("Error setting volume flags.\n"); From f73d77d56845f85ea4a2a309d2efffb72d78afa7 Mon Sep 17 00:00:00 2001 From: aia21 Date: Sat, 9 Dec 2006 14:01:12 +0000 Subject: [PATCH 154/289] - Implement ntfs_pread() and ntfs_pwrite() in terms of device operations pread() and pwrite() respectively and fall back to using seek() + read()/write() if no pread()/pwrite() device operation is supplied or the OS does not support the pread()/pwrite() system call. Adapt unix_io pread()/pwrite() device operations to use pread()/ pwrite() system call and adapt win32_io device operations to not supply pread()/pwrite(). (Csaba Henk, Anton) --- CREDITS | 1 + ChangeLog | 7 ++++ libntfs/device.c | 79 +++++++++++++++++++++++++++++++++++++++++----- libntfs/dir.c | 14 ++------ libntfs/unix_io.c | 4 +-- libntfs/win32_io.c | 14 -------- 6 files changed, 84 insertions(+), 35 deletions(-) diff --git a/CREDITS b/CREDITS index 3c6c6df1..09698845 100644 --- a/CREDITS +++ b/CREDITS @@ -17,6 +17,7 @@ Matthew J. Fanto Yuval Fledel Marcin GibuÅ‚a Christophe Grenier +Csaba Henk Ian Jackson Carmelo Kintana Jan Kratochvil diff --git a/ChangeLog b/ChangeLog index 53d84111..9f3d41ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -99,6 +99,13 @@ xx/xx/2006 - x.xx.x - . - ntfsmount: fix rename if destination already exists. (Yura) - ntfsfix: do not set VOLUME_MOUNTED_ON_NT4 flag as it causes Vista to not boot any more. + - Implement ntfs_pread() and ntfs_pwrite() in terms of device + operations pread() and pwrite() respectively and fall back to using + seek() + read()/write() if no pread()/pwrite() device operation is + supplied or the OS does not support the pread()/pwrite() system call. + Adapt unix_io pread()/pwrite() device operations to use pread()/ + pwrite() system call and adapt win32_io device operations to not + supply pread()/pwrite(). (Csaba Henk, Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/device.c b/libntfs/device.c index c732f8cc..1500479c 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -152,6 +152,22 @@ int ntfs_device_free(struct ntfs_device *dev) return 0; } +/** + * fake_pread - read operation disguised as pread + * @dev: device to read from + * @b: output data buffer + * @count: number of bytes to read + * @pos: position in device to read from + * + * Auxiliary function, used when we emulate pread by seek() + a sequence of + * read()s. + */ +static s64 fake_pread(struct ntfs_device *dev, void *b, s64 count, + s64 pos __attribute__((unused))) +{ + return dev->d_ops->read(dev, b, count); +} + /** * ntfs_pread - positioned read from disk * @dev: device to read from @@ -175,6 +191,7 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) { s64 br, total; struct ntfs_device_operations *dops; + s64 (*_pread)(struct ntfs_device *, void *, s64, s64); ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); if (!b || count < 0 || pos < 0) { @@ -184,21 +201,34 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) if (!count) return 0; dops = dev->d_ops; - /* Locate to position. */ - if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { - ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned error", - pos); + _pread = dops->pread; + if (!_pread) + _pread = fake_pread; +seek: + /* Locate to position if pread is to be emulated by seek() + read(). */ + if (_pread == fake_pread && + dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { + ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned " + "error", pos); return -1; } /* Read the data. */ for (total = 0; count; count -= br, total += br) { - br = dops->read(dev, (char*)b + total, count); + br = _pread(dev, (char*)b + total, count, pos + total); /* If everything ok, continue. */ if (br > 0) continue; /* If EOF or error return number of bytes read. */ if (!br || total) return total; + /* + * If pread is not supported by the OS, fall back to emulating + * it by seek() + read(). + */ + if (errno == ENOSYS && _pread != fake_pread) { + _pread = fake_pread; + goto seek; + } /* Nothing read and error, return error status. */ return br; } @@ -206,6 +236,22 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) return total; } +/** + * fake_pwrite - write operation disguised as pwrite + * @dev: device to write to + * @b: input data buffer + * @count: number of bytes to write + * @pos: position in device to write to + * + * Auxiliary function, used when we emulate pwrite by seek() + a sequence of + * write()s. + */ +static s64 fake_pwrite(struct ntfs_device *dev, const void *b, s64 count, + s64 pos __attribute__((unused))) +{ + return dev->d_ops->write(dev, b, count); +} + /** * ntfs_pwrite - positioned write to disk * @dev: device to write to @@ -230,6 +276,7 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, { s64 written, total; struct ntfs_device_operations *dops; + s64 (*_pwrite)(struct ntfs_device *, const void *, s64, s64); ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); if (!b || count < 0 || pos < 0) { @@ -243,8 +290,15 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, return -1; } dops = dev->d_ops; - /* Locate to position. */ - if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { + _pwrite = dops->pwrite; + if (!_pwrite) + _pwrite = fake_pwrite; +seek: + /* + * Locate to position if pwrite is to be emulated by seek() + write(). + */ + if (_pwrite == fake_pwrite && + dops->seek(dev, pos, SEEK_SET) == (off_t)-1) { ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error", pos); return -1; @@ -252,7 +306,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, NDevSetDirty(dev); /* Write the data. */ for (total = 0; count; count -= written, total += written) { - written = dops->write(dev, (const char*)b + total, count); + written = _pwrite(dev, (const char*)b + total, count, + pos + total); /* If everything ok, continue. */ if (written > 0) continue; @@ -261,6 +316,14 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, */ if (!written || total) break; + /* + * If pwrite is not supported by the OS, fall back to emulating + * it by seek() + write(). + */ + if (errno == ENOSYS && _pwrite != fake_pwrite) { + _pwrite = fake_pwrite; + goto seek; + } /* Nothing written and error, return error status. */ return written; } diff --git a/libntfs/dir.c b/libntfs/dir.c index b25e7ea5..3b157011 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -486,25 +486,23 @@ close_err_out: u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, const char *pathname) { - u64 inum, result = (u64)-1; + u64 inum, result; int len, err = 0; char *p, *q; ntfs_inode *ni = NULL; ntfschar *unicode = NULL; char *ascii = NULL; + inum = result = (u64)-1; if (!vol || !pathname) { err = EINVAL; goto close; } - ntfs_log_trace("Path: '%s'\n", pathname); - if (parent) { ni = parent; } else inum = FILE_root; - unicode = calloc(1, MAX_PATH); ascii = strdup(pathname); if (!unicode || !ascii) { @@ -512,7 +510,6 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, err = ENOMEM; goto close; } - p = ascii; /* Remove leading /'s. */ while (p && *p == PATH_SEP) @@ -527,14 +524,12 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, goto close; } } - /* Find the end of the first token. */ q = strchr(p, PATH_SEP); if (q != NULL) { *q = 0; q++; } - len = ntfs_mbstoucs(p, &unicode, MAX_PATH); if (len < 0) { ntfs_log_debug("Couldn't convert name to Unicode: " @@ -542,20 +537,17 @@ u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, err = EILSEQ; goto close; } - inum = ntfs_inode_lookup_by_name(ni, unicode, len); - if (inum == (u64) -1) { + if (inum == (u64)-1) { ntfs_log_debug("Couldn't find name '%s' in pathname " "'%s'.\n", p, pathname); err = ENOENT; goto close; } inum = MREF(inum); - if (ni != parent) ntfs_inode_close(ni); ni = NULL; - p = q; while (p && *p == PATH_SEP) p++; diff --git a/libntfs/unix_io.c b/libntfs/unix_io.c index 048791e0..cd1b4573 100644 --- a/libntfs/unix_io.c +++ b/libntfs/unix_io.c @@ -229,7 +229,7 @@ static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf, static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset) { - return ntfs_pread(dev, offset, count, buf); + return pread(DEV_FD(dev), buf, count, offset); } /** @@ -251,7 +251,7 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, return -1; } NDevSetDirty(dev); - return ntfs_pwrite(dev, offset, count, buf); + return pwrite(DEV_FD(dev), buf, count, offset); } /** diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index 752df435..4360a20c 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -1449,26 +1449,12 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, } } -static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, - s64 count, s64 offset) -{ - return ntfs_pread(dev, offset, count, b); -} - -static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, - s64 count, s64 offset) -{ - return ntfs_pwrite(dev, offset, count, b); -} - struct ntfs_device_operations ntfs_device_win32_io_ops = { .open = ntfs_device_win32_open, .close = ntfs_device_win32_close, .seek = ntfs_device_win32_seek, .read = ntfs_device_win32_read, .write = ntfs_device_win32_write, - .pread = ntfs_device_win32_pread, - .pwrite = ntfs_device_win32_pwrite, .sync = ntfs_device_win32_sync, .stat = ntfs_device_win32_stat, .ioctl = ntfs_device_win32_ioctl From 43b61b82e7384a381fc95b5aad31a446b06a168a Mon Sep 17 00:00:00 2001 From: aia21 Date: Sun, 10 Dec 2006 19:38:02 +0000 Subject: [PATCH 155/289] If pread/pwrite are not supported by the OS, set the device pread()/pwrite() pointers to NULL so we automatically use seek() + read()/write() from now on. --- libntfs/device.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libntfs/device.c b/libntfs/device.c index 1500479c..45856bee 100644 --- a/libntfs/device.c +++ b/libntfs/device.c @@ -223,10 +223,12 @@ seek: return total; /* * If pread is not supported by the OS, fall back to emulating - * it by seek() + read(). + * it by seek() + read() and set the device pread() pointer to + * NULL so we automatically use seek() + read() from now on. */ if (errno == ENOSYS && _pread != fake_pread) { _pread = fake_pread; + dops->pread = NULL; goto seek; } /* Nothing read and error, return error status. */ @@ -318,10 +320,13 @@ seek: break; /* * If pwrite is not supported by the OS, fall back to emulating - * it by seek() + write(). + * it by seek() + write() and set the device pwrite() pointer + * to NULL so we automatically use seek() + write() from now + * on. */ if (errno == ENOSYS && _pwrite != fake_pwrite) { _pwrite = fake_pwrite; + dops->pwrite = NULL; goto seek; } /* Nothing written and error, return error status. */ From 03fabce6eb36ce624144d6482aff2857739cd6c4 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 11 Dec 2006 03:02:23 +0000 Subject: [PATCH 156/289] o fix magicNTFS defenition o remove NTFS_SB_MAGIC because it is unusefull o rename magicNTFS -> NTFS_SB_MAGIC o make bootsect.c use NTFS_SB_MAGIC instead of hardcoded value --- include/ntfs/layout.h | 5 ++--- libntfs/bootsect.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 486340c3..9782f426 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -27,9 +27,8 @@ #include "endians.h" #include "support.h" -/* The NTFS oem_id */ -#define magicNTFS const_cpu_to_le64(0x202020205346544e) /* "NTFS " */ -#define NTFS_SB_MAGIC 0x5346544e /* 'NTFS' */ +/* The NTFS oem_id "NTFS " */ +#define NTFS_SB_MAGIC const_cpu_to_le64(0x202020205346544eULL) /* * Location of bootsector on partition: diff --git a/libntfs/bootsect.c b/libntfs/bootsect.c index f2bafb4e..90a30f01 100644 --- a/libntfs/bootsect.c +++ b/libntfs/bootsect.c @@ -83,7 +83,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, /* Check OEMidentifier is "NTFS " */ ntfs_log_debug("Checking OEMid... "); - if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) /* "NTFS " */ + if (b->oem_id != NTFS_SB_MAGIC) /* "NTFS " */ goto not_ntfs; ntfs_log_debug("OK\n"); From 19089b08bda4f9fb08f69a6529e65724724da16a Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 11 Dec 2006 03:03:30 +0000 Subject: [PATCH 157/289] one place with mount option description --- include/ntfs/volume.h | 5 +---- libntfs/volume.c | 13 +++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index ef79e3b9..54ed0b15 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -60,10 +60,7 @@ typedef enum { NTFS_MNT_NOATIME = 2, NTFS_MNT_CASE_SENSITIVE = 4, NTFS_MNT_NOT_EXCLUSIVE = 8, - NTFS_MNT_FORENSIC = 16, /* Mount for forensic purposes, i.e. do - not do any writing at all during the - mount, i.e. no journal emptying, no - dirty bit setting, etc. */ + NTFS_MNT_FORENSIC = 16, } ntfs_mount_flags; /** diff --git a/libntfs/volume.c b/libntfs/volume.c index 77cc3c75..020ef1ab 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -763,6 +763,9 @@ out: * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if * they are not in POSIX namespace * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively + * NTFS_MNT_FORENSIC - mount for forensic purposes, i.e. do not do + * any writing at all during the mount, i.e. no + * journal emptying, no dirty bit setting, etc. * * The function opens the device @dev and verifies that it contains a valid * bootsector. Then, it allocates an ntfs_volume structure and initializes @@ -1175,14 +1178,8 @@ error_exit: * This function mounts an ntfs volume. @name should contain the name of the * device/file to mount as the ntfs volume. * - * @flags is an optional second parameter. Some flags are similar to flags used - * as for the mount system call (man 2 mount). Currently the following flags - * are implemented: - * NTFS_MNT_RDONLY - mount volume read-only - * NTFS_MNT_NOATIME - do not update access time - * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if - * they are not in POSIX namespace - * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively + * @flags is an optional second parameter. See ntfs_device_mount comment for + * description. * * The function opens the device or file @name and verifies that it contains a * valid bootsector. Then, it allocates an ntfs_volume structure and initializes From c616e296637aef4ef98e175a85e20c02d817475f Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 11 Dec 2006 03:06:35 +0000 Subject: [PATCH 158/289] ntfsck by Yuval to extra dist with minor changes from me --- ntfsprogs/Makefile.am | 6 +- ntfsprogs/ntfsck.c | 866 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 ntfsprogs/ntfsck.c diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 000f2501..17f3902b 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -15,7 +15,7 @@ bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \ ntfscp EXTRA_PROGRAMS = ntfsdump_logfile ntfswipe ntfstruncate ntfsmove \ - ntfsmftalloc + ntfsmftalloc ntfsck man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \ ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \ @@ -84,6 +84,10 @@ ntfscp_SOURCES = ntfscp.c utils.c utils.h ntfscp_LDADD = $(AM_LIBS) ntfscp_LDFLAGS = $(AM_LFLAGS) +ntfsck_SOURCES = ntfsck.c utils.c utils.h +ntfsck_LDADD = $(AM_LIBS) +ntfsck_LDFLAGS = $(AM_LFLAGS) + if ENABLE_FUSE ntfsmount_SOURCES = ntfsmount.c utils.c utils.h ntfsmount_LDADD = $(AM_LIBS) $(FUSE_LIBS) diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c new file mode 100644 index 00000000..704ccd75 --- /dev/null +++ b/ntfsprogs/ntfsck.c @@ -0,0 +1,866 @@ +/** + * ntfsck - Part of the Linux-NTFS project. + * + * Copyright (c) 2006 Yuval Fledel + * + * This utility will check and fix errors on an NTFS volume. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "config.h" + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "layout.h" +#include "cluster.h" +#include "bitmap.h" +#include "utils.h" +#include "endians.h" +#include "bootsect.h" + +#define RETURN_FS_ERRORS_CORRECTED (1) +#define RETURN_SYSTEM_NEEDS_REBOOT (2) +#define RETURN_FS_ERRORS_LEFT_UNCORRECTED (4) +#define RETURN_OPERATIONAL_ERROR (8) +#define RETURN_USAGE_OR_SYNTAX_ERROR (16) +#define RETURN_CANCELLED_BY_USER (32) +/* Where did 64 go? */ +#define RETURN_SHARED_LIBRARY_ERROR (128) + +/* todo: command line: (everything is optional) + * fsck-frontend options: + * -C [fd] : display progress bar (send it to the file descriptor if specified) + * -T : don't show the title on startup + * fsck-checker options: + * -a : auto-repair. no questions. (optional: if marked clean and -f not specified, just check if mounable) + * -p : auto-repair safe. no questions (optional: same) + * -n : only check. no repair. + * -r : interactively repair. + * -y : always yes. + * -v : verbose. + * -V : version. + * taken from fsck.ext2 + * -b sb : use the superblock from sb. For corrupted volumes. (do we want separete boot/mft options?) + * -c : use badblocks(8) to find bad blocks (R/O mode) and add the findings to $Bad. + * -C fd : write competion info to fd. If 0, print a completion bar. + * -d : debugging output. + * -D : rebalance indices. + * -f : force checking even if marked clean. + * -F : flush buffers before beginning. (for time-benchmarking) + * -k : When used with -c, don't erase previous $Bad items. + * -n : Open fs as readonly. assume always no. (why is it needed if -r is not specified?) + * -t : Print time statistics. + * taken from fsck.reiserfs + * --rebuild-sb : try to find $MFT start and rebuild the boot sector. + * --rebuild-tree : scan for items and rebuild the indices that point to them (0x30, $SDS, etc.) + * --clean-reserved: zero rezerved fields. (use with care!) + * --adjust-size -z: insert a sparse hole if the data_size is larger than the size marked in the runlist. + * --logfile file : report corruptions (unlike other errors) to a file instead of stderr. + * --nolog : don't report corruptions at all. + * --quiet -q : no progress bar. + * taken from fsck.msdos + * -w : flush after every write. + * - do n passes. (only 2 in fsck.msdos. second should not report errors. Bonus: stop when error list does not change) + * taken from fsck.jfs + * --omit-journal-reply: self-descriptive (why would someone do that?) + * --replay-journal-only: self-descriptive. don't check otherwise. + * taken from fsck.xfs + * -s : only serious errors should be reported. + * -i ino : verbose behaviour only for inode ino. + * -b bno : verbose behaviour only for cluster bno. + * -L : zero log. + * inspired by others + * - don't do cluster accounting. + * - don't do mft record accounting. + * - don't do file names accounting. + * - don't do security_id accounting. + * - don't check acl inheritance problems. + * - undelete unused mft records. (bonus: different options for 100% salvagable and less) + * - error-level-report n: only report errors above this error level + * - error-level-repair n: only repair errors below this error level + * - don't fail on ntfsclone metadata pruning. + * signals: + * SIGUSR1 : start displaying progress bar + * SIGUSR2 : stop displaying progress bar. + */ + +/* Assuming NO_NTFS_DEVICE_DEFAULT_IO_OPS is not set */ + +static int errors = 0; +static int unsupported = 0; + +static short bytes_per_sector, sectors_per_cluster; +//static s64 mft_offset, mftmirr_offset; +static s64 current_mft_record; + +/** + * This is just a preliminary volume. + * Filled while checking the boot sector and used in the preliminary MFT check. + */ +static ntfs_volume vol; + +static runlist_element *mft_rl, *mft_bitmap_rl; + +#define check_failed(FORMAT, ARGS...) \ + do { \ + errors++; \ + ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__, \ + NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS); \ + } while (0); + +/** + * 0 success. + * 1 fail. + */ +static int assert_u32_equal(u32 val, u32 ok, const char *name) +{ + if (val!=ok) { + check_failed("Assertion failed for '%lld:%s'. should be 0x%x, " + "was 0x%x.\n", current_mft_record, name, + (int)ok, (int)val); + //errors++; + return 1; + } + return 0; +} + +static int assert_u32_noteq(u32 val, u32 wrong, const char *name) +{ + if (val==wrong) { + check_failed("Assertion failed for '%lld:%s'. should not be " + "0x%x.\n", current_mft_record, name, (int)wrong); + return 1; + } + return 0; +} + +static int assert_u32_lesseq(u32 val1, u32 val2, const char *name) +{ + if (val1 > val2) { + check_failed("Assertion failed for '%s'. 0x%x > 0x%x\n", + name, (int)val1, (int)val2); + //errors++; + return 1; + } + return 0; +} + +static int assert_u32_less(u32 val1, u32 val2, const char *name) +{ + if (val1 >= val2) { + check_failed("Assertion failed for '%s'. 0x%x >= 0x%x\n", + name, (int)val1, (int)val2); + //errors++; + return 1; + } + return 0; +} + +/** + * Return: 0 ok, 1 error. + * + * todo: may we use ntfs_boot_sector_is_ntfs() instead? + * It already does the checks but will not be able to fix anything. + */ +static BOOL verify_boot_sector(struct ntfs_device *dev) +{ + u8 buf[512]; + NTFS_BOOT_SECTOR *ntfs_boot = (NTFS_BOOT_SECTOR *)&buf; + //u32 bytes_per_cluster; + + current_mft_record = 9; + + if (dev->d_ops->pread(dev, buf, sizeof(buf), 0)!=sizeof(buf)) { + check_failed("Failed to read boot sector.\n"); + return 1; + } + + if ((buf[0]!=0xeb) || + ((buf[1]!=0x52) && (buf[1]!=0x5b)) || + (buf[2]!=0x90)) { + check_failed("Boot sector: Bad jump.\n"); + } + if (ntfs_boot->oem_id != NTFS_SB_MAGIC) { + check_failed("Boot sector: Bad NTFS magic.\n"); + } + bytes_per_sector = le16_to_cpu(ntfs_boot->bpb.bytes_per_sector); + if (!bytes_per_sector) { + check_failed("Boot sector: Bytes per sector is 0.\n"); + } + if (bytes_per_sector%512) { + check_failed("Boot sector: Bytes per sector is not a multiple" + " of 512.\n"); + } + sectors_per_cluster = ntfs_boot->bpb.sectors_per_cluster; + + // todo: if partition, query bios and match heads/tracks? */ + + // Initialize some values from vol. We will need those later. + ntfs_boot_sector_parse(&vol, (NTFS_BOOT_SECTOR *)buf); + vol.dev = dev; + + return 0; +} + +/** + * Load the runlist of the attribute. + * + * Return NULL if an error. + * The caller is responsible on freeing the allocated memory if the result is not NULL. + * + * Set size_of_file_record to some reasonable size when in doubt (the Windows default is 1024.) + * + * attr_type must be little endian. + * + * This function has code duplication with check_file_record() and + * check_attr_record() but its goal is to be less strict. Thus the + * duplicated checks are the minimal required for not crashing. + * + * Assumes dev is open. + */ +static runlist *load_runlist(struct ntfs_device *dev, s64 offset_to_file_record, u32 attr_type, u32 size_of_file_record) +{ + u8 *buf; + u16 attrs_offset; + u32 length; + ATTR_RECORD *attr_rec; + + if (size_of_file_record<22) // offset to attrs_offset + return NULL; + + buf = (u8*)ntfs_malloc(size_of_file_record); + if (!buf) + return NULL; + + if (dev->d_ops->pread(dev, buf, size_of_file_record, offset_to_file_record)!=size_of_file_record) { + check_failed("Failed to read file record at offset %lld (0x%llx).\n", offset_to_file_record, offset_to_file_record); + return NULL; + } + + attrs_offset = le16_to_cpu(((MFT_RECORD*)buf)->attrs_offset); + // first attribute must be after the header. + if (attrs_offset<42) { + check_failed("First attribute must be after the header (%u).\n", (int)attrs_offset); + } + attr_rec = (ATTR_RECORD *)(buf + attrs_offset); + //printf("uv1.\n"); + + while ((u8*)attr_rec<=buf+size_of_file_record-4) { + + //printf("Attr type: 0x%x.\n", attr_rec->type); + // Check attribute record. (Only what is in the buffer) + if (attr_rec->type==AT_END) { + check_failed("Attribute 0x%x not found in file record at offset %lld (0x%llx).\n", (int)le32_to_cpu(attr_rec->type), offset_to_file_record, offset_to_file_record); + return NULL; + } + if ((u8*)attr_rec>buf+size_of_file_record-8) { + // not AT_END yet no room for the length field. + check_failed("Attribute 0x%x is not AT_END, yet no " + "room for the length field.\n", + (int)le32_to_cpu(attr_rec->type)); + return NULL; + } + + length = le32_to_cpu(attr_rec->length); + + // Check that this attribute does not overflow the mft_record + if ((u8*)attr_rec+length >= buf+size_of_file_record) { + check_failed("Attribute (0x%x) is larger than FILE record at offset %lld (0x%llx).\n", + (int)le32_to_cpu(attr_rec->type), offset_to_file_record, offset_to_file_record); + return NULL; + } + // todo: what ATTRIBUTE_LIST (0x20)? + + if (attr_rec->type==attr_type) { + // Eurika! + + // ntfs_mapping_pairs_decompress only use two values from vol. Just fake it. + // todo: it will also use vol->major_ver if defined(DEBUG). But only for printing purposes. + + // Assume ntfs_boot_sector_parse() was called. + return ntfs_mapping_pairs_decompress(&vol, attr_rec, NULL); + } + + attr_rec = (ATTR_RECORD*)((u8*)attr_rec+length); + } + // If we got here, there was an overflow. + check_failed("file record corrupted at offset %lld (0x%llx).\n", offset_to_file_record, offset_to_file_record); + return NULL; +} + +/** + * Return: >=0 last VCN + * LCN_EINVAL error. + */ +static VCN get_last_vcn(runlist *rl) +{ + VCN res; + + if (!rl) + return LCN_EINVAL; + + res = LCN_EINVAL; + while (rl->length) { + ntfs_log_verbose("vcn: %lld, length: %lld.\n", rl->vcn, + rl->length); + if (rl->vcn<0) + res = rl->vcn; + else + res = rl->vcn + rl->length; + rl++; + } + + return res; +} + +static u32 mft_bitmap_records; +static u8 *mft_bitmap_buf; + +/** + * Assumes mft_bitmap_rl is initialized. + * return: 0 ok. + * RETURN_OPERATIONAL_ERROR on error. + */ +static int mft_bitmap_load(struct ntfs_device *dev) +{ + VCN vcn; + u32 mft_bitmap_length; + + vcn = get_last_vcn(mft_bitmap_rl); + if (vcn<=LCN_EINVAL) { + mft_bitmap_buf = NULL; + /* This case should not happen, not even with on-disk errors */ + goto error; + } + + mft_bitmap_length = vcn * vol.cluster_size; + mft_bitmap_records = 8 * mft_bitmap_length * vol.cluster_size / + vol.mft_record_size; + + //printf("sizes: %d, %d.\n", mft_bitmap_length, mft_bitmap_records); + + mft_bitmap_buf = (u8*)ntfs_malloc(mft_bitmap_length); + if (!mft_bitmap_buf) + goto error; + if (ntfs_rl_pread(&vol, mft_bitmap_rl, 0, mft_bitmap_length, + mft_bitmap_buf)!=mft_bitmap_length) + goto error; + return 0; +error: + mft_bitmap_records = 0; + ntfs_log_error("Could not load $MFT/Bitmap.\n"); + return RETURN_OPERATIONAL_ERROR; +} + +/** + * -1 Error. + * 0 Unused record + * 1 Used record + * + * Assumes mft_bitmap_rl was initialized. + */ +static int mft_bitmap_get_bit(s64 mft_no) +{ + if (mft_no>=mft_bitmap_records) + return -1; + return ntfs_bit_get(mft_bitmap_buf, mft_no); +} + +/** + * @attr_rec: The attribute record to check + * @mft_rec: The parent FILE record. + * @buflen: The size of the FILE record. + * + * Return: + * NULL: Fatal error occured. Not sure where is the next record. + * otherwise: pointer to the next attribute record. + * + * The function only check fields that are inside this attr record. + * + * Assumes mft_rec is current_mft_record. + */ +static ATTR_REC *check_attr_record(ATTR_REC *attr_rec, MFT_RECORD *mft_rec, + u16 buflen) +{ + u16 name_offset; + u16 attrs_offset = le16_to_cpu(mft_rec->attrs_offset); + u32 attr_type = le32_to_cpu(attr_rec->type); + u32 length = le32_to_cpu(attr_rec->length); + + // Check that this attribute does not overflow the mft_record + if ((u8*)attr_rec+length >= ((u8*)mft_rec)+buflen) { + check_failed("Attribute (0x%x) is larger than FILE record (%lld).\n", + (int)attr_type, current_mft_record); + return NULL; + } + + // Attr type must be a multiple of 0x10 and 0x10<=x<=0x100. + if ((attr_type & ~0x0F0) && (attr_type != 0x100)) { + check_failed("Unknown attribute type 0x%x.\n", + (int)attr_type); + goto check_attr_record_next_attr; + } + + if (length<24) { + check_failed("Attribute %lld:0x%x Length too short (%u).\n", + current_mft_record, (int)attr_type, (int)length); + goto check_attr_record_next_attr; + } + + // If this is the first attribute: + // todo: instance number must be smaller than next_instance. + if ((u8*)attr_rec == ((u8*)mft_rec) + attrs_offset) { + if (!mft_rec->base_mft_record) + assert_u32_equal(attr_type, 0x10, + "First attribute type"); + // The following not always holds. + // attr 0x10 becomes instance 1 and attr 0x40 becomes 0. + //assert_u32_equal(attr_rec->instance, 0, + // "First attribute instance number"); + } else { + assert_u32_noteq(attr_type, 0x10, + "Not-first attribute type"); + // The following not always holds. + //assert_u32_noteq(attr_rec->instance, 0, + // "Not-first attribute instance number"); + } + //if (current_mft_record==938 || current_mft_record==1683 || current_mft_record==3152 || current_mft_record==22410) + //printf("Attribute %lld:0x%x instance: %u isbase:%d.\n", + // current_mft_record, (int)attr_type, (int)le16_to_cpu(attr_rec->instance), (int)mft_rec->base_mft_record); + // todo: instance is unique. + + // Check flags. + if (attr_rec->flags & ~(const_cpu_to_le16(0xc0ff))) { + check_failed("Attribute %lld:0x%x Unknown flags (0x%x).\n", + current_mft_record, (int)attr_type, + (int)le16_to_cpu(attr_rec->flags)); + } + + if (attr_rec->non_resident>1) { + check_failed("Attribute %lld:0x%x Unknown non-resident " + "flag (0x%x).\n", current_mft_record, + (int)attr_type, (int)attr_rec->non_resident); + goto check_attr_record_next_attr; + } + + name_offset = le16_to_cpu(attr_rec->name_offset); + /* + * todo: name must be legal unicode. + * Not really, information below in urls is about filenames, but I + * believe it also applies to attribute names. (Yura) + * http://blogs.msdn.com/michkap/archive/2006/09/24/769540.aspx + * http://blogs.msdn.com/michkap/archive/2006/09/10/748699.aspx + */ + + if (attr_rec->non_resident) { + // Non-Resident + + // Make sure all the fields exist. + if (length<64) { + check_failed("Non-resident attribute %lld:0x%x too short (%u).\n", + current_mft_record, (int)attr_type, (int)length); + goto check_attr_record_next_attr; + } + if (attr_rec->compression_unit && (length<72)) { + check_failed("Compressed attribute %lld:0x%x too short (%u).\n", + current_mft_record, (int)attr_type, (int)length); + goto check_attr_record_next_attr; + } + + // todo: name comes before mapping pairs, and after the header. + // todo: length==mapping_pairs_offset+length of compressed mapping pairs. + // todo: mapping_pairs_offset is 8-byte aligned. + + // todo: lowest vcn <= highest_vcn + // todo: if base record -> lowest vcn==0 + // todo: lowest_vcn!=0 -> attribute list is used. + // todo: lowest_vcn & highest_vcn are in the drive (0<=xvalue_offset); + u32 value_length = le32_to_cpu(attr_rec->value_length); + // Resident + if (attr_rec->name_length) { + if (name_offset < 24) + check_failed("Resident attribute with " + "name intersecting header.\n"); + if (value_offset < name_offset + + attr_rec->name_length) + check_failed("Named resident attribute " + "with value before name.\n"); + } + // if resident, length==value_length+value_offset + //assert_u32_equal(le32_to_cpu(attr_rec->value_length)+ + // value_offset, length, + // "length==value_length+value_offset"); + // if resident, length==value_length+value_offset + if (value_length+value_offset > length) { + check_failed("value_length(%d)+value_offset(%d)>length(%d) for attribute 0x%x.\n", (int)value_length, (int)value_offset, (int)length, (int)attr_type); + return NULL; + } + + // Check resident_flags. + if (attr_rec->resident_flags>0x01) { + check_failed("Unknown resident flags (0x%x) for attribute 0x%x.\n", (int)attr_rec->resident_flags, (int)attr_type); + } else if (attr_rec->resident_flags && (attr_type!=0x30)) { + check_failed("Resident flags mark attribute 0x%x as indexed.\n", (int)attr_type); + } + + // reservedR is 0. + assert_u32_equal(attr_rec->reservedR, 0, "Resident Reserved"); + + // todo: attribute must not be 0xa0 (not sure about 0xb0, 0xe0, 0xf0) + // todo: check content well-formness per attr_type. + } + return 0; +check_attr_record_next_attr: + return (ATTR_REC *)(((u8 *)attr_rec) + length); +} + +/** + * All checks that can be satisfied only by data from the buffer. + * No other [MFT records/metadata files] are required. + * + * The buffer is changed by removing the Update Sequence. + * + * Return: + * 0 Everything's cool. + * else Consider this record as damaged. + */ +static BOOL check_file_record(u8 *buffer, u16 buflen) +{ + u16 usa_count, usa_ofs, attrs_offset, usa; + u32 bytes_in_use, bytes_allocated, i; + MFT_RECORD *mft_rec = (MFT_RECORD *)buffer; + ATTR_REC *attr_rec; + + // check record magic + assert_u32_equal(mft_rec->magic, magic_FILE, "FILE record magic"); + // todo: records 16-23 must be filled in order. + // todo: what to do with magic_BAAD? + + // check usa_count+offset to update seq <= attrs_offset < + // bytes_in_use <= bytes_allocated <= buflen. + usa_ofs = le16_to_cpu(mft_rec->usa_ofs); + usa_count = le16_to_cpu(mft_rec->usa_count); + attrs_offset = le16_to_cpu(mft_rec->attrs_offset); + bytes_in_use = le32_to_cpu(mft_rec->bytes_in_use); + bytes_allocated = le32_to_cpu(mft_rec->bytes_allocated); + if (assert_u32_lesseq(usa_ofs+usa_count, attrs_offset, + "usa_ofs+usa_count <= attrs_offset") || + assert_u32_less(attrs_offset, bytes_in_use, + "attrs_offset < bytes_in_use") || + assert_u32_lesseq(bytes_in_use, bytes_allocated, + "bytes_in_use <= bytes_allocated") || + assert_u32_lesseq(bytes_allocated, buflen, + "bytes_allocated <= max_record_size")) { + return 1; + } + + + // We should know all the flags. + if (mft_rec->flags>0xf) { + check_failed("Unknown MFT record flags (0x%x).\n", + (unsigned int)mft_rec->flags); + } + // todo: flag in_use must be on. + + // Remove update seq & check it. + usa = *(u16*)(buffer+usa_ofs); // The value that should be at the end of every sector. + assert_u32_equal(usa_count-1, buflen/bytes_per_sector, "USA length"); + for (i=1;itype==AT_END) { + // Done. + return 0; + } + if ((u8*)attr_rec>buffer+buflen-8) { + // not AT_END yet no room for the length field. + check_failed("Attribute 0x%x is not AT_END, yet no " + "room for the length field.\n", + (int)le32_to_cpu(attr_rec->type)); + return 1; + } + + attr_rec = check_attr_record(attr_rec, mft_rec, buflen); + if (!attr_rec) + return 1; + } + // If we got here, there was an overflow. + return 1; + + // todo: an attribute should be at the offset to first attribute, and the offset should be inside the buffer. It should have the value of "next attribute id". + // todo: if base record, it should start with attribute 0x10. + + // Highlevel check of attributes. + // todo: Attributes are well-formed. + // todo: Room for next attribute in the end of the previous record. + + return FALSE; +} + +static void replay_log(ntfs_volume *vol) +{ + // At this time, only check that the log is fully replayed. + ntfs_log_warning("Unsupported: replay_log()\n"); + // todo: if logfile is clean, return success. + unsupported++; +} + +static void verify_mft_record(ntfs_volume *vol, s64 mft_num) +{ + u8 *buffer; + int is_used; + + current_mft_record = mft_num; + + is_used = mft_bitmap_get_bit(mft_num); + if (is_used<0) { + ntfs_log_error("Error getting bit value for record %lld.\n", mft_num); + } else if (!is_used) { + ntfs_log_verbose("Record %lld unused. Skipping.\n", mft_num); + return; + } + + buffer = ntfs_malloc(vol->mft_record_size); + if (!buffer) + goto verify_mft_record_error; + + ntfs_log_verbose("MFT record %lld\n", mft_num); + if (ntfs_attr_pread(vol->mft_na, mft_num*vol->mft_record_size, vol->mft_record_size, buffer) < 0) { + ntfs_log_perror("Couldn't read $MFT record %lld", mft_num); + goto verify_mft_record_error; + } + + check_file_record(buffer, vol->mft_record_size); + // todo: if offset to first attribute >= 0x30, number of mft record should match. + // todo: Match the "record is used" with the mft bitmap. + // todo: if this is not base, check that the parent is a base, and is in use, and pointing to this record. + + // todo: if base record: for each extent record: + // todo: verify_file_record + // todo: hard link count should be the number of 0x30 attributes. + // todo: Order of attributes. + // todo: make sure compression_unit is the same. + + return; +verify_mft_record_error: + + if (buffer) + free(buffer); + errors++; +} + +/** + * This function serves as bootstraping for the more comprehensive checks. + * It will load the MFT runlist and MFT/Bitmap runlist. + * It should not depend on other checks or we may have a circular dependancy. + * Also, this loadng must be forgiving, unlike the comprehensive checks. + */ +static int verify_mft_preliminary(struct ntfs_device *dev) +{ + current_mft_record = 0; + s64 mft_offset, mftmirr_offset; + int res; + + ntfs_log_trace("Entering verify_mft_preliminary().\n"); + // todo: get size_of_file_record from boot sector + // Load the first segment of the $MFT/DATA runlist. + mft_offset = vol.mft_lcn * vol.cluster_size; + mftmirr_offset = vol.mftmirr_lcn * vol.cluster_size; + mft_rl = load_runlist(dev, mft_offset, AT_DATA, 1024); + if (!mft_rl) { + check_failed("Loading $MFT runlist failed. Trying $MFTMirr.\n"); + mft_rl = load_runlist(dev, mftmirr_offset, AT_DATA, 1024); + } + if (!mft_rl) { + check_failed("Loading $MFTMirr runlist failed too. Aborting.\n"); + return RETURN_FS_ERRORS_LEFT_UNCORRECTED | RETURN_OPERATIONAL_ERROR; + } + // TODO: else { recover $MFT } // Use $MFTMirr to recover $MFT. + // todo: support loading the next runlist extents when ATTRIBUTE_LIST is used on $MFT. + // If attribute list: Gradually load mft runlist. (parse runlist from first file record, check all referenced file records, continue with the next file record). If no attribute list, just load it. + + // Load the runlist of $MFT/Bitmap. + // todo: what about ATTRIBUTE_LIST? Can we reuse code? + mft_bitmap_rl = load_runlist(dev, mft_offset, AT_BITMAP, 1024); + if (!mft_bitmap_rl) { + check_failed("Loading $MFT/Bitmap runlist failed. Trying $MFTMirr.\n"); + mft_bitmap_rl = load_runlist(dev, mftmirr_offset, AT_BITMAP, 1024); + } + if (!mft_bitmap_rl) { + check_failed("Loading $MFTMirr/Bitmap runlist failed too. Aborting.\n"); + return RETURN_FS_ERRORS_LEFT_UNCORRECTED; + // todo: rebuild the bitmap by using the "in_use" file record flag or by filling it with 1's. + } + + /* Load $MFT/Bitmap */ + if ((res = mft_bitmap_load(dev))) + return res; + return -1; /* FIXME: Just added to fix compiler warning without + thinking about what should be here. (Yura) */ +} + +static void check_volume(ntfs_volume *vol) +{ + s64 mft_num, nr_mft_records; + + ntfs_log_warning("Unsupported: check_volume()\n"); + unsupported++; + + // For each mft record, verify that it contains a valid file record. + nr_mft_records = vol->mft_na->initialized_size >> + vol->mft_record_size_bits; + ntfs_log_info("Checking %lld MFT records.\n", nr_mft_records); + + for (mft_num=0; mft_num < nr_mft_records; mft_num++) { + verify_mft_record(vol, mft_num); + } + + // todo: Check metadata files. + + // todo: Second pass on mft records. Now check the contents as well. + // todo: When going through runlists, build a bitmap. + + // todo: cluster accounting. + return; +} + +static int reset_dirty(ntfs_volume *vol) +{ + u16 flags; + + if (!(vol->flags | VOLUME_IS_DIRTY)) + return 0; + + ntfs_log_verbose("Resetting dirty flag.\n"); + + flags = vol->flags & ~VOLUME_IS_DIRTY; + + if (ntfs_volume_write_flags(vol, flags)) { + ntfs_log_error("Error setting volume flags.\n"); + return -1; + } + return 0; +} + +/** + * main - Does just what C99 claim it does. + * + * For more details on arguments and results, check the man page. + */ +int main(int argc, char **argv) +{ + struct ntfs_device *dev; + ntfs_volume *vol; + const char *name; + int ret; + + if (argc != 2) + return RETURN_USAGE_OR_SYNTAX_ERROR; + name = argv[1]; + + ntfs_log_set_handler(ntfs_log_handler_outerr); + //ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_PROGRESS); + + /* Allocate an ntfs_device structure. */ + dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL); + if (!dev) + return RETURN_OPERATIONAL_ERROR; + + if (dev->d_ops->open(dev, O_RDONLY)) { //O_RDWR/O_RDONLY? + ntfs_log_perror("Error opening partition device"); + ntfs_device_free(dev); + return RETURN_OPERATIONAL_ERROR; + } + + if ((ret = verify_boot_sector(dev))) { + dev->d_ops->close(dev); + return ret; + } + ntfs_log_verbose("Boot sector verification complete. Proceeding to $MFT"); + + verify_mft_preliminary(dev); + + /* ntfs_device_mount() expects the device to be closed. */ + if (dev->d_ops->close(dev)) + ntfs_log_perror("Failed to close the device."); + + // at this point we know that the volume is valid enough for mounting. + + /* Call ntfs_device_mount() to do the actual mount. */ + vol = ntfs_device_mount(dev, NTFS_MNT_NOATIME | NTFS_MNT_RDONLY); + if (!vol) { + ntfs_device_free(dev); + return 2; + } + + replay_log(vol); + + if (vol->flags & VOLUME_IS_DIRTY) + ntfs_log_warning("Volume is dirty.\n"); + + check_volume(vol); + + if (errors) + ntfs_log_info("Errors found.\n"); + if (unsupported) + ntfs_log_info("Unsupported cases found.\n"); + + if (!errors && !unsupported) { + reset_dirty(vol); + } + + ntfs_umount(vol, FALSE); + + if (errors) + return 2; + if (unsupported) + return 1; + return 0; +} + From 2b611a1461594969db0029cfd77f61230aed6e5a Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 11 Dec 2006 03:16:22 +0000 Subject: [PATCH 159/289] fix clusters per index block calculation (Szaka) --- include/ntfs/layout.h | 8 ++------ libntfs/dir.c | 5 +++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 9782f426..85cf8461 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -2111,14 +2111,10 @@ typedef struct { this must be COLLATION_FILE_NAME. */ u32 index_block_size; /* Size of each index block in bytes (in the index allocation attribute). */ - s8 clusters_per_index_block; /* Cluster size of each index block (in + u8 clusters_per_index_block; /* Cluster size of each index block (in the index allocation attribute), when an index block is >= than a cluster, - otherwise this will be the -log of - the size (like how the encoding of - the mft record size and the index - record size found in the boot sector - work). Has to be a power of 2. */ + otherwise sectors per index block. */ u8 reserved[3]; /* Reserved/align to 8-byte boundary. */ INDEX_HEADER index; /* Index header describing the following index entries. */ diff --git a/libntfs/dir.c b/libntfs/dir.c index 3b157011..0d29bf30 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1244,8 +1244,9 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, ni->vol->indx_record_size >> ni->vol->cluster_size_bits; else - ir->clusters_per_index_block = - -ni->vol->indx_record_size_bits; + ir->clusters_per_index_block = + ni->vol->indx_record_size >> + ni->vol->sector_size_bits; ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER)); ir->index.index_length = cpu_to_le32(index_len); ir->index.allocated_size = cpu_to_le32(index_len); From a38ead2f2056f442b3fd008efa0e4f7db60f8755 Mon Sep 17 00:00:00 2001 From: aia21 Date: Mon, 11 Dec 2006 10:41:34 +0000 Subject: [PATCH 160/289] Szaka prefers to have the lofgile reset and dirty bit setting done even if they are already done so remove the conditionals I added. --- ntfsprogs/ntfsfix.8.in | 4 ++-- ntfsprogs/ntfsfix.c | 2 +- ntfsprogs/ntfsresize.c | 32 +++++++++++++------------------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/ntfsprogs/ntfsfix.8.in b/ntfsprogs/ntfsfix.8.in index dfe1b485..1890e35e 100644 --- a/ntfsprogs/ntfsfix.8.in +++ b/ntfsprogs/ntfsfix.8.in @@ -14,14 +14,14 @@ is a utility that fixes some common NTFS problems. .B ntfsfix is .B NOT -a Linux version of chkdsk. It only repairs some fundamental NTFS +a Linux version of chkdsk. It only repairs some fundamental NTFS inconsistencies, resets the NTFS journal file and schedules an NTFS consistency check for the first boot into Windows. .sp You may run .B ntfsfix on an NTFS volume if you think it was damaged by Windows or some other way -and it can't be mounted. +and it cannot be mounted. .SH OPTIONS Below is a summary of all the options that .B ntfsfix diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 50efe8ac..5aca7a9e 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -259,8 +259,8 @@ static int set_dirty_flag(ntfs_volume *vol) return -1; } vol->flags = flags; - ntfs_log_info(OK); NVolSetWasDirty(vol); + ntfs_log_info(OK); return 0; } diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 62e28bb6..b5cbeddb 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2289,25 +2289,19 @@ static ntfs_volume *mount_volume(void) */ static void prepare_volume_fixup(ntfs_volume *vol) { - /* No need to schedule chkdsk if it is already scheduled. */ - if (!NVolWasDirty(vol)) { - printf("Schedule chkdsk for NTFS consistency check at Windows " - "boot time ...\n"); - vol->flags |= VOLUME_IS_DIRTY; - if (ntfs_volume_write_flags(vol, vol->flags)) - perr_exit("Failed to set the volume dirty"); - NVolSetWasDirty(vol); - if (vol->dev->d_ops->sync(vol->dev) == -1) - perr_exit("Failed to sync device"); - } - /* No need to empty the journal if it is already empty. */ - if (!NVolLogFileEmpty(vol)) { - printf("Resetting $LogFile ... (this might take a while)\n"); - if (ntfs_logfile_reset(vol)) - perr_exit("Failed to reset $LogFile"); - if (vol->dev->d_ops->sync(vol->dev) == -1) - perr_exit("Failed to sync device"); - } + printf("Schedule chkdsk for NTFS consistency check at Windows boot " + "time ...\n"); + vol->flags |= VOLUME_IS_DIRTY; + if (ntfs_volume_write_flags(vol, vol->flags)) + perr_exit("Failed to set the volume dirty"); + NVolSetWasDirty(vol); + if (vol->dev->d_ops->sync(vol->dev) == -1) + perr_exit("Failed to sync device"); + printf("Resetting $LogFile ... (this might take a while)\n"); + if (ntfs_logfile_reset(vol)) + perr_exit("Failed to reset $LogFile"); + if (vol->dev->d_ops->sync(vol->dev) == -1) + perr_exit("Failed to sync device"); } static void set_disk_usage_constraint(ntfs_resize_t *resize) From 7b60afcc2f2a255b6c9b4620bc40b04a6ce6c617 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 12 Dec 2006 15:02:25 +0000 Subject: [PATCH 161/289] fix sparse errors. and first steps towards endianness checking --- include/ntfs/types.h | 18 ++++++++++------ libntfs/dir.c | 48 ++++++++++++------------------------------- libntfs/unistr.c | 4 ++-- ntfsprogs/ntfslabel.c | 2 +- ntfsprogs/utils.c | 4 +++- 5 files changed, 31 insertions(+), 45 deletions(-) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index 89f07871..ea156b27 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -45,17 +45,23 @@ typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; -typedef u16 le16; -typedef u32 le32; -typedef u64 le64; +#ifdef __CHECKER__ +#define __bitwise __attribute__((bitwise)) +#else +#define __bitwise +#endif + +typedef u16 __bitwise le16; +typedef u32 __bitwise le32; +typedef u64 __bitwise le64; /* * Declare sle{16,32,64} to be unsigned because we do not want sign extension * on BE architectures. */ -typedef u16 sle16; -typedef u32 sle32; -typedef u64 sle64; +typedef u16 __bitwise sle16; +typedef u32 __bitwise sle32; +typedef u64 __bitwise sle64; typedef u16 ntfschar; /* 2-byte Unicode character type. */ #define UCHAR_T_SIZE_BITS 1 diff --git a/libntfs/dir.c b/libntfs/dir.c index 0d29bf30..38c2193c 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -594,29 +594,10 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), const_cpu_to_le16('.'), const_cpu_to_le16('\0') }; -/* - * union index_union - Helper for ntfs_readdir(). - */ -typedef union { - INDEX_ROOT *ir; - INDEX_ALLOCATION *ia; -} index_union __attribute__((__transparent_union__)); - -/** - * enum INDEX_TYPE - Helper for ntfs_readdir(). - */ -typedef enum { - INDEX_TYPE_ROOT, /* index root */ - INDEX_TYPE_ALLOCATION, /* index allocation */ -} INDEX_TYPE; - /** * ntfs_filldir - ntfs specific filldir method * @dir_ni: ntfs inode of current directory * @pos: current position in directory - * @ivcn_bits: log(2) of index vcn size - * @index_type: specifies whether @iu is an index root or an index allocation - * @iu: index root or index block to which @ie belongs * @ie: current index entry * @dirent: context for filldir callback supplied by the caller * @filldir: filldir callback supplied by the caller @@ -624,8 +605,7 @@ typedef enum { * Pass information specifying the current directory entry @ie to the @filldir * callback. */ -static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, - const INDEX_TYPE index_type, index_union iu, INDEX_ENTRY *ie, +static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir) { FILE_NAME_ATTR *fn = &ie->key.file_name; @@ -633,13 +613,6 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits, ntfs_log_trace("Entering.\n"); - /* Advance the position even if going to skip the entry. */ - if (index_type == INDEX_TYPE_ALLOCATION) - *pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu( - iu.ia->index_block_vcn) << ivcn_bits) + - dir_ni->vol->mft_record_size; - else /* if (index_type == INDEX_TYPE_ROOT) */ - *pos = (u8*)ie - (u8*)iu.ir; /* Skip root directory self reference entry. */ if (MREF_LE(ie->indexed_file) == FILE_root) return 0; @@ -770,9 +743,10 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (!ia_na) { if (errno != ENOENT) { - ntfs_log_perror("Failed to open index allocation attribute. " - "Directory inode 0x%llx is corrupt or bug", - (unsigned long long)dir_ni->mft_no); + ntfs_log_perror("Failed to open index allocation " + "attribute. Directory inode 0x%llx is " + "corrupt or bug", (unsigned long long) + dir_ni->mft_no); return -1; } i_size = 0; @@ -877,12 +851,13 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, /* Skip index root entry if continuing previous readdir. */ if (ir_pos > (u8*)ie - (u8*)ir) continue; + /* Advance the position even if going to skip the entry. */ + *pos = (u8*)ie - (u8*)ir; /* * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, - INDEX_TYPE_ROOT, ir, ie, dirent, filldir); + rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); if (rc) { ntfs_attr_put_search_ctx(ctx); ctx = NULL; @@ -1035,12 +1010,15 @@ find_next_index_buffer: /* Skip index entry if continuing previous readdir. */ if (ia_pos - ia_start > (u8*)ie - (u8*)ia) continue; + /* Advance the position even if going to skip the entry. */ + *pos = (u8*)ie - (u8*)ia + (sle64_to_cpu( + ia->index_block_vcn) << index_vcn_size_bits) + + dir_ni->vol->mft_record_size; /* * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, index_vcn_size_bits, - INDEX_TYPE_ALLOCATION, ia, ie, dirent, filldir); + rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); if (rc) goto done; } diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 9f802674..c1a4d2a5 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -302,7 +302,7 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen) dst = ntfs_malloc((len + 1) * sizeof(ntfschar)); if (dst) { memcpy(dst, s, len * sizeof(ntfschar)); - dst[len] = cpu_to_le16(L'\0'); + dst[len] = 0; } return dst; } @@ -623,7 +623,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len) } #endif /* Now write the NULL character. */ - ucs[o] = cpu_to_le16(L'\0'); + ucs[o] = 0; if (*outs != ucs) *outs = ucs; return o; diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index 2d1eccae..6f642670 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -326,7 +326,7 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, "allowed. Truncating excess characters.\n", (unsigned)(0x100 / sizeof(ntfschar))); label_len = 0x100; - new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0'); + new_label[label_len / sizeof(ntfschar)] = 0; } if (a) { if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index f2bc43ad..ed8ceaf8 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -441,11 +441,12 @@ ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft) * if parent is 5 (/) stop * get inode of parent */ +#define max_path 20 int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize) { // XXX option: names = posix/win32 or dos // flags: path, filename, or both - const int max_path = 20; + ntfs_volume *vol; ntfs_attr_search_ctx *ctx; @@ -555,6 +556,7 @@ int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize) return 1; } +#undef max_path /** * utils_attr_get_name From 2e44b6ca7c0f9720de887c3110d3113878feea7b Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 12 Dec 2006 15:44:52 +0000 Subject: [PATCH 162/289] fix some sparse warnings btw, it looks like sparse loses it head when it see something like: void foo(s64 *bar) { ... } ... { s64 baz; foo(&baz); ... } --- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsinfo.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index c53ca0fe..6a01ec2d 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -72,7 +72,7 @@ struct options { static const char *EXEC_NAME = "ntfscp"; static struct options opts; -volatile sig_atomic_t caught_terminate = 0; +static volatile sig_atomic_t caught_terminate = 0; /** * version - Print version information about the program diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 2fbd77c5..127c8f5a 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -985,7 +985,7 @@ static void ntfs_dump_attr_security_descriptor(ATTR_RECORD *attr, ntfs_volume *v if (attr->non_resident) { /* FIXME: We don't handle fragmented mapping pairs case. */ - runlist *rl = ntfs_mapping_pairs_decompress(vol, attr, 0); + runlist *rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); if (rl) { s64 data_size, bytes_read; @@ -1282,7 +1282,7 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) } if (opts.verbose) { - runlist *rl = ntfs_mapping_pairs_decompress(vol, a, 0); + runlist *rl = ntfs_mapping_pairs_decompress(vol, a, NULL); if (rl) { runlist *rlc = rl; // TODO: Switch this to properly aligned hex... @@ -1878,7 +1878,7 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) if (!opts.verbose) return; /* FIXME: We don't handle fragmented mapping pairs case. */ - rl = ntfs_mapping_pairs_decompress(vol, attr, 0); + rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); if (rl) { s64 bytes_read; From 10b22550cd059498502f1bc51b547fb361ae36a1 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 12 Dec 2006 19:00:00 +0000 Subject: [PATCH 163/289] more sparse fixes left only endianness and this stupid problems with s64 --- libntfs/gnome-vfs-module.c | 3 --- ntfsprogs/attrdef.c | 2 ++ ntfsprogs/boot.c | 2 ++ ntfsprogs/ntfsclone.c | 28 ++++++++++++++-------------- ntfsprogs/ntfscmp.c | 4 ++-- ntfsprogs/ntfsfix.c | 2 +- ntfsprogs/ntfsresize.c | 4 ++-- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/libntfs/gnome-vfs-module.c b/libntfs/gnome-vfs-module.c index 8f09563f..e1a85ad9 100644 --- a/libntfs/gnome-vfs-module.c +++ b/libntfs/gnome-vfs-module.c @@ -28,9 +28,6 @@ #include #include /* for g_atexit() */ -/* Filesystem-module-scope lock for _any_ libntfs access. */ -G_LOCK_DEFINE(libntfs); - static void vfs_module_shutdown_atexit(void); /** diff --git a/ntfsprogs/attrdef.c b/ntfsprogs/attrdef.c index 4ffa5eeb..55a48594 100644 --- a/ntfsprogs/attrdef.c +++ b/ntfsprogs/attrdef.c @@ -1,3 +1,5 @@ +#include "attrdef.h" + /** * attrdef_ntfs12_array */ diff --git a/ntfsprogs/boot.c b/ntfsprogs/boot.c index f0535ffd..f1bdeb67 100644 --- a/ntfsprogs/boot.c +++ b/ntfsprogs/boot.c @@ -1,3 +1,5 @@ +#include "boot.h" + /** * boot_array - the first 3429 bytes of $Boot * The first 3429 bytes of $Boot. The rest is just zero. Total 8192 bytes. diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 82044e5b..423ac154 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -95,7 +95,7 @@ static const char *dirty_volume_msg = "Volume '%s' is scheduled for a check or it was shutdown \n" "uncleanly. Please boot Windows or use the --force option to progress.\n"; -struct { +static struct { int verbose; int quiet; int debug; @@ -139,19 +139,19 @@ struct ntfs_walk_cluster { }; -ntfs_volume *vol = NULL; -struct bitmap lcn_bitmap; +static ntfs_volume *vol = NULL; +static struct bitmap lcn_bitmap; -int fd_in; -int fd_out; -FILE *msg_out = NULL; +static int fd_in; +static int fd_out; +static FILE *msg_out = NULL; -int wipe = 0; -unsigned int nr_used_mft_records = 0; -unsigned int wiped_unused_mft_data = 0; -unsigned int wiped_unused_mft = 0; -unsigned int wiped_resident_data = 0; -unsigned int wiped_timestamp_data = 0; +static int wipe = 0; +static unsigned int nr_used_mft_records = 0; +static unsigned int wiped_unused_mft_data = 0; +static unsigned int wiped_unused_mft = 0; +static unsigned int wiped_resident_data = 0; +static unsigned int wiped_timestamp_data = 0; static BOOL image_is_host_endian = FALSE; @@ -176,7 +176,7 @@ static BOOL image_is_host_endian = FALSE; #define NTFSCLONE_IMG_VER_MINOR 0 /* All values are in little endian. */ -struct { +static struct { char magic[IMAGE_MAGIC_SIZE]; u8 major_ver; u8 minor_ver; @@ -1406,7 +1406,7 @@ static void mount_volume(unsigned long new_mntflag) volume_size(vol, vol->nr_clusters)); } -struct ntfs_walk_cluster backup_clusters = { NULL, NULL }; +static struct ntfs_walk_cluster backup_clusters = { NULL, NULL }; static int device_offset_valid(int fd, s64 ofs) { diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 53361dc6..414b64b7 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -39,7 +39,7 @@ static const char *hibernated_volume_msg = "turned off properly\n"; -struct { +static struct { int debug; int show_progress; int verbose; @@ -309,7 +309,7 @@ static inline s64 get_nr_mft_records(ntfs_volume *vol) #define NTFSCMP_EXTENSION_RECORD 4 #define NTFSCMP_INODE_CLOSE_ERROR 5 -const char *ntfscmp_errs[] = { +static const char *ntfscmp_errs[] = { "OK", "INODE_OPEN_ERROR", "INODE_OPEN_IO_ERROR", diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 5aca7a9e..66e1becf 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -83,7 +83,7 @@ static const char *EXEC_NAME = "ntfsfix"; static const char *OK = "OK\n"; static const char *FAILED = "FAILED\n"; -struct { +static struct { char *volume; } opt; diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index b5cbeddb..b4797282 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -125,7 +125,7 @@ static const char *many_bad_sectors_msg = "* other reason. We suggest to get a replacement disk as soon as possible. *\n" "***************************************************************************\n"; -struct { +static struct { int verbose; int debug; int ro_flag; @@ -200,7 +200,7 @@ typedef struct { /* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster allocation related structure, attached to ntfs_resize_t */ -s64 max_free_cluster_range = 0; +static s64 max_free_cluster_range = 0; #define NTFS_MBYTE (1000 * 1000) From 914cf8f2be02c1756d53985b21d2ec956275f6b8 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 12 Dec 2006 20:27:32 +0000 Subject: [PATCH 164/289] Workaround for this bogus s64 warnings. Thanks, Linus! --- include/ntfs/types.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index ea156b27..0e214128 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -35,6 +35,10 @@ #include #endif +#ifdef __CHECKER__ +typedef int __attribute__((__mode__(__DI__))) int64_t; +#endif + typedef uint8_t u8; /* Unsigned types of an exact size */ typedef uint16_t u16; typedef uint32_t u32; From 1a4fb3431ca75d879fc1936f76ed6706f808e347 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 13 Dec 2006 00:11:50 +0000 Subject: [PATCH 165/289] - mkntfs: Generate a random DCE compliant UUID for the created volume and include --with-uuid[=PFX] and --without-uuid options. (Anton) - configure.ac: Set language to C. (Anton) - mkntfs: Always set default cluster size to 4096 bytes regardless of volume size. This is what Windows Vista does and it makes perfect sense from a performance point of view. (Anton) --- ChangeLog | 6 ++ configure.ac | 40 ++++++++++++ include/ntfs/volume.h | 2 + libntfs/dir.c | 7 +-- libntfs/logging.c | 24 ++++--- ntfsprogs/.cvsignore | 1 + ntfsprogs/Makefile.am | 3 +- ntfsprogs/mkntfs.8.in | 17 +---- ntfsprogs/mkntfs.c | 143 +++++++++++++++++++++++++++++++++++------- ntfsprogs/ntfsclone.c | 6 +- 10 files changed, 194 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9f3d41ce..7ae30243 100644 --- a/ChangeLog +++ b/ChangeLog @@ -106,6 +106,12 @@ xx/xx/2006 - x.xx.x - . Adapt unix_io pread()/pwrite() device operations to use pread()/ pwrite() system call and adapt win32_io device operations to not supply pread()/pwrite(). (Csaba Henk, Anton) + - mkntfs: Generate a random DCE compliant UUID for the created volume + and include --with-uuid[=PFX] and --without-uuid options. (Anton) + - configure.ac: Set language to C. (Anton) + - mkntfs: Always set default cluster size to 4096 bytes regardless of + volume size. This is what Windows Vista does and it makes perfect + sense from a performance point of view. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/configure.ac b/configure.ac index ddded1e8..bea9e751 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ AC_INIT([ntfsprogs],[1.13.2-WIP],[linux-ntfs-dev@lists.sourceforge.net]) LTVERSION_LIBNTFS="10:0:0" AC_SUBST(LTVERSION_LIBNTFS) +AC_LANG([C]) AC_CANONICAL_HOST([]) AC_CANONICAL_TARGET([]) AC_CONFIG_SRCDIR([config.h.in]) @@ -241,6 +242,42 @@ all_includes="$all_includes $USER_INCLUDES" AC_SUBST(all_includes) AC_SUBST(all_libraries) +# Specify support for generating DCE compliant UUIDs (aka GUIDs). We check if +# uuid/uuid.h header is present and the uuid library is present that goes with +# it and then check if uuid_generate() is present and usable. +# +# DCE UUIDs are enabled by default and can be disabled with the --disable-uuid +# option to the configure script. +AC_ARG_WITH(uuid, [ + --with-uuid@<:@=PFX@:>@ generate DCE compliant UUIDs, with optional prefix + to uuid library and headers @<:@default=detect@:>@ + --without-uuid do not generate DCE compliant UUIDs], + if test "$with_uuid" = "yes"; then + extrapath=default + elif test "$with_uuid" = "no"; then + extrapath= + else + extrapath=$with_uuid + fi, + extrapath=default +) +if test "x$extrapath" != "x"; then + if test "x$extrapath" != "xdefault"; then + MKNTFS_CPPFLAGS="$MKNTFS_CPPFLAGS -I$extrapath/include" + MKNTFS_LIBS="$MKNTFS_LIBS -L$extrapath/lib" + fi + AC_CHECK_HEADER([uuid/uuid.h], + AC_CHECK_LIB([uuid], [uuid_generate], + AC_DEFINE([ENABLE_UUID], 1, + [Define this to 1 if you want to enable generation of + DCE compliant UUIDs.]) + MKNTFS_LIBS="$MKNTFS_LIBS -luuid", + AC_MSG_WARN([Linux-NTFS DCE compliant UUID generation code requires the uuid library.]), + ), + AC_MSG_WARN([Linux-NTFS DCE compliant UUID generation code requires the uuid library.]), + ) +fi + # Get compiler name if test ! -z "$CC"; then _cc="$CC" @@ -292,6 +329,9 @@ AC_SUBST(LIBNTFS_CFLAGS) AC_SUBST(LIBNTFS_GNOMEVFS_CFLAGS) AC_SUBST(LIBNTFS_GNOMEVFS_LIBS) +AC_SUBST(MKNTFS_CPPFLAGS) +AC_SUBST(MKNTFS_LIBS) + AC_SUBST(AUTODIRS) # Checks for libraries. diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 54ed0b15..61915d07 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -152,6 +152,8 @@ struct _ntfs_volume { u8 major_ver; /* Ntfs major version of volume. */ u8 minor_ver; /* Ntfs minor version of volume. */ u16 flags; /* Bit array of VOLUME_* flags. */ + GUID guid; /* The volume guid if present (otherwise it is + a NULL guid). */ u16 sector_size; /* Byte size of a sector. */ u8 sector_size_bits; /* Log(2) of the byte size of a sector. */ diff --git a/libntfs/dir.c b/libntfs/dir.c index 38c2193c..0343db43 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -596,7 +596,6 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), /** * ntfs_filldir - ntfs specific filldir method - * @dir_ni: ntfs inode of current directory * @pos: current position in directory * @ie: current index entry * @dirent: context for filldir callback supplied by the caller @@ -605,7 +604,7 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), * Pass information specifying the current directory entry @ie to the @filldir * callback. */ -static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, INDEX_ENTRY *ie, +static int ntfs_filldir(s64 *pos, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir) { FILE_NAME_ATTR *fn = &ie->key.file_name; @@ -857,7 +856,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); + rc = ntfs_filldir(pos, ie, dirent, filldir); if (rc) { ntfs_attr_put_search_ctx(ctx); ctx = NULL; @@ -1018,7 +1017,7 @@ find_next_index_buffer: * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(dir_ni, pos, ie, dirent, filldir); + rc = ntfs_filldir(pos, ie, dirent, filldir); if (rc) goto done; } diff --git a/libntfs/logging.c b/libntfs/logging.c index 6e9a6f43..c3e8bc95 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -71,18 +71,20 @@ struct ntfs_logging { /** * ntfs_log - This struct controls all the logging in the library and tools. */ -static struct ntfs_logging ntfs_log = { +static struct ntfs_logging ntfs_log = (struct ntfs_logging) { + .levels = NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | + NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR | + NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | + NTFS_LOG_LEVEL_PROGRESS | #ifdef DEBUG - NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | + NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | #endif - NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING | - NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | - NTFS_LOG_LEVEL_PROGRESS, - NTFS_LOG_FLAG_ONLYNAME, + 0, + .flags = NTFS_LOG_FLAG_ONLYNAME, #ifdef DEBUG - ntfs_log_handler_outerr + .handler = ntfs_log_handler_outerr, #else - ntfs_log_handler_null + .handler = ntfs_log_handler_null, #endif }; @@ -343,8 +345,10 @@ int ntfs_log_redirect(const char *function, const char *file, #ifdef HAVE_SYSLOG_H int ntfs_log_handler_syslog(const char *function __attribute__((unused)), - const char *file, __attribute__((unused)) int line, u32 level, - void *data __attribute__((unused)), const char *format, va_list args) + const char *file, int line __attribute__((unused)), + u32 level __attribute__((unused)), + void *data __attribute__((unused)), const char *format, + va_list args) { int ret = 0; int olderr = errno; diff --git a/ntfsprogs/.cvsignore b/ntfsprogs/.cvsignore index d31d1c5a..fdb0f809 100644 --- a/ntfsprogs/.cvsignore +++ b/ntfsprogs/.cvsignore @@ -4,6 +4,7 @@ Makefile Makefile.in mkntfs ntfscat +ntfsck ntfsclone ntfscluster ntfscmp diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 17f3902b..398a7917 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -44,8 +44,9 @@ ntfsfix_SOURCES = ntfsfix.c utils.c utils.h ntfsfix_LDADD = $(AM_LIBS) ntfsfix_LDFLAGS = $(AM_LFLAGS) +mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS) mkntfs_SOURCES = attrdef.c attrdef.h upcase.c upcase.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h -mkntfs_LDADD = $(AM_LIBS) +mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS) mkntfs_LDFLAGS = $(AM_LFLAGS) ntfslabel_SOURCES = ntfslabel.c utils.c utils.h diff --git a/ntfsprogs/mkntfs.8.in b/ntfsprogs/mkntfs.8.in index 38c13021..69ecd9e1 100644 --- a/ntfsprogs/mkntfs.8.in +++ b/ntfsprogs/mkntfs.8.in @@ -127,20 +127,7 @@ Enable compression on the volume. Specify the size of clusters in bytes. Valid cluster size values are powers of two, with at least 256, and at most 65536 bytes per cluster. If omitted, .B mkntfs -determines the -.I cluster\-size -from the volume size. The value is determined as follows: -.TS -box; -lB lB lB -l l r. -Volume size Default cluster size -0 \- 512MB 512 bytes -512MB \- 1GB 1024 bytes -1GB \- 2GB 2048 bytes -2GB + 4096 bytes -.TE -.sp +uses 4096 bytes as the default cluster size. .sp Note that the default cluster size is set to be at least equal to the sector size as a cluster cannot be smaller than a sector. Also, note that values @@ -150,7 +137,7 @@ by Windows). .TP \fB\-N\fR, \fB\-\-ntfs\-version\fR STRING Select the version of NTFS you wish to create. This can be "1.2" -(Windows NT 4.0) or "3.1" (Windows XP, Server 2003 and Vista). +(Windows NT 4.0) or "3.1" (Windows XP, Server 2003, and Vista). Versions are upwards compatible and Windows 2000, which uses version "3.0", can read/write both. diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 70904b2f..967362e5 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -81,6 +81,10 @@ #ifdef HAVE_LIBGEN_H #include #endif +#ifdef ENABLE_UUID +#include +#endif + #ifdef HAVE_GETOPT_H #include @@ -2083,6 +2087,34 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, return i; } +#ifdef ENABLE_UUID + +/** + * add_attr_object_id - + * + * Note we insert only a basic object id which only has the GUID and none of + * the extended fields. This is because we currently only use this function + * when creating the object id for the volume. + * + * Return 0 on success or -errno on error. + */ +static int add_attr_object_id(MFT_RECORD *m, const GUID *object_id) +{ + OBJECT_ID_ATTR oi; + int err; + + oi = (OBJECT_ID_ATTR) { + .object_id = *object_id, + }; + err = insert_resident_attr_in_mft_record(m, AT_OBJECT_ID, NULL, + 0, 0, 0, 0, (u8*)&oi, sizeof(oi.object_id)); + if (err < 0) + ntfs_log_error("add_attr_vol_info failed: %s\n", strerror(-err)); + return err; +} + +#endif + /** * add_attr_sd * @@ -2754,9 +2786,8 @@ do_next: idx_entry = (INDEX_ENTRY*)((u8*)idx_entry + le16_to_cpu(idx_entry->length)); } - } else { + } else return -EINVAL; - } memmove((u8*)idx_entry + idx_size, (u8*)idx_entry, le32_to_cpu(m->bytes_in_use) - ((u8*)idx_entry - (u8*)m)); @@ -3300,6 +3331,56 @@ static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, return 0; } +#ifdef ENABLE_UUID + +/** + * index_obj_id_insert + * + * Insert an index entry with the key @guid and data pointing to the mft record + * @ref in the $O index root of the mft record @m (which must be the mft record + * for $ObjId). + * + * Return 0 on success or -errno on error. + */ +static int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, + const MFT_REF ref) +{ + INDEX_ENTRY *idx_entry_new; + int data_ofs, idx_size, err; + OBJ_ID_INDEX_DATA *oi; + + /* + * Insert the index entry for the object id in the index. + * + * First determine the size of the index entry to be inserted. This + * consists of the index entry header, followed by the index key, i.e. + * the GUID, followed by the index data, i.e. OBJ_ID_INDEX_DATA. + */ + data_ofs = (sizeof(INDEX_ENTRY_HEADER) + sizeof(GUID) + 7) & ~7; + idx_size = (data_ofs + sizeof(OBJ_ID_INDEX_DATA) + 7) & ~7; + idx_entry_new = ntfs_calloc(idx_size); + if (!idx_entry_new) + return -errno; + idx_entry_new->data_offset = cpu_to_le16(data_ofs); + idx_entry_new->data_length = cpu_to_le16(sizeof(OBJ_ID_INDEX_DATA)); + idx_entry_new->length = cpu_to_le16(idx_size); + idx_entry_new->key_length = cpu_to_le16(sizeof(GUID)); + idx_entry_new->key.object_id = *guid; + oi = (OBJ_ID_INDEX_DATA*)((u8*)idx_entry_new + data_ofs); + oi->mft_reference = ref; + err = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size, m, + NTFS_INDEX_O, 2, AT_UNUSED); + free(idx_entry_new); + if (err < 0) { + ntfs_log_error("index_obj_id_insert failed inserting index " + "entry: %s\n", strerror(-err)); + return err; + } + return 0; +} + +#endif + /** * mkntfs_cleanup */ @@ -3593,14 +3674,11 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) ntfs_log_debug("volume size = %llikiB\n", volume_size / 1024); /* If user didn't specify the cluster size, determine it now. */ if (!vol->cluster_size) { - if (volume_size <= 512LL << 20) /* <= 512MB */ - vol->cluster_size = 512; - else if (volume_size <= 1LL << 30) /* ]512MB-1GB] */ - vol->cluster_size = 1024; - else if (volume_size <= 2LL << 30) /* ]1GB-2GB] */ - vol->cluster_size = 2048; - else - vol->cluster_size = 4096; + /* + * Windows Vista always uses 4096 bytes as the default cluster + * size regardless of the volume size so we do it, too. + */ + vol->cluster_size = 4096; /* For small volumes on devices with large sector sizes. */ if (vol->cluster_size < (u32)opts.sector_size) vol->cluster_size = opts.sector_size; @@ -4192,11 +4270,16 @@ static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, return TRUE; } - /** * create_file_volume - */ -static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, VOLUME_FLAGS fl) +static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, + VOLUME_FLAGS fl + , const GUID *volume_guid +#ifndef ENABLE_UUID + __attribute__((unused)) +#endif + ) { int i, err; u8 *sd; @@ -4216,14 +4299,21 @@ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, VOLUME_FLAGS fl) if (!err) err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? strlen(g_vol->vol_name) : 0); +#ifdef ENABLE_UUID + if (!err) + err = add_attr_object_id(m, volume_guid); +#endif if (!err) { if (fl & VOLUME_IS_DIRTY) - ntfs_log_quiet("Setting the volume dirty so check disk runs " - "on next reboot into Windows.\n"); - err = add_attr_vol_info(m, fl, g_vol->major_ver, g_vol->minor_ver); + ntfs_log_quiet("Setting the volume dirty so check " + "disk runs on next reboot into " + "Windows.\n"); + err = add_attr_vol_info(m, fl, g_vol->major_ver, + g_vol->minor_ver); } if (err < 0) { - ntfs_log_error("Couldn't create $Volume: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $Volume: %s\n", + strerror(-err)); return FALSE; } return TRUE; @@ -4672,7 +4762,11 @@ static BOOL mkntfs_create_root_structures(void) volume_flags |= VOLUME_IS_DIRTY; } free(bs); - if (!create_file_volume(m, root_ref, volume_flags)) +#ifdef ENABLE_UUID + /* Generate a GUID for the volume. */ + uuid_generate((void*)&g_vol->guid); +#endif + if (!create_file_volume(m, root_ref, volume_flags, &g_vol->guid)) return FALSE; ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); @@ -4768,7 +4862,7 @@ static BOOL mkntfs_create_root_structures(void) if (!err) err = initialize_secure(buf_sds_init, buf_sds_first_size, m); - free (buf_sds_init); + free(buf_sds_init); buf_sds_init = NULL; if (err < 0) { ntfs_log_error("Couldn't create $Secure: %s\n", @@ -4882,7 +4976,6 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); return FALSE; } - ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); m->flags |= MFT_RECORD_IS_4; @@ -4897,12 +4990,18 @@ static BOOL mkntfs_create_root_structures(void) /* FIXME: This should be IGNORE_CASE */ if (!err) err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); + COLLATION_NTOFS_ULONGS, + g_vol->indx_record_size); +#ifdef ENABLE_UUID + if (!err) + err = index_obj_id_insert(m, &g_vol->guid, + MK_LE_MREF(FILE_Volume, FILE_Volume)); +#endif if (err < 0) { - ntfs_log_error("Couldn't create $ObjId: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $ObjId: %s\n", + strerror(-err)); return FALSE; } - ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); m->flags |= MFT_RECORD_IS_4; diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 423ac154..dac19f30 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1717,7 +1717,7 @@ static void check_dest_free_space(u64 src_bytes) { u64 dest_bytes; struct statvfs stvfs; - struct stat stat; + struct stat st; if (opt.metadata || opt.blkdev_out || opt.std_out) return; @@ -1732,8 +1732,8 @@ static void check_dest_free_space(u64 src_bytes) } /* If file is a FIFO then there is no point in checking the size. */ - if (!fstat(fd_out, &stat)) { - if (S_ISFIFO(stat.st_mode)) + if (!fstat(fd_out, &st)) { + if (S_ISFIFO(st.st_mode)) return; } else Printf("WARNING: fstat failed: %s\n", strerror(errno)); From 78c46fd3c3de902aca2fe0ee59606eaab1865b9c Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 13 Dec 2006 09:17:14 +0000 Subject: [PATCH 166/289] - Do not create object id attribute on NTFS 1.2 volumes. - Create object id attribute after volume flags attribute. --- ntfsprogs/mkntfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 967362e5..6d434b20 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -4299,10 +4299,6 @@ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, if (!err) err = add_attr_vol_name(m, g_vol->vol_name, g_vol->vol_name ? strlen(g_vol->vol_name) : 0); -#ifdef ENABLE_UUID - if (!err) - err = add_attr_object_id(m, volume_guid); -#endif if (!err) { if (fl & VOLUME_IS_DIRTY) ntfs_log_quiet("Setting the volume dirty so check " @@ -4311,6 +4307,10 @@ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, err = add_attr_vol_info(m, fl, g_vol->major_ver, g_vol->minor_ver); } +#ifdef ENABLE_UUID + if (!err && g_vol->major_ver >= 3) + err = add_attr_object_id(m, volume_guid); +#endif if (err < 0) { ntfs_log_error("Couldn't create $Volume: %s\n", strerror(-err)); From 19257df7f0d472e978b4353791ddea3935e33f37 Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 13 Dec 2006 10:46:49 +0000 Subject: [PATCH 167/289] Update version to 2.0.0, update NEWS, update mkntfs man page and mkntfs itself. - mkntfs: As announced, remove the deprecated support for creation of NTFS 1.2/3.0 volumes. We now create NTFS 3.1 volumes only. (Anton) - mkntfs: Remove lots of unused/unneeded debugging code. (Anton) --- ChangeLog | 5 +- NEWS | 13 +- configure.ac | 2 +- ntfsprogs/attrdef.c | 156 ------- ntfsprogs/attrdef.h | 1 - ntfsprogs/mkntfs.8.in | 28 +- ntfsprogs/mkntfs.c | 924 +++++++++--------------------------------- ntfsprogs/sd.c | 555 +++---------------------- ntfsprogs/sd.h | 1 - 9 files changed, 264 insertions(+), 1421 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7ae30243..8dabb45b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -xx/xx/2006 - x.xx.x - . +xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) @@ -112,6 +112,9 @@ xx/xx/2006 - x.xx.x - . - mkntfs: Always set default cluster size to 4096 bytes regardless of volume size. This is what Windows Vista does and it makes perfect sense from a performance point of view. (Anton) + - mkntfs: As announced, remove the deprecated support for creation of + NTFS 1.2/3.0 volumes. We now create NTFS 3.1 volumes only. (Anton) + - mkntfs: Remove lots of unused/unneeded debugging code. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/NEWS b/NEWS index 9dea75ff..bc35211c 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,10 @@ Current news ============ -Older news -========== +ntfsmount now has full basic read/write support. -mkntfs now creates NTFS 3.1 (Windows XP) volumes by default. The old NTFS 1.2 -format is now deprecated and whilst it can still be specified using a command -line option, it will be removed in a future release. +ntfsresize (and the entirety of ntfsprogs/libntfs in fact) now have full +support for Windows Vista. -ntfsmount can create/delete/move files and directories! It is not a full -implementation, thus sometimes it will say 'Operation is not supported', -nothing bad will happen to user data in this case. (Yura Pakhuchiy) +mkntfs now creates a DCE compliant GUID for the volume and does a few other +things to be more compliant with Windows Vista. diff --git a/configure.ac b/configure.ac index bea9e751..1afef49f 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ # AC_PREREQ(2.59) -AC_INIT([ntfsprogs],[1.13.2-WIP],[linux-ntfs-dev@lists.sourceforge.net]) +AC_INIT([ntfsprogs],[2.0.0],[linux-ntfs-dev@lists.sourceforge.net]) # # Before making a release, the LTVERSION string should be modified. diff --git a/ntfsprogs/attrdef.c b/ntfsprogs/attrdef.c index 55a48594..36501e5c 100644 --- a/ntfsprogs/attrdef.c +++ b/ntfsprogs/attrdef.c @@ -1,161 +1,5 @@ #include "attrdef.h" -/** - * attrdef_ntfs12_array - */ -const unsigned char attrdef_ntfs12_array[2400] = { - 36, 0, 83, 0, 84, 0, 65, 0, 78, 0, 68, 0, 65, 0, 82, 0, - 68, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0, - 65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 48, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 65, 0, 84, 0, 84, 0, 82, 0, 73, 0, 66, 0, 85, 0, - 84, 0, 69, 0, 95, 0, 76, 0, 73, 0, 83, 0, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 70, 0, 73, 0, 76, 0, 69, 0, 95, 0, 78, 0, 65, 0, - 77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, - 68, 0, 0, 0, 0, 0, 0, 0, 66, 2, 0, 0, 0, 0, 0, 0, - 36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0, - 86, 0, 69, 0, 82, 0, 83, 0, 73, 0, 79, 0, 78, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 83, 0, 69, 0, 67, 0, 85, 0, 82, 0, 73, 0, 84, 0, - 89, 0, 95, 0, 68, 0, 69, 0, 83, 0, 67, 0, 82, 0, 73, 0, - 80, 0, 84, 0, 79, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0, - 78, 0, 65, 0, 77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0, - 73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0, 65, 0, 84, 0, - 73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 68, 0, 65, 0, 84, 0, 65, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 82, 0, - 79, 0, 79, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 65, 0, - 76, 0, 76, 0, 79, 0, 67, 0, 65, 0, 84, 0, 73, 0, 79, 0, - 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 66, 0, 73, 0, 84, 0, 77, 0, 65, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 83, 0, 89, 0, 77, 0, 66, 0, 79, 0, 76, 0, 73, 0, - 67, 0, 95, 0, 76, 0, 73, 0, 78, 0, 75, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, - 36, 0, 69, 0, 65, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0, - 82, 0, 77, 0, 65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, - 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, - 36, 0, 69, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - /** * attrdef_ntfs3x_array */ diff --git a/ntfsprogs/attrdef.h b/ntfsprogs/attrdef.h index 09740fab..0c664394 100644 --- a/ntfsprogs/attrdef.h +++ b/ntfsprogs/attrdef.h @@ -1,7 +1,6 @@ #ifndef _NTFS_ATTRDEF_H_ #define _NTFS_ATTRDEF_H_ -extern const unsigned char attrdef_ntfs12_array[2400]; extern const unsigned char attrdef_ntfs3x_array[2560]; #endif /* _NTFS_ATTRDEF_H_ */ diff --git a/ntfsprogs/mkntfs.8.in b/ntfsprogs/mkntfs.8.in index 69ecd9e1..665be78c 100644 --- a/ntfsprogs/mkntfs.8.in +++ b/ntfsprogs/mkntfs.8.in @@ -45,10 +45,6 @@ mkntfs \- create an NTFS file system .B \-n ] [ -.B \-N -.I ntfs\-version -] -[ .B \-p .I part\-start\-sect ] @@ -123,6 +119,14 @@ Set the volume label for the filesystem. \fB\-C\fR, \fB\-\-enable\-compression\fR Enable compression on the volume. .TP +\fB\-n\fR, \fB\-\-no\-action\fR +Causes +.B mkntfs +to not actually create a filesystem, but display what it would do if it were +to create a filesystem. All steps of the format are carried out except the +actual writing to the device. +.SS Advanced options +.TP \fB\-c\fR, \fB\-\-cluster\-size\fR BYTES Specify the size of clusters in bytes. Valid cluster size values are powers of two, with at least 256, and at most 65536 bytes per cluster. If omitted, @@ -135,22 +139,6 @@ greater than 4096 have the side effect that compression is disabled on the volume (due to limitations in the NTFS compression algorithm currently in use by Windows). .TP -\fB\-N\fR, \fB\-\-ntfs\-version\fR STRING -Select the version of NTFS you wish to create. This can be "1.2" -(Windows NT 4.0) or "3.1" (Windows XP, Server 2003, and Vista). -Versions are upwards compatible and Windows 2000, which uses version "3.0", -can read/write both. - -If this option is omitted then version "3.1" is used. -.TP -\fB\-n\fR, \fB\-\-no\-action\fR -Causes -.B mkntfs -to not actually create a filesystem, but display what it would do if it were -to create a filesystem. All steps of the format are carried out except the -actual writing to the device. -.SS Advanced options -.TP \fB\-s\fR, \fB\-\-sector\-size\fR BYTES Specify the size of sectors in bytes. Valid sector size values are 256, 512, 1024, 2048 and 4096 bytes per sector. If omitted, diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 6d434b20..b21f1b29 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -206,8 +206,6 @@ static struct mkntfs_options { long mft_zone_multiplier; /* -z, value from 1 to 4. Default is 1. */ long long num_sectors; /* size of device in sectors */ long cluster_size; /* -c, format with this cluster-size */ - u8 ver_major; /* -N, ntfs version to create */ - u8 ver_minor; char *label; /* -L, volume label */ } opts; @@ -232,18 +230,17 @@ static void mkntfs_usage(void) " -Q, --quick Perform a quick format\n" " -L, --label STRING Set the volume label\n" " -C, --enable-compression Enable compression on the volume\n" - " -c, --cluster-size BYTES Specify the cluster size for the volume\n" " -I, --no-indexing Disable indexing on the volume\n" " -n, --no-action Do not write to disk\n" "\n" "Advanced options:\n" + " -c, --cluster-size BYTES Specify the cluster size for the volume\n" " -s, --sector-size BYTES Specify the sector size for the device\n" " -p, --partition-start SECTOR Specify the partition start sector\n" " -H, --heads NUM Specify the number of heads\n" " -S, --sectors-per-track NUM Specify the number of sectors per track\n" " -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" " -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" - " -N, --ntfs-version VERSION NTFS version: 3.1 (default) or 1.2 (old)\n" " -F, --force Force execution despite errors\n" "\n" "Output options:\n" @@ -351,7 +348,7 @@ static void mkntfs_init_options(struct mkntfs_options *opts2) */ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *opts2) { - static const char *sopt = "-c:CfFhH:IlL:nN:p:qQs:S:TvVz:"; + static const char *sopt = "-c:CfFhH:IlL:np:qQs:S:TvVz:"; static const struct option lopt[] = { { "cluster-size", required_argument, NULL, 'c' }, { "debug", no_argument, NULL, 'Z' }, @@ -365,7 +362,6 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * { "mft-zone-multiplier",required_argument, NULL, 'z' }, { "no-action", no_argument, NULL, 'n' }, { "no-indexing", no_argument, NULL, 'I' }, - { "ntfs-version", required_argument, NULL, 'N' }, { "partition-start", required_argument, NULL, 'p' }, { "quick", no_argument, NULL, 'Q' }, { "quiet", no_argument, NULL, 'q' }, @@ -435,28 +431,6 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * case 'n': opts2->no_action = TRUE; break; - case 'N': /* ntfs-version */ - if ((opts2->ver_major == 0) && (opts2->ver_minor == 0)) { - if (strcmp(optarg , "1.2") == 0) { - opts2->ver_major = 1; - opts2->ver_minor = 2; -/* - FIXME: version 3.0 was not checked - } else if (strcmp(optarg , "3.0") == 0) { - opts2->ver_major = 3; - opts2->ver_minor = 0; -*/ } else if (strcmp(optarg , "3.1") == 0) { - opts2->ver_major = 3; - opts2->ver_minor = 1; - } else { - ntfs_log_error("NTFS version '%s' is invalid.\n", optarg); - err++; - } - } else { - ntfs_log_error("You may only specify the NTFS version once.\n"); - err++; - } - break; case 'p': if (!mkntfs_parse_llong(optarg, "partition start", &opts2->part_start_sect)) err++; @@ -679,373 +653,6 @@ static s64 ntfs_rlwrite(struct ntfs_device *dev, const runlist *rl, return total; } - -/** - * dump_resident_attr_val - */ -static void dump_resident_attr_val(ATTR_TYPES type, char *val, u32 val_len) -{ - const char *don_t_know = "Don't know what to do with this attribute " - "type yet."; - const char *skip = "Skipping display of $%s attribute value.\n"; - const char *todo = "This is still work in progress."; - char *b = NULL; - int i, j; - - switch (type) { - case AT_STANDARD_INFORMATION: - /* TODO */ - printf("%s\n", todo); - return; - case AT_ATTRIBUTE_LIST: - /* TODO */ - printf("%s\n", todo); - return; - case AT_FILE_NAME: - /* TODO */ - printf("%s\n", todo); - return; - case AT_OBJECT_ID: - /* TODO */ - printf("%s\n", todo); - return; - case AT_SECURITY_DESCRIPTOR: - /* TODO */ - printf("%s\n", todo); - return; - case AT_VOLUME_NAME: - printf("Volume name length = %i\n", (unsigned int)val_len); - if (val_len) { - i = ntfs_ucstombs((ntfschar*)val, val_len, &b, 0); - if (i < 0) - printf("Volume name contains non-displayable " - "Unicode characters.\n"); - printf("Volume name = %s\n", b); - free(b); - } - return; - case AT_VOLUME_INFORMATION: -#define VOL_INF(x) ((VOLUME_INFORMATION *)(x)) - printf("NTFS version %i.%i\n", VOL_INF(val)->major_ver, - VOL_INF(val)->minor_ver); - i = VOL_INF(val)->flags; -#undef VOL_INF - printf("Volume flags = 0x%x: ", i); - if (!i) { - printf("NONE\n"); - return; - } - j = 0; - if (i & VOLUME_MODIFIED_BY_CHKDSK) { - printf("VOLUME_MODIFIED_BY_CHKDSK"); - j = 1; - } - if (i & VOLUME_REPAIR_OBJECT_ID) { - if (j) - printf(" | "); - printf("VOLUME_REPAIR_OBJECT_ID"); - j = 1; - } - if (i & VOLUME_DELETE_USN_UNDERWAY) { - if (j) - printf(" | "); - printf("VOLUME_DELETE_USN_UNDERWAY"); - j = 1; - } - if (i & VOLUME_MOUNTED_ON_NT4) { - if (j) - printf(" | "); - printf("VOLUME_MOUNTED_ON_NT4"); - j = 1; - } - if (i & VOLUME_UPGRADE_ON_MOUNT) { - if (j) - printf(" | "); - printf("VOLUME_UPGRADE_ON_MOUNT"); - j = 1; - } - if (i & VOLUME_RESIZE_LOG_FILE) { - if (j) - printf(" | "); - printf("VOLUME_RESIZE_LOG_FILE"); - j = 1; - } - if (i & VOLUME_IS_DIRTY) { - if (j) - printf(" | "); - printf("VOLUME_IS_DIRTY"); - j = 1; - } - printf("\n"); - return; - case AT_DATA: - printf(skip, "DATA"); - return; - case AT_INDEX_ROOT: - /* TODO */ - printf("collation_rule %u\n", (unsigned)le32_to_cpu - (((INDEX_ROOT*)val)->collation_rule)); - printf("index.entries_offset %u\n", (unsigned)le32_to_cpu - (((INDEX_ROOT*)val)->index.entries_offset)); - printf("index.index_length %u\n", (unsigned)le32_to_cpu - (((INDEX_ROOT*)val)->index.index_length)); - printf("%s\n", todo); - return; - case AT_INDEX_ALLOCATION: - /* TODO */ - printf("%s\n", todo); - return; - case AT_BITMAP: - printf(skip, "BITMAP"); - return; - case AT_REPARSE_POINT: - /* TODO */ - printf("%s\n", todo); - return; - case AT_EA_INFORMATION: - /* TODO */ - printf("%s\n", don_t_know); - return; - case AT_EA: - /* TODO */ - printf("%s\n", don_t_know); - return; - case AT_LOGGED_UTILITY_STREAM: - /* TODO */ - printf("%s\n", don_t_know); - return; - default: - i = le32_to_cpu(type); - printf("Cannot display unknown %s defined attribute type 0x%x" - ".\n", (u32)i >= - le32_to_cpu(AT_FIRST_USER_DEFINED_ATTRIBUTE) ? - "user" : "system", i); - } -} - -/** - * dump_resident_attr - */ -static void dump_resident_attr(ATTR_RECORD *a) -{ - int i; - - i = le32_to_cpu(a->value_length); - printf("Attribute value length = %u (0x%x)\n", i, i); - i = le16_to_cpu(a->value_offset); - printf("Attribute value offset = %u (0x%x)\n", i, i); - i = a->resident_flags; - printf("Resident flags = 0x%x: ", i); - if (!i) - printf("NONE\n"); - else if (i & ~RESIDENT_ATTR_IS_INDEXED) - printf("UNKNOWN FLAG(S)\n"); - else - printf("RESIDENT_ATTR_IS_INDEXED\n"); - dump_resident_attr_val(a->type, (char*)a + le16_to_cpu(a->value_offset), - le32_to_cpu(a->value_length)); -} - -/** - * dump_mapping_pairs_array - */ -static void dump_mapping_pairs_array(char *b __attribute__((unused)), - unsigned int max_len __attribute__((unused))) -{ - /* TODO */ - return; -} - -/** - * dump_non_resident_attr - */ -static void dump_non_resident_attr(ATTR_RECORD *a) -{ - s64 l; - int i; - - l = sle64_to_cpu(a->lowest_vcn); - printf("Lowest VCN = %lli (0x%llx)\n", (long long)l, - (unsigned long long)l); - l = sle64_to_cpu(a->highest_vcn); - printf("Highest VCN = %lli (0x%llx)\n", (long long)l, - (unsigned long long)l); - printf("Mapping pairs array offset = 0x%x\n", - le16_to_cpu(a->mapping_pairs_offset)); - printf("Compression unit = 0x%x: %sCOMPRESSED\n", a->compression_unit, - a->compression_unit ? "" : "NOT "); - if (sle64_to_cpu(a->lowest_vcn)) - printf("Attribute is not the first extent. The following " - "sizes are meaningless:\n"); - l = sle64_to_cpu(a->allocated_size); - printf("Allocated size = %lli (0x%llx)\n", (long long)l, - (unsigned long long)l); - l = sle64_to_cpu(a->data_size); - printf("Data size = %lli (0x%llx)\n", (long long)l, - (unsigned long long)l); - l = sle64_to_cpu(a->initialized_size); - printf("Initialized size = %lli (0x%llx)\n", - (long long)l, (unsigned long long)l); - if (a->flags & ATTR_COMPRESSION_MASK) { - l = sle64_to_cpu(a->compressed_size); - printf("Compressed size = %lli (0x%llx)\n", - (long long)l, (unsigned long long)l); - } - i = le16_to_cpu(a->mapping_pairs_offset); - dump_mapping_pairs_array((char*)a + i, le32_to_cpu(a->length) - i); -} - -/** - * dump_attr_record - */ -static void dump_attr_record(ATTR_RECORD *a) -{ - unsigned int u; - char s[0x200]; - int i; - - printf("-- Beginning dump of attribute record. --\n"); - if (a->type == AT_END) { - printf("Attribute type = 0x%x ($END)\n", - (unsigned int)const_le32_to_cpu(AT_END)); - u = le32_to_cpu(a->length); - printf("Length of resident part = %u (0x%x)\n", u, u); - return; - } - u = le32_to_cpu(a->type); - for (i = 0; g_vol->attrdef[i].type; i++) - if (le32_to_cpu(g_vol->attrdef[i].type) >= u) - break; - if (g_vol->attrdef[i].type) { -#if 0 - printf("type = 0x%x\n", le32_to_cpu(g_vol->attrdef[i].type)); - { char *p = (char*)g_vol->attrdef[i].name; - printf("name = %c%c%c%c%c\n", *p, p[1], p[2], p[3], p[4]); - } -#endif - if (ntfs_ucstombs(g_vol->attrdef[i].name, 0x40, (char**)&s, sizeof(s)) < 0) { - ntfs_log_error("Could not convert Unicode string to single " - "byte string in current locale.\n"); - strncpy(s, "Error converting Unicode string", - sizeof(s)); - } - } else { - strncpy(s, "UNKNOWN_TYPE", sizeof(s)); - } - printf("Attribute type = 0x%x (%s)\n", u, s); - u = le32_to_cpu(a->length); - printf("Length of resident part = %u (0x%x)\n", u, u); - printf("Attribute is %sresident\n", a->non_resident ? "non-" : ""); - printf("Name length = %u unicode characters\n", a->name_length); - printf("Name offset = %u (0x%x)\n", cpu_to_le16(a->name_offset), - cpu_to_le16(a->name_offset)); - u = a->flags; - if (a->name_length) { - if (ntfs_ucstombs((ntfschar*)((char*)a + cpu_to_le16(a->name_offset)), - min(sizeof(s), a->name_length + 1U), (char**)&s, sizeof(s)) < 0) { - ntfs_log_error("Could not convert Unicode string to single " - "byte string in current locale.\n"); - strncpy(s, "Error converting Unicode string", - sizeof(s)); - } - printf("Name = %s\n", s); - } - printf("Attribute flags = 0x%x: ", le16_to_cpu(u)); - if (!u) { - printf("NONE"); - } else { - int first = TRUE; - if (u & ATTR_COMPRESSION_MASK) { - if (u & ATTR_IS_COMPRESSED) { - printf("ATTR_IS_COMPRESSED"); - first = FALSE; - } - if ((u & ATTR_COMPRESSION_MASK) & ~ATTR_IS_COMPRESSED) { - if (!first) - printf(" | "); - else - first = FALSE; - printf("ATTR_UNKNOWN_COMPRESSION"); - } - } - if (u & ATTR_IS_ENCRYPTED) { - if (!first) - printf(" | "); - else - first = FALSE; - printf("ATTR_IS_ENCRYPTED"); - } - if (u & ATTR_IS_SPARSE) { - if (!first) - printf(" | "); - else - first = FALSE; - printf("ATTR_IS_SPARSE"); - } - } - printf("\n"); - printf("Attribute instance = %u\n", le16_to_cpu(a->instance)); - if (a->non_resident) { - dump_non_resident_attr(a); - } else { - dump_resident_attr(a); - } -} - -/** - * dump_mft_record - */ -__attribute__((unused)) -static void dump_mft_record(MFT_RECORD *m) -{ - ATTR_RECORD *a; - unsigned int u; - MFT_REF r; - - printf("-- Beginning dump of mft record. --\n"); - u = le32_to_cpu(m->magic); - printf("Mft record signature (magic) = %c%c%c%c\n", u & 0xff, - u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff); - u = le16_to_cpu(m->usa_ofs); - printf("Update sequence array offset = %u (0x%x)\n", u, u); - printf("Update sequence array size = %u\n", le16_to_cpu(m->usa_count)); - printf("$LogFile sequence number (lsn) = %llu\n", - (unsigned long long)le64_to_cpu(m->lsn)); - printf("Sequence number = %u\n", le16_to_cpu(m->sequence_number)); - printf("Reference (hard link) count = %u\n", - le16_to_cpu(m->link_count)); - u = le16_to_cpu(m->attrs_offset); - printf("First attribute offset = %u (0x%x)\n", u, u); - printf("Flags = %u: ", le16_to_cpu(m->flags)); - if (m->flags & MFT_RECORD_IN_USE) - printf("MFT_RECORD_IN_USE"); - else - printf("MFT_RECORD_NOT_IN_USE"); - if (m->flags & MFT_RECORD_IS_DIRECTORY) - printf(" | MFT_RECORD_IS_DIRECTORY"); - printf("\n"); - u = le32_to_cpu(m->bytes_in_use); - printf("Bytes in use = %u (0x%x)\n", u, u); - u = le32_to_cpu(m->bytes_allocated); - printf("Bytes allocated = %u (0x%x)\n", u, u); - r = le64_to_cpu(m->base_mft_record); - printf("Base mft record reference:\n\tMft record number = %llu\n\t" - "Sequence number = %u\n", (unsigned long long)MREF(r), - MSEQNO(r)); - printf("Next attribute instance = %u\n", - le16_to_cpu(m->next_attr_instance)); - a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset)); - printf("-- Beginning dump of attributes within mft record. --\n"); - while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) { - dump_attr_record(a); - if (a->type == AT_END) - break; - a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length)); - }; - printf("-- End of attributes. --\n"); -} - - /** * make_room_for_attribute - make room for an attribute inside an mft record * @m: mft record @@ -1980,21 +1587,17 @@ static int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, si.last_mft_change_time = si.creation_time; si.last_access_time = si.creation_time; si.file_attributes = flags; /* already LE */ - if (g_vol->major_ver < 3) { - memset(&si.reserved12, 0, sizeof(si.reserved12)); - } else { - si.maximum_versions = cpu_to_le32(0); - si.version_number = cpu_to_le32(0); - si.class_id = cpu_to_le32(0); - si.security_id = security_id; - if (si.security_id != 0) - sd_size = 72; - /* FIXME: $Quota support... */ - si.owner_id = cpu_to_le32(0); - si.quota_charged = cpu_to_le64(0ULL); - /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ - si.usn = cpu_to_le64(0ULL); - } + si.maximum_versions = cpu_to_le32(0); + si.version_number = cpu_to_le32(0); + si.class_id = cpu_to_le32(0); + si.security_id = security_id; + if (si.security_id != 0) + sd_size = 72; + /* FIXME: $Quota support... */ + si.owner_id = cpu_to_le32(0); + si.quota_charged = cpu_to_le64(0ULL); + /* FIXME: $UsnJrnl support... Not needed on fresh w2k3-volume */ + si.usn = cpu_to_le64(0ULL); /* NTFS 1.2: size of si = 48, NTFS 3.[01]: size of si = 72 */ err = insert_resident_attr_in_mft_record(m, AT_STANDARD_INFORMATION, NULL, 0, 0, 0, 0, (u8*)&si, sd_size); @@ -2914,8 +2517,6 @@ static int initialize_quota(MFT_RECORD *m) + le16_to_cpu(idx_entry_q1->data_offset)); idx_entry_q1_data->version = const_cpu_to_le32(0x02); idx_entry_q1_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; - if (g_vol->minor_ver == 0) - idx_entry_q1_data->flags |= QUOTA_FLAG_OUT_OF_DATE; idx_entry_q1_data->bytes_used = const_cpu_to_le64(0x00); idx_entry_q1_data->change_time = utc2ntfs(mkntfs_time()); idx_entry_q1_data->threshold = const_cpu_to_le64((s64)-1); @@ -3846,13 +3447,10 @@ static BOOL mkntfs_initialize_bitmaps(void) for (i = g_vol->nr_clusters; i < (u64)g_lcn_bitmap_byte_size << 3; i++) ntfs_bit_set(g_lcn_bitmap, i, 1); /* - * Determine mft_size: (16 (1.2) or 27 (3.0+) mft records) or - * one cluster, whichever is bigger. + * Mft size is 27 (NTFS 3.0+) mft records or one cluster, whichever is + * bigger. */ - if (g_vol->major_ver >= 3) - g_mft_size = 27; - else - g_mft_size = 16; + g_mft_size = 27; g_mft_size *= g_vol->mft_record_size; if (g_mft_size < (s32)g_vol->cluster_size) g_mft_size = g_vol->cluster_size; @@ -4010,13 +3608,7 @@ static BOOL mkntfs_initialize_rl_logfile(void) g_logfile_size = 512LL * 1024; /* -> 512kiB */ else if (volume_size <= 200LL * 1024 * 1024) /* < 200MiB */ g_logfile_size = 2048LL * 1024; /* -> 2MiB */ - else if (g_vol->major_ver < 3) { - if (volume_size >= 400LL << 20) /* > 400MiB */ - g_logfile_size = 4 << 20; /* -> 4MiB */ - else - g_logfile_size = (volume_size / 100) & - ~(g_vol->cluster_size - 1); - } else { + else { /* * FIXME: The $LogFile size is 64 MiB upwards from 12GiB but * the "200" divider below apparently approximates "100" or @@ -4132,14 +3724,13 @@ static BOOL mkntfs_fill_device_with_zeroes(void) */ int i; ssize_t bw; - unsigned long long position, mid_clust; + unsigned long long position; float progress_inc = (float)g_vol->nr_clusters / 100; u64 volume_size; volume_size = g_vol->nr_clusters << g_vol->cluster_size_bits; ntfs_log_progress("Initializing device with zeroes: 0%%"); - mid_clust = (volume_size >> 1) / g_vol->cluster_size; for (position = 0; position < (unsigned long long)g_vol->nr_clusters; position++) { if (!(position % (int)(progress_inc+1))) { @@ -4158,15 +3749,6 @@ static BOOL mkntfs_fill_device_with_zeroes(void) "system.\n"); return FALSE; } - if (position == mid_clust && - (g_vol->major_ver < 1 || - (g_vol->major_ver == 1 && - g_vol->minor_ver < 2))) { - ntfs_log_error("Error: Bad cluster found in " - "location reserved for system " - "file $Boot.\n"); - return FALSE; - } /* Add the baddie to our bad blocks list. */ if (!append_to_bad_blocks(position)) return FALSE; @@ -4189,10 +3771,7 @@ static BOOL mkntfs_fill_device_with_zeroes(void) if (bw != -1 || errno != EIO) { ntfs_log_error("This should not happen.\n"); return FALSE; - } else if (i + 1ull == position && - (g_vol->major_ver >= 2 || - (g_vol->major_ver == 1 && - g_vol->minor_ver >= 2))) { + } else if (i + 1ull == position) { ntfs_log_error("Error: Bad cluster found in " "location reserved for system " "file $Boot.\n"); @@ -4274,8 +3853,7 @@ static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, * create_file_volume - */ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, - VOLUME_FLAGS fl - , const GUID *volume_guid + VOLUME_FLAGS fl, const GUID *volume_guid #ifndef ENABLE_UUID __attribute__((unused)) #endif @@ -4308,7 +3886,7 @@ static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, g_vol->minor_ver); } #ifdef ENABLE_UUID - if (!err && g_vol->major_ver >= 3) + if (!err) err = add_attr_object_id(m, volume_guid); #endif if (err < 0) { @@ -4387,13 +3965,11 @@ static BOOL mkntfs_create_root_structures(void) VOLUME_FLAGS volume_flags = 0; int nr_sysfiles; u8 *buf_log = NULL; - int buf_sds_first_size = 0; - int buf_sds_size = 0; - char *buf_sds_init = NULL; - char *buf_sds = NULL; + int buf_sds_first_size; + char *buf_sds; ntfs_log_quiet("Creating NTFS volume structures.\n"); - nr_sysfiles = g_vol->major_ver < 3 ? 16 : 27; + nr_sysfiles = 27; /* * Setup an empty mft record. Note, we can just give 0 as the mft * reference as we are creating an NTFS 1.2 volume for which the mft @@ -4439,8 +4015,7 @@ static BOOL mkntfs_create_root_structures(void) m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); if (i < 16 || i > 23) { - if (g_vol->major_ver >= 3 && g_vol->minor_ver >= 1) - m->mft_record_number = cpu_to_le32(i); + m->mft_record_number = cpu_to_le32(i); m->flags |= MFT_RECORD_IN_USE; ntfs_bit_set(g_mft_bitmap, 0LL + i, 1); } @@ -4452,33 +4027,27 @@ static BOOL mkntfs_create_root_structures(void) if (opts.enable_compression) file_attrs |= FILE_ATTR_COMPRESSED; } - - if (g_vol->major_ver < 3) { + /* setting specific security_id flag and */ + /* file permissions for ntfs 3.x */ + if (i == 0 || i == 1 || i == 2 || i == 6 || i == 8 || + i == 10) { add_attr_std_info(m, file_attrs, - cpu_to_le32(0)); + cpu_to_le32(0x0100)); + } else if (i == 9) { + file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; + add_attr_std_info(m, file_attrs, + cpu_to_le32(0x0101)); + } else if (i == 11) { + add_attr_std_info(m, file_attrs, + cpu_to_le32(0x0101)); + } else if (i == 24 || i == 25 || i == 26) { + file_attrs |= FILE_ATTR_ARCHIVE; + file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; + add_attr_std_info(m, file_attrs, + cpu_to_le32(0x0101)); } else { - /* setting specific security_id flag and */ - /* file permissions for ntfs 3.x */ - if (i == 0 || i == 1 || i == 2 || i == 6 || i == 8 || - i == 10) { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0100)); - } else if (i == 9) { - file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else if (i == 11) { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else if (i == 24 || i == 25 || i == 26) { - file_attrs |= FILE_ATTR_ARCHIVE; - file_attrs |= FILE_ATTR_VIEW_INDEX_PRESENT; - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x0101)); - } else { - add_attr_std_info(m, file_attrs, - cpu_to_le32(0x00)); - } + add_attr_std_info(m, file_attrs, + cpu_to_le32(0x00)); } } /* The root directory mft reference. */ @@ -4493,19 +4062,8 @@ static BOOL mkntfs_create_root_structures(void) FILE_ATTR_I30_INDEX_PRESENT, 0, 0, ".", FILE_NAME_WIN32_AND_DOS); if (!err) { - if (g_vol->major_ver == 1) { - init_system_file_sd(FILE_root, &sd, &i); - err = add_attr_sd(m, sd, i); - } else if (NTFS_V3_0(g_vol->major_ver, g_vol->minor_ver)) { - init_system_file_sd(FILE_root, &sd, &i); - err = add_attr_sd(m, sd, i); - } else if (NTFS_V3_1(g_vol->major_ver, g_vol->minor_ver)) { - init_root_sd_31(&sd, &i); - err = add_attr_sd(m, sd, i); - } else { - ntfs_log_error("BUG: Unsupported NTFS version\n"); - return FALSE; - } + init_root_sd_31(&sd, &i); + err = add_attr_sd(m, sd, i); } /* FIXME: This should be IGNORE_CASE */ if (!err) @@ -4541,7 +4099,6 @@ static BOOL mkntfs_create_root_structures(void) strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ /* Add all other attributes, on a per-file basis for clarity. */ ntfs_log_verbose("Creating $MFT (mft record 0)\n"); m = (MFT_RECORD*)g_buf; @@ -4553,10 +4110,6 @@ static BOOL mkntfs_create_root_structures(void) g_mft_size, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$MFT", FILE_NAME_WIN32_AND_DOS); - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_MFT, &sd, &i); - err = add_attr_sd(m, sd, i); - } /* mft_bitmap is not modified in mkntfs; no need to sync it later. */ if (!err) err = add_attr_bitmap_positioned(m, NULL, 0, 0, g_rl_mft_bmp, @@ -4565,8 +4118,6 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("Couldn't create $MFT: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ - ntfs_log_verbose("Creating $MFTMirr (mft record 1)\n"); m = (MFT_RECORD*)(g_buf + 1 * g_vol->mft_record_size); err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_mftmirr, g_buf, @@ -4578,21 +4129,15 @@ static BOOL mkntfs_create_root_structures(void) g_rl_mftmirr[0].length * g_vol->cluster_size, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$MFTMirr", FILE_NAME_WIN32_AND_DOS); - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_MFTMirr, &sd, &i); - err = add_attr_sd(m, sd, i); - } if (err < 0) { ntfs_log_error("Couldn't create $MFTMirr: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); m = (MFT_RECORD*)(g_buf + 2 * g_vol->mft_record_size); buf_log = ntfs_malloc(g_logfile_size); if (!buf_log) return FALSE; - memset(buf_log, -1, g_logfile_size); err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_logfile, buf_log, g_logfile_size); @@ -4604,19 +4149,12 @@ static BOOL mkntfs_create_root_structures(void) g_logfile_size, g_logfile_size, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$LogFile", FILE_NAME_WIN32_AND_DOS); - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_LogFile, &sd, &i); - err = add_attr_sd(m, sd, i); - } if (err < 0) { ntfs_log_error("Couldn't create $LogFile: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ - ntfs_log_verbose("Creating $AttrDef (mft record 4)\n"); m = (MFT_RECORD*)(g_buf + 4 * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->attrdef, g_vol->attrdef_len); if (!err) err = create_hardlink(g_index_block, root_ref, m, @@ -4633,7 +4171,6 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("Couldn't create $AttrDef: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ ntfs_log_verbose("Creating $Bitmap (mft record 6)\n"); m = (MFT_RECORD*)(g_buf + 6 * g_vol->mft_record_size); /* the data attribute of $Bitmap must be non-resident or otherwise */ @@ -4651,16 +4188,10 @@ static BOOL mkntfs_create_root_structures(void) ~(g_vol->cluster_size - 1), g_lcn_bitmap_byte_size, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$Bitmap", FILE_NAME_WIN32_AND_DOS); - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_Bitmap, &sd, &i); - err = add_attr_sd(m, sd, i); - } if (err < 0) { ntfs_log_error("Couldn't create $Bitmap: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ - ntfs_log_verbose("Creating $Boot (mft record 7)\n"); m = (MFT_RECORD*)(g_buf + 7 * g_vol->mft_record_size); bs = ntfs_calloc(8192); @@ -4763,8 +4294,16 @@ static BOOL mkntfs_create_root_structures(void) } free(bs); #ifdef ENABLE_UUID - /* Generate a GUID for the volume. */ - uuid_generate((void*)&g_vol->guid); + /* + * We cheat a little here and if the user has requested all times to be + * set to zero then we set the GUID to zero as well. This options is + * only used for development purposes so that should be fine. + */ + if (!opts.use_epoch_time) { + /* Generate a GUID for the volume. */ + uuid_generate((void*)&g_vol->guid); + } else + memset(&g_vol->guid, 0, sizeof(g_vol->guid)); #endif if (!create_file_volume(m, root_ref, volume_flags, &g_vol->guid)) return FALSE; @@ -4783,94 +4322,52 @@ static BOOL mkntfs_create_root_structures(void) 0LL, 0LL, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$BadClus", FILE_NAME_WIN32_AND_DOS); } - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_BadClus, &sd, &i); - err = add_attr_sd(m, sd, i); - } if (err < 0) { ntfs_log_error("Couldn't create $BadClus: %s\n", strerror(-err)); return FALSE; } + /* create $Secure (NTFS 3.0+) */ + ntfs_log_verbose("Creating $Secure (mft record 9)\n"); + m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); + m->flags |= MFT_RECORD_IS_VIEW_INDEX; + if (!err) + err = create_hardlink(g_index_block, root_ref, m, + MK_LE_MREF(9, 9), 0LL, 0LL, + FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | + FILE_ATTR_VIEW_INDEX_PRESENT, 0, 0, + "$Secure", FILE_NAME_WIN32_AND_DOS); + buf_sds = NULL; + buf_sds_first_size = 0; + if (!err) { + int buf_sds_size; - /* dump_mft_record(m); */ - /* create $Quota (1.2) or $Secure (3.0+) */ - if (g_vol->major_ver < 3) { - ntfs_log_verbose("Creating $Quota (mft record 9)\n"); - m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, NULL, 0); - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(9, 9), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, - 0, "$Quota", FILE_NAME_WIN32_AND_DOS); - if (!err) { - init_system_file_sd(FILE_Secure, &sd, &i); - err = add_attr_sd(m, sd, i); - } - if (err < 0) { - ntfs_log_error("Couldn't create $Quota: %s\n", - strerror(-err)); + buf_sds_first_size = 0xfc; + buf_sds_size = 0x40000 + buf_sds_first_size; + buf_sds = ntfs_calloc(buf_sds_size); + if (!buf_sds) return FALSE; - } - } else { - ntfs_log_verbose("Creating $Secure (mft record 9)\n"); - m = (MFT_RECORD*)(g_buf + 9 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(9, 9), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_VIEW_INDEX_PRESENT, 0, 0, - "$Secure", FILE_NAME_WIN32_AND_DOS); - if (!err) { - if (g_vol->minor_ver == 0) { - buf_sds_first_size = 0x1E0; - buf_sds_size = 0x40000 + buf_sds_first_size; - buf_sds_init = ntfs_calloc(buf_sds_first_size); - if (!buf_sds_init) - return FALSE; - init_secure_30(buf_sds_init); - } else { - buf_sds_first_size = 0xFC; - buf_sds_size = 0x40000 + buf_sds_first_size; - buf_sds_init = ntfs_calloc(buf_sds_first_size); - if (!buf_sds_init) - return FALSE; - init_secure_31(buf_sds_init); - } - buf_sds = ntfs_calloc(buf_sds_size); - if (!buf_sds) { - free(buf_sds_init); - return FALSE; - } - memcpy(buf_sds, buf_sds_init, buf_sds_first_size); - memcpy(buf_sds + 0x40000, buf_sds_init, - buf_sds_first_size); - err = add_attr_data(m, "$SDS", 4, 0, 0, (u8*)buf_sds, - buf_sds_size); - free(buf_sds); - } - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$SDH", 4, 0, AT_UNUSED, - COLLATION_NTOFS_SECURITY_HASH, - g_vol->indx_record_size); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$SII", 4, 0, AT_UNUSED, - COLLATION_NTOFS_ULONG, g_vol->indx_record_size); - if (!err) - err = initialize_secure(buf_sds_init, buf_sds_first_size, m); - - free(buf_sds_init); - buf_sds_init = NULL; - if (err < 0) { - ntfs_log_error("Couldn't create $Secure: %s\n", - strerror(-err)); - return FALSE; - } + init_secure_31(buf_sds); + memcpy(buf_sds + 0x40000, buf_sds, buf_sds_first_size); + err = add_attr_data(m, "$SDS", 4, 0, 0, (u8*)buf_sds, + buf_sds_size); + } + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$SDH", 4, 0, AT_UNUSED, + COLLATION_NTOFS_SECURITY_HASH, + g_vol->indx_record_size); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$SII", 4, 0, AT_UNUSED, + COLLATION_NTOFS_ULONG, g_vol->indx_record_size); + if (!err) + err = initialize_secure(buf_sds, buf_sds_first_size, m); + free(buf_sds); + if (err < 0) { + ntfs_log_error("Couldn't create $Secure: %s\n", + strerror(-err)); + return FALSE; } - /* dump_mft_record(m); */ ntfs_log_verbose("Creating $UpCase (mft record 0xa)\n"); m = (MFT_RECORD*)(g_buf + 0xa * g_vol->mft_record_size); err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->upcase, @@ -4883,56 +4380,33 @@ static BOOL mkntfs_create_root_structures(void) ~(g_vol->cluster_size - 1), g_vol->upcase_len << 1, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$UpCase", FILE_NAME_WIN32_AND_DOS); - if (!err && g_vol->major_ver == 1) { - init_system_file_sd(FILE_UpCase, &sd, &i); - err = add_attr_sd(m, sd, i); - } if (err < 0) { ntfs_log_error("Couldn't create $UpCase: %s\n", strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ - - if (g_vol->major_ver < 3) { - ntfs_log_verbose("Creating empty record, marked as in use " - "(mft record 11)\n"); - m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, NULL, 0); - if (!err) { - init_system_file_sd(11, &sd, &j); - err = add_attr_sd(m, sd, j); - } - if (err < 0) { - ntfs_log_error("Couldn't create system file 11 (0x0b): %s\n", - strerror(-err)); - return FALSE; - } - /* dump_mft_record(m); */ - } else { - ntfs_log_verbose("Creating $Extend (mft record 11)\n"); - /* - * $Extends index must be resident. Otherwise, w2k3 will - * regard the volume as corrupt. (ERSO) - */ - m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_DIRECTORY; - if (!err) - err = create_hardlink(g_index_block, root_ref, m, - MK_LE_MREF(11, 11), 0LL, 0LL, - FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_I30_INDEX_PRESENT, 0, 0, - "$Extend", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$I30", 4, 0, AT_FILE_NAME, - COLLATION_FILE_NAME, g_vol->indx_record_size); - if (err < 0) { - ntfs_log_error("Couldn't create $Extend: %s\n", - strerror(-err)); - return FALSE; - } + ntfs_log_verbose("Creating $Extend (mft record 11)\n"); + /* + * $Extend index must be resident. Otherwise, w2k3 will regard the + * volume as corrupt. (ERSO) + */ + m = (MFT_RECORD*)(g_buf + 11 * g_vol->mft_record_size); + m->flags |= MFT_RECORD_IS_DIRECTORY; + if (!err) + err = create_hardlink(g_index_block, root_ref, m, + MK_LE_MREF(11, 11), 0LL, 0LL, + FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | + FILE_ATTR_I30_INDEX_PRESENT, 0, 0, + "$Extend", FILE_NAME_WIN32_AND_DOS); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$I30", 4, 0, AT_FILE_NAME, + COLLATION_FILE_NAME, g_vol->indx_record_size); + if (err < 0) { + ntfs_log_error("Couldn't create $Extend: %s\n", + strerror(-err)); + return FALSE; } - /* NTFS 1.2 reserved system files (mft records 0xc-0xf) */ + /* NTFS reserved system files (mft records 0xc-0xf) */ for (i = 0xc; i < 0x10; i++) { ntfs_log_verbose("Creating system file (mft record 0x%x)\n", i); m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); @@ -4946,81 +4420,78 @@ static BOOL mkntfs_create_root_structures(void) i, i, strerror(-err)); return FALSE; } - /* dump_mft_record(m); */ } /* create systemfiles for ntfs volumes (3.1) */ /* starting with file 24 (ignoring file 16-23) */ - if (g_vol->major_ver >= 3) { - extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | - FILE_ATTR_ARCHIVE | FILE_ATTR_VIEW_INDEX_PRESENT; - ntfs_log_verbose("Creating $Quota (mft record 24)\n"); - m = (MFT_RECORD*)(g_buf + 24 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), extend_ref, m, - MK_LE_MREF(24, 1), 0LL, 0LL, extend_flags, - 0, 0, "$Quota", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$Q", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONG, g_vol->indx_record_size); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_SID, g_vol->indx_record_size); - if (!err) - err = initialize_quota(m); - if (err < 0) { - ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); - m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), extend_ref, - m, MK_LE_MREF(25, 1), 0LL, 0LL, - extend_flags, 0, 0, "$ObjId", - FILE_NAME_WIN32_AND_DOS); + extend_flags = FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM | + FILE_ATTR_ARCHIVE | FILE_ATTR_VIEW_INDEX_PRESENT; + ntfs_log_verbose("Creating $Quota (mft record 24)\n"); + m = (MFT_RECORD*)(g_buf + 24 * g_vol->mft_record_size); + m->flags |= MFT_RECORD_IS_4; + m->flags |= MFT_RECORD_IS_VIEW_INDEX; + if (!err) + err = create_hardlink_res((MFT_RECORD*)(g_buf + + 11 * g_vol->mft_record_size), extend_ref, m, + MK_LE_MREF(24, 1), 0LL, 0LL, extend_flags, + 0, 0, "$Quota", FILE_NAME_WIN32_AND_DOS); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$Q", 2, 0, AT_UNUSED, + COLLATION_NTOFS_ULONG, g_vol->indx_record_size); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, + COLLATION_NTOFS_SID, g_vol->indx_record_size); + if (!err) + err = initialize_quota(m); + if (err < 0) { + ntfs_log_error("Couldn't create $Quota: %s\n", strerror(-err)); + return FALSE; + } + ntfs_log_verbose("Creating $ObjId (mft record 25)\n"); + m = (MFT_RECORD*)(g_buf + 25 * g_vol->mft_record_size); + m->flags |= MFT_RECORD_IS_4; + m->flags |= MFT_RECORD_IS_VIEW_INDEX; + if (!err) + err = create_hardlink_res((MFT_RECORD*)(g_buf + + 11 * g_vol->mft_record_size), extend_ref, + m, MK_LE_MREF(25, 1), 0LL, 0LL, + extend_flags, 0, 0, "$ObjId", + FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, - g_vol->indx_record_size); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$O", 2, 0, AT_UNUSED, + COLLATION_NTOFS_ULONGS, + g_vol->indx_record_size); #ifdef ENABLE_UUID - if (!err) - err = index_obj_id_insert(m, &g_vol->guid, - MK_LE_MREF(FILE_Volume, FILE_Volume)); + if (!err) + err = index_obj_id_insert(m, &g_vol->guid, + MK_LE_MREF(FILE_Volume, FILE_Volume)); #endif - if (err < 0) { - ntfs_log_error("Couldn't create $ObjId: %s\n", - strerror(-err)); - return FALSE; - } - ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); - m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); - m->flags |= MFT_RECORD_IS_4; - m->flags |= MFT_RECORD_IS_VIEW_INDEX; - if (!err) - err = create_hardlink_res((MFT_RECORD*)(g_buf + - 11 * g_vol->mft_record_size), - extend_ref, m, MK_LE_MREF(26, 1), - 0LL, 0LL, extend_flags, 0, 0, - "$Reparse", FILE_NAME_WIN32_AND_DOS); - /* FIXME: This should be IGNORE_CASE */ - if (!err) - err = add_attr_index_root(m, "$R", 2, 0, AT_UNUSED, - COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); - if (err < 0) { - ntfs_log_error("Couldn't create $Reparse: %s\n", + if (err < 0) { + ntfs_log_error("Couldn't create $ObjId: %s\n", strerror(-err)); - return FALSE; - } + return FALSE; + } + ntfs_log_verbose("Creating $Reparse (mft record 26)\n"); + m = (MFT_RECORD*)(g_buf + 26 * g_vol->mft_record_size); + m->flags |= MFT_RECORD_IS_4; + m->flags |= MFT_RECORD_IS_VIEW_INDEX; + if (!err) + err = create_hardlink_res((MFT_RECORD*)(g_buf + + 11 * g_vol->mft_record_size), + extend_ref, m, MK_LE_MREF(26, 1), + 0LL, 0LL, extend_flags, 0, 0, + "$Reparse", FILE_NAME_WIN32_AND_DOS); + /* FIXME: This should be IGNORE_CASE */ + if (!err) + err = add_attr_index_root(m, "$R", 2, 0, AT_UNUSED, + COLLATION_NTOFS_ULONGS, g_vol->indx_record_size); + if (err < 0) { + ntfs_log_error("Couldn't create $Reparse: %s\n", + strerror(-err)); + return FALSE; } return TRUE; } @@ -5049,6 +4520,9 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) ntfs_log_perror("Could not create volume"); goto done; } + /* Create NTFS 3.1 (Windows XP/Vista) volumes. */ + g_vol->major_ver = 3; + g_vol->minor_ver = 1; /* Transfer some options to the volume. */ if (opts.label) { g_vol->vol_name = strdup(opts.label); @@ -5057,14 +4531,6 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) goto done; } } - if (opts.ver_major) { - g_vol->major_ver = opts.ver_major; - g_vol->minor_ver = opts.ver_minor; - } else { - /* Create NTFS 3.1 (Windows XP) volumes by default. */ - g_vol->major_ver = 3; - g_vol->minor_ver = 1; - } if (opts.cluster_size >= 0) g_vol->cluster_size = opts.cluster_size; /* Length is in unicode characters. */ @@ -5074,25 +4540,14 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) goto done; init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); - if (g_vol->major_ver < 3) { - g_vol->attrdef = ntfs_calloc(36000); - if (g_vol->attrdef) { - memcpy(g_vol->attrdef, attrdef_ntfs12_array, - sizeof(attrdef_ntfs12_array)); - g_vol->attrdef_len = 36000; - } - } else { - g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); - if (g_vol->attrdef) { - memcpy(g_vol->attrdef, attrdef_ntfs3x_array, - sizeof(attrdef_ntfs3x_array)); - g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); - } - } + g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); if (!g_vol->attrdef) { ntfs_log_perror("Could not create attrdef structure"); goto done; } + memcpy(g_vol->attrdef, attrdef_ntfs3x_array, + sizeof(attrdef_ntfs3x_array)); + g_vol->attrdef_len = sizeof(attrdef_ntfs3x_array); /* Open the partition. */ if (!mkntfs_open_partition(g_vol)) goto done; @@ -5259,4 +4714,3 @@ int main(int argc, char *argv[]) done: return result; } - diff --git a/ntfsprogs/sd.c b/ntfsprogs/sd.c index 69437210..ac89c43f 100644 --- a/ntfsprogs/sd.c +++ b/ntfsprogs/sd.c @@ -5,7 +5,7 @@ /** * init_system_file_sd * - * NTFS 1.2, 3.0, 3.1 - System files security decriptors + * NTFS 3.1 - System files security decriptors * ===================================================== * * Create the security descriptor for system file number @sys_file_no and @@ -17,9 +17,7 @@ * $Volume, $Quota, and system files 0xb-0xf are the same. They are almost the * same as the above, the only difference being that the two SIDs present in * the DACL grant GENERIC_WRITE and GENERIC_READ equivalent privileges while - * the above only grant GENERIC_READ equivalent privileges. (For some reason - * the flags for GENERIC_READ/GENERIC_WRITE are not set by NT4, even though - * the permissions are equivalent, so we comply. + * the above only grant GENERIC_READ equivalent privileges. * * Root directory system file (".") is different altogether. * @@ -46,15 +44,9 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) sd->revision = 1; sd->alignment = 0; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - if (sys_file_no == FILE_root) { - *sd_val_len = 0x50; - sd->owner = const_cpu_to_le32(0x30); - sd->group = const_cpu_to_le32(0x40); - } else { - *sd_val_len = 0x68; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - } + *sd_val_len = 0x68; + sd->owner = const_cpu_to_le32(0x48); + sd->group = const_cpu_to_le32(0x58); sd->sacl = const_cpu_to_le32(0); sd->dacl = const_cpu_to_le32(0x14); /* @@ -64,13 +56,8 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) acl = (ACL*)((char*)sd + le32_to_cpu(sd->dacl)); acl->revision = 2; acl->alignment1 = 0; - if (sys_file_no == FILE_root) { - acl->size = const_cpu_to_le16(0x1c); - acl->ace_count = const_cpu_to_le16(1); - } else { - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(2); - } + acl->size = const_cpu_to_le16(0x34); + acl->ace_count = const_cpu_to_le16(2); acl->alignment2 = const_cpu_to_le16(0); /* * Now at offset 0x1c, just after the DACL's ACL, we have the first @@ -78,10 +65,7 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) */ aa_ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; - if (sys_file_no == FILE_root) - aa_ace->flags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE; - else - aa_ace->flags = 0; + aa_ace->flags = 0; aa_ace->size = const_cpu_to_le16(0x14); switch (sys_file_no) { case FILE_MFT: case FILE_MFTMirr: case FILE_LogFile: @@ -96,13 +80,6 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA; break; - case FILE_root: - aa_ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_READ_ATTRIBUTES | FILE_DELETE_CHILD | - FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA | - FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | - FILE_LIST_DIRECTORY; - break; } aa_ace->sid.revision = 1; aa_ace->sid.sub_authority_count = 1; @@ -111,63 +88,53 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) aa_ace->sid.identifier_authority.value[2] = 0; aa_ace->sid.identifier_authority.value[3] = 0; aa_ace->sid.identifier_authority.value[4] = 0; - if (sys_file_no == FILE_root) { - /* SECURITY_WORLD_SID_AUTHORITY (S-1-1) */ - aa_ace->sid.identifier_authority.value[5] = 1; - aa_ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_WORLD_RID); - /* This is S-1-1-0, the WORLD_SID. */ - } else { - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - aa_ace->sid.identifier_authority.value[5] = 5; - aa_ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - } + /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ + aa_ace->sid.identifier_authority.value[5] = 5; + aa_ace->sid.sub_authority[0] = + const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); /* * Now at offset 0x30 within security descriptor, just after the first * ACE of the DACL. All system files, except the root directory, have * a second ACE. */ - if (sys_file_no != FILE_root) { - /* The second ACE of the DACL. Type is access allowed. */ - aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace + - le16_to_cpu(aa_ace->size)); - aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; - aa_ace->flags = 0; - aa_ace->size = const_cpu_to_le16(0x18); - switch (sys_file_no) { - case FILE_MFT: case FILE_MFTMirr: - case FILE_LogFile: case FILE_AttrDef: - case FILE_Bitmap: case FILE_Boot: - case FILE_BadClus: case FILE_UpCase: - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | - FILE_READ_ATTRIBUTES | FILE_READ_EA | - FILE_READ_DATA; - break; - case FILE_Volume: case FILE_Secure: - case 0xb ... 0xffff : - aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | - FILE_WRITE_ATTRIBUTES | - FILE_READ_ATTRIBUTES | FILE_WRITE_EA | - FILE_READ_EA | FILE_APPEND_DATA | - FILE_WRITE_DATA | FILE_READ_DATA; - break; - } - aa_ace->sid.revision = 1; - aa_ace->sid.sub_authority_count = 2; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - aa_ace->sid.identifier_authority.value[0] = 0; - aa_ace->sid.identifier_authority.value[1] = 0; - aa_ace->sid.identifier_authority.value[2] = 0; - aa_ace->sid.identifier_authority.value[3] = 0; - aa_ace->sid.identifier_authority.value[4] = 0; - aa_ace->sid.identifier_authority.value[5] = 5; - aa_ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - aa_ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - /* Now at offset 0x48 into the security descriptor. */ + /* The second ACE of the DACL. Type is access allowed. */ + aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace + + le16_to_cpu(aa_ace->size)); + aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; + aa_ace->flags = 0; + aa_ace->size = const_cpu_to_le16(0x18); + switch (sys_file_no) { + case FILE_MFT: case FILE_MFTMirr: + case FILE_LogFile: case FILE_AttrDef: + case FILE_Bitmap: case FILE_Boot: + case FILE_BadClus: case FILE_UpCase: + aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | + FILE_READ_ATTRIBUTES | FILE_READ_EA | + FILE_READ_DATA; + break; + case FILE_Volume: case FILE_Secure: + case 0xb ... 0xffff : + aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | + FILE_WRITE_ATTRIBUTES | + FILE_READ_ATTRIBUTES | FILE_WRITE_EA | + FILE_READ_EA | FILE_APPEND_DATA | + FILE_WRITE_DATA | FILE_READ_DATA; + break; } + aa_ace->sid.revision = 1; + aa_ace->sid.sub_authority_count = 2; + /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ + aa_ace->sid.identifier_authority.value[0] = 0; + aa_ace->sid.identifier_authority.value[1] = 0; + aa_ace->sid.identifier_authority.value[2] = 0; + aa_ace->sid.identifier_authority.value[3] = 0; + aa_ace->sid.identifier_authority.value[4] = 0; + aa_ace->sid.identifier_authority.value[5] = 5; + aa_ace->sid.sub_authority[0] = + const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + aa_ace->sid.sub_authority[1] = + const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + /* Now at offset 0x48 into the security descriptor. */ /* As specified in the security descriptor, we now have the owner SID.*/ sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 1; @@ -262,8 +229,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //ace2 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); @@ -323,8 +289,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //ace5 ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); @@ -343,8 +308,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //ace6 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); @@ -363,8 +327,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //ace7 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); @@ -381,8 +344,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 1; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_WORLD_RID); + ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_WORLD_RID); //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); @@ -395,10 +357,8 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //group sid sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); @@ -411,408 +371,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); -} - -/** - * init_secure - * - * NTFS 3.0 - System files security decriptors - * =========================================== - * Create the security descriptor entries in $SDS data stream like they - * are in a partition, newly formatted with windows 2000 - */ -void init_secure_30(char *sd_val) -{ - SECURITY_DESCRIPTOR_HEADER *sds; - SECURITY_DESCRIPTOR_RELATIVE *sd; - ACL *acl; - ACCESS_ALLOWED_ACE *ace; - SID *sid; - -/* - * security descriptor #1 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val); - sds->hash = const_cpu_to_le32(0xF80312F0); - sds->security_id = const_cpu_to_le32(0x0100); - sds->offset = const_cpu_to_le64(0x00); - sds->length = const_cpu_to_le32(0x7C); - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(0x02); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x120089); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x120089); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - -/* - * security descriptor #2 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80); - sds->hash = const_cpu_to_le32(0xB32451); - sds->security_id = const_cpu_to_le32(0x0101); - sds->offset = const_cpu_to_le64(0x80); - sds->length = const_cpu_to_le32(0x7C); - - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(0x02); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x12019F); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x12019F); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - -/* - * security descriptor #3 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80 + 0x80); - sds->hash = const_cpu_to_le32(0x0A9F9562); - sds->security_id = const_cpu_to_le32(0x0102); - sds->offset = const_cpu_to_le64(0x0100); - sds->length = const_cpu_to_le32(0x60); - - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x30); - sd->group = const_cpu_to_le32(0x40); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x1C); - acl->ace_count = const_cpu_to_le16(0x01); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_WRITE_DATA | - FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | - FILE_TRAVERSE | FILE_DELETE_CHILD | - FILE_READ_ATTRIBUTES; - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x01; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - -/* - * security descriptor #4 - */ - //header - sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80 + 0x80 + 0x60); - sds->hash = const_cpu_to_le32(0x453F0A2E); - sds->security_id = const_cpu_to_le32(0x0103); - sds->offset = const_cpu_to_le64(0x0160); - sds->length = const_cpu_to_le32(0x78); - - //security descriptor relative - sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + - sizeof(SECURITY_DESCRIPTOR_HEADER)); - sd->revision = 0x01; - sd->alignment = 0x00; - sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); - - //acl - acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; - acl->size = const_cpu_to_le16(0x34); - acl->ace_count = const_cpu_to_le16(0x02); - acl->alignment2 = 0x00; - - //ace1 - ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x18); - ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_WRITE_DATA | - FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | - FILE_TRAVERSE | FILE_DELETE_CHILD | - FILE_READ_ATTRIBUTES; - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - //ace2 - ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_WRITE_DATA | - FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | - FILE_TRAVERSE | FILE_DELETE_CHILD | - FILE_READ_ATTRIBUTES; - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 5; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - //owner sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); - sid->revision = 0x01; - sid->sub_authority_count = 0x02; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = - const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - - //group sid - sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); - sid->revision = 0x01; - sid->sub_authority_count = 0x01; - // SECURITY_NT_SID_AUTHORITY (S-1-5) - sid->identifier_authority.value[0] = 0; - sid->identifier_authority.value[1] = 0; - sid->identifier_authority.value[2] = 0; - sid->identifier_authority.value[3] = 0; - sid->identifier_authority.value[4] = 0; - sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = - const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - - return; + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); } /** diff --git a/ntfsprogs/sd.h b/ntfsprogs/sd.h index aac6b111..0dc5f977 100644 --- a/ntfsprogs/sd.h +++ b/ntfsprogs/sd.h @@ -5,7 +5,6 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len); void init_root_sd_31(u8 **sd_val, int *sd_val_len); -void init_secure_30(char *sd_val); void init_secure_31(char *sd_val); #endif /* _NTFS_SD_H_ */ From 5f3079c2bb864da678263fffcfef2e47efc2f1be Mon Sep 17 00:00:00 2001 From: aia21 Date: Wed, 13 Dec 2006 10:51:32 +0000 Subject: [PATCH 168/289] Fix ntfstruncate build breakage. --- ntfsprogs/ntfstruncate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ntfsprogs/ntfstruncate.c b/ntfsprogs/ntfstruncate.c index 69c20beb..76fd8580 100644 --- a/ntfsprogs/ntfstruncate.c +++ b/ntfsprogs/ntfstruncate.c @@ -716,7 +716,7 @@ int main(int argc, char **argv) * Setup a default $AttrDef. FIXME: Should be reading this from the * volume itself, at ntfs_mount() time. */ - attr_defs = (ATTR_DEF*)&attrdef_ntfs12_array; + attr_defs = (ATTR_DEF*)&attrdef_ntfs3x_array; /* Parse command line options. */ parse_options(argc, argv); @@ -808,4 +808,3 @@ int main(int argc, char **argv) ntfs_log_quiet("ntfstruncate completed successfully. Have a nice day.\n"); return 0; } - From 0911eb8b0de580452488f595e31a14db20eb4149 Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 15 Dec 2006 14:52:43 +0000 Subject: [PATCH 169/289] Make volumes created with mkntfs more compliant with Vista (still not finished). --- ntfsprogs/mkntfs.c | 5 ++++- ntfsprogs/sd.c | 50 +++++++++++++++++++++------------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index b21f1b29..8559fd2a 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -1548,7 +1548,10 @@ static int insert_resident_attr_in_mft_record(MFT_RECORD *m, a->length = cpu_to_le32(asize); a->non_resident = 0; a->name_length = name_len; - a->name_offset = const_cpu_to_le16(24); + if (type == AT_OBJECT_ID) + a->name_offset = const_cpu_to_le16(0); + else + a->name_offset = const_cpu_to_le16(24); a->flags = flags; a->instance = m->next_attr_instance; m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) diff --git a/ntfsprogs/sd.c b/ntfsprogs/sd.c index ac89c43f..379233cf 100644 --- a/ntfsprogs/sd.c +++ b/ntfsprogs/sd.c @@ -44,9 +44,9 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) sd->revision = 1; sd->alignment = 0; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; - *sd_val_len = 0x68; + *sd_val_len = 0x64; sd->owner = const_cpu_to_le32(0x48); - sd->group = const_cpu_to_le32(0x58); + sd->group = const_cpu_to_le32(0x54); sd->sacl = const_cpu_to_le32(0); sd->dacl = const_cpu_to_le32(0x14); /* @@ -68,13 +68,12 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) aa_ace->flags = 0; aa_ace->size = const_cpu_to_le16(0x14); switch (sys_file_no) { - case FILE_MFT: case FILE_MFTMirr: case FILE_LogFile: - case FILE_AttrDef: case FILE_Bitmap: case FILE_Boot: - case FILE_BadClus: case FILE_UpCase: + case FILE_AttrDef: + case FILE_Boot: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; break; - case FILE_Volume: case FILE_Secure: case 0xb ... 0xffff: + default: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_WRITE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | @@ -103,17 +102,15 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; aa_ace->flags = 0; aa_ace->size = const_cpu_to_le16(0x18); + /* Only $AttrDef and $Boot behave differently to everything else. */ switch (sys_file_no) { - case FILE_MFT: case FILE_MFTMirr: - case FILE_LogFile: case FILE_AttrDef: - case FILE_Bitmap: case FILE_Boot: - case FILE_BadClus: case FILE_UpCase: + case FILE_AttrDef: + case FILE_Boot: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; break; - case FILE_Volume: case FILE_Secure: - case 0xb ... 0xffff : + default: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | @@ -134,11 +131,13 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); aa_ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); - /* Now at offset 0x48 into the security descriptor. */ - /* As specified in the security descriptor, we now have the owner SID.*/ + /* + * Now at offset 0x48 into the security descriptor, as specified in the + * security descriptor, we now have the owner SID. + */ sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 1; - sid->sub_authority_count = 2; + sid->sub_authority_count = 1; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; @@ -146,12 +145,10 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); /* - * Now at offset 0x40 or 0x58 (root directory and the other system - * files, respectively) into the security descriptor, as specified in - * the security descriptor, we have the group SID. + * Now at offset 0x54 into the security descriptor, as specified in the + * security descriptor, we have the group SID. */ sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); sid->revision = 1; @@ -168,7 +165,7 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) } /** - * init_root_sd_31 (ERSO) + * init_root_sd_31 * * creates the security_descriptor for the root folder on ntfs 3.1. * It is very long; lots of ACE's at first, then large pieces of zeroes; @@ -185,8 +182,8 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ACCESS_ALLOWED_ACE *ace; SID *sid; - static char sd_array[0x1030]; - *sd_val_len = 0x1030; + static char sd_array[0x102c]; + *sd_val_len = 0x102c; *sd_val = (u8*)&sd_array; //security descriptor relative @@ -195,7 +192,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) sd->alignment = 0x00; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; sd->owner = const_cpu_to_le32(0x1014); - sd->group = const_cpu_to_le32(0x1024); + sd->group = const_cpu_to_le32(0x1020); sd->sacl = const_cpu_to_le32(0x00); sd->dacl = const_cpu_to_le32(0x14); @@ -349,7 +346,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 0x01; - sid->sub_authority_count = 0x02; + sid->sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; @@ -357,8 +354,7 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; - sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //group sid sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); From 1fa522a0a1cfaefb42caf13399cb0798d910ecd5 Mon Sep 17 00:00:00 2001 From: aia21 Date: Fri, 15 Dec 2006 15:21:27 +0000 Subject: [PATCH 170/289] - libntfs: Add support for FreeBSD 5.0+ sector aligned access requirements. (Max Khon) With some modifications from me... --- CREDITS | 1 + ChangeLog | 2 + TODO.libntfs | 3 + libntfs/device_io.c | 24 +- libntfs/freebsd_io.c | 555 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 577 insertions(+), 8 deletions(-) create mode 100644 libntfs/freebsd_io.c diff --git a/CREDITS b/CREDITS index 09698845..cc8a0dc6 100644 --- a/CREDITS +++ b/CREDITS @@ -19,6 +19,7 @@ Marcin GibuÅ‚a Christophe Grenier Csaba Henk Ian Jackson +Max Khon Carmelo Kintana Jan Kratochvil Lode Leroy diff --git a/ChangeLog b/ChangeLog index 8dabb45b..0034c3bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -115,6 +115,8 @@ xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - mkntfs: As announced, remove the deprecated support for creation of NTFS 1.2/3.0 volumes. We now create NTFS 3.1 volumes only. (Anton) - mkntfs: Remove lots of unused/unneeded debugging code. (Anton) + - libntfs: Add support for FreeBSD 5.0+ sector aligned access + requirements. (Max Khon) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/TODO.libntfs b/TODO.libntfs index 3c303b1f..6183520d 100644 --- a/TODO.libntfs +++ b/TODO.libntfs @@ -30,6 +30,9 @@ previous mount left the block size to larger value and we expect 512 bytes as that would be incredibly inefficient +- fix freebsd_io.c and win32_io.c to support device operations ->pread() and + ->pwrite() to improve their performance + ******************* * MEDIUM priority * ******************* diff --git a/libntfs/device_io.c b/libntfs/device_io.c index 9a044d61..706e935f 100644 --- a/libntfs/device_io.c +++ b/libntfs/device_io.c @@ -1,7 +1,7 @@ /* * device_io.c - Default device io operations. Part of the Linux-NTFS project. * - * Copyright (c) 2003 Anton Altaparmakov + * Copyright (c) 2003-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -23,16 +23,24 @@ #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS -#ifndef __CYGWIN32__ - -/* Not on Cygwin; use standard Unix style low level device operations. */ -#include "unix_io.c" - -#else /* __CYGWIN32__ */ +#if defined(__CYGWIN32__) /* On Cygwin; use Win32 low level device operations. */ #include "win32_io.c" -#endif /* __CYGWIN32__ */ +#elif defined(__FreeBSD__) + +/* On FreeBSD; need to use sector aligned i/o. */ +#include "freebsd_io.c" + +#else + +/* + * Not on Cygwin or FreeBSD; use standard Unix style low level device + * operations. + */ +#include "unix_io.c" + +#endif #endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */ diff --git a/libntfs/freebsd_io.c b/libntfs/freebsd_io.c new file mode 100644 index 00000000..cd348d59 --- /dev/null +++ b/libntfs/freebsd_io.c @@ -0,0 +1,555 @@ +/** + * freebsd_io.c - FreeBSD disk io functions. Originated from the Linux-NTFS + * project. + * + * FreeBSD 5.0+ does not have character devices and requires + * read/writes from/to block devices to be sector aligned. + * + * Copyright (c) 2006 Max Khon + * Copyright (c) 2006 Anton Altaparmakov + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_FD_H +#include +#endif +#include + +#include "types.h" +#include "mst.h" +#include "debug.h" +#include "device.h" +#include "logging.h" + +typedef struct { + int fd; + s64 pos; + s32 block_size; + s64 media_size; +} freebsd_fd; + +#define DEV_FD(dev) (((freebsd_fd *) dev->d_private)) +#define RAW_IO_ALIGNED(dev, offset, count) \ + (DEV_FD(dev)->block_size == 0 || \ + ((offset) % DEV_FD(dev)->block_size == 0 && \ + (count) % DEV_FD(dev)->block_size == 0)) +#define RAW_IO_ALIGN(dev, offset) \ + ((offset) / DEV_FD(dev)->block_size * DEV_FD(dev)->block_size) +#define RAW_IO_MAX_SIZE (128 * 1024 * 1024) + +/* Define to nothing if not present on this system. */ +#ifndef O_EXCL +# define O_EXCL 0 +#endif + +/** + * Get block_size and media_size + */ +static int freebsd_get_size(struct ntfs_device *dev) +{ + off_t ms; + int bs; + struct stat sb; + + if (fstat(DEV_FD(dev)->fd, &sb) < 0) { + ntfs_log_perror("Failed to stat '%s'", dev->d_name); + return -1; + } + if (S_ISREG(sb.st_mode)) { + DEV_FD(dev)->media_size = sb.st_size; + ntfs_log_trace("%s: regular file (media_size %lld)\n", + dev->d_name, DEV_FD(dev)->media_size); + return 0; + } + if (ioctl(DEV_FD(dev)->fd, DIOCGSECTORSIZE, &bs) < 0) { + ntfs_log_perror("Failed to ioctl(DIOCGSECTORSIZE) '%s'", + dev->d_name); + return -1; + } + DEV_FD(dev)->block_size = bs; + ntfs_log_trace("%s: block size %d\n", dev->d_name, bs); + if (ioctl(DEV_FD(dev)->fd, DIOCGMEDIASIZE, &ms) < 0) { + ntfs_log_perror("Failed to ioctl(DIOCGMEDIASIZE) '%s'", + dev->d_name); + return -1; + } + DEV_FD(dev)->media_size = ms; + ntfs_log_trace("%s: media size %lld\n", dev->d_name, ms); + return 0; +} + +/** + * freebsd_pread - Aligned read + */ +static inline ssize_t freebsd_pread(struct ntfs_device *dev, char *buf, + size_t count, s64 offset) +{ + return pread(DEV_FD(dev)->fd, buf, count, offset); +} + +/** + * freebsd_pwrite - Aligned write + */ +static inline ssize_t freebsd_pwrite(struct ntfs_device *dev, const char *buf, + size_t count, s64 offset) +{ + return pwrite(DEV_FD(dev)->fd, buf, count, offset); +} + +/** + * ntfs_device_freebsd_io_open - Open a device and lock it exclusively + * @dev: + * @flags: + * + * Description... + * + * Returns: + */ +static int ntfs_device_freebsd_io_open(struct ntfs_device *dev, int flags) +{ +#if 0 + struct flock flk; +#endif + struct stat sbuf; + int err; + + if (NDevOpen(dev)) { + errno = EBUSY; + return -1; + } + if (stat(dev->d_name, &sbuf)) { + ntfs_log_perror("Failed to access '%s'", dev->d_name); + return -1; + } + if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) + NDevSetBlock(dev); + + dev->d_private = malloc(sizeof(freebsd_fd)); + if (!dev->d_private) + return -1; + DEV_FD(dev)->fd = -1; + DEV_FD(dev)->pos = 0; + DEV_FD(dev)->block_size = 0; + DEV_FD(dev)->media_size = 0; + + /* + * Open file for exclusive access if mounting r/w. + * Fuseblk takes care about block devices. + * FIXME: This is totally wrong. ntfsmount needs to just disabled the + * O_EXCL otherwise all other utilities are not mounting O_EXCL when + * they definitely should be doing it! + */ + if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR) + flags |= O_EXCL; + DEV_FD(dev)->fd = open(dev->d_name, flags); + if (DEV_FD(dev)->fd == -1) { + err = errno; + goto err_out; + } + + if ((flags & O_RDWR) != O_RDWR) + NDevSetReadOnly(dev); + +#if 0 + memset(&flk, 0, sizeof(flk)); + if (NDevReadOnly(dev)) + flk.l_type = F_RDLCK; + else + flk.l_type = F_WRLCK; + flk.l_whence = SEEK_SET; + flk.l_start = flk.l_len = 0LL; + if (fcntl(DEV_FD(dev)->fd, F_SETLK, &flk)) { + err = errno; + ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ? + "read" : "write", dev->d_name); + if (close(DEV_FD(dev)->fd)) + ntfs_log_perror("Failed to close '%s'", dev->d_name); + goto err_out; + } +#endif + + if (freebsd_get_size(dev) < 0) { + err = errno; + close(DEV_FD(dev)->fd); + goto err_out; + } + + NDevSetOpen(dev); + return 0; +err_out: + free(dev->d_private); + dev->d_private = NULL; + errno = err; + return -1; +} + +/** + * ntfs_device_freebsd_io_close - Close the device, releasing the lock + * @dev: + * + * Description... + * + * Returns: + */ +static int ntfs_device_freebsd_io_close(struct ntfs_device *dev) +{ +#if 0 + struct flock flk; +#endif + + if (!NDevOpen(dev)) { + errno = EBADF; + return -1; + } + if (NDevDirty(dev)) + fsync(DEV_FD(dev)->fd); + +#if 0 + /* Release exclusive (mandatory) lock on the whole device. */ + memset(&flk, 0, sizeof(flk)); + flk.l_type = F_UNLCK; + flk.l_whence = SEEK_SET; + flk.l_start = flk.l_len = 0LL; + if (fcntl(DEV_FD(dev)->fd, F_SETLK, &flk)) + ntfs_log_perror("ntfs_device_freebsd_io_close: Warning: Could not " + "unlock %s", dev->d_name); +#endif + + /* Close the file descriptor and clear our open flag. */ + if (close(DEV_FD(dev)->fd)) + return -1; + NDevClearOpen(dev); + free(dev->d_private); + dev->d_private = NULL; + return 0; +} + +/** + * ntfs_device_freebsd_io_seek - Seek to a place on the device + * @dev: + * @offset: + * @whence: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_freebsd_io_seek(struct ntfs_device *dev, s64 offset, + int whence) +{ + s64 abs_pos; + + ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence); + switch (whence) { + case SEEK_SET: + abs_pos = offset; + break; + + case SEEK_CUR: + abs_pos = DEV_FD(dev)->pos + offset; + break; + + case SEEK_END: + abs_pos = DEV_FD(dev)->media_size + offset; + break; + + default: + ntfs_log_trace("Wrong mode %d.\n", whence); + errno = EINVAL; + return -1; + } + + if (abs_pos < 0 || abs_pos > DEV_FD(dev)->media_size) { + ntfs_log_trace("Seeking outsize seekable area.\n"); + errno = EINVAL; + return -1; + } + DEV_FD(dev)->pos = abs_pos; + return abs_pos; +} + +/** + * ntfs_device_freebsd_io_read - Read from the device, from the current location + * @dev: + * @buf: + * @count: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_freebsd_io_read(struct ntfs_device *dev, void *buf, + s64 count) +{ + s64 start, start_aligned; + s64 end, end_aligned; + size_t count_aligned; + char *buf_aligned; + ssize_t nr; + + /* short-circuit for regular files */ + start = DEV_FD(dev)->pos; + if (count > RAW_IO_MAX_SIZE) + count = RAW_IO_MAX_SIZE; + if (RAW_IO_ALIGNED(dev, start, count)) { + nr = freebsd_pread(dev, buf, count, start); + if (nr <= 0) + return nr; + + DEV_FD(dev)->pos += nr; + return nr; + } + + /* + * +- start_aligned +- end_aligned + * | | + * | +- start +- end | + * v v v v + * |----------|----------|----------| + * ^ ^ + * +----- count ------+ + * ^ ^ + * +-------- count_aligned ---------+ + */ + start_aligned = RAW_IO_ALIGN(dev, start); + end = start + count; + end_aligned = RAW_IO_ALIGN(dev, end) + + (RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_FD(dev)->block_size); + count_aligned = end_aligned - start_aligned; + ntfs_log_trace( + "%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n", + dev->d_name, count, count_aligned, + start, start_aligned, end, end_aligned); + + /* allocate buffer */ + buf_aligned = malloc(count_aligned); + if (buf_aligned == NULL) { + ntfs_log_trace("malloc(%d) failed\n", count_aligned); + return -1; + } + + /* read aligned data */ + nr = freebsd_pread(dev, buf_aligned, count_aligned, start_aligned); + if (nr == 0) + return 0; + if (nr < 0 || nr < start - start_aligned) { + free(buf_aligned); + return -1; + } + + /* copy out */ + memcpy(buf, buf_aligned + (start - start_aligned), count); + free(buf_aligned); + + nr -= start - start_aligned; + if (nr > count) + nr = count; + DEV_FD(dev)->pos += nr; + return nr; +} + +/** + * ntfs_device_freebsd_io_write - Write to the device, at the current location + * @dev: + * @buf: + * @count: + * + * Description... + * + * Returns: + */ +static s64 ntfs_device_freebsd_io_write(struct ntfs_device *dev, const void *buf, + s64 count) +{ + s64 start, start_aligned; + s64 end, end_aligned; + size_t count_aligned; + char *buf_aligned; + ssize_t nw; + + if (NDevReadOnly(dev)) { + errno = EROFS; + return -1; + } + NDevSetDirty(dev); + + /* short-circuit for regular files */ + start = DEV_FD(dev)->pos; + if (count > RAW_IO_MAX_SIZE) + count = RAW_IO_MAX_SIZE; + if (RAW_IO_ALIGNED(dev, start, count)) { + nw = freebsd_pwrite(dev, buf, count, start); + if (nw <= 0) + return nw; + + DEV_FD(dev)->pos += nw; + return nw; + } + + /* + * +- start_aligned +- end_aligned + * | | + * | +- start +- end | + * v v v v + * |----------|----------|----------| + * ^ ^ + * +----- count ------+ + * ^ ^ + * +-------- count_aligned ---------+ + */ + start_aligned = RAW_IO_ALIGN(dev, start); + end = start + count; + end_aligned = RAW_IO_ALIGN(dev, end) + + (RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_FD(dev)->block_size); + count_aligned = end_aligned - start_aligned; + ntfs_log_trace( + "%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n", + dev->d_name, count, count_aligned, + start, start_aligned, end, end_aligned); + + /* allocate buffer */ + buf_aligned = malloc(count_aligned); + if (buf_aligned == NULL) { + ntfs_log_trace("malloc(%d) failed\n", count_aligned); + return -1; + } + + /* read aligned lead-in */ + if (freebsd_pread(dev, buf_aligned, DEV_FD(dev)->block_size, start_aligned) != DEV_FD(dev)->block_size) { + ntfs_log_trace("read lead-in failed\n"); + free(buf_aligned); + return -1; + } + + /* read aligned lead-out */ + if (end != end_aligned && count_aligned > DEV_FD(dev)->block_size) { + if (freebsd_pread(dev, buf_aligned + count_aligned - DEV_FD(dev)->block_size, DEV_FD(dev)->block_size, end_aligned - DEV_FD(dev)->block_size) != DEV_FD(dev)->block_size) { + ntfs_log_trace("read lead-out failed\n"); + free(buf_aligned); + return -1; + } + } + + /* copy data to write */ + memcpy(buf_aligned + (start - start_aligned), buf, count); + + /* write aligned data */ + nw = freebsd_pwrite(dev, buf_aligned, count_aligned, start_aligned); + free(buf_aligned); + if (nw < 0 || nw < start - start_aligned) + return -1; + + nw -= start - start_aligned; + if (nw > count) + nw = count; + DEV_FD(dev)->pos += nw; + return nw; +} + +/** + * ntfs_device_freebsd_io_sync - Flush any buffered changes to the device + * @dev: + * + * Description... + * + * Returns: + */ +static int ntfs_device_freebsd_io_sync(struct ntfs_device *dev) +{ + if (!NDevReadOnly(dev)) { + int res = fsync(DEV_FD(dev)->fd); + if (!res) + NDevClearDirty(dev); + return res; + } + return 0; +} + +/** + * ntfs_device_freebsd_io_stat - Get information about the device + * @dev: + * @buf: + * + * Description... + * + * Returns: + */ +static int ntfs_device_freebsd_io_stat(struct ntfs_device *dev, struct stat *buf) +{ + return fstat(DEV_FD(dev)->fd, buf); +} + +/** + * ntfs_device_freebsd_io_ioctl - Perform an ioctl on the device + * @dev: + * @request: + * @argp: + * + * Description... + * + * Returns: + */ +static int ntfs_device_freebsd_io_ioctl(struct ntfs_device *dev, int request, + void *argp) +{ + return ioctl(DEV_FD(dev)->fd, request, argp); +} + +/** + * Device operations for working with unix style devices and files. + */ +struct ntfs_device_operations ntfs_device_unix_io_ops = { + .open = ntfs_device_freebsd_io_open, + .close = ntfs_device_freebsd_io_close, + .seek = ntfs_device_freebsd_io_seek, + .read = ntfs_device_freebsd_io_read, + .write = ntfs_device_freebsd_io_write, + .sync = ntfs_device_freebsd_io_sync, + .stat = ntfs_device_freebsd_io_stat, + .ioctl = ntfs_device_freebsd_io_ioctl, +}; From 3c668b7d03bd3dd3ee82a61363fb74677dc21059 Mon Sep 17 00:00:00 2001 From: yura Date: Fri, 15 Dec 2006 17:00:02 +0000 Subject: [PATCH 171/289] - O_EXCL already handled by MNT_NOT_EXCLUSIVE at more early stage - fix comments --- libntfs/freebsd_io.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libntfs/freebsd_io.c b/libntfs/freebsd_io.c index cd348d59..f5e96c00 100644 --- a/libntfs/freebsd_io.c +++ b/libntfs/freebsd_io.c @@ -1,12 +1,12 @@ /** - * freebsd_io.c - FreeBSD disk io functions. Originated from the Linux-NTFS - * project. + * freebsd_io.c - FreeBSD disk io functions. Part of the Linux-NTFS project. * - * FreeBSD 5.0+ does not have character devices and requires - * read/writes from/to block devices to be sector aligned. + * FreeBSD 5.0+ does not have block devices and requires read/writes from/to + * character devices to be sector aligned. * * Copyright (c) 2006 Max Khon * Copyright (c) 2006 Anton Altaparmakov + * Copyright (c) 2006 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -177,15 +177,6 @@ static int ntfs_device_freebsd_io_open(struct ntfs_device *dev, int flags) DEV_FD(dev)->block_size = 0; DEV_FD(dev)->media_size = 0; - /* - * Open file for exclusive access if mounting r/w. - * Fuseblk takes care about block devices. - * FIXME: This is totally wrong. ntfsmount needs to just disabled the - * O_EXCL otherwise all other utilities are not mounting O_EXCL when - * they definitely should be doing it! - */ - if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR) - flags |= O_EXCL; DEV_FD(dev)->fd = open(dev->d_name, flags); if (DEV_FD(dev)->fd == -1) { err = errno; From bedd6f4a1333fe2fd4817780d9e65adc1ab50d01 Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 18 Dec 2006 13:32:58 +0000 Subject: [PATCH 172/289] add some debug output useful on freebsd for aligned access testing --- autogen.sh | 2 +- ntfsprogs/ntfsmount.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/autogen.sh b/autogen.sh index 150e902d..f6d13303 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/local/bin/bash # Run this to generate configure, Makefile.in's, etc if test "$srcdir" == ""; then diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 39387123..0a35635d 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -165,8 +165,10 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free) nr_free--; } free(buf); - if (!total || br < 0) + if (!total || br < 0) { + ntfs_log_error("pread: %s\n", strerror(errno)); return -errno; + } ctx->free_mft = nr_free; ctx->state &= ~(NF_FreeMFTOutdate); return nr_free; @@ -197,8 +199,10 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) nr_free--; } free(buf); - if (!total || br < 0) + if (!total || br < 0) { + ntfs_log_error("pread: %s\n", strerror(errno)); return -errno; + } ctx->free_clusters = nr_free; ctx->state &= ~(NF_FreeClustersOutdate); return nr_free; From 452b99f01bff684f9135426b39fda92a8e26532a Mon Sep 17 00:00:00 2001 From: yura Date: Mon, 18 Dec 2006 13:39:23 +0000 Subject: [PATCH 173/289] oops, committed temporary thing by accident hope this will work for everyone --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index f6d13303..a51d759f 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,4 @@ -#!/usr/local/bin/bash +#!/usr/bin/env bash # Run this to generate configure, Makefile.in's, etc if test "$srcdir" == ""; then From f6adc3fc78b67502d205279e00fe43819b4a7fb2 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 19 Dec 2006 16:31:52 +0000 Subject: [PATCH 174/289] - mkntfs: Create more Vista like volumes. We now match the security descriptor attributes (but not yet the security descriptors stored in $Secure). (Anton) - libntfs: Rewrite ntfs_upcase_table_build() to generate a Vista compatible upcase table ($UpCase). (Anton) - mkntfs: Remove own generation of upcase table, i.e. delete ntfsprogs/upcase.[ch] and use ntfs_upcase_table_build() supplied by libntfs. (Anton) --- ChangeLog | 8 ++ include/ntfs/unistr.h | 2 +- libntfs/unistr.c | 123 ++++++++++++++++------------ libntfs/volume.c | 1 - ntfsprogs/Makefile.am | 2 +- ntfsprogs/mkntfs.c | 10 +-- ntfsprogs/sd.c | 181 +++++++++++++++++++++++------------------- ntfsprogs/sd.h | 4 +- ntfsprogs/upcase.c | 90 --------------------- ntfsprogs/upcase.h | 7 -- 10 files changed, 190 insertions(+), 238 deletions(-) delete mode 100644 ntfsprogs/upcase.c delete mode 100644 ntfsprogs/upcase.h diff --git a/ChangeLog b/ChangeLog index 0034c3bf..8e237dd3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -117,6 +117,14 @@ xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - mkntfs: Remove lots of unused/unneeded debugging code. (Anton) - libntfs: Add support for FreeBSD 5.0+ sector aligned access requirements. (Max Khon) + - mkntfs: Create more Vista like volumes. We now match the security + descriptor attributes (but not yet the security descriptors stored in + $Secure). (Anton) + - libntfs: Rewrite ntfs_upcase_table_build() to generate a Vista + compatible upcase table ($UpCase). (Anton) + - mkntfs: Remove own generation of upcase table, i.e. delete + ntfsprogs/upcase.[ch] and use ntfs_upcase_table_build() supplied by + libntfs. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/include/ntfs/unistr.h b/include/ntfs/unistr.h index 81450f89..2c5fd554 100644 --- a/include/ntfs/unistr.h +++ b/include/ntfs/unistr.h @@ -2,7 +2,7 @@ * unistr.h - Exports for Unicode string handling. Part of the Linux-NTFS * project. * - * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published diff --git a/libntfs/unistr.c b/libntfs/unistr.c index c1a4d2a5..53de09e8 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -1,7 +1,7 @@ /** * unistr.c - Unicode string handling. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2000-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -40,6 +40,7 @@ #endif #include "attrib.h" +#include "endians.h" #include "types.h" #include "unistr.h" #include "debug.h" @@ -644,62 +645,86 @@ err_out: * ntfs_upcase_table_build() builds the default upcase table for NTFS and * stores it in the caller supplied buffer @uc of size @uc_len. * + * The generated $UpCase table is the one used by Windows Vista. + * * Note, @uc_len must be at least 128kiB in size or bad things will happen! */ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) { - static int uc_run_table[][3] = { /* Start, End, Add */ - {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, - {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, - {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, - {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, - {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, - {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, - {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, - {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, - {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, - {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, - {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, - {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, - {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, - {0} + /* + * "Start" is inclusive and "End" is exclusive, every value has the + * value of "Add" added to it. + */ + static int add[][3] = { /* Start, End, Add */ + {0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32}, + {0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130}, + {0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32}, + {0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64}, + {0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80}, + {0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8}, + {0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8}, + {0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8}, + {0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74}, + {0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128}, + {0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8}, + {0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8}, + {0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8}, + {0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9}, + {0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48}, + {0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0} }; - static int uc_dup_table[][2] = { /* Start, End */ - {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, - {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, - {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, - {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, - {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, - {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, - {0} + /* + * "Start" is exclusive and "End" is inclusive, every second value is + * decremented by one. + */ + static int skip_dec[][2] = { /* Start, End */ + {0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178}, + {0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd}, + {0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220}, + {0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f}, + {0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481}, + {0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce}, + {0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513}, + {0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61}, + {0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0} }; - static int uc_byte_table[][2] = { /* Offset, Value */ - {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, - {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, - {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, - {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, - {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, - {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, - {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, - {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, - {0} + /* + * Set the Unicode character at offset "Offset" to "Value". Note, + * "Value" is host endian. + */ + static int set[][2] = { /* Offset, Value */ + {0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184}, + {0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6}, + {0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7}, + {0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc}, + {0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca}, + {0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66}, + {0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190}, + {0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196}, + {0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f}, + {0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae}, + {0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9}, + {0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0} }; - int i, r; + unsigned i, r; - memset((char*)uc, 0, uc_len); - uc_len >>= 1; - if (uc_len > 65536) - uc_len = 65536; - for (i = 0; (u32)i < uc_len; i++) - uc[i] = i; - for (r = 0; uc_run_table[r][0]; r++) - for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) - uc[i] += uc_run_table[r][2]; - for (r = 0; uc_dup_table[r][0]; r++) - for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) - uc[i + 1]--; - for (r = 0; uc_byte_table[r][0]; r++) - uc[uc_byte_table[r][0]] = uc_byte_table[r][1]; + memset(uc, 0, uc_len); + uc_len /= 2; + /* Start with a one-to-one mapping, i.e. no upcasing happens at all. */ + for (i = 0; i < uc_len; i++) + uc[i] = cpu_to_le16(i); + /* Adjust specified runs by the specified amount. */ + for (r = 0; add[r][0]; r++) + for (i = add[r][0]; i < add[r][1]; i++) + uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + add[r][2]); + /* Decrement every second value in specified runs. */ + for (r = 0; skip_dec[r][0]; r++) + for (i = skip_dec[r][0]; i < skip_dec[r][1]; + i += 2) + uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); + /* Set specified characters to specified values. */ + for (r = 0; set[r][0]; r++) + uc[set[r][0]] = cpu_to_le16(set[r][1]); } /** diff --git a/libntfs/volume.c b/libntfs/volume.c index 020ef1ab..bc658b40 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -436,7 +436,6 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, sizeof(ntfschar)); if (!vol->upcase) goto error_exit; - ntfs_upcase_table_build(vol->upcase, vol->upcase_len * sizeof(ntfschar)); if (flags & NTFS_MNT_RDONLY) diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 398a7917..42a4aeb0 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -45,7 +45,7 @@ ntfsfix_LDADD = $(AM_LIBS) ntfsfix_LDFLAGS = $(AM_LFLAGS) mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS) -mkntfs_SOURCES = attrdef.c attrdef.h upcase.c upcase.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h +mkntfs_SOURCES = attrdef.c attrdef.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS) mkntfs_LDFLAGS = $(AM_LFLAGS) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 8559fd2a..a654853b 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -145,12 +145,12 @@ #include "utils.h" #include "ntfstime.h" #include "sd.h" -#include "upcase.h" #include "boot.h" #include "attrdef.h" #include "version.h" #include "logging.h" #include "support.h" +#include "unistr.h" #ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS #error "No default device io operations! Cannot build mkntfs. \ @@ -4065,7 +4065,7 @@ static BOOL mkntfs_create_root_structures(void) FILE_ATTR_I30_INDEX_PRESENT, 0, 0, ".", FILE_NAME_WIN32_AND_DOS); if (!err) { - init_root_sd_31(&sd, &i); + init_root_sd(&sd, &i); err = add_attr_sd(m, sd, i); } /* FIXME: This should be IGNORE_CASE */ @@ -4349,7 +4349,7 @@ static BOOL mkntfs_create_root_structures(void) buf_sds = ntfs_calloc(buf_sds_size); if (!buf_sds) return FALSE; - init_secure_31(buf_sds); + init_secure_sds(buf_sds); memcpy(buf_sds + 0x40000, buf_sds, buf_sds_first_size); err = add_attr_data(m, "$SDS", 4, 0, 0, (u8*)buf_sds, buf_sds_size); @@ -4541,8 +4541,8 @@ static int mkntfs_redirect(struct mkntfs_options *opts2) g_vol->upcase = ntfs_malloc(g_vol->upcase_len * sizeof(ntfschar)); if (!g_vol->upcase) goto done; - - init_upcase_table(g_vol->upcase, g_vol->upcase_len * sizeof(ntfschar)); + ntfs_upcase_table_build(g_vol->upcase, + g_vol->upcase_len * sizeof(ntfschar)); g_vol->attrdef = ntfs_malloc(sizeof(attrdef_ntfs3x_array)); if (!g_vol->attrdef) { ntfs_log_perror("Could not create attrdef structure"); diff --git a/ntfsprogs/sd.c b/ntfsprogs/sd.c index 379233cf..06d35fe8 100644 --- a/ntfsprogs/sd.c +++ b/ntfsprogs/sd.c @@ -3,7 +3,7 @@ #include "sd.h" /** - * init_system_file_sd + * init_system_file_sd - * * NTFS 3.1 - System files security decriptors * ===================================================== @@ -11,15 +11,8 @@ * Create the security descriptor for system file number @sys_file_no and * return a pointer to the descriptor. * - * $MFT, $MFTMirr, $LogFile, $AttrDef, $Bitmap, $Boot, $BadClus, and $UpCase - * are the same. - * - * $Volume, $Quota, and system files 0xb-0xf are the same. They are almost the - * same as the above, the only difference being that the two SIDs present in - * the DACL grant GENERIC_WRITE and GENERIC_READ equivalent privileges while - * the above only grant GENERIC_READ equivalent privileges. - * - * Root directory system file (".") is different altogether. + * Note the root directory system file (".") is very different and handled by a + * different function. * * The sd is returned in *@sd_val and has length *@sd_val_len. * @@ -165,17 +158,14 @@ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) } /** - * init_root_sd_31 + * init_root_sd - * - * creates the security_descriptor for the root folder on ntfs 3.1. - * It is very long; lots of ACE's at first, then large pieces of zeroes; - * the owner user/group is near the end. On a partition created with - * w2k3 the owner user/group at the end is surrounded by 'garbage', which I - * yet do not understand. Here I have replaced the 'garbage' with - * zeros, which seems to work. Chkdsk does not add the 'garbage', nor alter - * this security descriptor in any way. + * Creates the security_descriptor for the root folder on ntfs 3.1 as created + * by Windows Vista (when the format is done from the disk management MMC + * snap-in, note this is different from the format done from the disk + * properties in Windows Explorer). */ -void init_root_sd_31(u8 **sd_val, int *sd_val_len) +void init_root_sd(u8 **sd_val, int *sd_val_len) { SECURITY_DESCRIPTOR_RELATIVE *sd; ACL *acl; @@ -188,34 +178,33 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) //security descriptor relative sd = (SECURITY_DESCRIPTOR_RELATIVE*)sd_array; - sd->revision = 0x01; - sd->alignment = 0x00; + sd->revision = SECURITY_DESCRIPTOR_REVISION; + sd->alignment = 0; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; sd->owner = const_cpu_to_le32(0x1014); sd->group = const_cpu_to_le32(0x1020); - sd->sacl = const_cpu_to_le32(0x00); - sd->dacl = const_cpu_to_le32(0x14); + sd->sacl = 0; + sd->dacl = const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); //acl acl = (ACL*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); - acl->revision = 0x02; - acl->alignment1 = 0x00; + acl->revision = ACL_REVISION; + acl->alignment1 = 0; acl->size = const_cpu_to_le16(0x1000); - acl->ace_count = const_cpu_to_le16(0x07); - acl->alignment2 = const_cpu_to_le16(0x00); + acl->ace_count = const_cpu_to_le16(0x08); + acl->alignment2 = 0; //ace1 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); - ace->type = 0x00; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = 0; ace->size = const_cpu_to_le16(0x18); ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | FILE_TRAVERSE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES; - - ace->sid.revision = 0x01; + ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; @@ -230,15 +219,35 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) //ace2 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE; + ace->size = const_cpu_to_le16(0x18); + ace->mask = GENERIC_ALL; + ace->sid.revision = SID_REVISION; + ace->sid.sub_authority_count = 0x02; + /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ + ace->sid.identifier_authority.value[0] = 0; + ace->sid.identifier_authority.value[1] = 0; + ace->sid.identifier_authority.value[2] = 0; + ace->sid.identifier_authority.value[3] = 0; + ace->sid.identifier_authority.value[4] = 0; + ace->sid.identifier_authority.value[5] = 5; + ace->sid.sub_authority[0] = + const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); + + //ace3 + ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = 0; ace->size = const_cpu_to_le16(0x14); ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | FILE_TRAVERSE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES; - ace->sid.revision = 0x01; + ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; @@ -250,33 +259,15 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); - //ace3 + //ace4 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; + ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x10000000); - ace->sid.revision = 0x01; + ace->mask = GENERIC_ALL; + ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; - /* SECURITY_CREATOR_SID_AUTHORITY (S-1-3) */ - ace->sid.identifier_authority.value[0] = 0; - ace->sid.identifier_authority.value[1] = 0; - ace->sid.identifier_authority.value[2] = 0; - ace->sid.identifier_authority.value[3] = 0; - ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 3; - ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_CREATOR_OWNER_RID); - - //ace4 - ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x1200A9); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; @@ -285,17 +276,20 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); + const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //ace5 ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = CONTAINER_INHERIT_ACE; - ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x04); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x02; + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = 0; + ace->size = const_cpu_to_le16(0x14); + ace->mask = SYNCHRONIZE | READ_CONTROL | DELETE | + FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | + FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA | + FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | + FILE_LIST_DIRECTORY; + ace->sid.revision = SID_REVISION; + ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; @@ -304,16 +298,36 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = - const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); - ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); + const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); //ace6 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE; + ace->size = const_cpu_to_le16(0x14); + ace->mask = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE; + ace->sid.revision = SID_REVISION; + ace->sid.sub_authority_count = 0x01; + /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ + ace->sid.identifier_authority.value[0] = 0; + ace->sid.identifier_authority.value[1] = 0; + ace->sid.identifier_authority.value[2] = 0; + ace->sid.identifier_authority.value[3] = 0; + ace->sid.identifier_authority.value[4] = 0; + ace->sid.identifier_authority.value[5] = 5; + ace->sid.sub_authority[0] = + const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); + + //ace7 + ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = 0; ace->size = const_cpu_to_le16(0x18); - ace->mask = const_cpu_to_le32(0x02); - ace->sid.revision = 0x01; + ace->mask = 9; + ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | + FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY; + ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; @@ -326,22 +340,25 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); - //ace7 + //ace8 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); - ace->type = 0x00; - ace->flags = 0x00; - ace->size = const_cpu_to_le16(0x14); - ace->mask = const_cpu_to_le32(0x1200A9); - ace->sid.revision = 0x01; - ace->sid.sub_authority_count = 0x01; - /* SECURITY_WORLD_SID_AUTHORITY (S-1-1) */ + ace->type = ACCESS_ALLOWED_ACE_TYPE; + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE; + ace->size = const_cpu_to_le16(0x18); + ace->mask = GENERIC_READ | GENERIC_EXECUTE; + ace->sid.revision = SID_REVISION; + ace->sid.sub_authority_count = 0x02; + /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; - ace->sid.identifier_authority.value[5] = 1; - ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_WORLD_RID); + ace->sid.identifier_authority.value[5] = 5; + ace->sid.sub_authority[0] = + const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); + ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); @@ -371,14 +388,14 @@ void init_root_sd_31(u8 **sd_val, int *sd_val_len) } /** - * init_secure_31(char **r, int size); + * init_secure_sds - * * NTFS 3.1 - System files security decriptors * =========================================== * Create the security descriptor entries in $SDS data stream like they * are in a partition, newly formatted with windows 2003 */ -void init_secure_31(char *sd_val) +void init_secure_sds(char *sd_val) { SECURITY_DESCRIPTOR_HEADER *sds; SECURITY_DESCRIPTOR_RELATIVE *sd; diff --git a/ntfsprogs/sd.h b/ntfsprogs/sd.h index 0dc5f977..7ad3e6a7 100644 --- a/ntfsprogs/sd.h +++ b/ntfsprogs/sd.h @@ -4,8 +4,8 @@ #include "types.h" void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len); -void init_root_sd_31(u8 **sd_val, int *sd_val_len); -void init_secure_31(char *sd_val); +void init_root_sd(u8 **sd_val, int *sd_val_len); +void init_secure_sds(char *sd_val); #endif /* _NTFS_SD_H_ */ diff --git a/ntfsprogs/upcase.c b/ntfsprogs/upcase.c deleted file mode 100644 index 113686cd..00000000 --- a/ntfsprogs/upcase.c +++ /dev/null @@ -1,90 +0,0 @@ -/** - * upcase - Part of the Linux-NTFS project. - * - * Copyright (c) 2001 Richard Russon - * Copyright (c) 2001-2006 Anton Altaparmakov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#ifdef HAVE_STRING_H -#include -#endif - -#include "endians.h" -#include "types.h" -#include "upcase.h" - -/** - * init_upcase_table - */ -void init_upcase_table(ntfschar *uc, u32 uc_len) -{ - static int uc_run_table[][3] = { /* Start, End, Add */ - {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, - {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, - {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, - {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, - {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, - {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, - {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, - {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, - {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, - {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, - {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, - {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, - {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, - {0} - }; - static int uc_dup_table[][2] = { /* Start, End */ - {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, - {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, - {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, - {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, - {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, - {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, - {0} - }; - static int uc_byte_table[][2] = { /* Offset, Value */ - {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, - {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, - {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, - {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, - {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, - {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, - {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, - {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, - {0} - }; - int i, r; - - memset(uc, 0, uc_len); - uc_len >>= 1; - /* Generate the little endian Unicode upcase table used by ntfs. */ - for (i = 0; (u32)i < uc_len; i++) - uc[i] = cpu_to_le16(i); - for (r = 0; uc_run_table[r][0]; r++) - for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) - uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + - uc_run_table[r][2]); - for (r = 0; uc_dup_table[r][0]; r++) - for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) - uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); - for (r = 0; uc_byte_table[r][0]; r++) - uc[uc_byte_table[r][0]] = cpu_to_le16(uc_byte_table[r][1]); -} diff --git a/ntfsprogs/upcase.h b/ntfsprogs/upcase.h deleted file mode 100644 index 9ec567dc..00000000 --- a/ntfsprogs/upcase.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _NTFS_UPCASE_H_ -#define _NTFS_UPCASE_H_ - -void init_upcase_table(ntfschar *uc, u32 uc_len); - -#endif /* _NTFS_UPCASE_H_ */ - From 197a4cc7567cddb86d17cb786b9953f840ed29cc Mon Sep 17 00:00:00 2001 From: yura Date: Wed, 3 Jan 2007 18:27:10 +0000 Subject: [PATCH 175/289] - upgrade to new shiny fuse option parsing API instead of my old hackish one (more readable and -4kb code) - remove show_sys_files and add case_insensitive options --- ChangeLog | 6 +- ntfsprogs/ntfsmount.c | 634 +++++++++++++++--------------------------- 2 files changed, 235 insertions(+), 405 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8e237dd3..f6ed3593 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. +xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) @@ -125,6 +125,10 @@ xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - mkntfs: Remove own generation of upcase table, i.e. delete ntfsprogs/upcase.[ch] and use ntfs_upcase_table_build() supplied by libntfs. (Anton) + - Upgrade ntfsmount to new FUSE option parsing API. (Yura) + - ntfsmount: Remove "show_sys_files" as potential harmful and + introduce new "case_insensitive" option to support both case + sensitive and insensitive mounts. (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 0a35635d..badd045e 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1,10 +1,11 @@ /** * ntfsmount - Part of the Linux-NTFS project. * - * Copyright (c) 2005-2006 Yura Pakhuchiy - * Copyright (c) 2005 Yuval Fledel + * Copyright (c) 2005-2007 Yura Pakhuchiy + * Copyright (c) 2005 Yuval Fledel + * Copyright (c) 2006 Szabolcs Szakacsits * - * Userspace NTFS driver. + * Userspace read/write NTFS driver. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,6 +87,9 @@ typedef enum { typedef struct { ntfs_volume *vol; + char *mnt_point; + char *device; + char *locale; int state; long free_clusters; long free_mft; @@ -95,12 +99,14 @@ typedef struct { unsigned int dmask; ntfs_fuse_streams_interface streams; BOOL ro; - BOOL show_sys_files; BOOL silent; BOOL force; BOOL debug; - BOOL noatime; BOOL no_detach; + BOOL quiet; + BOOL verbose; + BOOL no_def_opts; + BOOL case_insensitive; } ntfs_fuse_context_t; typedef enum { @@ -110,18 +116,61 @@ typedef enum { free MFT records is outdated. */ } ntfs_fuse_state_bits; -static struct options { - char *mnt_point; /* Mount point */ - char *options; /* Mount options */ - char *device; /* Device to mount */ - int quiet; /* Less output */ - int verbose; /* Extra output */ -} opts; +#define NTFS_FUSE_OPT(t, p) { t, offsetof(ntfs_fuse_context_t, p), TRUE } +#define NTFS_FUSE_OPT_NEG(t, p) { t, offsetof(ntfs_fuse_context_t, p), FALSE } +#define NTFS_FUSE_OPT_VAL(t, p, v) { t, offsetof(ntfs_fuse_context_t, p), v } + +enum { + NF_KEY_HELP, + NF_KEY_UMASK, +}; + +static const struct fuse_opt ntfs_fuse_opts[] = { + NTFS_FUSE_OPT("-v", verbose), + NTFS_FUSE_OPT("--verbose", verbose), + NTFS_FUSE_OPT("-q", quiet), + NTFS_FUSE_OPT("--quiet", quiet), + NTFS_FUSE_OPT("force", force), + NTFS_FUSE_OPT("silent", silent), + NTFS_FUSE_OPT("ro", ro), + NTFS_FUSE_OPT("fake_rw", ro), + NTFS_FUSE_OPT("debug", debug), + NTFS_FUSE_OPT("no_detach", no_detach), + NTFS_FUSE_OPT("no_def_opts", no_def_opts), + NTFS_FUSE_OPT("case_insensitive", case_insensitive), + NTFS_FUSE_OPT("fmask=%o", fmask), + NTFS_FUSE_OPT("dmask=%o", dmask), + NTFS_FUSE_OPT("umask=%o", fmask), + NTFS_FUSE_OPT("uid=%d", uid), + NTFS_FUSE_OPT("gid=%d", gid), + NTFS_FUSE_OPT("locale=%s", locale), + NTFS_FUSE_OPT_NEG("nosilent", silent), + NTFS_FUSE_OPT_NEG("rw", ro), + NTFS_FUSE_OPT_VAL("streams_interface=none", streams, + NF_STREAMS_INTERFACE_NONE), + NTFS_FUSE_OPT_VAL("streams_interface=windows", streams, + NF_STREAMS_INTERFACE_WINDOWS), + NTFS_FUSE_OPT_VAL("streams_interface=xattr", streams, + NF_STREAMS_INTERFACE_XATTR), + FUSE_OPT_KEY("-h", NF_KEY_HELP), + FUSE_OPT_KEY("-?", NF_KEY_HELP), + FUSE_OPT_KEY("--help", NF_KEY_HELP), + FUSE_OPT_KEY("umask=", NF_KEY_UMASK), + FUSE_OPT_KEY("noauto", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END +}; static const char *EXEC_NAME = "ntfsmount"; -static char def_opts[] = "default_permissions,allow_other,"; +static char ntfs_fuse_default_options[] = + "default_permissions,allow_other,use_ino,kernel_cache"; static ntfs_fuse_context_t *ctx; +/** + * ntfs_fuse_mark_free_space_outdated - forces free space recalculation + */ static __inline__ void ntfs_fuse_mark_free_space_outdated(void) { /* Mark information about free MFT record and clusters outdated. */ @@ -522,8 +571,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, free(filename); return 0; } - if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || - ctx->show_sys_files) + if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user) fill_ctx->filler(fill_ctx->buf, filename, NULL, 0); free(filename); return 0; @@ -1390,13 +1438,15 @@ exit: static void ntfs_fuse_destroy(void *priv __attribute__((unused))) { if (ctx->vol) { - ntfs_log_info("Unmounting %s (%s)\n", opts.device, + ntfs_log_info("Unmounting %s (%s)\n", ctx->device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) ntfs_log_perror("Failed to unmount volume"); } + free(ctx->device); + free(ctx->mnt_point); + free(ctx->locale); free(ctx); - free(opts.device); } static struct fuse_operations ntfs_fuse_oper = { @@ -1427,247 +1477,23 @@ static struct fuse_operations ntfs_fuse_oper = { #endif /* HAVE_SETXATTR */ }; -static int ntfs_fuse_init(void) -{ - ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t)); - if (!ctx) - return -1; - - *ctx = (ntfs_fuse_context_t) { - .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, - .uid = geteuid(), - .gid = getegid(), - .fmask = 0111, - .dmask = 0, - .streams = NF_STREAMS_INTERFACE_NONE, - }; - return 0; -} - -static int ntfs_fuse_mount(const char *device) -{ - ntfs_volume *vol; - - vol = utils_mount_volume(device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | - ((ctx->noatime) ? NTFS_MNT_NOATIME : 0) | - NTFS_MNT_NOT_EXCLUSIVE /*| NTFS_MNT_CASE_SENSITIVE*/, - ctx->force); - if (!vol) { - ntfs_log_error("Mount failed.\n"); - return -1; - } - ctx->vol = vol; - return 0; -} - static void signal_handler(int arg __attribute__((unused))) { fuse_exit((fuse_get_context())->fuse); } -static char *parse_mount_options(const char *org_options) -{ - char *options, *s, *opt, *val, *ret; - BOOL no_def_opts = FALSE; - - /* - * +7 for "fsname=". - * +1 for comma. - * +1 for null-terminator. - * +PATH_MAX for resolved by realpath() device name. - */ - ret = ntfs_malloc(strlen(def_opts) + strlen(org_options) + PATH_MAX + - 9); - if (!ret) - return NULL; - - *ret = 0; - options = strdup(org_options); - if (!options) { - ntfs_log_perror("strdup failed"); - return NULL; - } - s = options; - while ((val = strsep(&s, ","))) { - opt = strsep(&val, "="); - if (!strcmp(opt, "ro")) { /* Read-only mount. */ - if (val) { - ntfs_log_error("'ro' option should not have " - "value.\n"); - goto err_exit; - } - ctx->ro = TRUE; - strcat(ret, "ro,"); - } else if (!strcmp(opt, "noatime")) { - if (val) { - ntfs_log_error("'noatime' option should not " - "have value.\n"); - goto err_exit; - } - ctx->noatime = TRUE; - strcat(ret, "noatime,"); /* Duplicate it for FUSE. */ - } else if (!strcmp(opt, "fake_rw")) { - if (val) { - ntfs_log_error("'fake_rw' option should not " - "have value.\n"); - goto err_exit; - } - ctx->ro = TRUE; - } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */ - /* - * We need this to be able to check whether filesystem - * mounted or not. - */ - ntfs_log_error("'fsname' is unsupported option.\n"); - goto err_exit; - } else if (!strcmp(opt, "no_def_opts")) { - if (val) { - ntfs_log_error("'no_def_opts' option should " - "not have value.\n"); - goto err_exit; - } - no_def_opts = TRUE; /* Don't add default options. */ - } else if (!strcmp(opt, "umask")) { - if (!val) { - ntfs_log_error("'umask' option should have " - "value.\n"); - goto err_exit; - } - sscanf(val, "%o", &ctx->fmask); - ctx->dmask = ctx->fmask; - } else if (!strcmp(opt, "fmask")) { - if (!val) { - ntfs_log_error("'fmask' option should have " - "value.\n"); - goto err_exit; - } - sscanf(val, "%o", &ctx->fmask); - } else if (!strcmp(opt, "dmask")) { - if (!val) { - ntfs_log_error("'dmask' option should have " - "value.\n"); - goto err_exit; - } - sscanf(val, "%o", &ctx->dmask); - } else if (!strcmp(opt, "uid")) { - if (!val) { - ntfs_log_error("'uid' option should have " - "value.\n"); - goto err_exit; - } - sscanf(val, "%i", &ctx->uid); - } else if (!strcmp(opt, "gid")) { - if (!val) { - ntfs_log_error("'gid' option should have " - "value.\n"); - goto err_exit; - } - sscanf(val, "%i", &ctx->gid); - } else if (!strcmp(opt, "show_sys_files")) { - if (val) { - ntfs_log_error("'show_sys_files' option should " - "not have value.\n"); - goto err_exit; - } - ctx->show_sys_files = TRUE; - } else if (!strcmp(opt, "silent")) { - if (val) { - ntfs_log_error("'silent' option should " - "not have value.\n"); - goto err_exit; - } - ctx->silent = TRUE; - } else if (!strcmp(opt, "force")) { - if (val) { - ntfs_log_error("'force' option should not " - "have value.\n"); - goto err_exit; - } - ctx->force = TRUE; - } else if (!strcmp(opt, "locale")) { - if (!val) { - ntfs_log_error("'locale' option should have " - "value.\n"); - goto err_exit; - } - if (!setlocale(LC_ALL, val)) - ntfs_log_error("Failed to set locale to %s. " - "Continue anyway.\n", val); - } else if (!strcmp(opt, "streams_interface")) { - if (!val) { - ntfs_log_error("'streams_interface' option " - "should have value.\n"); - goto err_exit; - } - if (!strcmp(val, "none")) - ctx->streams = NF_STREAMS_INTERFACE_NONE; - else if (!strcmp(val, "xattr")) - ctx->streams = NF_STREAMS_INTERFACE_XATTR; - else if (!strcmp(val, "windows")) - ctx->streams = NF_STREAMS_INTERFACE_WINDOWS; - else { - ntfs_log_error("Invalid named data streams " - "access interface.\n"); - goto err_exit; - } - } else if (!strcmp(opt, "noauto")) { - /* Don't pass noauto option to fuse. */ - } else if (!strcmp(opt, "debug")) { - if (val) { - ntfs_log_error("'debug' option should not have " - "value.\n"); - goto err_exit; - } - ctx->debug = TRUE; - ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); - ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); - } else if (!strcmp(opt, "no_detach")) { - if (val) { - ntfs_log_error("'no_detach' option should not " - "have value.\n"); - goto err_exit; - } - ctx->no_detach = TRUE; - } else if (!strcmp(opt, "remount")) { - ntfs_log_error("Remounting is not supported at present." - " You have to umount volume and then " - "mount it once again.\n"); - goto err_exit; - } else { /* Probably FUSE option. */ - strcat(ret, opt); - if (val) { - strcat(ret, "="); - strcat(ret, val); - } - strcat(ret, ","); - } - } - if (!no_def_opts) - strcat(ret, def_opts); - strcat(ret, "fsname="); - strcat(ret, opts.device); -exit: - free(options); - return ret; -err_exit: - free(ret); - ret = NULL; - goto exit; -} - static void usage(void) { - ntfs_log_info("\n%s v%s (libntfs %s) - NTFS module for FUSE.\n\n", - EXEC_NAME, VERSION, ntfs_libntfs_version()); - ntfs_log_info("Copyright (C) 2005-2006 Yura Pakhuchiy\n\n"); + ntfs_log_info("\n%s v%s (libntfs %s) - Userspace read/write NTFS " + "driver.\n\n", EXEC_NAME, VERSION, + ntfs_libntfs_version()); + ntfs_log_info("Copyright (c) 2005-2007 Yura Pakhuchiy\n"); + ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n"); + ntfs_log_info("Copyright (c) 2006 Szabolcs Szakacsits\n\n"); ntfs_log_info("usage: %s device mount_point [-o options]\n\n", EXEC_NAME); - ntfs_log_info("ntfsmount options are:\n\tforce\n\tno_def_opts\n\tumask" - "\n\tfmask\n\tdmask\n\tuid\n\tgid\n\tshow_sys_files\n\t" - "silent\n\tlocale\n\tstreams_interface\n" - "Also look into FUSE documentation about it options " - "(NOTE: not all FUSE options are supported by ntfsmount).\n"); - ntfs_log_info("Default options are: \"%s\".\n\n", def_opts); + ntfs_log_info("Default options:\n\t%s\n\n", + ntfs_fuse_default_options); ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); } @@ -1681,178 +1507,178 @@ static char *realpath(const char *path, char *resolved_path) } #endif -/** - * parse_options - Read and validate the programs command line - * - * Read the command line, verify the syntax and parse the options. - * This function is very long, but quite simple. - * - * Return: 1 Success - * 0 Error, one or more problems - */ -static int parse_options(int argc, char *argv[]) +static int ntfs_fuse_init(void) { - int err = 0, help = 0; - int c = -1; - - static const char *sopt = "-o:h?qv"; - static const struct option lopt[] = { - { "options", required_argument, NULL, 'o' }, - { "help", no_argument, NULL, 'h' }, - { "quiet", no_argument, NULL, 'q' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } - }; - - opterr = 0; /* We'll handle the errors, thank you. */ - - opts.mnt_point = NULL; - opts.options = NULL; - opts.device = NULL; - - while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { - switch (c) { - case 1: /* A non-option argument */ - if (!opts.device) { - opts.device = malloc(PATH_MAX + 1); - if (!opts.device) { - ntfs_log_perror("malloc"); - err++; - break; - } - /* We don't want relative path in /etc/mtab. */ - if (optarg[0] != '/') { - if (!realpath(optarg, opts.device)) { - ntfs_log_perror("Failed to " - "access %s", - optarg); - free(opts.device); - opts.device = NULL; - err++; - break; - } - } else - strcpy(opts.device, optarg); - } else if (!opts.mnt_point) - opts.mnt_point = optarg; - else { - ntfs_log_error("You must specify exactly one " - "device and exactly one mount " - "point.\n"); - err++; - } - break; - case 'o': - if (!opts.options) - opts.options = optarg; - else { - ntfs_log_error("You must specify exactly one " - "set of options.\n"); - err++; - } - break; - case 'h': - case '?': - help++; - break; - case 'q': - opts.quiet++; - break; - case 'v': - opts.verbose++; - break; - default: - ntfs_log_error("Unknown option '%s'.\n", optarg); - err++; - break; - } - } - - if (help) { - opts.quiet = 0; - } else { - if (!opts.device) { - ntfs_log_error("No device specified.\n"); - err++; - } - - if (opts.quiet && opts.verbose) { - ntfs_log_error("You may not use --quiet and --verbose " - "at the same time.\n"); - err++; - } - } - - if (help || err) - usage(); - - return (!help && !err); -} - -int main(int argc, char *argv[]) -{ - char *parsed_options; - struct fuse_args margs = FUSE_ARGS_INIT(0, NULL); - struct fuse *fh; - struct fuse_chan *fch; - utils_set_locale(); ntfs_log_set_handler(ntfs_log_handler_stderr); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); - if (!parse_options(argc, argv)) - return 1; + ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t)); + if (!ctx) + return -1; + + *ctx = (ntfs_fuse_context_t) { + .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, + .uid = geteuid(), + .gid = getegid(), + .fmask = 0111, + .dmask = 0, + .streams = NF_STREAMS_INTERFACE_NONE, + .silent = TRUE, + }; + return 0; +} + +static int ntfs_fuse_opt_proc(void *data __attribute__((unused)), + const char *arg, int key, struct fuse_args *outargs) +{ + switch (key) { + case NF_KEY_HELP: + return -1; /* Force usage show. */ + case NF_KEY_UMASK: + ctx->dmask = ctx->fmask; + return 0; + case FUSE_OPT_KEY_NONOPT: /* All non-option arguments go here. */ + if (!ctx->device) { + /* We don't want relative path in /etc/mtab. */ + if (arg[0] != '/') { + ctx->device = ntfs_malloc(PATH_MAX + 1); + if (!ctx->device) + return -1; + if (!realpath(arg, ctx->device)) { + ntfs_log_perror("realpath(): %s", arg); + free(ctx->device); + ctx->device = NULL; + return -1; + } + } else { + ctx->device = strdup(arg); + if (!ctx->device) { + ntfs_log_perror("strdup()"); + return -1; + } + } + return 0; + } + if (!ctx->mnt_point) { + ctx->mnt_point = strdup(arg); + if (!ctx->mnt_point) { + ntfs_log_perror("strdup()"); + return -1; + } + return 0; + } + ntfs_log_error("You must specify exactly one device and " + "exactly one mount point.\n"); + return -1; + default: + if (!strcmp(arg, "remount")) { + ntfs_log_error("Remounting is not supported yet. " + "You have to umount volume and then " + "mount it once again.\n"); + return -1; + } + return 1; /* Just pass all unknown to us options to FUSE. */ + } +} + +static int parse_options(struct fuse_args *args) +{ + int ret; + char *fsname; + + ret = fuse_opt_parse(args, ctx, ntfs_fuse_opts, ntfs_fuse_opt_proc); + if (!ctx->device) { + ntfs_log_error("No device specified.\n"); + return -1; + } + if (ctx->quiet && ctx->verbose) { + ntfs_log_error("You may not use --quiet and --verbose at the " + "same time.\n"); + return -1; + } + if (ctx->debug) { + ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG); + ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE); + } + if (ctx->locale && !setlocale(LC_ALL, ctx->locale)) + ntfs_log_error("Failed to set locale to %s " + "(continue anyway).\n", ctx->locale); + fsname = ntfs_malloc(strlen(ctx->device) + 64); + if (!fsname) + return -1; + sprintf(fsname, "-ofsname=%s", ctx->device); + if (fuse_opt_add_arg(args, fsname) == -1) { + free(fsname); + return -1; + } + free(fsname); + if (!ctx->no_def_opts) { + if (fuse_opt_add_arg(args, "-o") == -1) + return -1; + if (fuse_opt_add_arg(args, ntfs_fuse_default_options) == -1) + return -1; + } + if (ctx->debug || ctx->no_detach) { + if (fuse_opt_add_arg(args, "-odebug") == -1) + return -1; + } + return ret; +} + +static int ntfs_fuse_mount(void) +{ + ntfs_volume *vol; + + vol = utils_mount_volume(ctx->device, NTFS_MNT_NOATIME | + ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | + ((ctx->case_insensitive) ? 0 : + NTFS_MNT_CASE_SENSITIVE) | + NTFS_MNT_NOT_EXCLUSIVE /* FIXME */, ctx->force); + if (!vol) { + ntfs_log_error("Mount failed.\n"); + return -1; + } + ctx->vol = vol; + return 0; +} + +int main(int argc, char *argv[]) +{ + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse *fh; + struct fuse_chan *fch; ntfs_fuse_init(); - /* Parse options. */ - parsed_options = parse_mount_options((opts.options) ? - opts.options : ""); - if (!parsed_options) { + if (parse_options(&args) == -1) { + usage(); + fuse_opt_free_args(&args); ntfs_fuse_destroy(NULL); - return 3; + return 1; } - - /* Mount volume. */ - if (ntfs_fuse_mount(opts.device)) { + /* Mount volume (libntfs part). */ + if (ntfs_fuse_mount()) { + fuse_opt_free_args(&args); ntfs_fuse_destroy(NULL); - free(parsed_options); - return 4; + return 1; } - /* Create filesystem. */ - fch = NULL; - if (!(fuse_opt_add_arg(&margs, "") == -1 || - fuse_opt_add_arg(&margs, "-o") == -1 || - fuse_opt_add_arg(&margs, parsed_options))) - fch = fuse_mount(opts.mnt_point, &margs); - fuse_opt_free_args(&margs); - free(parsed_options); + /* Create filesystem (FUSE part). */ + fch = fuse_mount(ctx->mnt_point, &args); if (!fch) { ntfs_log_error("fuse_mount failed.\n"); + fuse_opt_free_args(&args); ntfs_fuse_destroy(NULL); - return 5; + return 1; } - fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */ - margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL); - if (fuse_opt_add_arg(&margs, "") == -1 || - fuse_opt_add_arg(&margs, "-o") == -1) - fh = NULL; - if (!ctx->debug && !ctx->no_detach) { - if (fuse_opt_add_arg(&margs, "use_ino,kernel_cache") == -1) - fh = NULL; - } else { - if (fuse_opt_add_arg(&margs, "use_ino,debug") == -1) - fh = NULL; - } - if (fh) - fh = fuse_new(fch, &margs , &ntfs_fuse_oper, - sizeof(ntfs_fuse_oper), NULL); - fuse_opt_free_args(&margs); + fh = fuse_new(fch, &args , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper), + NULL); + fuse_opt_free_args(&args); if (!fh) { ntfs_log_error("fuse_new failed.\n"); - fuse_unmount(opts.mnt_point, fch); + fuse_unmount(ctx->mnt_point, fch); ntfs_fuse_destroy(NULL); - return 6; + return 1; } if (!ctx->debug && !ctx->no_detach) { if (daemon(0, 0)) @@ -1866,13 +1692,13 @@ int main(int argc, char *argv[]) ntfs_log_info("Version %s (libntfs %s)\n", VERSION, ntfs_libntfs_version()); ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS version %d.%d)\n", - opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", + ctx->device, (ctx->ro) ? "Read-Only" : "Read-Write", ctx->vol->vol_name, ctx->vol->major_ver, ctx->vol->minor_ver); /* Main loop. */ fuse_loop(fh); /* Destroy. */ - fuse_unmount(opts.mnt_point, fch); + fuse_unmount(ctx->mnt_point, fch); fuse_destroy(fh); return 0; } From dcc13dca8b7c1f36b89f7dac5833c284b7554f14 Mon Sep 17 00:00:00 2001 From: uvman Date: Sun, 7 Jan 2007 19:08:22 +0000 Subject: [PATCH 176/289] ni->allocated_size for resident files is rounded up to multiples of 8. A '>> 9' on such value may round up or down. Fix it to always round up. Samba 3 use st_blocks to detect if a file is sparse. ActiveSync 4 fails on sparse files. --- ChangeLog | 1 + ntfsprogs/ntfsmount.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index f6ed3593..46cb4628 100644 --- a/ChangeLog +++ b/ChangeLog @@ -129,6 +129,7 @@ xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount: Remove "show_sys_files" as potential harmful and introduce new "case_insensitive" option to support both case sensitive and insensitive mounts. (Yura) + - ntfsmount: st_block calculation was wrong for resident files. (Yuval) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index badd045e..c42ec166 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -375,7 +375,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (na) { stbuf->st_size = na->data_size; - stbuf->st_blocks = na->allocated_size >> 9; + stbuf->st_blocks = (na->allocated_size+511) >> 9; ntfs_attr_close(na); } else { stbuf->st_size = 0; @@ -386,7 +386,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) /* Regular or Interix (INTX) file. */ stbuf->st_mode = S_IFREG; stbuf->st_size = ni->data_size; - stbuf->st_blocks = ni->allocated_size >> 9; + stbuf->st_blocks = (ni->allocated_size+511) >> 9; stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { na = ntfs_attr_open(ni, AT_DATA, stream_name, @@ -398,7 +398,8 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } if (stream_name_len) { stbuf->st_size = na->data_size; - stbuf->st_blocks = ni->allocated_size >> 9; + stbuf->st_blocks = (ni->allocated_size+511) >> + 9; } /* Check whether it's Interix FIFO or socket. */ if (!(ni->flags & FILE_ATTR_HIDDEN) && From 857573a2e4a713927b0f4807dbf2c06c0e3554ec Mon Sep 17 00:00:00 2001 From: yura Date: Sun, 7 Jan 2007 19:19:53 +0000 Subject: [PATCH 177/289] minor style fix and changelog description --- ChangeLog | 2 +- ntfsprogs/ntfsmount.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 46cb4628..27e54770 100644 --- a/ChangeLog +++ b/ChangeLog @@ -129,7 +129,7 @@ xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount: Remove "show_sys_files" as potential harmful and introduce new "case_insensitive" option to support both case sensitive and insensitive mounts. (Yura) - - ntfsmount: st_block calculation was wrong for resident files. (Yuval) + - ntfsmount: st_block calculation was wrong. (Yuval) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index c42ec166..8a79a28b 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -375,7 +375,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (na) { stbuf->st_size = na->data_size; - stbuf->st_blocks = (na->allocated_size+511) >> 9; + stbuf->st_blocks = (na->allocated_size + 511) >> 9; ntfs_attr_close(na); } else { stbuf->st_size = 0; @@ -386,7 +386,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) /* Regular or Interix (INTX) file. */ stbuf->st_mode = S_IFREG; stbuf->st_size = ni->data_size; - stbuf->st_blocks = (ni->allocated_size+511) >> 9; + stbuf->st_blocks = (ni->allocated_size + 511) >> 9; stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { na = ntfs_attr_open(ni, AT_DATA, stream_name, @@ -398,8 +398,8 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } if (stream_name_len) { stbuf->st_size = na->data_size; - stbuf->st_blocks = (ni->allocated_size+511) >> - 9; + stbuf->st_blocks = + (ni->allocated_size + 511) >> 9; } /* Check whether it's Interix FIFO or socket. */ if (!(ni->flags & FILE_ATTR_HIDDEN) && From 3575e2089e78e325988c969521a231e27557a284 Mon Sep 17 00:00:00 2001 From: aia21 Date: Tue, 6 Mar 2007 15:44:30 +0000 Subject: [PATCH 178/289] - mkntfs: Use Vista $Boot rather than XP one. (Anton) --- ChangeLog | 1 + ntfsprogs/boot.c | 464 ++++++++++++++++++++++++++--------------------- ntfsprogs/boot.h | 2 +- 3 files changed, 256 insertions(+), 211 deletions(-) diff --git a/ChangeLog b/ChangeLog index 27e54770..f527db9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -130,6 +130,7 @@ xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. introduce new "case_insensitive" option to support both case sensitive and insensitive mounts. (Yura) - ntfsmount: st_block calculation was wrong. (Yuval) + - mkntfs: Use Vista $Boot rather than XP one. (Anton) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/boot.c b/ntfsprogs/boot.c index f1bdeb67..9272be9f 100644 --- a/ntfsprogs/boot.c +++ b/ntfsprogs/boot.c @@ -1,224 +1,268 @@ #include "boot.h" /** - * boot_array - the first 3429 bytes of $Boot - * The first 3429 bytes of $Boot. The rest is just zero. Total 8192 bytes. + * boot_array - the first 4136 bytes of $Boot + * + * The first 4136 bytes of $Boot. The rest is just zero. Total 8192 bytes. */ -const unsigned char boot_array[3429] = { -235, 91, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0, +const unsigned char boot_array[4136] = { +235, 82, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 51, 192, -142, 208, 188, 0, 124, 251, 184, 192, 7, 142, 216, 199, 6, 84, 0, 0, - 0, 199, 6, 86, 0, 0, 0, 199, 6, 91, 0, 16, 0, 184, 0, 13, -142, 192, 43, 219, 232, 7, 0, 104, 0, 13, 104, 102, 2, 203, 80, 83, - 81, 82, 6, 102, 161, 84, 0, 102, 3, 6, 28, 0, 102, 51, 210, 102, - 15, 183, 14, 24, 0, 102, 247, 241, 254, 194, 136, 22, 90, 0, 102, 139, -208, 102, 193, 234, 16, 247, 54, 26, 0, 136, 22, 37, 0, 163, 88, 0, -161, 24, 0, 42, 6, 90, 0, 64, 59, 6, 91, 0, 118, 3, 161, 91, - 0, 80, 180, 2, 139, 22, 88, 0, 177, 6, 210, 230, 10, 54, 90, 0, -139, 202, 134, 233, 138, 54, 37, 0, 178, 128, 205, 19, 88, 114, 42, 1, - 6, 84, 0, 131, 22, 86, 0, 0, 41, 6, 91, 0, 118, 11, 193, 224, - 5, 140, 194, 3, 208, 142, 194, 235, 138, 7, 90, 89, 91, 88, 195, 190, - 89, 1, 235, 8, 190, 227, 1, 235, 3, 190, 57, 1, 232, 9, 0, 190, -173, 1, 232, 3, 0, 251, 235, 254, 172, 60, 0, 116, 9, 180, 14, 187, - 7, 0, 205, 16, 235, 242, 195, 29, 0, 65, 32, 100, 105, 115, 107, 32, -114, 101, 97, 100, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114, -114, 101, 100, 46, 13, 10, 0, 41, 0, 65, 32, 107, 101, 114, 110, 101, -108, 32, 102, 105, 108, 101, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110, -103, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 100, 105, 115, 107, 46, - 13, 10, 0, 37, 0, 65, 32, 107, 101, 114, 110, 101, 108, 32, 102, 105, -108, 101, 32, 105, 115, 32, 116, 111, 111, 32, 100, 105, 115, 99, 111, 110, -116, 105, 103, 117, 111, 117, 115, 46, 13, 10, 0, 51, 0, 73, 110, 115, -101, 114, 116, 32, 97, 32, 115, 121, 115, 116, 101, 109, 32, 100, 105, 115, -107, 101, 116, 116, 101, 32, 97, 110, 100, 32, 114, 101, 115, 116, 97, 114, -116, 13, 10, 116, 104, 101, 32, 115, 121, 115, 116, 101, 109, 46, 13, 10, - 0, 23, 0, 92, 78, 84, 76, 68, 82, 32, 105, 115, 32, 99, 111, 109, -112, 114, 101, 115, 115, 101, 100, 46, 13, 10, 0, 0, 0, 0, 85, 170, - 5, 0, 78, 0, 84, 0, 76, 0, 68, 0, 82, 0, 4, 0, 36, 0, - 73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, 0, 0, 0, 0, + 0, 0, 0, 0, 250, 51, 192, 142, 208, 188, 0, 124, 251, 104, 192, 7, + 31, 30, 104, 102, 0, 203, 136, 22, 14, 0, 102, 129, 62, 3, 0, 78, + 84, 70, 83, 117, 21, 180, 65, 187, 170, 85, 205, 19, 114, 12, 129, 251, + 85, 170, 117, 6, 247, 193, 1, 0, 117, 3, 233, 210, 0, 30, 131, 236, + 24, 104, 26, 0, 180, 72, 138, 22, 14, 0, 139, 244, 22, 31, 205, 19, +159, 131, 196, 24, 158, 88, 31, 114, 225, 59, 6, 11, 0, 117, 219, 163, + 15, 0, 193, 46, 15, 0, 4, 30, 90, 51, 219, 185, 0, 32, 43, 200, +102, 255, 6, 17, 0, 3, 22, 15, 0, 142, 194, 255, 6, 22, 0, 232, + 64, 0, 43, 200, 119, 239, 184, 0, 187, 205, 26, 102, 35, 192, 117, 45, +102, 129, 251, 84, 67, 80, 65, 117, 36, 129, 249, 2, 1, 114, 30, 22, +104, 7, 187, 22, 104, 112, 14, 22, 104, 9, 0, 102, 83, 102, 83, 102, + 85, 22, 22, 22, 104, 184, 1, 102, 97, 14, 7, 205, 26, 233, 106, 1, +144, 144, 102, 96, 30, 6, 102, 161, 17, 0, 102, 3, 6, 28, 0, 30, +102, 104, 0, 0, 0, 0, 102, 80, 6, 83, 104, 1, 0, 104, 16, 0, +180, 66, 138, 22, 14, 0, 22, 31, 139, 244, 205, 19, 102, 89, 91, 90, +102, 89, 102, 89, 31, 15, 130, 22, 0, 102, 255, 6, 17, 0, 3, 22, + 15, 0, 142, 194, 255, 14, 22, 0, 117, 188, 7, 31, 102, 97, 195, 160, +248, 1, 232, 8, 0, 160, 251, 1, 232, 2, 0, 235, 254, 180, 1, 139, +240, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205, 16, 235, 242, 195, + 13, 10, 65, 32, 100, 105, 115, 107, 32, 114, 101, 97, 100, 32, 101, 114, +114, 111, 114, 32, 111, 99, 99, 117, 114, 114, 101, 100, 0, 13, 10, 66, + 79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110, +103, 0, 13, 10, 66, 79, 79, 84, 77, 71, 82, 32, 105, 115, 32, 99, +111, 109, 112, 114, 101, 115, 115, 101, 100, 0, 13, 10, 80, 114, 101, 115, +115, 32, 67, 116, 114, 108, 43, 65, 108, 116, 43, 68, 101, 108, 32, 116, +111, 32, 114, 101, 115, 116, 97, 114, 116, 13, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 128, 157, 178, 202, 0, 0, 85, 170, + 7, 0, 66, 0, 79, 0, 79, 0, 84, 0, 77, 0, 71, 0, 82, 0, + 4, 0, 36, 0, 73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 140, 200, 142, 216, 193, 224, 4, 250, 139, 224, -251, 102, 15, 183, 6, 11, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227, -102, 163, 78, 2, 102, 139, 14, 64, 0, 128, 249, 0, 15, 143, 14, 0, -246, 217, 102, 184, 1, 0, 0, 0, 102, 211, 224, 235, 8, 144, 102, 161, - 78, 2, 102, 247, 225, 102, 163, 82, 2, 102, 15, 183, 30, 11, 0, 102, - 51, 210, 102, 247, 243, 102, 163, 86, 2, 232, 44, 4, 102, 139, 14, 74, - 2, 102, 137, 14, 34, 2, 102, 3, 14, 82, 2, 102, 137, 14, 38, 2, -102, 3, 14, 82, 2, 102, 137, 14, 42, 2, 102, 3, 14, 82, 2, 102, -137, 14, 58, 2, 102, 3, 14, 82, 2, 102, 137, 14, 66, 2, 102, 184, -144, 0, 0, 0, 102, 139, 14, 34, 2, 232, 65, 9, 102, 11, 192, 15, -132, 22, 254, 102, 163, 46, 2, 102, 184, 160, 0, 0, 0, 102, 139, 14, - 38, 2, 232, 40, 9, 102, 163, 50, 2, 102, 184, 176, 0, 0, 0, 102, -139, 14, 42, 2, 232, 22, 9, 102, 163, 54, 2, 102, 161, 46, 2, 102, - 11, 192, 15, 132, 227, 253, 103, 128, 120, 8, 0, 15, 133, 218, 253, 103, -102, 141, 80, 16, 103, 3, 66, 4, 103, 102, 15, 182, 72, 12, 102, 137, - 14, 94, 2, 103, 102, 139, 72, 8, 102, 137, 14, 90, 2, 102, 161, 90, - 2, 102, 15, 183, 14, 11, 0, 102, 51, 210, 102, 247, 241, 102, 163, 98, - 2, 102, 161, 66, 2, 102, 3, 6, 90, 2, 102, 163, 70, 2, 102, 131, - 62, 50, 2, 0, 15, 132, 25, 0, 102, 131, 62, 54, 2, 0, 15, 132, -135, 253, 102, 139, 30, 54, 2, 30, 7, 102, 139, 62, 70, 2, 232, 177, - 1, 102, 15, 183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 153, 6, -102, 11, 192, 15, 132, 88, 253, 103, 102, 139, 0, 30, 7, 102, 139, 62, - 58, 2, 232, 209, 4, 102, 161, 58, 2, 102, 187, 128, 0, 0, 0, 102, -185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 203, 0, 102, 11, -192, 15, 132, 42, 253, 103, 102, 15, 183, 88, 12, 102, 129, 227, 255, 0, - 0, 0, 15, 133, 30, 253, 102, 139, 216, 104, 0, 32, 7, 102, 43, 255, -232, 79, 1, 138, 22, 36, 0, 184, 232, 3, 142, 192, 141, 54, 11, 0, - 43, 192, 104, 0, 32, 80, 203, 80, 83, 81, 82, 6, 255, 54, 91, 0, -255, 54, 84, 0, 255, 54, 86, 0, 139, 195, 193, 232, 4, 140, 193, 3, -193, 37, 255, 15, 45, 0, 16, 247, 216, 139, 14, 91, 0, 193, 225, 5, - 81, 59, 193, 118, 2, 139, 193, 80, 193, 232, 5, 163, 91, 0, 232, 61, -252, 88, 89, 43, 200, 118, 11, 140, 194, 3, 208, 142, 194, 184, 0, 16, -235, 222, 143, 6, 86, 0, 143, 6, 84, 0, 143, 6, 91, 0, 7, 90, - 89, 91, 88, 195, 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13, - 0, 102, 247, 225, 102, 163, 84, 0, 102, 139, 195, 102, 247, 225, 163, 91, - 0, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7, -232, 116, 255, 102, 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131, - 56, 255, 15, 132, 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11, -201, 15, 133, 10, 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103, - 58, 72, 9, 15, 133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 61, - 5, 102, 81, 30, 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0, -195, 103, 102, 131, 120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4, -235, 171, 102, 43, 192, 195, 102, 139, 243, 232, 18, 5, 103, 102, 3, 0, -103, 247, 64, 12, 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103, - 58, 74, 64, 15, 133, 24, 0, 103, 102, 141, 114, 66, 232, 239, 4, 102, - 81, 30, 7, 102, 139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, -131, 120, 8, 0, 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51, -192, 195, 103, 128, 123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103, -102, 141, 83, 16, 103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243, -164, 102, 97, 144, 31, 7, 195, 103, 102, 141, 83, 16, 103, 102, 139, 74, - 8, 102, 65, 102, 43, 192, 232, 1, 0, 195, 6, 30, 102, 96, 103, 128, -123, 8, 1, 15, 132, 3, 0, 233, 127, 251, 102, 131, 249, 0, 15, 133, - 6, 0, 102, 97, 144, 31, 7, 195, 102, 83, 102, 80, 102, 81, 102, 87, - 6, 232, 87, 3, 102, 139, 209, 7, 102, 95, 102, 89, 102, 59, 202, 15, -141, 3, 0, 102, 139, 209, 232, 171, 254, 102, 43, 202, 102, 139, 218, 102, -139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, 102, 15, 183, 22, 11, - 0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, 195, 102, 91, 235, 170, - 6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, 0, 233, 25, 251, -102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, 7, 195, 102, 83, -102, 80, 102, 81, 102, 87, 6, 102, 81, 102, 51, 210, 102, 15, 182, 14, - 13, 0, 102, 247, 241, 102, 82, 232, 225, 2, 102, 15, 182, 30, 13, 0, -102, 247, 227, 102, 90, 102, 3, 194, 102, 80, 102, 15, 182, 6, 13, 0, -102, 247, 225, 102, 139, 208, 102, 88, 102, 89, 7, 102, 95, 102, 89, 102, - 59, 202, 15, 141, 3, 0, 102, 139, 209, 102, 163, 84, 0, 137, 22, 91, - 0, 6, 30, 102, 96, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4, - 3, 199, 80, 7, 232, 160, 253, 102, 97, 144, 31, 7, 102, 43, 202, 102, -139, 218, 102, 139, 194, 102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3, -248, 102, 88, 102, 3, 195, 102, 91, 233, 101, 255, 6, 30, 102, 96, 38, -103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, 11, 201, - 15, 132, 101, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, 254, 1, - 0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, 3, 38, -103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, 102, 73, -235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, 1, 0, - 0, 0, 102, 163, 30, 2, 102, 161, 26, 2, 102, 3, 6, 82, 2, 102, -163, 74, 2, 102, 161, 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227, -102, 163, 84, 0, 102, 161, 86, 2, 163, 91, 0, 102, 139, 30, 26, 2, - 30, 7, 232, 242, 252, 102, 15, 183, 251, 232, 111, 255, 102, 161, 26, 2, + 0, 0, 0, 0, 0, 0, 235, 34, 144, 144, 5, 0, 78, 0, 84, 0, + 76, 0, 68, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 15, 183, 6, 11, 0, +102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 163, 82, 2, 102, 139, 14, + 64, 0, 128, 249, 0, 15, 143, 14, 0, 246, 217, 102, 184, 1, 0, 0, + 0, 102, 211, 224, 235, 8, 144, 102, 161, 82, 2, 102, 247, 225, 102, 163, +102, 2, 102, 15, 183, 30, 11, 0, 102, 51, 210, 102, 247, 243, 102, 163, + 86, 2, 232, 149, 4, 102, 139, 14, 78, 2, 102, 137, 14, 38, 2, 102, + 3, 14, 102, 2, 102, 137, 14, 42, 2, 102, 3, 14, 102, 2, 102, 137, + 14, 46, 2, 102, 3, 14, 102, 2, 102, 137, 14, 62, 2, 102, 3, 14, +102, 2, 102, 137, 14, 70, 2, 102, 184, 144, 0, 0, 0, 102, 139, 14, + 38, 2, 232, 131, 9, 102, 11, 192, 15, 132, 83, 254, 102, 163, 50, 2, +102, 184, 160, 0, 0, 0, 102, 139, 14, 42, 2, 232, 106, 9, 102, 163, + 54, 2, 102, 184, 176, 0, 0, 0, 102, 139, 14, 46, 2, 232, 88, 9, +102, 163, 58, 2, 102, 161, 50, 2, 102, 11, 192, 15, 132, 32, 254, 103, +128, 120, 8, 0, 15, 133, 23, 254, 103, 102, 141, 80, 16, 103, 3, 66, + 4, 103, 102, 15, 182, 72, 12, 102, 137, 14, 114, 2, 103, 102, 139, 72, + 8, 102, 137, 14, 110, 2, 102, 161, 110, 2, 102, 15, 183, 14, 11, 0, +102, 51, 210, 102, 247, 241, 102, 163, 118, 2, 102, 161, 70, 2, 102, 3, + 6, 110, 2, 102, 163, 74, 2, 102, 131, 62, 54, 2, 0, 15, 132, 29, + 0, 102, 131, 62, 58, 2, 0, 15, 132, 196, 253, 102, 139, 30, 58, 2, + 30, 7, 102, 139, 62, 74, 2, 102, 161, 46, 2, 232, 224, 1, 102, 15, +183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 34, 8, 102, 11, 192, + 15, 133, 22, 0, 102, 15, 183, 14, 90, 2, 102, 184, 92, 2, 0, 0, +232, 12, 8, 102, 11, 192, 15, 132, 66, 12, 103, 102, 139, 0, 30, 7, +102, 139, 62, 62, 2, 232, 63, 6, 102, 161, 62, 2, 102, 187, 32, 0, + 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 228, + 0, 102, 133, 192, 15, 133, 35, 0, 102, 161, 62, 2, 102, 187, 128, 0, + 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 196, + 0, 102, 11, 192, 15, 133, 68, 0, 233, 241, 11, 102, 51, 210, 102, 185, +128, 0, 0, 0, 102, 161, 62, 2, 232, 202, 8, 102, 11, 192, 15, 132, +218, 11, 30, 7, 102, 139, 62, 62, 2, 232, 219, 5, 102, 161, 62, 2, +102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, + 0, 0, 232, 128, 0, 102, 11, 192, 15, 132, 176, 11, 103, 102, 15, 183, + 88, 12, 102, 129, 227, 255, 0, 0, 0, 15, 133, 165, 11, 102, 139, 216, +104, 0, 32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 0, 1, 104, 0, + 32, 7, 102, 43, 255, 102, 161, 62, 2, 232, 172, 10, 138, 22, 14, 0, +184, 232, 3, 142, 192, 141, 54, 11, 0, 43, 192, 104, 0, 32, 80, 203, + 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13, 0, 102, 247, 225, +102, 163, 17, 0, 102, 139, 195, 102, 247, 225, 163, 22, 0, 139, 223, 131, +227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 51, 252, 102, + 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131, 56, 255, 15, 132, + 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11, 201, 15, 133, 10, + 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103, 58, 72, 9, 15, +133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 151, 6, 102, 81, 30, + 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 102, 131, +120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4, 235, 171, 102, 43, +192, 195, 102, 139, 243, 232, 108, 6, 103, 102, 3, 0, 103, 247, 64, 12, + 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103, 58, 74, 64, 15, +133, 24, 0, 103, 102, 141, 114, 66, 232, 73, 6, 102, 81, 30, 7, 102, +139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103, 131, 120, 8, 0, + 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51, 192, 195, 103, 128, +123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103, 102, 141, 83, 16, +103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243, 164, 102, 97, 144, + 31, 7, 195, 102, 80, 103, 102, 141, 83, 16, 102, 133, 192, 15, 133, 10, + 0, 103, 102, 139, 74, 8, 102, 65, 235, 17, 144, 103, 102, 139, 66, 24, +102, 51, 210, 102, 247, 54, 82, 2, 102, 139, 200, 102, 43, 192, 102, 94, +232, 1, 0, 195, 6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, + 0, 233, 107, 251, 102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, + 7, 195, 102, 83, 102, 80, 102, 81, 102, 86, 102, 87, 6, 232, 145, 4, +102, 139, 209, 7, 102, 95, 102, 94, 102, 89, 102, 133, 192, 15, 132, 52, + 0, 102, 59, 202, 15, 141, 3, 0, 102, 139, 209, 232, 130, 254, 102, 43, +202, 102, 139, 218, 102, 139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, +102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, +195, 102, 91, 235, 159, 102, 133, 246, 15, 132, 3, 251, 102, 81, 102, 87, + 6, 103, 102, 15, 182, 67, 9, 102, 133, 192, 15, 132, 32, 0, 102, 209, +224, 102, 43, 224, 102, 139, 252, 102, 84, 102, 86, 103, 102, 15, 183, 115, + 10, 102, 3, 243, 102, 139, 200, 243, 164, 102, 94, 235, 3, 144, 102, 80, +102, 80, 103, 102, 139, 3, 102, 80, 103, 102, 139, 67, 24, 102, 80, 103, +102, 139, 86, 32, 102, 133, 210, 15, 132, 11, 0, 102, 139, 254, 30, 7, +102, 139, 194, 232, 113, 3, 102, 139, 198, 102, 90, 102, 89, 102, 66, 102, + 81, 102, 86, 232, 63, 6, 102, 133, 192, 15, 132, 146, 250, 102, 94, 102, + 89, 102, 139, 254, 30, 7, 232, 78, 3, 102, 139, 198, 102, 139, 217, 102, + 89, 102, 90, 102, 81, 102, 86, 102, 209, 233, 232, 248, 253, 102, 133, 192, + 15, 132, 107, 250, 102, 94, 102, 89, 102, 3, 225, 7, 102, 95, 102, 89, +102, 139, 208, 102, 88, 102, 91, 102, 139, 218, 233, 245, 254, 6, 30, 102, + 96, 38, 103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, + 11, 201, 15, 132, 57, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, +254, 1, 0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, + 3, 38, 103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, +102, 73, 235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, + 1, 0, 0, 0, 102, 163, 34, 2, 102, 161, 30, 2, 102, 3, 6, 102, + 2, 102, 163, 106, 2, 102, 3, 6, 102, 2, 102, 163, 78, 2, 102, 161, + 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2, +102, 137, 7, 102, 163, 17, 0, 131, 195, 4, 102, 161, 86, 2, 102, 137, + 7, 163, 22, 0, 131, 195, 4, 102, 137, 30, 78, 2, 102, 139, 30, 30, + 2, 30, 7, 232, 92, 249, 102, 139, 251, 232, 81, 255, 102, 161, 30, 2, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, - 0, 0, 232, 100, 253, 102, 11, 192, 15, 132, 87, 0, 102, 139, 216, 30, - 7, 102, 139, 62, 22, 2, 232, 249, 253, 102, 139, 30, 22, 2, 103, 102, -129, 59, 128, 0, 0, 0, 15, 132, 6, 0, 103, 3, 91, 4, 235, 238, -103, 102, 129, 59, 128, 0, 0, 0, 15, 133, 39, 0, 102, 83, 103, 102, -139, 67, 16, 102, 139, 62, 74, 2, 30, 7, 232, 9, 1, 102, 91, 102, -161, 82, 2, 102, 1, 6, 74, 2, 102, 255, 6, 30, 2, 103, 3, 91, - 4, 235, 205, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, 14, 30, - 2, 102, 161, 26, 2, 102, 82, 102, 80, 102, 81, 102, 82, 102, 187, 128, + 0, 0, 232, 16, 253, 102, 11, 192, 15, 132, 25, 1, 102, 139, 216, 30, + 7, 102, 139, 62, 26, 2, 102, 51, 192, 232, 162, 253, 102, 139, 30, 26, + 2, 102, 129, 63, 128, 0, 0, 0, 15, 132, 235, 0, 3, 95, 4, 235, +240, 102, 83, 102, 139, 71, 16, 102, 247, 38, 86, 2, 102, 80, 102, 51, +210, 102, 15, 182, 30, 13, 0, 102, 247, 243, 102, 82, 232, 220, 0, 102, + 11, 192, 15, 132, 57, 249, 102, 139, 14, 86, 2, 102, 15, 182, 30, 13, + 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 139, 30, 78, 2, 102, 137, + 7, 131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 43, 194, 102, 59, 193, + 15, 134, 3, 0, 102, 139, 193, 102, 137, 7, 102, 43, 200, 102, 90, 15, +132, 117, 0, 102, 3, 194, 102, 80, 102, 51, 210, 102, 15, 182, 30, 13, + 0, 102, 247, 243, 102, 81, 232, 130, 0, 102, 89, 102, 11, 192, 15, 132, +221, 248, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 139, 30, 78, 2, +102, 139, 23, 131, 195, 4, 102, 3, 23, 102, 59, 208, 15, 133, 21, 0, +102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0, 102, 139, 193, +102, 1, 7, 235, 165, 131, 195, 4, 102, 137, 30, 78, 2, 102, 137, 7, +131, 195, 4, 102, 15, 182, 6, 13, 0, 102, 59, 193, 15, 134, 3, 0, +102, 139, 193, 102, 137, 7, 235, 130, 131, 195, 4, 102, 255, 6, 34, 2, +102, 137, 30, 78, 2, 102, 91, 3, 95, 4, 102, 129, 63, 128, 0, 0, + 0, 15, 132, 12, 255, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, + 14, 34, 2, 102, 139, 54, 106, 2, 102, 3, 54, 102, 2, 102, 82, 102, + 81, 102, 82, 102, 139, 30, 106, 2, 102, 139, 62, 86, 2, 102, 139, 4, +102, 163, 17, 0, 131, 198, 4, 102, 139, 4, 163, 22, 0, 131, 198, 4, + 30, 7, 232, 221, 247, 102, 43, 248, 15, 132, 8, 0, 247, 38, 11, 0, + 3, 216, 235, 217, 102, 139, 62, 106, 2, 30, 7, 232, 191, 253, 102, 161, +106, 2, 102, 187, 128, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 139, +209, 232, 129, 251, 102, 11, 192, 15, 132, 244, 247, 102, 139, 216, 102, 88, +102, 86, 232, 44, 1, 102, 94, 102, 11, 192, 15, 132, 5, 0, 102, 91, +102, 91, 195, 102, 89, 102, 90, 226, 132, 102, 51, 192, 195, 6, 30, 102, + 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13, 0, 102, 247, +243, 102, 82, 102, 87, 232, 83, 255, 102, 95, 102, 11, 192, 15, 132, 174, +247, 102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, +163, 17, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, + 19, 0, 137, 30, 22, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, +102, 81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 22, 0, +102, 185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, +140, 192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 5, 247, 102, 95, 7, +102, 3, 62, 82, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 112, +255, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, +102, 139, 14, 86, 2, 232, 85, 255, 232, 210, 252, 102, 97, 144, 31, 7, +195, 6, 30, 102, 96, 102, 247, 38, 114, 2, 102, 139, 30, 54, 2, 102, +139, 14, 114, 2, 102, 139, 54, 42, 2, 30, 7, 102, 139, 62, 70, 2, +232, 129, 251, 232, 167, 252, 102, 97, 144, 31, 7, 195, 102, 80, 102, 83, +102, 81, 102, 139, 30, 74, 2, 102, 139, 200, 102, 193, 232, 3, 102, 131, +225, 7, 102, 3, 216, 102, 184, 1, 0, 0, 0, 102, 211, 224, 103, 132, + 3, 15, 132, 4, 0, 248, 235, 2, 144, 249, 102, 89, 102, 91, 102, 88, +195, 103, 128, 123, 8, 1, 15, 132, 4, 0, 102, 43, 192, 195, 103, 102, +141, 115, 16, 103, 102, 139, 86, 8, 102, 59, 194, 15, 135, 11, 0, 103, +102, 139, 22, 102, 59, 194, 15, 131, 4, 0, 102, 43, 192, 195, 103, 3, + 94, 16, 102, 43, 246, 103, 128, 59, 0, 15, 132, 62, 0, 232, 129, 0, +102, 3, 241, 232, 57, 0, 102, 3, 202, 102, 59, 193, 15, 140, 33, 0, +102, 139, 209, 102, 80, 103, 102, 15, 182, 11, 102, 139, 193, 102, 131, 224, + 15, 102, 193, 233, 4, 102, 3, 217, 102, 3, 216, 102, 67, 102, 88, 235, +196, 102, 43, 200, 102, 43, 194, 102, 3, 198, 195, 102, 43, 192, 195, 102, + 43, 201, 103, 138, 11, 128, 225, 15, 102, 131, 249, 0, 15, 133, 4, 0, +102, 43, 201, 195, 102, 83, 102, 82, 102, 3, 217, 103, 102, 15, 190, 19, +102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, +103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, +195, 102, 83, 102, 82, 102, 43, 210, 103, 138, 19, 102, 131, 226, 15, 102, + 43, 201, 103, 138, 11, 192, 233, 4, 102, 131, 249, 0, 15, 133, 8, 0, +102, 43, 201, 102, 90, 102, 91, 195, 102, 3, 218, 102, 3, 217, 103, 102, + 15, 190, 19, 102, 73, 102, 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, +193, 226, 8, 103, 138, 19, 102, 75, 102, 73, 235, 235, 102, 139, 202, 102, + 90, 102, 91, 195, 102, 11, 201, 15, 133, 1, 0, 195, 102, 81, 102, 86, +103, 131, 62, 97, 15, 140, 12, 0, 103, 131, 62, 122, 15, 143, 4, 0, +103, 131, 46, 32, 102, 131, 198, 2, 226, 230, 102, 94, 102, 89, 195, 102, + 80, 102, 81, 102, 139, 208, 102, 161, 50, 2, 103, 102, 141, 88, 16, 103, + 3, 67, 4, 103, 102, 141, 64, 16, 102, 139, 218, 232, 68, 249, 102, 11, +192, 15, 132, 5, 0, 102, 89, 102, 89, 195, 102, 161, 54, 2, 102, 11, +192, 15, 133, 8, 0, 102, 89, 102, 89, 102, 51, 192, 195, 102, 139, 22, + 54, 2, 103, 102, 141, 82, 16, 103, 102, 139, 66, 24, 102, 51, 210, 102, +247, 54, 110, 2, 102, 51, 246, 102, 80, 102, 86, 102, 88, 102, 94, 102, + 59, 198, 15, 132, 58, 0, 102, 86, 102, 64, 102, 80, 102, 72, 232, 27, +254, 114, 232, 232, 235, 253, 102, 90, 102, 94, 102, 89, 102, 91, 102, 83, +102, 81, 102, 86, 102, 82, 102, 161, 70, 2, 103, 102, 141, 64, 24, 232, +208, 248, 102, 11, 192, 116, 196, 102, 89, 102, 89, 102, 89, 102, 89, 195, +102, 89, 102, 89, 102, 51, 192, 195, 102, 81, 102, 80, 102, 184, 5, 0, + 0, 0, 30, 7, 102, 139, 249, 232, 141, 253, 102, 139, 193, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, -215, 252, 102, 11, 192, 15, 132, 64, 249, 102, 139, 216, 102, 88, 232, 42, - 1, 102, 11, 192, 15, 132, 7, 0, 102, 91, 102, 91, 102, 91, 195, 102, - 89, 102, 88, 102, 90, 102, 3, 6, 82, 2, 226, 185, 102, 51, 192, 195, - 6, 30, 102, 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13, - 0, 102, 247, 243, 102, 82, 232, 144, 255, 102, 11, 192, 15, 132, 249, 248, -102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 163, - 84, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, 19, - 0, 137, 30, 91, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, 102, - 81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 91, 0, 102, -185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, 140, -192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 155, 251, 102, 95, 7, 102, - 3, 62, 78, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 116, 255, -102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, 102, -139, 14, 86, 2, 232, 89, 255, 232, 241, 253, 102, 97, 144, 31, 7, 195, - 6, 30, 102, 96, 102, 247, 38, 98, 2, 102, 139, 30, 50, 2, 102, 139, - 14, 98, 2, 30, 7, 102, 139, 62, 66, 2, 232, 35, 253, 232, 203, 253, -102, 97, 144, 31, 7, 195, 102, 80, 102, 83, 102, 81, 102, 139, 30, 70, - 2, 102, 139, 200, 102, 193, 232, 3, 102, 131, 225, 7, 102, 3, 216, 102, -184, 1, 0, 0, 0, 102, 211, 224, 103, 132, 3, 15, 132, 4, 0, 248, -235, 2, 144, 249, 102, 89, 102, 91, 102, 88, 195, 103, 128, 123, 8, 1, - 15, 132, 4, 0, 102, 43, 192, 195, 103, 102, 141, 115, 16, 103, 102, 139, - 86, 8, 102, 59, 194, 15, 135, 11, 0, 103, 102, 139, 22, 102, 59, 194, - 15, 131, 4, 0, 102, 43, 192, 195, 103, 3, 94, 16, 102, 43, 246, 103, -128, 59, 0, 15, 132, 62, 0, 232, 129, 0, 102, 3, 241, 232, 57, 0, -102, 3, 202, 102, 59, 193, 15, 140, 33, 0, 102, 139, 209, 102, 80, 103, -102, 15, 182, 11, 102, 139, 193, 102, 131, 224, 15, 102, 193, 233, 4, 102, - 3, 217, 102, 3, 216, 102, 67, 102, 88, 235, 196, 102, 43, 200, 102, 43, -194, 102, 3, 198, 195, 102, 43, 192, 195, 102, 43, 201, 103, 138, 11, 128, -225, 15, 102, 131, 249, 0, 15, 133, 4, 0, 102, 43, 201, 195, 102, 83, -102, 82, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102, 75, 102, 131, -249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19, 102, 75, 102, - 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 83, 102, 82, 102, - 43, 210, 103, 138, 19, 102, 131, 226, 15, 102, 43, 201, 103, 138, 11, 192, -233, 4, 102, 131, 249, 0, 15, 133, 8, 0, 102, 43, 201, 102, 90, 102, - 91, 195, 102, 3, 218, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102, - 75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19, -102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 11, -201, 15, 133, 1, 0, 195, 102, 81, 102, 86, 103, 131, 62, 97, 15, 140, - 12, 0, 103, 131, 62, 122, 15, 143, 4, 0, 103, 131, 46, 32, 102, 131, -198, 2, 226, 230, 102, 94, 102, 89, 195, 102, 80, 102, 81, 102, 139, 208, -102, 161, 46, 2, 103, 102, 141, 88, 16, 103, 3, 67, 4, 103, 102, 141, - 64, 16, 102, 139, 218, 232, 158, 250, 102, 11, 192, 15, 132, 5, 0, 102, - 89, 102, 89, 195, 102, 161, 50, 2, 102, 11, 192, 15, 133, 8, 0, 102, - 89, 102, 89, 102, 51, 192, 195, 102, 139, 22, 50, 2, 103, 102, 141, 82, - 16, 103, 102, 139, 66, 8, 102, 64, 102, 139, 30, 78, 2, 102, 247, 227, -102, 51, 210, 102, 247, 54, 90, 2, 102, 80, 102, 88, 102, 11, 192, 15, -132, 48, 0, 102, 72, 102, 80, 232, 28, 254, 114, 238, 232, 241, 253, 102, - 90, 102, 89, 102, 91, 102, 83, 102, 81, 102, 82, 102, 161, 66, 2, 103, -102, 141, 64, 24, 232, 47, 250, 102, 11, 192, 116, 206, 102, 89, 102, 89, -102, 89, 195, 102, 89, 102, 89, 102, 51, 192, 195, 6, 30, 102, 96, 102, -139, 54, 66, 2, 102, 185, 32, 0, 0, 0, 102, 247, 193, 3, 0, 0, - 0, 15, 133, 3, 0, 232, 13, 0, 102, 173, 232, 105, 0, 226, 235, 102, - 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 51, 192, 102, 51, 219, 176, - 13, 180, 14, 187, 7, 0, 205, 16, 176, 10, 180, 14, 187, 7, 0, 205, - 16, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 11, 201, 15, 133, - 9, 0, 232, 208, 255, 102, 97, 144, 31, 7, 195, 102, 51, 192, 102, 51, -219, 173, 180, 14, 187, 7, 0, 205, 16, 226, 240, 232, 183, 255, 102, 97, -144, 31, 7, 195, 96, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205, - 16, 235, 242, 97, 144, 195, 6, 30, 102, 96, 102, 185, 8, 0, 0, 0, -102, 139, 208, 102, 131, 226, 15, 102, 82, 102, 193, 232, 4, 226, 241, 102, -185, 8, 0, 0, 0, 102, 88, 102, 131, 248, 9, 15, 143, 7, 0, 102, -131, 192, 48, 235, 9, 144, 102, 131, 232, 10, 102, 131, 192, 65, 102, 51, -219, 180, 14, 187, 7, 0, 205, 16, 226, 219, 176, 32, 180, 14, 187, 7, - 0, 205, 16, 102, 97, 144, 31, 7, 232, 96, 0, 195, 6, 30, 102, 96, -102, 190, 22, 13, 0, 0, 232, 79, 245, 102, 97, 144, 31, 7, 195, 6, - 30, 102, 96, 102, 190, 38, 13, 0, 0, 232, 60, 245, 102, 97, 144, 31, - 7, 195, 6, 30, 102, 96, 102, 190, 54, 13, 0, 0, 232, 41, 245, 102, - 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 70, 13, 0, 0, 232, - 22, 245, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 86, 13, - 0, 0, 232, 3, 245, 102, 97, 144, 31, 7, 195, 102, 80, 102, 184, 0, - 0, 245, 255, 102, 64, 102, 11, 192, 117, 249, 102, 88, 195, 102, 81, 102, - 80, 102, 184, 5, 0, 0, 0, 30, 7, 102, 139, 249, 232, 71, 252, 102, -139, 193, 102, 91, 102, 83, 102, 15, 183, 14, 12, 2, 102, 186, 14, 2, - 0, 0, 232, 68, 248, 102, 91, 102, 89, 102, 11, 192, 15, 133, 47, 0, -102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, 35, 0, 102, 91, 102, - 95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, 9, 252, 102, 139, 199, -102, 15, 183, 14, 12, 2, 102, 186, 14, 2, 0, 0, 232, 10, 248, 195, -102, 81, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, - 0, 0, 0, 0, 232, 242, 247, 102, 11, 192, 15, 132, 82, 0, 102, 139, -216, 30, 7, 102, 139, 62, 22, 2, 232, 135, 248, 30, 7, 102, 139, 30, - 22, 2, 102, 89, 38, 102, 57, 15, 15, 132, 46, 0, 38, 102, 131, 63, -255, 15, 132, 45, 0, 38, 131, 127, 4, 0, 15, 132, 36, 0, 38, 102, - 15, 183, 71, 4, 3, 216, 139, 195, 37, 0, 128, 116, 215, 140, 192, 5, - 0, 8, 142, 192, 129, 227, 255, 127, 235, 202, 38, 102, 139, 71, 16, 195, -102, 89, 102, 51, 192, 195, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110, -116, 32, 48, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110, -116, 32, 49, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110, -116, 32, 50, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110, -116, 32, 51, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110, -116, 32, 52, 13, 10 + 51, 248, 102, 91, 102, 89, 102, 133, 192, 15, 133, 21, 0, 102, 139, 193, +102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0, 0, 232, 22, 248, 235, + 51, 144, 102, 51, 210, 102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, + 35, 0, 102, 91, 102, 95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, + 53, 253, 102, 139, 199, 102, 15, 183, 14, 16, 2, 102, 186, 18, 2, 0, + 0, 232, 225, 247, 195, 102, 82, 102, 81, 102, 187, 32, 0, 0, 0, 102, +185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 199, 247, 102, 11, +192, 15, 132, 99, 0, 102, 139, 216, 30, 7, 102, 139, 62, 26, 2, 102, + 51, 192, 232, 89, 248, 30, 7, 102, 139, 30, 26, 2, 102, 89, 102, 90, + 38, 102, 57, 15, 15, 133, 12, 0, 38, 102, 57, 87, 8, 15, 132, 49, + 0, 235, 19, 144, 38, 102, 131, 63, 255, 15, 132, 47, 0, 38, 131, 127, + 4, 0, 15, 132, 38, 0, 38, 102, 15, 183, 71, 4, 3, 216, 139, 195, + 37, 0, 128, 116, 203, 140, 192, 5, 0, 8, 142, 192, 129, 227, 255, 127, +235, 190, 38, 102, 139, 71, 16, 195, 102, 89, 102, 90, 102, 51, 192, 195, +102, 80, 102, 81, 102, 139, 199, 102, 193, 232, 4, 6, 89, 3, 200, 81, + 7, 102, 131, 231, 15, 102, 89, 102, 88, 195, 96, 6, 190, 189, 13, 191, + 0, 32, 30, 7, 185, 13, 0, 144, 243, 165, 7, 97, 195, 1, 35, 69, +103, 137, 171, 205, 239, 254, 220, 186, 152, 118, 84, 50, 16, 240, 225, 210, +195, 0, 0, 0, 0, 32, 32, 96, 139, 54, 24, 32, 38, 138, 5, 136, + 4, 71, 70, 102, 255, 6, 20, 32, 129, 254, 96, 32, 117, 6, 232, 91, + 0, 190, 32, 32, 226, 230, 137, 54, 24, 32, 97, 195, 102, 96, 139, 54, + 24, 32, 176, 128, 136, 4, 70, 50, 192, 129, 254, 96, 32, 117, 6, 232, + 58, 0, 190, 32, 32, 129, 254, 88, 32, 117, 233, 102, 51, 192, 102, 163, + 88, 32, 102, 161, 20, 32, 102, 193, 224, 3, 102, 15, 200, 102, 163, 92, + 32, 232, 24, 0, 187, 0, 32, 102, 139, 7, 102, 15, 200, 102, 137, 7, +131, 195, 4, 129, 251, 52, 32, 117, 238, 102, 97, 195, 102, 96, 187, 32, + 32, 102, 139, 7, 102, 15, 200, 102, 137, 7, 131, 195, 4, 129, 251, 96, + 32, 117, 238, 187, 0, 32, 102, 139, 15, 102, 139, 87, 4, 102, 139, 119, + 8, 102, 139, 127, 12, 102, 139, 111, 16, 187, 32, 32, 199, 6, 26, 32, + 48, 15, 198, 6, 28, 32, 20, 144, 83, 139, 30, 26, 32, 255, 23, 102, + 3, 71, 2, 91, 102, 3, 232, 102, 3, 47, 102, 139, 193, 102, 193, 192, + 5, 102, 3, 197, 102, 139, 239, 102, 139, 254, 102, 139, 242, 102, 193, 198, + 30, 102, 139, 209, 102, 139, 200, 102, 139, 7, 102, 51, 71, 8, 102, 51, + 71, 32, 102, 51, 71, 52, 102, 209, 192, 102, 137, 71, 64, 131, 195, 4, +254, 14, 28, 32, 117, 178, 131, 6, 26, 32, 6, 129, 62, 26, 32, 72, + 15, 117, 159, 187, 0, 32, 102, 1, 15, 102, 1, 87, 4, 102, 1, 119, + 8, 102, 1, 127, 12, 102, 1, 111, 16, 102, 97, 195, 102, 139, 198, 102, + 51, 199, 102, 35, 194, 102, 51, 199, 195, 102, 139, 194, 102, 51, 198, 102, + 51, 199, 195, 102, 83, 102, 139, 194, 102, 35, 198, 102, 139, 218, 102, 35, +223, 102, 11, 195, 102, 139, 222, 102, 35, 223, 102, 11, 195, 102, 91, 195, +252, 14, 153, 121, 130, 90, 9, 15, 161, 235, 217, 110, 19, 15, 220, 188, + 27, 143, 9, 15, 214, 193, 98, 202, 6, 30, 102, 96, 102, 51, 219, 184, + 0, 187, 205, 26, 102, 35, 192, 15, 133, 187, 0, 102, 129, 251, 84, 67, + 80, 65, 15, 133, 176, 0, 129, 249, 2, 1, 15, 130, 168, 0, 102, 97, +144, 31, 7, 6, 30, 102, 96, 103, 128, 123, 8, 0, 15, 133, 12, 0, +103, 102, 141, 83, 16, 103, 102, 139, 10, 235, 37, 144, 103, 102, 141, 83, + 16, 103, 102, 139, 74, 40, 102, 129, 249, 0, 0, 8, 0, 15, 131, 12, + 0, 103, 102, 139, 66, 44, 102, 35, 192, 15, 132, 3, 0, 102, 51, 201, + 14, 31, 232, 245, 253, 102, 35, 201, 15, 132, 50, 0, 102, 186, 0, 128, + 0, 0, 102, 59, 202, 15, 134, 31, 0, 102, 43, 202, 6, 102, 81, 102, + 87, 102, 82, 102, 139, 202, 232, 183, 253, 232, 251, 253, 102, 90, 102, 95, +102, 89, 7, 102, 3, 250, 235, 218, 232, 165, 253, 232, 233, 253, 232, 11, +254, 14, 7, 102, 187, 84, 67, 80, 65, 102, 191, 0, 32, 0, 0, 102, +185, 20, 0, 0, 0, 102, 184, 7, 187, 0, 0, 102, 186, 10, 0, 0, + 0, 102, 51, 246, 205, 26, 102, 97, 144, 31, 7, 195, 160, 249, 1, 233, + 64, 241, 160, 250, 1, 233, 58, 241 }; - diff --git a/ntfsprogs/boot.h b/ntfsprogs/boot.h index 74e9ba12..45d79927 100644 --- a/ntfsprogs/boot.h +++ b/ntfsprogs/boot.h @@ -1,7 +1,7 @@ #ifndef _NTFS_BOOT_H_ #define _NTFS_BOOT_H_ -extern const unsigned char boot_array[3429]; +extern const unsigned char boot_array[4136]; #endif /* _NTFS_BOOT_H_ */ From 01dad951c23e84ce6e25f37adf53066b8cf491e2 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 13 Mar 2007 18:39:47 +0000 Subject: [PATCH 179/289] minor cleanups --- ntfsprogs/ntfscp.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 6a01ec2d..b7a96927 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -384,7 +384,7 @@ int main(int argc, char *argv[]) } else out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file); if (!out) { - /* copy the file if the dest_file's parent dir can be opened */ + /* Copy the file if the dest_file's parent dir can be opened. */ char *parent_dirname; char *filename; ntfs_inode *dir_ni; @@ -401,7 +401,7 @@ int main(int argc, char *argv[]) } dirname_last_whack = strrchr(parent_dirname, '/'); if (dirname_last_whack) { - dirname_last_whack[1] = '\0'; + dirname_last_whack[1] = 0; dir_ni = ntfs_pathname_to_inode(vol, NULL, parent_dirname); } else { @@ -412,7 +412,7 @@ int main(int argc, char *argv[]) if (dir_ni) { if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { /* Remove the last '/' for estetic reasons. */ - dirname_last_whack[0] = '\0'; + dirname_last_whack[0] = 0; ntfs_log_error("The file '%s' already exists " "and is not a directory. " "Aborting.\n", parent_dirname); @@ -440,14 +440,12 @@ int main(int argc, char *argv[]) } free(parent_dirname); } - /* the destination file is a path */ + /* The destination is a directory. */ if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { char *filename; char *overwrite_filename; int overwrite_filename_len; - /* inode to the file that is being created */ ntfs_inode *ni; - /* inode to the directory to create the file */ ntfs_inode *dir_ni; int filename_len; int dest_dirname_len; @@ -456,7 +454,7 @@ int main(int argc, char *argv[]) dir_ni = out; filename_len = strlen(filename); dest_dirname_len = strlen(opts.dest_file); - overwrite_filename_len = filename_len+dest_dirname_len+2; + overwrite_filename_len = filename_len+dest_dirname_len + 2; overwrite_filename = malloc(overwrite_filename_len); if (!overwrite_filename) { ntfs_log_perror("ERROR: Failed to allocate %i bytes " @@ -466,8 +464,7 @@ int main(int argc, char *argv[]) goto close_src; } strcpy(overwrite_filename, opts.dest_file); - /* add '/' in the end of dest_dirname if there is not one there */ - if (opts.dest_file[dest_dirname_len-1] != '/') { + if (opts.dest_file[dest_dirname_len - 1] != '/') { strcat(overwrite_filename, "/"); } strcat(overwrite_filename, filename); @@ -480,8 +477,8 @@ int main(int argc, char *argv[]) ntfs_inode_close(out); out = ni; } else { - ntfs_log_verbose("Creating a new file '%s' under '%s'\n", - filename, opts.dest_file); + ntfs_log_verbose("Creating a new file '%s' under " + "'%s'\n", filename, opts.dest_file); ni = ntfs_new_file(dir_ni, filename); ntfs_inode_close(dir_ni); if (!ni) { From 48399b98b36acf3416b586d432040920592d8669 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 13 Mar 2007 18:45:51 +0000 Subject: [PATCH 180/289] cleanup --- libntfs/attrib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 1b9f89e5..6bdf7cd8 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -953,9 +953,9 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) unsigned int update_mapping_pairs : 1; } need_to = { 0, 0, 0 }; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " - "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos, - (long long)count); + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, " + "count 0x%llx.\n", na->ni->mft_no, na->type, + (long long)pos, (long long)count); if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; return -1; From 2c7fd02349004d6ee2d76f7a776c07e514bfa343 Mon Sep 17 00:00:00 2001 From: yura Date: Tue, 13 Mar 2007 18:52:02 +0000 Subject: [PATCH 181/289] ntfsmount: use utimens() instead of deprecated utime(). --- ChangeLog | 1 + ntfsprogs/ntfsmount.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index f527db9b..036efa79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -131,6 +131,7 @@ xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. sensitive and insensitive mounts. (Yura) - ntfsmount: st_block calculation was wrong. (Yuval) - mkntfs: Use Vista $Boot rather than XP one. (Anton) + - ntfsmount: use utimens() instead of deprecated utime(). (Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 8a79a28b..da8346e2 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1120,7 +1120,7 @@ static int ntfs_fuse_rmdir(const char *path) return ntfs_fuse_rm(path); } -static int ntfs_fuse_utime(const char *path, struct utimbuf *buf) +static int ntfs_fuse_utimens(const char *path, const struct timespec ts[2]) { ntfs_inode *ni; @@ -1129,10 +1129,10 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf) ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; - if (buf) { - ni->last_access_time = buf->actime; - ni->last_data_change_time = buf->modtime; - ni->last_mft_change_time = buf->modtime; + if (ts) { + ni->last_access_time = ts[0].tv_sec; + ni->last_data_change_time = ts[1].tv_sec; + ni->last_mft_change_time = ts[1].tv_sec; } else { time_t now; @@ -1468,7 +1468,7 @@ static struct fuse_operations ntfs_fuse_oper = { .rename = ntfs_fuse_rename, .mkdir = ntfs_fuse_mkdir, .rmdir = ntfs_fuse_rmdir, - .utime = ntfs_fuse_utime, + .utimens = ntfs_fuse_utimens, .destroy = ntfs_fuse_destroy, #ifdef HAVE_SETXATTR .getxattr = ntfs_fuse_getxattr, From 62d49cb175bf7a595a0e5f2418b17830b9b2b02b Mon Sep 17 00:00:00 2001 From: aia21 Date: Mon, 19 Mar 2007 14:39:44 +0000 Subject: [PATCH 182/289] Minor updates for OSX compatibility, i.e. glibtoolize not libtoolize, and automake 1.10 fix, etc. --- ChangeLog | 2 +- README | 2 +- autogen.sh | 11 +++++++++++ configure.ac | 1 + ntfsprogs.spec.in | 2 +- ntfsprogs/mkntfs.c | 19 ++----------------- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 036efa79..d52c0ed1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. +xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) diff --git a/README b/README index f3cdfb7d..26968cba 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Linux-NTFS The Linux-NTFS project aims to bring full support for the NTFS filesystem to the Linux operating system. -Linux-NTFS is copyright (c) 2000-2006 Anton Altaparmakov. +Linux-NTFS is copyright (c) 2000-2007 Anton Altaparmakov. All of the contents of the Linux-NTFS project are free software, released under the GNU General Public License and you are welcome to redistribute them under diff --git a/autogen.sh b/autogen.sh index a51d759f..31c11403 100755 --- a/autogen.sh +++ b/autogen.sh @@ -24,6 +24,17 @@ fi exit 1 } +UNAME=`which uname` +if [ $? -eq 0 -a -n ${UNAME} -a -x ${UNAME} ]; then + OS=`${UNAME} -s` + if [ $? -eq 0 -a -n ${OS} -a "${OS}" == "Darwin" ]; then + echo "" + echo "Running on Mac OS X / Darwin. Setting LIBTOOLIZE=glibtoolize..." + echo "" + export LIBTOOLIZE="glibtoolize" + fi +fi + echo Running autoreconf --verbose --install autoreconf --force --verbose --install diff --git a/configure.ac b/configure.ac index 1afef49f..00818b36 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,7 @@ esac # Checks for programs. AC_PROG_CC AC_PROG_GCC_TRADITIONAL +AM_PROG_CC_C_O AC_PROG_INSTALL AC_PATH_PROG(RM, rm, rm) AC_PROG_LN_S diff --git a/ntfsprogs.spec.in b/ntfsprogs.spec.in index f5374642..a4cf18a6 100644 --- a/ntfsprogs.spec.in +++ b/ntfsprogs.spec.in @@ -41,7 +41,7 @@ allows GNOME VFS clients to seamlessly utilize the NTFS library (libntfs). Summary : NTFS FUSE module (ntfsmount) Group : System Environment/Base Requires : ntfsprogs = %{ver}-%{rel} -Requires : fuse >= 2.3.0 +Requires : fuse >= 2.6.1 %description fuse This package contains the ntfsmount utility which is an NTFS filesystem in userspace (FUSE) module allowing users to mount an ntfs filesystem from diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index a654853b..b6c4fe47 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -1,7 +1,7 @@ /** * mkntfs - Part of the Linux-NTFS project. * - * Copyright (c) 2000-2006 Anton Altaparmakov + * Copyright (c) 2000-2007 Anton Altaparmakov * Copyright (c) 2001-2005 Richard Russon * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2005 Erik Sornes @@ -29,21 +29,6 @@ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * WARNING: This program might not work on architectures which do not allow - * unaligned access. For those, the program would need to start using - * get/put_unaligned macros (#include ), but not doing it yet, - * since NTFS really mostly applies to ia32 only, which does allow unaligned - * accesses. We might not actually have a problem though, since the structs are - * defined as being packed so that might be enough for gcc to insert the - * correct code. - * - * If anyone using a non-little endian and/or an aligned access only CPU tries - * this program please let me know whether it works or not! - * - * Anton Altaparmakov - */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -263,7 +248,7 @@ static void mkntfs_version(void) { ntfs_log_info("\n%s v%s (libntfs %s)\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); ntfs_log_info("Create an NTFS volume on a user specified (block) device.\n\n"); - ntfs_log_info("Copyright (c) 2000-2006 Anton Altaparmakov\n"); + ntfs_log_info("Copyright (c) 2000-2007 Anton Altaparmakov\n"); ntfs_log_info("Copyright (c) 2001-2005 Richard Russon\n"); ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); From 52d034e5f3dcb5b73e028c43a854aa8067da3e4a Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:34:16 +0300 Subject: [PATCH 183/289] ntfsmount: fix errno in truncate() operation --- ntfsprogs/ntfsmount.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index da8346e2..a20b818f 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -759,7 +759,10 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) res = -errno; goto exit; } - res = ntfs_attr_truncate(na, size); + if (ntfs_attr_truncate(na, size)) + res = -errno; + else + res = 0; ntfs_fuse_mark_free_space_outdated(); ntfs_attr_close(na); exit: From e6620be16de9d74017d0cc4095a2ca1f034e85ed Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:35:47 +0300 Subject: [PATCH 184/289] Do not create holes in ntfs_attr_pwrite that will be instantiated right after creation * Add new API: __ntfs_attr_truncate that allow user to select whether holes should be created or clusters allocated * Update ntfs_attr_pwrite and ntfscp to use it. --- include/ntfs/attrib.h | 1 + libntfs/attrib.c | 27 +++++++++++++++++++++------ ntfsprogs/ntfscp.c | 6 +++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index a1502c99..2daee4d6 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -315,6 +315,7 @@ extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra); extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn); +extern int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse); extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize); extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 6bdf7cd8..4864db54 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -986,7 +986,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) /* If the write reaches beyond the end, extend the attribute. */ old_data_size = na->data_size; if (pos + count > na->data_size) { - if (ntfs_attr_truncate(na, pos + count)) { + if (__ntfs_attr_truncate(na, pos + count, FALSE)) { eo = errno; ntfs_log_trace("Attribute extend failed.\n"); errno = eo; @@ -4698,6 +4698,7 @@ put_err_out: * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute * @na: non-resident ntfs attribute to expand * @newsize: new size (in bytes) to which to expand the attribute + * @sparse: if TRUE then will create hole if possible * * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, * by allocating new clusters. @@ -4708,7 +4709,8 @@ put_err_out: * ERANGE - @newsize is not valid for the attribute type of @na. * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. */ -static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) +static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, + BOOL sparse) { LCN lcn_seek_from; VCN first_free_vcn; @@ -4758,7 +4760,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) * If we extend $DATA attribute on NTFS 3+ volume, we can add * sparse runs instead of real allocation of clusters. */ - if (na->type == AT_DATA && vol->major_ver >= 3) { + if (na->type == AT_DATA && vol->major_ver >= 3 && sparse) { rl = ntfs_malloc(0x1000); if (!rl) return -1; @@ -4903,10 +4905,12 @@ put_err_out: return -1; } + /** - * ntfs_attr_truncate - resize an ntfs attribute + * __ntfs_attr_truncate - resize an ntfs attribute * @na: open ntfs attribute to resize * @newsize: new size (in bytes) to which to resize the attribute + * @sparse: if TRUE then will create hole if possible * * Change the size of an open ntfs attribute @na to @newsize bytes. If the * attribute is made bigger and the attribute is resident the newly @@ -4926,7 +4930,7 @@ put_err_out: * @newsize bytes length. * EOPNOTSUPP - The desired resize is not implemented yet. */ -int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) +int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse) { int ret; @@ -4959,7 +4963,8 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) } if (NAttrNonResident(na)) { if (newsize > na->data_size) - ret = ntfs_non_resident_attr_expand(na, newsize); + ret = ntfs_non_resident_attr_expand(na, newsize, + sparse); else ret = ntfs_non_resident_attr_shrink(na, newsize); } else @@ -4971,6 +4976,16 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) return ret; } + +/** + * Wrapper around __ntfs_attr_truncate that always tries to creates hole + */ +int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) +{ + return __ntfs_attr_truncate(na, newsize, TRUE); +} + + /** * ntfs_attr_readall - read the entire data from an ntfs attribute * @ni: open ntfs inode in which the ntfs attribute resides diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index b7a96927..72af5a96 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -1,7 +1,7 @@ /** * ntfscp - Part of the Linux-NTFS project. * - * Copyright (c) 2004-2006 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * Copyright (c) 2005 Anton Altaparmakov * Copyright (c) 2006 Hil Liao * @@ -85,7 +85,7 @@ static void version(void) { ntfs_log_info("\n%s v%s (libntfs %s) - Overwrite files on NTFS " "volume.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); - ntfs_log_info("Copyright (c) 2004-2006 Yura Pakhuchiy\n"); + ntfs_log_info("Copyright (c) 2004-2007 Yura Pakhuchiy\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -524,7 +524,7 @@ int main(int argc, char *argv[]) ntfs_log_verbose("Old file size: %lld\n", na->data_size); if (na->data_size != new_size) { - if (ntfs_attr_truncate(na, new_size)) { + if (__ntfs_attr_truncate(na, new_size, FALSE)) { ntfs_log_perror("ERROR: Couldn't resize attribute"); goto close_attr; } From e404ce82039d68dfd6e641b35a0d2aa8c8b5e95d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:36:37 +0300 Subject: [PATCH 185/289] Fix 64bit warnings (Yuval) --- libntfs/dir.c | 3 ++- libntfs/index.c | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 0343db43..a08fa48f 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -287,7 +287,8 @@ descend_into_child_node: if (br != 1) { if (br != -1) errno = EIO; - ntfs_log_perror("Failed to read vcn 0x%llx", vcn); + ntfs_log_perror("Failed to read vcn 0x%llx", + (unsigned long long)vcn); goto close_err_out; } diff --git a/libntfs/index.c b/libntfs/index.c index a977200b..472254db 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -88,7 +88,8 @@ static int ntfs_ib_write(ntfs_index_context *icx, VCN vcn, void *buf) 1, icx->block_size, buf); if (ret != 1) { ntfs_log_perror("Failed to write index block %lld of inode " - "%llu", vcn, icx->ni->mft_no); + "%llu", (long long)vcn, + (unsigned long long)icx->ni->mft_no); return STATUS_ERROR; } return STATUS_OK; @@ -402,7 +403,8 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) if (!ntfs_is_indx_record(ib->magic)) { ntfs_log_error("Corrupt index block signature: vcn %lld inode " - "%llu\n", (long long)vcn, icx->ni->mft_no); + "%llu\n", (long long)vcn, + (unsigned long long)icx->ni->mft_no); return -1; } @@ -410,8 +412,9 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) ntfs_log_error("Corrupt index block: VCN (%lld) is different " "from expected VCN (%lld) in inode %llu\n", - (long long) sle64_to_cpu(ib->index_block_vcn), - (long long)vcn, icx->ni->mft_no); + (long long)sle64_to_cpu(ib->index_block_vcn), + (long long)vcn, + (unsigned long long)icx->ni->mft_no); return -1; } @@ -495,7 +498,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len, (u8 *)ie + le16_to_cpu(ie->length) > index_end) { errno = ERANGE; ntfs_log_error("Index entry out of bounds in inode " - "%llu.\n", icx->ni->mft_no); + "%llu.\n", + (unsigned long long)icx->ni->mft_no); return STATUS_ERROR; } /* @@ -566,7 +570,7 @@ static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open index allocation of inode " - "%llu", ni->mft_no); + "%llu", (unsigned long long)ni->mft_no); return NULL; } return na; @@ -587,7 +591,7 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) ntfs_log_perror("Failed to read index block"); else ntfs_log_error("Failed to read full index block at " - "%lld\n", pos); + "%lld\n", (long long)pos); return -1; } @@ -759,7 +763,8 @@ descend_into_child_node: if ((ib->index.flags & NODE_MASK) == LEAF_NODE) { ntfs_log_error("Index entry with child node found in a leaf " - "node in inode 0x%llx.\n", ni->mft_no); + "node in inode 0x%llx.\n", + (unsigned long long)ni->mft_no); goto err_out; } From b99d331f78d9fa273e02f0c1b2d60337728ab8fc Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:41:10 +0300 Subject: [PATCH 186/289] We do not need to map whole runlist in this case, only until @pos. Introduce ntfs_attr_map_runlist_range to implement this. --- include/ntfs/attrib.h | 1 + libntfs/attrib.c | 94 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index 2daee4d6..5cbf8a0c 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -279,6 +279,7 @@ extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, const u32 bk_size, void *src); extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn); +extern int ntfs_attr_map_runlist_range(ntfs_attr *na, VCN from_vcn, VCN to_vcn); extern int ntfs_attr_map_whole_runlist(ntfs_attr *na); extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 4864db54..3a245b3e 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -459,7 +459,7 @@ void ntfs_attr_close(ntfs_attr *na) * @na: ntfs attribute for which to map (part of) a runlist * @vcn: map runlist part containing this vcn * - * Map the part of a runlist containing the @vcn of an the ntfs attribute @na. + * Map the part of a runlist containing the @vcn of the ntfs attribute @na. * * Return 0 on success and -1 on error with errno set to the error code. */ @@ -467,7 +467,6 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) { LCN lcn; ntfs_attr_search_ctx *ctx; - int err; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, (long long)vcn); @@ -490,14 +489,84 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) na->rl); if (rl) { na->rl = rl; - ntfs_attr_put_search_ctx(ctx); return 0; } } - err = errno; ntfs_attr_put_search_ctx(ctx); - errno = err; + return -1; +} + +/** + * ntfs_attr_map_runlist_range - map (a part of) a runlist of an ntfs attribute + * @na: ntfs attribute for which to map (part of) a runlist + * @from_vcn: map runlist part starting this vcn + * @to_vcn: map runlist part ending this vcn + * + * Map the part of a runlist from containing the @from_vcn to containing the + * @to_vcn of an ntfs attribute @na. It is OK for @to_vcn to be beyond last run. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_attr_map_runlist_range(ntfs_attr *na, VCN from_vcn, VCN to_vcn) +{ + ntfs_attr_search_ctx *ctx = NULL; + runlist *rl; + + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, " + "from_vcn 0x%llx, to_vcn 0x%llx.\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)from_vcn, (long long)to_vcn); + + /* Map extent with @from_vcn. */ + if (ntfs_attr_map_runlist(na, from_vcn)) + goto err_out; + + for (rl = na->rl; rl->vcn <= to_vcn;) { + /* Skip not interesting to us runs. */ + if (rl->lcn >= 0 || rl->lcn == LCN_HOLE || (rl->vcn + + rl->length < from_vcn && + rl->lcn == LCN_RL_NOT_MAPPED)) { + rl++; + continue; + } + + /* We reached the end of runlist, just exit. */ + if (rl->lcn == LCN_ENOENT) + break; + + /* Check for errors. */ + if (rl->lcn < 0 && rl->lcn != LCN_RL_NOT_MAPPED) { + errno = EIO; + goto err_out; + } + + /* Runlist is not mapped here. */ + if (!ctx) { + ctx = ntfs_attr_get_search_ctx(na->ni, NULL); + if (!ctx) + goto err_out; + } + /* Find the attribute in the mft record. */ + if (ntfs_attr_lookup(na->type, na->name, na->name_len, + CASE_SENSITIVE, rl->vcn, NULL, 0, + ctx)) + goto err_out; + + /* Decode the runlist. */ + rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr, + na->rl); + if (!rl) + goto err_out; + na->rl = rl; + } + + ntfs_attr_put_search_ctx(ctx); + ntfs_log_trace("Done.\n"); + return 0; +err_out: + ntfs_attr_put_search_ctx(ctx); + ntfs_log_trace("Failed.\n"); return -1; } @@ -505,8 +574,8 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute * @na: ntfs attribute for which to map the runlist * - * Map the whole runlist of an the ntfs attribute @na. For an attribute made - * up of only one attribute extent this is the same as calling + * Map the whole runlist of the ntfs attribute @na. For an attribute made up + * of only one attribute extent this is the same as calling * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this * will map the runlist fragments from each of the extents thus giving access * to the entirety of the disk allocation of an attribute. @@ -1030,7 +1099,13 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) total = 0; /* Handle writes beyond initialized_size. */ if (pos + count > na->initialized_size) { - if (ntfs_attr_map_whole_runlist(na)) + /* + * Map runlist between initialized size and place we start + * writing at. + */ + if (ntfs_attr_map_runlist_range(na, na->initialized_size >> + vol->cluster_size_bits, + pos >> vol->cluster_size_bits)) goto err_out; /* Set initialized_size to @pos + @count. */ ctx = ntfs_attr_get_search_ctx(na->ni, NULL); @@ -2301,7 +2376,8 @@ ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) * ntfs_attr_put_search_ctx - release an attribute search context * @ctx: attribute search context to free * - * Release the attribute search context @ctx. + * Release the attribute search context @ctx. This function does not change + * errno and doing nothing if NULL passed to it. */ void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) { From 48c336fd6aece5d56e246eeb49f734a1b17546cd Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:45:28 +0300 Subject: [PATCH 187/289] O(1) mapping pairs update for normal files --- libntfs/attrib.c | 133 ++++++++++++++++++++++++++++++++++++---------- libntfs/runlist.c | 15 ++++-- 2 files changed, 117 insertions(+), 31 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 3a245b3e..41e40b8c 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1392,7 +1392,7 @@ done: ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ if (need_to.update_mapping_pairs) - ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); + ntfs_attr_update_mapping_pairs(na, update_from); /* Finally, return the number of bytes written. */ return total; rl_err_out: @@ -1450,7 +1450,7 @@ err_out: ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ if (need_to.update_mapping_pairs) - ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); + ntfs_attr_update_mapping_pairs(na, update_from); /* Restore original data_size if needed. */ if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) ntfs_log_trace("Failed to restore data_size.\n"); @@ -4186,11 +4186,18 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) * call to this function. Vice-versa @na->compressed_size will be calculated and * set to correct value during this function. * - * FIXME: This function does not update sparse bit and compressed size correctly - * if called with @from_vcn != 0. + * New runlist should be fully formed starting @from_vcn. Runs before @from_vcn + * can be mapped or not, but on-disk structures should not be modified before + * call to this function so they can be mapped if necessary. + * + * FIXME: Make it O(1) for sparse files too, not only for normal. * * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define. * + * NOTE: Be careful in the future with updating bits on compressed files (at + * present assumed that on-disk flag is already set/cleared before call to + * this function). + * * On success return 0 and on error return -1 with errno set to the error code. * The following error codes are defined: * EINVAL - Invalid arguments passed. @@ -4209,7 +4216,7 @@ int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn) BOOL finished_build; retry: - if (!na || !na->rl || from_vcn) { + if (!na || !na->rl) { ntfs_log_trace("Invalid parameters passed.\n"); errno = EINVAL; return -1; @@ -4221,8 +4228,9 @@ retry: return -1; } - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long - long)na->ni->mft_no, na->type); + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, from vcn 0x%lld." + "\n", (unsigned long long)na->ni->mft_no, na->type, + from_vcn); if (na->ni->nr_extents == -1) base_ni = na->ni->base_ni; @@ -4239,7 +4247,8 @@ retry: stop_vcn = 0; finished_build = FALSE; while (!ntfs_attr_lookup(na->type, na->name, na->name_len, - CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) { + CASE_SENSITIVE, ctx->is_first ? 0 : from_vcn, + NULL, 0, ctx)) { a = ctx->attr; m = ctx->mrec; /* @@ -4248,7 +4257,7 @@ retry: * contain @from_vcn. Also we do not need @from_vcn anymore, * set it to 0 to make ntfs_attr_lookup enumerate attributes. */ - if (from_vcn) { + if (from_vcn && a->lowest_vcn) { LCN first_lcn; stop_vcn = sle64_to_cpu(a->lowest_vcn); @@ -4256,7 +4265,7 @@ retry: /* * Check whether the first run we need to update is * the last run in runlist, if so, then deallocate - * all attrubute extents starting this one. + * all attribute extents starting this one. */ first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn); if (first_lcn == LCN_EINVAL) { @@ -4307,14 +4316,43 @@ retry: /* Update allocated size. */ a->allocated_size = cpu_to_sle64(na->allocated_size); - /* Update sparse bit. */ + /* + * Check whether part of runlist we are updating is + * sparse. + */ sparse = ntfs_rl_sparse(na->rl); if (sparse == -1) { ntfs_log_trace("Bad runlist.\n"); - err = EIO; + err = errno; goto put_err_out; } - /* Attribute become sparse. */ + /* + * If new part or on-disk attribute is not sparse, then + * we should fully map runlist to make final decision. + */ + if (sparse || (a->flags & ATTR_IS_SPARSE)) { + if (from_vcn && ntfs_attr_map_runlist_range(na, + 0, from_vcn - 1)) { + ntfs_log_trace("Failed to map runlist " + "before @from_vcn.\n"); + err = errno; + goto put_err_out; + } + /* + * Reconsider whether whole runlist is sparse + * if new part is not. + */ + if (!sparse) { + sparse = ntfs_rl_sparse(na->rl); + if (sparse == -1) { + ntfs_log_trace("Bad " + "runlist.\n"); + err = errno; + goto put_err_out; + } + } + } + /* Attribute becomes sparse/compressed. */ if (sparse && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { /* @@ -4369,8 +4407,13 @@ retry: a->mapping_pairs_offset = cpu_to_le16(le16_to_cpu( a->mapping_pairs_offset) + 8); + /* + * We should update all mapping pairs, because + * we shifted their starting position. + */ + from_vcn = 0; } - /* Attribute no longer sparse. */ + /* Attribute becomes normal. */ if (!sparse && (a->flags & ATTR_IS_SPARSE) && !(a->flags & ATTR_IS_COMPRESSED)) { NAttrClearSparse(na); @@ -4384,9 +4427,14 @@ retry: a->mapping_pairs_offset = cpu_to_le16(le16_to_cpu( a->mapping_pairs_offset) - 8); + /* + * We should update all mapping pairs, because + * we shifted their starting position. + */ + from_vcn = 0; } /* Update compressed size if required. */ - if (sparse) { + if (sparse || (a->flags & ATTR_IS_COMPRESSED)) { s64 new_compr_size; new_compr_size = ntfs_rl_get_compressed_size( @@ -4415,7 +4463,21 @@ retry: na->allocated_size; NInoFileNameSetDirty(na->ni); } + + /* + * We do want to do anything for the first extent in + * case we are updating mapping pairs not from the + * begging. + */ + if (!a->highest_vcn || from_vcn <= + sle64_to_cpu(a->highest_vcn) + 1) + from_vcn = 0; + else { + if (from_vcn) + continue; + } } + /* Get the size for the rest of mapping pairs array. */ mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl, stop_vcn); @@ -4531,6 +4593,13 @@ retry: ntfs_log_trace("Attribute lookup failed.\n"); goto put_err_out; } + /* Sanity check. */ + if (from_vcn) { + err = ENOMSG; + ntfs_log_error("Library BUG! @from_vcn is nonzero, please " + "report to %s.\n", NTFS_DEV_LIST); + goto put_err_out; + } /* Deallocate not used attribute extents and return with success. */ if (finished_build) { @@ -4557,6 +4626,7 @@ retry: } ntfs_log_trace("Deallocate done.\n"); ntfs_attr_put_search_ctx(ctx); + ntfs_log_trace("Done!"); return 0; } ntfs_attr_put_search_ctx(ctx); @@ -4625,6 +4695,7 @@ retry: if (!err) break; } + ntfs_log_trace("Done!\n"); return 0; put_err_out: if (ctx) @@ -4712,7 +4783,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) /* Prepare to mapping pairs update. */ na->allocated_size = first_free_vcn << vol->cluster_size_bits; /* Write mapping pairs for new runlist. */ - if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { + if (ntfs_attr_update_mapping_pairs(na, first_free_vcn)) { ntfs_log_trace("Eeek! Mapping pairs update failed. " "Leaving inconsistent metadata. " "Run chkdsk.\n"); @@ -4788,7 +4859,6 @@ put_err_out: static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, BOOL sparse) { - LCN lcn_seek_from; VCN first_free_vcn; ntfs_volume *vol; ntfs_attr_search_ctx *ctx; @@ -4826,9 +4896,10 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, * clusters if there is a change. */ if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) { - if (ntfs_attr_map_whole_runlist(na)) { - ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " - "failed.\n"); + /* Map required part of runlist. */ + if (ntfs_attr_map_runlist(na, na->allocated_size >> + vol->cluster_size_bits)) { + ntfs_log_error("Failed to map runlist.\n"); return -1; } @@ -4857,6 +4928,8 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, * attribute let the cluster allocator choose the * starting LCN. */ + LCN lcn_seek_from; + lcn_seek_from = -1; if (na->rl->length) { /* Seek to the last run list element. */ @@ -4891,7 +4964,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, if (!rln) { /* Failed, free just allocated clusters. */ err = errno; - ntfs_log_trace("Eeek! Run list merge failed.\n"); + ntfs_log_trace("Run list merge failed.\n"); ntfs_cluster_free_from_rl(vol, rl); free(rl); errno = err; @@ -4902,10 +4975,10 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, /* Prepare to mapping pairs update. */ na->allocated_size = first_free_vcn << vol->cluster_size_bits; /* Write mapping pairs for new runlist. */ - if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> - vol->cluster_size_bits*/)) { + if (ntfs_attr_update_mapping_pairs(na, org_alloc_size >> + vol->cluster_size_bits)) { err = errno; - ntfs_log_trace("Eeek! Mapping pairs update failed.\n"); + ntfs_log_trace("Mapping pairs update failed.\n"); goto rollback; } } @@ -4965,10 +5038,10 @@ rollback: ntfs_log_trace("Couldn't truncate runlist. Rollback failed.\n"); } else { /* Prepare to mapping pairs update. */ - na->allocated_size = org_alloc_size << vol->cluster_size_bits; + na->allocated_size = org_alloc_size; /* Restore mapping pairs. */ - if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> - vol->cluster_size_bits*/)) { + if (ntfs_attr_update_mapping_pairs(na, na->allocated_size >> + vol->cluster_size_bits)) { ntfs_log_trace("Failed to restore old mapping pairs. " "Rollback failed.\n"); } @@ -5028,6 +5101,7 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse) */ if (NAttrEncrypted(na)) { errno = EACCES; + ntfs_log_trace("Failed (encrypted).\n"); return -1; } /* @@ -5035,6 +5109,7 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse) */ if (NAttrCompressed(na)) { errno = EOPNOTSUPP; + ntfs_log_trace("Failed (compressed).\n"); return -1; } if (NAttrNonResident(na)) { @@ -5049,6 +5124,10 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse) if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || na->type == AT_INDEX_ALLOCATION) ntfs_inode_update_time(na->ni); + if (!ret) + ntfs_log_trace("Done!\n"); + else + ntfs_log_trace("Failed.\n"); return ret; } diff --git a/libntfs/runlist.c b/libntfs/runlist.c index 709ae1bd..b729804c 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -436,7 +436,7 @@ static runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { if (!dst || !src) { - ntfs_log_debug("Eeek. ntfs_rl_split() invoked with NULL pointer!\n"); + ntfs_log_trace("Invoked with NULL pointer!\n"); errno = EINVAL; return NULL; } @@ -1630,6 +1630,10 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) * ntfs_rl_sparse - check whether runlist have sparse regions or not. * @rl: runlist to check * + * This function just skips not mapped regions assuming they are not sparse, + * so you need to ensure that runlist is fully mapped if you want perform full + * check. + * * Return 1 if have, 0 if not, -1 on error with errno set to the error code. */ int ntfs_rl_sparse(runlist *rl) @@ -1642,15 +1646,18 @@ int ntfs_rl_sparse(runlist *rl) return -1; } - for (rlc = rl; rlc->length; rlc++) + for (rlc = rl; rlc->length; rlc++) { if (rlc->lcn < 0) { + if (rlc->lcn == LCN_RL_NOT_MAPPED) + continue; if (rlc->lcn != LCN_HOLE) { - ntfs_log_trace("Received unmapped runlist.\n"); - errno = EINVAL; + ntfs_log_trace("Bad runlist.\n"); + errno = EIO; return -1; } return 1; } + } return 0; } From def36146b7d9452de92698234236e97cbed26185 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:46:10 +0300 Subject: [PATCH 188/289] Sparse 0.3 do not longer requires this workaround! --- include/ntfs/types.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index 0e214128..ea156b27 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -35,10 +35,6 @@ #include #endif -#ifdef __CHECKER__ -typedef int __attribute__((__mode__(__DI__))) int64_t; -#endif - typedef uint8_t u8; /* Unsigned types of an exact size */ typedef uint16_t u16; typedef uint32_t u32; From 0d264b7d2598da501aa80626d8f01f142b68f780 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:47:57 +0300 Subject: [PATCH 189/289] Introduce sparse endian annotations. Adopt library (also fix 2 real bugs) and progs (lots of bugs). --- include/ntfs/attrib.h | 40 ++-- include/ntfs/endians.h | 143 ++++++++----- include/ntfs/inode.h | 4 +- include/ntfs/layout.h | 448 ++++++++++++++++++++------------------- include/ntfs/logfile.h | 4 +- include/ntfs/ntfstime.h | 8 +- include/ntfs/types.h | 9 +- include/ntfs/volume.h | 6 +- libntfs/attrib.c | 26 +-- libntfs/attrlist.c | 12 +- libntfs/dir.c | 2 +- libntfs/index.c | 14 +- libntfs/inode.c | 11 +- libntfs/mft.c | 23 +- libntfs/mst.c | 13 +- libntfs/runlist.c | 2 +- libntfs/unistr.c | 9 +- libntfs/volume.c | 18 +- ntfsprogs/mkntfs.c | 328 +++++++++++++++------------- ntfsprogs/ntfscat.c | 37 ++-- ntfsprogs/ntfsclone.c | 42 ++-- ntfsprogs/ntfscmp.c | 55 +++-- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsfix.c | 26 +-- ntfsprogs/ntfsinfo.c | 66 +++--- ntfsprogs/ntfsresize.c | 26 +-- ntfsprogs/ntfsundelete.c | 112 ++++++---- ntfsprogs/ntfsundelete.h | 3 +- ntfsprogs/sd.c | 1 - ntfsprogs/utils.c | 17 +- 30 files changed, 835 insertions(+), 672 deletions(-) diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index 5cbf8a0c..99665f31 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -2,7 +2,7 @@ * attrib.h - Exports for attribute handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -203,25 +203,25 @@ typedef enum { #define NAttrSetNonResident(na) set_nattr_flag(na, NonResident) #define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident) -#define GenNAttrIno(func_name,flag) \ -static inline int NAttr##func_name(ntfs_attr *na) \ -{ \ - if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - return (na->ni->flags & FILE_ATTR_##flag); \ - return 0; \ -} \ -static inline void NAttrSet##func_name(ntfs_attr *na) \ -{ \ - if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - na->ni->flags |= FILE_ATTR_##flag; \ - else \ - ntfs_log_trace("BUG! Should be called only for "\ - "unnamed data attribute.\n"); \ -} \ -static inline void NAttrClear##func_name(ntfs_attr *na) \ -{ \ - if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - na->ni->flags &= ~FILE_ATTR_##flag; \ +#define GenNAttrIno(func_name,flag) \ +static inline int NAttr##func_name(ntfs_attr *na) \ +{ \ + if (na->type == AT_DATA && na->name == AT_UNNAMED) \ + return (na->ni->flags & FILE_ATTR_##flag) ? 1 : 0; \ + return 0; \ +} \ +static inline void NAttrSet##func_name(ntfs_attr *na) \ +{ \ + if (na->type == AT_DATA && na->name == AT_UNNAMED) \ + na->ni->flags |= FILE_ATTR_##flag; \ + else \ + ntfs_log_trace("BUG! Should be called only for " \ + "unnamed data attribute.\n"); \ +} \ +static inline void NAttrClear##func_name(ntfs_attr *na) \ +{ \ + if (na->type == AT_DATA && na->name == AT_UNNAMED) \ + na->ni->flags &= ~FILE_ATTR_##flag; \ } GenNAttrIno(Compressed, COMPRESSED) diff --git a/include/ntfs/endians.h b/include/ntfs/endians.h index ec73c442..0b3dd762 100644 --- a/include/ntfs/endians.h +++ b/include/ntfs/endians.h @@ -3,6 +3,7 @@ * Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -110,39 +111,42 @@ #if defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) -#define __le16_to_cpu(x) (x) -#define __le32_to_cpu(x) (x) -#define __le64_to_cpu(x) (x) +#define __le16_to_cpu(x) ((__force u16)(x)) +#define __le32_to_cpu(x) ((__force u32)(x)) +#define __le64_to_cpu(x) ((__force u64)(x)) -#define __cpu_to_le16(x) (x) -#define __cpu_to_le32(x) (x) -#define __cpu_to_le64(x) (x) +#define __cpu_to_le16(x) ((__force le16)(x)) +#define __cpu_to_le32(x) ((__force le32)(x)) +#define __cpu_to_le64(x) ((__force le64)(x)) -#define __constant_le16_to_cpu(x) (x) -#define __constant_le32_to_cpu(x) (x) -#define __constant_le64_to_cpu(x) (x) +#define __constant_le16_to_cpu(x) ((__force u16)(x)) +#define __constant_le32_to_cpu(x) ((__force u32)(x)) +#define __constant_le64_to_cpu(x) ((__force u64)(x)) -#define __constant_cpu_to_le16(x) (x) -#define __constant_cpu_to_le32(x) (x) -#define __constant_cpu_to_le64(x) (x) +#define __constant_cpu_to_le16(x) ((__force le16)(x)) +#define __constant_cpu_to_le32(x) ((__force le32)(x)) +#define __constant_cpu_to_le64(x) ((__force le64)(x)) #elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) -#define __le16_to_cpu(x) bswap_16(x) -#define __le32_to_cpu(x) bswap_32(x) -#define __le64_to_cpu(x) bswap_64(x) +#define __le16_to_cpu(x) bswap_16((__force u16)(x)) +#define __le32_to_cpu(x) bswap_32((__force u16)(x)) +#define __le64_to_cpu(x) bswap_64((__force u16)(x)) -#define __cpu_to_le16(x) bswap_16(x) -#define __cpu_to_le32(x) bswap_32(x) -#define __cpu_to_le64(x) bswap_64(x) +#define __cpu_to_le16(x) (__force le16)bswap_16((__force u16)(x)) +#define __cpu_to_le32(x) (__force le32)bswap_32((__force u32)(x)) +#define __cpu_to_le64(x) (__force le64)bswap_64((__force u64)(x)) -#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x)) -#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x)) -#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x)) +#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((__force u16)(x)) +#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((__force u32)(x)) +#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((__force u64)(x)) -#define __constant_cpu_to_le16(x) __ntfs_bswap_constant_16((u16)(x)) -#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x)) -#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((u64)(x)) +#define __constant_cpu_to_le16(x) \ + (__force le16)__ntfs_bswap_constant_16((__force u16)(x)) +#define __constant_cpu_to_le32(x) \ + (__force le32)__ntfs_bswap_constant_32((__force u32)(x)) +#define __constant_cpu_to_le64(x) \ + (__force le64)__ntfs_bswap_constant_64((__force u64)(x)) #else @@ -152,52 +156,83 @@ /* Unsigned from LE to CPU conversion. */ -#define le16_to_cpu(x) (u16)__le16_to_cpu((u16)(x)) -#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x)) -#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x)) +#define le16_to_cpu(x) (u16)__le16_to_cpu((le16)(x)) +#define le32_to_cpu(x) (u32)__le32_to_cpu((le32)(x)) +#define le64_to_cpu(x) (u64)__le64_to_cpu((le64)(x)) -#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x)) -#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x)) -#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x)) +#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const le16*)(x)) +#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const le32*)(x)) +#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const le64*)(x)) /* Signed from LE to CPU conversion. */ -#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x)) -#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x)) -#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x)) +#define sle16_to_cpu(x) (s16)__le16_to_cpu((sle16)(x)) +#define sle32_to_cpu(x) (s32)__le32_to_cpu((sle32)(x)) +#define sle64_to_cpu(x) (s64)__le64_to_cpu((sle64)(x)) -#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x)) -#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x)) -#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x)) +#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(const sle16*)(x)) +#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(const sle32*)(x)) +#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(const sle64*)(x)) /* Unsigned from CPU to LE conversion. */ -#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x)) -#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x)) -#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x)) +#define cpu_to_le16(x) (le16)__cpu_to_le16((u16)(x)) +#define cpu_to_le32(x) (le32)__cpu_to_le32((u32)(x)) +#define cpu_to_le64(x) (le64)__cpu_to_le64((u64)(x)) -#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x)) -#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x)) -#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x)) +#define cpu_to_le16p(x) (le16)__cpu_to_le16(*(const u16*)(x)) +#define cpu_to_le32p(x) (le32)__cpu_to_le32(*(const u32*)(x)) +#define cpu_to_le64p(x) (le64)__cpu_to_le64(*(const u64*)(x)) /* Signed from CPU to LE conversion. */ -#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x)) -#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x)) -#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x)) +#define cpu_to_sle16(x) (__force sle16)__cpu_to_le16((s16)(x)) +#define cpu_to_sle32(x) (__force sle32)__cpu_to_le32((s32)(x)) +#define cpu_to_sle64(x) (__force sle64)__cpu_to_le64((s64)(x)) -#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x)) -#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x)) -#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x)) +#define cpu_to_sle16p(x) (__force sle16)__cpu_to_le16(*(const s16*)(x)) +#define cpu_to_sle32p(x) (__force sle32)__cpu_to_le32(*(const s32*)(x)) +#define cpu_to_sle64p(x) (__force sle64)__cpu_to_le64(*(const s64*)(x)) /* Constant endianness conversion defines. */ -#define const_le16_to_cpu(x) __constant_le16_to_cpu(x) -#define const_le32_to_cpu(x) __constant_le32_to_cpu(x) -#define const_le64_to_cpu(x) __constant_le64_to_cpu(x) +#define const_le16_to_cpu(x) (u16)__constant_le16_to_cpu((le16)(x)) +#define const_le32_to_cpu(x) (u32)__constant_le32_to_cpu((le32)(x)) +#define const_le64_to_cpu(x) (u64)__constant_le64_to_cpu((le64)(x)) -#define const_cpu_to_le16(x) __constant_cpu_to_le16(x) -#define const_cpu_to_le32(x) __constant_cpu_to_le32(x) -#define const_cpu_to_le64(x) __constant_cpu_to_le64(x) +#define const_cpu_to_le16(x) (le16)__constant_cpu_to_le16((u16)(x)) +#define const_cpu_to_le32(x) (le32)__constant_cpu_to_le32((u32)(x)) +#define const_cpu_to_le64(x) (le64)__constant_cpu_to_le64((u64)(x)) + +#ifdef __CHECKER__ +static void ntfs_endian_self_test(void) +{ + /* Should not generate warnings. */ + (le16)cpu_to_le16((u16)0); + (le32)cpu_to_le32((u32)0); + (le64)cpu_to_le64((u64)0); + (sle16)cpu_to_sle16((s16)0); + (sle32)cpu_to_sle32((s32)0); + (sle64)cpu_to_sle64((s64)0); + (u16)le16_to_cpu((__force le16)0); + (u32)le32_to_cpu((__force le32)0); + (u64)le64_to_cpu((__force le64)0); + (s16)sle16_to_cpu((__force sle16)0); + (s32)sle32_to_cpu((__force sle32)0); + (s64)sle64_to_cpu((__force sle64)0); + (le16)const_cpu_to_le16((u16)0); + (le32)const_cpu_to_le32((u32)0); + (le64)const_cpu_to_le64((u64)0); + (u16)const_le16_to_cpu((__force le16)0); + (u32)const_le32_to_cpu((__force le32)0); + (u64)const_le64_to_cpu((__force le64)0); + + /* + * TODO: Need some how to test that warnings are actually generated, + * but without flooding output with them and vice-versa print warning + * in case if some one warning is not triggered, but should. Any ideas? + */ +} +#endif #endif /* defined _NTFS_ENDIANS_H */ diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index a7b431e3..1da51a0d 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -2,7 +2,7 @@ * inode.h - Defines for NTFS inode handling. Part of the Linux-NTFS project. * * Copyright (c) 2001,2002 Anton Altaparmakov - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -155,7 +155,7 @@ extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref); extern int ntfs_inode_close(ntfs_inode *ni); extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, - const MFT_REF mref); + const leMFT_REF mref); extern int ntfs_inode_attach_all_extents(ntfs_inode *ni); diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index 85cf8461..eb1c43ec 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -2,7 +2,7 @@ * layout.h - Ntfs on-disk layout structures. Part of the Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov - * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -31,34 +31,34 @@ #define NTFS_SB_MAGIC const_cpu_to_le64(0x202020205346544eULL) /* - * Location of bootsector on partition: + * Location of boot sector on partition: * The standard NTFS_BOOT_SECTOR is on sector 0 of the partition. * On NT4 and above there is one backup copy of the boot sector to * be found on the last sector of the partition (not normally accessible - * from within Windows as the bootsector contained number of sectors + * from within Windows as the boot sector contained number of sectors * value is one less than the actual value!). * On versions of NT 3.51 and earlier, the backup copy was located at * number of sectors/2 (integer divide), i.e. in the middle of the volume. */ /** - * struct BIOS_PARAMETER_BLOCK - BIOS parameter block (bpb) structure. + * struct BIOS_PARAMETER_BLOCK - BIOS parameter block (BPB) structure. */ typedef struct { - u16 bytes_per_sector; /* Size of a sector in bytes. */ + le16 bytes_per_sector; /* Size of a sector in bytes. */ u8 sectors_per_cluster; /* Size of a cluster in sectors. */ - u16 reserved_sectors; /* zero */ + le16 reserved_sectors; /* zero */ u8 fats; /* zero */ - u16 root_entries; /* zero */ - u16 sectors; /* zero */ + le16 root_entries; /* zero */ + le16 sectors; /* zero */ u8 media_type; /* 0xf8 = hard disk */ - u16 sectors_per_fat; /* zero */ -/*0x0d*/u16 sectors_per_track; /* Required to boot Windows. */ -/*0x0f*/u16 heads; /* Required to boot Windows. */ -/*0x11*/u32 hidden_sectors; /* Offset to the start of the partition + le16 sectors_per_fat; /* zero */ +/*0x0d*/le16 sectors_per_track; /* Required to boot Windows. */ +/*0x0f*/le16 heads; /* Required to boot Windows. */ +/*0x11*/le32 hidden_sectors; /* Offset to the start of the partition relative to the disk in sectors. Required to boot Windows. */ -/*0x15*/u32 large_sectors; /* zero */ +/*0x15*/le32 large_sectors; /* zero */ /* sizeof() = 25 (0x19) bytes */ } __attribute__((__packed__)) BIOS_PARAMETER_BLOCK; @@ -67,27 +67,27 @@ typedef struct { */ typedef struct { u8 jump[3]; /* Irrelevant (jump to boot up code).*/ - u64 oem_id; /* Magic "NTFS ". */ + le64 oem_id; /* Magic "NTFS ". */ /*0x0b*/BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */ u8 physical_drive; /* 0x00 floppy, 0x80 hard disk */ u8 current_head; /* zero */ u8 extended_boot_signature; /* 0x80 */ u8 reserved2; /* zero */ -/*0x28*/s64 number_of_sectors; /* Number of sectors in volume. Gives +/*0x28*/sle64 number_of_sectors; /* Number of sectors in volume. Gives maximum volume size of 2^63 sectors. Assuming standard sector size of 512 bytes, the maximum byte size is approx. 4.7x10^21 bytes. (-; */ - s64 mft_lcn; /* Cluster location of mft data. */ - s64 mftmirr_lcn; /* Cluster location of copy of mft. */ + sle64 mft_lcn; /* Cluster location of mft data. */ + sle64 mftmirr_lcn; /* Cluster location of copy of mft. */ s8 clusters_per_mft_record; /* Mft record size in clusters. */ u8 reserved0[3]; /* zero */ s8 clusters_per_index_record; /* Index block size in clusters. */ u8 reserved1[3]; /* zero */ - u64 volume_serial_number; /* Irrelevant (serial number). */ - u32 checksum; /* Boot sector checksum. */ + le64 volume_serial_number; /* Irrelevant (serial number). */ + le32 checksum; /* Boot sector checksum. */ /*0x54*/u8 bootstrap[426]; /* Irrelevant (boot up code). */ - u16 end_of_sector_marker; /* End of bootsector magic. Always is + le16 end_of_sector_marker; /* End of boot sector magic. Always is 0xaa55 in little endian. */ /* sizeof() = 512 (0x200) bytes */ } __attribute__((__packed__)) NTFS_BOOT_SECTOR; @@ -129,8 +129,18 @@ typedef enum { * Generic magic comparison macros. Finally found a use for the ## preprocessor * operator! (-8 */ -#define ntfs_is_magic(x, m) ( (u32)(x) == (u32)magic_##m ) -#define ntfs_is_magicp(p, m) ( *(u32*)(p) == (u32)magic_##m ) + +static inline BOOL __ntfs_is_magic(le32 x, NTFS_RECORD_TYPES r) +{ + return (x == (__force le32)r); +} +#define ntfs_is_magic(x, m) __ntfs_is_magic(x, magic_##m) + +static inline BOOL __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPES r) +{ + return (*p == (__force le32)r); +} +#define ntfs_is_magicp(p, m) __ntfs_is_magicp(p, magic_##m) /* * Specialised magic comparison macros for the NTFS_RECORD_TYPES defined above. @@ -165,28 +175,28 @@ typedef enum { /** * struct NTFS_RECORD - * - * The Update Sequence Array (usa) is an array of the u16 values which belong + * The Update Sequence Array (USA) is an array of the le16 values which belong * to the end of each sector protected by the update sequence record in which * this array is contained. Note that the first entry is the Update Sequence - * Number (usn), a cyclic counter of how many times the protected record has + * Number (USN), a cyclic counter of how many times the protected record has * been written to disk. The values 0 and -1 (ie. 0xffff) are not used. All - * last u16's of each sector have to be equal to the usn (during reading) or + * last le16's of each sector have to be equal to the USN (during reading) or * are set to it (during writing). If they are not, an incomplete multi sector * transfer has occurred when the data was written. * The maximum size for the update sequence array is fixed to: * maximum size = usa_ofs + (usa_count * 2) = 510 bytes - * The 510 bytes comes from the fact that the last u16 in the array has to - * (obviously) finish before the last u16 of the first 512-byte sector. + * The 510 bytes comes from the fact that the last le16 in the array has to + * (obviously) finish before the last le16 of the first 512-byte sector. * This formula can be used as a consistency check in that usa_ofs + * (usa_count * 2) has to be less than or equal to 510. */ typedef struct { NTFS_RECORD_TYPES magic;/* A four-byte magic identifying the record type and/or status. */ - u16 usa_ofs; /* Offset to the Update Sequence Array (usa) + le16 usa_ofs; /* Offset to the Update Sequence Array (USA) from the start of the ntfs record. */ - u16 usa_count; /* Number of u16 sized entries in the usa - including the Update Sequence Number (usn), + le16 usa_count; /* Number of u16 sized entries in the USA + including the Update Sequence Number (USN), thus the number of fixups is the usa_count minus 1. */ } __attribute__((__packed__)) NTFS_RECORD; @@ -215,7 +225,7 @@ typedef enum { FILE_AttrDef = 4, /* Array of attribute definitions in data attribute. */ FILE_root = 5, /* Root directory. */ - FILE_Bitmap = 6, /* Allocation bitmap of all clusters (lcns) in + FILE_Bitmap = 6, /* Allocation bitmap of all clusters (LCNs) in data attribute. */ FILE_Boot = 7, /* Boot sector (always at cluster 0) in data attribute. */ @@ -229,7 +239,7 @@ typedef enum { characters in data attribute. */ FILE_Extend = 11, /* Directory containing other system files (eg. $ObjId, $Quota, $Reparse and $UsnJrnl). This - is new to NTFS3.0. */ + is new to NTFS 3.0. */ FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */ FILE_reserved13 = 13, FILE_reserved14 = 14, @@ -257,8 +267,8 @@ typedef enum { MFT_RECORD_IS_DIRECTORY = const_cpu_to_le16(0x0002), MFT_RECORD_IS_4 = const_cpu_to_le16(0x0004), MFT_RECORD_IS_VIEW_INDEX = const_cpu_to_le16(0x0008), - MFT_REC_SPACE_FILLER = 0xffff, /* Just to make flags - 16-bit. */ + MFT_REC_SPACE_FILLER = const_cpu_to_le16(0xffff), + /* Just to make flags 16-bit. */ } __attribute__((__packed__)) MFT_RECORD_FLAGS; /* @@ -309,6 +319,7 @@ typedef enum { #define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU) typedef u64 MFT_REF; +typedef le64 leMFT_REF; #define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \ ((MFT_REF)(m) & MFT_REF_MASK_CPU))) @@ -337,17 +348,17 @@ typedef struct { /*Ofs*/ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ - u16 usa_ofs; /* See NTFS_RECORD definition above. */ - u16 usa_count; /* See NTFS_RECORD definition above. */ + le16 usa_ofs; /* See NTFS_RECORD definition above. */ + le16 usa_count; /* See NTFS_RECORD definition above. */ -/* 8*/ LSN lsn; /* $LogFile sequence number for this record. +/* 8*/ leLSN lsn; /* $LogFile sequence number for this record. Changed every time the record is modified. */ -/* 16*/ u16 sequence_number; /* Number of times this mft record has been +/* 16*/ le16 sequence_number; /* Number of times this mft record has been reused. (See description for MFT_REF above.) NOTE: The increment (skipping zero) is done when the file is deleted. NOTE: If this is zero it is left zero. */ -/* 18*/ u16 link_count; /* Number of hard links, i.e. the number of +/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of directory entries referencing this record. NOTE: Only used in mft base records. NOTE: When deleting a directory entry we @@ -357,18 +368,18 @@ typedef struct { directory entry from the mft record and decrement the link_count. FIXME: Careful with Win32 + DOS names! */ -/* 20*/ u16 attrs_offset; /* Byte offset to the first attribute in this +/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this mft record from the start of the mft record. NOTE: Must be aligned to 8-byte boundary. */ /* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file is deleted, the MFT_RECORD_IN_USE flag is set to zero. */ -/* 24*/ u32 bytes_in_use; /* Number of bytes used in this mft record. +/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record. NOTE: Must be aligned to 8-byte boundary. */ -/* 28*/ u32 bytes_allocated; /* Number of bytes allocated for this mft +/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft record. This should be equal to the mft record size. */ -/* 32*/ MFT_REF base_mft_record; /* This is zero for base mft records. +/* 32*/ leMFT_REF base_mft_record;/* This is zero for base mft records. When it is not zero it is a mft reference pointing to the base mft record to which this record belongs (this is then used to @@ -380,7 +391,7 @@ typedef struct { attribute list also means finding the other potential extents, belonging to the non-base mft record). */ -/* 40*/ u16 next_attr_instance; /* The instance number that will be +/* 40*/ le16 next_attr_instance; /* The instance number that will be assigned to the next attribute added to this mft record. NOTE: Incremented each time after it is used. NOTE: Every time the mft @@ -388,8 +399,8 @@ typedef struct { NOTE: The first instance number is always 0. */ /* The below fields are specific to NTFS 3.1+ (Windows XP and above): */ -/* 42*/ u16 reserved; /* Reserved/alignment. */ -/* 44*/ u32 mft_record_number; /* Number of this mft record. */ +/* 42*/ le16 reserved; /* Reserved/alignment. */ +/* 44*/ le32 mft_record_number; /* Number of this mft record. */ /* sizeof() = 48 bytes */ /* * When (re)using the mft record, we place the update sequence array at this @@ -411,17 +422,17 @@ typedef struct { /*Ofs*/ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */ - u16 usa_ofs; /* See NTFS_RECORD definition above. */ - u16 usa_count; /* See NTFS_RECORD definition above. */ + le16 usa_ofs; /* See NTFS_RECORD definition above. */ + le16 usa_count; /* See NTFS_RECORD definition above. */ -/* 8*/ LSN lsn; /* $LogFile sequence number for this record. +/* 8*/ leLSN lsn; /* $LogFile sequence number for this record. Changed every time the record is modified. */ -/* 16*/ u16 sequence_number; /* Number of times this mft record has been +/* 16*/ le16 sequence_number; /* Number of times this mft record has been reused. (See description for MFT_REF above.) NOTE: The increment (skipping zero) is done when the file is deleted. NOTE: If this is zero it is left zero. */ -/* 18*/ u16 link_count; /* Number of hard links, i.e. the number of +/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of directory entries referencing this record. NOTE: Only used in mft base records. NOTE: When deleting a directory entry we @@ -431,15 +442,15 @@ typedef struct { directory entry from the mft record and decrement the link_count. FIXME: Careful with Win32 + DOS names! */ -/* 20*/ u16 attrs_offset; /* Byte offset to the first attribute in this +/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this mft record from the start of the mft record. NOTE: Must be aligned to 8-byte boundary. */ /* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file is deleted, the MFT_RECORD_IN_USE flag is set to zero. */ -/* 24*/ u32 bytes_in_use; /* Number of bytes used in this mft record. +/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record. NOTE: Must be aligned to 8-byte boundary. */ -/* 28*/ u32 bytes_allocated; /* Number of bytes allocated for this mft +/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft record. This should be equal to the mft record size. */ /* 32*/ MFT_REF base_mft_record; /* This is zero for base mft records. @@ -454,7 +465,7 @@ typedef struct { attribute list also means finding the other potential extents, belonging to the non-base mft record). */ -/* 40*/ u16 next_attr_instance; /* The instance number that will be +/* 40*/ le16 next_attr_instance; /* The instance number that will be assigned to the next attribute added to this mft record. NOTE: Incremented each time after it is used. NOTE: Every time the mft @@ -520,28 +531,28 @@ typedef enum { * unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[] * for what I mean but COLLATION_UNICODE_STRING would not give any special * treatment to any characters at all, but this is speculation. - * COLLATION_NTOFS_ULONG - Sorting is done according to ascending u32 key + * COLLATION_NTOFS_ULONG - Sorting is done according to ascending le32 key * values. E.g. used for $SII index in FILE_Secure, which sorts by - * security_id (u32). + * security_id (le32). * COLLATION_NTOFS_SID - Sorting is done according to ascending SID values. * E.g. used for $O index in FILE_Extend/$Quota. * COLLATION_NTOFS_SECURITY_HASH - Sorting is done first by ascending hash * values and second by ascending security_id values. E.g. used for $SDH * index in FILE_Secure. * COLLATION_NTOFS_ULONGS - Sorting is done according to a sequence of ascending - * u32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which + * le32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which * sorts by object_id (16-byte), by splitting up the object_id in four - * u32 values and using them as individual keys. E.g. take the following + * le32 values and using them as individual keys. E.g. take the following * two security_ids, stored as follows on disk: * 1st: a1 61 65 b7 65 7b d4 11 9e 3d 00 e0 81 10 42 59 * 2nd: 38 14 37 d2 d2 f3 d4 11 a5 21 c8 6b 79 b1 97 45 - * To compare them, they are split into four u32 values each, like so: + * To compare them, they are split into four le32 values each, like so: * 1st: 0xb76561a1 0x11d47b65 0xe0003d9e 0x59421081 * 2nd: 0xd2371438 0x11d4f3d2 0x6bc821a5 0x4597b179 * Now, it is apparent why the 2nd object_id collates after the 1st: the - * first u32 value of the 1st object_id is less than the first u32 of - * the 2nd object_id. If the first u32 values of both object_ids were - * equal then the second u32 values would be compared, etc. + * first le32 value of the 1st object_id is less than the first le32 of + * the 2nd object_id. If the first le32 values of both object_ids were + * equal then the second le32 values would be compared, etc. */ typedef enum { COLLATION_BINARY = const_cpu_to_le32(0), /* Collate by binary @@ -614,12 +625,12 @@ typedef struct { /* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero terminated. */ /* 80*/ ATTR_TYPES type; /* Type of the attribute. */ -/* 84*/ u32 display_rule; /* Default display rule. +/* 84*/ le32 display_rule; /* Default display rule. FIXME: What does it mean? (AIA) */ /* 88*/ COLLATION_RULES collation_rule; /* Default collation rule. */ /* 8c*/ ATTR_DEF_FLAGS flags; /* Flags describing the attribute. */ -/* 90*/ s64 min_size; /* Optional minimum attribute size. */ -/* 98*/ s64 max_size; /* Maximum size of attribute. */ +/* 90*/ sle64 min_size; /* Optional minimum attribute size. */ +/* 98*/ sle64 max_size; /* Maximum size of attribute. */ /* sizeof() = 0xa0 or 160 bytes */ } __attribute__((__packed__)) ATTR_DEF; @@ -719,14 +730,14 @@ typedef enum { typedef struct { /*Ofs*/ /* 0*/ ATTR_TYPES type; /* The (32-bit) type of the attribute. */ -/* 4*/ u32 length; /* Byte size of the resident part of the +/* 4*/ le32 length; /* Byte size of the resident part of the attribute (aligned to 8-byte boundary). Used to get to the next attribute. */ /* 8*/ u8 non_resident; /* If 0, attribute is resident. If 1, attribute is non-resident. */ /* 9*/ u8 name_length; /* Unicode character size of name of attribute. 0 if unnamed. */ -/* 10*/ u16 name_offset; /* If name_length != 0, the byte offset to the +/* 10*/ le16 name_offset; /* If name_length != 0, the byte offset to the beginning of the name from the attribute record. Note that the name is stored as a Unicode string. When creating, place offset @@ -736,15 +747,15 @@ typedef struct { respectively, aligning to an 8-byte boundary. */ /* 12*/ ATTR_FLAGS flags; /* Flags describing the attribute. */ -/* 14*/ u16 instance; /* The instance of this attribute record. This +/* 14*/ le16 instance; /* The instance of this attribute record. This number is unique within this mft record (see MFT_RECORD/next_attribute_instance notes above for more details). */ /* 16*/ union { /* Resident attributes. */ struct { -/* 16 */ u32 value_length; /* Byte size of attribute value. */ -/* 20 */ u16 value_offset; /* Byte offset of the attribute +/* 16 */ le32 value_length; /* Byte size of attribute value. */ +/* 20 */ le16 value_offset; /* Byte offset of the attribute value from the start of the attribute record. When creating, align to 8-byte boundary if we @@ -760,21 +771,21 @@ typedef struct { } __attribute__((__packed__)); /* Non-resident attributes. */ struct { -/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number +/* 16*/ leVCN lowest_vcn;/* Lowest valid virtual cluster number for this portion of the attribute value or 0 if this is the only extent (usually the case). - Only when an attribute list is used does lowest_vcn != 0 ever occur. */ -/* 24*/ VCN highest_vcn; /* Highest valid vcn of this extent of +/* 24*/ leVCN highest_vcn;/* Highest valid vcn of this extent of the attribute value. - Usually there is only one portion, so this usually equals the attribute value size in clusters minus 1. Can be -1 for zero length files. Can be 0 for "single extent" attributes. */ -/* 32*/ u16 mapping_pairs_offset; /* Byte offset from the +/* 32*/ le16 mapping_pairs_offset; /* Byte offset from the beginning of the structure to the mapping pairs array which contains the mappings between the - vcns and the logical cluster numbers (lcns). + VCNs and the logical cluster numbers (LCNs). When creating, place this at the end of this record header aligned to 8-byte boundary. */ /* 34*/ u8 compression_unit; /* The compression unit expressed @@ -786,7 +797,7 @@ typedef struct { /* 35*/ u8 reserved1[5]; /* Align to 8-byte boundary. */ /* The sizes below are only used when lowest_vcn is zero, as otherwise it would be difficult to keep them up-to-date.*/ -/* 40*/ s64 allocated_size; /* Byte size of disk space +/* 40*/ sle64 allocated_size; /* Byte size of disk space allocated to hold the attribute value. Always is a multiple of the cluster size. When a file is compressed, this field is a multiple of the @@ -794,10 +805,10 @@ typedef struct { it represents the logically allocated space rather than the actual on disk usage. For this use the compressed_size (see below). */ -/* 48*/ s64 data_size; /* Byte size of the attribute +/* 48*/ sle64 data_size; /* Byte size of the attribute value. Can be larger than allocated_size if attribute value is compressed or sparse. */ -/* 56*/ s64 initialized_size; /* Byte size of initialized +/* 56*/ sle64 initialized_size; /* Byte size of initialized portion of the attribute value. Usually equals data_size. */ /* 64 */ void *non_resident_end[0]; /* Use offsetof(ATTR_RECORD, @@ -805,7 +816,7 @@ typedef struct { size of a non resident attribute. */ /* sizeof(uncompressed attr) = 64*/ -/* 64*/ s64 compressed_size; /* Byte size of the attribute +/* 64*/ sle64 compressed_size; /* Byte size of the attribute value after compression. Only present when compressed. Always is a multiple of the cluster size. Represents the actual amount of @@ -831,7 +842,7 @@ typedef enum { FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001), FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002), FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004), - /* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */ + /* Old DOS valid. Unused in NT. = cpu_to_le32(0x00000008), */ FILE_ATTR_DIRECTORY = const_cpu_to_le32(0x00000010), /* FILE_ATTR_DIRECTORY is not considered valid in NT. It is reserved @@ -905,13 +916,13 @@ typedef enum { */ typedef struct { /*Ofs*/ -/* 0*/ s64 creation_time; /* Time file was created. Updated when +/* 0*/ sle64 creation_time; /* Time file was created. Updated when a filename is changed(?). */ -/* 8*/ s64 last_data_change_time; /* Time the data attribute was last +/* 8*/ sle64 last_data_change_time; /* Time the data attribute was last modified. */ -/* 16*/ s64 last_mft_change_time; /* Time this mft record was last +/* 16*/ sle64 last_mft_change_time; /* Time this mft record was last modified. */ -/* 24*/ s64 last_access_time; /* Approximate time when the file was +/* 24*/ sle64 last_access_time; /* Approximate time when the file was last accessed (obviously this is not updated on read-only volumes). In Windows this is only updated when @@ -949,29 +960,29 @@ typedef struct { * views that as a corruption, assuming that it behaves like this for all * attributes. */ - /* 36*/ u32 maximum_versions; /* Maximum allowed versions for + /* 36*/ le32 maximum_versions; /* Maximum allowed versions for file. Zero if version numbering is disabled. */ - /* 40*/ u32 version_number; /* This file's version (if any). + /* 40*/ le32 version_number; /* This file's version (if any). Set to zero if maximum_versions is zero. */ - /* 44*/ u32 class_id; /* Class id from bidirectional + /* 44*/ le32 class_id; /* Class id from bidirectional class id index (?). */ - /* 48*/ u32 owner_id; /* Owner_id of the user owning + /* 48*/ le32 owner_id; /* Owner_id of the user owning the file. Translate via $Q index in FILE_Extend /$Quota to the quota control entry for the user owning the file. Zero if quotas are disabled. */ - /* 52*/ u32 security_id; /* Security_id for the file. + /* 52*/ le32 security_id; /* Security_id for the file. Translate via $SII index and $SDS data stream in FILE_Secure to the security descriptor. */ - /* 56*/ u64 quota_charged; /* Byte size of the charge to + /* 56*/ le64 quota_charged; /* Byte size of the charge to the quota for all streams of the file. Note: Is zero if quotas are disabled. */ - /* 64*/ u64 usn; /* Last update sequence number + /* 64*/ le64 usn; /* Last update sequence number of the file. This is a direct index into the - change (aka usn) journal file. It is zero if - the usn journal is disabled. + change (aka USN) journal file. It is zero if + the USN journal is disabled. NOTE: To disable the journal need to delete the journal file itself and to then walk the - whole mft and set all Usn entries in all mft + whole mft and set all USN entries in all mft records to zero! (This can take a while!) The journal is FILE_Extend/$UsnJrnl. Win2k will recreate the journal and initiate @@ -1017,13 +1028,13 @@ typedef struct { typedef struct { /*Ofs*/ /* 0*/ ATTR_TYPES type; /* Type of referenced attribute. */ -/* 4*/ u16 length; /* Byte size of this entry. */ +/* 4*/ le16 length; /* Byte size of this entry. */ /* 6*/ u8 name_length; /* Size in Unicode chars of the name of the attribute or 0 if unnamed. */ /* 7*/ u8 name_offset; /* Byte offset to beginning of attribute name (always set this to where the name would start even if unnamed). */ -/* 8*/ VCN lowest_vcn; /* Lowest virtual cluster number of this portion +/* 8*/ leVCN lowest_vcn; /* Lowest virtual cluster number of this portion of the attribute value. This is usually 0. It is non-zero for the case where one attribute does not fit into one mft record and thus @@ -1035,10 +1046,10 @@ typedef struct { value! The windows driver uses cmp, followed by jg when comparing this, thus it treats it as signed. */ -/* 16*/ MFT_REF mft_reference; /* The reference of the mft record holding +/* 16*/ leMFT_REF mft_reference;/* The reference of the mft record holding the ATTR_RECORD for this portion of the attribute value. */ -/* 24*/ u16 instance; /* If lowest_vcn = 0, the instance of the +/* 24*/ le16 instance; /* If lowest_vcn = 0, the instance of the attribute being referenced; otherwise 0. */ /* 26*/ ntfschar name[0]; /* Use when creating only. When reading use name_offset to determine the location of the @@ -1093,16 +1104,16 @@ typedef enum { */ typedef struct { /*hex ofs*/ -/* 0*/ MFT_REF parent_directory; /* Directory this filename is +/* 0*/ leMFT_REF parent_directory; /* Directory this filename is referenced from. */ -/* 8*/ s64 creation_time; /* Time file was created. */ -/* 10*/ s64 last_data_change_time; /* Time the data attribute was last +/* 8*/ sle64 creation_time; /* Time file was created. */ +/* 10*/ sle64 last_data_change_time; /* Time the data attribute was last modified. */ -/* 18*/ s64 last_mft_change_time; /* Time this mft record was last +/* 18*/ sle64 last_mft_change_time; /* Time this mft record was last modified. */ -/* 20*/ s64 last_access_time; /* Last time this mft record was +/* 20*/ sle64 last_access_time; /* Last time this mft record was accessed. */ -/* 28*/ s64 allocated_size; /* Byte size of on-disk allocated space +/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space for the data attribute. So for normal $DATA, this is the allocated_size from the unnamed @@ -1111,17 +1122,17 @@ typedef struct { compressed_size from the unnamed $DATA attribute. NOTE: This is a multiple of the cluster size. */ -/* 30*/ s64 data_size; /* Byte size of actual data in data +/* 30*/ sle64 data_size; /* Byte size of actual data in data attribute. */ /* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 3c*/ union { /* 3c*/ struct { - /* 3c*/ u16 packed_ea_size; /* Size of the buffer needed to + /* 3c*/ le16 packed_ea_size; /* Size of the buffer needed to pack the extended attributes (EAs), if such are present.*/ - /* 3e*/ u16 reserved; /* Reserved for alignment. */ + /* 3e*/ le16 reserved; /* Reserved for alignment. */ } __attribute__((__packed__)); - /* 3c*/ u32 reparse_point_tag; /* Type of reparse point, + /* 3c*/ le32 reparse_point_tag; /* Type of reparse point, present only in reparse points and only if there are no EAs. */ @@ -1148,11 +1159,11 @@ typedef struct { */ typedef union { struct { - u32 data1; /* The first eight hexadecimal digits of the + le32 data1; /* The first eight hexadecimal digits of the GUID. */ - u16 data2; /* The first group of four hexadecimal + le16 data2; /* The first group of four hexadecimal digits. */ - u16 data3; /* The second group of four hexadecimal + le16 data3; /* The second group of four hexadecimal digits. */ u8 data4[8]; /* The first two bytes are the third group of four hexadecimal digits. The remaining six @@ -1175,7 +1186,7 @@ typedef union { * domain_id - Reserved (always zero). */ typedef struct { - MFT_REF mft_reference; /* Mft record containing the object_id in + leMFT_REF mft_reference;/* Mft record containing the object_id in the index entry key. */ union { struct { @@ -1331,7 +1342,7 @@ typedef enum { /* Identifier authority. */ * NT_AUTHORITY_SID S-1-5 * DIALUP_SID S-1-5-1 * - * NETWORD_SID S-1-5-2 + * NETWORK_SID S-1-5-2 * BATCH_SID S-1-5-3 * INTERACTIVE_SID S-1-5-4 * SERVICE_SID S-1-5-6 @@ -1357,8 +1368,8 @@ typedef enum { /* Identifier authority. */ */ typedef union { struct { - u16 high_part; /* High 16-bits. */ - u32 low_part; /* Low 32-bits. */ + be16 high_part; /* High 16-bits. */ + be32 low_part; /* Low 32-bits. */ } __attribute__((__packed__)); u8 value[6]; /* Value as individual bytes. */ } __attribute__((__packed__)) SID_IDENTIFIER_AUTHORITY; @@ -1395,7 +1406,7 @@ typedef struct { u8 revision; u8 sub_authority_count; SID_IDENTIFIER_AUTHORITY identifier_authority; - u32 sub_authority[1]; /* At least one sub_authority. */ + le32 sub_authority[1]; /* At least one sub_authority. */ } __attribute__((__packed__)) SID; /** @@ -1476,7 +1487,7 @@ typedef enum { typedef struct { ACE_TYPES type; /* Type of the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */ - u16 size; /* Size in bytes of the ACE. */ + le16 size; /* Size in bytes of the ACE. */ } __attribute__((__packed__)) ACE_HEADER; /** @@ -1642,7 +1653,7 @@ typedef struct { /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ ACE_TYPES type; /* Type of the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */ - u16 size; /* Size in bytes of the ACE. */ + le16 size; /* Size in bytes of the ACE. */ /* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */ /* 8*/ SID sid; /* The SID associated with the ACE. */ @@ -1664,7 +1675,7 @@ typedef struct { /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ ACE_TYPES type; /* Type of the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */ - u16 size; /* Size in bytes of the ACE. */ + le16 size; /* Size in bytes of the ACE. */ /* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */ /* 8*/ OBJECT_ACE_FLAGS object_flags; /* Flags describing the object ACE. */ @@ -1687,10 +1698,10 @@ typedef struct { typedef struct { u8 revision; /* Revision of this ACL. */ u8 alignment1; - u16 size; /* Allocated space in bytes for ACL. Includes this + le16 size; /* Allocated space in bytes for ACL. Includes this header, the ACEs and the remaining free space. */ - u16 ace_count; /* Number of ACEs in the ACL. */ - u16 alignment2; + le16 ace_count; /* Number of ACEs in the ACL. */ + le16 alignment2; /* sizeof() = 8 bytes */ } __attribute__((__packed__)) ACL; @@ -1788,17 +1799,17 @@ typedef struct { u8 alignment; SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of the descriptor as well as the following fields. */ - u32 owner; /* Byte offset to a SID representing an object's + le32 owner; /* Byte offset to a SID representing an object's owner. If this is NULL, no owner SID is present in the descriptor. */ - u32 group; /* Byte offset to a SID representing an object's + le32 group; /* Byte offset to a SID representing an object's primary group. If this is NULL, no primary group SID is present in the descriptor. */ - u32 sacl; /* Byte offset to a system ACL. Only valid, if + le32 sacl; /* Byte offset to a system ACL. Only valid, if SE_SACL_PRESENT is set in the control field. If SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL is specified. */ - u32 dacl; /* Byte offset to a discretionary ACL. Only valid, if + le32 dacl; /* Byte offset to a discretionary ACL. Only valid, if SE_DACL_PRESENT is set in the control field. If SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL (unconditionally granting access) is specified. */ @@ -1909,21 +1920,21 @@ typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR; * This is also the index entry data part of both the $SII and $SDH indexes. */ typedef struct { - u32 hash; /* Hash of the security descriptor. */ - u32 security_id; /* The security_id assigned to the descriptor. */ - u64 offset; /* Byte offset of this entry in the $SDS stream. */ - u32 length; /* Size in bytes of this entry in $SDS stream. */ + le32 hash; /* Hash of the security descriptor. */ + le32 security_id; /* The security_id assigned to the descriptor. */ + le64 offset; /* Byte offset of this entry in the $SDS stream. */ + le32 length; /* Size in bytes of this entry in $SDS stream. */ } __attribute__((__packed__)) SECURITY_DESCRIPTOR_HEADER; /** * struct SDH_INDEX_DATA - */ typedef struct { - u32 hash; /* Hash of the security descriptor. */ - u32 security_id; /* The security_id assigned to the descriptor. */ - u64 offset; /* Byte offset of this entry in the $SDS stream. */ - u32 length; /* Size in bytes of this entry in $SDS stream. */ - u32 reserved_II; /* Padding - always unicode "II" or zero. This field + le32 hash; /* Hash of the security descriptor. */ + le32 security_id; /* The security_id assigned to the descriptor. */ + le64 offset; /* Byte offset of this entry in the $SDS stream. */ + le32 length; /* Size in bytes of this entry in $SDS stream. */ + le32 reserved_II; /* Padding - always unicode "II" or zero. This field isn't counted in INDEX_ENTRY's data_length. */ } __attribute__((__packed__)) SDH_INDEX_DATA; @@ -1948,10 +1959,10 @@ typedef SECURITY_DESCRIPTOR_HEADER SII_INDEX_DATA; typedef struct { /* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */ - u32 hash; /* Hash of the security descriptor. */ - u32 security_id; /* The security_id assigned to the descriptor. */ - u64 offset; /* Byte offset of this entry in the $SDS stream. */ - u32 length; /* Size in bytes of this entry in $SDS stream. */ + le32 hash; /* Hash of the security descriptor. */ + le32 security_id; /* The security_id assigned to the descriptor. */ + le64 offset; /* Byte offset of this entry in the $SDS stream. */ + le32 length; /* Size in bytes of this entry in $SDS stream. */ /* 20*/ SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security descriptor. */ } __attribute__((__packed__)) SDS_ENTRY; @@ -1962,7 +1973,7 @@ typedef struct { * The collation type is COLLATION_NTOFS_ULONG. */ typedef struct { - u32 security_id; /* The security_id assigned to the descriptor. */ + le32 security_id; /* The security_id assigned to the descriptor. */ } __attribute__((__packed__)) SII_INDEX_KEY; /** @@ -1972,8 +1983,8 @@ typedef struct { * The collation rule is COLLATION_NTOFS_SECURITY_HASH. */ typedef struct { - u32 hash; /* Hash of the security descriptor. */ - u32 security_id; /* The security_id assigned to the descriptor. */ + le32 hash; /* Hash of the security descriptor. */ + le32 security_id; /* The security_id assigned to the descriptor. */ } __attribute__((__packed__)) SDH_INDEX_KEY; /** @@ -2013,7 +2024,7 @@ typedef enum { * NTFS 1.2. I haven't personally seen other values yet. */ typedef struct { - u64 reserved; /* Not used (yet?). */ + le64 reserved; /* Not used (yet?). */ u8 major_ver; /* Major version of the ntfs format. */ u8 minor_ver; /* Minor version of the ntfs format. */ VOLUME_FLAGS flags; /* Bit array of VOLUME_* flags. */ @@ -2064,12 +2075,12 @@ typedef enum { * start of the index root or index allocation structures themselves. */ typedef struct { - u32 entries_offset; /* Byte offset to first INDEX_ENTRY + le32 entries_offset; /* Byte offset to first INDEX_ENTRY aligned to 8-byte boundary. */ - u32 index_length; /* Data size of the index in bytes, + le32 index_length; /* Data size of the index in bytes, i.e. bytes used from allocated size, aligned to 8-byte boundary. */ - u32 allocated_size; /* Byte size of this index (block), + le32 allocated_size; /* Byte size of this index (block), multiple of 8 bytes. */ /* NOTE: For the index root attribute, the above two numbers are always equal, as the attribute is resident and it is resized as needed. In @@ -2095,7 +2106,7 @@ typedef struct { * large to fit in the index root, on the other hand, two additional attributes * are present: an index allocation attribute, containing sub-nodes of the B+ * directory tree (see below), and a bitmap attribute, describing which virtual - * cluster numbers (vcns) in the index allocation attribute are in use by an + * cluster numbers (VCNs) in the index allocation attribute are in use by an * index block. * * NOTE: The root directory (FILE_root) contains an entry for itself. Other @@ -2109,7 +2120,7 @@ typedef struct { COLLATION_RULES collation_rule; /* Collation rule used to sort the index entries. If type is $FILE_NAME, this must be COLLATION_FILE_NAME. */ - u32 index_block_size; /* Size of each index block in bytes (in + le32 index_block_size; /* Size of each index block in bytes (in the index allocation attribute). */ u8 clusters_per_index_block; /* Cluster size of each index block (in the index allocation attribute), when @@ -2132,12 +2143,12 @@ typedef struct { typedef struct { /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */ NTFS_RECORD_TYPES magic;/* Magic is "INDX". */ - u16 usa_ofs; /* See NTFS_RECORD definition. */ - u16 usa_count; /* See NTFS_RECORD definition. */ + le16 usa_ofs; /* See NTFS_RECORD definition. */ + le16 usa_count; /* See NTFS_RECORD definition. */ -/* 8*/ LSN lsn; /* $LogFile sequence number of the last +/* 8*/ leLSN lsn; /* $LogFile sequence number of the last modification of this index block. */ -/* 16*/ VCN index_block_vcn; /* Virtual cluster number of the index block. */ +/* 16*/ leVCN index_block_vcn; /* Virtual cluster number of the index block. */ /* 24*/ INDEX_HEADER index; /* Describes the following index entries. */ /* sizeof()= 40 (0x28) bytes */ /* @@ -2165,8 +2176,8 @@ typedef INDEX_BLOCK INDEX_ALLOCATION; * primary key / is not a key at all. (AIA) */ typedef struct { - u32 reparse_tag; /* Reparse point type (inc. flags). */ - MFT_REF file_id; /* Mft record of the file containing the + le32 reparse_tag; /* Reparse point type (inc. flags). */ + leMFT_REF file_id; /* Mft record of the file containing the reparse point attribute. */ } __attribute__((__packed__)) REPARSE_INDEX_KEY; @@ -2218,19 +2229,19 @@ typedef enum { * The $Q index entry data is the quota control entry and is defined below. */ typedef struct { - u32 version; /* Currently equals 2. */ + le32 version; /* Currently equals 2. */ QUOTA_FLAGS flags; /* Flags describing this quota entry. */ - u64 bytes_used; /* How many bytes of the quota are in use. */ - s64 change_time; /* Last time this quota entry was changed. */ - s64 threshold; /* Soft quota (-1 if not limited). */ - s64 limit; /* Hard quota (-1 if not limited). */ - s64 exceeded_time; /* How long the soft quota has been exceeded. */ + le64 bytes_used; /* How many bytes of the quota are in use. */ + sle64 change_time; /* Last time this quota entry was changed. */ + sle64 threshold; /* Soft quota (-1 if not limited). */ + sle64 limit; /* Hard quota (-1 if not limited). */ + sle64 exceeded_time; /* How long the soft quota has been exceeded. */ /* The below field is NOT present for the quota defaults entry. */ SID sid; /* The SID of the user/object associated with this quota entry. If this field is missing then the INDEX_ENTRY is padded with zeros to multiply of 8 which are not counted in - the data_length field. If the sid is present + the data_length field. If the SID is present then this structure is padded with zeros to multiply of 8 and the padding is counted in the INDEX_ENTRY's data_length. */ @@ -2240,8 +2251,8 @@ typedef struct { * struct QUOTA_O_INDEX_DATA - */ typedef struct { - u32 owner_id; - u32 unknown; /* Always 32. Seems to be padding and it's not + le32 owner_id; + le32 unknown; /* Always 32. Seems to be padding and it's not counted in the INDEX_ENTRY's data_length. This field shouldn't be really here. */ } __attribute__((__packed__)) QUOTA_O_INDEX_DATA; @@ -2267,7 +2278,8 @@ typedef enum { entry in an index block. The index entry does not represent a file but it can point to a sub-node. */ - INDEX_ENTRY_SPACE_FILLER = 0xffff, /* Just to force 16-bit width. */ + INDEX_ENTRY_SPACE_FILLER = const_cpu_to_le16(0xffff), + /* Just to force 16-bit width. */ } __attribute__((__packed__)) INDEX_ENTRY_FLAGS; /** @@ -2275,25 +2287,25 @@ typedef enum { */ typedef struct { /* 0*/ union { /* Only valid when INDEX_ENTRY_END is not set. */ - MFT_REF indexed_file; /* The mft reference of the file + leMFT_REF indexed_file; /* The mft reference of the file described by this index entry. Used for directory indexes. */ struct { /* Used for views/indexes to find the entry's data. */ - u16 data_offset; /* Data byte offset from this + le16 data_offset; /* Data byte offset from this INDEX_ENTRY. Follows the index key. */ - u16 data_length; /* Data length in bytes. */ - u32 reservedV; /* Reserved (zero). */ + le16 data_length; /* Data length in bytes. */ + le32 reservedV; /* Reserved (zero). */ } __attribute__((__packed__)); } __attribute__((__packed__)); -/* 8*/ u16 length; /* Byte size of this index entry, multiple of +/* 8*/ le16 length; /* Byte size of this index entry, multiple of 8-bytes. */ -/* 10*/ u16 key_length; /* Byte size of the key value, which is in the +/* 10*/ le16 key_length; /* Byte size of the key value, which is in the index entry. It follows field reserved. Not multiple of 8-bytes. */ /* 12*/ INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */ -/* 14*/ u16 reserved; /* Reserved/align to 8-byte boundary. */ +/* 14*/ le16 reserved; /* Reserved/align to 8-byte boundary. */ /* sizeof() = 16 bytes */ } __attribute__((__packed__)) INDEX_ENTRY_HEADER; @@ -2309,25 +2321,25 @@ typedef struct { typedef struct { /* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */ union { /* Only valid when INDEX_ENTRY_END is not set. */ - MFT_REF indexed_file; /* The mft reference of the file + leMFT_REF indexed_file; /* The mft reference of the file described by this index entry. Used for directory indexes. */ struct { /* Used for views/indexes to find the entry's data. */ - u16 data_offset; /* Data byte offset from this + le16 data_offset; /* Data byte offset from this INDEX_ENTRY. Follows the index key. */ - u16 data_length; /* Data length in bytes. */ - u32 reservedV; /* Reserved (zero). */ + le16 data_length; /* Data length in bytes. */ + le32 reservedV; /* Reserved (zero). */ } __attribute__((__packed__)); } __attribute__((__packed__)); - u16 length; /* Byte size of this index entry, multiple of + le16 length; /* Byte size of this index entry, multiple of 8-bytes. */ - u16 key_length; /* Byte size of the key value, which is in the + le16 key_length; /* Byte size of the key value, which is in the index entry. It follows field reserved. Not multiple of 8-bytes. */ INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */ - u16 reserved; /* Reserved/align to 8-byte boundary. */ + le16 reserved; /* Reserved/align to 8-byte boundary. */ /* 16*/ union { /* The key of the indexed attribute. NOTE: Only present if INDEX_ENTRY_END bit in flags is not set. NOTE: On @@ -2344,7 +2356,7 @@ typedef struct { FILE_Extend/$Reparse. */ SID sid; /* $O index in FILE_Extend/$Quota: SID of the owner of the user_id. */ - u32 owner_id; /* $Q index in FILE_Extend/$Quota: + le32 owner_id; /* $Q index in FILE_Extend/$Quota: user_id of the owner of the quota control entry in the data part of the index. */ @@ -2427,9 +2439,9 @@ typedef enum { * NOTE: Can be resident or non-resident. */ typedef struct { - u32 reparse_tag; /* Reparse point type (inc. flags). */ - u16 reparse_data_length; /* Byte size of reparse data. */ - u16 reserved; /* Align to 8-byte boundary. */ + le32 reparse_tag; /* Reparse point type (inc. flags). */ + le16 reparse_data_length; /* Byte size of reparse data. */ + le16 reserved; /* Align to 8-byte boundary. */ u8 reparse_data[0]; /* Meaning depends on reparse_tag. */ } __attribute__((__packed__)) REPARSE_POINT; @@ -2439,11 +2451,11 @@ typedef struct { * NOTE: Always resident. */ typedef struct { - u16 ea_length; /* Byte size of the packed extended + le16 ea_length; /* Byte size of the packed extended attributes. */ - u16 need_ea_count; /* The number of extended attributes which have + le16 need_ea_count; /* The number of extended attributes which have the NEED_EA bit set. */ - u32 ea_query_length; /* Byte size of the buffer required to query + le32 ea_query_length; /* Byte size of the buffer required to query the extended attributes when calling ZwQueryEaFile() in Windows NT/2k. I.e. the byte size of the unpacked extended @@ -2470,11 +2482,11 @@ typedef enum { * FIXME: It seems that name is always uppercased. Is it true? */ typedef struct { - u32 next_entry_offset; /* Offset to the next EA_ATTR. */ + le32 next_entry_offset; /* Offset to the next EA_ATTR. */ EA_FLAGS flags; /* Flags describing the EA. */ u8 name_length; /* Length of the name of the extended attribute in bytes. */ - u16 value_length; /* Byte size of the EA's value. */ + le16 value_length; /* Byte size of the EA's value. */ u8 name[0]; /* Name of the EA. */ u8 value[0]; /* The value of the EA. Immediately follows the name. */ @@ -2538,10 +2550,10 @@ typedef struct { * The header of the Logged utility stream (0x100) attribute named "$EFS". */ typedef struct { -/* 0*/ u32 length; /* Length of EFS attribute in bytes. */ - u32 state; /* Always 0? */ - u32 version; /* Efs version. Always 2? */ - u32 crypto_api_version; /* Always 0? */ +/* 0*/ le32 length; /* Length of EFS attribute in bytes. */ + le32 state; /* Always 0? */ + le32 version; /* Efs version. Always 2? */ + le32 crypto_api_version; /* Always 0? */ /* 16*/ u8 unknown4[16]; /* MD5 hash of decrypted FEK? This field is created with a call to UuidCreate() so is unlikely to be an MD5 hash and is more @@ -2549,20 +2561,20 @@ typedef struct { or something like that. */ /* 32*/ u8 unknown5[16]; /* MD5 hash of DDFs? */ /* 48*/ u8 unknown6[16]; /* MD5 hash of DRFs? */ -/* 64*/ u32 offset_to_ddf_array;/* Offset in bytes to the array of data +/* 64*/ le32 offset_to_ddf_array;/* Offset in bytes to the array of data decryption fields (DDF), see below. Zero if no DDFs are present. */ - u32 offset_to_drf_array;/* Offset in bytes to the array of data + le32 offset_to_drf_array;/* Offset in bytes to the array of data recovery fields (DRF), see below. Zero if no DRFs are present. */ - u32 reserved; /* Reserved. */ + le32 reserved; /* Reserved. */ } __attribute__((__packed__)) EFS_ATTR_HEADER; /** * struct EFS_DF_ARRAY_HEADER - */ typedef struct { - u32 df_count; /* Number of data decryption/recovery fields in + le32 df_count; /* Number of data decryption/recovery fields in the array. */ } __attribute__((__packed__)) EFS_DF_ARRAY_HEADER; @@ -2570,25 +2582,25 @@ typedef struct { * struct EFS_DF_HEADER - */ typedef struct { -/* 0*/ u32 df_length; /* Length of this data decryption/recovery +/* 0*/ le32 df_length; /* Length of this data decryption/recovery field in bytes. */ - u32 cred_header_offset; /* Offset in bytes to the credential header. */ - u32 fek_size; /* Size in bytes of the encrypted file + le32 cred_header_offset;/* Offset in bytes to the credential header. */ + le32 fek_size; /* Size in bytes of the encrypted file encryption key (FEK). */ - u32 fek_offset; /* Offset in bytes to the FEK from the start of + le32 fek_offset; /* Offset in bytes to the FEK from the start of the data decryption/recovery field. */ -/* 16*/ u32 unknown1; /* always 0? Might be just padding. */ +/* 16*/ le32 unknown1; /* always 0? Might be just padding. */ } __attribute__((__packed__)) EFS_DF_HEADER; /** * struct EFS_DF_CREDENTIAL_HEADER - */ typedef struct { -/* 0*/ u32 cred_length; /* Length of this credential in bytes. */ - u32 sid_offset; /* Offset in bytes to the user's sid from start +/* 0*/ le32 cred_length; /* Length of this credential in bytes. */ + le32 sid_offset; /* Offset in bytes to the user's sid from start of this structure. Zero if no sid is present. */ -/* 8*/ u32 type; /* Type of this credential: +/* 8*/ le32 type; /* Type of this credential: 1 = CryptoAPI container. 2 = Unexpected type. 3 = Certificate thumbprint. @@ -2596,28 +2608,28 @@ typedef struct { union { /* CryptoAPI container. */ struct { -/* 12*/ u32 container_name_offset; /* Offset in bytes to +/* 12*/ le32 container_name_offset; /* Offset in bytes to the name of the container from start of this structure (may not be zero). */ -/* 16*/ u32 provider_name_offset; /* Offset in bytes to +/* 16*/ le32 provider_name_offset; /* Offset in bytes to the name of the provider from start of this structure (may not be zero). */ - u32 public_key_blob_offset; /* Offset in bytes to + le32 public_key_blob_offset; /* Offset in bytes to the public key blob from start of this structure. */ -/* 24*/ u32 public_key_blob_size; /* Size in bytes of +/* 24*/ le32 public_key_blob_size; /* Size in bytes of public key blob. */ } __attribute__((__packed__)); /* Certificate thumbprint. */ struct { -/* 12*/ u32 cert_thumbprint_header_size; /* Size in +/* 12*/ le32 cert_thumbprint_header_size; /* Size in bytes of the header of the certificate thumbprint. */ -/* 16*/ u32 cert_thumbprint_header_offset; /* Offset in +/* 16*/ le32 cert_thumbprint_header_offset; /* Offset in bytes to the header of the certificate thumbprint from start of this structure. */ - u32 unknown1; /* Always 0? Might be padding... */ - u32 unknown2; /* Always 0? Might be padding... */ + le32 unknown1; /* Always 0? Might be padding... */ + le32 unknown2; /* Always 0? Might be padding... */ } __attribute__((__packed__)); } __attribute__((__packed__)); } __attribute__((__packed__)) EFS_DF_CREDENTIAL_HEADER; @@ -2628,16 +2640,16 @@ typedef EFS_DF_CREDENTIAL_HEADER EFS_DF_CRED_HEADER; * struct EFS_DF_CERTIFICATE_THUMBPRINT_HEADER - */ typedef struct { -/* 0*/ u32 thumbprint_offset; /* Offset in bytes to the thumbprint. */ - u32 thumbprint_size; /* Size of thumbprint in bytes. */ -/* 8*/ u32 container_name_offset; /* Offset in bytes to the name of the +/* 0*/ le32 thumbprint_offset; /* Offset in bytes to the thumbprint. */ + le32 thumbprint_size; /* Size of thumbprint in bytes. */ +/* 8*/ le32 container_name_offset; /* Offset in bytes to the name of the container from start of this structure or 0 if no name present. */ - u32 provider_name_offset; /* Offset in bytes to the name of the + le32 provider_name_offset; /* Offset in bytes to the name of the cryptographic provider from start of this structure or 0 if no name present. */ -/* 16*/ u32 user_name_offset; /* Offset in bytes to the user name +/* 16*/ le32 user_name_offset; /* Offset in bytes to the user name from start of this structure or 0 if no user name present. (This is also known as lpDisplayInformation.) */ @@ -2659,8 +2671,8 @@ typedef struct { union { /* For character and block devices. */ struct { - u64 major; /* Major device number. */ - u64 minor; /* Minor device number. */ + le64 major; /* Major device number. */ + le64 minor; /* Minor device number. */ void *device_end[0]; /* Marker for offsetof(). */ } __attribute__((__packed__)); /* For symbolic links. */ diff --git a/include/ntfs/logfile.h b/include/ntfs/logfile.h index 8aadc8c1..b35b5ecf 100644 --- a/include/ntfs/logfile.h +++ b/include/ntfs/logfile.h @@ -2,6 +2,7 @@ * logfile.h - Exports for $LogFile handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2005 Anton Altaparmakov + * Copyright (c) 2005-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -110,7 +111,8 @@ typedef struct { */ enum { RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002), - RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */ + RESTART_SPACE_FILLER = const_cpu_to_le16(0xffff), + /* gcc: Force enum bit width to 16. */ } __attribute__((__packed__)); typedef le16 RESTART_AREA_FLAGS; diff --git a/include/ntfs/ntfstime.h b/include/ntfs/ntfstime.h index e0d1ae20..2fb85a54 100644 --- a/include/ntfs/ntfstime.h +++ b/include/ntfs/ntfstime.h @@ -1,8 +1,8 @@ /* * ntfstime.h - NTFS time related functions. Part of the Linux-NTFS project. * - * Copyright (c) 2005 Anton Altaparmakov - * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2005-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -40,7 +40,7 @@ * * Return: n A Unix time (number of seconds since 1970) */ -static __inline__ time_t ntfs2utc(s64 ntfs_time) +static __inline__ time_t ntfs2utc(sle64 ntfs_time) { return (sle64_to_cpu(ntfs_time) - (NTFS_TIME_OFFSET)) / 10000000; } @@ -60,7 +60,7 @@ static __inline__ time_t ntfs2utc(s64 ntfs_time) * * Return: n An NTFS time (100ns units since Jan 1601) */ -static __inline__ s64 utc2ntfs(time_t utc_time) +static __inline__ sle64 utc2ntfs(time_t utc_time) { /* Convert to 100ns intervals and then add the NTFS time offset. */ return cpu_to_sle64((s64)utc_time * 10000000 + NTFS_TIME_OFFSET); diff --git a/include/ntfs/types.h b/include/ntfs/types.h index ea156b27..bb0e654b 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -4,6 +4,7 @@ * * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2006 Szabolcs Szakacsits + * Copyright (c) 2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -47,8 +48,10 @@ typedef int64_t s64; #ifdef __CHECKER__ #define __bitwise __attribute__((bitwise)) +#define __force __attribute__((force)) #else #define __bitwise +#define __force #endif typedef u16 __bitwise le16; @@ -63,7 +66,11 @@ typedef u16 __bitwise sle16; typedef u32 __bitwise sle32; typedef u64 __bitwise sle64; -typedef u16 ntfschar; /* 2-byte Unicode character type. */ +typedef u16 __bitwise be16; +typedef u32 __bitwise be32; +typedef u64 __bitwise be64; + +typedef le16 ntfschar; /* 2-byte Unicode character type. */ #define UCHAR_T_SIZE_BITS 1 /* diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 61915d07..e5f97c93 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -2,7 +2,7 @@ * volume.h - Exports for NTFS volume handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov - * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -151,7 +151,7 @@ struct _ntfs_volume { ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */ u8 major_ver; /* Ntfs major version of volume. */ u8 minor_ver; /* Ntfs minor version of volume. */ - u16 flags; /* Bit array of VOLUME_* flags. */ + le16 flags; /* Bit array of VOLUME_* flags. */ GUID guid; /* The volume guid if present (otherwise it is a NULL guid). */ @@ -234,6 +234,6 @@ extern int ntfs_umount(ntfs_volume *vol, const BOOL force); extern int ntfs_version_is_supported(ntfs_volume *vol); extern int ntfs_logfile_reset(ntfs_volume *vol); -extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags); +extern int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags); #endif /* defined _NTFS_VOLUME_H */ diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 41e40b8c..9e91b3e4 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -4,7 +4,7 @@ * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2002-2006 Szabolcs Szakacsits - * Copyright (c) 2004-2006 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -393,7 +393,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, */ if (type == AT_ATTRIBUTE_LIST) a->flags = 0; - cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); + cs = (a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? 1 : 0; if (!name) { if (a->name_length) { name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( @@ -410,9 +410,9 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, } __ntfs_attr_init(na, ni, type, name, name_len); if (a->non_resident) { - ntfs_attr_init(na, TRUE, a->flags & ATTR_IS_COMPRESSED, - a->flags & ATTR_IS_ENCRYPTED, - a->flags & ATTR_IS_SPARSE, + ntfs_attr_init(na, TRUE, (a->flags & ATTR_IS_COMPRESSED)? 1 : 0, + (a->flags & ATTR_IS_ENCRYPTED) ? 1 : 0, + (a->flags & ATTR_IS_SPARSE) ? 1 : 0, sle64_to_cpu(a->allocated_size), sle64_to_cpu(a->data_size), sle64_to_cpu(a->initialized_size), @@ -420,10 +420,10 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, cs ? a->compression_unit : 0); } else { s64 l = le32_to_cpu(a->value_length); - ntfs_attr_init(na, FALSE, a->flags & ATTR_IS_COMPRESSED, - a->flags & ATTR_IS_ENCRYPTED, - a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, - cs ? (l + 7) & ~7 : 0, 0); + ntfs_attr_init(na, FALSE, (a->flags & ATTR_IS_COMPRESSED) ? 1:0, + (a->flags & ATTR_IS_ENCRYPTED) ? 1 : 0, + (a->flags & ATTR_IS_SPARSE) ? 1 : 0, + (l + 7) & ~7, l, l, cs ? (l + 7) & ~7 : 0, 0); } ntfs_attr_put_search_ctx(ctx); return na; @@ -2622,7 +2622,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfs_inode *base_ni; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n", - (long long) ni->mft_no, (unsigned) type, (unsigned) flags); + (long long) ni->mft_no, le32_to_cpu(type), le16_to_cpu(flags)); if (!ni || (!name && name_len)) { errno = EINVAL; @@ -2746,9 +2746,9 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, " "dataruns_size %d, flags 0x%x.\n", - (long long) ni->mft_no, (unsigned) type, + (long long) ni->mft_no, le32_to_cpu(type), (long long) lowest_vcn, dataruns_size, - (unsigned) flags); + le16_to_cpu(flags)); if (!ni || dataruns_size <= 0 || (!name && name_len)) { errno = EINVAL; @@ -3226,7 +3226,7 @@ rm_attr_err_out: free_err_out: /* Free MFT record, if it isn't contain attributes. */ if (le32_to_cpu(attr_ni->mrec->bytes_in_use) - - le32_to_cpu(attr_ni->mrec->attrs_offset) == 8) { + le16_to_cpu(attr_ni->mrec->attrs_offset) == 8) { if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) { ntfs_log_trace("Failed to free MFT record. Leaving " "inconsistent metadata.\n"); diff --git a/libntfs/attrlist.c b/libntfs/attrlist.c index f09d4b42..ce171bf9 100644 --- a/libntfs/attrlist.c +++ b/libntfs/attrlist.c @@ -3,7 +3,7 @@ * project. * * Copyright (c) 2004-2005 Anton Altaparmakov - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -105,7 +105,7 @@ int ntfs_attrlist_need(ntfs_inode *ni) int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) { ATTR_LIST_ENTRY *ale; - MFT_REF mref; + leMFT_REF mref; ntfs_attr *na = NULL; ntfs_attr_search_ctx *ctx; u8 *new_al; @@ -152,7 +152,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*) ((u8*)attr + le16_to_cpu(attr->name_offset)) : AT_UNNAMED, attr->name_length, CASE_SENSITIVE, - (attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) : + (attr->non_resident) ? sle64_to_cpu(attr->lowest_vcn) : 0, (attr->non_resident) ? NULL : ((u8*)attr + le16_to_cpu(attr->value_offset)), (attr->non_resident) ? 0 : le32_to_cpu(attr->value_length), ctx)) { @@ -264,10 +264,10 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx) base_ni = ctx->ntfs_ino; ale = ctx->al_entry; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n", - (long long) ctx->ntfs_ino->mft_no, + ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld." + "\n", (long long) ctx->ntfs_ino->mft_no, (unsigned) le32_to_cpu(ctx->al_entry->type), - (long long) le64_to_cpu(ctx->al_entry->lowest_vcn)); + (long long) sle64_to_cpu(ctx->al_entry->lowest_vcn)); if (!NInoAttrList(base_ni)) { ntfs_log_trace("Attribute list isn't present.\n"); diff --git a/libntfs/dir.c b/libntfs/dir.c index a08fa48f..33684181 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -2,7 +2,7 @@ * dir.c - Directory handling code. Part of the Linux-NTFS project. * * Copyright (c) 2002-2005 Anton Altaparmakov - * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or diff --git a/libntfs/index.c b/libntfs/index.c index 472254db..4d1300c4 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -3,7 +3,7 @@ * * Copyright (c) 2004-2005 Anton Altaparmakov * Copyright (c) 2004-2005 Richard Russon - * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005-2006 Szabolcs Szakacsits * * This program/include file is free software; you can redistribute it and/or @@ -193,9 +193,9 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx) }; } -static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) +static leVCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie) { - return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); + return (leVCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN)); } /** @@ -224,7 +224,7 @@ static u8 *ntfs_ie_get_end(INDEX_HEADER *ih) static int ntfs_ie_end(INDEX_ENTRY *ie) { - return ie->flags & INDEX_ENTRY_END; + return (ie->flags & INDEX_ENTRY_END) ? 1 : 0; } /** @@ -344,7 +344,7 @@ static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) { - *ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn); + *ntfs_ie_get_vcn_addr(ie) = cpu_to_sle64(vcn); } /** @@ -811,8 +811,8 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); /* Set USN to 1 */ - *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); - ib->lsn = cpu_to_le64(0); + *(le16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); + ib->lsn = 0; ib->index_block_vcn = cpu_to_sle64(ib_vcn); diff --git a/libntfs/inode.c b/libntfs/inode.c index a82ebdc0..20518ece 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -2,7 +2,7 @@ * inode.c - Inode handling code. Part of the Linux-NTFS project. * * Copyright (c) 2002-2005 Anton Altaparmakov - * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -343,7 +343,7 @@ int ntfs_inode_close(ntfs_inode *ni) * Note, extent inodes are never closed directly. They are automatically * disposed off by the closing of the base inode. */ -ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) +ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const leMFT_REF mref) { u64 mft_no = MREF_LE(mref); ntfs_inode *ni; @@ -453,8 +453,7 @@ int ntfs_inode_attach_all_extents(ntfs_inode *ni) while ((u8*)ale < ni->attr_list + ni->attr_list_size) { if (ni->mft_no != MREF_LE(ale->mft_reference) && prev_attached != MREF_LE(ale->mft_reference)) { - if (!ntfs_extent_inode_open(ni, - MREF_LE(ale->mft_reference))) { + if (!ntfs_extent_inode_open(ni, ale->mft_reference)) { ntfs_log_trace("Couldn't attach extent " "inode (attr type 0x%x " "references to it).\n", @@ -1143,8 +1142,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) } if (ustr && ntfs_names_are_equal(ustr, len, - (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), - attr->name_length, 0, NULL, 0)) + (ntfschar *)((u8 *)attr + le16_to_cpu( + attr->name_offset)), attr->name_length, 0, NULL, 0)) ret = 1; ntfs_ucsfree(ustr); diff --git a/libntfs/mft.c b/libntfs/mft.c index 6ba963a6..caf491fb 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -2,7 +2,7 @@ * mft.c - Mft record handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov - * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -323,7 +323,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, "Thank you.\n", NTFS_DEV_LIST); } /* Set the update sequence number to 1. */ - *(u16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1); + *(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1); mrec->lsn = cpu_to_le64(0ull); mrec->sequence_number = cpu_to_le16(1); mrec->link_count = cpu_to_le16(0); @@ -1191,7 +1191,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni) ATTR_RECORD *a; ntfs_inode *ni; int err; - u16 seq_no, usn; + le16 seq_no, usn; if (base_ni) ntfs_log_trace("Entering (allocating an extent mft record for " @@ -1389,7 +1389,7 @@ mft_rec_already_initialized: goto undo_mftbmp_alloc; } seq_no = m->sequence_number; - usn = *(u16*)((u8*)m + le16_to_cpu(m->usa_ofs)); + usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)); if (ntfs_mft_record_layout(vol, bit, m)) { err = errno; ntfs_log_error("Failed to re-format mft record.\n"); @@ -1397,11 +1397,10 @@ mft_rec_already_initialized: errno = err; goto undo_mftbmp_alloc; } - if (le16_to_cpu(seq_no)) + if (seq_no) m->sequence_number = seq_no; - seq_no = le16_to_cpu(usn); - if (seq_no && seq_no != 0xffff) - *(u16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; + if (usn && le16_to_cpu(usn) != 0xffff) + *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)) = usn; /* Set the mft record itself in use. */ m->flags |= MFT_RECORD_IN_USE; /* Now need to open an ntfs inode for the mft record. */ @@ -1495,7 +1494,8 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni) { u64 mft_no; int err; - u16 seq_no, old_seq_no; + u16 seq_no; + le16 old_seq_no; ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); @@ -1560,13 +1560,14 @@ sync_rollback: */ int ntfs_mft_usn_dec(MFT_RECORD *mrec) { - u16 usn, *usnp; + u16 usn; + le16 *usnp; if (!mrec) { errno = EINVAL; return -1; } - usnp = (u16 *)((char *)mrec + le16_to_cpu(mrec->usa_ofs)); + usnp = (le16 *)((char *)mrec + le16_to_cpu(mrec->usa_ofs)); usn = le16_to_cpup(usnp); if (usn-- <= 1) usn = 0xfffe; diff --git a/libntfs/mst.c b/libntfs/mst.c index 140700ea..e9ca83b9 100644 --- a/libntfs/mst.c +++ b/libntfs/mst.c @@ -2,6 +2,7 @@ * mst.c - Multi sector fixup handling code. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -130,7 +131,7 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) { u16 usa_ofs, usa_count, usn; - u16 *usa_pos, *data_pos; + le16 *usa_pos, *data_pos, usnle; /* Sanity check + only fixup if it makes sense. */ if (!b || ntfs_is_baad_record(b->magic) || @@ -150,7 +151,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) return -1; } /* Position of usn in update sequence array. */ - usa_pos = (u16*)((u8*)b + usa_ofs); + usa_pos = (le16*)((u8*)b + usa_ofs); /* * Cyclically increment the update sequence number * (skipping 0 and -1, i.e. 0xffff). @@ -158,10 +159,10 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) usn = le16_to_cpup(usa_pos) + 1; if (usn == 0xffff || !usn) usn = 1; - usn = cpu_to_le16(usn); - *usa_pos = usn; + usnle = cpu_to_le16(usn); + *usa_pos = usnle; /* Position in data of first u16 that needs fixing up. */ - data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; + data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1; /* Fixup all sectors. */ while (usa_count--) { /* @@ -170,7 +171,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size) */ *(++usa_pos) = *data_pos; /* Apply fixup to data. */ - *data_pos = usn; + *data_pos = usnle; /* Increment position in data as well. */ data_pos += NTFS_BLOCK_SIZE/sizeof(u16); } diff --git a/libntfs/runlist.c b/libntfs/runlist.c index b729804c..e0170b6b 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -4,7 +4,7 @@ * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2002-2006 Szabolcs Szakacsits - * Copyright (c) 2004 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 53de09e8..bbeb6ccf 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -2,6 +2,7 @@ * unistr.c - Unicode string handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2006 Anton Altaparmakov + * Copyright (c) 2005-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -130,7 +131,7 @@ int ntfs_names_collate(const ntfschar *name1, const u32 name1_len, const u32 upcase_len) { u32 cnt; - ntfschar c1, c2; + u16 c1, c2; #ifdef DEBUG if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) { @@ -187,7 +188,7 @@ int ntfs_names_collate(const ntfschar *name1, const u32 name1_len, */ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n) { - ntfschar c1, c2; + u16 c1, c2; size_t i; #ifdef DEBUG @@ -230,7 +231,7 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n) int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n, const ntfschar *upcase, const u32 upcase_size) { - ntfschar c1, c2; + u16 c1, c2; size_t i; #ifdef DEBUG @@ -323,7 +324,7 @@ void ntfs_name_upcase(ntfschar *name, u32 name_len, const ntfschar *upcase, const u32 upcase_len) { u32 i; - ntfschar u; + u16 u; for (i = 0; i < name_len; i++) if ((u = le16_to_cpu(name[i])) < upcase_len) diff --git a/libntfs/volume.c b/libntfs/volume.c index bc658b40..225e2ee4 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -4,7 +4,7 @@ * Copyright (c) 2000-2006 Anton Altaparmakov * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2004-2005 Richard Russon - * Copyright (c) 2005-2006 Yura Pakhuchiy + * Copyright (c) 2005-2007 Yura Pakhuchiy * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -849,14 +849,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); if (mrec->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_recordp(mrec)) { + if (ntfs_is_baad_record(mrec->magic)) { ntfs_log_debug("FAILED\n"); ntfs_log_debug("$MFT error: Incomplete multi " "sector transfer detected in " "%s.\n", s); goto io_error_exit; } - if (!ntfs_is_mft_recordp(mrec)) { + if (!ntfs_is_mft_record(mrec->magic)) { ntfs_log_debug("FAILED\n"); ntfs_log_debug("$MFT error: Invalid mft " "record for %s.\n", s); @@ -865,14 +865,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) } mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); if (mrec2->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_recordp(mrec2)) { + if (ntfs_is_baad_record(mrec2->magic)) { ntfs_log_debug("FAILED\n"); ntfs_log_debug("$MFTMirr error: Incomplete " "multi sector transfer " "detected in %s.\n", s); goto io_error_exit; } - if (!ntfs_is_mft_recordp(mrec2)) { + if (!ntfs_is_mft_record(mrec2->magic)) { ntfs_log_debug("FAILED\n"); ntfs_log_debug("$MFTMirr error: Invalid mft " "record for %s.\n", s); @@ -1076,12 +1076,12 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) goto error_exit; } for (j = 0; j < (s32)u; j++) { - ntfschar uc = le16_to_cpu(vname[j]); + u16 uc = le16_to_cpu(vname[j]); if (uc > 0xff) - uc = (ntfschar)'_'; + uc = (u16)'_'; vol->vol_name[j] = (char)uc; } - vol->vol_name[u] = '\0'; + vol->vol_name[u] = 0; } } ntfs_log_debug(OK); @@ -1506,7 +1506,7 @@ error_exit: * * Return 0 if successful and -1 if not with errno set to the error code. */ -int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) +int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags) { ATTR_RECORD *a; VOLUME_INFORMATION *c; diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index b6c4fe47..3ba6d439 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -5,6 +5,7 @@ * Copyright (c) 2001-2005 Richard Russon * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2005 Erik Sornes + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will create an NTFS 1.2 or 3.1 volume on a user * specified (block) device. @@ -209,35 +210,35 @@ static void mkntfs_license(void) static void mkntfs_usage(void) { ntfs_log_info("\nUsage: %s [options] device [number-of-sectors]\n" - "\n" - "Basic options:\n" - " -f, --fast Perform a quick format\n" - " -Q, --quick Perform a quick format\n" - " -L, --label STRING Set the volume label\n" - " -C, --enable-compression Enable compression on the volume\n" - " -I, --no-indexing Disable indexing on the volume\n" - " -n, --no-action Do not write to disk\n" - "\n" - "Advanced options:\n" - " -c, --cluster-size BYTES Specify the cluster size for the volume\n" - " -s, --sector-size BYTES Specify the sector size for the device\n" - " -p, --partition-start SECTOR Specify the partition start sector\n" - " -H, --heads NUM Specify the number of heads\n" - " -S, --sectors-per-track NUM Specify the number of sectors per track\n" - " -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" - " -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" - " -F, --force Force execution despite errors\n" - "\n" - "Output options:\n" - " -q, --quiet Quiet execution\n" - " -v, --verbose Verbose execution\n" - " --debug Very verbose execution\n" - "\n" - "Help options:\n" - " -V, --version Display version\n" - " -l, --license Display licensing information\n" - " -h, --help Display this help\n" - "\n", basename(EXEC_NAME)); +"\n" +"Basic options:\n" +" -f, --fast Perform a quick format\n" +" -Q, --quick Perform a quick format\n" +" -L, --label STRING Set the volume label\n" +" -C, --enable-compression Enable compression on the volume\n" +" -I, --no-indexing Disable indexing on the volume\n" +" -n, --no-action Do not write to disk\n" +"\n" +"Advanced options:\n" +" -c, --cluster-size BYTES Specify the cluster size for the volume\n" +" -s, --sector-size BYTES Specify the sector size for the device\n" +" -p, --partition-start SECTOR Specify the partition start sector\n" +" -H, --heads NUM Specify the number of heads\n" +" -S, --sectors-per-track NUM Specify the number of sectors per track\n" +" -z, --mft-zone-multiplier NUM Set the MFT zone multiplier\n" +" -T, --zero-time Fake the time to be 00:00 UTC, Jan 1, 1970\n" +" -F, --force Force execution despite errors\n" +"\n" +"Output options:\n" +" -q, --quiet Quiet execution\n" +" -v, --verbose Verbose execution\n" +" --debug Very verbose execution\n" +"\n" +"Help options:\n" +" -V, --version Display version\n" +" -l, --license Display licensing information\n" +" -h, --help Display this help\n" +"\n", basename(EXEC_NAME)); ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); } @@ -246,12 +247,15 @@ static void mkntfs_usage(void) */ static void mkntfs_version(void) { - ntfs_log_info("\n%s v%s (libntfs %s)\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); - ntfs_log_info("Create an NTFS volume on a user specified (block) device.\n\n"); + ntfs_log_info("\n%s v%s (libntfs %s)\n\n", EXEC_NAME, VERSION, + ntfs_libntfs_version()); + ntfs_log_info("Create an NTFS volume on a user specified (block) " + "device.\n\n"); ntfs_log_info("Copyright (c) 2000-2007 Anton Altaparmakov\n"); ntfs_log_info("Copyright (c) 2001-2005 Richard Russon\n"); ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); + ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -285,7 +289,8 @@ static BOOL mkntfs_parse_long(const char *string, const char *name, long *num) /** * mkntfs_parse_llong */ -static BOOL mkntfs_parse_llong(const char *string, const char *name, long long *num) +static BOOL mkntfs_parse_llong(const char *string, const char *name, + long long *num) { char *end = NULL; long long tmp; @@ -300,7 +305,8 @@ static BOOL mkntfs_parse_llong(const char *string, const char *name, long long * tmp = strtoll(string, &end, 0); if (end && *end) { - ntfs_log_error("Cannot understand the %s '%s'.\n", name, string); + ntfs_log_error("Cannot understand the %s '%s'.\n", name, + string); return FALSE; } else { *num = tmp; @@ -364,7 +370,8 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * int ver = 0; if (!argv || !opts2) { - ntfs_log_error("Internal error: invalid parameters to mkntfs_options.\n"); + ntfs_log_error("Internal error: invalid parameters to " + "mkntfs_options.\n"); return FALSE; } @@ -374,15 +381,18 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * switch (c) { case 1: /* A device, or a number of sectors */ if (!opts2->dev_name) - opts2->dev_name = argv[optind-1]; - else if (!mkntfs_parse_llong(optarg, "number of sectors", &opts2->num_sectors)) + opts2->dev_name = argv[optind - 1]; + else if (!mkntfs_parse_llong(optarg, + "number of sectors", + &opts2->num_sectors)) err++; break; case 'C': opts2->enable_compression = TRUE; break; case 'c': - if (!mkntfs_parse_long(optarg, "cluster size", &opts2->cluster_size)) + if (!mkntfs_parse_long(optarg, "cluster size", + &opts2->cluster_size)) err++; break; case 'F': @@ -406,7 +416,8 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * if (!opts2->label) { opts2->label = argv[optind-1]; } else { - ntfs_log_error("You may only specify the label once.\n"); + ntfs_log_error("You may only specify the label " + "once.\n"); err++; } break; @@ -417,34 +428,45 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * opts2->no_action = TRUE; break; case 'p': - if (!mkntfs_parse_llong(optarg, "partition start", &opts2->part_start_sect)) + if (!mkntfs_parse_llong(optarg, "partition start", + &opts2->part_start_sect)) err++; break; case 'q': - ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_PROGRESS); + ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET | + NTFS_LOG_LEVEL_VERBOSE | + NTFS_LOG_LEVEL_PROGRESS); break; case 's': - if (!mkntfs_parse_long(optarg, "sector size", &opts2->sector_size)) + if (!mkntfs_parse_long(optarg, "sector size", + &opts2->sector_size)) err++; break; case 'S': - if (!mkntfs_parse_long(optarg, "sectors per track", &opts2->sectors_per_track)) + if (!mkntfs_parse_long(optarg, "sectors per track", + &opts2->sectors_per_track)) err++; break; case 'T': opts2->use_epoch_time = TRUE; break; case 'v': - ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_PROGRESS); + ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET | + NTFS_LOG_LEVEL_VERBOSE | + NTFS_LOG_LEVEL_PROGRESS); break; case 'V': ver++; /* display version info */ break; case 'Z': /* debug - turn on everything */ - ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_QUIET); + ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | + NTFS_LOG_LEVEL_TRACE | + NTFS_LOG_LEVEL_VERBOSE | + NTFS_LOG_LEVEL_QUIET); break; case 'z': - if (!mkntfs_parse_long(optarg, "mft zone multiplier", &opts2->mft_zone_multiplier)) + if (!mkntfs_parse_long(optarg, "mft zone multiplier", + &opts2->mft_zone_multiplier)) err++; break; default: @@ -455,9 +477,11 @@ static BOOL mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options * (optopt == 's') || (optopt == 'S') || (optopt == 'N') || (optopt == 'z')) && (!optarg)) { - ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]); + ntfs_log_error("Option '%s' requires an " + "argument.\n", argv[optind-1]); } else if (optopt != '?') { - ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]); + ntfs_log_error("Unknown option '%s'.\n", + argv[optind - 1]); } err++; break; @@ -1137,8 +1161,8 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, err = -EOPNOTSUPP; goto err_out; } - if (flags & (ATTR_IS_ENCRYPTED || ATTR_IS_SPARSE)) { - ntfs_log_error("Encrypted/sparse attributes not supported yet.\n"); + if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { + ntfs_log_error("Encrypted/sparse attributes not supported.\n"); err = -EOPNOTSUPP; goto err_out; } @@ -1213,18 +1237,18 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); a->lowest_vcn = cpu_to_le64(0); - a->highest_vcn = cpu_to_le64(highest_vcn - 1LL); + a->highest_vcn = cpu_to_sle64(highest_vcn - 1LL); a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); memset(a->reserved1, 0, sizeof(a->reserved1)); /* FIXME: Allocated size depends on compression. */ - a->allocated_size = cpu_to_le64(highest_vcn * g_vol->cluster_size); - a->data_size = cpu_to_le64(val_len); + a->allocated_size = cpu_to_sle64(highest_vcn * g_vol->cluster_size); + a->data_size = cpu_to_sle64(val_len); if (name_len) memcpy((char*)a + hdr_size, uname, name_len << 1); if (flags & ATTR_COMPRESSION_MASK) { if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { - ntfs_log_error("Unknown compression format. Reverting to " - "standard compression.\n"); + ntfs_log_error("Unknown compression format. Reverting " + "to standard compression.\n"); a->flags &= ~ATTR_COMPRESSION_MASK; a->flags |= ATTR_IS_COMPRESSED; } @@ -1239,21 +1263,22 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, a->compression_unit = 0; bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, &inited_size); if (bw != val_len) { - ntfs_log_error("Error writing non-resident attribute value.\n"); + ntfs_log_error("Error writing non-resident attribute " + "value.\n"); return -errno; } err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + ((name_len + 7) & ~7), mpa_size, rl, 0, NULL); } - a->initialized_size = cpu_to_le64(inited_size); + a->initialized_size = cpu_to_sle64(inited_size); if (err < 0 || bw != val_len) { /* FIXME: Handle error. */ /* deallocate clusters */ /* remove attribute */ if (err >= 0) err = -EIO; - ntfs_log_error("insert_positioned_attr_in_mft_record failed with " - "error %i.\n", err < 0 ? err : (int)bw); + ntfs_log_error("insert_positioned_attr_in_mft_record failed " + "with error %i.\n", err < 0 ? err : (int)bw); } err_out: if (ctx) @@ -1319,8 +1344,8 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, err = -EOPNOTSUPP; goto err_out; } - if (flags & (ATTR_IS_ENCRYPTED || ATTR_IS_SPARSE)) { - ntfs_log_error("Encrypted/sparse attributes not supported yet.\n"); + if (flags & (ATTR_IS_ENCRYPTED | ATTR_IS_SPARSE)) { + ntfs_log_error("Encrypted/sparse attributes not supported.\n"); err = -EOPNOTSUPP; goto err_out; } @@ -1399,14 +1424,14 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, a->lowest_vcn = cpu_to_le64(0); for (i = 0; rl[i].length; i++) ; - a->highest_vcn = cpu_to_le64(rl[i].vcn - 1); + a->highest_vcn = cpu_to_sle64(rl[i].vcn - 1); a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); memset(a->reserved1, 0, sizeof(a->reserved1)); /* FIXME: Allocated size depends on compression. */ - a->allocated_size = cpu_to_le64((val_len + (g_vol->cluster_size - 1)) & + a->allocated_size = cpu_to_sle64((val_len + (g_vol->cluster_size - 1)) & ~(g_vol->cluster_size - 1)); - a->data_size = cpu_to_le64(val_len); - a->initialized_size = cpu_to_le64(val_len); + a->data_size = cpu_to_sle64(val_len); + a->initialized_size = cpu_to_sle64(val_len); if (name_len) memcpy((char*)a + hdr_size, uname, name_len << 1); if (flags & ATTR_COMPRESSION_MASK) { @@ -1563,7 +1588,7 @@ err_out: * Return 0 on success or -errno on error. */ static int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, - u32 security_id) + le32 security_id) { STANDARD_INFORMATION si; int err, sd_size; @@ -1599,7 +1624,7 @@ static int add_attr_std_info(MFT_RECORD *m, const FILE_ATTR_FLAGS flags, * * Return 0 on success or -errno on error. */ -static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, +static int add_attr_file_name(MFT_RECORD *m, const leMFT_REF parent_dir, const s64 allocated_size, const s64 data_size, const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, const u32 reparse_point_tag, const char *file_name, @@ -1614,14 +1639,14 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, /* Check if the attribute is already there. */ ctx = ntfs_attr_get_search_ctx(NULL, m); if (!ctx) { - ntfs_log_error("Failed to allocate attribute search context.\n"); + ntfs_log_error("Failed to get attribute search context.\n"); return -ENOMEM; } - if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, - ctx)) { + if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, + NULL, 0, ctx)) { int eo = errno; - ntfs_log_error("BUG: Standard information attribute not present in " - "file record\n"); + ntfs_log_error("BUG: Standard information attribute not " + "present in file record.\n"); ntfs_attr_put_search_ctx(ctx); return -eo; } @@ -1642,8 +1667,8 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, fn->last_access_time = si->last_access_time; ntfs_attr_put_search_ctx(ctx); - fn->allocated_size = cpu_to_le64(allocated_size); - fn->data_size = cpu_to_le64(data_size); + fn->allocated_size = cpu_to_sle64(allocated_size); + fn->data_size = cpu_to_sle64(data_size); fn->file_attributes = flags; /* These are in a union so can't have both. */ if (packed_ea_size && reparse_point_tag) { @@ -1896,8 +1921,8 @@ static int add_attr_index_root(MFT_RECORD *m, const char *name, return -EINVAL; } if (index_block_size < (u32)opts.sector_size) { - ntfs_log_error("add_attr_index_root: index block size is " - "smaller than the sector size.\n"); + ntfs_log_error("add_attr_index_root: index block size " + "is smaller than the sector size.\n"); free(r); return -EINVAL; } @@ -2084,7 +2109,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, "Thank you.", NTFS_DEV_LIST); } /* Set USN to 1. */ - *(u16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = + *(le16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = cpu_to_le16(1); ia_val->lsn = cpu_to_le64(0); ia_val->index_block_vcn = cpu_to_le64(0); @@ -2129,8 +2154,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, goto err_out; } /* Set VCN pointer to 0LL. */ - *(VCN*)((char*)re + cpu_to_le16(re->length) - sizeof(VCN)) = - cpu_to_le64(0); + *(leVCN*)((char*)re + le16_to_cpu(re->length) - sizeof(VCN)) = 0; err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)ia_val, index_block_size); if (err) { err = -errno; @@ -2482,7 +2506,7 @@ static int initialize_secure(char *sds, u32 sds_size, MFT_RECORD *m) */ static int initialize_quota(MFT_RECORD *m) { - int o_size, q1_size, q2_size, err; + int o_size, q1_size, q2_size, err, i; INDEX_ENTRY *idx_entry_o, *idx_entry_q1, *idx_entry_q2; QUOTA_O_INDEX_DATA *idx_entry_o_data; QUOTA_CONTROL_ENTRY *idx_entry_q1_data, *idx_entry_q2_data; @@ -2507,8 +2531,8 @@ static int initialize_quota(MFT_RECORD *m) idx_entry_q1_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; idx_entry_q1_data->bytes_used = const_cpu_to_le64(0x00); idx_entry_q1_data->change_time = utc2ntfs(mkntfs_time()); - idx_entry_q1_data->threshold = const_cpu_to_le64((s64)-1); - idx_entry_q1_data->limit = const_cpu_to_le64((s64)-1); + idx_entry_q1_data->threshold = cpu_to_sle64(-1); + idx_entry_q1_data->limit = cpu_to_sle64(-1); idx_entry_q1_data->exceeded_time = const_cpu_to_le64(0x00); err = insert_index_entry_in_res_dir_index(idx_entry_q1, q1_size, m, NTFS_INDEX_Q, 2, AT_UNUSED); @@ -2534,15 +2558,14 @@ static int initialize_quota(MFT_RECORD *m) idx_entry_q2_data->flags = QUOTA_FLAG_DEFAULT_LIMITS; idx_entry_q2_data->bytes_used = const_cpu_to_le64(0x00); idx_entry_q2_data->change_time = utc2ntfs(mkntfs_time());; - idx_entry_q2_data->threshold = const_cpu_to_le64((s64)-1); - idx_entry_q2_data->limit = const_cpu_to_le64((s64)-1); + idx_entry_q2_data->threshold = cpu_to_sle64(-1); + idx_entry_q2_data->limit = cpu_to_sle64(-1); idx_entry_q2_data->exceeded_time = const_cpu_to_le64(0x00); idx_entry_q2_data->sid.revision = 1; idx_entry_q2_data->sid.sub_authority_count = 2; - idx_entry_q2_data->sid.identifier_authority.high_part = - const_cpu_to_le16(0x0000); - idx_entry_q2_data->sid.identifier_authority.low_part = - const_cpu_to_le32(0x05000000); + for (i = 0; i < 5; i++) + idx_entry_q2_data->sid.identifier_authority.value[i] = 0; + idx_entry_q2_data->sid.identifier_authority.value[5] = 0x05; idx_entry_q2_data->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); idx_entry_q2_data->sid.sub_authority[1] = @@ -2565,10 +2588,9 @@ static int initialize_quota(MFT_RECORD *m) idx_entry_o->reserved = const_cpu_to_le16(0x00); idx_entry_o->key.sid.revision = 0x01; idx_entry_o->key.sid.sub_authority_count = 0x02; - idx_entry_o->key.sid.identifier_authority.high_part = - const_cpu_to_le16(0x0000); - idx_entry_o->key.sid.identifier_authority.low_part = - const_cpu_to_le32(0x05000000); + for (i = 0; i < 5; i++) + idx_entry_o->key.sid.identifier_authority.value[i] = 0; + idx_entry_o->key.sid.identifier_authority.value[5] = 0x05; idx_entry_o->key.sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); idx_entry_o->key.sid.sub_authority[1] = @@ -2594,7 +2616,7 @@ static int initialize_quota(MFT_RECORD *m) * * Return 0 on success or -errno on error. */ -static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, MFT_REF file_ref, +static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, leMFT_REF file_ref, FILE_NAME_ATTR *file_name, u32 file_name_size) { int err, i; @@ -2627,7 +2649,8 @@ static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, MFT_REF file_ref, if (i < 0) ntfs_log_debug("Name contains non-displayable " "Unicode characters.\n"); - ntfs_log_debug("file_name_attr1->file_name = %s\n", __buf); + ntfs_log_debug("file_name_attr1->file_name = %s\n", + __buf); free(__buf); } ntfs_log_debug("file_name_attr2->file_name_length = %i\n", @@ -2635,11 +2658,13 @@ static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, MFT_REF file_ref, if (ie->key.file_name.file_name_length) { char *__buf = NULL; i = ntfs_ucstombs(ie->key.file_name.file_name, - ie->key.file_name.file_name_length + 1, &__buf, 0); + ie->key.file_name.file_name_length + 1, &__buf, + 0); if (i < 0) ntfs_log_debug("Name contains non-displayable " "Unicode characters.\n"); - ntfs_log_debug("file_name_attr2->file_name = %s\n", __buf); + ntfs_log_debug("file_name_attr2->file_name = %s\n", + __buf); free(__buf); } #endif @@ -2670,7 +2695,8 @@ static int insert_file_link_in_dir_index(INDEX_BLOCK *idx, MFT_REF file_ref, return -EEXIST; i = ntfs_file_values_compare(file_name, (FILE_NAME_ATTR*)&ie->key.file_name, 1, - CASE_SENSITIVE, g_vol->upcase, g_vol->upcase_len); + CASE_SENSITIVE, g_vol->upcase, + g_vol->upcase_len); if (i == -1) break; /* Complete match. Bugger. Can't insert. */ @@ -2680,7 +2706,8 @@ do_next: #ifdef DEBUG /* Next entry. */ if (!ie->length) { - ntfs_log_debug("BUG: ie->length is zero, breaking out of loop.\n"); + ntfs_log_debug("BUG: ie->length is zero, breaking out " + "of loop.\n"); break; } #endif @@ -2689,8 +2716,8 @@ do_next: i = (sizeof(INDEX_ENTRY_HEADER) + file_name_size + 7) & ~7; err = make_room_for_index_entry_in_index_block(idx, ie, i); if (err) { - ntfs_log_error("make_room_for_index_entry_in_index_block failed: " - "%s\n", strerror(-err)); + ntfs_log_error("make_room_for_index_entry_in_index_block " + "failed: %s\n", strerror(-err)); return err; } /* Create entry in place and copy file name attribute value. */ @@ -2716,8 +2743,8 @@ do_next: * * Return 0 on success or -errno on error. */ -static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, - MFT_RECORD *m_file, const MFT_REF ref_file, +static int create_hardlink_res(MFT_RECORD *m_parent, const leMFT_REF ref_parent, + MFT_RECORD *m_file, const leMFT_REF ref_file, const s64 allocated_size, const s64 data_size, const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, const u32 reparse_point_tag, const char *file_name, @@ -2740,8 +2767,8 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, fn->last_data_change_time = fn->creation_time; fn->last_mft_change_time = fn->creation_time; fn->last_access_time = fn->creation_time; - fn->allocated_size = cpu_to_le64(allocated_size); - fn->data_size = cpu_to_le64(data_size); + fn->allocated_size = cpu_to_sle64(allocated_size); + fn->data_size = cpu_to_sle64(data_size); fn->file_attributes = flags; /* These are in a union so can't have both. */ if (packed_ea_size && reparse_point_tag) { @@ -2784,8 +2811,8 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, i = insert_resident_attr_in_mft_record(m_file, AT_FILE_NAME, NULL, 0, 0, 0, RESIDENT_ATTR_IS_INDEXED, (u8*)fn, fn_size); if (i < 0) { - ntfs_log_error("create_hardlink failed adding file name attribute: " - "%s\n", strerror(-i)); + ntfs_log_error("create_hardlink failed adding file name " + "attribute: %s\n", strerror(-i)); free(fn); /* Undo link count increment. */ m_file->link_count = cpu_to_le16( @@ -2804,8 +2831,8 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, i = insert_index_entry_in_res_dir_index(idx_entry_new, idx_size + 0x10, m_parent, NTFS_INDEX_I30, 4, AT_FILE_NAME); if (i < 0) { - ntfs_log_error("create_hardlink failed inserting index entry: %s\n", - strerror(-i)); + ntfs_log_error("create_hardlink failed inserting index entry: " + "%s\n", strerror(-i)); /* FIXME: Remove the file name attribute from @m_file. */ free(idx_entry_new); free(fn); @@ -2832,8 +2859,8 @@ static int create_hardlink_res(MFT_RECORD *m_parent, const MFT_REF ref_parent, * * Return 0 on success or -errno on error. */ -static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, - MFT_RECORD *m_file, const MFT_REF ref_file, +static int create_hardlink(INDEX_BLOCK *idx, const leMFT_REF ref_parent, + MFT_RECORD *m_file, const leMFT_REF ref_file, const s64 allocated_size, const s64 data_size, const FILE_ATTR_FLAGS flags, const u16 packed_ea_size, const u32 reparse_point_tag, const char *file_name, @@ -2856,8 +2883,8 @@ static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, fn->last_data_change_time = fn->creation_time; fn->last_mft_change_time = fn->creation_time; fn->last_access_time = fn->creation_time; - fn->allocated_size = cpu_to_le64(allocated_size); - fn->data_size = cpu_to_le64(data_size); + fn->allocated_size = cpu_to_sle64(allocated_size); + fn->data_size = cpu_to_sle64(data_size); fn->file_attributes = flags; /* These are in a union so can't have both. */ if (packed_ea_size && reparse_point_tag) { @@ -2932,7 +2959,7 @@ static int create_hardlink(INDEX_BLOCK *idx, const MFT_REF ref_parent, * Return 0 on success or -errno on error. */ static int index_obj_id_insert(MFT_RECORD *m, const GUID *guid, - const MFT_REF ref) + const leMFT_REF ref) { INDEX_ENTRY *idx_entry_new; int data_ofs, idx_size, err; @@ -3840,7 +3867,7 @@ static BOOL mkntfs_sync_index_record(INDEX_ALLOCATION* idx, MFT_RECORD* m, /** * create_file_volume - */ -static BOOL create_file_volume(MFT_RECORD *m, MFT_REF root_ref, +static BOOL create_file_volume(MFT_RECORD *m, leMFT_REF root_ref, VOLUME_FLAGS fl, const GUID *volume_guid #ifndef ENABLE_UUID __attribute__((unused)) @@ -3943,8 +3970,8 @@ static BOOL mkntfs_create_root_structures(void) { NTFS_BOOT_SECTOR *bs; MFT_RECORD *m; - MFT_REF root_ref; - MFT_REF extend_ref; + leMFT_REF root_ref; + leMFT_REF extend_ref; int i; int j; int err; @@ -3970,7 +3997,8 @@ static BOOL mkntfs_create_root_structures(void) for (i = 0; i < nr_sysfiles; i++) { if (ntfs_mft_record_layout(g_vol, 0, m = (MFT_RECORD *)(g_buf + i * g_vol->mft_record_size))) { - ntfs_log_error("Failed to layout system mft records.\n"); + ntfs_log_error("Failed to layout system mft records." + "\n"); return FALSE; } if (i == 0 || i > 23) @@ -3987,7 +4015,8 @@ static BOOL mkntfs_create_root_structures(void) i * (s32)g_vol->mft_record_size < g_mft_size; i++) { m = (MFT_RECORD *)(g_buf + i * g_vol->mft_record_size); if (ntfs_mft_record_layout(g_vol, 0, m)) { - ntfs_log_error("Failed to layout mft record.\n"); + ntfs_log_error("Failed to layout mft record." + "\n"); return FALSE; } m->flags = cpu_to_le16(0); @@ -3999,7 +4028,7 @@ static BOOL mkntfs_create_root_structures(void) * to each as well as marking them in use in the mft bitmap. */ for (i = 0; i < nr_sysfiles; i++) { - u32 file_attrs; + le32 file_attrs; m = (MFT_RECORD*)(g_buf + i * g_vol->mft_record_size); if (i < 16 || i > 23) { @@ -4065,14 +4094,16 @@ static BOOL mkntfs_create_root_structures(void) ATTR_RECORD *a; ctx = ntfs_attr_get_search_ctx(NULL, m); if (!ctx) { - ntfs_log_perror("Failed to allocate attribute search context"); + ntfs_log_perror("Failed to allocate attribute search " + "context"); return FALSE; } /* There is exactly one file name so this is ok. */ - if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, - ctx)) { + if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, + 0, ctx)) { ntfs_attr_put_search_ctx(ctx); - ntfs_log_error("BUG: $FILE_NAME attribute not found.\n"); + ntfs_log_error("BUG: $FILE_NAME attribute not found." + "\n"); return FALSE; } a = ctx->attr; @@ -4118,7 +4149,8 @@ static BOOL mkntfs_create_root_structures(void) FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$MFTMirr", FILE_NAME_WIN32_AND_DOS); if (err < 0) { - ntfs_log_error("Couldn't create $MFTMirr: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $MFTMirr: %s\n", + strerror(-err)); return FALSE; } ntfs_log_verbose("Creating $LogFile (mft record 2)\n"); @@ -4138,12 +4170,14 @@ static BOOL mkntfs_create_root_structures(void) FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$LogFile", FILE_NAME_WIN32_AND_DOS); if (err < 0) { - ntfs_log_error("Couldn't create $LogFile: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $LogFile: %s\n", + strerror(-err)); return FALSE; } ntfs_log_verbose("Creating $AttrDef (mft record 4)\n"); m = (MFT_RECORD*)(g_buf + 4 * g_vol->mft_record_size); - err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->attrdef, g_vol->attrdef_len); + err = add_attr_data(m, NULL, 0, 0, 0, (u8*)g_vol->attrdef, + g_vol->attrdef_len); if (!err) err = create_hardlink(g_index_block, root_ref, m, MK_LE_MREF(FILE_AttrDef, FILE_AttrDef), @@ -4156,7 +4190,8 @@ static BOOL mkntfs_create_root_structures(void) err = add_attr_sd(m, sd, i); } if (err < 0) { - ntfs_log_error("Couldn't create $AttrDef: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $AttrDef: %s\n", + strerror(-err)); return FALSE; } ntfs_log_verbose("Creating $Bitmap (mft record 6)\n"); @@ -4172,8 +4207,9 @@ static BOOL mkntfs_create_root_structures(void) if (!err) err = create_hardlink(g_index_block, root_ref, m, MK_LE_MREF(FILE_Bitmap, FILE_Bitmap), - (g_lcn_bitmap_byte_size + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1), g_lcn_bitmap_byte_size, + (g_lcn_bitmap_byte_size + g_vol->cluster_size - + 1) & ~(g_vol->cluster_size - 1), + g_lcn_bitmap_byte_size, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$Bitmap", FILE_NAME_WIN32_AND_DOS); if (err < 0) { @@ -4196,8 +4232,8 @@ static BOOL mkntfs_create_root_structures(void) opts.sector_size); bs->bpb.media_type = 0xf8; /* hard disk */ bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track); - ntfs_log_debug("sectors per track = %ld (0x%lx)\n", opts.sectors_per_track, - opts.sectors_per_track); + ntfs_log_debug("sectors per track = %ld (0x%lx)\n", + opts.sectors_per_track, opts.sectors_per_track); bs->bpb.heads = cpu_to_le16(opts.heads); ntfs_log_debug("heads = %ld (0x%lx)\n", opts.heads, opts.heads); bs->bpb.hidden_sectors = cpu_to_le32(opts.part_start_sect); @@ -4212,12 +4248,13 @@ static BOOL mkntfs_create_root_structures(void) bs->clusters_per_mft_record = g_vol->mft_record_size / g_vol->cluster_size; } else { - bs->clusters_per_mft_record = -(ffs(g_vol->mft_record_size) - 1); + bs->clusters_per_mft_record = -(ffs(g_vol->mft_record_size) - + 1); if ((u32)(1 << -bs->clusters_per_mft_record) != g_vol->mft_record_size) { free(bs); - ntfs_log_error("BUG: calculated clusters_per_mft_record " - "is wrong (= 0x%x)\n", + ntfs_log_error("BUG: calculated clusters_per_mft_record" + " is wrong (= 0x%x)\n", bs->clusters_per_mft_record); return FALSE; } @@ -4230,10 +4267,12 @@ static BOOL mkntfs_create_root_structures(void) g_vol->cluster_size; } else { bs->clusters_per_index_record = -g_vol->indx_record_size_bits; - if ((1 << -bs->clusters_per_index_record) != (s32)g_vol->indx_record_size) { + if ((1 << -bs->clusters_per_index_record) != + (s32)g_vol->indx_record_size) { free(bs); - ntfs_log_error("BUG: calculated clusters_per_index_record " - "is wrong (= 0x%x)\n", + ntfs_log_error("BUG: calculated " + "clusters_per_index_record is wrong " + "(= 0x%x)\n", bs->clusters_per_index_record); return FALSE; } @@ -4242,8 +4281,8 @@ static BOOL mkntfs_create_root_structures(void) bs->clusters_per_index_record, bs->clusters_per_index_record); /* Generate a 64-bit random number for the serial number. */ - bs->volume_serial_number = cpu_to_sle64(((s64)random() << 32) | - ((s64)random() & 0xffffffff)); + bs->volume_serial_number = cpu_to_le64(((u64)random() << 32) | + ((u64)random() & 0xffffffff)); /* * Leave zero for now as NT4 leaves it zero, too. If want it later, see * ../libntfs/bootsect.c for how to calculate it. @@ -4255,7 +4294,8 @@ static BOOL mkntfs_create_root_structures(void) ntfs_log_error("FATAL: Generated boot sector is invalid!\n"); return FALSE; } - err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_boot, (u8*)bs, 8192); + err = add_attr_data_positioned(m, NULL, 0, 0, 0, g_rl_boot, (u8*)bs, + 8192); if (!err) err = create_hardlink(g_index_block, root_ref, m, MK_LE_MREF(FILE_Boot, FILE_Boot), @@ -4311,7 +4351,8 @@ static BOOL mkntfs_create_root_structures(void) 0, 0, "$BadClus", FILE_NAME_WIN32_AND_DOS); } if (err < 0) { - ntfs_log_error("Couldn't create $BadClus: %s\n", strerror(-err)); + ntfs_log_error("Couldn't create $BadClus: %s\n", + strerror(-err)); return FALSE; } /* create $Secure (NTFS 3.0+) */ @@ -4365,7 +4406,8 @@ static BOOL mkntfs_create_root_structures(void) MK_LE_MREF(FILE_UpCase, FILE_UpCase), ((g_vol->upcase_len << 1) + g_vol->cluster_size - 1) & - ~(g_vol->cluster_size - 1), g_vol->upcase_len << 1, + ~(g_vol->cluster_size - 1), + g_vol->upcase_len << 1, FILE_ATTR_HIDDEN | FILE_ATTR_SYSTEM, 0, 0, "$UpCase", FILE_NAME_WIN32_AND_DOS); if (err < 0) { @@ -4404,8 +4446,8 @@ static BOOL mkntfs_create_root_structures(void) err = add_attr_sd(m, sd, j); } if (err < 0) { - ntfs_log_error("Couldn't create system file %i (0x%x): %s\n", - i, i, strerror(-err)); + ntfs_log_error("Couldn't create system file %i (0x%x): " + "%s\n", i, i, strerror(-err)); return FALSE; } } diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index 57d2af69..88a12fe8 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -4,6 +4,7 @@ * Copyright (c) 2003-2005 Richard Russon * Copyright (c) 2003-2005 Anton Altaparmakov * Copyright (c) 2003-2005 Szabolcs Szakacsits + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will concatenate files and print on the standard output. * @@ -59,12 +60,13 @@ static struct options opts; */ static void version(void) { - ntfs_log_info("\n%s v%s (libntfs %s) - Concatenate files and print on the " - "standard output.\n\n", EXEC_NAME, VERSION, + ntfs_log_info("\n%s v%s (libntfs %s) - Concatenate files and print " + "on the standard output.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); ntfs_log_info("Copyright (c) 2003-2005 Richard Russon\n"); ntfs_log_info("Copyright (c) 2003-2005 Anton Altaparmakov\n"); ntfs_log_info("Copyright (c) 2003-2005 Szabolcs Szakacsits\n"); + ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -131,15 +133,15 @@ static int parse_attribute(const char *value, ATTR_TYPES *attr) for (i = 0; attr_name[i]; i++) { if ((strcmp(value, attr_name[i]) == 0) || - (strcmp(value, attr_name[i]+1) == 0)) { - *attr = (ATTR_TYPES) ((i+1)*16); + (strcmp(value, attr_name[i] + 1) == 0)) { + *attr = (ATTR_TYPES)cpu_to_le32((i + 1) * 16); return 1; } } num = strtol(value, NULL, 0); if ((num > 0) && (num < 257)) { - *attr = (ATTR_TYPES) num; + *attr = (ATTR_TYPES)cpu_to_le32(num); return 1; } @@ -181,7 +183,7 @@ static int parse_options(int argc, char **argv) opterr = 0; /* We'll handle the errors, thank you. */ opts.inode = -1; - opts.attr = -1; + opts.attr = cpu_to_le32(-1); opts.attr_name = NULL; opts.attr_name_len = 0; @@ -189,17 +191,19 @@ static int parse_options(int argc, char **argv) switch (c) { case 1: /* A non-option argument */ if (!opts.device) { - opts.device = argv[optind-1]; + opts.device = argv[optind - 1]; } else if (!opts.file) { - opts.file = argv[optind-1]; + opts.file = argv[optind - 1]; } else { - ntfs_log_error("You must specify exactly one file.\n"); + ntfs_log_error("You must specify exactly one " + "file.\n"); err++; } break; case 'a': - if (opts.attr != (ATTR_TYPES)-1) { - ntfs_log_error("You must specify exactly one attribute.\n"); + if (opts.attr != cpu_to_le32(-1)) { + ntfs_log_error("You must specify exactly one " + "attribute.\n"); } else if (parse_attribute(optarg, &attr) > 0) { opts.attr = attr; break; @@ -234,7 +238,8 @@ static int parse_options(int argc, char **argv) opts.attr_name_len = ntfs_mbstoucs(optarg, &opts.attr_name, 0); if (opts.attr_name_len < 0) { - ntfs_log_perror("Invalid attribute name '%s'", optarg); + ntfs_log_perror("Invalid attribute name '%s'", + optarg); usage(); } @@ -317,8 +322,7 @@ static int index_get_size(ntfs_inode *inode) return 0; // not a directory iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->value_offset)); - - return iroot->index_block_size; + return le32_to_cpu(iroot->index_block_size); } /** @@ -340,7 +344,8 @@ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, attr = ntfs_attr_open(inode, type, name, namelen); if (!attr) { - ntfs_log_error("Cannot find attribute type 0x%lx.\n", (long) type); + ntfs_log_error("Cannot find attribute type 0x%x.\n", + le32_to_cpu(type)); free(buffer); return 1; } @@ -422,7 +427,7 @@ int main(int argc, char *argv[]) } attr = AT_DATA; - if (opts.attr != (ATTR_TYPES)-1) + if (opts.attr != cpu_to_le32(-1)) attr = opts.attr; result = cat(vol, inode, attr, opts.attr_name, opts.attr_name_len); diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index dac19f30..8bb94ab0 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -3,6 +3,7 @@ * * Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2004-2006 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * Special image format support copyright (c) 2004 Per Olofsson * * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. @@ -153,8 +154,6 @@ static unsigned int wiped_unused_mft = 0; static unsigned int wiped_resident_data = 0; static unsigned int wiped_timestamp_data = 0; -static BOOL image_is_host_endian = FALSE; - #define IMAGE_MAGIC "\0ntfsclone-image" #define IMAGE_MAGIC_SIZE 16 @@ -180,11 +179,11 @@ static struct { char magic[IMAGE_MAGIC_SIZE]; u8 major_ver; u8 minor_ver; - u32 cluster_size; - s64 device_size; - s64 nr_clusters; - s64 inuse; - u32 offset_to_image_data; /* From start of image_hdr. */ + le32 cluster_size; + sle64 device_size; + sle64 nr_clusters; + sle64 inuse; + le32 offset_to_image_data; /* From start of image_hdr. */ } __attribute__((__packed__)) image_hdr; #define NTFSCLONE_IMG_HEADER_SIZE_OLD \ @@ -612,7 +611,7 @@ static void lseek_to_cluster(s64 lcn) static void image_skip_clusters(s64 count) { if (opt.save_image && count > 0) { - typeof(count) count_buf; + sle64 count_buf; char buff[1 + sizeof(count)]; buff[0] = 0; @@ -661,8 +660,8 @@ static void clone_ntfs(u64 nr_clusters) progress_init(&progress, p_counter, nr_clusters, 100); if (opt.save_image) { - if (write_all(&fd_out, &image_hdr, - image_hdr.offset_to_image_data) == -1) + if (write_all(&fd_out, &image_hdr, le32_to_cpu( + image_hdr.offset_to_image_data)) == -1) perr_exit("write_all"); } @@ -704,6 +703,7 @@ static void write_empty_clusters(s32 csize, s64 count, static void restore_image(void) { + sle64 countle; s64 pos = 0, count; s32 csize = le32_to_cpu(image_hdr.cluster_size); char cmd; @@ -722,10 +722,9 @@ static void restore_image(void) perr_exit("read_all"); if (cmd == 0) { - if (read_all(&fd_in, &count, sizeof(count)) == -1) + if (read_all(&fd_in, &countle, sizeof(countle)) == -1) perr_exit("read_all"); - if (!image_is_host_endian) - count = sle64_to_cpu(count); + count = sle64_to_cpu(countle); if (opt.std_out) write_empty_clusters(csize, count, &progress, &p_counter); @@ -746,7 +745,7 @@ static void restore_image(void) static void wipe_index_entry_timestams(INDEX_ENTRY *e) { - s64 timestamp = utc2ntfs(0); + sle64 timestamp = utc2ntfs(0); /* FIXME: can fall into infinite loop if corrupted */ while (!(e->flags & INDEX_ENTRY_END)) { @@ -855,7 +854,7 @@ out_indexr: free(indexr); } -static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp) +static void wipe_index_root_timestamps(ATTR_RECORD *attr, sle64 timestamp) { INDEX_ENTRY *entry; INDEX_ROOT *iroot; @@ -917,7 +916,7 @@ do { \ static void wipe_timestamps(ntfs_walk_clusters_ctx *image) { ATTR_RECORD *a = image->ctx->attr; - s64 timestamp = utc2ntfs(0); + sle64 timestamp = utc2ntfs(0); if (a->type == AT_FILE_NAME) WIPE_TIMESTAMPS(FILE_NAME_ATTR, a, timestamp); @@ -1552,9 +1551,8 @@ static s64 open_image(void) #endif image_hdr.offset_to_image_data = const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); - image_is_host_endian = TRUE; } else { - typeof(image_hdr.offset_to_image_data) offset_to_image_data; + le32 offset_to_image_data; int delta; if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR) @@ -1567,16 +1565,16 @@ static s64 open_image(void) if (read_all(&fd_in, &offset_to_image_data, sizeof(offset_to_image_data)) == -1) perr_exit("read_all"); - image_hdr.offset_to_image_data = - le32_to_cpu(offset_to_image_data); + image_hdr.offset_to_image_data = offset_to_image_data; /* * Read any fields from the header that we have not read yet so * that the input stream is positioned correctly. This means * we can support future minor versions that just extend the * header in a backwards compatible way. */ - delta = offset_to_image_data - (NTFSCLONE_IMG_HEADER_SIZE_OLD + - sizeof(image_hdr.offset_to_image_data)); + delta = le32_to_cpu(offset_to_image_data) - + (NTFSCLONE_IMG_HEADER_SIZE_OLD + + sizeof(image_hdr.offset_to_image_data)); if (delta > 0) { char *dummy_buf; diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 414b64b7..f53c33fc 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -1,10 +1,26 @@ /** - * ntfscmp - compare two NTFS volumes. + * ntfscmp - Part of the Linux-NTFS project. * * Copyright (c) 2005-2006 Szabolcs Szakacsits - * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * - * This utility is part of the Linux-NTFS project. + * This utility compare two NTFS volumes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" @@ -386,7 +402,8 @@ static void print_attribute_name(char *name) } #define GET_ATTR_NAME(a) \ - ((ntfschar *)(((u8 *)(a)) + ((a)->name_offset))), ((a)->name_length) + ((ntfschar *)(((u8 *)(a)) + le16_to_cpu((a)->name_offset))), \ + ((a)->name_length) static void free_name(char **name) { @@ -537,15 +554,15 @@ static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) if (cmp_buffer((u8 *)cia1.ia, (u8 *)cia2.ia, 0x18, na1)) goto out; - ib_size = cia1.ia->index.allocated_size + 0x18; + ib_size = le32_to_cpu(cia1.ia->index.allocated_size) + 0x18; bit = 0; while ((u8 *)cia1.tmp_ia < (u8 *)cia1.ia + na1->data_size) { if (*cia1.byte & (1 << bit)) { - ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia1.tmp_ia, - ib_size); - ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *)cia2.tmp_ia, - ib_size); + ret1 = ntfs_mst_post_read_fixup((NTFS_RECORD *) + cia1.tmp_ia, ib_size); + ret2 = ntfs_mst_post_read_fixup((NTFS_RECORD *) + cia2.tmp_ia, ib_size); if (ret1 != ret2) { print_differ(na1); goto out; @@ -555,8 +572,9 @@ static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2) continue; if (cmp_buffer(((u8 *)cia1.tmp_ia) + 0x18, - ((u8 *)cia2.tmp_ia) + 0x18, - cia1.ia->index.index_length, na1)) + ((u8 *)cia2.tmp_ia) + 0x18, + le32_to_cpu(cia1.ia-> + index.index_length), na1)) goto out; } @@ -638,7 +656,7 @@ static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2) /* * FIXME: includes paddings which are not handled by ntfsinfo! */ - header_size = a1->length; + header_size = le32_to_cpu(a1->length); } return memcmp(a1, a2, header_size); @@ -818,9 +836,11 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2) old_atype1 = atype1; old_ret1 = ret1; - if (!ret1 && (atype1 <= atype2 || ret2)) + if (!ret1 && (le32_to_cpu(atype1) <= le32_to_cpu(atype2) || + ret2)) ret1 = next_attr(ctx1, &atype1, &name1, &errno1); - if (!ret2 && (old_atype1 >= atype2 || old_ret1)) + if (!ret2 && (le32_to_cpu(old_atype1) >= le32_to_cpu(atype2) || + old_ret1)) ret2 = next_attr(ctx2, &atype2, &name2, &errno2); print_attributes(ni1, atype1, atype2, name1, name2); @@ -834,14 +854,15 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2) break; } - if (ret2 || atype1 < atype2) { + if (ret2 || le32_to_cpu(atype1) < le32_to_cpu(atype2)) { if (new_attribute(ctx1, prev_atype, prev_name)) { print_ctx(ctx1); printf("presence: EXISTS != MISSING\n"); - set_prev(&prev_name, &prev_atype, name1, atype1); + set_prev(&prev_name, &prev_atype, name1, + atype1); } - } else if (ret1 || atype1 > atype2) { + } else if (ret1 || le32_to_cpu(atype1) > le32_to_cpu(atype2)) { if (new_attribute(ctx2, prev_atype, prev_name)) { print_ctx(ctx2); printf("presence: MISSING != EXISTS \n"); diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 72af5a96..b2425174 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -182,7 +182,7 @@ static int parse_options(int argc, char **argv) ntfs_log_error("Couldn't parse attribute.\n"); err++; } else - opts.attribute = (ATTR_TYPES)attr; + opts.attribute = (ATTR_TYPES)cpu_to_le32(attr); break; case 'i': opts.inode++; diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 66e1becf..738b13d9 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -1,8 +1,9 @@ /** * ntfsfix - Part of the Linux-NTFS project. * - * Copyright (c) 2000-2006 Anton Altaparmakov. - * Copyright (c) 2002-2006 Szabolcs Szakacsits. + * Copyright (c) 2000-2006 Anton Altaparmakov + * Copyright (c) 2002-2006 Szabolcs Szakacsits + * Copyright (c) 2007 Yura Pakhuchiy * * This utility fixes some common NTFS problems, resets the NTFS journal file * and schedules an NTFS consistency check for the first boot into Windows. @@ -116,8 +117,9 @@ static void version(void) { ntfs_log_info("%s v%s\n\n" "Attempt to fix an NTFS partition.\n\n" - "Copyright (c) 2000-2006 Anton Altaparmakov.\n" - "Copyright (c) 2002-2006 Szabolcs Szakacsits.\n\n", + "Copyright (c) 2000-2006 Anton Altaparmakov\n" + "Copyright (c) 2002-2006 Szabolcs Szakacsits\n" + "Copyright (c) 2007 Yura Pakhuchiy\n\n", EXEC_NAME, VERSION); ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); exit(1); @@ -168,7 +170,7 @@ static void parse_options(int argc, char **argv) /** * OLD_ntfs_volume_set_flags */ -static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) +static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const le16 flags) { MFT_RECORD *m = NULL; ATTR_RECORD *a; @@ -225,7 +227,7 @@ static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) goto err_out; } /* Set the volume flags. */ - vol->flags = c->flags = cpu_to_le16(flags); + vol->flags = c->flags = flags; if (ntfs_mft_record_write(vol, FILE_Volume, m)) { ntfs_log_perror("Error writing $Volume"); goto err_out; @@ -243,7 +245,7 @@ err_exit: */ static int set_dirty_flag(ntfs_volume *vol) { - u16 flags; + le16 flags; if (NVolWasDirty(vol)) return 0; @@ -362,7 +364,7 @@ static int fix_mftmirr(ntfs_volume *vol) use_mirr = FALSE; mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); if (mrec->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_recordp(mrec)) { + if (ntfs_is_baad_record(mrec->magic)) { ntfs_log_info(FAILED); ntfs_log_error("$MFT error: Incomplete multi " "sector transfer detected in " @@ -370,7 +372,7 @@ static int fix_mftmirr(ntfs_volume *vol) ")-:\n", s); goto error_exit; } - if (!ntfs_is_mft_recordp(mrec)) { + if (!ntfs_is_mft_record(mrec->magic)) { ntfs_log_info(FAILED); ntfs_log_error("$MFT error: Invalid mft " "record for %s.\nCannot " @@ -380,14 +382,14 @@ static int fix_mftmirr(ntfs_volume *vol) } mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); if (mrec2->flags & MFT_RECORD_IN_USE) { - if (ntfs_is_baad_recordp(mrec2)) { + if (ntfs_is_baad_record(mrec2->magic)) { ntfs_log_info(FAILED); ntfs_log_error("$MFTMirr error: Incomplete " "multi sector transfer " "detected in %s.\n", s); goto error_exit; } - if (!ntfs_is_mft_recordp(mrec2)) { + if (!ntfs_is_mft_record(mrec2->magic)) { ntfs_log_info(FAILED); ntfs_log_error("$MFTMirr error: Invalid mft " "record for %s.\n", s); @@ -395,7 +397,7 @@ static int fix_mftmirr(ntfs_volume *vol) } /* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */ if (!(mrec->flags & MFT_RECORD_IN_USE) && - !ntfs_is_mft_recordp(mrec)) + !ntfs_is_mft_record(mrec->magic)) use_mirr = TRUE; } if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 127c8f5a..f723e52d 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -6,7 +6,7 @@ * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2004-2005 Yuval Fledel - * Copyright (c) 2004-2006 Yura Pakhuchiy + * Copyright (c) 2004-2007 Yura Pakhuchiy * Copyright (c) 2005 Cristian Klein * * This utility will dump a file's attributes. @@ -113,7 +113,7 @@ static void version(void) printf(" 2003-2006 Szabolcs Szakacsits\n"); printf(" 2003 Leonard NorrgÃ¥rd\n"); printf(" 2004-2005 Yuval Fledel\n"); - printf(" 2004-2006 Yura Pakhuchiy\n"); + printf(" 2004-2007 Yura Pakhuchiy\n"); printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -333,7 +333,7 @@ static int parse_options(int argc, char *argv[]) * sle64_to_cpu(standard_attr->creation_time)); * printf("\tFile Creation Time:\t %s", time_str); */ -static char *ntfsinfo_time_to_str(const s64 sle_ntfs_clock) +static char *ntfsinfo_time_to_str(const sle64 sle_ntfs_clock) { time_t unix_clock = ntfs2utc(sle_ntfs_clock); return ctime(&unix_clock); @@ -448,7 +448,7 @@ static void ntfs_dump_volume(ntfs_volume *vol) * @type: dump flags for this attribute type * @flags: flags for dumping */ -static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, u32 flags) +static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, le32 flags) { printf("%sFile attributes:\t", indent); if (flags & FILE_ATTR_READONLY) { @@ -1030,7 +1030,7 @@ static void ntfs_dump_attr_volume_name(ATTR_RECORD *attr) { ntfschar *ucs_vol_name = NULL; - if (attr->value_length>0) { + if (le32_to_cpu(attr->value_length) > 0) { char *mbs_vol_name = NULL; int mbs_vol_name_size; /* calculate volume name position */ @@ -1038,20 +1038,18 @@ static void ntfs_dump_attr_volume_name(ATTR_RECORD *attr) le16_to_cpu(attr->value_offset)); /* convert the name to current locale multibyte sequence */ mbs_vol_name_size = ntfs_ucstombs(ucs_vol_name, - le32_to_cpu(attr->value_length)/sizeof(ntfschar), - &mbs_vol_name,0); + le32_to_cpu(attr->value_length) / + sizeof(ntfschar), &mbs_vol_name, 0); if (mbs_vol_name_size>0) { /* output the converted name. */ - printf("\tVolume Name:\t\t '%s'\n",mbs_vol_name); + printf("\tVolume Name:\t\t '%s'\n", mbs_vol_name); free(mbs_vol_name); - } else { - /* an error occurred, errno holds the reason - notify the user */ - ntfs_log_perror("ntfsinfo error: could not parse volume name"); - } - } else { + } else + ntfs_log_perror("ntfsinfo error: could not parse " + "volume name"); + } else printf("\tVolume Name:\t\t unnamed\n"); - } } /** @@ -1089,12 +1087,12 @@ static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) if (vol_information->flags & VOLUME_FLAGS_MASK) { printf("(0x%04x)\n", (unsigned)le16_to_cpu(vol_information->flags)); - } else { + } else printf("none set (0x0000)\n"); - } - if (vol_information->flags & (0xFFFF - VOLUME_FLAGS_MASK)) + if (vol_information->flags & (~VOLUME_FLAGS_MASK)) printf("\t\t\t\t Unknown Flags: 0x%04x\n", - vol_information->flags & (0xFFFF - VOLUME_FLAGS_MASK)); + le16_to_cpu(vol_information->flags & + (~VOLUME_FLAGS_MASK))); } static ntfschar NTFS_DATA_SDS[5] = { const_cpu_to_le16('$'), @@ -1168,7 +1166,7 @@ static void ntfs_dump_sds(ATTR_RECORD *attr, ntfs_inode *ni) free(sds); } -static const char *get_attribute_type_name(u32 type) +static const char *get_attribute_type_name(le32 type) { switch (type) { case AT_UNUSED: return "$UNUSED"; @@ -1367,7 +1365,7 @@ static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) break; default: ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - (unsigned)le32_to_cpu(type)); + (unsigned)type); break; } } @@ -1383,7 +1381,8 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) { INDEX_ENTRY_DATA *data; - data = (INDEX_ENTRY_DATA *)((u8 *)entry + entry->data_offset); + data = (INDEX_ENTRY_DATA *)((u8 *)entry + + le16_to_cpu(entry->data_offset)); switch (type) { case INDEX_ATTR_SECURE_SII: @@ -1469,20 +1468,20 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) data->quota_q.change_time)); ntfs_log_verbose("\t\tThreshold:\t\t %lld (0x%llx)\n", (unsigned long long) - le64_to_cpu(data->quota_q.threshold), + sle64_to_cpu(data->quota_q.threshold), (unsigned long long) - le64_to_cpu(data->quota_q.threshold)); + sle64_to_cpu(data->quota_q.threshold)); ntfs_log_verbose("\t\tLimit:\t\t\t %lld (0x%llx)\n", (unsigned long long) - le64_to_cpu(data->quota_q.limit), + sle64_to_cpu(data->quota_q.limit), (unsigned long long) - le64_to_cpu(data->quota_q.limit)); + sle64_to_cpu(data->quota_q.limit)); ntfs_log_verbose("\t\tExceeded time:\t\t %lld (0x%llx)\n", (unsigned long long) - le64_to_cpu(data->quota_q.exceeded_time), + sle64_to_cpu(data->quota_q.exceeded_time), (unsigned long long) - le64_to_cpu(data->quota_q.exceeded_time)); - if (entry->data_length > 48) { + sle64_to_cpu(data->quota_q.exceeded_time)); + if (le16_to_cpu(entry->data_length) > 48) { char *sid; sid = ntfs_sid_to_mbs(&data->quota_q.sid, NULL, 0); ntfs_log_verbose("\t\tOwner SID:\t\t %s\n", sid); @@ -1491,7 +1490,7 @@ static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) break; default: ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", - (unsigned)le32_to_cpu(type)); + (unsigned)type); break; } } @@ -2013,8 +2012,8 @@ static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) /* hex dump */ printf("\tDumping some of the attribute data:\n"); ntfs_hex_dump((u8*)attr + le16_to_cpu(attr->value_offset), - (le16_to_cpu(attr->value_length)>128)? - 128 : le16_to_cpu(attr->value_length)); + (le32_to_cpu(attr->value_length) > 128) ? + 128 : le32_to_cpu(attr->value_length)); } } @@ -2024,7 +2023,7 @@ static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) static void ntfs_dump_inode_general_info(ntfs_inode *inode) { MFT_RECORD *mrec = inode->mrec; - u16 inode_flags = mrec->flags; + le16 inode_flags = mrec->flags; printf("Dumping Inode %llu (0x%llx)\n", (long long)inode->mft_no, @@ -2061,7 +2060,8 @@ static void ntfs_dump_inode_general_info(ntfs_inode *inode) inode_flags &= ~MFT_RECORD_IS_VIEW_INDEX; } if (inode_flags) - printf("UNKNOWN: 0x%04x", (unsigned)inode_flags); + printf("UNKNOWN: 0x%04x", (unsigned)le16_to_cpu( + inode_flags)); } else { printf("none"); } diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index b4797282..a6fc9926 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -4,6 +4,7 @@ * Copyright (c) 2002-2006 Szabolcs Szakacsits * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2002-2003 Richard Russon + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will resize an NTFS volume without data loss. * @@ -367,6 +368,7 @@ static void version(void) printf("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); printf("Copyright (c) 2002-2005 Anton Altaparmakov\n"); printf("Copyright (c) 2002-2003 Richard Russon\n"); + printf("Copyright (c) 2007 Yura Pakhuchiy\n"); printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -1169,7 +1171,7 @@ static void replace_attribute_runlist(ntfs_volume *vol, ntfs_log_verbose("Bytes in use : %u\n", (unsigned int) le32_to_cpu(ctx->mrec->bytes_in_use)); - next_attr = (char *)a + le16_to_cpu(a->length); + next_attr = (char *)a + le32_to_cpu(a->length); l = mp_size - l; ntfs_log_verbose("Bytes in use new : %u\n", l + (unsigned int) @@ -1196,7 +1198,7 @@ static void replace_attribute_runlist(ntfs_volume *vol, memmove(next_attr + l, next_attr, remains_size); ctx->mrec->bytes_in_use = cpu_to_le32(l + le32_to_cpu(ctx->mrec->bytes_in_use)); - a->length += l; + a->length = cpu_to_le32(le32_to_cpu(a->length) + l); } mp = ntfs_calloc(mp_size); @@ -1609,8 +1611,8 @@ static int is_mftdata(ntfs_resize_t *resize) if (resize->mref == 0) return 1; - if ( MREF(resize->mrec->base_mft_record) == 0 && - MSEQNO(resize->mrec->base_mft_record) != 0) + if (MREF_LE(resize->mrec->base_mft_record) == 0 && + MSEQNO_LE(resize->mrec->base_mft_record) != 0) return 1; return 0; @@ -1872,9 +1874,9 @@ static void truncate_badclust_bad_attr(ntfs_resize_t *resize) rl_truncate(&rl_bad, nr_clusters); - a->highest_vcn = cpu_to_le64(nr_clusters - 1LL); - a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size); - a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size); + a->highest_vcn = cpu_to_sle64(nr_clusters - 1LL); + a->allocated_size = cpu_to_sle64(nr_clusters * vol->cluster_size); + a->data_size = cpu_to_sle64(nr_clusters * vol->cluster_size); replace_attribute_runlist(vol, resize->ctx, rl_bad); @@ -1949,10 +1951,10 @@ static void truncate_bitmap_data_attr(ntfs_resize_t *resize) realloc_bitmap_data_attr(resize, &rl, nr_bm_clusters); } - a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL); - a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size); - a->data_size = cpu_to_le64(bm_bsize); - a->initialized_size = cpu_to_le64(bm_bsize); + a->highest_vcn = cpu_to_sle64(nr_bm_clusters - 1LL); + a->allocated_size = cpu_to_sle64(nr_bm_clusters * vol->cluster_size); + a->data_size = cpu_to_sle64(bm_bsize); + a->initialized_size = cpu_to_sle64(bm_bsize); replace_attribute_runlist(vol, resize->ctx, rl); @@ -2151,7 +2153,7 @@ static void update_bootsector(ntfs_resize_t *r) r->progress.flags |= NTFS_PROGBAR_SUPPRESS; copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old, r->mftmir_rl.length); - bs.mftmirr_lcn = cpu_to_le64(r->mftmir_rl.lcn); + bs.mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn); r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS; } diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index 4718a96a..0dac320c 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -3,7 +3,8 @@ * * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2004-2005 Holger Ohmacht - * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will recover deleted files from an NTFS volume. * @@ -221,11 +222,13 @@ static int parse_inode_arg(void) */ static void version(void) { - ntfs_log_info("\n%s v%s (libntfs %s) - Recover deleted files from an NTFS " - "Volume.\n\n", EXEC_NAME, VERSION, + ntfs_log_info("\n%s v%s (libntfs %s) - Recover deleted files from an " + "NTFS Volume.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); ntfs_log_info("Copyright (c) 2002-2005 Richard Russon\n" - "Copyright (c) 2004-2005 Holger Ohmacht\n"); + "Copyright (c) 2004-2005 Holger Ohmacht\n" + "Copyright (c) 2005 Anton Altaparmakov\n" + "Copyright (c) 2007 Yura Pakhuchiy\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } @@ -834,7 +837,8 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol) rec = calloc(1, vol->mft_record_size); if (!rec) { - ntfs_log_error("ERROR: Couldn't allocate memory in get_parent_name()\n"); + ntfs_log_error("ERROR: Couldn't allocate memory in " + "get_parent_name()\n"); return; } @@ -842,10 +846,12 @@ static void get_parent_name(struct filename* name, ntfs_volume* vol) if (!mft_data) { ntfs_log_perror("ERROR: Couldn't open $MFT/$DATA"); } else { - inode_num = MREF(name->parent_mref); + inode_num = MREF_LE(name->parent_mref); - if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num, vol->mft_record_size, rec) < 1) { - ntfs_log_error("ERROR: Couldn't read MFT Record %lld.\n", inode_num); + if (ntfs_attr_pread(mft_data, vol->mft_record_size * inode_num, + vol->mft_record_size, rec) < 1) { + ntfs_log_error("ERROR: Couldn't read MFT Record %lld" + ".\n", inode_num); } else if ((filename_attr = verify_parent(name, rec))) { if (ntfs_ucstombs(filename_attr->file_name, filename_attr->file_name_length, @@ -906,11 +912,13 @@ static int get_filenames(struct ufile *file, ntfs_volume* vol) while ((rec = find_attribute(AT_FILE_NAME, ctx))) { /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset)); + attr = (FILE_NAME_ATTR *)((char *)rec + + le16_to_cpu(rec->value_offset)); name = calloc(1, sizeof(*name)); if (!name) { - ntfs_log_error("ERROR: Couldn't allocate memory in get_filenames().\n"); + ntfs_log_error("ERROR: Couldn't allocate memory in " + "get_filenames().\n"); count = -1; break; } @@ -990,28 +998,32 @@ static int get_data(struct ufile *file, ntfs_volume *vol) while ((rec = find_attribute(AT_DATA, ctx))) { data = calloc(1, sizeof(*data)); if (!data) { - ntfs_log_error("ERROR: Couldn't allocate memory in get_data().\n"); + ntfs_log_error("ERROR: Couldn't allocate memory in " + "get_data().\n"); count = -1; break; } data->resident = !rec->non_resident; - data->compressed = rec->flags & ATTR_IS_COMPRESSED; - data->encrypted = rec->flags & ATTR_IS_ENCRYPTED; + data->compressed = (rec->flags & ATTR_IS_COMPRESSED) ? 1 : 0; + data->encrypted = (rec->flags & ATTR_IS_ENCRYPTED) ? 1 : 0; if (rec->name_length) { - data->uname = (ntfschar *) ((char *) rec + le16_to_cpu(rec->name_offset)); + data->uname = (ntfschar *)((char *)rec + + le16_to_cpu(rec->name_offset)); data->uname_len = rec->name_length; - if (ntfs_ucstombs(data->uname, data->uname_len, &data->name, - 0) < 0) { - ntfs_log_error("ERROR: Cannot translate name into current locale.\n"); + if (ntfs_ucstombs(data->uname, data->uname_len, + &data->name, 0) < 0) { + ntfs_log_error("ERROR: Cannot translate name " + "into current locale.\n"); } } if (data->resident) { - data->size_data = le32_to_cpu(rec->value_length); - data->data = ((char*) (rec)) + le16_to_cpu(rec->value_offset); + data->size_data = le32_to_cpu(rec->value_length); + data->data = (char*)rec + + le16_to_cpu(rec->value_offset); } else { data->size_alloc = sle64_to_cpu(rec->allocated_size); data->size_data = sle64_to_cpu(rec->data_size); @@ -1169,17 +1181,20 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol) clusters_free = 0; if (data->encrypted) { - ntfs_log_verbose("File is encrypted, recovery is impossible.\n"); + ntfs_log_verbose("File is encrypted, recovery is " + "impossible.\n"); continue; } if (data->compressed) { - ntfs_log_verbose("File is compressed, recovery not yet implemented.\n"); + ntfs_log_verbose("File is compressed, recovery not yet " + "implemented.\n"); continue; } if (data->resident) { - ntfs_log_verbose("File is resident, therefore recoverable.\n"); + ntfs_log_verbose("File is resident, therefore " + "recoverable.\n"); percent = 100; data->percent = 100; continue; @@ -1187,16 +1202,18 @@ static int calc_percentage(struct ufile *file, ntfs_volume *vol) rl = data->runlist; if (!rl) { - ntfs_log_verbose("File has no runlist, hence no data.\n"); + ntfs_log_verbose("File has no runlist, hence no data." + "\n"); continue; } if (rl[0].length <= 0) { - ntfs_log_verbose("File has an empty runlist, hence no data.\n"); + ntfs_log_verbose("File has an empty runlist, hence no " + "data.\n"); continue; } - if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */ + if (rl[0].lcn == LCN_RL_NOT_MAPPED) { /* extended mft record */ ntfs_log_verbose("Missing segment at beginning, %lld " "clusters\n", (long long)rl[0].length); clusters_inuse += rl[0].length; @@ -1288,12 +1305,18 @@ static void dump_record(struct ufile *file) ntfs_log_quiet("Filename: (%d) %s\n", f->name_space, f->name); ntfs_log_quiet("File Flags: "); - if (f->flags & FILE_ATTR_SYSTEM) ntfs_log_quiet("System "); - if (f->flags & FILE_ATTR_DIRECTORY) ntfs_log_quiet("Directory "); - if (f->flags & FILE_ATTR_SPARSE_FILE) ntfs_log_quiet("Sparse "); - if (f->flags & FILE_ATTR_REPARSE_POINT) ntfs_log_quiet("Reparse "); - if (f->flags & FILE_ATTR_COMPRESSED) ntfs_log_quiet("Compressed "); - if (f->flags & FILE_ATTR_ENCRYPTED) ntfs_log_quiet("Encrypted "); + if (f->flags & FILE_ATTR_SYSTEM) + ntfs_log_quiet("System "); + if (f->flags & FILE_ATTR_DIRECTORY) + ntfs_log_quiet("Directory "); + if (f->flags & FILE_ATTR_SPARSE_FILE) + ntfs_log_quiet("Sparse "); + if (f->flags & FILE_ATTR_REPARSE_POINT) + ntfs_log_quiet("Reparse "); + if (f->flags & FILE_ATTR_COMPRESSED) + ntfs_log_quiet("Compressed "); + if (f->flags & FILE_ATTR_ENCRYPTED) + ntfs_log_quiet("Encrypted "); if (!(f->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_DIRECTORY | FILE_ATTR_SPARSE_FILE | FILE_ATTR_REPARSE_POINT | FILE_ATTR_COMPRESSED | FILE_ATTR_ENCRYPTED))) { @@ -1310,13 +1333,17 @@ static void dump_record(struct ufile *file) ntfs_log_quiet("Size alloc: %lld\n", f->size_alloc); ntfs_log_quiet("Size data: %lld\n", f->size_data); - strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_c)); + strftime(buffer, sizeof(buffer), "%F %R", + localtime(&f->date_c)); ntfs_log_quiet("Date C: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_a)); + strftime(buffer, sizeof(buffer), "%F %R", + localtime(&f->date_a)); ntfs_log_quiet("Date A: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_m)); + strftime(buffer, sizeof(buffer), "%F %R", + localtime(&f->date_m)); ntfs_log_quiet("Date M: %s\n", buffer); - strftime(buffer, sizeof(buffer), "%F %R", localtime(&f->date_r)); + strftime(buffer, sizeof(buffer), "%F %R", + localtime(&f->date_r)); ntfs_log_quiet("Date R: %s\n", buffer); } @@ -1349,7 +1376,8 @@ static void dump_record(struct ufile *file) } } - ntfs_log_quiet("Amount potentially recoverable %d%%\n", d->percent); + ntfs_log_quiet("Amount potentially recoverable %d%%\n", + d->percent); } ntfs_log_quiet("________________________________________\n\n"); @@ -1402,10 +1430,14 @@ static void list_record(struct ufile *file) struct data *d = list_entry(item, struct data, list); if (!d->name) { - if (d->resident) flagr = 'R'; - else flagr = 'N'; - if (d->compressed) flagc = 'C'; /* These two are mutually exclusive */ - if (d->encrypted) flagc = 'E'; + if (d->resident) + flagr = 'R'; + else + flagr = 'N'; + if (d->compressed) + flagc = 'C'; + if (d->encrypted) + flagc = 'E'; percent = max(percent, d->percent); } diff --git a/ntfsprogs/ntfsundelete.h b/ntfsprogs/ntfsundelete.h index 177f5eec..529587b7 100644 --- a/ntfsprogs/ntfsundelete.h +++ b/ntfsprogs/ntfsundelete.h @@ -2,6 +2,7 @@ * ntfsundelete - Part of the Linux-NTFS project. * * Copyright (c) 2002 Richard Russon + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will recover deleted files from an NTFS volume. * @@ -72,7 +73,7 @@ struct filename { time_t date_r; /* read */ char *name; /* Filename in current locale */ FILE_NAME_TYPE_FLAGS name_space; - long long parent_mref; + leMFT_REF parent_mref; char *parent_name; }; diff --git a/ntfsprogs/sd.c b/ntfsprogs/sd.c index 06d35fe8..bfc7341d 100644 --- a/ntfsprogs/sd.c +++ b/ntfsprogs/sd.c @@ -324,7 +324,6 @@ void init_root_sd(u8 **sd_val, int *sd_val_len) ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = 0; ace->size = const_cpu_to_le16(0x18); - ace->mask = 9; ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY; ace->sid.revision = SID_REVISION; diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index ed8ceaf8..9d8beb9e 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -4,6 +4,7 @@ * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2003-2006 Anton Altaparmakov * Copyright (c) 2003 Lode Leroy + * Copyright (c) 2005-2007 Yura Pakhuchiy * * A set of shared functions for ntfs utilities * @@ -578,7 +579,8 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b name = NULL; namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name)); if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) { - ntfs_log_error("Couldn't translate attribute type to current locale.\n"); + ntfs_log_error("Couldn't translate attribute type to " + "current locale.\n"); // ? return 0; } @@ -602,9 +604,10 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b name = NULL; namelen = attr->name_length; - if (ntfs_ucstombs((ntfschar *)((char *)attr + attr->name_offset), - namelen, &name, 0) < 0) { - ntfs_log_error("Couldn't translate attribute name to current locale.\n"); + if (ntfs_ucstombs((ntfschar *)((char *)attr + le16_to_cpu( + attr->name_offset)), namelen, &name, 0) < 0) { + ntfs_log_error("Couldn't translate attribute name to current " + "locale.\n"); // ? len = snprintf(buffer, bufsize, ""); return 0; @@ -785,7 +788,7 @@ int utils_is_metadata(ntfs_inode *inode) file = inode->mrec; if (file && (file->base_mft_record != 0)) { - num = MREF(file->base_mft_record); + num = MREF_LE(file->base_mft_record); if (__metadata(vol, num) == 1) return 1; } @@ -796,9 +799,9 @@ int utils_is_metadata(ntfs_inode *inode) return -1; /* We know this will always be resident. */ - attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset)); + attr = (FILE_NAME_ATTR *)((char *)rec + le16_to_cpu(rec->value_offset)); - num = MREF(attr->parent_directory); + num = MREF_LE(attr->parent_directory); if ((num != FILE_root) && (__metadata(vol, num) == 1)) return 1; From d059090386d64b6d5f67170144f6f5a536211f05 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 8 Jun 2007 13:48:28 +0300 Subject: [PATCH 190/289] info: nice LCN dumping --- ntfsprogs/ntfsinfo.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index f723e52d..907bcc9b 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1192,6 +1192,26 @@ static const char *get_attribute_type_name(le32 type) return "$UNKNOWN"; } +static const char * ntfs_dump_lcn(LCN lcn) +{ + switch (lcn) { + case LCN_HOLE: + return "\t"; + case LCN_RL_NOT_MAPPED: + return ""; + case LCN_ENOENT: + return "\t"; + case LCN_EINVAL: + return "\t"; + case LCN_EIO: + return "\t"; + default: + ntfs_log_error("Invalid LCN value %llx passed to " + "ntfs_dump_lcn().\n", lcn); + return "???\t"; + } +} + static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) { printf("Dumping attribute %s (0x%x)\n", @@ -1280,14 +1300,24 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) } if (opts.verbose) { - runlist *rl = ntfs_mapping_pairs_decompress(vol, a, NULL); + runlist *rl; + + rl = ntfs_mapping_pairs_decompress(vol, a, NULL); if (rl) { runlist *rlc = rl; + // TODO: Switch this to properly aligned hex... printf("\tRunlist:\tVCN\t\tLCN\t\tLength\n"); while (rlc->length) { - printf("\t\t\t0x%llx\t\t0x%llx\t\t0x%llx\n", - rlc->vcn, rlc->lcn, rlc->length); + if (rlc->lcn >= 0) + printf("\t\t\t0x%llx\t\t0x%llx\t\t" + "0x%llx\n", rlc->vcn, + rlc->lcn, rlc->length); + else + printf("\t\t\t0x%llx\t\t%s\t" + "0x%llx\n", rlc->vcn, + ntfs_dump_lcn(rlc->lcn), + rlc->length); rlc++; } free(rl); From 7a68bb3ea01d6962b8247888e6c2a6f1ff03cc74 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 10 Jun 2007 14:28:56 +0300 Subject: [PATCH 191/289] Endian fixes for gnome-vfs module. Thanks to Anton for tip. --- include/ntfs/gnome-vfs-module.h | 2 +- libntfs/gnome-vfs-method.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/ntfs/gnome-vfs-module.h b/include/ntfs/gnome-vfs-module.h index bd27f713..31671044 100644 --- a/include/ntfs/gnome-vfs-module.h +++ b/include/ntfs/gnome-vfs-module.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS G_LOCK_EXTERN(libntfs); -#define libntfs_newn(objp, n) ((objp) = g_new(typeof(*(objp)), (n))) +#define libntfs_newn(objp, n) ((objp) = (typeof(objp))g_new(typeof(*(objp)), (n))) #define libntfs_new(objp) (libntfs_newn((objp), 1)) #define LIBNTFS_MEMZERO(objp) (memset((objp), 0, sizeof(*(objp)))) diff --git a/libntfs/gnome-vfs-method.c b/libntfs/gnome-vfs-method.c index 523fa3d9..723a3723 100644 --- a/libntfs/gnome-vfs-method.c +++ b/libntfs/gnome-vfs-method.c @@ -214,7 +214,7 @@ static GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return, *pathname_next != G_DIR_SEPARATOR; pathname_next++) ; if (*pathname_next) { /* terminate current path element */ - *pathname_next++ = '\0'; + *pathname_next++ = 0; } while (*pathname_next == G_DIR_SEPARATOR) pathname_next++; @@ -224,7 +224,8 @@ static GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return, libntfs_newn(pathname_parse_ucs2, strlen(pathname_parse_unescaped) + 1); for (i = 0; pathname_parse_unescaped[i]; i++) - pathname_parse_ucs2[i] = pathname_parse_unescaped[i]; + pathname_parse_ucs2[i] = cpu_to_le16( + pathname_parse_unescaped[i]); pathname_parse_ucs2[i] = 0; g_free(pathname_parse_unescaped); G_LOCK(libntfs); @@ -326,7 +327,8 @@ static gchar *libntfs_ntfscharo_utf8(const ntfschar *name, const int name_len) gstring = g_string_sized_new(name_len); for (i = 0; i < name_len; i++) - gstring = g_string_append_unichar(gstring, name[i]); + gstring = g_string_append_unichar(gstring, + le16_to_cpu(name[i])); return g_string_free(gstring, /* returns utf8-formatted string */ FALSE); /* free_segment */ } @@ -347,8 +349,8 @@ static int libntfs_gnomevfs_read_directory_filldir( g_return_val_if_fail(name_len >= 0, -1); g_return_val_if_fail(pos >= 0, -1); - /* system directory; FIXME: What is its proper identification? */ - if (name_len > 0 && name[0] == '$') + /* system directory */ + if (MREF(mref) != FILE_root && MREF(mref) < FILE_first_user) return 0; /* continue traversal */ file_info = gnome_vfs_file_info_new(); From 8981594cf041be9f518b125140314ea464fe2ea9 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 30 Jun 2007 20:19:25 +0300 Subject: [PATCH 192/289] ntfsdecrypt: Fix sparse warnings. --- ntfsprogs/ntfsdecrypt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 1db17ee9..9ec6dad1 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -101,14 +101,14 @@ typedef enum { */ typedef struct { gcry_cipher_hd_t gcry_cipher_hd; - u32 alg_id; + le32 alg_id; u8 *key_data; gcry_cipher_hd_t *des_gcry_cipher_hd_ptr; } ntfs_fek; /* DESX-MS128 implementation for libgcrypt. */ static gcry_module_t ntfs_desx_module; -static unsigned ntfs_desx_algorithm_id = -1; +static int ntfs_desx_algorithm_id = -1; typedef struct { u64 in_whitening, out_whitening; @@ -988,7 +988,7 @@ static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, errno = ENOMEM; return NULL; } - fek->alg_id = *(u32*)(fek_buf + 8); + fek->alg_id = *(le32*)(fek_buf + 8); //ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id)); fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7); memcpy(fek->key_data, fek_buf + 16, key_size); @@ -1179,11 +1179,11 @@ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) } /* Apply the IV. */ if (fek->alg_id == CALG_AES_256) { - ((u64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); - ((u64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); + ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); + ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); } else { /* All other algos (Des, 3Des, DesX) use the same IV. */ - ((u64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); + ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); } return 512; } From 1947aacb8995a82070e45abe950535781305ccc8 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 1 Jul 2007 01:52:48 +0300 Subject: [PATCH 193/289] Cleanup --- include/ntfs/inode.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 1da51a0d..b6a7d0c4 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -129,10 +129,6 @@ struct _ntfs_inode { inode of the base mft record. */ }; - /* Temp: for directory handling */ - void *private_data; /* ntfs_dt containing this inode */ - int ref_count; - /* Below fields are valid only for base inode. */ s64 data_size; /* Data size stored in the filename index. */ s64 allocated_size; /* Allocated size stored in the filename From 311ecc507e9fb501e46881913573ae29e2acc8a1 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 4 Jul 2007 04:03:15 +0300 Subject: [PATCH 194/289] Memleak --- libntfs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libntfs/inode.c b/libntfs/inode.c index 20518ece..dcbe7045 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -889,6 +889,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) goto remove_attrlist_record;; } /* Done! */ + ntfs_attr_put_search_ctx(ctx); ntfs_attr_close(na); return 0; remove_attrlist_record: From 87b686f9c95584efaf2cf276f37ffc1c8e459121 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 21 Jul 2007 14:30:18 +0300 Subject: [PATCH 195/289] Undef __bitwise and __force in case someone else defined them before us --- include/ntfs/types.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index bb0e654b..bc1ad00b 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -47,11 +47,15 @@ typedef int32_t s32; typedef int64_t s64; #ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) -#define __force __attribute__((force)) + #undef __bitwise + #undef __force + #define __bitwise __attribute__((bitwise)) + #define __force __attribute__((force)) #else -#define __bitwise -#define __force + #undef __bitwise + #undef __force + #define __bitwise + #define __force #endif typedef u16 __bitwise le16; From ea4d352f7ea583fd752a755be9baa71b24dd1f5f Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 21 Jul 2007 22:01:57 +0300 Subject: [PATCH 196/289] Fix sparse warnings from git HEAD version --- libntfs/mft.c | 2 +- ntfsprogs/mkntfs.c | 23 ++++++++++++----------- ntfsprogs/ntfsresize.c | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libntfs/mft.c b/libntfs/mft.c index caf491fb..74a28bd3 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -324,7 +324,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref, } /* Set the update sequence number to 1. */ *(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1); - mrec->lsn = cpu_to_le64(0ull); + mrec->lsn = 0; mrec->sequence_number = cpu_to_le16(1); mrec->link_count = cpu_to_le16(0); /* Aligned to 8-byte boundary. */ diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 3ba6d439..81f922bb 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -1236,7 +1236,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, a->instance = m->next_attr_instance; m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); - a->lowest_vcn = cpu_to_le64(0); + a->lowest_vcn = 0; a->highest_vcn = cpu_to_sle64(highest_vcn - 1LL); a->mapping_pairs_offset = cpu_to_le16(hdr_size + ((name_len + 7) & ~7)); memset(a->reserved1, 0, sizeof(a->reserved1)); @@ -1255,7 +1255,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, a->compression_unit = 4; inited_size = val_len; /* FIXME: Set the compressed size. */ - a->compressed_size = cpu_to_le64(0); + a->compressed_size = 0; /* FIXME: Write out the compressed data. */ /* FIXME: err = build_mapping_pairs_compressed(); */ err = -EOPNOTSUPP; @@ -1421,7 +1421,7 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, a->instance = m->next_attr_instance; m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); - a->lowest_vcn = cpu_to_le64(0); + a->lowest_vcn = 0; for (i = 0; rl[i].length; i++) ; a->highest_vcn = cpu_to_sle64(rl[i].vcn - 1); @@ -1436,14 +1436,14 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, memcpy((char*)a + hdr_size, uname, name_len << 1); if (flags & ATTR_COMPRESSION_MASK) { if (flags & ATTR_COMPRESSION_MASK & ~ATTR_IS_COMPRESSED) { - ntfs_log_error("Unknown compression format. Reverting to " - "standard compression.\n"); + ntfs_log_error("Unknown compression format. Reverting " + "to standard compression.\n"); a->flags &= ~ATTR_COMPRESSION_MASK; a->flags |= ATTR_IS_COMPRESSED; } a->compression_unit = 4; /* FIXME: Set the compressed size. */ - a->compressed_size = cpu_to_le64(0); + a->compressed_size = 0; /* FIXME: Write out the compressed data. */ /* FIXME: err = build_mapping_pairs_compressed(); */ err = -EOPNOTSUPP; @@ -1451,7 +1451,8 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, a->compression_unit = 0; bw = ntfs_rlwrite(g_vol->dev, rl, val, val_len, NULL); if (bw != val_len) { - ntfs_log_error("Error writing non-resident attribute value.\n"); + ntfs_log_error("Error writing non-resident attribute " + "value.\n"); return -errno; } err = ntfs_mapping_pairs_build(g_vol, (u8*)a + hdr_size + @@ -2111,8 +2112,8 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, /* Set USN to 1. */ *(le16*)((char*)ia_val + le16_to_cpu(ia_val->usa_ofs)) = cpu_to_le16(1); - ia_val->lsn = cpu_to_le64(0); - ia_val->index_block_vcn = cpu_to_le64(0); + ia_val->lsn = 0; + ia_val->index_block_vcn = 0; ia_val->index.flags = LEAF_NODE; /* Align to 8-byte boundary. */ ia_val->index.entries_offset = cpu_to_le32((sizeof(INDEX_HEADER) + @@ -2533,7 +2534,7 @@ static int initialize_quota(MFT_RECORD *m) idx_entry_q1_data->change_time = utc2ntfs(mkntfs_time()); idx_entry_q1_data->threshold = cpu_to_sle64(-1); idx_entry_q1_data->limit = cpu_to_sle64(-1); - idx_entry_q1_data->exceeded_time = const_cpu_to_le64(0x00); + idx_entry_q1_data->exceeded_time = 0; err = insert_index_entry_in_res_dir_index(idx_entry_q1, q1_size, m, NTFS_INDEX_Q, 2, AT_UNUSED); free(idx_entry_q1); @@ -2560,7 +2561,7 @@ static int initialize_quota(MFT_RECORD *m) idx_entry_q2_data->change_time = utc2ntfs(mkntfs_time());; idx_entry_q2_data->threshold = cpu_to_sle64(-1); idx_entry_q2_data->limit = cpu_to_sle64(-1); - idx_entry_q2_data->exceeded_time = const_cpu_to_le64(0x00); + idx_entry_q2_data->exceeded_time = 0; idx_entry_q2_data->sid.revision = 1; idx_entry_q2_data->sid.sub_authority_count = 2; for (i = 0; i < 5; i++) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index a6fc9926..6d215d8a 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -348,7 +348,7 @@ static void proceed_question(void) printf("Are you sure you want to proceed (y/[n])? "); buf[0] = 0; fgets(buf, sizeof(buf), stdin); - if (strchr(short_yes, buf[0]) == 0) { + if (!strchr(short_yes, buf[0])) { printf("OK quitting. NO CHANGES have been made to your " "NTFS volume.\n"); exit(1); From 67f0ef364bebc58d5dc4496eb762ac55d75f4329 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 23 Jul 2007 18:11:39 +0300 Subject: [PATCH 197/289] fix CREDITS to be in utf8, not in mixed encodings --- CREDITS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CREDITS b/CREDITS index cc8a0dc6..29bd3e4c 100644 --- a/CREDITS +++ b/CREDITS @@ -31,7 +31,7 @@ Per Olofsson Yura Pakhuchiy Yuri Per Richard Russon -Erik Sørnes +Erik Sørnes Szabolcs Szakacsits zhanglinbao From 09affc5d42bb3b45f2298d76e7405ff5c223b8f0 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 31 Jul 2007 20:40:27 +0300 Subject: [PATCH 198/289] Whitespaces cleanup --- libntfs/misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/misc.c b/libntfs/misc.c index 5cdf2da4..22d3784c 100644 --- a/libntfs/misc.c +++ b/libntfs/misc.c @@ -39,7 +39,7 @@ void *ntfs_calloc(size_t size) { void *p; - + p = calloc(1, size); if (!p) ntfs_log_perror("Failed to calloc %lld bytes", (long long)size); @@ -55,7 +55,7 @@ void *ntfs_calloc(size_t size) void *ntfs_malloc(size_t size) { void *p; - + p = malloc(size); if (!p) ntfs_log_perror("Failed to malloc %lld bytes", (long long)size); From efe2c9642c14f08652a20f5eb6e992b21e12a300 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 16 Aug 2007 13:52:18 +0300 Subject: [PATCH 199/289] minor cleanup --- ntfsprogs/ntfsmount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index a20b818f..5cd2ea2c 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1506,7 +1506,7 @@ static void usage(void) static char *realpath(const char *path, char *resolved_path) { strncpy(resolved_path, path, PATH_MAX); - resolved_path[PATH_MAX] = '\0'; + resolved_path[PATH_MAX] = 0; return resolved_path; } #endif From ad0c5f59c90ca60b7dbd81e73f3407b968936dd5 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 22 Aug 2007 16:55:57 +0300 Subject: [PATCH 200/289] Transparently integrate reading of encrypted files into library This adds crypto.[ch], several exported functions that you are not interested to use and dependency on >=libconfig-1.0.1 to read list of PFX files with keys. See libntfs/config for example configuration file. --- configure.ac | 30 +- include/ntfs/Makefile.am | 1 + include/ntfs/attrib.h | 17 +- include/ntfs/crypto.h | 44 ++ libntfs/Makefile.am | 8 + libntfs/attrib.c | 12 +- libntfs/config | 10 + libntfs/crypto.c | 1519 ++++++++++++++++++++++++++++++++++++++ ntfsprogs/Makefile.am | 3 +- ntfsprogs/ntfsdecrypt.c | 8 - ntfsprogs/ntfsmount.c | 2 +- 11 files changed, 1630 insertions(+), 24 deletions(-) create mode 100644 include/ntfs/crypto.h create mode 100644 libntfs/config create mode 100644 libntfs/crypto.c diff --git a/configure.ac b/configure.ac index 00818b36..96f68805 100644 --- a/configure.ac +++ b/configure.ac @@ -115,8 +115,8 @@ AC_ARG_ENABLE(ntfsmount, AC_ARG_ENABLE(crypto, AS_HELP_STRING(--enable-crypto,enable crypto related code and utilities - (default=no)), , - enable_crypto=no + (default=detect)), , + enable_crypto=auto ) AC_ARG_ENABLE(really-static, @@ -137,7 +137,7 @@ AC_ARG_ENABLE(test, ) AM_CONDITIONAL(ENABLE_TEST, test "$enable_test" = yes) if test "$enable_test" = "yes"; then - CFLAGS="$CFLAGS -DNTFS_TEST" + CFLAGS="${CFLAGS} -DNTFS_TEST" fi AH_TEMPLATE([NTFS_DISABLE_DEBUG_LOGGING], @@ -212,7 +212,7 @@ AM_CONDITIONAL(ENABLE_FUSE, $compile_ntfsmount) compile_crypto=false if test "$enable_crypto" != "no"; then have_libgcrypt=false - AM_PATH_LIBGCRYPT(1.2.0, [ have_libgcrypt=true ], + AM_PATH_LIBGCRYPT(1.2.2, [ have_libgcrypt=true ], [ if test "$enable_crypto" = "yes"; then AC_MSG_ERROR([Linux-NTFS crypto code requires the gcrypt library.]) @@ -221,17 +221,29 @@ if test "$enable_crypto" != "no"; then fi ]) have_libgnutls=false - AM_PATH_LIBGNUTLS(1.2.8, [ have_libgnutls=true ], - [ + PKG_CHECK_MODULES(GNUTLS, gnutls >= 1.4.4, [ have_libgnutls=true ], if test "$enable_crypto" = "yes"; then AC_MSG_ERROR([Linux-NTFS crypto code requires the gnutls library.]) else AC_MSG_WARN([Linux-NTFS crypto code requires the gnutls library.]) fi - ]) + ) + have_libconfig=false + PKG_CHECK_MODULES(libconfig, libconfig >= 1.0.1, [ have_libconfig=true ], + if test "$enable_crypto" = "yes"; then + AC_MSG_ERROR([Linux-NTFS crypto code requires the libconfig.]) + else + AC_MSG_WARN([Linux-NTFS crypto code requires the libconfig.]) + fi + ) if test "$have_libgcrypt" = "true"; then if test "$have_libgnutls" = "true"; then - compile_crypto=true + if test "$have_libconfig" = "true"; then + compile_crypto=true + AC_DEFINE([ENABLE_CRYPTO], 1, + [Define this to 1 if you want to enable support of + encrypted files in libntfs and utilities.]) + fi fi fi fi @@ -345,7 +357,7 @@ AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \ endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \ sys/ioctl.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \ sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \ - machine/endian.h gcrypt.h windows.h gnutls/pkcs12.h syslog.h]) + machine/endian.h windows.h syslog.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL diff --git a/include/ntfs/Makefile.am b/include/ntfs/Makefile.am index 1b9a0433..0e3eb039 100644 --- a/include/ntfs/Makefile.am +++ b/include/ntfs/Makefile.am @@ -8,6 +8,7 @@ linux_ntfsinclude_HEADERS = \ collate.h \ compat.h \ compress.h \ + crypto.h \ debug.h \ device.h \ device_io.h \ diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index 99665f31..1ab2dd4f 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -34,6 +34,7 @@ typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx; #include "volume.h" #include "debug.h" #include "logging.h" +#include "crypto.h" extern ntfschar AT_UNNAMED[]; @@ -140,6 +141,7 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx) * @compression_block_size: size of a compression block (cb) * @compression_block_size_bits: log2 of the size of a cb * @compression_block_clusters: number of clusters per cb + * @crypto: (valid only for encrypted) see description below * * This structure exists purely to provide a mechanism of caching the runlist * of an attribute. If you want to operate on a particular attribute extent, @@ -166,6 +168,17 @@ static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx) * * @state contains NTFS attribute specific flags describing this attribute * structure. See ntfs_attr_state_bits above. + * + * @crypto points to private structure of crypto code. You should not access + * fields of this structure, but you can check whether it is NULL or not. If it + * is not NULL, then we successfully obtained FEK (File Encryption Key) and + * ntfs_attr_p{read,write} calls probably would succeed. If it is NULL, then we + * failed to obtain FEK (do not have corresponding PFX file, wrong password, + * etc..) or library was compiled without crypto support. Attribute size can be + * changed without knowledge of FEK, so you can use ntfs_attr_truncate in any + * case. + * NOTE: This field valid only if attribute encrypted (eg., NAttrEncrypted + * returns non-zero). */ struct _ntfs_attr { runlist_element *rl; @@ -181,10 +194,12 @@ struct _ntfs_attr { u32 compression_block_size; u8 compression_block_size_bits; u8 compression_block_clusters; + ntfs_crypto_attr *crypto; }; /** - * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr structure + * enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr + * structure */ typedef enum { NA_Initialized, /* 1: structure is initialized. */ diff --git a/include/ntfs/crypto.h b/include/ntfs/crypto.h new file mode 100644 index 00000000..6f8361d9 --- /dev/null +++ b/include/ntfs/crypto.h @@ -0,0 +1,44 @@ +/** + * crypto.h - Exports for dealing with encrypted files. Part of the + * Linux-NTFS project. + * + * Copyright (c) 2007 Yura Pakhuchiy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_CRYPTO_H +#define _NTFS_CRYPTO_H + +/* + * This is our Big Secret (TM) structure, so do not allow anyone even read it + * values. ;-) In fact, it is private because exist only in libntfs version + * compiled with cryptography support, so users can not depend on it. + */ +typedef struct _ntfs_crypto_attr ntfs_crypto_attr; + +/* + * These functions should not be used directly. They are called for encrypted + * attributes from corresponding functions without _crypto_ part. + */ + +extern int ntfs_crypto_attr_open(ntfs_attr *na); +extern void ntfs_crypto_attr_close(ntfs_attr *na); + +extern s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count, + void *b); + +#endif /* _NTFS_CRYPTO_H */ diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index 072719b8..10655eb9 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -32,9 +32,16 @@ LTVERSION_LIBNTFS_GNOMEVFS = 1:0:0 linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs lib_LTLIBRARIES = libntfs.la + libntfs_la_LDFLAGS = -version-info $(LTVERSION_LIBNTFS) -no-undefined libntfs_la_CFLAGS = $(LIBNTFS_CFLAGS) \ -DLTVERSION_LIBNTFS=\"$(LTVERSION_LIBNTFS)\" + +if ENABLE_CRYPTO +libntfs_la_LDFLAGS += `libgnutls-config --libs` `pkg-config --libs libconfig` +libntfs_la_CFLAGS += `libgnutls-config --cflags` `pkg-config --cflags libconfig` +endif + libntfs_la_SOURCES = \ attrib.c \ attrlist.c \ @@ -43,6 +50,7 @@ libntfs_la_SOURCES = \ collate.c \ compat.c \ compress.c \ + crypto.c \ debug.c \ device.c \ device_io.c \ diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 9e91b3e4..60e61edb 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -57,6 +57,7 @@ #include "bitmap.h" #include "logging.h" #include "support.h" +#include "crypto.h" ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') }; @@ -426,6 +427,8 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, (l + 7) & ~7, l, l, cs ? (l + 7) & ~7 : 0, 0); } ntfs_attr_put_search_ctx(ctx); + if (NAttrEncrypted(na)) + ntfs_crypto_attr_open(na); return na; put_err_out: ntfs_attr_put_search_ctx(ctx); @@ -446,6 +449,8 @@ void ntfs_attr_close(ntfs_attr *na) { if (!na) return; + if (NAttrEncrypted(na)) + ntfs_crypto_attr_close(na); if (NAttrNonResident(na) && na->rl) free(na->rl); /* Don't release if using an internal constant. */ @@ -855,10 +860,9 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) * Encrypted non-resident attributes are not supported. We return * access denied, which is what Windows NT4 does, too. */ - if (NAttrEncrypted(na) && NAttrNonResident(na)) { - errno = EACCES; - return -1; - } + if (NAttrEncrypted(na) && NAttrNonResident(na)) + return ntfs_crypto_attr_pread(na, pos, count, b); + vol = na->ni->vol; /* Update access time if needed. */ if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || diff --git a/libntfs/config b/libntfs/config new file mode 100644 index 00000000..71a18d99 --- /dev/null +++ b/libntfs/config @@ -0,0 +1,10 @@ +# libntfs sample configuration file + +crypto : { + keys = ( + ("/home/yura/ntfs/my3.pfx", "my3"), # key with password +# ("/home/yura/ntfs/my-rec.pfx", ""), // password-less key + ("/home/yura/ntfs/my.pfx") /* password-less key */ + ); +}; + diff --git a/libntfs/crypto.c b/libntfs/crypto.c new file mode 100644 index 00000000..e448cf84 --- /dev/null +++ b/libntfs/crypto.c @@ -0,0 +1,1519 @@ +/** + * crypto.c - Routines for dealing with encrypted files. Part of the + * Linux-NTFS project. + * + * Copyright (c) 2005 Yuval Fledel + * Copyright (c) 2005-2007 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: Cleanup this file. Write nice descriptions for non-exported functions + * and maybe clean up namespace (not necessary for all functions to belong to + * ntfs_crypto, we can have ntfs_fek, ntfs_rsa, etc.., but there should be + * maximum 2-3 namespaces, not every function begins with it own namespace + * like now). + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "attrib.h" +#include "types.h" +#include "volume.h" +#include "debug.h" +#include "dir.h" +#include "layout.h" +#include "crypto.h" + +#ifdef ENABLE_CRYPTO + +#include +#include +#include + +#include + +#define NTFS_CONFIG_PATH_SYSTEM "/etc/libntfs/config" +#define NTFS_CONFIG_PATH_USER ".libntfs/config" + +#define NTFS_SHA1_THUMBPRINT_SIZE 0x14 + +#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3) + +#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4" +#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1" + +#define NTFS_EFS_SECTOR_SIZE 512 + +typedef enum { + DF_TYPE_UNKNOWN, + DF_TYPE_DDF, + DF_TYPE_DRF, +} NTFS_DF_TYPES; + +/** + * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit) + * + * To choose which one is used in Windows, create or set the REG_DWORD registry + * key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\ + * AlgorithmID to the value of your chosen crypto algorithm, e.g. to use DesX, + * set AlgorithmID to 0x6604. + * + * Note that the Windows versions I have tried so far (all are high crypto + * enabled) ignore the AlgorithmID value if it is not one of CALG_3DES, + * CALG_DESX, or CALG_AES_256, i.e. you cannot select CALG_DES at all using + * this registry key. It would be interesting to check out encryption on one + * of the "crippled" crypto Windows versions... + */ +typedef enum { + CALG_DES = const_cpu_to_le32(0x6601), + /* If not one of the below three, fall back to standard Des. */ + CALG_3DES = const_cpu_to_le32(0x6603), + CALG_DESX = const_cpu_to_le32(0x6604), + CALG_AES_256 = const_cpu_to_le32(0x6610), +} NTFS_CRYPTO_ALGORITHMS; + +/** + * struct ntfs_fek - Decrypted, in-memory file encryption key. + */ +struct _ntfs_fek { + gcry_cipher_hd_t gcry_cipher_hd; + le32 alg_id; + u8 *key_data; + gcry_cipher_hd_t *des_gcry_cipher_hd_ptr; +}; + +typedef struct _ntfs_fek ntfs_fek; + +struct _ntfs_crypto_attr { + ntfs_fek *fek; +}; + +typedef struct { + u64 in_whitening, out_whitening; + gcry_cipher_hd_t gcry_cipher_hd; +} ntfs_desx_ctx; + +static ntfschar NTFS_EFS[5] = { + const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'), + const_cpu_to_le16('S'), const_cpu_to_le16(0) +}; + +typedef struct { + gcry_sexp_t key; + NTFS_DF_TYPES df_type; + char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE]; +} ntfs_rsa_private_key_t; + +/* + * Yes, global variables sucks, but we need to keep whether we performed + * gcrypt/gnutls global initialization and keep user's RSA keys. + */ +typedef struct { + int initialized; + int desx_alg_id; + gcry_module_t desx_module; + ntfs_rsa_private_key_t **rsa_key; + int nr_rsa_keys; +} ntfs_crypto_ctx_t; + +static ntfs_crypto_ctx_t ntfs_crypto_ctx = { + .desx_alg_id = -1, + .desx_module = NULL, +}; + +/** + * ntfs_pkcs12_load_pfxfile + */ +static int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx, + unsigned *pfx_size) +{ + int f, to_read, total, attempts, br; + struct stat key_stat; + + if (!keyfile || !pfx || !pfx_size) { + ntfs_log_error("You have to specify the key file, a pointer " + "to hold the key file contents, and a pointer " + "to hold the size of the key file contents.\n"); + return -1; + } + f = open(keyfile, O_RDONLY); + if (f == -1) { + ntfs_log_perror("Failed to open key file"); + return -1; + } + if (fstat(f, &key_stat) == -1) { + ntfs_log_perror("Failed to stat key file"); + goto file_out; + } + if (!S_ISREG(key_stat.st_mode)) { + ntfs_log_error("Key file is not a regular file, cannot read " + "it.\n"); + goto file_out; + } + if (!key_stat.st_size) { + ntfs_log_error("Key file has zero size.\n"); + goto file_out; + } + *pfx = malloc(key_stat.st_size + 1); + if (!*pfx) { + ntfs_log_perror("Failed to allocate buffer for key file " + "contents"); + goto file_out; + } + to_read = key_stat.st_size; + total = attempts = 0; + do { + br = read(f, *pfx + total, to_read); + if (br == -1) { + ntfs_log_perror("Failed to read from key file"); + goto free_out; + } + if (!br) + attempts++; + to_read -= br; + total += br; + } while (to_read > 0 && attempts < 3); + close(f); + /* Make sure it is zero terminated. */ + (*pfx)[key_stat.st_size] = 0; + *pfx_size = key_stat.st_size; + return 0; +free_out: + free(*pfx); +file_out: + close(f); + return -1; +} + +/** + * ntfs_rsa_private_key_import_from_gnutls + */ +static gcry_sexp_t ntfs_rsa_private_key_import_from_gnutls( + gnutls_x509_privkey_t priv_key) +{ + int i, j; + size_t tmp_size; + gnutls_datum_t rd[6]; + gcry_mpi_t rm[6]; + gcry_sexp_t rsa_key; + + /* Extract the RSA parameters from the GNU TLS private key. */ + if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1], + &rd[2], &rd[3], &rd[4], &rd[5])) { + ntfs_log_error("Failed to export rsa parameters. (Is the " + "key an RSA private key?)\n"); + return NULL; + } + /* Convert each RSA parameter to MPI format. */ + for (i = 0; i < 6; i++) { + if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data, + rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to convert RSA parameter %i " + "to mpi format (size %d)\n", i, + rd[i].size); + rsa_key = NULL; + break; + } + } + /* Release the no longer needed datum values. */ + for (j = 0; j < 6; j++) { + if (rd[j].data && rd[j].size) + gnutls_free(rd[j].data); + } + /* + * Build the gcrypt private key, note libgcrypt uses p and q inversed + * to what gnutls uses. + */ + if (i == 6 && gcry_sexp_build(&rsa_key, NULL, + "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", + rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) != + GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to build RSA private key s-exp.\n"); + rsa_key = NULL; + } + /* Release the no longer needed MPI values. */ + for (j = 0; j < i; j++) + gcry_mpi_release(rm[j]); + return rsa_key; +} + +/** + * ntfs_rsa_private_key_release + */ +static void ntfs_rsa_private_key_release(ntfs_rsa_private_key_t *rsa_key) +{ + if (rsa_key) { + if (rsa_key->key) + gcry_sexp_release(rsa_key->key); + free(rsa_key); + } +} + +/** + * ntfs_pkcs12_extract_rsa_key + */ +static ntfs_rsa_private_key_t *ntfs_pkcs12_extract_rsa_key(u8 *pfx, + int pfx_size, const char *password) +{ + int err, bag_index, flags; + gnutls_datum_t dpfx, dkey; + gnutls_pkcs12_t pkcs12 = NULL; + gnutls_pkcs12_bag_t bag = NULL; + gnutls_x509_privkey_t pkey = NULL; + gnutls_x509_crt_t crt = NULL; + ntfs_rsa_private_key_t *rsa_key = NULL; + char purpose_oid[100]; + size_t purpose_oid_size = sizeof(purpose_oid); + size_t tp_size; + BOOL have_thumbprint = FALSE; + + rsa_key = malloc(sizeof(ntfs_rsa_private_key_t)); + if (!rsa_key) { + ntfs_log_perror("%s", __FUNCTION__); + return NULL; + } + rsa_key->df_type = DF_TYPE_UNKNOWN; + rsa_key->key = NULL; + tp_size = sizeof(rsa_key->thumbprint); + /* Create a pkcs12 structure. */ + err = gnutls_pkcs12_init(&pkcs12); + if (err) { + ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n", + gnutls_strerror(err)); + goto err; + } + /* Convert the PFX file (DER format) to native pkcs12 format. */ + dpfx.data = pfx; + dpfx.size = pfx_size; + err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0); + if (err) { + ntfs_log_error("Failed to convert the PFX file from DER to " + "native PKCS#12 format: %s\n", + gnutls_strerror(err)); + goto err; + } + /* + * Verify that the password is correct and that the key file has not + * been tampered with. Note if the password has zero length and the + * verification fails, retry with password set to NULL. This is needed + * to get password less .pfx files generated with Windows XP SP1 (and + * probably earlier versions of Windows) to work. + */ +retry_verify: + err = gnutls_pkcs12_verify_mac(pkcs12, password); + if (err) { + if (err == GNUTLS_E_MAC_VERIFY_FAILED && + password && !strlen(password)) { + password = NULL; + goto retry_verify; + } + ntfs_log_error("You are probably misspelled password to PFX " + "file.\n"); + goto err; + } + for (bag_index = 0; ; bag_index++) { + err = gnutls_pkcs12_bag_init(&bag); + if (err) { + ntfs_log_error("Failed to initialize PKCS#12 Bag " + "structure: %s\n", + gnutls_strerror(err)); + goto err; + } + err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag); + if (err) { + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + err = 0; + break; + } + ntfs_log_error("Failed to obtain Bag from PKCS#12 " + "structure: %s\n", + gnutls_strerror(err)); + goto err; + } +check_again: + err = gnutls_pkcs12_bag_get_count(bag); + if (err < 0) { + ntfs_log_error("Failed to obtain Bag count: %s\n", + gnutls_strerror(err)); + goto err; + } + err = gnutls_pkcs12_bag_get_type(bag, 0); + if (err < 0) { + ntfs_log_error("Failed to determine Bag type: %s\n", + gnutls_strerror(err)); + goto err; + } + flags = 0; + switch (err) { + case GNUTLS_BAG_PKCS8_KEY: + flags = GNUTLS_PKCS_PLAIN; + case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: + err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); + if (err < 0) { + ntfs_log_error("Failed to obtain Bag data: " + "%s\n", gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_privkey_init(&pkey); + if (err) { + ntfs_log_error("Failed to initialized " + "private key structure: %s\n", + gnutls_strerror(err)); + goto err; + } + /* Decrypt the private key into GNU TLS format. */ + err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey, + GNUTLS_X509_FMT_DER, password, flags); + if (err) { + ntfs_log_error("Failed to convert private " + "key from DER to GNU TLS " + "format: %s\n", + gnutls_strerror(err)); + goto err; + } +#if 0 + /* + * Export the key again, but unencrypted, and output it + * to stderr. Note the output has an RSA header so to + * compare to openssl pkcs12 -nodes -in myfile.pfx + * output need to ignore the part of the key between + * the first "MII..." up to the second "MII...". The + * actual RSA private key begins at the second "MII..." + * and in my testing at least was identical to openssl + * output and was also identical both on big and little + * endian so gnutls should be endianness safe. + */ + char *buf = malloc(8192); + size_t bufsize = 8192; + err = gnutls_x509_privkey_export_pkcs8(pkey, + GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf, + &bufsize); + if (err) { + ntfs_log_error("eek1\n"); + exit(1); + } + ntfs_log_error("%s\n", buf); + free(buf); +#endif + /* Convert the private key to our internal format. */ + rsa_key->key = + ntfs_rsa_private_key_import_from_gnutls(pkey); + if (!rsa_key->key) + goto err; + break; + case GNUTLS_BAG_ENCRYPTED: + err = gnutls_pkcs12_bag_decrypt(bag, password); + if (err) { + ntfs_log_error("Failed to decrypt Bag: %s\n", + gnutls_strerror(err)); + goto err; + } + goto check_again; + case GNUTLS_BAG_CERTIFICATE: + err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); + if (err < 0) { + ntfs_log_error("Failed to obtain Bag data: " + "%s\n", gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_init(&crt); + if (err) { + ntfs_log_error("Failed to initialize " + "certificate structure: %s\n", + gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_import(crt, &dkey, + GNUTLS_X509_FMT_DER); + if (err) { + ntfs_log_error("Failed to convert certificate " + "from DER to GNU TLS format: " + "%s\n", gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_get_key_purpose_oid(crt, 0, + purpose_oid, &purpose_oid_size, NULL); + if (err) { + ntfs_log_error("Failed to get key purpose " + "OID: %s\n", + gnutls_strerror(err)); + goto err; + } + purpose_oid[purpose_oid_size - 1] = 0; + if (!strcmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DRF)) + rsa_key->df_type = DF_TYPE_DRF; + else if (!strcmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DDF)) + rsa_key->df_type = DF_TYPE_DDF; + else { + ntfs_log_error("Certificate has unknown " + "purpose OID %s.\n", + purpose_oid); + err = EINVAL; + goto err; + } + /* Return the thumbprint to the caller. */ + err = gnutls_x509_crt_get_fingerprint(crt, + GNUTLS_DIG_SHA1, rsa_key->thumbprint, + &tp_size); + if (err) { + ntfs_log_error("Failed to get thumbprint: " + "%s\n", gnutls_strerror(err)); + goto err; + } + if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) { + ntfs_log_error("Invalid thumbprint size %zd. " + "Should be %d.\n", tp_size, + sizeof(rsa_key->thumbprint)); + err = EINVAL; + goto err; + } + have_thumbprint = TRUE; + gnutls_x509_crt_deinit(crt); + crt = NULL; + break; + default: + /* We do not care about other types. */ + break; + } + gnutls_pkcs12_bag_deinit(bag); + } +err: + if (err || !rsa_key->key || rsa_key->df_type == DF_TYPE_UNKNOWN || + !have_thumbprint) { + if (!err) + ntfs_log_error("Key type or thumbprint not found, " + "aborting.\n"); + ntfs_rsa_private_key_release(rsa_key); + rsa_key = NULL; + } + if (crt) + gnutls_x509_crt_deinit(crt); + if (pkey) + gnutls_x509_privkey_deinit(pkey); + if (bag) + gnutls_pkcs12_bag_deinit(bag); + if (pkcs12) + gnutls_pkcs12_deinit(pkcs12); + return rsa_key; +} + +/** + * ntfs_buffer_reverse - + * + * This is a utility function for reversing the order of a buffer in place. + * Users of this function should be very careful not to sweep byte order + * problems under the rug. + */ +static inline void ntfs_buffer_reverse(u8 *buf, unsigned buf_size) +{ + unsigned i; + u8 t; + + for (i = 0; i < buf_size / 2; i++) { + t = buf[i]; + buf[i] = buf[buf_size - i - 1]; + buf[buf_size - i - 1] = t; + } +} + +#ifndef HAVE_STRNLEN +/** + * strnlen - strnlen is a gnu extension so emulate it if not present + */ +static size_t strnlen(const char *s, size_t maxlen) +{ + const char *p, *end; + + /* Look for a '\0' character. */ + for (p = s, end = s + maxlen; p < end && *p; p++) + ; + return p - s; +} +#endif /* ! HAVE_STRNLEN */ + +/** + * ntfs_raw_fek_decrypt - + * + * Note: decrypting into the input buffer. + */ +static unsigned ntfs_raw_fek_decrypt(u8 *fek, u32 fek_size, + ntfs_rsa_private_key_t *rsa_key) +{ + gcry_mpi_t fek_mpi; + gcry_sexp_t fek_sexp, fek_sexp2; + gcry_error_t err; + size_t size, padding; + + /* Reverse the raw FEK. */ + ntfs_buffer_reverse(fek, fek_size); + /* Convert the FEK to internal MPI format. */ + err = gcry_mpi_scan(&fek_mpi, GCRYMPI_FMT_USG, fek, fek_size, NULL); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to convert file encryption key to " + "internal MPI format: %s\n", + gcry_strerror(err)); + return 0; + } + /* Create an internal S-expression from the FEK. */ + err = gcry_sexp_build(&fek_sexp, NULL, + "(enc-val (flags) (rsa (a %m)))", fek_mpi); + gcry_mpi_release(fek_mpi); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to create internal S-expression of " + "the file encryption key: %s\n", + gcry_strerror(err)); + return 0; + } + /* Decrypt the FEK. */ + err = gcry_pk_decrypt(&fek_sexp2, fek_sexp, rsa_key->key); + gcry_sexp_release(fek_sexp); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to decrypt the file encryption key: " + "%s\n", gcry_strerror(err)); + return 0; + } + /* Extract the actual FEK from the decrypted raw S-expression. */ + fek_sexp = gcry_sexp_find_token(fek_sexp2, "value", 0); + gcry_sexp_release(fek_sexp2); + if (!fek_sexp) { + ntfs_log_error("Failed to find the decrypted file encryption " + "key in the internal S-expression.\n"); + return 0; + } + /* Convert the decrypted FEK S-expression into MPI format. */ + fek_mpi = gcry_sexp_nth_mpi(fek_sexp, 1, GCRYMPI_FMT_USG); + gcry_sexp_release(fek_sexp); + if (!fek_mpi) { + ntfs_log_error("Failed to convert the decrypted file " + "encryption key S-expression to internal MPI " + "format.\n"); + return 0; + } + /* Convert the decrypted FEK from MPI format to binary data. */ + err = gcry_mpi_print(GCRYMPI_FMT_USG, fek, fek_size, &size, fek_mpi); + gcry_mpi_release(fek_mpi); + if (err != GPG_ERR_NO_ERROR || !size) { + ntfs_log_error("Failed to convert decrypted file encryption " + "key from internal MPI format to binary data: " + "%s\n", gcry_strerror(err)); + return 0; + } + /* + * Finally, remove the PKCS#1 padding and return the size of the + * decrypted FEK. + */ + padding = strnlen((char *)fek, size) + 1; + if (padding > size) { + ntfs_log_error("Failed to remove PKCS#1 padding from " + "decrypted file encryption key.\n"); + return 0; + } + size -= padding; + memmove(fek, fek + padding, size); + return size; +} + +/** + * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key + * @src: source buffer containing 128-bit key + * + * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the + * out-whitening keys required to perform desx {de,en}cryption. + */ +static gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key, + u64 *out_whitening, u64 *in_whitening) +{ + static const u8 *salt1 = (const u8*)"Dan Simon "; + static const u8 *salt2 = (const u8*)"Scott Field"; + static const int salt_len = 12; + gcry_md_hd_t hd1, hd2; + u32 *md; + gcry_error_t err; + + err = gcry_md_open(&hd1, GCRY_MD_MD5, 0); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to open MD5 digest.\n"); + return err; + } + /* Hash the on-disk key. */ + gcry_md_write(hd1, src, 128 / 8); + /* Copy the current hash for efficiency. */ + err = gcry_md_copy(&hd2, hd1); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to copy MD5 digest object.\n"); + goto out; + } + /* Hash with the first salt and store the result. */ + gcry_md_write(hd1, salt1, salt_len); + md = (u32*)gcry_md_read(hd1, 0); + des_key[0] = md[0] ^ md[1]; + des_key[1] = md[2] ^ md[3]; + /* Hash with the second salt and store the result. */ + gcry_md_write(hd2, salt2, salt_len); + md = (u32*)gcry_md_read(hd2, 0); + *out_whitening = *(u64*)md; + *in_whitening = *(u64*)(md + 2); + gcry_md_close(hd2); +out: + gcry_md_close(hd1); + return err; +} + +/** + * ntfs_desx_setkey - libgcrypt set_key implementation for DES-X-MS128 + * @context: pointer to a variable of type ntfs_desx_ctx + * @key: the 128 bit DES-X-MS128 key, concated with the DES handle + * @keylen: must always be 16 + * + * This is the libgcrypt set_key implementation for DES-X-MS128. + */ +static gcry_err_code_t ntfs_desx_setkey(void *context, const u8 *key, + unsigned keylen) +{ + ntfs_desx_ctx *ctx = context; + gcry_error_t err; + u8 des_key[8]; + + if (keylen != 16) { + ntfs_log_error("Key length for desx must be 16.\n"); + return GPG_ERR_INV_KEYLEN; + } + err = gcry_cipher_open(&ctx->gcry_cipher_hd, GCRY_CIPHER_DES, + GCRY_CIPHER_MODE_ECB, 0); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to open des cipher (error 0x%x).\n", + err); + return err; + } + err = ntfs_desx_key_expand(key, (u32*)des_key, &ctx->out_whitening, + &ctx->in_whitening); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to expand desx key (error 0x%x).\n", + err); + gcry_cipher_close(ctx->gcry_cipher_hd); + return err; + } + err = gcry_cipher_setkey(ctx->gcry_cipher_hd, des_key, sizeof(des_key)); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to set des key (error 0x%x).\n", err); + gcry_cipher_close(ctx->gcry_cipher_hd); + return err; + } + /* + * Take a note of the ctx->gcry_cipher_hd since we need to close it at + * ntfs_decrypt_data_key_close() time. + */ + **(gcry_cipher_hd_t***)(key + ((keylen + 7) & ~7)) = + &ctx->gcry_cipher_hd; + return GPG_ERR_NO_ERROR; +} + +/** + * ntfs_desx_decrypt + */ +static void ntfs_desx_decrypt(void *context, u8 *outbuf, const u8 *inbuf) +{ + ntfs_desx_ctx *ctx = context; + gcry_error_t err; + + err = gcry_cipher_reset(ctx->gcry_cipher_hd); + if (err != GPG_ERR_NO_ERROR) + ntfs_log_error("Failed to reset des cipher (error 0x%x).\n", + err); + *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening; + err = gcry_cipher_encrypt(ctx->gcry_cipher_hd, outbuf, 8, NULL, 0); + if (err != GPG_ERR_NO_ERROR) + ntfs_log_error("Des decryption failed (error 0x%x).\n", err); + *(u64*)outbuf ^= ctx->in_whitening; +} + +static gcry_cipher_spec_t ntfs_desx_cipher = { + .name = "DES-X-MS128", + .blocksize = 8, + .keylen = 128, + .contextsize = sizeof(ntfs_desx_ctx), + .setkey = ntfs_desx_setkey, + .decrypt = ntfs_desx_decrypt, +}; + +#ifdef NTFS_TEST +/* + * Do not remove this test code from this file! (AIA) + * It would be nice to move all tests (these and runlist) out of the library + * (at least, into the separate file{,s}), so they would not annoy eyes. (Yura) + */ + +/** + * ntfs_desx_key_expand_test + */ +static BOOL ntfs_desx_key_expand_test(void) +{ + const u8 known_desx_on_disk_key[16] = { + 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f, + 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30 + }; + const u8 known_des_key[8] = { + 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f, + }; + const u8 known_out_whitening[8] = { + 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d, + }; + const u8 known_in_whitening[8] = { + 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e + }; + u64 test_out_whitening, test_in_whitening; + union { + u64 u64; + u32 u32[2]; + } test_des_key; + gcry_error_t err; + BOOL res; + + err = ntfs_desx_key_expand(known_desx_on_disk_key, test_des_key.u32, + &test_out_whitening, &test_in_whitening); + if (err != GPG_ERR_NO_ERROR) + res = FALSE; + else + res = test_des_key.u64 == *(u64*)known_des_key && + test_out_whitening == + *(u64*)known_out_whitening && + test_in_whitening == + *(u64*)known_in_whitening; + ntfs_log_error("Testing whether ntfs_desx_key_expand() works: %s\n", + res ? "SUCCESS" : "FAILED"); + return res; +} + +/** + * ntfs_des_test + */ +static BOOL ntfs_des_test(void) +{ + const u8 known_des_key[8] = { + 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f + }; + const u8 known_des_encrypted_data[8] = { + 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f + }; + const u8 known_decrypted_data[8] = { + 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09 + }; + u8 test_decrypted_data[8]; + int res; + gcry_error_t err; + gcry_cipher_hd_t gcry_cipher_hd; + + err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES, + GCRY_CIPHER_MODE_ECB, 0); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to open des cipher (error 0x%x).\n", + err); + return FALSE; + } + err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key, + sizeof(known_des_key)); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to set des key (error 0x%x.\n", err); + gcry_cipher_close(gcry_cipher_hd); + return FALSE; + } + /* + * Apply DES decryption (ntfs actually uses encryption when decrypting). + */ + err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data, + sizeof(test_decrypted_data), known_des_encrypted_data, + sizeof(known_des_encrypted_data)); + gcry_cipher_close(gcry_cipher_hd); + if (err) { + ntfs_log_error("Failed to des decrypt test data (error " + "0x%x).\n", err); + return FALSE; + } + res = !memcmp(test_decrypted_data, known_decrypted_data, + sizeof(known_decrypted_data)); + ntfs_log_error("Testing whether des decryption works: %s\n", + res ? "SUCCESS" : "FAILED"); + return res; +} + +#else /* !defined(NTFS_TEST) */ + +/** + * ntfs_desx_key_expand_test + */ +static inline BOOL ntfs_desx_key_expand_test(void) +{ + return TRUE; +} + +/** + * ntfs_des_test + */ +static inline BOOL ntfs_des_test(void) +{ + return TRUE; +} + +#endif /* !defined(NTFS_TEST) */ + +/** + * ntfs_fek_import_from_raw + */ +static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, + unsigned fek_size) +{ + ntfs_fek *fek; + u32 key_size, wanted_key_size, gcry_algo; + gcry_error_t err; + + key_size = le32_to_cpup(fek_buf); + ntfs_log_debug("key_size 0x%x\n", key_size); + if (key_size + 16 > fek_size) { + ntfs_log_debug("Invalid FEK. It was probably decrypted with " + "the incorrect RSA key."); + errno = EINVAL; + return NULL; + } + fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) + + sizeof(gcry_cipher_hd_t)); + if (!fek) { + errno = ENOMEM; + return NULL; + } + fek->alg_id = *(le32*)(fek_buf + 8); + ntfs_log_debug("algorithm_id 0x%x\n", le32_to_cpu(fek->alg_id)); + fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7); + memcpy(fek->key_data, fek_buf + 16, key_size); + fek->des_gcry_cipher_hd_ptr = NULL; + *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) = + &fek->des_gcry_cipher_hd_ptr; + switch (fek->alg_id) { + case CALG_DESX: + if (!ntfs_crypto_ctx.desx_module) { + if (!ntfs_desx_key_expand_test() || !ntfs_des_test()) { + err = EINVAL; + goto out; + } + err = gcry_cipher_register(&ntfs_desx_cipher, + &ntfs_crypto_ctx.desx_alg_id, + &ntfs_crypto_ctx.desx_module); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to register desx " + "cipher: %s\n", + gcry_strerror(err)); + err = EINVAL; + goto out; + } + } + wanted_key_size = 16; + gcry_algo = ntfs_crypto_ctx.desx_alg_id; + break; + case CALG_3DES: + wanted_key_size = 24; + gcry_algo = GCRY_CIPHER_3DES; + break; + case CALG_AES_256: + wanted_key_size = 32; + gcry_algo = GCRY_CIPHER_AES256; + break; + default: + wanted_key_size = 8; + gcry_algo = GCRY_CIPHER_DES; + if (fek->alg_id == CALG_DES) + ntfs_log_error("DES is not supported at present\n"); + else + ntfs_log_error("Unknown crypto algorithm 0x%x\n", + le32_to_cpu(fek->alg_id)); + ntfs_log_error(". Please email %s and say that you saw this " + "message. We will then try to implement " + "support for this algorithm.\n", NTFS_DEV_LIST); + err = EOPNOTSUPP; + goto out; + } + if (key_size != wanted_key_size) { + ntfs_log_error("%s key of %u bytes but needed size is %u " + "bytes, assuming corrupt or incorrect key. " + "Aborting.\n", + gcry_cipher_algo_name(gcry_algo), + (unsigned)key_size, (unsigned)wanted_key_size); + err = EIO; + goto out; + } + err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo, + GCRY_CIPHER_MODE_CBC, 0); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("gcry_cipher_open() failed: %s\n", + gcry_strerror(err)); + err = EINVAL; + goto out; + } + err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data, key_size); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("gcry_cipher_setkey() failed: %s\n", + gcry_strerror(err)); + gcry_cipher_close(fek->gcry_cipher_hd); + err = EINVAL; + goto out; + } + return fek; +out: + free(fek); + errno = err; + return NULL; +} + +/** + * ntfs_fek_release + */ +static void ntfs_fek_release(ntfs_fek *fek) +{ + if (fek->des_gcry_cipher_hd_ptr) + gcry_cipher_close(*fek->des_gcry_cipher_hd_ptr); + gcry_cipher_close(fek->gcry_cipher_hd); + free(fek); +} + +/** + * ntfs_df_array_fek_get + */ +static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, + ntfs_rsa_private_key_t *rsa_key) +{ + EFS_DF_HEADER *df_header; + EFS_DF_CREDENTIAL_HEADER *df_cred; + EFS_DF_CERT_THUMBPRINT_HEADER *df_cert; + u8 *fek_buf; + ntfs_fek *fek; + u32 df_count, fek_size; + unsigned i, thumbprint_size = sizeof(rsa_key->thumbprint); + + df_count = le32_to_cpu(df_array->df_count); + if (!df_count) + ntfs_log_error("There are no elements in the DF array.\n"); + df_header = (EFS_DF_HEADER*)(df_array + 1); + for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)( + (u8*)df_header + le32_to_cpu(df_header->df_length))) { + df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header + + le32_to_cpu(df_header->cred_header_offset)); + if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) { + ntfs_log_debug("Credential type is not certificate " + "thumbprint, skipping DF entry.\n"); + continue; + } + df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred + + le32_to_cpu( + df_cred->cert_thumbprint_header_offset)); + if (le32_to_cpu(df_cert->thumbprint_size) != thumbprint_size) { + ntfs_log_error("Thumbprint size %d is not valid " + "(should be %d), skipping this DF " + "entry.\n", + le32_to_cpu(df_cert->thumbprint_size), + thumbprint_size); + continue; + } + if (memcmp((u8*)df_cert + + le32_to_cpu(df_cert->thumbprint_offset), + rsa_key->thumbprint, thumbprint_size)) { + ntfs_log_debug("Thumbprints do not match, skipping " + "this DF entry.\n"); + continue; + } + /* + * The thumbprints match so this is probably the DF entry + * matching the RSA key. Try to decrypt the FEK with it. + */ + fek_size = le32_to_cpu(df_header->fek_size); + fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset); + /* Decrypt the FEK. Note: This is done in place. */ + fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key); + if (fek_size) { + /* Convert the FEK to our internal format. */ + fek = ntfs_fek_import_from_raw(fek_buf, fek_size); + if (fek) + return fek; + ntfs_log_error("Failed to convert the decrypted file " + "encryption key to internal format.\n"); + } else + ntfs_log_error("Failed to decrypt the file " + "encryption key.\n"); + } + return NULL; +} + +/** + * ntfs_inode_fek_get - + */ +static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode, + ntfs_rsa_private_key_t *rsa_key) +{ + EFS_ATTR_HEADER *efs; + EFS_DF_ARRAY_HEADER *df_array = NULL; + ntfs_fek *fek = NULL; + + /* Obtain the $EFS contents. */ + efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, NTFS_EFS, 4, + NULL); + if (!efs) { + ntfs_log_perror("Failed to read $EFS attribute"); + return NULL; + } + /* + * Depending on whether the key is a normal key or a data recovery key, + * iterate through the DDF or DRF array, respectively. + */ + if (rsa_key->df_type == DF_TYPE_DDF) { + if (efs->offset_to_ddf_array) + df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + + le32_to_cpu(efs->offset_to_ddf_array)); + else + ntfs_log_error("There are no entries in the DDF " + "array.\n"); + } else if (rsa_key->df_type == DF_TYPE_DRF) { + if (efs->offset_to_drf_array) + df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + + le32_to_cpu(efs->offset_to_drf_array)); + else + ntfs_log_error("There are no entries in the DRF " + "array.\n"); + } else + ntfs_log_error("Invalid DF type.\n"); + if (df_array) + fek = ntfs_df_array_fek_get(df_array, rsa_key); + free(efs); + return fek; +} + +/** + * ntfs_fek_decrypt_sector + */ +static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) +{ + gcry_error_t err; + + err = gcry_cipher_reset(fek->gcry_cipher_hd); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to reset cipher: %s\n", + gcry_strerror(err)); + return -1; + } + /* + * Note: You may wonder why we are not calling gcry_cipher_setiv() here + * instead of doing it by hand after the decryption. The answer is + * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give + * it a length of 16 for AES256 so it does not like it. + */ + err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0); + if (err != GPG_ERR_NO_ERROR) { + ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err)); + return -1; + } + /* Apply the IV. */ + if (fek->alg_id == CALG_AES_256) { + ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); + ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); + } else { + /* All other algorithms (Des, 3Des, DesX) use the same IV. */ + ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); + } + return 512; +} + +/** + * ntfs_crypto_deinit - perform library-wide crypto deinitialization + */ +static void ntfs_crypto_deinit(void) +{ + int i; + + if (!ntfs_crypto_ctx.initialized) + return; + + for (i = 0; i < ntfs_crypto_ctx.nr_rsa_keys; i++) + ntfs_rsa_private_key_release(ntfs_crypto_ctx.rsa_key[i]); + free(ntfs_crypto_ctx.rsa_key); + ntfs_crypto_ctx.rsa_key = NULL; + ntfs_crypto_ctx.nr_rsa_keys = 0; + gnutls_global_deinit(); + if (ntfs_crypto_ctx.desx_module) { + gcry_cipher_unregister(ntfs_crypto_ctx.desx_module); + ntfs_crypto_ctx.desx_module = NULL; + ntfs_crypto_ctx.desx_alg_id = -1; + } + ntfs_crypto_ctx.initialized = 0; +} + + +static void ntfs_crypto_parse_config(struct config_t *cfg) +{ + ntfs_crypto_ctx_t *ctx = &ntfs_crypto_ctx; + config_setting_t *cfg_keys, *cfg_key; + const char *pfx_file, *pfx_pwd; + ntfs_rsa_private_key_t *key; + u8 *pfx_buf; + unsigned pfx_size; + int i; + + /* Search for crypto.keys list. */ + cfg_keys = config_lookup(cfg, "crypto.keys"); + if (!cfg_keys) { + ntfs_log_error("Unable to find crypto.keys in config file.\n"); + return; + } + /* Iterate trough list of records about keys. */ + for (i = 0; (cfg_key = config_setting_get_elem(cfg_keys, i)); i++) { + /* Get path and password to key. */ + pfx_file = config_setting_get_string_elem(cfg_key, 0); + pfx_pwd = config_setting_get_string_elem(cfg_key, 1); + if (!pfx_file) { + ntfs_log_error("Entry number %d in section crypto.keys " + "of configuration file formed " + "incorrectly.\n", i + 1); + continue; + } + if (!pfx_pwd) + pfx_pwd = ""; + /* Load the PKCS#12 file containing the user's private key. */ + if (ntfs_pkcs12_load_pfxfile(pfx_file, &pfx_buf, &pfx_size)) { + ntfs_log_error("Failed to load key file %s.\n", + pfx_file); + continue; + } + /* + * Check whether we need to allocate memory for new key pointer. + * If yes, allocate memory for it and for 3 more pointers. + */ + if (!(ctx->nr_rsa_keys % 4)) { + ntfs_rsa_private_key_t **new; + + new = realloc(ctx->rsa_key, + sizeof(ntfs_rsa_private_key_t *) * + (ctx->nr_rsa_keys + 4)); + if (!new) { + ntfs_log_perror("Unable to store all keys"); + break; + } + ctx->rsa_key = new; + } + /* Obtain the user's private RSA key from the key file. */ + key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, pfx_pwd); + if (key) + ctx->rsa_key[ctx->nr_rsa_keys++] = key; + else + ntfs_log_error("Failed to obtain RSA key from %s\n", + pfx_file); + /* No longer need the pfx file contents. */ + free(pfx_buf); + } +} + + +static void ntfs_crypto_read_configs(void) +{ + struct config_t cfg; + char *home; + int fd = -1; + + config_init(&cfg); + /* Load system configuration file. */ + if (config_read_file(&cfg, NTFS_CONFIG_PATH_SYSTEM)) + ntfs_crypto_parse_config(&cfg); + else + if (config_error_line(&cfg)) /* Do not cry if file absent. */ + ntfs_log_error("Failed to read system configuration " + "file: %s (line %d).\n", + config_error_text(&cfg), + config_error_line(&cfg)); + /* Load user configuration file. */ + fd = open(".", O_RDONLY); /* Save current working directory. */ + if (fd == -1) { + ntfs_log_error("Failed to open working directory.\n"); + goto out; + } + home = getenv("HOME"); + if (!home) { + ntfs_log_error("Environment variable HOME is not set.\n"); + goto out; + } + if (chdir(home) == -1) { + ntfs_log_perror("chdir() to home directory failed"); + goto out; + } + if (config_read_file(&cfg, NTFS_CONFIG_PATH_USER)) + ntfs_crypto_parse_config(&cfg); + else + if (config_error_line(&cfg)) /* Do not cry if file absent. */ + ntfs_log_error("Failed to read user configuration " + "file: %s (line %d).\n", + config_error_text(&cfg), + config_error_line(&cfg)); + if (fchdir(fd) == -1) + ntfs_log_error("Failed to restore original working " + "directory.\n"); +out: + if (fd != -1) + close(fd); + config_destroy(&cfg); +} + +/** + * ntfs_crypto_init - perform library-wide crypto initializations + * + * This function is called during first call of ntfs_crypto_attr_open and + * performs gcrypt and GNU TLS initializations, then read list of PFX files + * from configuration files and load RSA keys from them. + */ +static int ntfs_crypto_init(void) +{ + int err; + + if (ntfs_crypto_ctx.initialized) + return 0; + + /* Initialize gcrypt library. Note: Must come before GNU TLS init. */ + if (gcry_control(GCRYCTL_DISABLE_SECMEM, 0) != GPG_ERR_NO_ERROR) { + ntfs_log_error("Failed to initialize the gcrypt library.\n"); + return -1; + } + /* Initialize GNU TLS library. Note: Must come after libgcrypt init. */ + err = gnutls_global_init(); + if (err < 0) { + ntfs_log_error("Failed to initialize GNU TLS library: %s\n", + gnutls_strerror(err)); + return -1; + } + /* Read crypto related sections of libntfs configuration files. */ + ntfs_crypto_read_configs(); + + ntfs_crypto_ctx.initialized = 1; + atexit(ntfs_crypto_deinit); + return 0; +} + + +/** + * ntfs_crypto_attr_open - perform crypto related initialization for attribute + * @na: ntfs attribute to perform initialization for + * + * This function is called from ntfs_attr_open for encrypted attributes and + * tries to decrypt FEK enumerating all user submitted RSA keys. If we + * successfully obtained FEK, then @na->crypto is allocated and FEK stored + * inside. In the other case @na->crypto is set to NULL. + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_crypto_attr_open(ntfs_attr *na) +{ + ntfs_fek *fek; + int i; + + if (!na || !NAttrEncrypted(na)) { + errno = EINVAL; + return -1; + } + + if (ntfs_crypto_init()) { + errno = EACCES; + return -1; + } + + for (i = 0; i < ntfs_crypto_ctx.nr_rsa_keys; i++) { + fek = ntfs_inode_fek_get(na->ni, ntfs_crypto_ctx.rsa_key[i]); + if (fek) { + na->crypto = ntfs_malloc(sizeof(ntfs_crypto_attr)); + if (!na->crypto) + return -1; + na->crypto->fek = fek; + return 0; + } + } + + na->crypto = NULL; + errno = EACCES; + return -1; +} + + +/** + * ntfs_crypto_attr_close - perform crypto related deinit for attribute + * @na: ntfs attribute to perform deinitialization for + * + * This function is called from ntfs_attr_close for encrypted attributes and + * frees memory that were allocated for it handling. + */ +void ntfs_crypto_attr_close(ntfs_attr *na) +{ + if (!na || !NAttrEncrypted(na)) + return; + + if (na->crypto) { + ntfs_fek_release(na->crypto->fek); + free(na->crypto); + } +} + + +/** + * ntfs_crypto_attr_pread - read from an encrypted attribute + * @na: ntfs attribute to read from + * @pos: byte position in the attribute to begin reading from + * @count: number of bytes to read + * @b: output data buffer + * + * This function is called from ntfs_attr_pread for encrypted attributes and + * should behave as described in ntfs_attr_pread description. + */ +s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) +{ + unsigned char *buffer; + s64 bytes_read, offset, total, length; + int i; + + if (!na || pos < 0 || count < 0 || !b || !NAttrEncrypted(na)) { + errno = EINVAL; + return -1; + } + if (!count) + return 0; + + if (!na->crypto) { + errno = EACCES; + return -1; + } + + buffer = malloc(NTFS_EFS_SECTOR_SIZE); + if (!buffer) + return -1; + + ntfs_attr_map_runlist_range(na, pos >> na->ni->vol->cluster_size_bits, + (pos + count - 1) >> na->ni->vol->cluster_size_bits); + + total = 0; + offset = ROUND_DOWN(pos, 9); + while (total < count && offset < na->data_size) { + /* Calculate number of bytes we actually want. */ + length = NTFS_EFS_SECTOR_SIZE; + if (offset + length > pos + count) + length = pos + count - offset; + if (offset + length > na->data_size) + length = na->data_size - offset; + + if (length < 0) { + total = -1; + errno = EIO; + ntfs_log_error("LIBRARY BUG!!! Please report that you " + "saw this message to %s. Thanks!", + NTFS_DEV_LIST); + break; + } + + /* Just write zeros if @offset fully beyond initialized size. */ + if (offset >= na->initialized_size) { + memset(b + total, 0, length); + total += length; + continue; + } + + bytes_read = ntfs_rl_pread(na->ni->vol, na->rl, offset, + NTFS_EFS_SECTOR_SIZE, buffer); + if (!bytes_read) + break; + if (bytes_read != NTFS_EFS_SECTOR_SIZE) { + ntfs_log_perror("%s(): ntfs_rl_pread returned %lld " + "bytes", __FUNCTION__, bytes_read); + break; + } + if ((i = ntfs_fek_decrypt_sector(na->crypto->fek, buffer, + offset)) < bytes_read) { + ntfs_log_error("%s(): Couldn't decrypt all data " + "(%u/%lld/%lld/%lld)!", __FUNCTION__, + i, (long long)bytes_read, + (long long)offset, (long long)total); + break; + } + + /* Handle partially in initialized size situation. */ + if (offset + length > na->initialized_size) + memset(buffer + (na->initialized_size - offset), 0, + offset + length - na->initialized_size); + + if (offset >= pos) + memcpy(b + total, buffer, length); + else { + length -= (pos - offset); + memcpy(b + total, buffer + (pos - offset), length); + } + total += length; + offset += bytes_read; + } + + free(buffer); + return total; +} + +#else /* !ENABLE_CRYPTO */ + +/* Stubs for crypto-disabled version of libntfs. */ + +int ntfs_crypto_attr_open(ntfs_attr *na) +{ + na->crypto = NULL; + errno = EACCES; + return -1; +} + +void ntfs_crypto_attr_close(ntfs_attr *na) +{ +} + +s64 ntfs_crypto_attr_pread(ntfs_attr *na, const s64 pos, s64 count, + void *b) +{ + errno = EACCES; + return -1; +} + +#endif /* !ENABLE_CRYPTO */ + diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 42a4aeb0..ef6016f9 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -125,7 +125,8 @@ ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS) if ENABLE_CRYPTO ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h ntfsdecrypt_LDADD = $(AM_LIBS) -ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) -lgcrypt -lgnutls +ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) `libgnutls-config --libs` +ntfsdecrypt_CFLAGS = `libgnutls-config --cflags` endif # Extra targets diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 9ec6dad1..bf77f4a8 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -25,10 +25,6 @@ #include "config.h" -#if !defined(HAVE_GCRYPT_H) || !defined(HAVE_GNUTLS_PKCS12_H) -#error A required header file is missing. Aborting. -#endif - #ifdef HAVE_SYS_TYPES_H #include #endif @@ -56,12 +52,8 @@ #ifdef HAVE_ERRNO_H #include #endif -#ifdef HAVE_GCRYPT_H #include -#endif -#ifdef HAVE_GNUTLS_PKCS12_H #include -#endif #include "types.h" #include "attrib.h" diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 5cd2ea2c..38931692 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -620,7 +620,7 @@ static int ntfs_fuse_open(const char *org_path, if (ni) { na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (na) { - if (NAttrEncrypted(na)) + if (NAttrEncrypted(na) && !na->crypto) res = -EACCES; ntfs_attr_close(na); } else From 4b58df6817785b59af349b0f2604a76e837969e2 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 22 Aug 2007 19:28:44 +0300 Subject: [PATCH 201/289] New API: ntfs_attr_get_name Add new API ntfs_attr_get_name - returns pointer to unicode name of attribute. TODO: I believe we have several such local helpers in ntfsprogs and libntfs. Find and replace them with this one. --- include/ntfs/attrib.h | 5 +++++ ntfsprogs/ntfsinfo.c | 19 +++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index 1ab2dd4f..bb911338 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -337,6 +337,11 @@ extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize); extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len); +static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr) +{ + return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset)); +} + // FIXME / TODO: Above here the file is cleaned up. (AIA) /** * get_attribute_value_length - return the length of the value of an attribute diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 907bcc9b..497514b8 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -349,22 +349,21 @@ static char *ntfsinfo_time_to_str(const sle64 sle_ntfs_clock) * null if cannot convert to multi-byte string. errno would contain the * error id. no memory allocated in that case */ -static char *ntfs_attr_get_name(ATTR_RECORD *attr) +static char *ntfs_attr_get_name_mbs(ATTR_RECORD *attr) { ntfschar *ucs_attr_name; char *mbs_attr_name = NULL; int mbs_attr_name_size; - /* calculate name position */ - ucs_attr_name = (ntfschar *)((char *)attr + le16_to_cpu(attr->name_offset)); - /* convert unicode to printable format */ - mbs_attr_name_size = ntfs_ucstombs(ucs_attr_name,attr->name_length, - &mbs_attr_name,0); - if (mbs_attr_name_size>0) { + /* Get name in unicode. */ + ucs_attr_name = ntfs_attr_get_name(attr); + /* Convert unicode to printable format. */ + mbs_attr_name_size = ntfs_ucstombs(ucs_attr_name, attr->name_length, + &mbs_attr_name, 0); + if (mbs_attr_name_size > 0) return mbs_attr_name; - } else { + else return NULL; - } } @@ -1232,7 +1231,7 @@ static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) if (a->name_length) { char *attribute_name = NULL; - attribute_name = ntfs_attr_get_name(a); + attribute_name = ntfs_attr_get_name_mbs(a); if (attribute_name) { printf("\tAttribute name:\t\t '%s'\n", attribute_name); free(attribute_name); From 6df32ed1ab08bdcb672d30ca808f147fc3d2e1ef Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 22 Aug 2007 19:30:12 +0300 Subject: [PATCH 202/289] ntfsinfo: Dump content of LOGGED_UTILITY_STREAM in hex in verbose mode --- ntfsprogs/ntfsinfo.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 497514b8..e7863e1f 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1980,13 +1980,26 @@ static void ntfs_dump_attr_property_set(ATTR_RECORD *attr __attribute__((unused) /* TODO */ } +static void ntfs_hex_dump(void *buf,unsigned int length); + /** * ntfs_dump_attr_logged_utility_stream() * * dump the property_set attribute */ -static void ntfs_dump_attr_logged_utility_stream(ATTR_RECORD *attr __attribute__((unused))) +static void ntfs_dump_attr_logged_utility_stream(ATTR_RECORD *attr, + ntfs_inode *ni) { + char *buf; + s64 size; + + if (!opts.verbose) + return; + buf = ntfs_attr_readall(ni, AT_LOGGED_UTILITY_STREAM, + ntfs_attr_get_name(attr), attr->name_length, &size); + if (buf) + ntfs_hex_dump(buf, size); + free(buf); /* TODO */ } @@ -2190,7 +2203,7 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) ntfs_dump_attr_property_set(ctx->attr); break; case AT_LOGGED_UTILITY_STREAM: - ntfs_dump_attr_logged_utility_stream(ctx->attr); + ntfs_dump_attr_logged_utility_stream(ctx->attr, inode); break; default: ntfs_dump_attr_unknown(ctx->attr); From 391929cff3acfccc2be39c29046ece2c20b0fd02 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 22 Aug 2007 18:53:17 +0300 Subject: [PATCH 203/289] Export NTFS_EFS string --- include/ntfs/crypto.h | 2 ++ libntfs/crypto.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ntfs/crypto.h b/include/ntfs/crypto.h index 6f8361d9..a4b72435 100644 --- a/include/ntfs/crypto.h +++ b/include/ntfs/crypto.h @@ -23,6 +23,8 @@ #ifndef _NTFS_CRYPTO_H #define _NTFS_CRYPTO_H +extern ntfschar NTFS_EFS[5]; + /* * This is our Big Secret (TM) structure, so do not allow anyone even read it * values. ;-) In fact, it is private because exist only in libntfs version diff --git a/libntfs/crypto.c b/libntfs/crypto.c index e448cf84..1a1b3468 100644 --- a/libntfs/crypto.c +++ b/libntfs/crypto.c @@ -134,7 +134,7 @@ typedef struct { gcry_cipher_hd_t gcry_cipher_hd; } ntfs_desx_ctx; -static ntfschar NTFS_EFS[5] = { +ntfschar NTFS_EFS[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'), const_cpu_to_le16('S'), const_cpu_to_le16(0) }; From c0b691ca172ba449aa257a9abb3698b56a8a0941 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 22 Aug 2007 21:29:19 +0300 Subject: [PATCH 204/289] Merge --enable-debug and --enable-debug-logging. Introduce --enable-sparse. --- configure.ac | 24 ++++++++++++------------ include/ntfs/debug.h | 2 +- include/ntfs/logging.h | 11 ++++++----- libntfs/debug.c | 2 +- libntfs/mft.c | 2 +- libntfs/volume.c | 4 ++-- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index 96f68805..71049793 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,11 @@ AC_ARG_ENABLE(debug, enable_debug=no ) +AC_ARG_ENABLE(sparse, + AS_HELP_STRING(--enable-sparse,enable sparse code checking), , + enable_sparse=no +) + # AH_TEMPLATE is needed here because we want to have a template in config.h # regardless of whether the option is given or not. AH_TEMPLATE([NO_NTFS_DEVICE_DEFAULT_IO_OPS], @@ -140,17 +145,6 @@ if test "$enable_test" = "yes"; then CFLAGS="${CFLAGS} -DNTFS_TEST" fi -AH_TEMPLATE([NTFS_DISABLE_DEBUG_LOGGING], - [Define this if you want to compile out the debug log messages. - This will reduce the size of the binaries.]) -AC_ARG_ENABLE(debug-logging, - AS_HELP_STRING(--enable-debug-logging,Add debug logging to the code),, - enable_debug_logging=no -) -if test "$enable_debug_logging" == "no"; then - AC_DEFINE(NTFS_DISABLE_DEBUG_LOGGING) -fi - # Use GNU extensions if available. AC_GNU_SOURCE @@ -330,7 +324,13 @@ fi # Add debugging switches if --enable-debug was specified. if test "$enable_debug" = "yes"; then - CFLAGS="$CFLAGS -ggdb3 -DDEBUG" + CFLAGS="$CFLAGS -ggdb3 -DDEBUG -O0" +fi + +# Set cgcc as compiler and add sparse flags if --enable-sparse was specified. +if test "$enable_sparse" = "yes"; then + CC="cgcc" + CFLAGS="$CFLAGS -Wbitwise -Wno-transparent-union" fi AC_SUBST(CFLAGS) diff --git a/include/ntfs/debug.h b/include/ntfs/debug.h index 57fdf3bc..bf456f12 100644 --- a/include/ntfs/debug.h +++ b/include/ntfs/debug.h @@ -30,7 +30,7 @@ struct _runlist_element; -#ifdef NTFS_DISABLE_DEBUG_LOGGING +#ifndef DEBUG static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {} #else extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl); diff --git a/include/ntfs/logging.h b/include/ntfs/logging.h index d30d545c..bde4531e 100644 --- a/include/ntfs/logging.h +++ b/include/ntfs/logging.h @@ -85,7 +85,7 @@ int ntfs_log_redirect(const char *function, const char *file, int line, #define NTFS_LOG_FLAG_COLOUR ((u32)1 << 5) /* Colour highlight some messages */ /* Macros to simplify logging. One for each level defined above. - * Note, if NTFS_DISABLE_DEBUG_LOGGING is defined, then ntfs_log_debug/trace have no effect. + * Note, if DEBUG is not defined, then ntfs_log_debug/trace have no effect. */ #define ntfs_log_critical(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_CRITICAL,NULL,FORMAT,##ARGS) #define ntfs_log_error(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS) @@ -96,16 +96,17 @@ int ntfs_log_redirect(const char *function, const char *file, int line, #define ntfs_log_verbose(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,FORMAT,##ARGS) #define ntfs_log_warning(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,FORMAT,##ARGS) -/* By default debug and trace messages are compiled into the program, +/* + * By default debug and trace messages are compiled into the program, * but not displayed. */ -#ifdef NTFS_DISABLE_DEBUG_LOGGING +#ifndef DEBUG #define ntfs_log_debug(FORMAT, ARGS...)do {} while (0) #define ntfs_log_trace(FORMAT, ARGS...)do {} while (0) -#else +#else /* !DEBUG */ #define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS) #define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS) -#endif /* NTFS_DISABLE_DEBUG_LOGGING */ +#endif /* DEBUG */ #endif /* _LOGGING_H_ */ diff --git a/libntfs/debug.c b/libntfs/debug.c index c4443023..2e3de9ca 100644 --- a/libntfs/debug.c +++ b/libntfs/debug.c @@ -32,7 +32,7 @@ #include "debug.h" #include "logging.h" -#ifndef NTFS_DISABLE_DEBUG_LOGGING +#ifdef DEBUG /** * ntfs_debug_runlist_dump - Dump a runlist. * @rl: diff --git a/libntfs/mft.c b/libntfs/mft.c index 74a28bd3..fc902219 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -465,7 +465,7 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni) "pass_end 0x%llx, data_pos 0x%llx.\n", pass, (long long)pass_start, (long long)pass_end, (long long)data_pos); -#ifndef NTFS_DISABLE_DEBUG_LOGGING +#ifdef DEBUG byte = NULL; b = 0; #endif diff --git a/libntfs/volume.c b/libntfs/volume.c index 225e2ee4..2ecb6881 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -410,7 +410,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, ntfs_volume *vol; NTFS_BOOT_SECTOR *bs; int eo; -#ifndef NTFS_DISABLE_DEBUG_LOGGING +#ifdef DEBUG const char *OK = "OK\n"; const char *FAILED = "FAILED\n"; BOOL debug = 1; @@ -778,7 +778,7 @@ out: ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) { s64 l; -#ifndef NTFS_DISABLE_DEBUG_LOGGING +#ifdef DEBUG const char *OK = "OK\n"; const char *FAILED = "FAILED\n"; #endif From f5a2ae79a9b0e59d002bbad478bcc11d1a1091f3 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 23 Aug 2007 17:39:00 +0300 Subject: [PATCH 205/289] Improve endian self-test per discussion with Anton. --- include/ntfs/endians.h | 48 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/include/ntfs/endians.h b/include/ntfs/endians.h index 0b3dd762..b3426df3 100644 --- a/include/ntfs/endians.h +++ b/include/ntfs/endians.h @@ -208,29 +208,39 @@ static void ntfs_endian_self_test(void) { /* Should not generate warnings. */ - (le16)cpu_to_le16((u16)0); - (le32)cpu_to_le32((u32)0); - (le64)cpu_to_le64((u64)0); - (sle16)cpu_to_sle16((s16)0); - (sle32)cpu_to_sle32((s32)0); - (sle64)cpu_to_sle64((s64)0); - (u16)le16_to_cpu((__force le16)0); - (u32)le32_to_cpu((__force le32)0); - (u64)le64_to_cpu((__force le64)0); - (s16)sle16_to_cpu((__force sle16)0); - (s32)sle32_to_cpu((__force sle32)0); - (s64)sle64_to_cpu((__force sle64)0); - (le16)const_cpu_to_le16((u16)0); - (le32)const_cpu_to_le32((u32)0); - (le64)const_cpu_to_le64((u64)0); - (u16)const_le16_to_cpu((__force le16)0); - (u32)const_le32_to_cpu((__force le32)0); - (u64)const_le64_to_cpu((__force le64)0); + (le16)cpu_to_le16((u16)1); + (le32)cpu_to_le32((u32)1); + (le64)cpu_to_le64((u64)1); + (sle16)cpu_to_sle16((s16)1); + (sle32)cpu_to_sle32((s32)1); + (sle64)cpu_to_sle64((s64)1); + (u16)le16_to_cpu((__force le16)1); + (u32)le32_to_cpu((__force le32)1); + (u64)le64_to_cpu((__force le64)1); + (s16)sle16_to_cpu((__force sle16)1); + (s32)sle32_to_cpu((__force sle32)1); + (s64)sle64_to_cpu((__force sle64)1); + (le16)const_cpu_to_le16((u16)1); + (le32)const_cpu_to_le32((u32)1); + (le64)const_cpu_to_le64((u64)1); + (u16)const_le16_to_cpu((__force le16)1); + (u32)const_le32_to_cpu((__force le32)1); + (u64)const_le64_to_cpu((__force le64)1); /* * TODO: Need some how to test that warnings are actually generated, * but without flooding output with them and vice-versa print warning - * in case if some one warning is not triggered, but should. Any ideas? + * in case if some one warning is not triggered, but should. (Yura) + * + * I think it can only be done in a ./configure like script / shell + * script that will compile known good and known bad code and pipe the + * output from sparse to a file, then grep the file for the wanted + * warnings/lack thereof and then it would say "Tests: PASS " or + * "Tests: FAILED" or whatever. And you can then hook that into a + * "make test" make target or similar so it is only done when one + * wants to do it... (Anton) + * + * Also we can look on sparse self test script. (Yura) */ } #endif From 65a81e35638a2c1ef870c31ca6545b715efc39d9 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 23 Aug 2007 17:58:52 +0300 Subject: [PATCH 206/289] ntfsclone do bad things about endians, so revert it to original state and put mark on it to not perform sparse bitwise checks --- include/ntfs/types.h | 2 +- ntfsprogs/ntfsclone.c | 48 +++++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/include/ntfs/types.h b/include/ntfs/types.h index bc1ad00b..cd9a9a99 100644 --- a/include/ntfs/types.h +++ b/include/ntfs/types.h @@ -46,7 +46,7 @@ typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; -#ifdef __CHECKER__ +#if defined(__CHECKER__) && !defined(NTFS_DO_NOT_CHECK_ENDIANS) #undef __bitwise #undef __force #define __bitwise __attribute__((bitwise)) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 8bb94ab0..9f78f900 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -3,7 +3,6 @@ * * Copyright (c) 2003-2006 Szabolcs Szakacsits * Copyright (c) 2004-2006 Anton Altaparmakov - * Copyright (c) 2007 Yura Pakhuchiy * Special image format support copyright (c) 2004 Per Olofsson * * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. @@ -56,6 +55,12 @@ #include #endif +/* + * FIXME: ntfsclone do bad things about endians handling. Fix it and remove + * this note and define. + */ +#define NTFS_DO_NOT_CHECK_ENDIANS + #include "debug.h" #include "types.h" #include "support.h" @@ -154,6 +159,8 @@ static unsigned int wiped_unused_mft = 0; static unsigned int wiped_resident_data = 0; static unsigned int wiped_timestamp_data = 0; +static BOOL image_is_host_endian = FALSE; + #define IMAGE_MAGIC "\0ntfsclone-image" #define IMAGE_MAGIC_SIZE 16 @@ -179,11 +186,11 @@ static struct { char magic[IMAGE_MAGIC_SIZE]; u8 major_ver; u8 minor_ver; - le32 cluster_size; - sle64 device_size; - sle64 nr_clusters; - sle64 inuse; - le32 offset_to_image_data; /* From start of image_hdr. */ + u32 cluster_size; + s64 device_size; + s64 nr_clusters; + s64 inuse; + u32 offset_to_image_data; /* From start of image_hdr. */ } __attribute__((__packed__)) image_hdr; #define NTFSCLONE_IMG_HEADER_SIZE_OLD \ @@ -611,7 +618,7 @@ static void lseek_to_cluster(s64 lcn) static void image_skip_clusters(s64 count) { if (opt.save_image && count > 0) { - sle64 count_buf; + typeof(count) count_buf; char buff[1 + sizeof(count)]; buff[0] = 0; @@ -660,8 +667,8 @@ static void clone_ntfs(u64 nr_clusters) progress_init(&progress, p_counter, nr_clusters, 100); if (opt.save_image) { - if (write_all(&fd_out, &image_hdr, le32_to_cpu( - image_hdr.offset_to_image_data)) == -1) + if (write_all(&fd_out, &image_hdr, + image_hdr.offset_to_image_data) == -1) perr_exit("write_all"); } @@ -703,7 +710,6 @@ static void write_empty_clusters(s32 csize, s64 count, static void restore_image(void) { - sle64 countle; s64 pos = 0, count; s32 csize = le32_to_cpu(image_hdr.cluster_size); char cmd; @@ -722,9 +728,10 @@ static void restore_image(void) perr_exit("read_all"); if (cmd == 0) { - if (read_all(&fd_in, &countle, sizeof(countle)) == -1) + if (read_all(&fd_in, &count, sizeof(count)) == -1) perr_exit("read_all"); - count = sle64_to_cpu(countle); + if (!image_is_host_endian) + count = sle64_to_cpu(count); if (opt.std_out) write_empty_clusters(csize, count, &progress, &p_counter); @@ -745,7 +752,7 @@ static void restore_image(void) static void wipe_index_entry_timestams(INDEX_ENTRY *e) { - sle64 timestamp = utc2ntfs(0); + s64 timestamp = utc2ntfs(0); /* FIXME: can fall into infinite loop if corrupted */ while (!(e->flags & INDEX_ENTRY_END)) { @@ -854,7 +861,7 @@ out_indexr: free(indexr); } -static void wipe_index_root_timestamps(ATTR_RECORD *attr, sle64 timestamp) +static void wipe_index_root_timestamps(ATTR_RECORD *attr, s64 timestamp) { INDEX_ENTRY *entry; INDEX_ROOT *iroot; @@ -916,7 +923,7 @@ do { \ static void wipe_timestamps(ntfs_walk_clusters_ctx *image) { ATTR_RECORD *a = image->ctx->attr; - sle64 timestamp = utc2ntfs(0); + s64 timestamp = utc2ntfs(0); if (a->type == AT_FILE_NAME) WIPE_TIMESTAMPS(FILE_NAME_ATTR, a, timestamp); @@ -1551,8 +1558,9 @@ static s64 open_image(void) #endif image_hdr.offset_to_image_data = const_cpu_to_le32((sizeof(image_hdr) + 7) & ~7); + image_is_host_endian = TRUE; } else { - le32 offset_to_image_data; + typeof(image_hdr.offset_to_image_data) offset_to_image_data; int delta; if (image_hdr.major_ver > NTFSCLONE_IMG_VER_MAJOR) @@ -1565,16 +1573,16 @@ static s64 open_image(void) if (read_all(&fd_in, &offset_to_image_data, sizeof(offset_to_image_data)) == -1) perr_exit("read_all"); - image_hdr.offset_to_image_data = offset_to_image_data; + image_hdr.offset_to_image_data = + le32_to_cpu(offset_to_image_data); /* * Read any fields from the header that we have not read yet so * that the input stream is positioned correctly. This means * we can support future minor versions that just extend the * header in a backwards compatible way. */ - delta = le32_to_cpu(offset_to_image_data) - - (NTFSCLONE_IMG_HEADER_SIZE_OLD + - sizeof(image_hdr.offset_to_image_data)); + delta = offset_to_image_data - (NTFSCLONE_IMG_HEADER_SIZE_OLD + + sizeof(image_hdr.offset_to_image_data)); if (delta > 0) { char *dummy_buf; From 3b64a5a512014aa6db0b2f6be545009f5a44a8be Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 3 Sep 2007 19:39:24 +0300 Subject: [PATCH 207/289] trailing spaces --- libntfs/attrib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 60e61edb..2f088cb9 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1211,10 +1211,10 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) errno = EIO; goto rl_err_out; } - + to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); - + /* Instantiate the hole. */ cur_vcn = rl->vcn; from_vcn = rl->vcn + (ofs >> vol->cluster_size_bits); From 95b044cff32b6fda5c4a9d4e3c1b58e225d989fd Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 3 Sep 2007 19:51:01 +0300 Subject: [PATCH 208/289] Small enchantments and cleanups from ntfs-3g --- libntfs/attrib.c | 12 ++++++++++-- ntfsprogs/ntfsmount.c | 4 ++-- ntfsprogs/utils.c | 7 +++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 2f088cb9..2fc0f6d1 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1395,8 +1395,16 @@ done: if (ctx) ntfs_attr_put_search_ctx(ctx); /* Update mapping pairs if needed. */ - if (need_to.update_mapping_pairs) - ntfs_attr_update_mapping_pairs(na, update_from); + if (need_to.update_mapping_pairs) { + if (ntfs_attr_update_mapping_pairs(na, update_from)) { + /* FIXME: We want rollback here. */ + ntfs_log_perror("%s(): Failed to update mapping pairs. " + "Leaving inconsistent metadata. " + "Run chkdsk!", __FUNCTION__); + errno = EIO; + return -1; + } + } /* Finally, return the number of bytes written. */ return total; rl_err_out: diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 38931692..198c8aab 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -165,7 +165,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { static const char *EXEC_NAME = "ntfsmount"; static char ntfs_fuse_default_options[] = - "default_permissions,allow_other,use_ino,kernel_cache"; + "default_permissions,allow_other,use_ino,kernel_cache,nonempty"; static ntfs_fuse_context_t *ctx; /** @@ -711,7 +711,7 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, } while (size) { res = ntfs_attr_pwrite(na, offset, size, buf); - if (res < (s64)size) + if (res < (s64)size && errno != ENOSPC) ntfs_log_error("ntfs_attr_pwrite returned less bytes " "than requested.\n"); if (res <= 0) { diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 9d8beb9e..ddc79c5e 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -122,6 +122,11 @@ static const char *dirty_volume_msg = "(NOT to us!) that init scripts kill ntfsmount or mount.ntfs-fuse during\n" "shutdown instead of proper umount.\n"; +static const char *fakeraid_msg = +"You seem to have a SoftRAID/FakeRAID hardware and must use an activated,\n" +"different device under /dev/mapper, (e.g. /dev/mapper/nvidia_eahaabcc1)\n" +"to mount NTFS. Please see the 'dmraid' documentation for help.\n"; + /** * utils_set_locale */ @@ -227,6 +232,8 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, ntfs_log_error("%s", unclean_journal_msg); else if (errno == EBUSY) ntfs_log_error("%s", opened_volume_msg); + else if (errno == ENXIO) + ntfs_log_error("%s", fakeraid_msg); return NULL; } From 219d3532264ed70547b7447acdf5984c19b45c0b Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 4 Sep 2007 17:20:13 +0300 Subject: [PATCH 209/289] Fix corner case in hole instantiating in ntfs_attr_pwrite(). (Szaka) --- libntfs/attrib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 2fc0f6d1..acd897db 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1260,6 +1260,8 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) if (rlc->lcn >= 0) { lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn); + if (lcn_seek_from < -1) + lcn_seek_from = -1; break; } } From 4679daa0af1f98702fa80cbb1dad195a6b1c77bf Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 5 Sep 2007 16:33:59 +0300 Subject: [PATCH 210/289] Fix hole instantiating and new API ntfs_rl_fill_zero Thanks to Szaka for finding this bug and idea of factoring out zero filling code. --- include/ntfs/runlist.h | 3 ++ libntfs/attrib.c | 64 ++++++++---------------------------------- libntfs/runlist.c | 42 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/include/ntfs/runlist.h b/include/ntfs/runlist.h index 726a28dc..f3520297 100644 --- a/include/ntfs/runlist.h +++ b/include/ntfs/runlist.h @@ -56,6 +56,9 @@ extern s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl, extern s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl, const s64 pos, s64 count, void *b); +extern int ntfs_rl_fill_zero(const ntfs_volume *vol, const runlist *rl, + s64 pos, const s64 count); + extern runlist_element *ntfs_runlists_merge(runlist_element *drl, runlist_element *srl); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index acd897db..100678ad 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1119,32 +1119,11 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) 0, NULL, 0, ctx)) goto err_out; /* If write starts beyond initialized_size, zero the gap. */ - if (pos > na->initialized_size) { - char *buf; + if (pos > na->initialized_size && ntfs_rl_fill_zero(vol, + na->rl, na->initialized_size, + pos - na->initialized_size)) + goto err_out; - buf = ntfs_malloc(NTFS_BUF_SIZE); - if (!buf) - goto err_out; - - memset(buf, 0, NTFS_BUF_SIZE); - ofs = na->initialized_size; - while (ofs < pos) { - to_write = min(pos - ofs, NTFS_BUF_SIZE); - written = ntfs_rl_pwrite(vol, na->rl, ofs, - to_write, buf); - if (written <= 0) { - int err = errno; - ntfs_log_trace("Failed to zero space " - "between initialized " - "size and @pos.\n"); - free(buf); - errno = err; - goto err_out; - } - ofs += written; - } - free(buf); - } ctx->attr->initialized_size = cpu_to_sle64(pos + count); if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, ctx->mrec)) { @@ -1321,34 +1300,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) errno = EIO; goto err_out; } - if (ofs) { - /* - * Need to clear region between start of - * @cur_vcn cluster and @ofs. - */ - char *buf; - - buf = malloc(ofs); - if (!buf) { - ntfs_log_trace("Not enough memory to " - "allocate %lld " - "bytes.\n", ofs); - errno = ENOMEM; - goto err_out; - } - memset(buf, 0, ofs); - if (ntfs_rl_pwrite(vol, na->rl, cur_vcn << - vol->cluster_size_bits, - ofs, buf) < 0) { - eo = errno; - ntfs_log_trace("Failed to zero " - "area.\n"); - free(buf); - errno = eo; - goto err_out; - } - free(buf); - } if (rl->vcn < cur_vcn) { /* * Clusters that replaced hole are merged with @@ -1365,6 +1316,13 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) ofs -= (rl->vcn - cur_vcn) << vol->cluster_size_bits; } + /* + * Clear region between start of @rl->vcn cluster and + * @ofs if necessary. + */ + if (ofs && ntfs_rl_fill_zero(vol, na->rl, rl->vcn << + vol->cluster_size_bits, ofs)) + goto err_out; } /* It is a real lcn, write it to the volume. */ to_write = min(count, (rl->length << vol->cluster_size_bits) - diff --git a/libntfs/runlist.c b/libntfs/runlist.c index e0170b6b..2fca1918 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -1208,6 +1208,48 @@ rl_err_out: return -1; } +/** + * ntfs_rl_fill_zero - fill given region with zeroes + * @vol: ntfs volume to write to + * @rl: runlist specifying where to write zeroes to + * @pos: byte position within runlist @rl at which to begin the zeroing + * @count: number of bytes to fill with zeros + * + * Return 0 on success and -1 on error with errno set to the error code. + */ +int ntfs_rl_fill_zero(const ntfs_volume *vol, const runlist *rl, s64 pos, + const s64 count) +{ + char *buf; + s64 written, size, end = pos + count; + int ret = 0; + + ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, + (long long)count); + + if (!vol || !rl || pos < 0 || count < 0) { + errno = EINVAL; + return -1; + } + + buf = ntfs_calloc(NTFS_BUF_SIZE); + if (!buf) + return -1; + + while (pos < end) { + size = min(end - pos, NTFS_BUF_SIZE); + written = ntfs_rl_pwrite(vol, rl, pos, size, buf); + if (written <= 0) { + ntfs_log_perror("Failed to zero space"); + ret = -1; + break; + } + pos += written; + } + free(buf); + return ret; +} + /** * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number * @n: number for which to get the number of bytes for From aec646eebca45c5b387dc7d46a62382f096a61ff Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 5 Sep 2007 16:47:03 +0300 Subject: [PATCH 211/289] Do not force debug output to be always shown even if --enable-debug specifiend during configure. Let user choose in runtime. --- libntfs/logging.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libntfs/logging.c b/libntfs/logging.c index c3e8bc95..ca6a9b5e 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -76,16 +76,9 @@ static struct ntfs_logging ntfs_log = (struct ntfs_logging) { NTFS_LOG_LEVEL_WARNING | NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL | NTFS_LOG_LEVEL_PROGRESS | -#ifdef DEBUG - NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | -#endif 0, .flags = NTFS_LOG_FLAG_ONLYNAME, -#ifdef DEBUG - .handler = ntfs_log_handler_outerr, -#else .handler = ntfs_log_handler_null, -#endif }; From 7d6a8f2767e715b6a11074669c157f29f9b3254d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 5 Sep 2007 21:00:16 +0300 Subject: [PATCH 212/289] ntfs_ie_add(): cleanup (Szaka) --- libntfs/index.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index 4d1300c4..2a5e6bd0 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -1406,13 +1406,16 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) { - char *fn; INDEX_HEADER *ih; int allocated_size, new_size; int ret = STATUS_ERROR; +#ifdef DEBUG + char *fn; fn = ntfs_ie_filename_get(ie); ntfs_log_trace("file: '%s'\n", fn); + free(fn); +#endif while (1) { if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), @@ -1457,7 +1460,6 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) ret = STATUS_OK; err_out: - free(fn); ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); return ret; } From 9f51bdfd052f0f7c8896f224fe6f715b0972fa30 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 5 Sep 2007 21:19:53 +0300 Subject: [PATCH 213/289] Catch and deny all junction/reparse point write operations. (Szaka) --- libntfs/dir.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 33684181..d9bb15b8 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1112,6 +1112,11 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, errno = EINVAL; return NULL; } + /* FIXME: Reparse points requires special handling. */ + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { + err = EOPNOTSUPP; + goto err_out; + } /* Allocate MFT record for new file. */ ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); if (!ni) { @@ -1222,7 +1227,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, ni->vol->indx_record_size >> ni->vol->cluster_size_bits; else - ir->clusters_per_index_block = + ir->clusters_per_index_block = ni->vol->indx_record_size >> ni->vol->sector_size_bits; ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER)); @@ -1685,6 +1690,11 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) ntfs_log_error("Invalid arguments."); goto err_out; } + /* FIXME: Reparse points requires special handling. */ + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + err = EOPNOTSUPP; + goto err_out; + } /* Create FILE_NAME attribute. */ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); fn = ntfs_calloc(fn_len); From 58ab68b0246aa37c27ca19b3982581dd42e2e567 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 6 Sep 2007 13:51:48 +0300 Subject: [PATCH 214/289] ntfsmount: remove some traces of legacy code --- ntfsprogs/ntfsmount.c | 70 +++++++++++-------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 198c8aab..39a84bbc 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -278,31 +278,27 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), struct statvfs *sfs) { long size; - ntfs_volume *vol; - vol = ctx->vol; - if (!vol) - return -ENODEV; /* Optimal transfer block size. */ - sfs->f_bsize = vol->cluster_size; - sfs->f_frsize = vol->cluster_size; + sfs->f_bsize = ctx->vol->cluster_size; + sfs->f_frsize = ctx->vol->cluster_size; /* * Total data blocks in file system in units of f_bsize and since * inodes are also stored in data blocs ($MFT is a file) this is just * the total clusters. */ - sfs->f_blocks = vol->nr_clusters; + sfs->f_blocks = ctx->vol->nr_clusters; /* Free data blocks in file system in units of f_bsize. */ - size = ntfs_fuse_get_nr_free_clusters(vol); + size = ntfs_fuse_get_nr_free_clusters(ctx->vol); if (size < 0) size = 0; /* Free blocks avail to non-superuser, same as above on NTFS. */ sfs->f_bavail = sfs->f_bfree = size; /* Number of inodes in file system (at this point in time). */ - size = vol->mft_na->data_size >> vol->mft_record_size_bits; + size = ctx->vol->mft_na->data_size >> ctx->vol->mft_record_size_bits; sfs->f_files = size; /* Free inodes in fs (based on current total count). */ - size = ntfs_fuse_get_nr_free_mft_records(vol, size); + size = ntfs_fuse_get_nr_free_mft_records(ctx->vol, size); if (size < 0) size = 0; sfs->f_ffree = size; @@ -354,17 +350,15 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) int res = 0; ntfs_inode *ni; ntfs_attr *na; - ntfs_volume *vol; char *path = NULL; ntfschar *stream_name; int stream_name_len; - vol = ctx->vol; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; memset(stbuf, 0, sizeof(struct stat)); - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -ENOENT; goto exit; @@ -583,15 +577,13 @@ static int ntfs_fuse_readdir(const char *path, void *buf, struct fuse_file_info *fi __attribute__((unused))) { ntfs_fuse_fill_context_t fill_ctx; - ntfs_volume *vol; ntfs_inode *ni; s64 pos = 0; int err = 0; - vol = ctx->vol; fill_ctx.filler = filler; fill_ctx.buf = buf; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; if (ntfs_readdir(ni, &pos, &fill_ctx, @@ -604,7 +596,6 @@ static int ntfs_fuse_readdir(const char *path, void *buf, static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi __attribute__((unused))) { - ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na; int res = 0; @@ -615,8 +606,7 @@ static int ntfs_fuse_open(const char *org_path, stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - vol = ctx->vol; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (ni) { na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (na) { @@ -637,7 +627,6 @@ static int ntfs_fuse_open(const char *org_path, static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi __attribute__((unused))) { - ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na = NULL; char *path = NULL; @@ -647,8 +636,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - vol = ctx->vol; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; goto exit; @@ -688,7 +676,6 @@ exit: static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi __attribute__((unused))) { - ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na = NULL; char *path = NULL; @@ -698,8 +685,7 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - vol = ctx->vol; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; goto exit; @@ -737,7 +723,6 @@ exit: static int ntfs_fuse_truncate(const char *org_path, off_t size) { - ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_attr *na; int res; @@ -748,8 +733,7 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - vol = ctx->vol; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; goto exit; @@ -1159,17 +1143,13 @@ static const int nf_ns_xattr_preffix_len = 5; static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) { ntfs_attr_search_ctx *actx = NULL; - ntfs_volume *vol; ntfs_inode *ni; char *to = list; int ret = 0; if (ctx->streams != NF_STREAMS_INTERFACE_XATTR) return -EOPNOTSUPP; - vol = ctx->vol; - if (!vol) - return -ENODEV; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; actx = ntfs_attr_get_search_ctx(ni, NULL); @@ -1223,17 +1203,13 @@ static int ntfs_fuse_getxattr_windows(const char *path, const char *name, char *value, size_t size) { ntfs_attr_search_ctx *actx = NULL; - ntfs_volume *vol; ntfs_inode *ni; char *to = value; int ret = 0; if (strcmp(name, "ntfs.streams.list")) return -EOPNOTSUPP; - vol = ctx->vol; - if (!vol) - return -ENODEV; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; actx = ntfs_attr_get_search_ctx(ni, NULL); @@ -1288,7 +1264,6 @@ exit: static int ntfs_fuse_getxattr(const char *path, const char *name, char *value, size_t size) { - ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; @@ -1301,10 +1276,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -ENODATA; - vol = ctx->vol; - if (!vol) - return -ENODEV; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename, 0); @@ -1338,7 +1310,6 @@ exit: static int ntfs_fuse_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { - ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; @@ -1349,10 +1320,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -EACCES; - vol = ctx->vol; - if (!vol) - return -ENODEV; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename, 0); @@ -1397,7 +1365,6 @@ exit: static int ntfs_fuse_removexattr(const char *path, const char *name) { - ntfs_volume *vol; ntfs_inode *ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; @@ -1408,10 +1375,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) || strlen(name) == (size_t)nf_ns_xattr_preffix_len) return -ENODATA; - vol = ctx->vol; - if (!vol) - return -ENODEV; - ni = ntfs_pathname_to_inode(vol, NULL, path); + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; lename_len = ntfs_mbstoucs(name + nf_ns_xattr_preffix_len, &lename, 0); From a1124ce7f42ab88572e7c668871d90fc26ea02aa Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 6 Sep 2007 18:11:53 +0300 Subject: [PATCH 215/289] Fix recent denial of __ntfs_create in reparse point --- libntfs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index d9bb15b8..85c768d9 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1114,8 +1114,8 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, } /* FIXME: Reparse points requires special handling. */ if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { - err = EOPNOTSUPP; - goto err_out; + errno = EOPNOTSUPP; + return NULL; } /* Allocate MFT record for new file. */ ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); From 82df6c1fead78a8b640bae6461eac31ad5991caa Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 6 Sep 2007 18:34:38 +0300 Subject: [PATCH 216/289] Rework time updates - Library no longer perform time updates, only provide API for this - Remove ntfs_inode_update_{a,}time() and introduce ntfs_inode_update_times() - Make ntfsmount properly update times - ntfs_delete() now takes pointer to pointer to ntfs_inode for while to delete and closes inode only in cases no more hard links left to file --- include/ntfs/dir.h | 2 +- include/ntfs/inode.h | 12 ++++++--- include/ntfs/volume.h | 7 +----- libntfs/attrib.c | 12 --------- libntfs/dir.c | 25 +++++++++--------- libntfs/inode.c | 49 +++++++++++++++--------------------- libntfs/volume.c | 3 --- ntfsprogs/ntfsck.c | 2 +- ntfsprogs/ntfsclone.c | 2 +- ntfsprogs/ntfsmount.c | 57 ++++++++++++++++++++++++++++++++++-------- ntfsprogs/ntfsresize.c | 3 +-- 11 files changed, 92 insertions(+), 82 deletions(-) diff --git a/include/ntfs/dir.h b/include/ntfs/dir.h index 600bb3a3..5299861b 100644 --- a/include/ntfs/dir.h +++ b/include/ntfs/dir.h @@ -77,7 +77,7 @@ extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, ntfschar *target, u8 target_len); -extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, +extern int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len); extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index b6a7d0c4..5ad9bc47 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -130,7 +130,7 @@ struct _ntfs_inode { }; /* Below fields are valid only for base inode. */ - s64 data_size; /* Data size stored in the filename index. */ + s64 data_size; /* Data size of unnamed DATA attribute. */ s64 allocated_size; /* Allocated size stored in the filename index. (NOTE: Equal to allocated size of the unnamed data attribute for normal or @@ -172,8 +172,14 @@ static __inline__ void ntfs_inode_mark_dirty(ntfs_inode *ni) NInoSetDirty(ni->base_ni); } -extern void ntfs_inode_update_atime(ntfs_inode *ni); -extern void ntfs_inode_update_time(ntfs_inode *ni); +typedef enum { + NTFS_UPDATE_ATIME = 1 << 0, + NTFS_UPDATE_MTIME = 1 << 1, + NTFS_UPDATE_CTIME = 1 << 2, +} ntfs_time_update_flags; + +extern void ntfs_inode_update_times(ntfs_inode *ni, + ntfs_time_update_flags mask); extern int ntfs_inode_sync(ntfs_inode *ni); diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index e5f97c93..c7f3e893 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -57,10 +57,9 @@ typedef struct _ntfs_volume ntfs_volume; */ typedef enum { NTFS_MNT_RDONLY = 1, - NTFS_MNT_NOATIME = 2, + NTFS_MNT_FORENSIC = 2, NTFS_MNT_CASE_SENSITIVE = 4, NTFS_MNT_NOT_EXCLUSIVE = 8, - NTFS_MNT_FORENSIC = 16, } ntfs_mount_flags; /** @@ -108,10 +107,6 @@ typedef enum { #define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty) #define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty) -#define NVolNoATime(nv) test_nvol_flag(nv, NoATime) -#define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime) -#define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime) - #define NVolWasDirty(nv) test_nvol_flag(nv, WasDirty) #define NVolSetWasDirty(nv) set_nvol_flag(nv, WasDirty) #define NVolClearWasDirty(nv) clear_nvol_flag(nv, WasDirty) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 100678ad..cccc86b9 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -864,10 +864,6 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) return ntfs_crypto_attr_pread(na, pos, count, b); vol = na->ni->vol; - /* Update access time if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_atime(na->ni); if (!count) return 0; /* Truncate reads beyond end of attribute. */ @@ -1050,10 +1046,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) errno = EOPNOTSUPP; return -1; } - /* Update access and change times if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_time(na->ni); if (!count) return 0; /* If the write reaches beyond the end, extend the attribute. */ @@ -5092,10 +5084,6 @@ int __ntfs_attr_truncate(ntfs_attr *na, const s64 newsize, BOOL sparse) ret = ntfs_non_resident_attr_shrink(na, newsize); } else ret = ntfs_resident_attr_resize(na, newsize); - /* Update access and change times if needed. */ - if (na->type == AT_DATA || na->type == AT_INDEX_ROOT || - na->type == AT_INDEX_ALLOCATION) - ntfs_inode_update_time(na->ni); if (!ret) ntfs_log_trace("Done!\n"); else diff --git a/libntfs/dir.c b/libntfs/dir.c index 85c768d9..b04089de 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -487,7 +487,7 @@ close_err_out: u64 ntfs_pathname_to_inode_num(ntfs_volume *vol, ntfs_inode *parent, const char *pathname) { - u64 inum, result; + u64 inum, result; int len, err = 0; char *p, *q; ntfs_inode *ni = NULL; @@ -1430,20 +1430,24 @@ ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, /** * ntfs_delete - delete file or directory from ntfs volume - * @ni: ntfs inode for object to delete + * @pni: ntfs inode for object to delete * @dir_ni: ntfs inode for directory in which delete object * @name: unicode name of the object to delete * @name_len: length of the name in unicode characters * - * @ni is always closed after the call to this function (even if it failed), - * user does not need to call ntfs_inode_close himself. + * @pni is pointer to pointer to ntfs_inode structure. Upon successful + * completion and if inode is really deleted (there are no more links left to + * it) this function will close @*pni and set it to NULL, in the other cases + * @*pni will stay opened. * * Return 0 on success or -1 on error with errno set to the error code. */ -int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) +int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name, + u8 name_len) { ntfs_attr_search_ctx *actx = NULL; ntfs_index_context *ictx = NULL; + ntfs_inode *ni; FILE_NAME_ATTR *fn = NULL; BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE; BOOL case_sensitive_match = TRUE; @@ -1451,15 +1455,12 @@ int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) ntfs_log_trace("Entering.\n"); - if (!ni || !dir_ni || !name || !name_len) { + if (!pni || !(ni = *pni) || !dir_ni || !name || !name_len || + ni->nr_extents == -1 || dir_ni->nr_extents == -1) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; goto err_out; } - if (ni->nr_extents == -1) - ni = ni->base_ni; - if (dir_ni->nr_extents == -1) - dir_ni = dir_ni->base_ni; /* * Search for FILE_NAME attribute with such name. If it's in POSIX or * WIN32_AND_DOS namespace, then simply remove it from index and inode. @@ -1642,14 +1643,12 @@ search: ntfs_log_error("Failed to free base MFT record. " "Leaving inconsistent metadata.\n"); } - ni = NULL; + *pni = NULL; out: if (actx) ntfs_attr_put_search_ctx(actx); if (ictx) ntfs_index_ctx_put(ictx); - if (ni) - ntfs_inode_close(ni); if (err) { ntfs_log_error("%s(): Failed.\n", __FUNCTION__); errno = err; diff --git a/libntfs/inode.c b/libntfs/inode.c index dcbe7045..d076a5b3 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -1069,43 +1069,34 @@ put_err_out: } /** - * ntfs_inode_update_atime - update access time for ntfs inode - * @ni: ntfs inode for which update access time + * ntfs_inode_update_times - update selected time fields for ntfs inode + * @ni: ntfs inode for which update time fields + * @mask: select which time fields should be updated * - * This function usually get called when user read not metadata from inode. - * Do not update time for system files. + * This function updates time fields to current time. Fields to update are + * selected using @mask (see enum @ntfs_time_update_flags for posssible values). */ -void ntfs_inode_update_atime(ntfs_inode *ni) +void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) { - if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >= - FILE_first_user || ni->mft_no == FILE_root)) { - ni->last_access_time = time(NULL); - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); + time_t now; + + if (!ni) { + ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); + return; } -} + if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || + NVolReadOnly(ni->vol) || !mask) + return; -/** - * ntfs_inode_update_time - update all times for ntfs inode - * @ni: ntfs inode for which update times - * - * This function updates last access, mft and data change times. Usually - * get called when user write not metadata to inode. Do not update time for - * system files. - */ -void ntfs_inode_update_time(ntfs_inode *ni) -{ - if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >= - FILE_first_user || ni->mft_no == FILE_root)) { - time_t now; - - now = time(NULL); + now = time(NULL); + if (mask & NTFS_UPDATE_ATIME) ni->last_access_time = now; + if (mask & NTFS_UPDATE_MTIME) ni->last_data_change_time = now; + if (mask & NTFS_UPDATE_CTIME) ni->last_mft_change_time = now; - NInoFileNameSetDirty(ni); - NInoSetDirty(ni); - } + NInoFileNameSetDirty(ni); + NInoSetDirty(ni); } /** diff --git a/libntfs/volume.c b/libntfs/volume.c index 2ecb6881..0f7dd140 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -440,8 +440,6 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, vol->upcase_len * sizeof(ntfschar)); if (flags & NTFS_MNT_RDONLY) NVolSetReadOnly(vol); - if (flags & NTFS_MNT_NOATIME) - NVolSetNoATime(vol); if (flags & NTFS_MNT_CASE_SENSITIVE) NVolSetCaseSensitive(vol); ntfs_log_debug("Reading bootsector... "); @@ -758,7 +756,6 @@ out: * as for the mount system call (man 2 mount). Currently the following flags * are implemented: * NTFS_MNT_RDONLY - mount volume read-only - * NTFS_MNT_NOATIME - do not update access time * NTFS_MNT_CASE_SENSITIVE - treat filenames as case sensitive even if * they are not in POSIX namespace * NTFS_MNT_NOT_EXCLUSIVE - (unix only) do not open volume exclusively diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c index 704ccd75..2171a620 100644 --- a/ntfsprogs/ntfsck.c +++ b/ntfsprogs/ntfsck.c @@ -833,7 +833,7 @@ int main(int argc, char **argv) // at this point we know that the volume is valid enough for mounting. /* Call ntfs_device_mount() to do the actual mount. */ - vol = ntfs_device_mount(dev, NTFS_MNT_NOATIME | NTFS_MNT_RDONLY); + vol = ntfs_device_mount(dev, NTFS_MNT_RDONLY); if (!vol) { ntfs_device_free(dev); return 2; diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 9f78f900..dfcb58d9 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1841,7 +1841,7 @@ int main(int argc, char **argv) /* 'force' again mount for dirty volumes (e.g. after resize). FIXME: use mount flags to avoid potential side-effects in future */ opt.force++; - mount_volume(NTFS_MNT_NOATIME); + mount_volume(0); free(lcn_bitmap.bm); setup_lcn_bitmap(); diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 39a84bbc..0ac8e278 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -107,6 +107,7 @@ typedef struct { BOOL verbose; BOOL no_def_opts; BOOL case_insensitive; + BOOL noatime; } ntfs_fuse_context_t; typedef enum { @@ -138,6 +139,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { NTFS_FUSE_OPT("no_detach", no_detach), NTFS_FUSE_OPT("no_def_opts", no_def_opts), NTFS_FUSE_OPT("case_insensitive", case_insensitive), + NTFS_FUSE_OPT("noatime", noatime), NTFS_FUSE_OPT("fmask=%o", fmask), NTFS_FUSE_OPT("dmask=%o", dmask), NTFS_FUSE_OPT("umask=%o", fmask), @@ -160,6 +162,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("noatime", FUSE_OPT_KEY_KEEP), FUSE_OPT_END }; @@ -190,6 +193,14 @@ static __inline__ int ntfs_fuse_is_named_data_stream(const char *path) return 0; } +static __inline__ void ntfs_fuse_update_times(ntfs_inode *ni, + ntfs_time_update_flags mask) +{ + if (ctx->noatime) + mask &= ~NTFS_UPDATE_ATIME; + ntfs_inode_update_times(ni, mask); +} + static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free) { u8 *buf; @@ -589,6 +600,7 @@ static int ntfs_fuse_readdir(const char *path, void *buf, if (ntfs_readdir(ni, &pos, &fill_ctx, (ntfs_filldir_t)ntfs_fuse_filler)) err = -errno; + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); ntfs_inode_close(ni); return err; } @@ -633,6 +645,8 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, ntfschar *stream_name; int stream_name_len, res, total = 0; + if (!size) + return 0; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; @@ -662,6 +676,7 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, total += res; } res = total; + ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); exit: if (na) ntfs_attr_close(na); @@ -711,6 +726,9 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, res = total; exit: ntfs_fuse_mark_free_space_outdated(); + if (res > 0) + ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME | + NTFS_UPDATE_CTIME); if (na) ntfs_attr_close(na); if (ni && ntfs_inode_close(ni)) @@ -738,6 +756,10 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) res = -errno; goto exit; } + if (ni->data_size == size) { + res = 0; + goto exit; + } na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { res = -errno; @@ -745,8 +767,11 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) } if (ntfs_attr_truncate(na, size)) res = -errno; - else + else { + ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME | + NTFS_UPDATE_CTIME); res = 0; + } ntfs_fuse_mark_free_space_outdated(); ntfs_attr_close(na); exit: @@ -827,9 +852,11 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, ni = ntfs_create(dir_ni, uname, uname_len, type); break; } - if (ni) + if (ni) { ntfs_inode_close(ni); - else + ntfs_fuse_update_times(dir_ni, + NTFS_UPDATE_CTIME | NTFS_UPDATE_MTIME); + } else res = -errno; exit: free(uname); @@ -948,6 +975,11 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path) /* Create hard link. */ if (ntfs_link(ni, dir_ni, uname, uname_len)) res = -errno; + else { + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_CTIME | + NTFS_UPDATE_MTIME); + } exit: if (ni) ntfs_inode_close(ni); @@ -993,9 +1025,14 @@ static int ntfs_fuse_rm(const char *org_path) goto exit; } /* Delete object. */ - if (ntfs_delete(ni, dir_ni, uname, uname_len)) + if (ntfs_delete(&ni, dir_ni, uname, uname_len)) res = -errno; - ni = NULL; + else { + if (ni) + ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_CTIME | + NTFS_UPDATE_MTIME); + } exit: if (ni) ntfs_inode_close(ni); @@ -1110,23 +1147,21 @@ static int ntfs_fuse_rmdir(const char *path) static int ntfs_fuse_utimens(const char *path, const struct timespec ts[2]) { ntfs_inode *ni; + time_t now; if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; + now = time(NULL); + ni->last_mft_change_time = now; if (ts) { ni->last_access_time = ts[0].tv_sec; ni->last_data_change_time = ts[1].tv_sec; - ni->last_mft_change_time = ts[1].tv_sec; } else { - time_t now; - - now = time(NULL); ni->last_access_time = now; ni->last_data_change_time = now; - ni->last_mft_change_time = now; } NInoFileNameSetDirty(ni); NInoSetDirty(ni); @@ -1599,7 +1634,7 @@ static int ntfs_fuse_mount(void) { ntfs_volume *vol; - vol = utils_mount_volume(ctx->device, NTFS_MNT_NOATIME | + vol = utils_mount_volume(ctx->device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | ((ctx->case_insensitive) ? 0 : NTFS_MNT_CASE_SENSITIVE) | diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 6d215d8a..627647a9 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2243,8 +2243,7 @@ static ntfs_volume *mount_volume(void) * volume at all. We will do the logfile emptying and dirty setting * later if needed. */ - if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_NOATIME | - NTFS_MNT_FORENSIC))) { + if (!(vol = ntfs_mount(opt.volume, opt.ro_flag | NTFS_MNT_FORENSIC))) { int err = errno; perr_printf("Opening '%s' as NTFS failed", opt.volume); From ec2afb736cd0e0b9bef31c4719a7b235844fbf64 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 7 Sep 2007 15:31:33 +0300 Subject: [PATCH 217/289] Fix cache handling in utils_attr_get_name. (Thanks to Bogdan for finding this bug) --- ntfsprogs/utils.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index ddc79c5e..2af7361d 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -642,7 +642,10 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b * * This function has a static buffer in which it caches a section of $Bitmap. * If the lcn, being tested, lies outside the range, the buffer will be - * refreshed. + * refreshed. @bmplcn stores offset to the first bit (in bits) stored in the + * buffer. + * + * NOTE: Be very carefull with shifts by 3 everywhere in this function. * * Return: 1 Cluster is in use * 0 Cluster is free space @@ -651,8 +654,7 @@ int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int b int utils_cluster_in_use(ntfs_volume *vol, long long lcn) { static unsigned char buffer[512]; - static long long bmplcn = -sizeof(buffer) - 1; /* Which bit of $Bitmap is in the buffer */ - + static long long bmplcn = -(sizeof(buffer) << 3); int byte, bit; ntfs_attr *attr; @@ -674,7 +676,8 @@ int utils_cluster_in_use(ntfs_volume *vol, long long lcn) memset(buffer, 0xFF, sizeof(buffer)); bmplcn = lcn & (~((sizeof(buffer) << 3) - 1)); - if (ntfs_attr_pread(attr, (bmplcn>>3), sizeof(buffer), buffer) < 0) { + if (ntfs_attr_pread(attr, (bmplcn >> 3), sizeof(buffer), + buffer) < 0) { ntfs_log_perror("Couldn't read $Bitmap"); ntfs_attr_close(attr); return -1; @@ -686,7 +689,9 @@ int utils_cluster_in_use(ntfs_volume *vol, long long lcn) bit = 1 << (lcn & 7); byte = (lcn >> 3) & (sizeof(buffer) - 1); - ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & bit); + ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, " + "in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & + bit); return (buffer[byte] & bit); } From b392bd17c8b094d1f6019bc127560b3f90a28855 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 7 Sep 2007 15:39:30 +0300 Subject: [PATCH 218/289] ntfsmount: Submit inode number during readdir Some broken programs rely on that filesystem will submit inode number during readdir() (what is optional). Make them happy since it is really not a problem. (Ted Anderson, Szaka) --- ntfsprogs/ntfsmount.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 0ac8e278..9848b59a 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -577,8 +577,11 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, free(filename); return 0; } - if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user) - fill_ctx->filler(fill_ctx->buf, filename, NULL, 0); + if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user) { + struct stat st = { .st_ino = MREF(mref) }; + + fill_ctx->filler(fill_ctx->buf, filename, &st, 0); + } free(filename); return 0; } From 54d78993688cef803a1a1fa31cee49eb98683b56 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 7 Sep 2007 15:50:29 +0300 Subject: [PATCH 219/289] Workaround windows defragmentation tool bug. Windows defragmentation tool do not update name offset correctly for unnamed attributes, but chkdsk do not like when it negative, so do not change it at all if it would become negative. (Szaka) --- libntfs/attrib.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index cccc86b9..21d5a513 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -4386,7 +4386,16 @@ retry: memmove((u8*)a + le16_to_cpu(a->name_offset) - 8, (u8*)a + le16_to_cpu(a->name_offset), a->name_length * sizeof(ntfschar)); - a->name_offset = cpu_to_le16(le16_to_cpu( + /* + * Windows defragmentation tool do not update + * name offset correctly for unnamed + * attributes, but chkdsk do not like when it + * negative, so do not change it at all if it + * would become negative. + */ + if (le16_to_cpu(a->name_offset) >= 8) + a->name_offset = cpu_to_le16( + le16_to_cpu( a->name_offset) - 8); a->mapping_pairs_offset = cpu_to_le16(le16_to_cpu( From a1103ccd612e4a31490c5e0484701abab58e7f9c Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 10 Sep 2007 18:38:06 +0300 Subject: [PATCH 220/289] Fix syslog logging handler to take in respect all logging flags. This makes ntfs_log_perror, ntfs_log_trace, etc., behave correctly when beeing used with it. --- libntfs/dir.c | 3 +-- libntfs/logging.c | 64 +++++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index b04089de..41245495 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1328,8 +1328,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)))) { err = errno; - ntfs_log_error("Failed to add entry to the index: %s.\n", - strerror(err)); + ntfs_log_perror("Failed to add entry to the index"); goto err_out; } /* Set hard links count and directory flag. */ diff --git a/libntfs/logging.c b/libntfs/logging.c index ca6a9b5e..1c767196 100644 --- a/libntfs/logging.c +++ b/libntfs/logging.c @@ -319,6 +319,7 @@ int ntfs_log_redirect(const char *function, const char *file, } +#ifdef HAVE_SYSLOG_H /** * ntfs_log_handler_syslog - syslog logging handler * @function: Function in which the log line occurred @@ -329,47 +330,56 @@ int ntfs_log_redirect(const char *function, const char *file, * @format: printf-style formatting string * @args: Arguments to be formatted * - * A simple syslog logging handler. Ignores colors. + * A syslog logging handler. Ignores colors and truncates output after 512 + * bytes. * * Returns: -1 Error occurred * 0 Message wasn't logged * num Number of output characters */ - -#ifdef HAVE_SYSLOG_H -int ntfs_log_handler_syslog(const char *function __attribute__((unused)), - const char *file, int line __attribute__((unused)), - u32 level __attribute__((unused)), - void *data __attribute__((unused)), const char *format, - va_list args) +int ntfs_log_handler_syslog(const char *function, const char *file, int line, + u32 level, void *data __attribute__((unused)), + const char *format, va_list args) { - int ret = 0; - int olderr = errno; + char buffer[512]; + int ret = 0, olderr = errno; if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) && (strchr(file, PATH_SEP))) /* Abbreviate the filename */ file = strrchr(file, PATH_SEP) + 1; -#if 0 /* FIXME: Implement this all. */ - if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */ - ret += fprintf(stream, "%s", ntfs_log_get_prefix(level)); - if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */ - ret += fprintf(stream, "%s ", file); + /* Prefix the output */ + if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) + ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s", + ntfs_log_get_prefix(level)); - if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */ - ret += fprintf(stream, "(%d) ", line); + /* Source filename */ + if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) + ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s ", + file); - if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */ - (level & NTFS_LOG_LEVEL_TRACE)) - ret += fprintf(stream, "%s(): ", function); + /* Source line number */ + if (ret < sizeof(buffer) && ntfs_log.flags & NTFS_LOG_FLAG_LINE) + ret += snprintf(buffer + ret, sizeof(buffer) - ret, "(%d) ", + line); - ret += vfprintf(stream, format, args); + /* Source function */ + if (ret < sizeof(buffer) && ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) + || (level & NTFS_LOG_LEVEL_TRACE))) + ret += snprintf(buffer + ret, sizeof(buffer) - ret, "%s(): ", + function); - if (level & NTFS_LOG_LEVEL_PERROR) - ret += fprintf(stream, ": %s\n", strerror(olderr)); -#endif - vsyslog(LOG_NOTICE, format, args); - ret = 1; /* FIXME: caclulate how many bytes had been written. */ + /* Message itself */ + if (ret < sizeof(buffer)) + ret += vsnprintf(buffer + ret, sizeof(buffer) - ret, format, + args); + + /* Append errno */ + if (ret < sizeof(buffer) && level & NTFS_LOG_LEVEL_PERROR) + ret += snprintf(buffer + ret, sizeof(buffer) - ret, ": %s.\n", + strerror(olderr)); + + syslog(LOG_NOTICE, "%s", buffer); errno = olderr; return ret; @@ -460,7 +470,7 @@ int ntfs_log_handler_fprintf(const char *function, const char *file, ret += vfprintf(stream, format, args); if (level & NTFS_LOG_LEVEL_PERROR) - ret += fprintf(stream, ": %s\n", strerror(olderr)); + ret += fprintf(stream, ": %s.\n", strerror(olderr)); if (col_suffix) ret += fprintf(stream, col_suffix); From 030ea75bef66cb0afc225bd7e78ed559ea5d535d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 10 Sep 2007 19:26:38 +0300 Subject: [PATCH 221/289] Rename rpm ntfsprogs-fuse to ntfsmount --- ntfsprogs.spec.in | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ntfsprogs.spec.in b/ntfsprogs.spec.in index a4cf18a6..f7faa898 100644 --- a/ntfsprogs.spec.in +++ b/ntfsprogs.spec.in @@ -37,16 +37,15 @@ This package contains the NTFS GNOME virtual filesystem (VFS) module which allows GNOME VFS clients to seamlessly utilize the NTFS library (libntfs). -%package fuse +%package -n ntfsmount Summary : NTFS FUSE module (ntfsmount) Group : System Environment/Base Requires : ntfsprogs = %{ver}-%{rel} Requires : fuse >= 2.6.1 -%description fuse -This package contains the ntfsmount utility which is an NTFS filesystem in -userspace (FUSE) module allowing users to mount an ntfs filesystem from -userspace and accessing it using the functionality provided by the NTFS -library (libntfs). +%description -n ntfsmount +This package contains the ntfsmount utility which is an userspace read/write +NTFS driver allowing users to mount an ntfs filesystem using FUSE and accessing +it using the functionality provided by the NTFS library (libntfs). %package devel @@ -101,7 +100,7 @@ rm -rf "$RPM_BUILD_ROOT" %{_libdir}/gnome-vfs-2.0/modules/libntfs-gnomevfs.*so* %config %{_sysconfdir}/gnome-vfs-2.0/modules/libntfs.conf -%files fuse +%files -n ntfsmount %defattr(-,root,root) %{bindir}/ntfsmount* /sbin/mount.ntfs-fuse @@ -115,6 +114,9 @@ rm -rf "$RPM_BUILD_ROOT" %{_libdir}/gnome-vfs-2.0/modules/libntfs-gnomevfs.*a* %changelog +* Mon Sep 10 2007 Yura Pakhuchiy +- Rename rpm ntfsprogs-fuse to ntfsmount. + * Fri Oct 7 2005 Anton Altaparmakov - Fix the file distribution after new binaries have been added as they were ending up in the wrong rpms. From cc166f9f42e97571bea0c7cdec0e978cb9374edf Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 10 Sep 2007 21:21:39 +0300 Subject: [PATCH 222/289] ntfs_readdir, ntfs_fuse_filler: return with error if FUSE filler failed. (Szaka) --- libntfs/dir.c | 27 ++++++++++----------------- ntfsprogs/ntfsmount.c | 5 +++-- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/libntfs/dir.c b/libntfs/dir.c index 41245495..124bb860 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -766,7 +766,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, le16_to_cpu(dir_ni->mrec->sequence_number)), NTFS_DT_DIR); if (rc) - goto done; + goto err_out; ++*pos; } if (*pos == 1) { @@ -781,7 +781,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, rc = filldir(dirent, dotdot, 2, FILE_NAME_POSIX, *pos, parent_mref, NTFS_DT_DIR); if (rc) - goto done; + goto err_out; ++*pos; } @@ -858,11 +858,8 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * invoke the filldir() callback as appropriate. */ rc = ntfs_filldir(pos, ie, dirent, filldir); - if (rc) { - ntfs_attr_put_search_ctx(ctx); - ctx = NULL; - goto done; - } + if (rc) + goto err_out; } ntfs_attr_put_search_ctx(ctx); ctx = NULL; @@ -1020,7 +1017,7 @@ find_next_index_buffer: */ rc = ntfs_filldir(pos, ie, dirent, filldir); if (rc) - goto done; + goto err_out; } goto find_next_index_buffer; EOD: @@ -1033,20 +1030,16 @@ done: ntfs_attr_close(bmp_na); if (ia_na) ntfs_attr_close(ia_na); -#ifdef DEBUG - if (!rc) - ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", - (long long)*pos); - else - ntfs_log_debug("filldir returned %i, *pos 0x%llx, " - "returning 0.\n", rc, (long long)*pos); -#endif + ntfs_log_debug("EOD, *pos 0x%llx, returning 0.\n", (long long)*pos); return 0; dir_err_out: errno = EIO; err_out: eo = errno; - ntfs_log_trace("failed.\n"); + if (rc) + ntfs_log_trace("filldir returned %i, *pos 0x%llx.", rc, + (long long)*pos); + ntfs_log_trace("Failed.\n"); if (ctx) ntfs_attr_put_search_ctx(ctx); free(ia); diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 9848b59a..34658c54 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -562,6 +562,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, const unsigned dt_type __attribute__((unused))) { char *filename = NULL; + int ret; if (name_type == FILE_NAME_DOS) return 0; @@ -580,10 +581,10 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user) { struct stat st = { .st_ino = MREF(mref) }; - fill_ctx->filler(fill_ctx->buf, filename, &st, 0); + ret = fill_ctx->filler(fill_ctx->buf, filename, &st, 0); } free(filename); - return 0; + return ret; } static int ntfs_fuse_readdir(const char *path, void *buf, From a9a1f28cf5995c23892bd59bbf42ebac2e7c6b26 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 11 Sep 2007 16:46:29 +0300 Subject: [PATCH 223/289] Fix previous fix to filler :) --- ntfsprogs/ntfsmount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 34658c54..88cee13f 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -562,7 +562,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, const unsigned dt_type __attribute__((unused))) { char *filename = NULL; - int ret; + int ret = 0; if (name_type == FILE_NAME_DOS) return 0; From 3b99cee600fd5ace20bac0b2c4c350887f2753ef Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 11 Sep 2007 16:58:01 +0300 Subject: [PATCH 224/289] Fix directory corruption in index code. (Szaka) TODO/FIXME: This hardly readable code definitely needs rewrite. Take index.c from 1.13.1 and implement all properly. --- libntfs/index.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index 2a5e6bd0..5e5760b3 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -1108,6 +1108,17 @@ static int ntfs_ia_add(ntfs_index_context *icx) return 0; } +static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len) +{ + ntfs_attr_search_ctx *ctx; + INDEX_ROOT *ir; + + ir = ntfs_ir_lookup(ni, name, len, &ctx); + if (ir) + ntfs_attr_put_search_ctx(ctx); + return ir; +} + static int ntfs_ir_reparent(ntfs_index_context *icx) { ntfs_attr_search_ctx *ctx; @@ -1136,7 +1147,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx) ntfs_log_perror("Failed to move index root to index block"); goto clear_bmp; } - + if (ntfs_ib_write(icx, new_ib_vcn, ib)) goto clear_bmp; @@ -1192,16 +1203,11 @@ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) */ ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); if (ret == STATUS_OK) { - ntfs_attr_search_ctx *ctx; - - icx->ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, - &ctx); + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; icx->ir->index.allocated_size = cpu_to_le32(data_size); - - ntfs_attr_put_search_ctx(ctx); } else { if (errno != ENOSPC && errno != EOVERFLOW) ntfs_log_trace("Failed to truncate INDEX_ROOT"); @@ -1300,6 +1306,10 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, ntfs_log_trace("Entering.\n"); + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!icx->ir) + return STATUS_ERROR; + new_size = le32_to_cpu(icx->ir->index.index_length) + le16_to_cpu(median->length); if (!(median->flags & INDEX_ENTRY_NODE)) @@ -1309,6 +1319,10 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, if (ret != STATUS_OK) return ret; + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); + if (!icx->ir) + return STATUS_ERROR; + return ntfs_ih_insert(&icx->ir->index, median, new_vcn, ntfs_icx_parent_pos(icx)); } From 28226c183b268399d75e1a2df0e69a621b586063 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 11 Sep 2007 19:46:20 +0300 Subject: [PATCH 225/289] Mount block devices with blkdev mount option --- configure.ac | 2 +- ntfsprogs/ntfsmount.c | 103 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 71049793..d2902c8f 100644 --- a/configure.ac +++ b/configure.ac @@ -357,7 +357,7 @@ AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \ endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \ sys/ioctl.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \ sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \ - machine/endian.h windows.h syslog.h]) + machine/endian.h windows.h syslog.h pwd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 88cee13f..f0ebc0ec 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -51,8 +51,15 @@ #ifdef HAVE_LIMITS_H #include #endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_GETOPT_H #include +#endif +#ifdef HAVE_SYSLOG_H #include +#endif #ifdef HAVE_SETXATTR #include @@ -108,6 +115,7 @@ typedef struct { BOOL no_def_opts; BOOL case_insensitive; BOOL noatime; + BOOL blkdev; } ntfs_fuse_context_t; typedef enum { @@ -148,6 +156,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { NTFS_FUSE_OPT("locale=%s", locale), NTFS_FUSE_OPT_NEG("nosilent", silent), NTFS_FUSE_OPT_NEG("rw", ro), + NTFS_FUSE_OPT_NEG("noblkdev", blkdev), NTFS_FUSE_OPT_VAL("streams_interface=none", streams, NF_STREAMS_INTERFACE_NONE), NTFS_FUSE_OPT_VAL("streams_interface=windows", streams, @@ -160,6 +169,8 @@ static const struct fuse_opt ntfs_fuse_opts[] = { FUSE_OPT_KEY("umask=", NF_KEY_UMASK), FUSE_OPT_KEY("noauto", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("blkdev", FUSE_OPT_KEY_DISCARD), + FUSE_OPT_KEY("blksize=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("noatime", FUSE_OPT_KEY_KEEP), @@ -1527,12 +1538,13 @@ static int ntfs_fuse_init(void) *ctx = (ntfs_fuse_context_t) { .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, - .uid = geteuid(), - .gid = getegid(), + .uid = getuid(), + .gid = getgid(), .fmask = 0111, .dmask = 0, .streams = NF_STREAMS_INTERFACE_NONE, .silent = TRUE, + .blkdev = TRUE, }; return 0; } @@ -1590,10 +1602,39 @@ static int ntfs_fuse_opt_proc(void *data __attribute__((unused)), } } +static int ntfs_fuse_is_block_dev(void) +{ + struct stat st; + + if (stat(ctx->device, &st)) { + ntfs_log_perror("Failed to stat %s", ctx->device); + return -1; + } + + if (S_ISBLK(st.st_mode)) { + if (!ctx->blkdev) { + ntfs_log_warning("WARNING: %s is block device, but you " + "submitted 'noblkdev' option. This is " + "not recommended.\n", ctx->device); + } + if (geteuid()) { + ntfs_log_warning("WARNING: %s is block device, but you " + "are not root and %s is not set-uid-" + "root, so using 'blkdev' option is not " + "possible. This is not recommended.\n", + ctx->device, EXEC_NAME); + ctx->blkdev = FALSE; + } + + } else + ctx->blkdev = FALSE; + return 0; +} + static int parse_options(struct fuse_args *args) { int ret; - char *fsname; + char *buffer = NULL; ret = fuse_opt_parse(args, ctx, ntfs_fuse_opts, ntfs_fuse_opt_proc); if (!ctx->device) { @@ -1612,15 +1653,38 @@ static int parse_options(struct fuse_args *args) if (ctx->locale && !setlocale(LC_ALL, ctx->locale)) ntfs_log_error("Failed to set locale to %s " "(continue anyway).\n", ctx->locale); - fsname = ntfs_malloc(strlen(ctx->device) + 64); - if (!fsname) + if (ntfs_fuse_is_block_dev()) return -1; - sprintf(fsname, "-ofsname=%s", ctx->device); - if (fuse_opt_add_arg(args, fsname) == -1) { - free(fsname); + + /* + * Now we will submit extra options to fuse. Allocate long enough + * buffer for all dynamically generated options. + */ + buffer = ntfs_malloc(strlen(ctx->device) + 128); + if (!buffer) + return -1; + /* fsname */ + sprintf(buffer, "-ofsname=%s", ctx->device); + if (fuse_opt_add_arg(args, buffer) == -1) { + free(buffer); return -1; } - free(fsname); + /* blkdev, user */ + if (ctx->blkdev) { + struct passwd *pw; + + pw = getpwuid(ctx->uid); + if (!pw || !pw->pw_name) { + free(buffer); + return -1; + } + sprintf(buffer, "-oblkdev,user=%s", pw->pw_name); + if (fuse_opt_add_arg(args, buffer) == -1) { + free(buffer); + return -1; + } + } + free(buffer); if (!ctx->no_def_opts) { if (fuse_opt_add_arg(args, "-o") == -1) return -1; @@ -1639,10 +1703,10 @@ static int ntfs_fuse_mount(void) ntfs_volume *vol; vol = utils_mount_volume(ctx->device, - ((ctx->ro) ? NTFS_MNT_RDONLY : 0) | - ((ctx->case_insensitive) ? 0 : - NTFS_MNT_CASE_SENSITIVE) | - NTFS_MNT_NOT_EXCLUSIVE /* FIXME */, ctx->force); + (ctx->case_insensitive ? 0 : NTFS_MNT_CASE_SENSITIVE) | + (ctx->blkdev ? NTFS_MNT_NOT_EXCLUSIVE : 0) | + (ctx->ro ? NTFS_MNT_RDONLY : 0), + ctx->force); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; @@ -1670,6 +1734,13 @@ int main(int argc, char *argv[]) ntfs_fuse_destroy(NULL); return 1; } + /* Gain root privileges if required. */ + if (ctx->blkdev) + if (setuid(0)) { + ntfs_log_perror("setuid(0) failed"); + fuse_opt_free_args(&args); + ntfs_fuse_destroy(NULL); + } /* Create filesystem (FUSE part). */ fch = fuse_mount(ctx->mnt_point, &args); if (!fch) { @@ -1687,9 +1758,13 @@ int main(int argc, char *argv[]) ntfs_fuse_destroy(NULL); return 1; } + /* Drop root privileges. */ + if (setuid(ctx->uid) || seteuid(ctx->uid)) + ntfs_log_warning("Failed to drop root privileges.\n"); + /* Detach from terminal. */ if (!ctx->debug && !ctx->no_detach) { if (daemon(0, 0)) - ntfs_log_error("Failed to daemonize.\n"); + ntfs_log_error("Failed to detach from terminal.\n"); else { ntfs_log_set_handler(ntfs_log_handler_syslog); /* Override default libntfs identify. */ From 9cd3246db7685f9d16eee415e931a411fba1fce2 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 11 Sep 2007 20:56:34 +0300 Subject: [PATCH 226/289] cleanup --- include/ntfs/inode.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 5ad9bc47..70d172fd 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -41,7 +41,7 @@ typedef struct _ntfs_inode ntfs_inode; typedef enum { NI_Dirty, /* 1: Mft record needs to be written to disk. */ - /* The NI_AttrList* tests only make sense for base inodes. */ + /* Below fields only make sense for base inodes. */ NI_AttrList, /* 1: Mft record contains an attribute list. */ NI_AttrListDirty, /* 1: Attribute list needs to be written to the mft record and then to disk. */ @@ -130,6 +130,12 @@ struct _ntfs_inode { }; /* Below fields are valid only for base inode. */ + + /* + * This two fields are used to sync filename index and guaranteed to be + * correct, however value in index itself maybe wrong (windows itself + * do not update them properly). + */ s64 data_size; /* Data size of unnamed DATA attribute. */ s64 allocated_size; /* Allocated size stored in the filename index. (NOTE: Equal to allocated size of From ba89f9ebf449db752d535d4a66ad8c39981eef86 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 12 Sep 2007 15:55:37 +0300 Subject: [PATCH 227/289] More sane set-uid-root handling --- ntfsprogs/ntfsmount.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index f0ebc0ec..5819af57 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1734,13 +1734,22 @@ int main(int argc, char *argv[]) ntfs_fuse_destroy(NULL); return 1; } - /* Gain root privileges if required. */ - if (ctx->blkdev) + if (ctx->blkdev) { + /* Gain root privileges for blkdev mount. */ if (setuid(0)) { ntfs_log_perror("setuid(0) failed"); fuse_opt_free_args(&args); ntfs_fuse_destroy(NULL); + return 1; } + } else { + /* + * Drop effective uid if our binary is set-uid-root and we are + * performing not blkdev mount. + */ + if (!geteuid() && seteuid(ctx->uid)) + ntfs_log_perror("Failed to drop effective uid"); + } /* Create filesystem (FUSE part). */ fch = fuse_mount(ctx->mnt_point, &args); if (!fch) { @@ -1758,8 +1767,8 @@ int main(int argc, char *argv[]) ntfs_fuse_destroy(NULL); return 1; } - /* Drop root privileges. */ - if (setuid(ctx->uid) || seteuid(ctx->uid)) + /* Drop root privileges if we obtained them. */ + if (ctx->blkdev && (setuid(ctx->uid) || seteuid(ctx->uid))) ntfs_log_warning("Failed to drop root privileges.\n"); /* Detach from terminal. */ if (!ctx->debug && !ctx->no_detach) { From 3504cc8796e3a8ff1e63257d032136b14742d25f Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 12 Sep 2007 16:15:54 +0300 Subject: [PATCH 228/289] Handle atime option --- ntfsprogs/ntfsmount.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 5819af57..83107a24 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -157,6 +157,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { NTFS_FUSE_OPT_NEG("nosilent", silent), NTFS_FUSE_OPT_NEG("rw", ro), NTFS_FUSE_OPT_NEG("noblkdev", blkdev), + NTFS_FUSE_OPT_NEG("atime", noatime), NTFS_FUSE_OPT_VAL("streams_interface=none", streams, NF_STREAMS_INTERFACE_NONE), NTFS_FUSE_OPT_VAL("streams_interface=windows", streams, @@ -173,6 +174,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { FUSE_OPT_KEY("blksize=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("atime", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("noatime", FUSE_OPT_KEY_KEEP), FUSE_OPT_END }; From 31a39d2a3700b2285c847e9b9269f5b7ec39d8f2 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 12 Sep 2007 16:43:27 +0300 Subject: [PATCH 229/289] Fix memory corruption in case option parsing failed. --- ntfsprogs/ntfsmount.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 83107a24..09d38afe 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1556,6 +1556,7 @@ static int ntfs_fuse_opt_proc(void *data __attribute__((unused)), { switch (key) { case NF_KEY_HELP: + usage(); return -1; /* Force usage show. */ case NF_KEY_UMASK: ctx->dmask = ctx->fmask; @@ -1635,12 +1636,14 @@ static int ntfs_fuse_is_block_dev(void) static int parse_options(struct fuse_args *args) { - int ret; char *buffer = NULL; - ret = fuse_opt_parse(args, ctx, ntfs_fuse_opts, ntfs_fuse_opt_proc); + if (fuse_opt_parse(args, ctx, ntfs_fuse_opts, ntfs_fuse_opt_proc)) + return -1; + if (!ctx->device) { ntfs_log_error("No device specified.\n"); + usage(); return -1; } if (ctx->quiet && ctx->verbose) { @@ -1697,7 +1700,7 @@ static int parse_options(struct fuse_args *args) if (fuse_opt_add_arg(args, "-odebug") == -1) return -1; } - return ret; + return 0; } static int ntfs_fuse_mount(void) @@ -1724,8 +1727,7 @@ int main(int argc, char *argv[]) struct fuse_chan *fch; ntfs_fuse_init(); - if (parse_options(&args) == -1) { - usage(); + if (parse_options(&args)) { fuse_opt_free_args(&args); ntfs_fuse_destroy(NULL); return 1; From 5d05d42d055695cfbf4e710bb77d044991f4ed78 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 12 Sep 2007 17:52:21 +0300 Subject: [PATCH 230/289] properly fix st_blocks calculation --- ChangeLog | 3 ++- ntfsprogs/ntfsmount.c | 53 ++++++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index d52c0ed1..c302d4a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -73,7 +73,8 @@ xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. everything beyond them. Update libntfs behaviour to be like in windows. (Yura) - ntfsmount: Fix free clusters and MFT records calculation. (Yura) - - ntfsmount: Fix st_blocks calculation. (Yuval, Yura) + - ntfsmount: Fix st_blocks calculation for resident files. (Yuval, + Yura) - ntfsmount: Umount volume in DESTROY. This is guarantees that all data would be synced before umount return for volumes mounted with blkdev option. (Yura) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 09d38afe..c2eece1d 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -387,13 +387,19 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) res = -ENOENT; goto exit; } + stbuf->st_uid = ctx->uid; + stbuf->st_gid = ctx->gid; + stbuf->st_ino = ni->mft_no; + stbuf->st_atime = ni->last_access_time; + stbuf->st_ctime = ni->last_mft_change_time; + stbuf->st_mtime = ni->last_data_change_time; if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY && !stream_name_len) { /* Directory. */ stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask); na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (na) { stbuf->st_size = na->data_size; - stbuf->st_blocks = (na->allocated_size + 511) >> 9; + stbuf->st_blocks = na->allocated_size >> 9; ntfs_attr_close(na); } else { stbuf->st_size = 0; @@ -401,27 +407,25 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } stbuf->st_nlink = 1; /* Needed for correct find work. */ } else { - /* Regular or Interix (INTX) file. */ + /* Regular, data stream or Interix (INTX) file. */ stbuf->st_mode = S_IFREG; - stbuf->st_size = ni->data_size; - stbuf->st_blocks = (ni->allocated_size + 511) >> 9; stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); - if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) { - na = ntfs_attr_open(ni, AT_DATA, stream_name, - stream_name_len); - if (!na) { - if (stream_name_len) - res = -ENOENT; - goto exit; - } - if (stream_name_len) { - stbuf->st_size = na->data_size; - stbuf->st_blocks = - (ni->allocated_size + 511) >> 9; - } + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + if (stream_name_len) + res = -ENOENT; + else + stbuf->st_size = stbuf->st_blocks = 0; + goto exit; + } + if (NAttrNonResident(na)) + stbuf->st_blocks = na->allocated_size >> 9; + else + stbuf->st_blocks = 0; + stbuf->st_size = na->data_size; + if (ni->flags & FILE_ATTR_SYSTEM && !stream_name_len) { /* Check whether it's Interix FIFO or socket. */ - if (!(ni->flags & FILE_ATTR_HIDDEN) && - !stream_name_len) { + if (!(ni->flags & FILE_ATTR_HIDDEN)) { /* FIFO. */ if (na->data_size == 0) stbuf->st_mode = S_IFIFO; @@ -435,8 +439,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) */ if (na->data_size <= sizeof(INTX_FILE_TYPES) + sizeof( ntfschar) * MAX_PATH && na->data_size > - sizeof(INTX_FILE_TYPES) && - !stream_name_len) { + sizeof(INTX_FILE_TYPES)) { INTX_FILE *intx_file; intx_file = ntfs_malloc(na->data_size); @@ -474,16 +477,10 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) stbuf->st_mode = S_IFLNK; free(intx_file); } - ntfs_attr_close(na); } + ntfs_attr_close(na); stbuf->st_mode |= (0777 & ~ctx->fmask); } - stbuf->st_uid = ctx->uid; - stbuf->st_gid = ctx->gid; - stbuf->st_ino = ni->mft_no; - stbuf->st_atime = ni->last_access_time; - stbuf->st_ctime = ni->last_mft_change_time; - stbuf->st_mtime = ni->last_data_change_time; exit: if (ni) ntfs_inode_close(ni); From e9f9d9905f32aaf79f9909d2a096fc59610fe633 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 13 Sep 2007 16:07:48 +0300 Subject: [PATCH 231/289] Cleanup --- libntfs/unistr.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/libntfs/unistr.c b/libntfs/unistr.c index bbeb6ccf..6e6aa9b8 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -474,16 +474,13 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, } #endif /* Now write the NULL character. */ - mbs[o] = '\0'; + mbs[o] = 0; if (*outs != mbs) *outs = mbs; return o; err_out: - if (mbs != *outs) { - int eo = errno; + if (mbs != *outs) free(mbs); - errno = eo; - } return -1; } @@ -630,11 +627,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len) *outs = ucs; return o; err_out: - if (ucs != *outs) { - int eo = errno; + if (ucs != *outs) free(ucs); - errno = eo; - } return -1; } From 398755a75e9f4e95cc2a731317ab24f552653cd6 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 13 Sep 2007 20:42:00 +0300 Subject: [PATCH 232/289] ntfsmount: Implement {no,}relatime (relative atime) options. According to http://userweb.kernel.org/~akpm/mount-relative-atime.txt Only several lines with new time handling ;-) --- ntfsprogs/ntfsmount.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index c2eece1d..3d665095 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -115,6 +115,7 @@ typedef struct { BOOL no_def_opts; BOOL case_insensitive; BOOL noatime; + BOOL relatime; BOOL blkdev; } ntfs_fuse_context_t; @@ -148,6 +149,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { NTFS_FUSE_OPT("no_def_opts", no_def_opts), NTFS_FUSE_OPT("case_insensitive", case_insensitive), NTFS_FUSE_OPT("noatime", noatime), + NTFS_FUSE_OPT("relatime", relatime), NTFS_FUSE_OPT("fmask=%o", fmask), NTFS_FUSE_OPT("dmask=%o", dmask), NTFS_FUSE_OPT("umask=%o", fmask), @@ -158,6 +160,7 @@ static const struct fuse_opt ntfs_fuse_opts[] = { NTFS_FUSE_OPT_NEG("rw", ro), NTFS_FUSE_OPT_NEG("noblkdev", blkdev), NTFS_FUSE_OPT_NEG("atime", noatime), + NTFS_FUSE_OPT_NEG("norelatime", relatime), NTFS_FUSE_OPT_VAL("streams_interface=none", streams, NF_STREAMS_INTERFACE_NONE), NTFS_FUSE_OPT_VAL("streams_interface=windows", streams, @@ -211,6 +214,10 @@ static __inline__ void ntfs_fuse_update_times(ntfs_inode *ni, { if (ctx->noatime) mask &= ~NTFS_UPDATE_ATIME; + if (ctx->relatime && mask == NTFS_UPDATE_ATIME && + ni->last_access_time >= ni->last_data_change_time && + ni->last_access_time >= ni->last_mft_change_time) + return; ntfs_inode_update_times(ni, mask); } From f5b9888eb63d60c837ce3f02624088b23b1315ac Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 13 Sep 2007 23:05:18 +0300 Subject: [PATCH 233/289] formatting --- libntfs/bitmap.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 57713c0b..45e1c877 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -115,7 +115,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, lastbyte_pos = ((count + 7) >> 3) + firstbyte; if (!lastbyte_pos) { // FIXME: Eeek! BUG! - ntfs_log_trace("Eeek! lastbyte is zero. Leaving " + ntfs_log_trace("lastbyte is zero. Leaving " "inconsistent metadata.\n"); err = EIO; goto free_err_out; @@ -129,9 +129,10 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, 3, 1, lastbyte_buf); if (br != 1) { // FIXME: Eeek! We need rollback! (AIA) - ntfs_log_trace("Eeek! Read of last byte " + ntfs_log_trace("Read of last byte " "failed. Leaving " - "inconsistent metadata.\n"); + "inconsistent " + "metadata.\n"); err = EIO; goto free_err_out; } @@ -154,7 +155,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, br = ntfs_attr_pwrite(na, tmp, bufsize, buf); if (br != bufsize) { // FIXME: Eeek! We need rollback! (AIA) - ntfs_log_trace("Eeek! Failed to write buffer to bitmap. " + ntfs_log_trace("Failed to write buffer to bitmap. " "Leaving inconsistent metadata.\n"); err = EIO; goto free_err_out; @@ -177,9 +178,9 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, if (lastbyte && count != 0) { // FIXME: Eeek! BUG! - ntfs_log_trace("Eeek! Last buffer but count is not zero (= " - "%lli). Leaving inconsistent metadata.\n", - (long long)count); + ntfs_log_trace("Last buffer but count is not zero (= " + "%lli). Leaving inconsistent metadata." + "\n", (long long)count); err = EIO; goto free_err_out; } From e248e6b986e8d5cfd98552a4007b26a762314142 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 14 Sep 2007 12:59:55 +0300 Subject: [PATCH 234/289] Make libntfs keep track number of free clusters and MFT records. Thanks for idea to David Fox and Szabolcs Szakacsits. --- include/ntfs/volume.h | 6 +-- libntfs/bitmap.c | 41 ++++++++++----- libntfs/lcnalloc.c | 1 + libntfs/mft.c | 2 + libntfs/volume.c | 91 ++++++++++++++++++++++++++++++++ ntfsprogs/ntfsmount.c | 119 +++--------------------------------------- 6 files changed, 132 insertions(+), 128 deletions(-) diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index c7f3e893..4bb88a90 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -208,10 +208,8 @@ struct _ntfs_volume { s32 attrdef_len; /* Size of the attribute definition table in bytes. */ - /* Temp: for directory handling */ - void *private_data; /* ntfs_dir for . */ - void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */ - void *private_bmp2; /* ntfs_bmp for $Bitmap */ + long nr_free_clusters; /* This two are self explaining. */ + long nr_free_mft_records; }; extern ntfs_volume *ntfs_volume_alloc(void); diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 45e1c877..69d498fd 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -58,7 +58,8 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, s64 count, int value) { - s64 bufsize, br; + ntfs_volume *vol = na->ni->vol; + s64 bufsize, br, left = count; u8 *buf, *lastbyte_buf; int bit, firstbyte, lastbyte, lastbyte_pos, tmp, err; @@ -95,7 +96,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, return -1; } /* and set or clear the appropriate bits in it. */ - while ((bit & 7) && count--) { + while ((bit & 7) && left--) { if (value) *buf |= 1 << bit++; else @@ -105,14 +106,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, start_bit = (start_bit + 7) & ~7; } - /* Loop until @count reaches zero. */ + /* Loop until @left reaches zero. */ lastbyte = 0; lastbyte_buf = NULL; - bit = count & 7; + bit = left & 7; do { /* If there is a last partial byte... */ - if (count > 0 && bit) { - lastbyte_pos = ((count + 7) >> 3) + firstbyte; + if (left > 0 && bit) { + lastbyte_pos = ((left + 7) >> 3) + firstbyte; if (!lastbyte_pos) { // FIXME: Eeek! BUG! ntfs_log_trace("lastbyte is zero. Leaving " @@ -125,7 +126,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, lastbyte_buf = buf + lastbyte_pos - 1; /* read the byte in... */ - br = ntfs_attr_pread(na, (start_bit + count) >> + br = ntfs_attr_pread(na, (start_bit + left) >> 3, 1, lastbyte_buf); if (br != 1) { // FIXME: Eeek! We need rollback! (AIA) @@ -137,7 +138,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, goto free_err_out; } /* and set/clear the appropriate bits in it. */ - while (bit && count--) { + while (bit && left--) { if (value) *lastbyte_buf |= 1 << --bit; else @@ -172,19 +173,33 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit, *buf = value ? 0xff : 0; } start_bit += tmp; - count -= tmp; - if (bufsize > (tmp = (count + 7) >> 3)) + left -= tmp; + if (bufsize > (tmp = (left + 7) >> 3)) bufsize = tmp; - if (lastbyte && count != 0) { + if (lastbyte && left != 0) { // FIXME: Eeek! BUG! ntfs_log_trace("Last buffer but count is not zero (= " "%lli). Leaving inconsistent metadata." - "\n", (long long)count); + "\n", (long long)left); err = EIO; goto free_err_out; } - } while (count > 0); + } while (left > 0); + + /* Update free clusters and MFT records. */ + if (na == vol->mftbmp_na) { + if (value) + vol->nr_free_mft_records -= count; + else + vol->nr_free_mft_records += count; + } + if (na == vol->lcnbmp_na) { + if (value) + vol->nr_free_clusters -= count; + else + vol->nr_free_clusters += count; + } /* Done! */ free(buf); diff --git a/libntfs/lcnalloc.c b/libntfs/lcnalloc.c index 9fad9a80..46698642 100644 --- a/libntfs/lcnalloc.c +++ b/libntfs/lcnalloc.c @@ -287,6 +287,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, } /* Allocate the bitmap bit. */ *byte |= bit; + vol->nr_free_clusters--; /* We need to write this bitmap buffer back to disk! */ need_writeback = 1; ntfs_log_trace("*byte = 0x%x, need_writeback is set.\n", diff --git a/libntfs/mft.c b/libntfs/mft.c index fc902219..c0a3cae4 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -609,6 +609,7 @@ static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol) errno = EIO; return -1; } + vol->nr_free_clusters--; /* Update the mft bitmap runlist. */ rl->length++; rl[1].vcn++; @@ -833,6 +834,7 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol) ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n"); return 0; } + vol->nr_free_mft_records += 64; /* 8 bytes x 8 bits each. */ ntfs_log_error("Failed to write to mft bitmap.\n"); err = errno; if (ll >= 0) diff --git a/libntfs/volume.c b/libntfs/volume.c index 0f7dd140..bfef1117 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -744,6 +744,88 @@ out: return ret; } +/** + * ntfs_volume_get_nr_free_mft_records - calculate number of free MFT records + * vol: ntfs volume for which perform calculations. + * + * This function initializes @vol->nr_free_mft_records. @vol->mftbmp_na should + * be already opened upon call to this function. + * + * Return 0 on success. On error return -1 with errno set appropriately and + * @vol->nr_free_mft_records is not touched in this case. + */ +static int ntfs_volume_get_nr_free_mft_records(ntfs_volume *vol) +{ + long nr_free = vol->mft_na->data_size >> vol->mft_record_size_bits; + s64 br, total = 0; + u8 *buf; + + buf = ntfs_malloc(vol->cluster_size); + if (!buf) + return -1; + while (1) { + int i, j; + + br = ntfs_attr_pread(vol->mftbmp_na, total, + vol->cluster_size, buf); + if (br <= 0) + break; + total += br; + for (i = 0; i < br; i++) + for (j = 0; j < 8; j++) + if ((buf[i] >> j) & 1) + nr_free--; + } + free(buf); + if (!total || br < 0) { + ntfs_log_error("pread: %s\n", strerror(errno)); + return -1; + } + vol->nr_free_mft_records = nr_free; + return 0; +} + +/** + * ntfs_volume_get_nr_free_clusters - calculate number of free clusters + * vol: ntfs volume for which perform calculations. + * + * This function initializes @vol->nr_free_clusters. @vol->lcnbmp_na should be + * already opened upon call to this function. + * + * Return 0 on success. On error return -1 with errno set appropriately and + * @vol->nr_free_clusters is not touched in this case. + */ +static long ntfs_volume_get_nr_free_clusters(ntfs_volume *vol) +{ + long nr_free = vol->nr_clusters; + s64 br, total = 0; + u8 *buf; + + buf = ntfs_malloc(vol->cluster_size); + if (!buf) + return -1; + while (1) { + int i, j; + + br = ntfs_attr_pread(vol->lcnbmp_na, total, + vol->cluster_size, buf); + if (br <= 0) + break; + total += br; + for (i = 0; i < br; i++) + for (j = 0; j < 8; j++) + if ((buf[i] >> j) & 1) + nr_free--; + } + free(buf); + if (!total || br < 0) { + ntfs_log_error("pread: %s\n", strerror(errno)); + return -1; + } + vol->nr_free_clusters = nr_free; + return 0; +} + /** * ntfs_device_mount - open ntfs volume * @dev: device to open @@ -1127,6 +1209,15 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) ntfs_attr_close(na); if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode, leaking memory"); + /* Initialize number of free clusters and MFT records. */ + if (ntfs_volume_get_nr_free_mft_records(vol)) { + ntfs_log_perror("Failed to calculate number of free MFTs"); + goto error_exit; + } + if (ntfs_volume_get_nr_free_clusters(vol)) { + ntfs_log_perror("Failed to calculate number of free clusters"); + goto error_exit; + } /* * Check for dirty logfile and hibernated Windows. * We care only about read-write mounts. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 3d665095..f6603f05 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -97,9 +97,6 @@ typedef struct { char *mnt_point; char *device; char *locale; - int state; - long free_clusters; - long free_mft; unsigned int uid; unsigned int gid; unsigned int fmask; @@ -119,13 +116,6 @@ typedef struct { BOOL blkdev; } ntfs_fuse_context_t; -typedef enum { - NF_FreeClustersOutdate = (1 << 0), /* Information about amount of - free clusters is outdated. */ - NF_FreeMFTOutdate = (1 << 1), /* Information about amount of - free MFT records is outdated. */ -} ntfs_fuse_state_bits; - #define NTFS_FUSE_OPT(t, p) { t, offsetof(ntfs_fuse_context_t, p), TRUE } #define NTFS_FUSE_OPT_NEG(t, p) { t, offsetof(ntfs_fuse_context_t, p), FALSE } #define NTFS_FUSE_OPT_VAL(t, p, v) { t, offsetof(ntfs_fuse_context_t, p), v } @@ -187,15 +177,6 @@ static char ntfs_fuse_default_options[] = "default_permissions,allow_other,use_ino,kernel_cache,nonempty"; static ntfs_fuse_context_t *ctx; -/** - * ntfs_fuse_mark_free_space_outdated - forces free space recalculation - */ -static __inline__ void ntfs_fuse_mark_free_space_outdated(void) -{ - /* Mark information about free MFT record and clusters outdated. */ - ctx->state |= (NF_FreeClustersOutdate | NF_FreeMFTOutdate); -} - /** * ntfs_fuse_is_named_data_stream - check path to be to named data stream * @path: path to check @@ -221,73 +202,6 @@ static __inline__ void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_inode_update_times(ni, mask); } -static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free) -{ - u8 *buf; - s64 br, total = 0; - - if (!(ctx->state & NF_FreeMFTOutdate)) - return ctx->free_mft; - buf = ntfs_malloc(vol->cluster_size); - if (!buf) - return -errno; - while (1) { - int i, j; - - br = ntfs_attr_pread(vol->mftbmp_na, total, - vol->cluster_size, buf); - if (br <= 0) - break; - total += br; - for (i = 0; i < br; i++) - for (j = 0; j < 8; j++) - if ((buf[i] >> j) & 1) - nr_free--; - } - free(buf); - if (!total || br < 0) { - ntfs_log_error("pread: %s\n", strerror(errno)); - return -errno; - } - ctx->free_mft = nr_free; - ctx->state &= ~(NF_FreeMFTOutdate); - return nr_free; -} - -static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) -{ - u8 *buf; - long nr_free = vol->nr_clusters; - s64 br, total = 0; - - if (!(ctx->state & NF_FreeClustersOutdate)) - return ctx->free_clusters; - buf = ntfs_malloc(vol->cluster_size); - if (!buf) - return -errno; - while (1) { - int i, j; - - br = ntfs_attr_pread(vol->lcnbmp_na, total, - vol->cluster_size, buf); - if (br <= 0) - break; - total += br; - for (i = 0; i < br; i++) - for (j = 0; j < 8; j++) - if ((buf[i] >> j) & 1) - nr_free--; - } - free(buf); - if (!total || br < 0) { - ntfs_log_error("pread: %s\n", strerror(errno)); - return -errno; - } - ctx->free_clusters = nr_free; - ctx->state &= ~(NF_FreeClustersOutdate); - return nr_free; -} - /** * ntfs_fuse_statfs - return information about mounted NTFS volume * @path: ignored (but fuse requires it) @@ -308,8 +222,6 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol) static int ntfs_fuse_statfs(const char *path __attribute__((unused)), struct statvfs *sfs) { - long size; - /* Optimal transfer block size. */ sfs->f_bsize = ctx->vol->cluster_size; sfs->f_frsize = ctx->vol->cluster_size; @@ -319,20 +231,16 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)), * the total clusters. */ sfs->f_blocks = ctx->vol->nr_clusters; - /* Free data blocks in file system in units of f_bsize. */ - size = ntfs_fuse_get_nr_free_clusters(ctx->vol); - if (size < 0) - size = 0; - /* Free blocks avail to non-superuser, same as above on NTFS. */ - sfs->f_bavail = sfs->f_bfree = size; + /* + * Free data blocks and free data block available to non-superuser in + * file system in units of f_bsize. + */ + sfs->f_bavail = sfs->f_bfree = ctx->vol->nr_free_clusters; /* Number of inodes in file system (at this point in time). */ - size = ctx->vol->mft_na->data_size >> ctx->vol->mft_record_size_bits; - sfs->f_files = size; + sfs->f_files = ctx->vol->mft_na->data_size >> + ctx->vol->mft_record_size_bits; /* Free inodes in fs (based on current total count). */ - size = ntfs_fuse_get_nr_free_mft_records(ctx->vol, size); - if (size < 0) - size = 0; - sfs->f_ffree = size; + sfs->f_ffree = ctx->vol->nr_free_mft_records; /* Maximum length of filenames. */ sfs->f_namemax = NTFS_MAX_NAME_LEN; return 0; @@ -746,7 +654,6 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, } res = total; exit: - ntfs_fuse_mark_free_space_outdated(); if (res > 0) ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME); @@ -793,7 +700,6 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) NTFS_UPDATE_CTIME); res = 0; } - ntfs_fuse_mark_free_space_outdated(); ntfs_attr_close(na); exit: if (ni && ntfs_inode_close(ni)) @@ -938,7 +844,6 @@ static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev) else res = ntfs_fuse_create_stream(path, stream_name, stream_name_len); - ntfs_fuse_mark_free_space_outdated(); exit: free(path); if (stream_name_len) @@ -950,7 +855,6 @@ static int ntfs_fuse_symlink(const char *to, const char *from) { if (ntfs_fuse_is_named_data_stream(from)) return -EINVAL; /* n/a for named data streams. */ - ntfs_fuse_mark_free_space_outdated(); return ntfs_fuse_create(from, S_IFLNK, 0, to); } @@ -992,7 +896,6 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path) res = -EIO; goto exit; } - ntfs_fuse_mark_free_space_outdated(); /* Create hard link. */ if (ntfs_link(ni, dir_ni, uname, uname_len)) res = -errno; @@ -1101,7 +1004,6 @@ static int ntfs_fuse_unlink(const char *org_path) res = ntfs_fuse_rm(path); else res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len); - ntfs_fuse_mark_free_space_outdated(); free(path); if (stream_name_len) free(stream_name); @@ -1153,7 +1055,6 @@ static int ntfs_fuse_mkdir(const char *path, { if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ - ntfs_fuse_mark_free_space_outdated(); return ntfs_fuse_create(path, S_IFDIR, 0, NULL); } @@ -1161,7 +1062,6 @@ static int ntfs_fuse_rmdir(const char *path) { if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ - ntfs_fuse_mark_free_space_outdated(); return ntfs_fuse_rm(path); } @@ -1389,7 +1289,6 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, res = -EEXIST; goto exit; } - ntfs_fuse_mark_free_space_outdated(); if (!na) { if (flags == XATTR_REPLACE) { res = -ENODATA; @@ -1444,7 +1343,6 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) res = -ENODATA; goto exit; } - ntfs_fuse_mark_free_space_outdated(); if (ntfs_attr_rm(na)) res = -errno; na = NULL; @@ -1543,7 +1441,6 @@ static int ntfs_fuse_init(void) return -1; *ctx = (ntfs_fuse_context_t) { - .state = NF_FreeClustersOutdate | NF_FreeMFTOutdate, .uid = getuid(), .gid = getgid(), .fmask = 0111, From 5e4341c0ac6ba9e04a62b7c423f2f4f1c065cc92 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 14 Sep 2007 13:09:14 +0300 Subject: [PATCH 235/289] Do not refuse mount if there is garbadge in hiberfil.sys file. (Szabolcs Szakacsits) --- libntfs/volume.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libntfs/volume.c b/libntfs/volume.c index bfef1117..b705c924 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -691,7 +691,7 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol) { ntfs_inode *ni; ntfs_attr *na = NULL; - int i, bytes_read, ret = -1; + int bytes_read, ret = -1; char *buf = NULL; ni = ntfs_hiberfile_open(vol); @@ -727,14 +727,6 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol) errno = EPERM; goto out; } - for (i = 0; i < NTFS_HIBERFILE_HEADER_SIZE; i++) { - if (buf[i]) { - ntfs_log_debug("Windows is hibernated, won't mount!\n"); - errno = EPERM; - goto out; - } - } - /* All right, all header bytes are zero */ ret = 0; out: if (na) From 942519d0937bb48174c510ad177092d038302b49 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 14 Sep 2007 18:53:46 +0300 Subject: [PATCH 236/289] ntfsmount: Add bmap support. (Szaka, Yura) --- ntfsprogs/ntfsmount.c | 93 +++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index f6603f05..2078c09f 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1091,6 +1091,49 @@ static int ntfs_fuse_utimens(const char *path, const struct timespec ts[2]) return 0; } +static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx) +{ + ntfs_inode *ni; + ntfs_attr *na; + LCN lcn; + int ret = 0, cl_per_bl = ctx->vol->cluster_size / blocksize; + + if (blocksize > ctx->vol->cluster_size || + ntfs_fuse_is_named_data_stream(path)) + return -EINVAL; + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return -errno; + na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); + if (!na) { + ret = -errno; + goto close_inode; + } + + if (NAttrCompressed(na) || NAttrEncrypted(na) || + !NAttrNonResident(na)) { + ret = -EINVAL; + goto close_attr; + } + + lcn = ntfs_attr_vcn_to_lcn(na, *idx / cl_per_bl); + if (lcn < 0) { + if (lcn == LCN_HOLE) + ret = -EINVAL; + else + ret = -EIO; + goto close_attr; + } + *idx = lcn * cl_per_bl + *idx % cl_per_bl; +close_attr: + ntfs_attr_close(na); +close_inode: + if (ntfs_inode_close(ni)) + ntfs_log_perror("bmap: failed to close inode"); + return ret; +} + #ifdef HAVE_SETXATTR static const char nf_ns_xattr_preffix[] = "user."; @@ -1390,6 +1433,7 @@ static struct fuse_operations ntfs_fuse_oper = { .mkdir = ntfs_fuse_mkdir, .rmdir = ntfs_fuse_rmdir, .utimens = ntfs_fuse_utimens, + .bmap = ntfs_fuse_bmap, .destroy = ntfs_fuse_destroy, #ifdef HAVE_SETXATTR .getxattr = ntfs_fuse_getxattr, @@ -1562,35 +1606,16 @@ static int parse_options(struct fuse_args *args) if (ntfs_fuse_is_block_dev()) return -1; - /* - * Now we will submit extra options to fuse. Allocate long enough - * buffer for all dynamically generated options. - */ buffer = ntfs_malloc(strlen(ctx->device) + 128); if (!buffer) return -1; - /* fsname */ sprintf(buffer, "-ofsname=%s", ctx->device); if (fuse_opt_add_arg(args, buffer) == -1) { free(buffer); return -1; } - /* blkdev, user */ - if (ctx->blkdev) { - struct passwd *pw; - - pw = getpwuid(ctx->uid); - if (!pw || !pw->pw_name) { - free(buffer); - return -1; - } - sprintf(buffer, "-oblkdev,user=%s", pw->pw_name); - if (fuse_opt_add_arg(args, buffer) == -1) { - free(buffer); - return -1; - } - } free(buffer); + if (!ctx->no_def_opts) { if (fuse_opt_add_arg(args, "-o") == -1) return -1; @@ -1604,6 +1629,28 @@ static int parse_options(struct fuse_args *args) return 0; } +static int ntfs_fuse_set_blkdev_options(struct fuse_args *args) +{ + int pagesize, blksize = ctx->vol->cluster_size; + struct passwd *pw; + char buffer[128]; + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize < 1) + pagesize = 4096; + if (blksize > pagesize) + blksize = pagesize; + pw = getpwuid(ctx->uid); + if (!pw || !pw->pw_name) { + ntfs_log_perror("getpwuid(%d) failed", ctx->uid); + return -1; + } + sprintf(buffer, "-oblkdev,blksize=%d,user=%s", blksize, pw->pw_name); + if (fuse_opt_add_arg(args, buffer) == -1) + return -1; + return 0; +} + static int ntfs_fuse_mount(void) { ntfs_volume *vol; @@ -1647,6 +1694,12 @@ int main(int argc, char *argv[]) ntfs_fuse_destroy(NULL); return 1; } + /* Set blkdev, blksize and user options. */ + if (ntfs_fuse_set_blkdev_options(&args)) { + fuse_opt_free_args(&args); + ntfs_fuse_destroy(NULL); + return 1; + } } else { /* * Drop effective uid if our binary is set-uid-root and we are From 57cc7904c9ea4f16ca3a352f7e13c194bfe2dca4 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 15 Sep 2007 17:31:39 +0300 Subject: [PATCH 237/289] cleanups (Szaka) --- libntfs/index.c | 4 +++- ntfsprogs/ntfsmount.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libntfs/index.c b/libntfs/index.c index 5e5760b3..843960a0 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -1490,7 +1490,7 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) { INDEX_ENTRY *ie; ntfs_index_context *icx; - int fn_size, ie_size, ret = -1; + int fn_size, ie_size, ret = -1, err; ntfs_log_trace("Entering.\n"); @@ -1517,7 +1517,9 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) if (!icx) goto out; + err = errno; ret = ntfs_ie_add(icx, ie); + errno = err; ntfs_index_ctx_put(icx); out: diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 2078c09f..736e6ad2 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -594,8 +594,10 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, while (size) { res = ntfs_attr_pread(na, offset, size, buf); if (res < (s64)size) - ntfs_log_error("ntfs_attr_pread returned less bytes " - "than requested.\n"); + ntfs_log_error("ntfs_attr_pread returned %d bytes " + "instead of requested %lld bytes " + "(offset %lld).\n", res, + (long long)size, (long long)offset); if (res <= 0) { res = -errno; goto exit; @@ -642,8 +644,10 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, while (size) { res = ntfs_attr_pwrite(na, offset, size, buf); if (res < (s64)size && errno != ENOSPC) - ntfs_log_error("ntfs_attr_pwrite returned less bytes " - "than requested.\n"); + ntfs_log_error("ntfs_attr_pwrite returned %d bytes " + "instead of requested %lld bytes " + "(offset %lld).\n", res, + (long long)size, (long long)offset); if (res <= 0) { res = -errno; goto exit; From 37476cf609d0a68c180df2a537d7e62a2a51bf97 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 15 Sep 2007 18:12:32 +0300 Subject: [PATCH 238/289] Introduce NTFS_MNT_FORCE instead of third parameter of utils_mount_volume --- include/ntfs/volume.h | 1 + ntfsprogs/ntfscat.c | 3 ++- ntfsprogs/ntfscluster.c | 3 ++- ntfsprogs/ntfscp.c | 4 +++- ntfsprogs/ntfsdecrypt.c | 3 ++- ntfsprogs/ntfsinfo.c | 3 ++- ntfsprogs/ntfslabel.c | 5 +++-- ntfsprogs/ntfsls.c | 3 ++- ntfsprogs/ntfsmount.c | 4 ++-- ntfsprogs/ntfsmove.c | 4 +++- ntfsprogs/ntfsundelete.c | 3 ++- ntfsprogs/ntfswipe.c | 4 +++- ntfsprogs/utils.c | 7 +++---- ntfsprogs/utils.h | 2 +- 14 files changed, 31 insertions(+), 18 deletions(-) diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 4bb88a90..a6948af0 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -60,6 +60,7 @@ typedef enum { NTFS_MNT_FORENSIC = 2, NTFS_MNT_CASE_SENSITIVE = 4, NTFS_MNT_NOT_EXCLUSIVE = 8, + NTFS_MNT_FORCE = 16, } ntfs_mount_flags; /** diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index 88a12fe8..31564f6a 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -410,7 +410,8 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { ntfs_log_perror("ERROR: couldn't mount volume"); return 1; diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index d72f5e8f..23f0e7b0 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -492,7 +492,8 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index b2425174..0a6988d4 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -345,8 +345,10 @@ int main(int argc, char *argv[]) if (opts.noaction) flags = NTFS_MNT_RDONLY; + if (opts.force) + flags |= NTFS_MNT_FORCE; - vol = utils_mount_volume(opts.device, flags, opts.force); + vol = utils_mount_volume(opts.device, flags); if (!vol) { ntfs_log_perror("ERROR: couldn't mount volume"); return 1; diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index bf77f4a8..cd0e72b9 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -1307,7 +1307,8 @@ int main(int argc, char *argv[]) return 1; } /* Mount the ntfs volume. */ - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { ntfs_log_error("Failed to mount ntfs volume. Aborting.\n"); ntfs_rsa_private_key_release(rsa_key); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index e7863e1f..e3adfe1d 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -2246,7 +2246,8 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { printf("Failed to open '%s'.\n", opts.device); exit(1); diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index 6f642670..1e6f60ba 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -394,8 +394,9 @@ int main(int argc, char **argv) if (!opts.label) opts.noaction++; - vol = utils_mount_volume(opts.device, opts.noaction ? - NTFS_MNT_RDONLY : 0, opts.force); + vol = utils_mount_volume(opts.device, + (opts.noaction ? NTFS_MNT_RDONLY : 0) | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c index a5c6cc20..77b29b7a 100644 --- a/ntfsprogs/ntfsls.c +++ b/ntfsprogs/ntfsls.c @@ -651,7 +651,8 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { // FIXME: Print error... (AIA) return 2; diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 736e6ad2..9d88a73b 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1662,8 +1662,8 @@ static int ntfs_fuse_mount(void) vol = utils_mount_volume(ctx->device, (ctx->case_insensitive ? 0 : NTFS_MNT_CASE_SENSITIVE) | (ctx->blkdev ? NTFS_MNT_NOT_EXCLUSIVE : 0) | - (ctx->ro ? NTFS_MNT_RDONLY : 0), - ctx->force); + (ctx->force ? NTFS_MNT_FORCE : 0) | + (ctx->ro ? NTFS_MNT_RDONLY : 0)); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index bda2b88c..fb6de815 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -876,8 +876,10 @@ int main(int argc, char *argv[]) if (opts.noaction) flags |= NTFS_MNT_RDONLY; + if (opts.force) + flags |= NTFS_MNT_FORCE; - vol = utils_mount_volume(opts.device, flags, opts.force); + vol = utils_mount_volume(opts.device, flags); if (!vol) { ntfs_log_info("!vol\n"); return 1; diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index 0dac320c..10f2d158 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -2155,7 +2155,8 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY, opts.force); + vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index 78acc94b..f955500a 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1341,8 +1341,10 @@ int main(int argc, char *argv[]) if (opts.info || opts.noaction) flags = NTFS_MNT_RDONLY; + if (opts.force) + flags |= NTFS_MNT_FORCE; - vol = utils_mount_volume(opts.device, flags, opts.force); + vol = utils_mount_volume(opts.device, flags); if (!vol) goto free; diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 2af7361d..d6c7e7b7 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -206,8 +206,7 @@ int utils_valid_device(const char *name, int force) /** * utils_mount_volume - Mount an NTFS volume */ -ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, - BOOL force) +ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags) { ntfs_volume *vol; @@ -216,7 +215,7 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, return NULL; } - if (!utils_valid_device(device, force)) + if (!utils_valid_device(device, flags & NTFS_MNT_FORCE)) return NULL; vol = ntfs_mount(device, flags); @@ -238,7 +237,7 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, } if (NVolWasDirty(vol)) { - if (!force) { + if (!(flags & NTFS_MNT_FORCE)) { ntfs_log_error("%s", dirty_volume_msg); ntfs_umount(vol, FALSE); return NULL; diff --git a/ntfsprogs/utils.h b/ntfsprogs/utils.h index 02712c82..a38f4310 100644 --- a/ntfsprogs/utils.h +++ b/ntfsprogs/utils.h @@ -56,7 +56,7 @@ ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft); int utils_valid_device(const char *name, int force); -ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force); +ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags); /** * defines... From bf3a7442eb3ac07760a3a8729af01c47dbbe899b Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 15 Sep 2007 23:03:10 +0300 Subject: [PATCH 239/289] ntfs_attr_pwrite: Write 4096 bytes blocks when possible. (David Fox, Szaka, Anton, Yura) --- libntfs/attrib.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 21d5a513..aae2e123 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1323,11 +1323,37 @@ retry: ntfs_log_trace("Writing 0x%llx bytes to vcn 0x%llx, lcn 0x%llx," " ofs 0x%llx.\n", to_write, rl->vcn, rl->lcn, ofs); - if (!NVolReadOnly(vol)) - written = ntfs_pwrite(vol->dev, (rl->lcn << - vol->cluster_size_bits) + ofs, - to_write, b); - else + if (!NVolReadOnly(vol)) { + s64 pos = (rl->lcn << vol->cluster_size_bits) + ofs; + int bsize = 4096; /* FIXME: Test whether we need + PAGE_SIZE here. Eg., on IA64. */ + /* + * Write 4096 size blocks if it's possible. This will + * cause the kernel not to seek and read disk blocks for + * filling the end of the buffer which increases write + * speed. + */ + if (vol->cluster_size >= bsize && !(ofs % bsize) && + (to_write % bsize) && ofs + to_write == + na->initialized_size) { + char *cb; + s64 rounded = (to_write + bsize - 1) & + ~(bsize - 1); + + cb = ntfs_malloc(rounded); + if (!cb) + goto err_out; + memcpy(cb, b, to_write); + memset(cb + to_write, 0, rounded - to_write); + written = ntfs_pwrite(vol->dev, pos, rounded, + cb); + if (written > to_write) + written = to_write; + free(cb); + } else + written = ntfs_pwrite(vol->dev, pos, to_write, + b); + } else written = to_write; /* If everything ok, update progress counters and continue. */ if (written > 0) { From e5690b57d489615f1f01d3184d621437a4c15077 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 16 Sep 2007 00:15:46 +0300 Subject: [PATCH 240/289] Allow mounting volumes with non-clean logfile with force mount option. Volume left dirty upon umount. So, this is equal to running ntfsfix and then mounting with force option. --- libntfs/volume.c | 13 +++++++++---- ntfsprogs/utils.c | 3 +-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libntfs/volume.c b/libntfs/volume.c index b705c924..ecf813e2 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -1219,14 +1219,20 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) * But do not do that if this is a FORENSIC mount. */ if (!(flags & NTFS_MNT_RDONLY)) { - if (ntfs_volume_check_logfile(vol) < 0) - goto error_exit; if (ntfs_volume_check_hiberfile(vol) < 0) goto error_exit; + if (ntfs_volume_check_logfile(vol) < 0) { + if (errno != EOPNOTSUPP || !(flags & NTFS_MNT_FORCE)) + goto error_exit; + ntfs_log_warning("WARNING: $LogFile is not clean, " + "forced to continue.\n"); + NVolSetWasDirty(vol); /* Leave volume dirty since we + empted logfile. */ + } if (!NVolForensicMount(vol)) { if (ntfs_logfile_reset(vol) < 0) goto error_exit; - if (!NVolWasDirty(vol)) { + if (!(vol->flags & VOLUME_IS_DIRTY)) { vol->flags |= VOLUME_IS_DIRTY; if (ntfs_volume_write_flags(vol, vol->flags) < 0) @@ -1234,7 +1240,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) } } } - return vol; io_error_exit: errno = EIO; diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index d6c7e7b7..416cf793 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -104,8 +104,7 @@ static const char *unclean_journal_msg = " C) Use 'Eject' from Windows Explorer to safely remove the device.\n" " D) If you ran chkdsk previously then boot Windows again which will\n" " automatically initialize the journal.\n" -" E) Run 'ntfsfix' on Linux which will reset the NTFS journal.\n" -" Then submit force option (WARNING: This solution it not recommended).\n" +" E) Submit 'force' option (WARNING: This solution it not recommended).\n" " F) ntfsmount: Mount the volume read-only by using the 'ro' mount option.\n"; static const char *opened_volume_msg = From d6dc40150fe5bda4471c083877c94e08c2211a15 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 18 Sep 2007 22:57:19 +0300 Subject: [PATCH 241/289] formatting --- libntfs/inode.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libntfs/inode.c b/libntfs/inode.c index d076a5b3..0e07f98c 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -671,8 +671,8 @@ int ntfs_inode_sync(ntfs_inode *ni) err = errno; if (err != EIO) err = EBUSY; - ntfs_log_trace("Attribute list sync failed (open " - "failed).\n"); + ntfs_log_trace("Attribute list sync failed " + "(open failed).\n"); } NInoAttrListSetDirty(ni); } else { @@ -684,14 +684,16 @@ int ntfs_inode_sync(ntfs_inode *ni) err = errno; if (err != EIO) err = EBUSY; - ntfs_log_trace("Attribute list sync " - "failed (write failed).\n"); + ntfs_log_trace("Attribute list " + "sync failed " + "(write).\n"); } NInoAttrListSetDirty(ni); } } else { err = EIO; - ntfs_log_trace("Attribute list sync failed (invalid size).\n"); + ntfs_log_trace("Attribute list sync failed " + "(invalid size).\n"); NInoAttrListSetDirty(ni); } ntfs_attr_close(na); From dc4e093df0349d4fba125efd6dc0e11cdf37f895 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 18 Sep 2007 23:08:21 +0300 Subject: [PATCH 242/289] Fix stupidness because of which we always wrote out MFT record on close --- libntfs/inode.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/libntfs/inode.c b/libntfs/inode.c index 0e07f98c..a18a60be 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -500,7 +500,6 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time); std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); std_info->last_access_time = utc2ntfs(ni->last_access_time); - ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); return 0; } @@ -636,17 +635,6 @@ int ntfs_inode_sync(ntfs_inode *ni) ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); - /* Update STANDARD_INFORMATION. */ - if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && - ntfs_inode_sync_standard_information(ni)) { - if (!err || errno == EIO) { - err = errno; - if (err != EIO) - err = EBUSY; - } - ntfs_log_trace("Failed to sync standard information.\n"); - } - /* Update FILE_NAME's in the index. */ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && NInoFileNameTestAndClearDirty(ni) && @@ -702,6 +690,19 @@ int ntfs_inode_sync(ntfs_inode *ni) /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ if (NInoTestAndClearDirty(ni)) { + /* Update STANDARD_INFORMATION. */ + if ((ni->mrec->flags & MFT_RECORD_IN_USE) && + ni->nr_extents != -1 && + ntfs_inode_sync_standard_information(ni)) { + if (!err || errno == EIO) { + err = errno; + if (err != EIO) + err = EBUSY; + } + ntfs_log_trace("Failed to sync standard " + "information.\n"); + } + /* Write MFT record. */ if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { if (!err || errno == EIO) { err = errno; From c0e8e211f3b047285b192046d8249246e81174f3 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 20 Sep 2007 14:00:55 +0300 Subject: [PATCH 243/289] libntfs: Cache opened inodes. --- include/ntfs/inode.h | 17 +++++++++++++++- include/ntfs/volume.h | 7 +++++++ libntfs/inode.c | 45 +++++++++++++++++++++++++++++++++++++++++-- libntfs/mft.c | 7 +++++-- libntfs/volume.c | 11 ++++++++++- 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 70d172fd..0e1b0f2d 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -27,6 +27,7 @@ /* Forward declaration */ typedef struct _ntfs_inode ntfs_inode; +#include "list.h" #include "types.h" #include "layout.h" #include "support.h" @@ -132,7 +133,7 @@ struct _ntfs_inode { /* Below fields are valid only for base inode. */ /* - * This two fields are used to sync filename index and guaranteed to be + * These two fields are used to sync filename index and guaranteed to be * correct, however value in index itself maybe wrong (windows itself * do not update them properly). */ @@ -144,12 +145,26 @@ struct _ntfs_inode { of the unnamed data attribute for sparse or compressed files.) */ + /* + * These four fields are copy of relevant fields from + * STANDARD_INFORMATION attribute and used to sync it and FILE_NAME + * attribute in the index. + */ time_t creation_time; time_t last_data_change_time; time_t last_mft_change_time; time_t last_access_time; + + /* These 2 fields are used to keep track of opened inodes. */ + struct list_head list_entry; /* Keep pointers to the next/prev list + entry. */ + int nr_references; /* How many times this inode was + opened. We really close inode only + when this reaches zero. */ }; +extern void __ntfs_inode_add_to_cache(ntfs_inode *ni); + extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol); extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref); diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index a6948af0..caad93a1 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -44,6 +44,7 @@ /* Forward declaration */ typedef struct _ntfs_volume ntfs_volume; +#include "list.h" #include "types.h" #include "support.h" #include "device.h" @@ -131,6 +132,9 @@ typedef enum { #define NTFS_BUF_SIZE 8192 +#define NTFS_INODE_CACHE_SIZE 512 /* WARNING: This should be power of 2. */ +#define NTFS_INODE_CACHE_SIZE_BITS (NTFS_INODE_CACHE_SIZE - 1) + /** * struct _ntfs_volume - structure describing an open volume in memory. */ @@ -211,6 +215,9 @@ struct _ntfs_volume { long nr_free_clusters; /* This two are self explaining. */ long nr_free_mft_records; + + struct list_head inode_cache[NTFS_INODE_CACHE_SIZE]; /* List of opened + inodes. */ }; extern ntfs_volume *ntfs_volume_alloc(void); diff --git a/libntfs/inode.c b/libntfs/inode.c index a18a60be..b21404cc 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -99,6 +99,16 @@ static int __ntfs_inode_release(ntfs_inode *ni) return 0; } +/** + * __ntfs_inode_add_to_cache - do not use me! Only for internal library use. + */ +void __ntfs_inode_add_to_cache(ntfs_inode *ni) +{ + list_add_tail(&ni->list_entry, &ni->vol->inode_cache[ + ni->mft_no & NTFS_INODE_CACHE_SIZE_BITS]); + ni->nr_references = 1; +} + /** * ntfs_inode_open - open an inode ready for access * @vol: volume to get the inode from @@ -129,12 +139,27 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) ntfs_attr_search_ctx *ctx; int err = 0; STANDARD_INFORMATION *std_info; + struct list_head *pos; ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref)); if (!vol) { errno = EINVAL; return NULL; } + /* Check cache, maybe this inode already opened? */ + list_for_each(pos, &vol->inode_cache[MREF(mref) & + NTFS_INODE_CACHE_SIZE_BITS]) { + ntfs_inode *tmp_ni; + + tmp_ni = list_entry(pos, ntfs_inode, list_entry); + if (tmp_ni->mft_no == MREF(mref)) { + ntfs_log_trace("Found this inode in cache, increment " + "reference count and return it.\n"); + tmp_ni->nr_references++; + return tmp_ni; + } + } + /* Search failed. Properly open inode. */ ni = __ntfs_inode_allocate(vol); if (!ni) return NULL; @@ -212,6 +237,7 @@ get_size: } } ntfs_attr_put_search_ctx(ctx); + __ntfs_inode_add_to_cache(ni); return ni; put_err_out: if (!err) @@ -254,6 +280,18 @@ int ntfs_inode_close(ntfs_inode *ni) ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); + /* Decrement number of users. If there are left then just return. */ + if (ni->nr_extents != -1) { + ni->nr_references--; + if (ni->nr_references) { + ntfs_log_trace("There are %d more references left to " + "this inode.\n", + ni->nr_references); + return 0; + } else + ntfs_log_trace("There are no more references left to " + "this inode.\n"); + } /* If we have dirty metadata, write it out. */ if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if (ntfs_inode_sync(ni)) { @@ -312,9 +350,12 @@ int ntfs_inode_close(ntfs_inode *ni) break; } if (i != -1) - ntfs_log_debug("Extent inode was not attached to base inode! " - "Weird! Continuing regardless.\n"); + ntfs_log_debug("Extent inode was not attached to base " + "inode! Continuing regardless.\n"); } + /* Remove inode from the list of opened inodes. */ + if (ni->nr_extents != -1) + list_del(&ni->list_entry); return __ntfs_inode_release(ni); } diff --git a/libntfs/mft.c b/libntfs/mft.c index c0a3cae4..29e059a4 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -1460,9 +1460,12 @@ mft_rec_already_initialized: ni->creation_time = ni->last_data_change_time = ni->last_mft_change_time = ni->last_access_time = time(NULL); - /* Update the default mft allocation position if it was used. */ - if (!base_ni) + if (!base_ni) { + /* Update the default mft allocation position if it was used. */ vol->mft_data_pos = bit + 1; + /* Add inode to cache. */ + __ntfs_inode_add_to_cache(ni); + } /* Return the opened, allocated inode of the allocated mft record. */ ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n", base_ni ? "extent " : "", (long long)bit); diff --git a/libntfs/volume.c b/libntfs/volume.c index ecf813e2..24fb9369 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -76,7 +76,15 @@ */ ntfs_volume *ntfs_volume_alloc(void) { - return calloc(1, sizeof(ntfs_volume)); + ntfs_volume *vol; + int i; + + vol = calloc(1, sizeof(ntfs_volume)); + if (vol) { + for (i = 0; i < NTFS_INODE_CACHE_SIZE; i++) + INIT_LIST_HEAD(&vol->inode_cache[i]); + } + return vol; } /** @@ -162,6 +170,7 @@ static int ntfs_mft_load(ntfs_volume *vol) } vol->mft_ni->mft_no = 0; vol->mft_ni->mrec = mb; + __ntfs_inode_add_to_cache(vol->mft_ni); /* Can't use any of the higher level functions yet! */ l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1, vol->mft_record_size, mb); From 038fea1b5b91d8e0893536ea74889306dbcbc08a Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 20 Sep 2007 14:21:28 +0300 Subject: [PATCH 244/289] Cleanup We calloc() buffer for attribute, but better always set na->crypto to NULL explicitly just for any case --- libntfs/crypto.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libntfs/crypto.c b/libntfs/crypto.c index 1a1b3468..688716db 100644 --- a/libntfs/crypto.c +++ b/libntfs/crypto.c @@ -1349,11 +1349,11 @@ int ntfs_crypto_attr_open(ntfs_attr *na) ntfs_fek *fek; int i; + na->crypto = NULL; if (!na || !NAttrEncrypted(na)) { errno = EINVAL; return -1; } - if (ntfs_crypto_init()) { errno = EACCES; return -1; @@ -1370,7 +1370,6 @@ int ntfs_crypto_attr_open(ntfs_attr *na) } } - na->crypto = NULL; errno = EACCES; return -1; } From 673c23d74a385193d91355c0218f04d4ff487e97 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 20 Sep 2007 15:35:02 +0300 Subject: [PATCH 245/289] libntfs: Cache opened attributes. --- include/ntfs/attrib.h | 3 +++ include/ntfs/inode.h | 2 ++ libntfs/attrib.c | 26 ++++++++++++++++++++++++++ libntfs/inode.c | 9 ++++++++- 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index bb911338..b20e0ffd 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -27,6 +27,7 @@ typedef struct _ntfs_attr ntfs_attr; typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx; +#include "list.h" #include "types.h" #include "inode.h" #include "unistr.h" @@ -195,6 +196,8 @@ struct _ntfs_attr { u8 compression_block_size_bits; u8 compression_block_clusters; ntfs_crypto_attr *crypto; + struct list_head list_entry; + int nr_references; }; /** diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 0e1b0f2d..8fb907ab 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -161,6 +161,8 @@ struct _ntfs_inode { int nr_references; /* How many times this inode was opened. We really close inode only when this reaches zero. */ + + struct list_head attr_cache; /* List of opened attributes. */ }; extern void __ntfs_inode_add_to_cache(ntfs_inode *ni); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index aae2e123..a1fe9545 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -354,6 +354,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, ntfs_attr_search_ctx *ctx; ntfs_attr *na; ATTR_RECORD *a; + struct list_head *pos; int err; BOOL cs; @@ -363,6 +364,21 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, errno = EINVAL; return NULL; } + /* Check cache, maybe this attribute already opened? */ + list_for_each(pos, &ni->attr_cache) { + ntfs_attr *tmp_na; + + tmp_na = list_entry(pos, ntfs_attr, list_entry); + if (tmp_na->type == type && tmp_na->name_len == name_len && + !ntfs_ucsncmp(tmp_na->name, name, name_len)) { + ntfs_log_trace("Found this attribute in cache, " + "increment reference count and " + "return it.\n"); + tmp_na->nr_references++; + return tmp_na; + } + } + /* Search failed. Properly open attrbute. */ na = calloc(sizeof(ntfs_attr), 1); if (!na) return NULL; @@ -429,6 +445,8 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, ntfs_attr_put_search_ctx(ctx); if (NAttrEncrypted(na)) ntfs_crypto_attr_open(na); + list_add_tail(&na->list_entry, &ni->attr_cache); + na->nr_references = 1; return na; put_err_out: ntfs_attr_put_search_ctx(ctx); @@ -449,6 +467,14 @@ void ntfs_attr_close(ntfs_attr *na) { if (!na) return; + na->nr_references--; + if (na->nr_references) { + ntfs_log_trace("There are %d more references left to " + "this attribute.\n", na->nr_references); + return; + } + ntfs_log_trace("There are no more references left to this attribute\n"); + list_del(&na->list_entry); if (NAttrEncrypted(na)) ntfs_crypto_attr_close(na); if (NAttrNonResident(na) && na->rl) diff --git a/libntfs/inode.c b/libntfs/inode.c index b21404cc..712cfd13 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -62,8 +62,10 @@ static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) ntfs_inode *ni; ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode)); - if (ni) + if (ni) { ni->vol = vol; + INIT_LIST_HEAD(&ni->attr_cache); + } return ni; } @@ -292,6 +294,11 @@ int ntfs_inode_close(ntfs_inode *ni) ntfs_log_trace("There are no more references left to " "this inode.\n"); } + /* Check whether all attributes of this inode are closed. */ + if (!list_empty(&ni->attr_cache)) + ntfs_log_error("%s(): Not all attributes are closed. " + "We definitely have memory leak. " + "Continue anyway.\n", __FUNCTION__); /* If we have dirty metadata, write it out. */ if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if (ntfs_inode_sync(ni)) { From 5151f826c4e75a907ecc9761105e538beddb1720 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 20 Sep 2007 15:46:31 +0300 Subject: [PATCH 246/289] ntfsmount: Save pointer to ntfs_attr in (fuse_file_info *)->fh and use it in ntfs_fuse_{read,write} --- ntfsprogs/ntfsmount.c | 106 ++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 62 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 9d88a73b..611f41af 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -534,11 +534,10 @@ static int ntfs_fuse_readdir(const char *path, void *buf, return err; } -static int ntfs_fuse_open(const char *org_path, - struct fuse_file_info *fi __attribute__((unused))) +static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi) { - ntfs_inode *ni; - ntfs_attr *na; + ntfs_inode *ni = NULL; + ntfs_attr *na = NULL; int res = 0; char *path = NULL; ntfschar *stream_name; @@ -553,42 +552,53 @@ static int ntfs_fuse_open(const char *org_path, if (na) { if (NAttrEncrypted(na) && !na->crypto) res = -EACCES; - ntfs_attr_close(na); } else res = -errno; - ntfs_inode_close(ni); } else res = -errno; free(path); if (stream_name_len) free(stream_name); + if (res) { + if (ni) + ntfs_inode_close(ni); + if (na) + ntfs_attr_close(na); + } else + fi->fh = (unsigned long)na; return res; } -static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, - off_t offset, struct fuse_file_info *fi __attribute__((unused))) +static int ntfs_fuse_flush(const char *path __attribute__((unused)), + struct fuse_file_info *fi) { - ntfs_inode *ni = NULL; - ntfs_attr *na = NULL; - char *path = NULL; - ntfschar *stream_name; - int stream_name_len, res, total = 0; + ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + ntfs_inode *ni = na->ni; + + if (ntfs_inode_sync(ni)) + return -errno; + return 0; +} + +static int ntfs_fuse_release(const char *path __attribute__((unused)), + struct fuse_file_info *fi) +{ + ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + ntfs_inode *ni = na->ni; + + ntfs_attr_close(na); + ntfs_inode_close(ni); + return 0; +} + +static int ntfs_fuse_read(const char *path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) +{ + ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + int res, total = 0; if (!size) return 0; - stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); - if (stream_name_len < 0) - return stream_name_len; - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); - if (!ni) { - res = -errno; - goto exit; - } - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (!na) { - res = -errno; - goto exit; - } if (offset + size > na->data_size) size = na->data_size - offset; while (size) { @@ -607,40 +617,17 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size, total += res; } res = total; - ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME); exit: - if (na) - ntfs_attr_close(na); - if (ni && ntfs_inode_close(ni)) - ntfs_log_perror("Failed to close inode"); - free(path); - if (stream_name_len) - free(stream_name); return res; } -static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi __attribute__((unused))) +static int ntfs_fuse_write(const char *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) { - ntfs_inode *ni = NULL; - ntfs_attr *na = NULL; - char *path = NULL; - ntfschar *stream_name; - int stream_name_len, res, total = 0; + ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + int res, total = 0; - stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); - if (stream_name_len < 0) - return stream_name_len; - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); - if (!ni) { - res = -errno; - goto exit; - } - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (!na) { - res = -errno; - goto exit; - } while (size) { res = ntfs_attr_pwrite(na, offset, size, buf); if (res < (s64)size && errno != ENOSPC) @@ -659,15 +646,8 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size, res = total; exit: if (res > 0) - ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME | + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME); - if (na) - ntfs_attr_close(na); - if (ni && ntfs_inode_close(ni)) - ntfs_log_perror("Failed to close inode"); - free(path); - if (stream_name_len) - free(stream_name); return res; } @@ -1423,6 +1403,8 @@ static struct fuse_operations ntfs_fuse_oper = { .readlink = ntfs_fuse_readlink, .readdir = ntfs_fuse_readdir, .open = ntfs_fuse_open, + .flush = ntfs_fuse_flush, + .release = ntfs_fuse_release, .read = ntfs_fuse_read, .write = ntfs_fuse_write, .truncate = ntfs_fuse_truncate, From d1a70067988af60b4fdf052f33656e74d61d5dc3 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 21 Sep 2007 15:51:50 +0300 Subject: [PATCH 247/289] ntfsmount: Introduce macro NTFS_FUSE_GET_NA for receiving ntfs_attr* from fuse_file_info* --- ntfsprogs/ntfsmount.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 611f41af..cb22f1c1 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -81,6 +81,9 @@ #define PATH_MAX 4096 #endif +#define NTFS_FUSE_GET_NA(fi) \ + ntfs_attr *na = (ntfs_attr *)(uintptr_t)(fi)->fh + typedef struct { fuse_fill_dir_t filler; void *buf; @@ -565,17 +568,16 @@ static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi) if (na) ntfs_attr_close(na); } else - fi->fh = (unsigned long)na; + fi->fh = (uintptr_t)na; return res; } static int ntfs_fuse_flush(const char *path __attribute__((unused)), struct fuse_file_info *fi) { - ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; - ntfs_inode *ni = na->ni; + NTFS_FUSE_GET_NA(fi); - if (ntfs_inode_sync(ni)) + if (ntfs_inode_sync(na->ni)) return -errno; return 0; } @@ -583,7 +585,7 @@ static int ntfs_fuse_flush(const char *path __attribute__((unused)), static int ntfs_fuse_release(const char *path __attribute__((unused)), struct fuse_file_info *fi) { - ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + NTFS_FUSE_GET_NA(fi); ntfs_inode *ni = na->ni; ntfs_attr_close(na); @@ -594,7 +596,7 @@ static int ntfs_fuse_release(const char *path __attribute__((unused)), static int ntfs_fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + NTFS_FUSE_GET_NA(fi); int res, total = 0; if (!size) @@ -625,7 +627,7 @@ exit: static int ntfs_fuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - ntfs_attr *na = (ntfs_attr *)(unsigned long)fi->fh; + NTFS_FUSE_GET_NA(fi); int res, total = 0; while (size) { From 3f8abbf2ca2b5e546a109e78f174e558180e4df6 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 21 Sep 2007 17:40:22 +0300 Subject: [PATCH 248/289] ntfsmount: Implement .create() --- ntfsprogs/ntfsmount.c | 87 ++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index cb22f1c1..aaf42181 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -716,8 +716,8 @@ static int ntfs_fuse_chown(const char *path, uid_t uid __attribute__((unused)), return -EOPNOTSUPP; } -static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, - const char *target) +static int __ntfs_fuse_mknod(const char *org_path, dev_t type, dev_t dev, + const char *target, ntfs_inode **_ni) { char *name; ntfschar *uname = NULL, *utarget = NULL; @@ -725,6 +725,8 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, char *path; int res = 0, uname_len, utarget_len; + if (_ni) + *_ni = NULL; path = strdup(org_path); if (!path) return -errno; @@ -766,7 +768,10 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, break; } if (ni) { - ntfs_inode_close(ni); + if (_ni) + *_ni = ni; + else + ntfs_inode_close(ni); ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_CTIME | NTFS_UPDATE_MTIME); } else @@ -781,43 +786,46 @@ exit: return res; } -static int ntfs_fuse_create_stream(const char *path, - ntfschar *stream_name, const int stream_name_len) +static int ntfs_fuse_create_stream(const char *path, ntfschar *stream_name, + const int stream_name_len, ntfs_inode **_ni) { ntfs_inode *ni; int res = 0; + if (_ni) + *_ni = NULL; ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) { res = -errno; - if (res == -ENOENT) { - /* - * If such file does not exist, create it and try once - * again to add stream to it. - */ - res = ntfs_fuse_create(path, S_IFREG, 0, NULL); - if (!res) - return ntfs_fuse_create_stream(path, - stream_name, stream_name_len); - else - res = -errno; - } - return res; + if (res == -ENOENT) + res = __ntfs_fuse_mknod(path, S_IFREG, 0, NULL, &ni); + if (!res && !ni) + res = -EIO; + if (res) + return res; } if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0)) res = -errno; - if (ntfs_inode_close(ni)) - ntfs_log_perror("Failed to close inode"); + if (_ni) + *_ni = ni; + else { + if (ntfs_inode_close(ni)) + ntfs_log_perror("Failed to close inode"); + } return res; } -static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev) +static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev, + ntfs_attr **na) { char *path = NULL; ntfschar *stream_name; int stream_name_len; int res = 0; + ntfs_inode *ni; + if (na) + *na = NULL; stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; @@ -826,10 +834,22 @@ static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev) goto exit; } if (!stream_name_len) - res = ntfs_fuse_create(path, mode & S_IFMT, dev, NULL); + res = __ntfs_fuse_mknod(path, mode & S_IFMT, dev, NULL, + na ? &ni : NULL); else res = ntfs_fuse_create_stream(path, stream_name, - stream_name_len); + stream_name_len, na ? &ni : NULL); + if (na && !res) { + if (ni) { + *na = ntfs_attr_open(ni, AT_DATA, stream_name, + stream_name_len); + if (!*na) { + ntfs_inode_close(ni); + res = -EIO; + } + } else + res = -EIO; + } exit: free(path); if (stream_name_len) @@ -837,11 +857,27 @@ exit: return res; } +static int ntfs_fuse_mknod(const char *path, mode_t mode, dev_t dev) +{ + return ntfs_fuse_mknod_common(path, mode, dev, NULL); +} + +static int ntfs_fuse_create(const char *path, mode_t mode, + struct fuse_file_info *fi) +{ + ntfs_attr *na; + int res; + + res = ntfs_fuse_mknod_common(path, mode, 0, &na); + fi->fh = (uintptr_t)na; + return res; +} + static int ntfs_fuse_symlink(const char *to, const char *from) { if (ntfs_fuse_is_named_data_stream(from)) return -EINVAL; /* n/a for named data streams. */ - return ntfs_fuse_create(from, S_IFLNK, 0, to); + return __ntfs_fuse_mknod(from, S_IFLNK, 0, to, NULL); } static int ntfs_fuse_link(const char *old_path, const char *new_path) @@ -1041,7 +1077,7 @@ static int ntfs_fuse_mkdir(const char *path, { if (ntfs_fuse_is_named_data_stream(path)) return -EINVAL; /* n/a for named data streams. */ - return ntfs_fuse_create(path, S_IFDIR, 0, NULL); + return __ntfs_fuse_mknod(path, S_IFDIR, 0, NULL, NULL); } static int ntfs_fuse_rmdir(const char *path) @@ -1414,6 +1450,7 @@ static struct fuse_operations ntfs_fuse_oper = { .chmod = ntfs_fuse_chmod, .chown = ntfs_fuse_chown, .mknod = ntfs_fuse_mknod, + .create = ntfs_fuse_create, .symlink = ntfs_fuse_symlink, .link = ntfs_fuse_link, .unlink = ntfs_fuse_unlink, From 36af29fe721aabe7ced8ef01dcab3ffc53c047eb Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 21 Sep 2007 17:50:40 +0300 Subject: [PATCH 249/289] ntfsmount: Implement .ftruncate() --- ntfsprogs/ntfsmount.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index aaf42181..7c9ebe04 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -696,6 +696,19 @@ exit: return res; } +static int ntfs_fuse_ftruncate(const char *path __attribute__((unused)), + off_t size, struct fuse_file_info *fi) +{ + NTFS_FUSE_GET_NA(fi); + + if (na->data_size == size) + return 0; + if (ntfs_attr_truncate(na, size)) + return -errno; + ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MTIME | NTFS_UPDATE_CTIME); + return 0; +} + static int ntfs_fuse_chmod(const char *path, mode_t mode __attribute__((unused))) { @@ -1446,6 +1459,7 @@ static struct fuse_operations ntfs_fuse_oper = { .read = ntfs_fuse_read, .write = ntfs_fuse_write, .truncate = ntfs_fuse_truncate, + .ftruncate = ntfs_fuse_ftruncate, .statfs = ntfs_fuse_statfs, .chmod = ntfs_fuse_chmod, .chown = ntfs_fuse_chown, From 4f7f0f654e7aefacb3d20401df56ccf0b471facc Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 21 Sep 2007 17:58:07 +0300 Subject: [PATCH 250/289] ntfsmount: Implement .fgetattr() --- ntfsprogs/ntfsmount.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 7c9ebe04..766f5c6c 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -408,6 +408,28 @@ exit: return res; } +static int ntfs_fuse_fgetattr(const char *path __attribute__((unused)), + struct stat *stbuf, struct fuse_file_info *fi) +{ + NTFS_FUSE_GET_NA(fi); + ntfs_inode *ni = na->ni; + + stbuf->st_ino = ni->mft_no; + stbuf->st_mode = S_IFREG | (0777 & ~ctx->fmask); + stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); + stbuf->st_uid = ctx->uid; + stbuf->st_gid = ctx->gid; + stbuf->st_atime = ni->last_access_time; + stbuf->st_ctime = ni->last_mft_change_time; + stbuf->st_mtime = ni->last_data_change_time; + if (NAttrNonResident(na)) + stbuf->st_blocks = na->allocated_size >> 9; + else + stbuf->st_blocks = 0; + stbuf->st_size = na->data_size; + return 0; +} + static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) { char *path; @@ -1451,6 +1473,7 @@ static void ntfs_fuse_destroy(void *priv __attribute__((unused))) static struct fuse_operations ntfs_fuse_oper = { .getattr = ntfs_fuse_getattr, + .fgetattr = ntfs_fuse_fgetattr, .readlink = ntfs_fuse_readlink, .readdir = ntfs_fuse_readdir, .open = ntfs_fuse_open, From dcf72f1315af53f0ecaaaabf783722769d74a760 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 21 Sep 2007 18:43:05 +0300 Subject: [PATCH 251/289] ntfs_inode_close: Document that @ni can be NULL. --- libntfs/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libntfs/inode.c b/libntfs/inode.c index 712cfd13..87f08464 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -266,6 +266,8 @@ err_out: * If it is an extent inode, we disconnect it from its base inode before we * destroy it. * + * It is OK to pass NULL to this function, it is just noop in this case. + * * Return 0 on success or -1 on error with errno set to the error code. On * error, @ni has not been freed. The user should attempt to handle the error * and call ntfs_inode_close() again. The following error codes are defined: From d788fc6591868d40f6960b062012670cfc157fdd Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 22 Sep 2007 18:29:16 +0300 Subject: [PATCH 252/289] Update TODO* files a bit --- TODO.libntfs | 28 ++++++++++------------------ TODO.ntfsprogs | 2 -- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/TODO.libntfs b/TODO.libntfs index 6183520d..73981b03 100644 --- a/TODO.libntfs +++ b/TODO.libntfs @@ -1,10 +1,3 @@ -******************** -* libntfs-gnomevfs * -******************** - -- be generic filter: provide ntfs_device_operations from parent GnomeVFSHandle - - *********** * libntfs * *********** @@ -13,13 +6,7 @@ * HIGH priority * ***************** -- complete ntfs_index_{add_filename,rm} - -- move ntfsdecrypt to library. - -- complete the implementation of ntfs_attr_truncate() (for compressed files) - -- add write of compressed attributes +- Make ntfs_attr_{truncate,pwrite} work for compressed/encrypted attributes - detect presence of usnjrnl and if present and mounting rw, re-stamp it (see current ntfs driver for example in 2.6.15 kernel) @@ -53,10 +40,6 @@ * LOW priority * **************** -- Do we attach attributes (ntfs_attr) to the corresponding ntfs_inode? Now we - just atach the inode to the attribute and expect the user to not shoot - themselves in the foot. - - add ACL read/write support to library - add MS BackupAPI to library @@ -66,3 +49,12 @@ - add defrag API to library - write utilities for all of the above + + + +******************** +* libntfs-gnomevfs * +******************** + +- be generic filter: provide ntfs_device_operations from parent GnomeVFSHandle + diff --git a/TODO.ntfsprogs b/TODO.ntfsprogs index 456794b7..71149329 100644 --- a/TODO.ntfsprogs +++ b/TODO.ntfsprogs @@ -65,7 +65,6 @@ Thanks, ********** - add ability to copy multiply files at once. -- add ability to create new files. *********** @@ -93,7 +92,6 @@ Thanks, * ntfsmount * ************* -- Cache opened inodes for faster access. ************** From 72ae9ade7e011e56f429e9f593a25fe956964211 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 22 Sep 2007 23:19:09 +0300 Subject: [PATCH 253/289] ntfs_delete: Add sanity check for case when user tries to delete inode with several references --- libntfs/dir.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libntfs/dir.c b/libntfs/dir.c index 124bb860..b2e0763b 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1453,6 +1453,12 @@ int ntfs_delete(ntfs_inode **pni, ntfs_inode *dir_ni, ntfschar *name, errno = EINVAL; goto err_out; } + if (ni->nr_references > 1 && le16_to_cpu(ni->mrec->link_count) == 1) { + ntfs_log_error("Trying to deleting inode with left " + "references.\n"); + errno = EINVAL; + goto err_out; + } /* * Search for FILE_NAME attribute with such name. If it's in POSIX or * WIN32_AND_DOS namespace, then simply remove it from index and inode. @@ -1546,6 +1552,14 @@ search: } ntfs_attr_close(na); } + /* One more sanity check. */ + if (ni->nr_references > 1 && looking_for_dos_name && + le16_to_cpu(ni->mrec->link_count) == 2) { + ntfs_log_error("Trying to deleting inode with left " + "references.\n"); + errno = EINVAL; + goto err_out; + } ntfs_log_trace("Found!\n"); /* Search for such FILE_NAME in index. */ ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); From 36b8f621f9be6a11dc3e0a5774c7c67c6517fa36 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 23 Sep 2007 00:36:18 +0300 Subject: [PATCH 254/289] libntfs: Sync and warn about not closed inodes in ntfs_umount --- libntfs/volume.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libntfs/volume.c b/libntfs/volume.c index 24fb9369..6d1064ae 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -97,6 +97,30 @@ ntfs_volume *ntfs_volume_alloc(void) */ static void __ntfs_volume_release(ntfs_volume *v) { + struct list_head *pos, *tmp; + int i; + + /* Sync and print error about not detached inodes. */ + for (i = 0; i < NTFS_INODE_CACHE_SIZE; i++) + list_for_each_safe(pos, tmp, &v->inode_cache[i]) { + ntfs_inode *ni = + list_entry(pos, ntfs_inode, list_entry); + + switch (ni->mft_no) { + case FILE_Volume: + case FILE_Bitmap: + case FILE_MFT: + case FILE_MFTMirr: + if (ni->nr_references == 1) + continue; + break; + } + + ntfs_log_error("%s(): Inode %llu still have %d " + "references.\n", __FUNCTION__, + ni->mft_no, ni->nr_references); + ntfs_inode_sync(ni); + } /* * Clear the dirty bit if it was not set before we mounted and this is * not a forensic mount. From 42f475f5527b6f56aa49d6107259c3b5bcd13cf3 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 23 Sep 2007 00:37:49 +0300 Subject: [PATCH 255/289] ntfsmount: Cache directory in which was performed last operation --- ntfsprogs/ntfsmount.c | 102 +++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 21 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 766f5c6c..cf5eb4b5 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -117,6 +117,9 @@ typedef struct { BOOL noatime; BOOL relatime; BOOL blkdev; + char cached_path[PATH_MAX]; + ntfs_inode *cached_ni; + ntfs_inode *root_ni; } ntfs_fuse_context_t; #define NTFS_FUSE_OPT(t, p) { t, offsetof(ntfs_fuse_context_t, p), TRUE } @@ -287,6 +290,68 @@ static int ntfs_fuse_parse_path(const char *org_path, char **path, return 0; } +/** + * ntfs_fuse_cache_get_dir + * + * WARNING: Do not close inodes obtained with this function. They will be closed + * automatically upon to next call to this function with different path or in + * .destroy(). + */ +static ntfs_inode *ntfs_fuse_cache_get_dir(const char *path) +{ + ntfs_inode *ni; + + if (!*path) + path = "/"; + + if (ctx->cached_ni && !strcmp(ctx->cached_path, path)) { + ntfs_log_trace("Got '%s' from cache.\n", path); + return ctx->cached_ni; + } + + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + if (!ni) + return NULL; + ntfs_inode_close(ctx->cached_ni); + ctx->cached_ni = ni; + strncpy(ctx->cached_path, path, sizeof(ctx->cached_path)); + if (ctx->cached_path[sizeof(ctx->cached_path) - 1]) { + /* Path was truncated, invalidate it since we can not use it. */ + ctx->cached_path[sizeof(ctx->cached_path) - 1] = 0; + *ctx->cached_path = 0; + } + ntfs_log_trace("Cached '%s'.\n", path); + return ni; +} + +/** + * ntfs_fuse_cache_get_file + * + * WARNING: This function changes @path during execution, but restores it + * original value upon exit. Do *NOT* pass constant strings to this function! + * + * WARNING: You should close inode obtained with this function vice-versa to + * inodes obtained with ntfs_fuse_cache_get_dir(). + */ +static ntfs_inode *ntfs_fuse_cache_get_file(char *path) +{ + ntfs_inode *dir_ni; + char *file; + + file = strrchr(path, '/'); + if (file == path) + return ntfs_pathname_to_inode(ctx->vol, NULL, file); + *file = 0; + dir_ni = ntfs_fuse_cache_get_dir(path); + *file = '/'; + file++; + + if (dir_ni) + return ntfs_pathname_to_inode(ctx->vol, dir_ni, file); + else + return NULL; +} + static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) { int res = 0; @@ -300,7 +365,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) if (stream_name_len < 0) return stream_name_len; memset(stbuf, 0, sizeof(struct stat)); - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_file(path); if (!ni) { res = -ENOENT; goto exit; @@ -447,7 +512,7 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size) res = -EINVAL; goto exit; } - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_file(path); if (!ni) { res = -errno; goto exit; @@ -548,14 +613,13 @@ static int ntfs_fuse_readdir(const char *path, void *buf, fill_ctx.filler = filler; fill_ctx.buf = buf; - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_dir(path); if (!ni) return -errno; if (ntfs_readdir(ni, &pos, &fill_ctx, (ntfs_filldir_t)ntfs_fuse_filler)) err = -errno; ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); - ntfs_inode_close(ni); return err; } @@ -571,7 +635,7 @@ static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi) stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_file(path); if (ni) { na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (na) { @@ -585,10 +649,8 @@ static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi) if (stream_name_len) free(stream_name); if (res) { - if (ni) - ntfs_inode_close(ni); - if (na) - ntfs_attr_close(na); + ntfs_inode_close(ni); + ntfs_attr_close(na); } else fi->fh = (uintptr_t)na; return res; @@ -687,7 +749,7 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size) stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name); if (stream_name_len < 0) return stream_name_len; - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_file(path); if (!ni) { res = -errno; goto exit; @@ -767,6 +829,7 @@ static int __ntfs_fuse_mknod(const char *org_path, dev_t type, dev_t dev, return -errno; /* Generate unicode filename. */ name = strrchr(path, '/'); + *name = 0; name++; uname_len = ntfs_mbstoucs(name, &uname, 0); if (uname_len < 0) { @@ -774,8 +837,7 @@ static int __ntfs_fuse_mknod(const char *org_path, dev_t type, dev_t dev, goto exit; } /* Open parent directory. */ - *name = 0; - dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + dir_ni = ntfs_fuse_cache_get_dir(path); if (!dir_ni) { res = -errno; if (res == -ENOENT) @@ -813,8 +875,6 @@ static int __ntfs_fuse_mknod(const char *org_path, dev_t type, dev_t dev, res = -errno; exit: free(uname); - if (dir_ni) - ntfs_inode_close(dir_ni); if (utarget) free(utarget); free(path); @@ -983,13 +1043,14 @@ static int ntfs_fuse_rm(const char *org_path) if (!path) return -errno; /* Open object for delete. */ - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + ni = ntfs_fuse_cache_get_file(path); if (!ni) { res = -errno; goto exit; } /* Generate unicode filename. */ name = strrchr(path, '/'); + *name = 0; name++; uname_len = ntfs_mbstoucs(name, &uname, 0); if (uname_len < 0) { @@ -997,8 +1058,7 @@ static int ntfs_fuse_rm(const char *org_path) goto exit; } /* Open parent directory. */ - *name = 0; - dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + dir_ni = ntfs_fuse_cache_get_dir(path); if (!dir_ni) { res = -errno; if (res == -ENOENT) @@ -1015,11 +1075,8 @@ static int ntfs_fuse_rm(const char *org_path) NTFS_UPDATE_MTIME); } exit: - if (ni) - ntfs_inode_close(ni); + ntfs_inode_close(ni); free(uname); - if (dir_ni) - ntfs_inode_close(dir_ni); free(path); return res; } @@ -1460,6 +1517,8 @@ exit: static void ntfs_fuse_destroy(void *priv __attribute__((unused))) { if (ctx->vol) { + ntfs_inode_close(ctx->cached_ni); + ntfs_inode_close(ctx->root_ni); ntfs_log_info("Unmounting %s (%s)\n", ctx->device, ctx->vol->vol_name); if (ntfs_umount(ctx->vol, FALSE)) @@ -1727,6 +1786,7 @@ static int ntfs_fuse_mount(void) return -1; } ctx->vol = vol; + ctx->root_ni = ntfs_inode_open(vol, FILE_root); return 0; } From a81520731cbee019abf5838f450f9c275b80896c Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sun, 23 Sep 2007 00:50:45 +0300 Subject: [PATCH 256/289] Install mount.fuse.ntfs symlink (to match mount with subtype=ntfs option) --- ntfsprogs/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index ef6016f9..8e44e2fd 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -148,6 +148,7 @@ install-exec-hook: $(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs if ENABLE_FUSE $(LN_S) -f $(bindir)/ntfsmount $(DESTDIR)/sbin/mount.ntfs-fuse + $(LN_S) -f $(bindir)/ntfsmount $(DESTDIR)/sbin/mount.fuse.ntfs endif install-data-hook: @@ -155,6 +156,7 @@ install-data-hook: $(LN_S) -f mkntfs.8 $(DESTDIR)$(man8dir)/mkfs.ntfs.8 if ENABLE_FUSE $(LN_S) -f ntfsmount.8 $(DESTDIR)$(man8dir)/mount.ntfs-fuse.8 + $(LN_S) -f ntfsmount.8 $(DESTDIR)$(man8dir)/mount.fuse.ntfs.8 endif uninstall-local: @@ -162,5 +164,7 @@ uninstall-local: $(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8 if ENABLE_FUSE $(RM) -f $(DESTDIR)/sbin/mount.ntfs-fuse + $(RM) -f $(DESTDIR)/sbin/mount.fuse.ntfs $(RM) -f $(DESTDIR)$(man8dir)/mount.ntfs-fuse.8 + $(RM) -f $(DESTDIR)$(man8dir)/mount.fuse.ntfs.8 endif From 1b5fb2693cc59c071edb627ee2d952e83d473543 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 24 Sep 2007 19:21:16 +0300 Subject: [PATCH 257/289] Introduce NTFS_ON_DEBUG macro to add one-liners which would be executed only if DEBUG is defined. And use it to shut up valgrind crying about writing of unitialized buffer (we do not initialize part of attribute list left for padding) --- include/ntfs/debug.h | 2 ++ libntfs/attrlist.c | 4 ++-- libntfs/inode.c | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/ntfs/debug.h b/include/ntfs/debug.h index bf456f12..e46c8559 100644 --- a/include/ntfs/debug.h +++ b/include/ntfs/debug.h @@ -32,8 +32,10 @@ struct _runlist_element; #ifndef DEBUG static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {} +#define NTFS_ON_DEBUG(x) #else extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl); +#define NTFS_ON_DEBUG(x) (x) #endif #define NTFS_BUG(msg) \ diff --git a/libntfs/attrlist.c b/libntfs/attrlist.c index ce171bf9..33b56062 100644 --- a/libntfs/attrlist.c +++ b/libntfs/attrlist.c @@ -185,8 +185,6 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) entry_offset = ((u8 *)ale - ni->attr_list); /* Set pointer to new entry. */ ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset); - /* Zero it to fix valgrind warning. */ - memset(ale, 0, entry_len); /* Form new entry. */ ale->type = attr->type; ale->length = cpu_to_le16(entry_len); @@ -198,6 +196,8 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) ale->lowest_vcn = 0; ale->mft_reference = mref; ale->instance = attr->instance; + NTFS_ON_DEBUG(memset(ale->name, 0, ((u8*)((u8*)ale + entry_len)) - + ((u8*)ale->name))); /* Shut up, valgrind. */ memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset), attr->name_length * sizeof(ntfschar)); diff --git a/libntfs/inode.c b/libntfs/inode.c index 87f08464..6e1681d4 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -831,6 +831,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) al_allocated = 0x40; al_len = 0; al = malloc(al_allocated); + NTFS_ON_DEBUG(memset(al, 0, 0x40)); /* Valgrind. */ ale = (ATTR_LIST_ENTRY *) al; if (!al) { ntfs_log_trace("Not enough memory.\n"); @@ -849,7 +850,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { if (ctx->attr->type == AT_ATTRIBUTE_LIST) { err = EIO; - ntfs_log_trace("Eeek! Attribute list already present.\n"); + ntfs_log_trace("Attribute list already present.\n"); goto put_err_out; } /* Calculate new length of attribute list. */ @@ -859,6 +860,8 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) while (al_len > al_allocated) { al_allocated += 0x40; aln = realloc(al, al_allocated); + NTFS_ON_DEBUG(memset(aln + al_allocated - 0x40, 0, + 0x40)); /* Valgrind. */ if (!aln) { ntfs_log_trace("Not enough memory.\n"); err = ENOMEM; From ad8097aa5564ef8efaa70c32a770ea44daf39a36 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 24 Sep 2007 20:27:41 +0300 Subject: [PATCH 258/289] ntfsmount: minor memory managment fix --- ntfsprogs/ntfsmount.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index cf5eb4b5..a8525ad9 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1524,12 +1524,22 @@ static void ntfs_fuse_destroy(void *priv __attribute__((unused))) if (ntfs_umount(ctx->vol, FALSE)) ntfs_log_perror("Failed to unmount volume"); } +} + +static void ntfs_fuse_free_context(void) +{ free(ctx->device); free(ctx->mnt_point); free(ctx->locale); free(ctx); } +static void ntfs_fuse_full_destroy(void) +{ + ntfs_fuse_destroy(NULL); + ntfs_fuse_free_context(); +} + static struct fuse_operations ntfs_fuse_oper = { .getattr = ntfs_fuse_getattr, .fgetattr = ntfs_fuse_fgetattr, @@ -1799,13 +1809,13 @@ int main(int argc, char *argv[]) ntfs_fuse_init(); if (parse_options(&args)) { fuse_opt_free_args(&args); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } /* Mount volume (libntfs part). */ if (ntfs_fuse_mount()) { fuse_opt_free_args(&args); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } if (ctx->blkdev) { @@ -1813,13 +1823,13 @@ int main(int argc, char *argv[]) if (setuid(0)) { ntfs_log_perror("setuid(0) failed"); fuse_opt_free_args(&args); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } /* Set blkdev, blksize and user options. */ if (ntfs_fuse_set_blkdev_options(&args)) { fuse_opt_free_args(&args); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } } else { @@ -1835,7 +1845,7 @@ int main(int argc, char *argv[]) if (!fch) { ntfs_log_error("fuse_mount failed.\n"); fuse_opt_free_args(&args); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } fh = fuse_new(fch, &args , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper), @@ -1844,7 +1854,7 @@ int main(int argc, char *argv[]) if (!fh) { ntfs_log_error("fuse_new failed.\n"); fuse_unmount(ctx->mnt_point, fch); - ntfs_fuse_destroy(NULL); + ntfs_fuse_full_destroy(); return 1; } /* Drop root privileges if we obtained them. */ @@ -1871,5 +1881,6 @@ int main(int argc, char *argv[]) /* Destroy. */ fuse_unmount(ctx->mnt_point, fch); fuse_destroy(fh); + ntfs_fuse_free_context(); return 0; } From 45a641b4084513df76dbf72eec1e757e82490f13 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 24 Sep 2007 21:08:32 +0300 Subject: [PATCH 259/289] ntfsmount: Fix recently introduced bug in attribute/inode close ordering in case if ntfs_fuse_open() failed. --- ntfsprogs/ntfsmount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index a8525ad9..84c9b869 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -649,8 +649,8 @@ static int ntfs_fuse_open(const char *org_path, struct fuse_file_info *fi) if (stream_name_len) free(stream_name); if (res) { - ntfs_inode_close(ni); ntfs_attr_close(na); + ntfs_inode_close(ni); } else fi->fh = (uintptr_t)na; return res; From f7068cf989116547f839c55a5c4134f5c4a91913 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Mon, 24 Sep 2007 21:58:02 +0300 Subject: [PATCH 260/289] ntfscp docs update --- ntfsprogs/ntfscp.8.in | 47 +++++++++++++++---------------------------- ntfsprogs/ntfscp.c | 6 ++++-- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/ntfsprogs/ntfscp.8.in b/ntfsprogs/ntfscp.8.in index d39763c5..30fa0b5a 100644 --- a/ntfsprogs/ntfscp.8.in +++ b/ntfsprogs/ntfscp.8.in @@ -1,30 +1,20 @@ -.\" Copyright (c) 2004\-2005 Yura Pakhuchiy. +.\" Copyright (c) 2004\-2007 Yura Pakhuchiy. .\" Copyright (c) 2005 Richard Russon. .\" This file may be copied under the terms of the GNU Public License. .\" -.TH NTFSCP 8 "November 2005" "ntfsprogs @VERSION@" +.TH NTFSCP 8 "September 2007" "ntfsprogs @VERSION@" .SH NAME -ntfscp \- overwrite file on an NTFS volume. +ntfscp \- copy file to an NTFS volume. .SH SYNOPSIS -.B ntfscp -[\fIoptions\fR] \fIdevice source_file destination\fR +\fBntfscp\fR [\fIoptions\fR] \fIdevice source_file destination\fR .SH DESCRIPTION -.B ntfscp -will overwrite file on an NTFS volume. At present -.B ntfscp -can't create new files. -.B destination -can be either file or directory. In case if -.B destination -is directory specified by name then -.B source_file -is copied into this directory, in case if -.B destination -is directory and specified by inode number then unnamed data attribute is -created for this inode and -.B source_file -is copied into it (WARNING: it's unusual to have unnamed data streams in the -directories, think twice before specifying directory by inode number). +\fBntfscp\fR will copy file to an NTFS volume. \fIdestination\fR can be either +file or directory. In case if \fIdestination\fR is directory specified by name +then \fIsource_file\fR is copied into this directory, in case if +\fIdestination\fR is directory and specified by inode number then unnamed data +attribute is created for this inode and \fIsource_file\fR is copied into it +(WARNING: it's unusual to have unnamed data streams in the directories, think +twice before specifying directory by inode number). .SH OPTIONS Below is a summary of all the options that .B ntfscp @@ -96,24 +86,19 @@ windows is C): .sp .RE .SH BUGS -There are no known problems with -.BR ntfscp . -If you find a bug please send an email describing the problem to the -development team: +There are no known problems with \fBntfscp\fR. If you find a bug please send an +email describing the problem to the development team: .br .nh linux\-ntfs\-dev@lists.sourceforge.net .hy .SH AUTHORS -.B ntfscp -was written by Yura Pakhuchiy, with contributions from Anton Altaparmakov. +\fBntfscp\fR was written by Yura Pakhuchiy, with contributions from Anton +Altaparmakov and Hil Liao. .SH DEDICATION With love to Marina Sapego. .SH AVAILABILITY -.B ntfscp -is part of the -.B ntfsprogs -package and is available from: +\fBntfscp\fR is part of the \fBntfsprogs\fR package and is available from: .br .nh http://www.linux\-ntfs.org/content/view/19/37 diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 0a6988d4..66813beb 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -5,7 +5,7 @@ * Copyright (c) 2005 Anton Altaparmakov * Copyright (c) 2006 Hil Liao * - * This utility will overwrite files on NTFS volume. + * This utility will copy file to an NTFS volume. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,9 +83,11 @@ static volatile sig_atomic_t caught_terminate = 0; */ static void version(void) { - ntfs_log_info("\n%s v%s (libntfs %s) - Overwrite files on NTFS " + ntfs_log_info("\n%s v%s (libntfs %s) - Copy file to an NTFS " "volume.\n\n", EXEC_NAME, VERSION, ntfs_libntfs_version()); ntfs_log_info("Copyright (c) 2004-2007 Yura Pakhuchiy\n"); + ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n"); + ntfs_log_info("Copyright (c) 2006 Hil Liao\n"); ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); } From 48e033623d7b796a14d293c1ee1f54417fd2fc1d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Tue, 25 Sep 2007 14:42:33 +0300 Subject: [PATCH 261/289] ntfsmount: Do not allow user mount devices he normally do not have rights to --- ntfsprogs/ntfsmount.c | 53 +++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 84c9b869..da46d56b 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -1807,46 +1807,35 @@ int main(int argc, char *argv[]) struct fuse_chan *fch; ntfs_fuse_init(); - if (parse_options(&args)) { - fuse_opt_free_args(&args); - ntfs_fuse_full_destroy(); - return 1; + if (parse_options(&args)) + goto err_out; + /* + * Drop effective uid to real uid because we do not want not previleged + * user that runs set-uid-root binary to be able to mount devices + * normally he do not have rights to. + */ + if (seteuid(ctx->uid)) { + ntfs_log_perror("seteuid(%d)", ctx->uid); + goto err_out; } /* Mount volume (libntfs part). */ - if (ntfs_fuse_mount()) { - fuse_opt_free_args(&args); - ntfs_fuse_full_destroy(); - return 1; - } + if (ntfs_fuse_mount()) + goto err_out; if (ctx->blkdev) { /* Gain root privileges for blkdev mount. */ - if (setuid(0)) { - ntfs_log_perror("setuid(0) failed"); - fuse_opt_free_args(&args); - ntfs_fuse_full_destroy(); - return 1; + if (seteuid(0) || setuid(0)) { + ntfs_log_perror("seteuid(0) or setuid(0) failed"); + goto err_out; } /* Set blkdev, blksize and user options. */ - if (ntfs_fuse_set_blkdev_options(&args)) { - fuse_opt_free_args(&args); - ntfs_fuse_full_destroy(); - return 1; - } - } else { - /* - * Drop effective uid if our binary is set-uid-root and we are - * performing not blkdev mount. - */ - if (!geteuid() && seteuid(ctx->uid)) - ntfs_log_perror("Failed to drop effective uid"); + if (ntfs_fuse_set_blkdev_options(&args)) + goto err_out; } /* Create filesystem (FUSE part). */ fch = fuse_mount(ctx->mnt_point, &args); if (!fch) { ntfs_log_error("fuse_mount failed.\n"); - fuse_opt_free_args(&args); - ntfs_fuse_full_destroy(); - return 1; + goto err_out; } fh = fuse_new(fch, &args , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper), NULL); @@ -1858,7 +1847,7 @@ int main(int argc, char *argv[]) return 1; } /* Drop root privileges if we obtained them. */ - if (ctx->blkdev && (setuid(ctx->uid) || seteuid(ctx->uid))) + if (ctx->blkdev && setuid(ctx->uid)) ntfs_log_warning("Failed to drop root privileges.\n"); /* Detach from terminal. */ if (!ctx->debug && !ctx->no_detach) { @@ -1883,4 +1872,8 @@ int main(int argc, char *argv[]) fuse_destroy(fh); ntfs_fuse_free_context(); return 0; +err_out: + fuse_opt_free_args(&args); + ntfs_fuse_full_destroy(); + return 1; } From d54ad2d637a127a78ea26c6e7c9f3da2dfec448e Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 26 Sep 2007 18:19:08 +0300 Subject: [PATCH 262/289] ntfsmount man page update --- ntfsprogs/ntfsmount.8.in | 292 +++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 169 deletions(-) diff --git a/ntfsprogs/ntfsmount.8.in b/ntfsprogs/ntfsmount.8.in index 484ffbf7..5e1016f1 100644 --- a/ntfsprogs/ntfsmount.8.in +++ b/ntfsprogs/ntfsmount.8.in @@ -1,139 +1,89 @@ -.\" Copyright (c) 2005-2006 Yura Pakhuchiy. +.\" Copyright (c) 2005-2007 Yura Pakhuchiy. .\" Copyright (c) 2005 Richard Russon. +.\" Copyright (c) 2006-2007 Szabolcs Szakacsits. .\" This file may be copied under the terms of the GNU Public License. .\" -.TH NTFSMOUNT 8 "February 2006" "ntfsprogs @VERSION@" +.TH NTFSMOUNT 8 "September 2007" "ntfsprogs @VERSION@" .SH NAME -ntfsmount \- NTFS module for FUSE. +ntfsmount \- Read/Write userspace NTFS driver. .SH SYNOPSIS -.B ntfsmount -.I device mount_point -[\fB\-o options\fR] -.SH DESCRIPTION -\fBntfsmount\fR is a \fBFUSE\fR module that rely on \fBlibntfs\fR. You need -\fBFUSE\fR to compile it, \fBxattr\fR is recommended, but not mandatory. -.TP -.B Fully implemented ntfsmount features: -\(bu Read\-write access to normal and sparse files. +\fBntfsmount\fR \fIdevice mount_point\fR [\fB\-o\fR \fIoptions\fR] .br -\(bu Read\-only access to compressed files. +\fBmount \-t fuse.ntfs\fR \fIdevice mount_point\fR [\fB\-o\fR \fIoptions\fR] +.sp +/etc/ftsab entry: +.br +\fIdevice mount_point\fR \fBfuse.ntfs\fR \fIoptions\fR \fB0 0\fR +.SH DESCRIPTION +\fBntfsmount\fR is a read/write userspace NTFS filesystem driver. Technically +it connects \fBFUSE\fR with \fBlibntfs\fR. +.TP +\fBntfsmount\fR features: +\(bu Create/Delete/Move files and directories. +.br +\(bu Hard link files. +.br +\(bu Read and write to normal and sparse files. +.br +\(bu Read compressed and encrypted files. .br \(bu Access to special Interix files (symlinks, devices, FIFOs). .br \(bu List/Read/Write/Add/Remove named data streams. .br -\(bu Supports Linux and FreeBSD. -.TP -.B Partly implemented features: -\(bu Create/Delete/Move files and directories. -.br -\(bu Hard link files. +\(bu Supports Linux, FreeBSD, NetBSD and Mac OS X. .SH OPTIONS -Below is a summary of all the options that \fBntfsmount\fR accepts. +\fBntfsmount\fR supports most of options that \fBmount\fR and \fBFUSE\fR +accepts (see "man 8 mount" and FUSE documentation for them). Additionally +\fBntfsmount\fR have some unique to it options, below is a summary of them. .TP -.B uid=, gid=, umask= -Provide default owner, group, and access mode mask. -These options work as documented in mount(8). By -default, the files/directories are owned by user that mounted volume and -he/she has read and write permissions, as well as -browse permission for directories. No one else has any -access permissions. I.e. the mode on all files is by -default rw\-\-\-\-\-\-\- and for directories rwx\-\-\-\-\-\-, a -consequence of the default fmask=0177 and dmask=0077. -Using a umask of zero will grant all permissions to -everyone, i.e. all files and directories will have mode -rwxrwxrwx. +.B silent, nosilent +\fBsilent\fR option makes ntfsmount to do not return "Operation is not +supported" error on chmod and chown operations (this option is on by default). +\fBnosilent\fR cancels this. .TP -.B fmask=, dmask= -Instead of specifying umask which applies both to -files and directories, fmask applies only to files and -mask only to directories. +.BI locale= value +You can set locale with this option. It's useful if locale environment variables +are not set before partitions from /etc/fstab had been mounted. Try submitting this option if you are experience problems with displaying national characters in filenames. .TP -.B show_sys_files -If show_sys_files is specified, show the system files -in directory listings. Otherwise the default behaviour -is to hide the system files. -Note that even when show_sys_files is specified, "$MFT" -may will not be visible due to bugs/mis\-features in glibc. -Further, note that irrespective of show_sys_files, all -files are accessible by name, i.e. you can always do -"ls \-l '$UpCase'" for example to specifically show the -system file containing the Unicode upcase table. +\fBuid=\fIvalue\fR, \fBgid=\fIvalue\fR +Set the owner and the group of files and directories. The values are numerical. +The defaults are the uid and gid of the current process. .TP -.B default_permissions -By default FUSE doesn't check file access permissions, the -filesystem is free to implement it's access policy or leave it to -the underlying file access mechanism (e.g. in case of network -filesystems). This option enables permission checking, restricting -access based on file mode. This is option is usually useful -together with the 'allow_other' mount option. +\fBumask=\fIvalue\fR, \fBdmask=\fIvalue\fR, \fBfmask=\fIvalue\fR +Set the bitmask of the file and directory permissions that are not present. +The value is given in octal. Instead of specifying umask which applies both to +files and directories, fmask applies only to files and dmask only to +directories. .TP -.B allow_other -This option overrides the security measure restricting file access -to the user mounting the filesystem. This option is by default only -allowed to root, but this restriction can be removed with a -configuration option described in the previous section. +.B case_insensitive +Make \fBntfsmount\fR treat filenames in POSIX names as case insensitive. +See \fBFILENAME NAMESPACES\fR section for details. .TP -.B kernel_cache -(NOTE: Only for FUSE 2.3.0, with FUSE >= 2.4.0 on by default) -This option disables flushing the cache of the file contents on -every open(). This should only be enabled on filesystems, where the -file data is never changed externally (not through the mounted FUSE -filesystem). Thus it is not suitable for network filesystems and -other "intermediate" filesystems. -NOTE: if this option is not specified (and neither 'direct_io') data -is still cached after the open(), so a read() system call will not -always initiate a read operation. +.B no_def_opts +By default ntfsmount acts as some useful options were passed to it (you can get +list of this options by running ntfsmount without any arguments). Submitting +this option will cancel such behaviour. .TP -.B large_read -Issue large read requests. This can improve performance for some -filesystems, but can also degrade performance. This option is only -useful on 2.4.X kernels, as on 2.6 kernels requests size is -automatically determined for optimum performance. -.TP -.B direct_io -(NOTE: Only for FUSE 2.3.0) -This option disables the use of page cache (file content cache) in -the kernel for this filesystem. This has several affects: -- Each read() or write() system call will initiate one or more -read or write operations, data will not be cached in the -kernel. -- The return value of the read() and write() system calls will -correspond to the return values of the read and write -operations. This is useful for example if the file size is not -known in advance (before reading it). -.TP -.B max_read= -With this option the maximum size of read operations can be set. -The default is infinite. Note that the size of read requests is -limited anyway to 32 pages (which is 128kbyte on i386). +.B noblkdev +By default ntfsmount tries to mount block devices with blkdev FUSE option if it +have enough privileges. Submit this option if blkdev mount does not work for +you for some reasons. .TP .B force Force mount even if errors occurred. Use this option only if you know what are you doing and don't cry about data loss. .TP -.B ro -Mount filesystem read\-only. +.B relatime, norelatime +Update inode access times relative to modify or change time. Access +time is only updated if the previous access time was earlier than the +current modify or change time. (Similar to noatime, but doesn't break +mutt or other applications that need to know if a file has been read +since the last time it was modified.) .TP -.B no_def_opts -By default ntfsmount acts as "default_permissions,allow_other" was passed to it, -this option cancel this behaviour. -.TP -.B silent -Do nothing on chmod and chown operations, but do not return error. -.TP -.B locale= -You can set locale with this option. It's useful if locale enviroment variables -are not set before partitions from /etc/fstab had been mounted. -.TP -.B streams_interface= +.BI streams_interface= value This option controls how the user can access named data streams. It can be set -to, one of \fBnone\fR, \fBwindows\fR or \fBxattr\fR. If the option is set to -\fBnone\fR, the user will have no access to the named data streams. If it's set -to \fBwindows\fR, then the user can access them just like in Windows (eg. cat -file:stream). If it's set to \fBxattr\fR, then the named data streams are -mapped to xattrs and user can manipulate them using \fB{get,set}fattr\fR -utilities. +to, one of \fBnone\fR, \fBwindows\fR or \fBxattr\fR. See \fBDATA STREAMS\fR section for details. .TP .B debug Makes ntfsmount to not detach from terminal and print a lot of debug output from @@ -141,81 +91,79 @@ libntfs and FUSE. .TP .B no_detach Same as above but with less debug output. +.SH FILENAME NAMESPACES +There are exist several namespaces for filenames in NTFS: DOS, Win32 and POSIX. +Names in DOS and Win32 namespaces are case insensitive, but names in POSIX +namespace are case sensitive. By default windows creates filenames in DOS and +Win32 namespaces (with exception for hard links), but ntfsmount always creates +files in POSIX namespace. Note: you can create several files that differs only +in case in one directory with ntfsmount, but windows applications may be +confused by this. .SH DATA STREAMS -All data on NTFS is stored in streams. Every file has exactly one unnamed -data stream and can have many named data streams. The size of a file is the -size of its unnamed data stream. By default, \fBntfsmount\fR will only read -the unnamed data stream. +All data on NTFS is stored in streams. Every file has exactly one unnamed data +stream and can have many named data streams. The size of a file is the size of +its unnamed data stream. Windows applications don't, consistently, allow you +to read named data streams, so you are recommended to use tools like FAR, or +utilities from Cygwin. .PP -By using the options "streams_interface=windows", you will be able to read +By default or if "streams_interface=none" option was passed, \fBntfsmount\fR will only read the unnamed data stream. +.PP +By using the option "streams_interface=windows", you will be able to read any named data streams, simply by specifying the stream's name after a colon. -For example: +Named data streams act like normals files, so you can read from them, write to +them and even delete them (using rm). You can list all the named data streams +a file has by getting the "ntfs.streams.list" extended attribute. Some examples: .RS .sp cat some.mp3:artist +.br +rm some.mp3:album +.br +echo Sympho Black Metal > some.mp3:genre +.br +getfattr \-n ntfs.streams.list some.mp3 .sp .RE -Windows applications don't, consistently, allow you to read named data -streams, so you are recommended to use tools like FAR, or utils from Cygwin. +If \fBstreams_interface\fR option is set to \fBxattr\fR, then the named data streams are mapped to xattrs and user can manipulate them using \fBgetfattr\fR and +\fBsetfattr\fR utilities. Eg.: +.RS +.sp +setfattr -n user.artist -v "Some Artist" some.mp3 +.br +getfattr -d some.mp3 +.RE +.SH ALLOWED CHARACTERS +Win32 does not allow characters like '<', '>', '*', '?' and so on in the +filenames, but NTFS supports any characters except '\\0' (NULL) and '/'. You +can create filenames with any allowed by NTFS characters using ntfsmount, but +aware, you will not be able to access files with denied by Win32 characters from +windows. +.SH ACCESS HANDLING AND SECURITY +By default, files and directories are owned by the user and group of the +mounting process and everybody has full read, write, execution and directory +browsing permissions. If you want to use permissions handling then use the +\fBuid\fR and/or the \fBgid\fR options together with the \fBumask\fR or +\fBfmask\fR and \fBdmask\fR options. .PP -Named data streams act like normals files, so you can read from them, write to -them and even delete them (using rm). You can list all the named data streams -a file has by getting the "ntfs.streams.list" extended attribute. NOTE: This -list feature is unique to the \fBntfsmount\fR and may never be supported by the -\fBkernel driver\fR. +Windows users have full access to the files created by \fBntfsmount\fR. .SH EXAMPLES -Mount /dev/hda1 to /mnt/ntfs\-fuse using ntfsmount: +Mount /dev/hda1 to /mnt/ntfs using ntfsmount submiting locale option: .RS .sp -.B ntfsmount /dev/hda1 /mnt/ntfs\-fuse -.sp -.RE -Read\-only mount /dev/hda5 to /home/user/mnt and make user with uid 1000 to be -owner of all files: -.RS -.sp -.B ntfsmount /dev/hda5 /home/user/mnt \-o ro,uid=1000 +.B ntfsmount /dev/hda1 /mnt/ntfs -o locale=be_BY.UTF-8 .sp .RE /etc/fstab entry for above: .RS .sp -.B /dev/hda5 /home/user/mnt ntfs\-fuse ro,uid=1000 0 0 +.B /dev/hda1 /mnt/ntfs fuse.ntfs locale=be_BY.UTF-8 0 0 .sp .RE -Umount /mnt/ntfs\-fuse: +Umount /mnt/ntfs: .RS .sp -.B fusermount \-u /mnt/ntfs\-fuse -.sp -.RE -Cat "artist" named data stream of "some.mp3": -.RS -.sp -.B cat some.mp3:artist -.sp -.RE -Write "Sympho Black Metal" to "genre" named data stream of "some.mp3": -.RS -.sp -.B echo Sympho Black Metal > some.mp3:genre -.sp -.RE -Remove "album" named data stream from "some.mp3": -.RS -.sp -.B rm some.mp3:album -.sp -.RE -List all named data streams for "some.mp3": -.RS -.sp -.B getfattr \-n ntfs.streams.list some.mp3 -.sp -.RE +.B fusermount \-u /mnt/ntfs .SH BUGS -There are no known problems with -.BR ntfsmount . If you find a bug please send an email describing the problem to the development team: .br @@ -223,17 +171,13 @@ development team: linux\-ntfs\-dev@lists.sourceforge.net .hy .SH AUTHORS -.B ntfsmount -was written by Yura Pakhuchiy, with contributions from Yuval Fledel. +\fBntfsmount\fR was written by Yura Pakhuchiy, with contributions from Yuval Fledel and Szabolcs Szakacsits. .SH DEDICATION With love to Marina Sapego. .SH THANKS Many thanks to Miklos Szeredi for advice and answers about FUSE. .SH AVAILABILITY -.B ntfsmount -is part of the -.B ntfsprogs -package and is available from: +\fBntfsmount\fR is part of the \fBntfsprogs\fR package and is available from: .br .nh http://www.linux\-ntfs.org/content/view/19/37 @@ -244,7 +188,17 @@ The manual pages are available online at: .nh http://man.linux-ntfs.org/ .hy +.sp +Additional up-to-date information can be found furthermore at: +.br +.nh +http://wiki.linux-ntfs.org/doku.php?id=ntfsmount +.hy .SH SEE ALSO +Read \fBlibntfs\fR(8) for details how to access encrypted files and mount +volumes with offset. +.sp +.BR libntfs (8), .BR ntfsprogs (8), .BR attr (5), .BR getfattr (1) From a92649480c4c9b21adf698894c7891f8b59f8d82 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 26 Sep 2007 22:41:28 +0300 Subject: [PATCH 263/289] Add man-page for libntfs --- libntfs/libntfs.8.in | 34 ++++++++++++++++++++++++++++++++++ ntfsprogs/ntfscat.8.in | 6 +++++- ntfsprogs/ntfsmount.8.in | 3 +-- ntfsprogs/ntfsprogs.8.in | 6 ++++-- 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 libntfs/libntfs.8.in diff --git a/libntfs/libntfs.8.in b/libntfs/libntfs.8.in new file mode 100644 index 00000000..f908f7cb --- /dev/null +++ b/libntfs/libntfs.8.in @@ -0,0 +1,34 @@ +.\" Copyright (c) 2007 Yura Pakhuchiy +.\" This file may be copied under the terms of the GNU Public License. +.TH LIBNTFS 8 "September 2007" "ntfsprogs @VERSION@" +.SH NAME +libntfs \- library for accessing and managing NTFS volumes +.SH OVERVIEW +\fBlibntfs\fR is GPL licensed library for accessing and managing NTFS volumes. +It is used by\fB ntfsprogs\fR and some other projects. +.SH ACCESSING ENCRYPTED FILES +Programs that uses\fB libntfs\fR can transparently access encrypted files on +NTFS volumes if\fB libntfs\fR was compiled with \fB--enable-crypto\fR option +(it depends on\fB libgcrypt\fR,\fB GNU TLS\fR and \fBlibconfig\fR) and user +wrote configuration file. Configuration file should be placed in +\fB/etc/libntfs/config\fR or \fB$(HOME)/.libntfs/config\fR and contain list +of .PFX key files (see ntfsprogs-/libntfs/config in ntfsprogs source +tarball for sample configuration file). Key files can be created/exported +using\fB cipher\fR tool under windows. +.SH AUTHORS +\fBlibntfs\fR was written by Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yuval Fledel and Yura Pakhuchiy. +.SH AVAILABILITY +The \fBntfsprogs\fR can be downloaded from: +.br +.nh +http://www.linux\-ntfs.org/content/view/19/37 +.hy +.sp +These manual pages can be viewed online at: +.br +.nh +http://man.linux-ntfs.org/ +.hy +.SH SEE ALSO +.BR ntfsprogs (8), +.BR libntfs\-gnomevfs (8) diff --git a/ntfsprogs/ntfscat.8.in b/ntfsprogs/ntfscat.8.in index 2ea3ff87..20e61591 100644 --- a/ntfsprogs/ntfscat.8.in +++ b/ntfsprogs/ntfscat.8.in @@ -1,7 +1,8 @@ .\" Copyright (c) 2003\-2005 Richard Russon. +.\" Copyright (c) 2007 Yura Pakhuchiy. .\" This file may be copied under the terms of the GNU Public License. .\" -.TH NTFSCAT 8 "November 2005" "ntfsprogs @VERSION@" +.TH NTFSCAT 8 "September 2007" "ntfsprogs @VERSION@" .SH NAME ntfscat \- print NTFS files and streams on the standard output .SH SYNOPSIS @@ -133,5 +134,8 @@ The manual pages are available online at: http://man.linux-ntfs.org/ .hy .SH SEE ALSO +Read \fBlibntfs\fR(8) for details how to access encrypted files. +.sp +.BR libntfs (8), .BR ntfsls (8), .BR ntfsprogs (8) diff --git a/ntfsprogs/ntfsmount.8.in b/ntfsprogs/ntfsmount.8.in index 5e1016f1..2502a280 100644 --- a/ntfsprogs/ntfsmount.8.in +++ b/ntfsprogs/ntfsmount.8.in @@ -195,8 +195,7 @@ Additional up-to-date information can be found furthermore at: http://wiki.linux-ntfs.org/doku.php?id=ntfsmount .hy .SH SEE ALSO -Read \fBlibntfs\fR(8) for details how to access encrypted files and mount -volumes with offset. +Read \fBlibntfs\fR(8) for details how to access encrypted files. .sp .BR libntfs (8), .BR ntfsprogs (8), diff --git a/ntfsprogs/ntfsprogs.8.in b/ntfsprogs/ntfsprogs.8.in index e265b2bc..110bbe17 100644 --- a/ntfsprogs/ntfsprogs.8.in +++ b/ntfsprogs/ntfsprogs.8.in @@ -1,9 +1,10 @@ .\" Copyright (c) 2002\-2005 Richard Russon. .\" Copyright (c) 2002\-2003 Anton Altaparmakov. .\" Copyright (c) 2005\-2006 Szabolcs Szakacsits. +.\" Copyright (c) 2005\-2007 Yura Pakhuchiy. .\" This file may be copied under the terms of the GNU Public License. .\" -.TH NTFSPROGS 8 "April 2006" "ntfsprogs @VERSION@" +.TH NTFSPROGS 8 "September 2007" "ntfsprogs @VERSION@" .SH NAME ntfsprogs \- tools for doing neat things with NTFS .SH OVERVIEW @@ -28,7 +29,7 @@ available for free and come with full source code. \- Compare two NTFS filesystems and tell the differences. .PP .BR ntfscp (8) -\- Overwrite a file on an NTFS. +\- Copy a file to an NTFS volume. .PP .BR ntfsfix (8) \- Check and fix some common errors, clear the LogFile and make Windows @@ -71,5 +72,6 @@ These manual pages can be viewed online at: http://man.linux-ntfs.org/ .hy .SH SEE ALSO +.BR libntfs (8), .BR libntfs\-gnomevfs (8) From c0005bfa0f90efd5d1b8c5c00f2c1176275c6fa2 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 26 Sep 2007 22:51:41 +0300 Subject: [PATCH 264/289] Add libntfs man page to build system --- configure.ac | 1 + libntfs/Makefile.am | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d2902c8f..bb2c49f8 100644 --- a/configure.ac +++ b/configure.ac @@ -393,6 +393,7 @@ AC_CONFIG_FILES([ include/ntfs/Makefile libntfs/Makefile libntfs/libntfs.conf + libntfs/libntfs.8 libntfs/libntfs-gnomevfs.8 ntfsprogs/Makefile ntfsprogs/mkntfs.8 diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index 10655eb9..1ed97fbd 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -87,7 +87,8 @@ libntfs_gnomevfs_la_SOURCES = \ gnome-vfs-method.c \ gnome-vfs-module.c -man_MANS = libntfs-gnomevfs.8 +man_MANS = libntfs.8 \ + libntfs-gnomevfs.8 AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes) From a3a077dcef7e1ef01a533c4d0fff1c3f51ac7310 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 26 Sep 2007 23:06:50 +0300 Subject: [PATCH 265/289] Update NEWS --- NEWS | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index bc35211c..97ada112 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,16 @@ -Current news -============ +ntfsprogs 2.0.0 +=============== -ntfsmount now has full basic read/write support. +ntfsmount (and libntfs) now has full basic read/write support. + +Cryptographic code now integrated into the libntfs, thus ntfscat and ntfsmount +now can read encrypted files. See "man 8 libntfs" for details. ntfsresize (and the entirety of ntfsprogs/libntfs in fact) now have full support for Windows Vista. +ntfsprogs and libntfs now entirely endian safe and move over now we have checks +that automatically reports endian errors. + mkntfs now creates a DCE compliant GUID for the volume and does a few other things to be more compliant with Windows Vista. From f24415abaa83271625b8fc31c37fed048ef6377c Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Wed, 26 Sep 2007 23:08:23 +0300 Subject: [PATCH 266/289] update AUTHORS --- AUTHORS | 3 --- 1 file changed, 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index e7aae7e0..86a3cf83 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,7 +6,4 @@ Current active project members are (in alphabetical order): Anton Altaparmakov Mario Emmenlauer -Yuval Fledel Yura Pakhuchiy -Richard Russon -Szabolcs Szakacsits From 2b1ef811e6f99659c2b180e9be8f8ef2fef086a1 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 27 Sep 2007 15:58:42 +0300 Subject: [PATCH 267/289] Add NTFS_MNT_INTERIX mount option to make libntfs recognize Interix files. At present it influence only on ntfs_filldir(), but we can have ntfs_stat() and other functions on which it will make more influence later. --- include/ntfs/volume.h | 7 +++++++ libntfs/dir.c | 15 ++++++++++----- libntfs/volume.c | 3 +++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index caad93a1..015c6ac1 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -62,6 +62,7 @@ typedef enum { NTFS_MNT_CASE_SENSITIVE = 4, NTFS_MNT_NOT_EXCLUSIVE = 8, NTFS_MNT_FORCE = 16, + NTFS_MNT_INTERIX = 32, } ntfs_mount_flags; /** @@ -91,6 +92,8 @@ typedef enum { it. */ NV_ForensicMount, /* 1: Mount is forensic, i.e. no modifications are to be done by mount/umount. */ + NV_Interix, /* 1: Make libntfs recognize Interix special + files. */ } ntfs_volume_state_bits; #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) @@ -117,6 +120,10 @@ typedef enum { #define NVolSetForensicMount(nv) set_nvol_flag(nv, ForensicMount) #define NVolClearForensicMount(nv) clear_nvol_flag(nv, ForensicMount) +#define NVolInterix(nv) test_nvol_flag(nv, Interix) +#define NVolSetInterix(nv) set_nvol_flag(nv, Interix) +#define NVolClearInterix(nv) clear_nvol_flag(nv, Interix) + /* * NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 2.x is used by Windows 2000 Beta diff --git a/libntfs/dir.c b/libntfs/dir.c index b2e0763b..85e9c0d1 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -597,6 +597,7 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), /** * ntfs_filldir - ntfs specific filldir method + * @vol: ntfs volume with wjich we are working * @pos: current position in directory * @ie: current index entry * @dirent: context for filldir callback supplied by the caller @@ -605,7 +606,7 @@ static const ntfschar dotdot[3] = { const_cpu_to_le16('.'), * Pass information specifying the current directory entry @ie to the @filldir * callback. */ -static int ntfs_filldir(s64 *pos, INDEX_ENTRY *ie, +static int ntfs_filldir(ntfs_volume *vol, s64 *pos, INDEX_ENTRY *ie, void *dirent, ntfs_filldir_t filldir) { FILE_NAME_ATTR *fn = &ie->key.file_name; @@ -618,8 +619,12 @@ static int ntfs_filldir(s64 *pos, INDEX_ENTRY *ie, return 0; if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT) dt_type = NTFS_DT_DIR; - else - dt_type = NTFS_DT_REG; + else { + if (NVolInterix(vol) && fn->file_attributes & FILE_ATTR_SYSTEM) + dt_type = NTFS_DT_UNKNOWN; + else + dt_type = NTFS_DT_REG; + } return filldir(dirent, fn->file_name, fn->file_name_length, fn->file_name_type, *pos, le64_to_cpu(ie->indexed_file), dt_type); @@ -857,7 +862,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(pos, ie, dirent, filldir); + rc = ntfs_filldir(vol, pos, ie, dirent, filldir); if (rc) goto err_out; } @@ -1015,7 +1020,7 @@ find_next_index_buffer: * Submit the directory entry to ntfs_filldir(), which will * invoke the filldir() callback as appropriate. */ - rc = ntfs_filldir(pos, ie, dirent, filldir); + rc = ntfs_filldir(vol, pos, ie, dirent, filldir); if (rc) goto err_out; } diff --git a/libntfs/volume.c b/libntfs/volume.c index 6d1064ae..00f4e408 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -475,6 +475,8 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, NVolSetReadOnly(vol); if (flags & NTFS_MNT_CASE_SENSITIVE) NVolSetCaseSensitive(vol); + if (flags & NTFS_MNT_INTERIX) + NVolSetInterix(vol); ntfs_log_debug("Reading bootsector... "); if (dev->d_ops->open(dev, NVolReadOnly(vol) ? O_RDONLY : ((flags & NTFS_MNT_NOT_EXCLUSIVE) ? O_RDWR : @@ -869,6 +871,7 @@ static long ntfs_volume_get_nr_free_clusters(ntfs_volume *vol) * NTFS_MNT_FORENSIC - mount for forensic purposes, i.e. do not do * any writing at all during the mount, i.e. no * journal emptying, no dirty bit setting, etc. + * NTFS_MNT_INTERIX - make libntfs recognize special Interix files * * The function opens the device @dev and verifies that it contains a valid * bootsector. Then, it allocates an ntfs_volume structure and initializes From e2deb0dad4e4e94ac119ac25958178229e1577c3 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 27 Sep 2007 16:29:57 +0300 Subject: [PATCH 268/289] ntfsmount: Fill .st_mode in readdir(). (Szaka, Yura) --- ntfsprogs/ntfsmount.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index da46d56b..426b03ce 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -594,8 +594,14 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx, return 0; } if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user) { - struct stat st = { .st_ino = MREF(mref) }; + struct stat st = { + .st_ino = MREF(mref), + }; + if (dt_type == NTFS_DT_REG) + st.st_mode = S_IFREG | (0777 & ~ctx->fmask); + if (dt_type == NTFS_DT_DIR) + st.st_mode = S_IFDIR | (0777 & ~ctx->dmask); ret = fill_ctx->filler(fill_ctx->buf, filename, &st, 0); } free(filename); @@ -1790,7 +1796,8 @@ static int ntfs_fuse_mount(void) (ctx->case_insensitive ? 0 : NTFS_MNT_CASE_SENSITIVE) | (ctx->blkdev ? NTFS_MNT_NOT_EXCLUSIVE : 0) | (ctx->force ? NTFS_MNT_FORCE : 0) | - (ctx->ro ? NTFS_MNT_RDONLY : 0)); + (ctx->ro ? NTFS_MNT_RDONLY : 0) | + NTFS_MNT_INTERIX); if (!vol) { ntfs_log_error("Mount failed.\n"); return -1; From 2d645bae536fdb4fdd4a348ecbb1effcf23cc7fc Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 27 Sep 2007 16:36:53 +0300 Subject: [PATCH 269/289] Apply latest CVS on top. I will rewrite history properly later. --- ChangeLog | 9 ++ libntfs/bootsect.c | 24 ++-- ntfsprogs/ntfsdecrypt.c | 267 +++++++++++++++++++++++++++++++--------- 3 files changed, 231 insertions(+), 69 deletions(-) diff --git a/ChangeLog b/ChangeLog index c302d4a0..d7b01198 100644 --- a/ChangeLog +++ b/ChangeLog @@ -133,6 +133,15 @@ xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsmount: st_block calculation was wrong. (Yuval) - mkntfs: Use Vista $Boot rather than XP one. (Anton) - ntfsmount: use utimens() instead of deprecated utime(). (Yura) + - libntfs: Ignore bootsector checksum inconsistencies as too many 3rd + party utilities update the boot sector without correcting the + checksum. Ported change from kernel driver. (Anton) + - ntfsdecrypt: Major improvement! We now validate the .pfx file to be + the right type of RSA key and we also determine the thumbprint and + compare the one in the keys to the one in the .pfx file thus we only + try to decrypt the FEK once we have the correct key. Several other + bug fixes leading to crashes. Also make compilation work on OS X + when gnutls is otherwise not found. (Anton, Yura) 21/06/2006 - 1.13.1 - Various fixes. diff --git a/libntfs/bootsect.c b/libntfs/bootsect.c index 90a30f01..4278ac1f 100644 --- a/libntfs/bootsect.c +++ b/libntfs/bootsect.c @@ -63,22 +63,26 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, ntfs_log_debug("\nBeginning bootsector check...\n"); - /* Calculate the checksum. Note, this is just a simple addition of - all u32 values in the bootsector starting at the beginning and - finishing at the offset of the checksum itself (i.e. not including - the checksum...). */ - if ((void*)b < (void*)&b->checksum) { + /* + * Check that checksum == sum of u32 values from b to the checksum + * field. If checksum is zero, no checking is done. We will work when + * the checksum test fails, since some utilities update the boot sector + * ignoring the checksum which leaves the checksum out-of-date. We + * report a warning if this is the case. + */ + if ((void*)b < (void*)&b->checksum && b->checksum) { u32 *u = (u32 *)b; u32 *bi = (u32 *)(&b->checksum); ntfs_log_debug("Calculating bootsector checksum... "); - for (i = 0; u < bi; ++u) i += le32_to_cpup(u); - - if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i) - goto not_ntfs; - ntfs_log_debug("OK\n"); + if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i) { + ntfs_log_debug("FAILED\n"); + ntfs_log_debug("The NTFS bootsector contains an " + "incorrect checksum."); + } else + ntfs_log_debug("OK\n"); } /* Check OEMidentifier is "NTFS " */ diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index cd0e72b9..81c596fe 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -2,7 +2,7 @@ * ntfsdecrypt - Decrypt ntfs encrypted files. Part of the Linux-NTFS project. * * Copyright (c) 2005 Yuval Fledel - * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2005-2007 Anton Altaparmakov * * This utility will decrypt files and print the decrypted data on the standard * output. @@ -66,6 +66,19 @@ typedef gcry_sexp_t ntfs_rsa_private_key; +#define NTFS_SHA1_THUMBPRINT_SIZE 0x14 + +#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3) + +#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4" +#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1" + +typedef enum { + DF_TYPE_UNKNOWN, + DF_TYPE_DDF, + DF_TYPE_DRF, +} NTFS_DF_TYPES; + /** * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit) * @@ -439,19 +452,34 @@ static ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls( return (ntfs_rsa_private_key)rsa_key; } +/** + * ntfs_rsa_private_key_release + */ +static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key) +{ + gcry_sexp_release((gcry_sexp_t)rsa_key); +} + /** * ntfs_pkcs12_extract_rsa_key */ static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size, - char *password) + char *password, char *thumbprint, int thumbprint_size, + NTFS_DF_TYPES *df_type) { int err, bag_index, flags; gnutls_datum_t dpfx, dkey; - gnutls_pkcs12_t pkcs12; - gnutls_pkcs12_bag_t bag; - gnutls_x509_privkey_t pkey; + gnutls_pkcs12_t pkcs12 = NULL; + gnutls_pkcs12_bag_t bag = NULL; + gnutls_x509_privkey_t pkey = NULL; + gnutls_x509_crt_t crt = NULL; ntfs_rsa_private_key rsa_key = NULL; + char purpose_oid[100]; + size_t purpose_oid_size = sizeof(purpose_oid); + size_t tp_size = thumbprint_size; + BOOL have_thumbprint = FALSE; + *df_type = DF_TYPE_UNKNOWN; /* Create a pkcs12 structure. */ err = gnutls_pkcs12_init(&pkcs12); if (err) { @@ -467,7 +495,7 @@ static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size, ntfs_log_error("Failed to convert the PFX file from DER to " "native PKCS#12 format: %s\n", gnutls_strerror(err)); - goto out; + goto err; } /* * Verify that the password is correct and that the key file has not @@ -484,9 +512,9 @@ retry_verify: password = NULL; goto retry_verify; } - ntfs_log_error("Failed to verify the MAC (%s). Is the " + ntfs_log_error("Failed to verify the MAC: %s Is the " "password correct?\n", gnutls_strerror(err)); - goto out; + goto err; } for (bag_index = 0; ; bag_index++) { err = gnutls_pkcs12_bag_init(&bag); @@ -494,29 +522,31 @@ retry_verify: ntfs_log_error("Failed to initialize PKCS#12 Bag " "structure: %s\n", gnutls_strerror(err)); - goto out; + goto err; } err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag); if (err) { - if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + err = 0; break; + } ntfs_log_error("Failed to obtain Bag from PKCS#12 " "structure: %s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } check_again: err = gnutls_pkcs12_bag_get_count(bag); if (err < 0) { ntfs_log_error("Failed to obtain Bag count: %s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } err = gnutls_pkcs12_bag_get_type(bag, 0); if (err < 0) { ntfs_log_error("Failed to determine Bag type: %s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } flags = 0; switch (err) { @@ -527,14 +557,14 @@ check_again: if (err < 0) { ntfs_log_error("Failed to obtain Bag data: " "%s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } err = gnutls_x509_privkey_init(&pkey); if (err) { ntfs_log_error("Failed to initialized " "private key structure: %s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } /* Decrypt the private key into GNU TLS format. */ err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey, @@ -544,7 +574,7 @@ check_again: "key from DER to GNU TLS " "format: %s\n", gnutls_strerror(err)); - goto key_out; + goto err; } #if 0 /* @@ -572,38 +602,110 @@ check_again: #endif /* Convert the private key to our internal format. */ rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey); - goto key_out; + if (!rsa_key) + goto err; + break; case GNUTLS_BAG_ENCRYPTED: err = gnutls_pkcs12_bag_decrypt(bag, password); if (err) { ntfs_log_error("Failed to decrypt Bag: %s\n", gnutls_strerror(err)); - goto bag_out; + goto err; } goto check_again; + case GNUTLS_BAG_CERTIFICATE: + err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); + if (err < 0) { + ntfs_log_error("Failed to obtain Bag data: " + "%s\n", gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_init(&crt); + if (err) { + ntfs_log_error("Failed to initialize " + "certificate structure: %s\n", + gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_import(crt, &dkey, + GNUTLS_X509_FMT_DER); + if (err) { + ntfs_log_error("Failed to convert certificate " + "from DER to GNU TLS format: " + "%s\n", gnutls_strerror(err)); + goto err; + } + err = gnutls_x509_crt_get_key_purpose_oid(crt, 0, + purpose_oid, &purpose_oid_size, NULL); + if (err) { + ntfs_log_error("Failed to get key purpose " + "OID: %s\n", + gnutls_strerror(err)); + goto err; + } + purpose_oid[purpose_oid_size - 1] = '\0'; + if (!strncmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DRF, + strlen( + NTFS_EFS_CERT_PURPOSE_OID_DRF))) + *df_type = DF_TYPE_DRF; + else if (!strncmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DDF, + strlen( + NTFS_EFS_CERT_PURPOSE_OID_DDF))) + *df_type = DF_TYPE_DDF; + else { + ntfs_log_error("Certificate has unknown " + "purpose OID %s.\n", + purpose_oid); + err = EINVAL; + goto err; + } + /* Return the thumbprint to the caller. */ + err = gnutls_x509_crt_get_fingerprint(crt, + GNUTLS_DIG_SHA1, thumbprint, &tp_size); + if (err) { + ntfs_log_error("Failed to get thumbprint: " + "%s\n", gnutls_strerror(err)); + goto err; + } + if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) { + ntfs_log_error("Invalid thumbprint size %zd. " + "Should be %d.\n", tp_size, + thumbprint_size); + err = EINVAL; + goto err; + } + have_thumbprint = TRUE; + gnutls_x509_crt_deinit(crt); + crt = NULL; + break; default: /* We do not care about other types. */ break; } gnutls_pkcs12_bag_deinit(bag); } -key_out: - gnutls_x509_privkey_deinit(pkey); -bag_out: - gnutls_pkcs12_bag_deinit(bag); -out: - gnutls_pkcs12_deinit(pkcs12); +err: + if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN || + !have_thumbprint)) { + if (!err) + ntfs_log_error("Key type or thumbprint not found, " + "aborting.\n"); + ntfs_rsa_private_key_release(rsa_key); + rsa_key = NULL; + } + if (crt) + gnutls_x509_crt_deinit(crt); + if (pkey) + gnutls_x509_privkey_deinit(pkey); + if (bag) + gnutls_pkcs12_bag_deinit(bag); + if (pkcs12) + gnutls_pkcs12_deinit(pkcs12); return rsa_key; } -/** - * ntfs_rsa_private_key_release - */ -static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key) -{ - gcry_sexp_release((gcry_sexp_t)rsa_key); -} - /** * ntfs_buffer_reverse - * @@ -964,16 +1066,20 @@ static inline BOOL ntfs_des_test(void) /** * ntfs_fek_import_from_raw */ -static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, - unsigned fek_size __attribute__((unused))) +static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size) { ntfs_fek *fek; u32 key_size, wanted_key_size, gcry_algo; gcry_error_t err; - // TODO: Sanity checking of sizes and offsets. key_size = le32_to_cpup(fek_buf); - //ntfs_log_debug("key_size 0x%x\n", key_size); + ntfs_log_debug("key_size 0x%x\n", key_size); + if (key_size + 16 > fek_size) { + ntfs_log_debug("Invalid FEK. It was probably decrypted with " + "the incorrect RSA key."); + errno = EINVAL; + return NULL; + } fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) + sizeof(gcry_cipher_hd_t)); if (!fek) { @@ -1032,7 +1138,8 @@ static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, } if (key_size != wanted_key_size) { ntfs_log_error("%s key of %u bytes but needed size is %u " - "bytes, assuming corrupt key. Aborting.\n", + "bytes, assuming corrupt or incorrect key. " + "Aborting.\n", gcry_cipher_algo_name(gcry_algo), (unsigned)key_size, (unsigned)wanted_key_size); err = EIO; @@ -1076,7 +1183,8 @@ static void ntfs_fek_release(ntfs_fek *fek) * ntfs_df_array_fek_get */ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, - ntfs_rsa_private_key rsa_key) + ntfs_rsa_private_key rsa_key, char *thumbprint, + int thumbprint_size) { EFS_DF_HEADER *df_header; EFS_DF_CREDENTIAL_HEADER *df_cred; @@ -1086,14 +1194,41 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, u32 df_count, fek_size; unsigned i; - df_header = (EFS_DF_HEADER*)(df_array + 1); df_count = le32_to_cpu(df_array->df_count); - for (i = 0; i < df_count; i++) { + if (!df_count) + ntfs_log_error("There are no elements in the DF array.\n"); + df_header = (EFS_DF_HEADER*)(df_array + 1); + for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)( + (u8*)df_header + le32_to_cpu(df_header->df_length))) { df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header + le32_to_cpu(df_header->cred_header_offset)); + if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) { + ntfs_log_debug("Credential type is not certificate " + "thumbprint, skipping DF entry.\n"); + continue; + } df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred + le32_to_cpu( df_cred->cert_thumbprint_header_offset)); + if (le32_to_cpu(df_cert->thumbprint_size) != thumbprint_size) { + ntfs_log_error("Thumbprint size %d is not valid " + "(should be %d), skipping this DF " + "entry.\n", + le32_to_cpu(df_cert->thumbprint_size), + thumbprint_size); + continue; + } + if (memcmp((u8*)df_cert + + le32_to_cpu(df_cert->thumbprint_offset), + thumbprint, thumbprint_size)) { + ntfs_log_debug("Thumbprints do not match, skipping " + "this DF entry.\n"); + continue; + } + /* + * The thumbprints match so this is probably the DF entry + * matching the RSA key. Try to decrypt the FEK with it. + */ fek_size = le32_to_cpu(df_header->fek_size); fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset); /* Decrypt the FEK. Note: This is done in place. */ @@ -1108,8 +1243,6 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, } else ntfs_log_error("Failed to decrypt the file " "encryption key.\n"); - df_header = (EFS_DF_HEADER*)((u8*)df_header + - le32_to_cpu(df_header->df_length)); } return NULL; } @@ -1118,10 +1251,11 @@ static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, * ntfs_inode_fek_get - */ static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode, - ntfs_rsa_private_key rsa_key) + ntfs_rsa_private_key rsa_key, char *thumbprint, + int thumbprint_size, NTFS_DF_TYPES df_type) { EFS_ATTR_HEADER *efs; - EFS_DF_ARRAY_HEADER *df_array; + EFS_DF_ARRAY_HEADER *df_array = NULL; ntfs_fek *fek = NULL; /* Obtain the $EFS contents. */ @@ -1130,17 +1264,29 @@ static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode, ntfs_log_perror("Failed to read $EFS attribute"); return NULL; } - /* Iterate through the DDFs & DRFs until we obtain a key. */ - if (efs->offset_to_ddf_array) { - df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + - le32_to_cpu(efs->offset_to_ddf_array)); - fek = ntfs_df_array_fek_get(df_array, rsa_key); - } - if (!fek && efs->offset_to_drf_array) { - df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + - le32_to_cpu(efs->offset_to_drf_array)); - fek = ntfs_df_array_fek_get(df_array, rsa_key); - } + /* + * Depending on whether the key is a normal key or a data recovery key, + * iterate through the DDF or DRF array, respectively. + */ + if (df_type == DF_TYPE_DDF) { + if (efs->offset_to_ddf_array) + df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + + le32_to_cpu(efs->offset_to_ddf_array)); + else + ntfs_log_error("There are no entries in the DDF " + "array.\n"); + } else if (df_type == DF_TYPE_DRF) { + if (efs->offset_to_drf_array) + df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + + le32_to_cpu(efs->offset_to_drf_array)); + else + ntfs_log_error("There are no entries in the DRF " + "array.\n"); + } else + ntfs_log_error("Invalid DF type.\n"); + if (df_array) + fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint, + thumbprint_size); free(efs); return fek; } @@ -1267,6 +1413,8 @@ int main(int argc, char *argv[]) ntfs_fek *fek; unsigned pfx_size; int res; + NTFS_DF_TYPES df_type; + char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE]; ntfs_log_set_handler(ntfs_log_handler_stderr); @@ -1295,14 +1443,14 @@ int main(int argc, char *argv[]) return 1; } /* Obtain the user's private RSA key from the key file. */ - rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password); + rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password, + thumbprint, sizeof(thumbprint), &df_type); /* Destroy the password. */ memset(password, 0, strlen(password)); /* No longer need the pfx file contents. */ free(pfx_buf); if (!rsa_key) { - ntfs_log_error("Failed to extract the private RSA key. Did " - "you perhaps mistype the password?\n"); + ntfs_log_error("Failed to extract the private RSA key.\n"); ntfs_crypto_deinit(); return 1; } @@ -1328,7 +1476,8 @@ int main(int argc, char *argv[]) return 1; } /* Obtain the file encryption key of the encrypted file. */ - fek = ntfs_inode_fek_get(inode, rsa_key); + fek = ntfs_inode_fek_get(inode, rsa_key, thumbprint, + sizeof(thumbprint), df_type); ntfs_rsa_private_key_release(rsa_key); if (fek) { res = ntfs_cat_decrypt(inode, fek); From 2f330759935e2a7b42ef9308d4ba4c7aac3ac8be Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Thu, 27 Sep 2007 16:41:22 +0300 Subject: [PATCH 270/289] Apply fix from crypto.c to ntfsdecrypt --- ntfsprogs/ntfsdecrypt.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 81c596fe..4fc495e5 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -3,6 +3,7 @@ * * Copyright (c) 2005 Yuval Fledel * Copyright (c) 2005-2007 Anton Altaparmakov + * Copyright (c) 2007 Yura Pakhuchiy * * This utility will decrypt files and print the decrypted data on the standard * output. @@ -644,15 +645,11 @@ check_again: goto err; } purpose_oid[purpose_oid_size - 1] = '\0'; - if (!strncmp(purpose_oid, - NTFS_EFS_CERT_PURPOSE_OID_DRF, - strlen( - NTFS_EFS_CERT_PURPOSE_OID_DRF))) + if (!strcmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DRF)) *df_type = DF_TYPE_DRF; - else if (!strncmp(purpose_oid, - NTFS_EFS_CERT_PURPOSE_OID_DDF, - strlen( - NTFS_EFS_CERT_PURPOSE_OID_DDF))) + else if (!strcmp(purpose_oid, + NTFS_EFS_CERT_PURPOSE_OID_DDF)) *df_type = DF_TYPE_DDF; else { ntfs_log_error("Certificate has unknown " From ae99cc4199b2897a133e6a1232398fe572efc6ca Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 28 Sep 2007 16:52:47 +0300 Subject: [PATCH 271/289] Update changelog --- ChangeLog | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index d7b01198..710c395d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,5 @@ -xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. +28/09/2007 - 2.0.0 - ntfsmount sports full read/write, libntfs can read + encrypted files and ntfsresize supports Vista. - ntfsmount now creates files and directories with security descriptor that grant full access to everyone. (Yura) @@ -14,10 +15,10 @@ xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. record. (Yura) - calloc/malloc -> ntfs_{calloc,malloc} conversions. (Szaka) - ntfsclone: don't create image files with executable bit set. (Szaka) - - ntfsclone: metadata cloning: write out extent records. (Szaka) + - ntfsclone: metadata cloning: write out extent records. (Szaka) - ntfsclone: fix sometimes missing error messages and be more detailed. (Szaka) - - ntfsclone: fix crash in wipe_index_allocation_timestamps(): don't + - ntfsclone: fix crash in wipe_index_allocation_timestamps(): don't dump empty index allocation attribute. (Szaka) - ntfscmp: fine grained AT_INDEX_ALLOCATION comparison. (Szaka) - ntfsinfo: rename 'Flags:' fields to be unique. (Szaka) @@ -31,7 +32,7 @@ xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. - ntfsinfo: redirect stderr to /dev/null if --debug isn't used in debug mode. (Szaka) - ntfsinfo: fix segfaults on corrupt index blocks. (Szaka) - - ntfsinfo: dump number of entries per block in index allocation + - ntfsinfo: dump number of entries per block in index allocation attributes. (Szaka) - ntfsinfo: dump ATTR_LIST_ENTRY padding in verbose mode. (Szaka) - ntfsinfo: dump all VCN's in the same numeral system. (Szaka) @@ -142,6 +143,67 @@ xx/03/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista. try to decrypt the FEK once we have the correct key. Several other bug fixes leading to crashes. Also make compilation work on OS X when gnutls is otherwise not found. (Anton, Yura) + - ntfsmount: fix errno in truncate() operation. (Yura) + - Add new API: __ntfs_attr_truncate that allow user to select whether + holes should be created or clusters allocated. (Yura) + - Add new API: ntfs_attr_map_runlist_range to map part of runlist from + selected VCN to selected VCN. (Yura) + - Make ntfs_attr_update_mapping_pairs to be mostly O(1) for normal + files. (Yura) + - Introduce sparse bitwise annotations to automatically catch endian + bugs. Adopt libntfs (and fix 2 bugs) and ntfsprogs (and fix lots of + bugs). (Yura) + - ntfsinfo: nicely dump special LCN values. (Yura) + - Transparently integrate reading of encrypted files into library. + This adds crypto.[ch], several exported functions that you are not + interested to use and dependency on >=libconfig-1.0.1 to read list of + PFX files with keys. See libntfs/config for example configuration + file. (Yura) + - Add new API ntfs_attr_get_name - returns pointer to unicode name of + attribute. (Yura) + - ntfsinfo: Dump raw content of LOGGED_UTILITY_STREAM in verbose + mode. (Yura) + - Export NTFS_EFS string. (Yura) + - Merge --enable-debug and --enable-debug-logging. (Yura) + - Add --enable-sparse configure option. (Yura) + - Fix corner case in hole instantiating in ntfs_attr_pwrite(). (Szaka) + - Fix heavy memory usage during whole instantiating and add new API: + ntfs_rl_fill_zero. (Szaka, Yura) + - ntfs_delete() now takes pointer to pointer to ntfs_inode for file to + delete and closes inode only in cases there are no more hard links + left to file. (Yura) + - Library no longer perform time updates, only provides API for + performing time updates. Remove ntfs_inode_update_{a,}time() and + introduce ntfs_inode_update_times(). Make ntfsmount update time + according to SUS. (Yura) + - Fix cache handling in utils_attr_get_name. (Bogdan, Yura) + - ntfsmount: Submit inode number during readdir. (Ted Anderson, Szaka) + - Fix syslog logging handler to respect all logging flags. (Yura) + - ntfs_readdir, ntfs_fuse_filler: return with error if FUSE filler + failed. (Szaka, Yura) + - Fix rare directory corruption in index code. (Szaka, Yura) + - ntfsmount: Mount block devices with blkdev mount option. (Yura) + - ntfsmount: Add set-uid-root binary support. (Yura) + - ntfsmount: Implement {no,}relatime (relative atime) options. (Yura) + - Make libntfs keep track number of free clusters and MFT records. + Thanks to David Fox and Szabolcs Szakacsits for idea. (Yura) + - ntfsmount: Add bmap support. (Szaka, Yura) + - Introduce NTFS_MNT_FORCE instead of third parameter (force) of + utils_mount_volume. (Yura) + - ntfs_attr_pwrite: Write 4096 bytes blocks when possible. (David Fox, + Szaka, Anton, Yura) + - Allow mounting volumes with non-clean logfile with force mount + option. Thanks to Szaka for idea. (Yura) + - libntfs: Attach opened inodes to volume. (Yura) + - libntfs: Attach opened attributes to inode. (Yura) + - ntfsmount: Save pointer to ntfs_attr in (fuse_file_info *)->fh and + use it in ntfs_fuse_{read,write}. (Yura) + - ntfsmount: Implement .create(), .ftruncate(), .fgetattr(). (Yura) + - libntfs: Sync and warn about not closed inodes in ntfs_umount. (Yura) + - ntfsmount: Cache directory in which was performed last + operation. (Yura) + - Install mount.fuse.ntfs symbolic link. (Yura) + - ntfsmount: Fill .st_mode in readdir(). (Szaka, Yura) 21/06/2006 - 1.13.1 - Various fixes. From e0e71a37763b3bc4be2e22416e13085e167a6858 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 28 Sep 2007 21:07:15 +0100 Subject: [PATCH 272/289] Fix grammar in NEWS and add a few useful extra outputs about the attribute list attribute in ntfsinfo.c. (Anton) --- NEWS | 8 ++++---- ntfsprogs/ntfsinfo.c | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 97ada112..a623d556 100644 --- a/NEWS +++ b/NEWS @@ -3,14 +3,14 @@ ntfsprogs 2.0.0 ntfsmount (and libntfs) now has full basic read/write support. -Cryptographic code now integrated into the libntfs, thus ntfscat and ntfsmount -now can read encrypted files. See "man 8 libntfs" for details. +Cryptographic code is now integrated into libntfs, thus ntfscat and ntfsmount +now can read encrypted files. See "man 8 libntfs" for details. ntfsresize (and the entirety of ntfsprogs/libntfs in fact) now have full support for Windows Vista. -ntfsprogs and libntfs now entirely endian safe and move over now we have checks -that automatically reports endian errors. +ntfsprogs and libntfs are now entirely endian safe and more over now we have +checks that automatically reports endian errors. mkntfs now creates a DCE compliant GUID for the volume and does a few other things to be more compliant with Windows Vista. diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index e3adfe1d..6a30cb21 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1211,11 +1211,16 @@ static const char * ntfs_dump_lcn(LCN lcn) } } -static void ntfs_dump_attribute_header(ATTR_RECORD *a, ntfs_volume *vol) +static void ntfs_dump_attribute_header(ntfs_attr_search_ctx *ctx, + ntfs_volume *vol) { - printf("Dumping attribute %s (0x%x)\n", + ATTR_RECORD *a = ctx->attr; + + printf("Dumping attribute %s (0x%x) from mft record %lld (0x%llx)\n", get_attribute_type_name(a->type), - (unsigned)le32_to_cpu(a->type)); + (unsigned)le32_to_cpu(a->type), + (unsigned long long)ctx->ntfs_ino->mft_no, + (unsigned long long)ctx->ntfs_ino->mft_no); ntfs_log_verbose("\tAttribute length:\t %u (0x%x)\n", (unsigned)le32_to_cpu(a->length), @@ -2153,7 +2158,7 @@ static void ntfs_dump_file_attributes(ntfs_inode *inode) continue; } - ntfs_dump_attribute_header(ctx->attr, inode->vol); + ntfs_dump_attribute_header(ctx, inode->vol); switch (ctx->attr->type) { case AT_STANDARD_INFORMATION: From eb8307dac332c22cd2d5d839775e3bdf4548ef8d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Sat, 29 Sep 2007 01:09:10 +0300 Subject: [PATCH 273/289] Add libntfs sample config to EXTRA_DIST --- libntfs/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index 1ed97fbd..7e1f726a 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -92,7 +92,7 @@ man_MANS = libntfs.8 \ AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes) -EXTRA_DIST = unix_io.c win32_io.c libntfs.conf.in +EXTRA_DIST = unix_io.c win32_io.c libntfs.conf.in config MAINTAINERCLEANFILES = Makefile.in From 844d3213a9f1ac738312f74c6ce584cfe5ad5cd9 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 07:32:25 +0100 Subject: [PATCH 274/289] ntfsck.c: Adapted includes to libntfs-3g. --- ntfsprogs/ntfsck.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c index 2171a620..37b0b2db 100644 --- a/ntfsprogs/ntfsck.c +++ b/ntfsprogs/ntfsck.c @@ -37,12 +37,13 @@ #include #endif -#include "layout.h" +#include +#include +#include +#include + #include "cluster.h" -#include "bitmap.h" #include "utils.h" -#include "endians.h" -#include "bootsect.h" #define RETURN_FS_ERRORS_CORRECTED (1) #define RETURN_SYSTEM_NEEDS_REBOOT (2) From 41e27e116a2caacea2db032e791fb739330d0803 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 07:36:10 +0100 Subject: [PATCH 275/289] Added 'misc.h' as an include to some source files because of missing ntfs_malloc / ntfs_calloc signatures. --- ntfsprogs/mkntfs.c | 1 + ntfsprogs/ntfsck.c | 1 + ntfsprogs/ntfsclone.c | 1 + ntfsprogs/ntfscmp.c | 1 + ntfsprogs/ntfsinfo.c | 1 + ntfsprogs/ntfsresize.c | 1 + ntfsprogs/utils.c | 1 + 7 files changed, 7 insertions(+) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 0b4b2e77..3fc70636 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -132,6 +132,7 @@ #include #include #include +#include #include "utils.h" #include "sd.h" diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c index 37b0b2db..0464493b 100644 --- a/ntfsprogs/ntfsck.c +++ b/ntfsprogs/ntfsck.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "cluster.h" #include "utils.h" diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 7c379131..0f992815 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -77,6 +77,7 @@ #include #include #include +#include #include "utils.h" /* #include "version.h" */ diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 377a37db..45170ecd 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -35,6 +35,7 @@ #include #include +#include #include "utils.h" /* #include "version.h" */ diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index f8cab9b9..b59afb4d 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -77,6 +77,7 @@ #include #include #include +#include #include "utils.h" /* #include "version.h" */ diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index d54396d1..680f2567 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "utils.h" /* #include "version.h" */ diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 1bac388f..f3fe533c 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -70,6 +70,7 @@ #include #include #include +#include #include "utils.h" /* #include "version.h" */ From dd3d394010b637797a8d38c42e404a792dbffd05 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 07:37:40 +0100 Subject: [PATCH 276/289] utils.h: Added ntfs_attr_get_name, a simple inline function from libntfs that was referenced in the ntfsprogs code. --- ntfsprogs/utils.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ntfsprogs/utils.h b/ntfsprogs/utils.h index c377f5bd..cefcd14e 100644 --- a/ntfsprogs/utils.h +++ b/ntfsprogs/utils.h @@ -126,4 +126,10 @@ static __inline__ int ntfs_mbstoucs_libntfscompat(const char *ins, return ntfs_mbstoucs(ins, outs); } +/* This simple utility function was missing from libntfs-3g. */ +static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr) +{ + return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset)); +} + #endif /* _NTFS_UTILS_H_ */ From f5f3878a8e822dcc49193e72c96650f302489937 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 07:56:29 +0100 Subject: [PATCH 277/289] Replaced all occurrences of the libntfs-specific NVolWasDirty macro with a test for the VOLUME_IS_DIRTY flag in vol->flags. This is not a perfect conversion. The VOLUME_IS_DIRTY flag reflects the _current_ state of the volume dirty bit and not the mount-time state. However, since libntfs-3g (as opposed to libntfs) does not automatically change the dirty bit on mount and unmount (only when ntfs_volume_write_flags is called explicitly), and these tests are done directly after a mount (ntfsclone.c, ntfscp.c, ntfsresize.c, ntfswipe.c, utils.c) or when the volume is in an appropriate state (ntfsfix.c), the result will be the same. --- ntfsprogs/ntfsclone.c | 2 +- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsfix.c | 4 +++- ntfsprogs/ntfsresize.c | 2 +- ntfsprogs/ntfswipe.c | 2 +- ntfsprogs/utils.c | 6 +++++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 0f992815..382badb1 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1397,7 +1397,7 @@ static void mount_volume(unsigned long new_mntflag) exit(1); } - if (NVolWasDirty(vol)) + if (vol->flags & VOLUME_IS_DIRTY) if (opt.force-- <= 0) err_exit(dirty_volume_msg, opt.volume); diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index f85b372a..f6090f25 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -357,7 +357,7 @@ int main(int argc, char *argv[]) return 1; } - if (NVolWasDirty(vol) && !opts.force) + if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force) goto umount; { diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index ba5c522f..a0220e6f 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -248,7 +248,9 @@ static int set_dirty_flag(ntfs_volume *vol) { le16 flags; - if (NVolWasDirty(vol)) + /* Porting note: We test for the current state of VOLUME_IS_DIRTY. This + * should actually be more appropriate than testing for NVolWasDirty. */ + if (vol->flags | VOLUME_IS_DIRTY) return 0; ntfs_log_info("Setting required flags on partition... "); /* diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 680f2567..8f0d4e26 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2262,7 +2262,7 @@ static ntfs_volume *mount_volume(void) exit(1); } - if (NVolWasDirty(vol)) + if (vol->flags & VOLUME_IS_DIRTY) if (opt.force-- <= 0) err_exit("Volume is scheduled for check.\nRun chkdsk /f" " and please try again, or see option -f.\n"); diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index 7b0578b7..93392dce 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1348,7 +1348,7 @@ int main(int argc, char *argv[]) if (!vol) goto free; - if (NVolWasDirty(vol) && !opts.force) + if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force) goto umount; if (opts.info) { diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index f3fe533c..947bddec 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -237,7 +237,11 @@ ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags) return NULL; } - if (NVolWasDirty(vol)) { + /* Porting notes: + * libntfs-3g does not record whether the volume log file was dirty + * before mount, so we can only warn if the VOLUME_IS_DIRTY flag is set + * in VOLUME_INFORMATION. */ + if (vol->flags & VOLUME_IS_DIRTY) { if (!(flags & NTFS_MNT_FORCE)) { ntfs_log_error("%s", dirty_volume_msg); ntfs_umount(vol, FALSE); From 6b513b1c55f3d1242c9004f724cc99a727330340 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 09:26:00 +0100 Subject: [PATCH 278/289] Replaced references to NVolSetWasDirty with appropriate substitutions. libntfs (unlike libntfs-3g) sets the volume dirty bit automatically on ntfs_mount (if not already set) and also automatically clears the volume dirty bit on ntfs_umount (if it was not already set before mount). The 'WasDirty' flag is set to indicate that the volume was already dirty when it was mounted, so setting it means bypassing the 'clear dirty flag' behaviour on unmount (it does not mean 'set dirty flag on unmount'). NVolSetWasDirty is accordingly replaced with the actions that were intended: - If the intention was to leave the dirty bit set on unmount, we explicitly set the bit if it is not already set. - If the intention was to simply update the 'WasDirty' bit to be consistent with earlier changes, we just comment out the statement. --- ntfsprogs/ntfsfix.c | 24 ++++++++++++++++++++++-- ntfsprogs/ntfsmove.c | 14 +++++++++++++- ntfsprogs/ntfsresize.c | 7 ++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index a0220e6f..c6ec628a 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -264,7 +264,14 @@ static int set_dirty_flag(ntfs_volume *vol) return -1; } vol->flags = flags; - NVolSetWasDirty(vol); + + /* Porting note: libntfs-3g does not have the 'WasDirty' flag/property, + * and never touches the 'dirty' bit except when explicitly told to do + * so. Since we just wrote the VOLUME_IS_DIRTY bit to disk, and + * vol->flags is up-to-date, we can just ignore the NVolSetWasDirty + * statement. */ + /* NVolSetWasDirty(vol); */ + ntfs_log_info(OK); return 0; } @@ -515,7 +522,20 @@ int main(int argc, char **argv) } } /* So the unmount does not clear it again. */ - NVolSetWasDirty(vol); + + /* Porting note: The WasDirty flag was set here to prevent ntfs_unmount + * from clearing the dirty bit (which might have been set in + * fix_mount()). So the intention is to leave the dirty bit set. + * + * libntfs-3g does not automatically set or clear dirty flags on + * mount/unmount, this means that the assumption that the dirty flag is + * now set does not hold. So we need to set it if not already set. */ + if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags(vol, + vol->flags | VOLUME_IS_DIRTY)) { + ntfs_log_error("Error: Failed to set volume dirty flag (%d " + "(%s))!\n", errno, strerror(errno)); + } + /* Check NTFS version is ok for us (in $Volume) */ ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver, vol->minor_ver); diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index 13092701..6cfff46f 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -893,7 +893,19 @@ int main(int argc, char *argv[]) count = move_file(vol, inode, opts.location, 0); if ((count > 0) && (!opts.nodirty)) { - NVolSetWasDirty(vol); + + /* Porting note: libntfs-3g does not automatically set or clear + * dirty flags on mount/unmount. It always preserves them until + * they are explicitly changed with ntfs_volume_write_flags. + * This means that the dirty flag is possibly not set, but + * should be set. So we explicitly set it with a call to + * ntfs_volume_write_flags. */ + if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags( + vol, vol->flags | VOLUME_IS_DIRTY)) { + ntfs_log_error("Error: Failed to set volume dirty " + "flag (%d (%s))!\n", errno, strerror(errno)); + } + ntfs_log_info("Relocated %lld bytes\n", count); } if (count >= 0) diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 8f0d4e26..18dd6a45 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2297,7 +2297,12 @@ static void prepare_volume_fixup(ntfs_volume *vol) vol->flags |= VOLUME_IS_DIRTY; if (ntfs_volume_write_flags(vol, vol->flags)) perr_exit("Failed to set the volume dirty"); - NVolSetWasDirty(vol); + + /* Porting note: This flag does not exist in libntfs-3g. The dirty flag + * is never modified by libntfs-3g on unmount and we set it above. We + * can safely comment out this statement. */ + /* NVolSetWasDirty(vol); */ + if (vol->dev->d_ops->sync(vol->dev) == -1) perr_exit("Failed to sync device"); printf("Resetting $LogFile ... (this might take a while)\n"); From 2acadfd3605214b8adeb0a1d12a3a983a8af1871 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 09:43:45 +0100 Subject: [PATCH 279/289] mkntfs.c: Fixed reference to 'guid' member of ntfs_volume which does not exist in libntfs-3g. --- ntfsprogs/mkntfs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 3fc70636..5a47d556 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -4010,6 +4010,7 @@ static BOOL mkntfs_create_root_structures(void) u8 *buf_log = NULL; int buf_sds_first_size; char *buf_sds; + GUID vol_guid; ntfs_log_quiet("Creating NTFS volume structures.\n"); nr_sysfiles = 27; @@ -4357,11 +4358,11 @@ static BOOL mkntfs_create_root_structures(void) */ if (!opts.use_epoch_time) { /* Generate a GUID for the volume. */ - uuid_generate((void*)&g_vol->guid); + uuid_generate((void*)&vol_guid); } else - memset(&g_vol->guid, 0, sizeof(g_vol->guid)); + memset(&g_vol->guid, 0, sizeof(vol_guid)); #endif - if (!create_file_volume(m, root_ref, volume_flags, &g_vol->guid)) + if (!create_file_volume(m, root_ref, volume_flags, &vol_guid)) return FALSE; ntfs_log_verbose("Creating $BadClus (mft record 8)\n"); m = (MFT_RECORD*)(g_buf + 8 * g_vol->mft_record_size); From 6b65b6024e66fe7f4484473b645da9e6504dbc47 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 09:48:24 +0100 Subject: [PATCH 280/289] ntfscp.c: libntfs-3g has added an additional argument to ntfs_create (le32 securid). We pass 0 as 'securid' as this is what should be passed when there is no inheritable security descriptor. This can of course be discussed. Maybe we should inherit something? From parent? I don't know enough about this. --- ntfsprogs/ntfscp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index f6090f25..f5abc528 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -300,7 +300,7 @@ static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni, filename); return NULL; } - ni = ntfs_create(dir_ni, ufilename, ufilename_len, S_IFREG); + ni = ntfs_create(dir_ni, 0, ufilename, ufilename_len, S_IFREG); free(ufilename); return ni; } From 665555491bc1c9eb2fd9770bb23fa5d2a8df4dc9 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 09:53:46 +0100 Subject: [PATCH 281/289] ntfsundelete.h: Added missing include 'utils.h'. --- ntfsprogs/ntfsundelete.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ntfsprogs/ntfsundelete.h b/ntfsprogs/ntfsundelete.h index a213e1ad..fa27afb7 100644 --- a/ntfsprogs/ntfsundelete.h +++ b/ntfsprogs/ntfsundelete.h @@ -29,6 +29,7 @@ #include #include "list.h" +#include "utils.h" enum optmode { MODE_NONE = 0, From 6ff5d3f8a70e8e2c383251a9fabccbc6ed476b53 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 10:02:25 +0100 Subject: [PATCH 282/289] Replaced all occurrences of the libntfs mount flag NTFS_MNT_RDONLY with the corresponding libntfs-3g mount flag MS_RDONLY. --- ntfsprogs/ntfscat.c | 2 +- ntfsprogs/ntfsck.c | 2 +- ntfsprogs/ntfsclone.c | 2 +- ntfsprogs/ntfscluster.c | 2 +- ntfsprogs/ntfscmp.c | 2 +- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsdecrypt.c | 2 +- ntfsprogs/ntfsdump_logfile.c | 2 +- ntfsprogs/ntfsinfo.c | 2 +- ntfsprogs/ntfslabel.c | 2 +- ntfsprogs/ntfsls.c | 2 +- ntfsprogs/ntfsmftalloc.c | 2 +- ntfsprogs/ntfsmove.c | 2 +- ntfsprogs/ntfsresize.c | 4 ++-- ntfsprogs/ntfstruncate.c | 2 +- ntfsprogs/ntfsundelete.c | 2 +- ntfsprogs/ntfswipe.c | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index c502d1a9..68be30c3 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -410,7 +410,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { ntfs_log_perror("ERROR: couldn't mount volume"); diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c index 0464493b..5fb1ddd3 100644 --- a/ntfsprogs/ntfsck.c +++ b/ntfsprogs/ntfsck.c @@ -835,7 +835,7 @@ int main(int argc, char **argv) // at this point we know that the volume is valid enough for mounting. /* Call ntfs_device_mount() to do the actual mount. */ - vol = ntfs_device_mount(dev, NTFS_MNT_RDONLY); + vol = ntfs_device_mount(dev, MS_RDONLY); if (!vol) { ntfs_device_free(dev); return 2; diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 382badb1..0e937d91 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1603,7 +1603,7 @@ static s64 open_volume(void) { s64 device_size; - mount_volume(NTFS_MNT_RDONLY); + mount_volume(MS_RDONLY); device_size = ntfs_device_size_get(vol->dev, 1); if (device_size <= 0) diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index 568695ef..4ae4680f 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -492,7 +492,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index 45170ecd..e7f8c929 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -962,7 +962,7 @@ static ntfs_volume *mount_volume(const char *volume) "You must 'umount' it first.\n", volume); } - vol = ntfs_mount(volume, NTFS_MNT_RDONLY); + vol = ntfs_mount(volume, MS_RDONLY); if (vol == NULL) { int err = errno; diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index f5abc528..b8ed0947 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -347,7 +347,7 @@ int main(int argc, char *argv[]) } if (opts.noaction) - flags = NTFS_MNT_RDONLY; + flags = MS_RDONLY; if (opts.force) flags |= NTFS_MNT_FORCE; diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index b5ee0c89..9cd0d39c 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -1452,7 +1452,7 @@ int main(int argc, char *argv[]) return 1; } /* Mount the ntfs volume. */ - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { ntfs_log_error("Failed to mount ntfs volume. Aborting.\n"); diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index 4d42021f..094dacec 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -198,7 +198,7 @@ static int logfile_open(BOOL is_volume, const char *filename, ntfs_inode *ni; ntfs_attr *na; - vol = ntfs_mount(filename, NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC); + vol = ntfs_mount(filename, MS_RDONLY | NTFS_MNT_FORENSIC); if (!vol) log_err_exit(NULL, "Failed to mount %s: %s\n", filename, strerror(errno)); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index b59afb4d..5af51a6e 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -2252,7 +2252,7 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { printf("Failed to open '%s'.\n", opts.device); diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index 1bd2f332..a337d83b 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -395,7 +395,7 @@ int main(int argc, char **argv) opts.noaction++; vol = utils_mount_volume(opts.device, - (opts.noaction ? NTFS_MNT_RDONLY : 0) | + (opts.noaction ? MS_RDONLY : 0) | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c index 9001932b..1f08b3fa 100644 --- a/ntfsprogs/ntfsls.c +++ b/ntfsprogs/ntfsls.c @@ -651,7 +651,7 @@ int main(int argc, char **argv) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) { // FIXME: Print error... (AIA) diff --git a/ntfsprogs/ntfsmftalloc.c b/ntfsprogs/ntfsmftalloc.c index e23e39f0..951097ac 100644 --- a/ntfsprogs/ntfsmftalloc.c +++ b/ntfsprogs/ntfsmftalloc.c @@ -313,7 +313,7 @@ int main(int argc, char **argv) /* Mount the device. */ if (opts.no_action) { ntfs_log_quiet("Running in READ-ONLY mode!\n"); - ul = NTFS_MNT_RDONLY; + ul = MS_RDONLY; } else ul = 0; vol = ntfs_mount(dev_name, ul); diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index 6cfff46f..d357582f 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -875,7 +875,7 @@ int main(int argc, char *argv[]) utils_set_locale(); if (opts.noaction) - flags |= NTFS_MNT_RDONLY; + flags |= MS_RDONLY; if (opts.force) flags |= NTFS_MNT_FORCE; diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 18dd6a45..799c6139 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -488,7 +488,7 @@ static int parse_options(int argc, char **argv) opt.info++; break; case 'n': - opt.ro_flag = NTFS_MNT_RDONLY; + opt.ro_flag = MS_RDONLY; break; case 'P': opt.show_progress = 0; @@ -524,7 +524,7 @@ static int parse_options(int argc, char **argv) err++; } if (opt.info) { - opt.ro_flag = NTFS_MNT_RDONLY; + opt.ro_flag = MS_RDONLY; if (opt.bytes) { printf(NERR_PREFIX "Options --info and --size " "can't be used together.\n"); diff --git a/ntfsprogs/ntfstruncate.c b/ntfsprogs/ntfstruncate.c index 679d80d2..518f3750 100644 --- a/ntfsprogs/ntfstruncate.c +++ b/ntfsprogs/ntfstruncate.c @@ -738,7 +738,7 @@ int main(int argc, char **argv) /* Mount the device. */ if (opts.no_action) { ntfs_log_quiet("Running in READ-ONLY mode!\n"); - ul = NTFS_MNT_RDONLY; + ul = MS_RDONLY; } else ul = 0; vol = ntfs_mount(dev_name, ul); diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index 4e604eb7..3f81b62c 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -2155,7 +2155,7 @@ int main(int argc, char *argv[]) utils_set_locale(); - vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | + vol = utils_mount_volume(opts.device, MS_RDONLY | (opts.force ? NTFS_MNT_FORCE : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index 93392dce..c91dad87 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1340,7 +1340,7 @@ int main(int argc, char *argv[]) print_summary(); if (opts.info || opts.noaction) - flags = NTFS_MNT_RDONLY; + flags = MS_RDONLY; if (opts.force) flags |= NTFS_MNT_FORCE; From 18789cdeaa05afe8af1c4799e62bfd31a1fcaab9 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 10:15:35 +0100 Subject: [PATCH 283/289] Replaced all occurrences of the libntfs mount flag NTFS_MNT_FORCE with the libntfs-3g mount flag MS_RECOVER. Note: The NTFS_MNT_FORCE, in addition to what MS_RECOVER does, also bypasses the check for the 'dirty' bit in libntfs' ntfs_mount. However, this check does not exist in libntfs-3g (libntfs-3g will not check or change the dirty bit, being confident that it can handle volumes marked as 'dirty'), so in essence the same behaviour is achieved with MS_RECOVER. --- ntfsprogs/ntfscat.c | 2 +- ntfsprogs/ntfscluster.c | 2 +- ntfsprogs/ntfscp.c | 2 +- ntfsprogs/ntfsdecrypt.c | 2 +- ntfsprogs/ntfsinfo.c | 2 +- ntfsprogs/ntfslabel.c | 2 +- ntfsprogs/ntfsls.c | 2 +- ntfsprogs/ntfsmove.c | 2 +- ntfsprogs/ntfsundelete.c | 2 +- ntfsprogs/ntfswipe.c | 2 +- ntfsprogs/utils.c | 19 +++++++++++++++++-- 11 files changed, 27 insertions(+), 12 deletions(-) diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index 68be30c3..7d6aebf9 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -411,7 +411,7 @@ int main(int argc, char *argv[]) utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) { ntfs_log_perror("ERROR: couldn't mount volume"); return 1; diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index 4ae4680f..5ca12ca2 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -493,7 +493,7 @@ int main(int argc, char *argv[]) utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index b8ed0947..67f533bf 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -349,7 +349,7 @@ int main(int argc, char *argv[]) if (opts.noaction) flags = MS_RDONLY; if (opts.force) - flags |= NTFS_MNT_FORCE; + flags |= MS_RECOVER; vol = utils_mount_volume(opts.device, flags); if (!vol) { diff --git a/ntfsprogs/ntfsdecrypt.c b/ntfsprogs/ntfsdecrypt.c index 9cd0d39c..722fa553 100644 --- a/ntfsprogs/ntfsdecrypt.c +++ b/ntfsprogs/ntfsdecrypt.c @@ -1453,7 +1453,7 @@ int main(int argc, char *argv[]) } /* Mount the ntfs volume. */ vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) { ntfs_log_error("Failed to mount ntfs volume. Aborting.\n"); ntfs_rsa_private_key_release(rsa_key); diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 5af51a6e..c67b4cc5 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -2253,7 +2253,7 @@ int main(int argc, char **argv) utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) { printf("Failed to open '%s'.\n", opts.device); exit(1); diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index a337d83b..9615aa05 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -396,7 +396,7 @@ int main(int argc, char **argv) vol = utils_mount_volume(opts.device, (opts.noaction ? MS_RDONLY : 0) | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c index 1f08b3fa..698ebc65 100644 --- a/ntfsprogs/ntfsls.c +++ b/ntfsprogs/ntfsls.c @@ -652,7 +652,7 @@ int main(int argc, char **argv) utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) { // FIXME: Print error... (AIA) return 2; diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index d357582f..bb0bc9ca 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -877,7 +877,7 @@ int main(int argc, char *argv[]) if (opts.noaction) flags |= MS_RDONLY; if (opts.force) - flags |= NTFS_MNT_FORCE; + flags |= MS_RECOVER; vol = utils_mount_volume(opts.device, flags); if (!vol) { diff --git a/ntfsprogs/ntfsundelete.c b/ntfsprogs/ntfsundelete.c index 3f81b62c..4b5bb219 100644 --- a/ntfsprogs/ntfsundelete.c +++ b/ntfsprogs/ntfsundelete.c @@ -2156,7 +2156,7 @@ int main(int argc, char *argv[]) utils_set_locale(); vol = utils_mount_volume(opts.device, MS_RDONLY | - (opts.force ? NTFS_MNT_FORCE : 0)); + (opts.force ? MS_RECOVER : 0)); if (!vol) return 1; diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index c91dad87..e8980d03 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1342,7 +1342,7 @@ int main(int argc, char *argv[]) if (opts.info || opts.noaction) flags = MS_RDONLY; if (opts.force) - flags |= NTFS_MNT_FORCE; + flags |= MS_RECOVER; vol = utils_mount_volume(opts.device, flags); if (!vol) diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 947bddec..b37b88c1 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -216,7 +216,22 @@ ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags) return NULL; } - if (!utils_valid_device(device, flags & NTFS_MNT_FORCE)) + /* Porting notes: + * + * libntfs-3g does not have the 'force' flag in ntfs_mount_flags. + * The 'force' flag in libntfs bypasses two safety checks when mounting + * read/write: + * 1. Do not mount when the VOLUME_IS_DIRTY flag in + * VOLUME_INFORMATION is set. + * 2. Do not mount when the logfile is unclean. + * + * libntfs-3g only has safety check number 2. The dirty flag is simply + * ignored because we are confident that we can handle a dirty volume. + * So we treat MS_RECOVER like NTFS_MNT_FORCE, knowing that the first + * check is always bypassed. + */ + + if (!utils_valid_device(device, flags & MS_RECOVER)) return NULL; vol = ntfs_mount(device, flags); @@ -242,7 +257,7 @@ ntfs_volume * utils_mount_volume(const char *device, ntfs_mount_flags flags) * before mount, so we can only warn if the VOLUME_IS_DIRTY flag is set * in VOLUME_INFORMATION. */ if (vol->flags & VOLUME_IS_DIRTY) { - if (!(flags & NTFS_MNT_FORCE)) { + if (!(flags & MS_RECOVER)) { ntfs_log_error("%s", dirty_volume_msg); ntfs_umount(vol, FALSE); return NULL; From d52190c3cb0a79eaf8e9a7308b1dca390e414dc5 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 10:17:32 +0100 Subject: [PATCH 284/289] Fixed reference to deprecated utility 'libgnutls-config' in ntfsprogs' Makefile.am. --- ntfsprogs/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 4510ccad..a6e1049d 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -114,9 +114,9 @@ ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS) if ENABLE_CRYPTO ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h -ntfsdecrypt_LDADD = $(AM_LIBS) -ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) `libgnutls-config --libs` -ntfsdecrypt_CFLAGS = `libgnutls-config --cflags` +ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) +ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) +ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) endif # Extra targets From 3ddcb40f2360fd9b747ebe1781194016673580da Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 10:29:32 +0100 Subject: [PATCH 285/289] ntfsdump_logfile.c: Removed unnecessary reference to unsupported mount option NTFS_MNT_FORENSIC. (The mount option is pointless as we are mounting the volume in read-only mode anyway.) --- ntfsprogs/ntfsdump_logfile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ntfsprogs/ntfsdump_logfile.c b/ntfsprogs/ntfsdump_logfile.c index 094dacec..6d2a23e1 100644 --- a/ntfsprogs/ntfsdump_logfile.c +++ b/ntfsprogs/ntfsdump_logfile.c @@ -198,7 +198,10 @@ static int logfile_open(BOOL is_volume, const char *filename, ntfs_inode *ni; ntfs_attr *na; - vol = ntfs_mount(filename, MS_RDONLY | NTFS_MNT_FORENSIC); + /* Porting note: NTFS_MNT_FORENSIC is not needed when we mount + * the volume in read-only mode. No changes will be made to the + * logfile or anything else when we are in read only-mode. */ + vol = ntfs_mount(filename, MS_RDONLY); if (!vol) log_err_exit(NULL, "Failed to mount %s: %s\n", filename, strerror(errno)); From 7b62a8328632f89e1412e0d292399b5a4d1f9832 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Thu, 2 Dec 2010 10:39:00 +0100 Subject: [PATCH 286/289] utils.h: Added missing typedef leMFT_REF. --- ntfsprogs/utils.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ntfsprogs/utils.h b/ntfsprogs/utils.h index cefcd14e..949fa979 100644 --- a/ntfsprogs/utils.h +++ b/ntfsprogs/utils.h @@ -132,4 +132,8 @@ static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr) return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset)); } +/* The define 'leMFT_REF' is not present in libntfs-3g. It is only symbolic so + * typedef it to MFT_REF.*/ +typedef MFT_REF leMFT_REF; + #endif /* _NTFS_UTILS_H_ */ From 9c0c2bf633b671f8f91c26d79cff92c4b5fc4698 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Fri, 3 Dec 2010 07:50:47 +0100 Subject: [PATCH 287/289] ntfsprogs/Makefile.am: Added libgcrypt's CFLAGS and LIBS when building ntfsdecrypt. --- ntfsprogs/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index a6e1049d..b7498283 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -114,9 +114,9 @@ ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS) if ENABLE_CRYPTO ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h -ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) +ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) $(LIBGCRYPT_LIBS) ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) -ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) +ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS) endif # Extra targets From 86eb7504ebaa31feb6c25d8874cae9fc4752f9a5 Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Fri, 3 Dec 2010 07:51:56 +0100 Subject: [PATCH 288/289] gnome-vfs-method.c: Fixed one occurrence of NTFS_MNT_RDONLY. --- libntfs/gnome-vfs-method.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libntfs/gnome-vfs-method.c b/libntfs/gnome-vfs-method.c index 317a514e..3b656ae4 100644 --- a/libntfs/gnome-vfs-method.c +++ b/libntfs/gnome-vfs-method.c @@ -163,7 +163,7 @@ static GnomeVFSResult libntfs_gnomevfs_uri_parent_init( } if (!(volume = ntfs_mount(uri->parent->text, - NTFS_MNT_RDONLY))) { + MS_RDONLY))) { g_free(uri_parent_string); return GNOME_VFS_ERROR_WRONG_FORMAT; } From 78b40e4b4c23c6965570f60e42044ce08481f8cf Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Fri, 3 Dec 2010 07:52:31 +0100 Subject: [PATCH 289/289] mkntfs.c: Fixed two references to missing member 'guid' in 'ntfs_volume'. --- ntfsprogs/mkntfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 5a47d556..8bc38c1d 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -4360,7 +4360,7 @@ static BOOL mkntfs_create_root_structures(void) /* Generate a GUID for the volume. */ uuid_generate((void*)&vol_guid); } else - memset(&g_vol->guid, 0, sizeof(vol_guid)); + memset(&vol_guid, 0, sizeof(vol_guid)); #endif if (!create_file_volume(m, root_ref, volume_flags, &vol_guid)) return FALSE; @@ -4525,7 +4525,7 @@ static BOOL mkntfs_create_root_structures(void) g_vol->indx_record_size); #ifdef ENABLE_UUID if (!err) - err = index_obj_id_insert(m, &g_vol->guid, + err = index_obj_id_insert(m, &vol_guid, MK_LE_MREF(FILE_Volume, FILE_Volume)); #endif if (err < 0) {