diff --git a/ChangeLog b/ChangeLog index 76a3569b..5d1efc22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -58,6 +58,15 @@ xx/xx/2005 - 1.12.2-WIP - ntfsinfo: dump index attribute keys. (Szaka) - mkntfs: don't fill the last $MFT cluster with empty MFT records. This is needed to conform to Windows' format behavior. (Szaka) + - Add @flags field to struct ntfs_inode. Remove NIno{Sparse,Compressed, + Encrypted}, update all users to use @(ntfs_inode)->flags. (Yura) + - Make @(ntfs_inode)->data_size and @(ntfs_inode)->allocated_size to + always contain valid value. (Yura) + - Always set correct file size and attributes in ntfs_link(). (Yura) + - Add info about Interix special files (symbolic links, character and + block devices, FIFOs and sockets) to layout.h. Teech ntfsmount to + handle them. (Yura) + - Fix allocated data size for resident attributes. (Yura) 10/10/2005 - 1.12.1 - Minor fix to location of mount.ntfs-fuse and mkfs.ntfs. diff --git a/include/ntfs/attrib.h b/include/ntfs/attrib.h index c681ab1a..51f24ee4 100644 --- a/include/ntfs/attrib.h +++ b/include/ntfs/attrib.h @@ -203,30 +203,30 @@ typedef enum { #define NAttrSetNonResident(na) set_nattr_flag(na, NonResident) #define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident) -#define GenNAttrIno(flag) \ -static inline int NAttr##flag(ntfs_attr *na) \ +#define GenNAttrIno(func_name,flag) \ +static inline int NAttr##func_name(ntfs_attr *na) \ { \ if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - return NIno##flag(na->ni); \ + return (na->ni->flags & FILE_ATTR_##flag); \ return 0; \ } \ -static inline void NAttrSet##flag(ntfs_attr *na) \ +static inline void NAttrSet##func_name(ntfs_attr *na) \ { \ if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - NInoSet##flag(na->ni); \ + na->ni->flags |= FILE_ATTR_##flag; \ else \ ntfs_log_trace("BUG! Should be called only for "\ "unnamed data attribute.\n"); \ } \ -static inline void NAttrClear##flag(ntfs_attr *na) \ +static inline void NAttrClear##func_name(ntfs_attr *na) \ { \ if (na->type == AT_DATA && na->name == AT_UNNAMED) \ - NInoClear##flag(na->ni); \ + na->ni->flags &= ~FILE_ATTR_##flag; \ } -GenNAttrIno(Compressed) -GenNAttrIno(Encrypted) -GenNAttrIno(Sparse) +GenNAttrIno(Compressed, COMPRESSED) +GenNAttrIno(Encrypted, ENCRYPTED) +GenNAttrIno(Sparse, SPARSE_FILE) /* * Union of all known attribute values. For convenience. Used in the attr diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 2dde1afe..22d35c89 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -45,9 +45,6 @@ typedef enum { NI_AttrList, /* 1: Mft record contains an attribute list. */ NI_AttrListDirty, /* 1: Attribute list needs to be written to the mft record and then to disk. */ - NI_Compressed, /* 1: Inode is compressed. */ - NI_Encrypted, /* 1: Inode is encrypted. */ - NI_Sparse, /* 1: Inode is sparse. */ NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated in the index. */ } ntfs_inode_state_bits; @@ -87,18 +84,6 @@ typedef enum { #define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty) #define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty) -#define NInoCompressed(ni) test_nino_flag(ni, Compressed) -#define NInoSetCompressed(ni) set_nino_flag(ni, Compressed) -#define NInoClearCompressed(ni) clear_nino_flag(ni, Compressed) - -#define NInoEncrypted(ni) test_nino_flag(ni, Encrypted) -#define NInoSetEncrypted(ni) set_nino_flag(ni, Encrypted) -#define NInoClearEncrypted(ni) clear_nino_flag(ni, Encrypted) - -#define NInoSparse(ni) test_nino_flag(ni, Sparse) -#define NInoSetSparse(ni) set_nino_flag(ni, Sparse) -#define NInoClearSparse(ni) clear_nino_flag(ni, Sparse) - #define NInoFileNameDirty(ni) \ test_nino_flag(ni, FileNameDirty) #define NInoFileNameSetDirty(ni) \ @@ -148,7 +133,7 @@ struct _ntfs_inode { void *private_data; /* ntfs_dt containing this inode */ int ref_count; - /* Below 2 fields needed to update indexes. They valid if != -1. */ + /* Below fields are valid only for base inode. */ s64 data_size; s64 allocated_size; diff --git a/include/ntfs/layout.h b/include/ntfs/layout.h index ca981a4d..351aeb71 100644 --- a/include/ntfs/layout.h +++ b/include/ntfs/layout.h @@ -852,9 +852,10 @@ typedef enum { is used to obtain all flags that are valid for reading. */ FILE_ATTR_VALID_SET_FLAGS = const_cpu_to_le32(0x000031a7), /* FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the - F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, - F_A_COMPRESSED and F_A_ENCRYPTED and preserves the rest. This mask - is used to to obtain all flags that are valid for setting. */ + FILE_ATTR_DEVICE, FILE_ATTR_DIRECTORY, FILE_ATTR_SPARSE_FILE, + FILE_ATTR_REPARSE_POINT, FILE_ATRE_COMPRESSED and FILE_ATTR_ENCRYPTED + and preserves the rest. This mask is used to to obtain all flags that + are valid for setting. */ /* * These flags are only present in the FILE_NAME attribute (in the diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 309b5511..72fe9c4a 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -409,9 +409,8 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, 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, l, l, - cs ? sle64_to_cpu(a->compressed_size) : 0, - cs ? a->compression_unit : 0); + a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, + cs ? (l + 7) & ~7 : 0, 0); } ntfs_attr_put_search_ctx(ctx); return na; @@ -3702,10 +3701,10 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) if (!ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, newsize)) { /* Update the ntfs attribute structure, too. */ - na->allocated_size = na->data_size = - na->initialized_size = newsize; + na->data_size = na->initialized_size = newsize; + na->allocated_size = (newsize + 7) & ~7; if (NAttrCompressed(na) || NAttrSparse(na)) - na->compressed_size = newsize; + na->compressed_size = na->allocated_size; goto resize_done; } /* Error! If not enough space, just continue. */ @@ -4027,8 +4026,8 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) NAttrClearCompressed(na); NAttrClearSparse(na); NAttrClearEncrypted(na); - na->allocated_size = na->initialized_size = na->compressed_size = - na->data_size; + na->initialized_size = na->data_size; + na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7; na->compression_block_size = 0; na->compression_block_size_bits = na->compression_block_clusters = 0; return 0; diff --git a/libntfs/dir.c b/libntfs/dir.c index 6e61686f..f822bee7 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1465,8 +1465,11 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) le16_to_cpu(dir_ni->mrec->sequence_number)); fn->file_name_length = name_len; fn->file_name_type = FILE_NAME_POSIX; + fn->file_attributes = ni->flags; if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) - fn->file_attributes = FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT; + fn->file_attributes |= FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT; + fn->allocated_size = cpu_to_sle64(ni->allocated_size); + fn->data_size = cpu_to_sle64(ni->data_size); fn->creation_time = utc2ntfs(ni->creation_time); fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); @@ -1502,15 +1505,6 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) /* Increment hard links count. */ ni->mrec->link_count = cpu_to_le16(le16_to_cpu( ni->mrec->link_count) + 1); - /* - * Do not set attributes and file size, instead of this mark filenames - * dirty to force attribute and size update during sync. - * NOTE: File size may will be not updated and not all attributes will - * be set, but it is acceptable since windows driver does not update - * all file names when one of the hard links changed. - * FIXME: It will be nice to update them all. - */ - NInoFileNameSetDirty(ni); /* Done! */ ntfs_inode_mark_dirty(ni); free(fn); diff --git a/libntfs/inode.c b/libntfs/inode.c index 2ac28942..bca5c3a1 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -145,8 +145,6 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) goto err_out; } ni->mft_no = MREF(mref); - ni->data_size = -1; - ni->allocated_size = -1; ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) goto err_out; @@ -160,12 +158,6 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); - if (std_info->file_attributes & FILE_ATTR_COMPRESSED) - NInoSetCompressed(ni); - if (std_info->file_attributes & FILE_ATTR_ENCRYPTED) - NInoSetEncrypted(ni); - if (std_info->file_attributes & FILE_ATTR_SPARSE_FILE) - NInoSetSparse(ni); ni->flags = std_info->file_attributes; ni->creation_time = ntfs2utc(std_info->creation_time); ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time); @@ -176,9 +168,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) ctx)) { if (errno != ENOENT) goto put_err_out; - /* Attribute list attribute not present so we are done. */ - ntfs_attr_put_search_ctx(ctx); - return ni; + /* Attribute list attribute does not present. */ + goto get_size; } NInoSetAttrList(ni); l = ntfs_get_attribute_value_length(ctx->attr); @@ -199,6 +190,27 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) err = EIO; goto put_err_out; } +get_size: + if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + if (errno != ENOENT) + goto put_err_out; + /* Directory or special file. */ + ni->data_size = ni->allocated_size = 0; + } else { + if (ctx->attr->non_resident) { + ni->data_size = sle64_to_cpu(ctx->attr->data_size); + if (ctx->attr->flags & + (ATTR_IS_COMPRESSED & ATTR_IS_SPARSE)) + ni->allocated_size = sle64_to_cpu( + ctx->attr->compressed_size); + else + ni->allocated_size = sle64_to_cpu( + ctx->attr->allocated_size); + } else { + ni->data_size = le32_to_cpu(ctx->attr->value_length); + ni->allocated_size = (ni->data_size + 7) & ~7; + } + } ntfs_attr_put_search_ctx(ctx); return ni; put_err_out: @@ -475,18 +487,7 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); - if (NInoCompressed(ni)) - std_info->file_attributes |= FILE_ATTR_COMPRESSED; - else - std_info->file_attributes &= ~FILE_ATTR_COMPRESSED; - if (NInoEncrypted(ni)) - std_info->file_attributes |= FILE_ATTR_ENCRYPTED; - else - std_info->file_attributes &= ~FILE_ATTR_ENCRYPTED; - if (NInoSparse(ni)) - std_info->file_attributes |= FILE_ATTR_SPARSE_FILE; - else - std_info->file_attributes &= ~FILE_ATTR_SPARSE_FILE; + std_info->file_attributes = ni->flags; std_info->creation_time = utc2ntfs(ni->creation_time); std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time); std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); @@ -562,22 +563,11 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni) } /* Update flags and file size. */ fn = (FILE_NAME_ATTR *)ictx->data; - if (NInoCompressed(ni)) - fn->file_attributes |= FILE_ATTR_COMPRESSED; - else - fn->file_attributes &= ~FILE_ATTR_COMPRESSED; - if (NInoEncrypted(ni)) - fn->file_attributes |= FILE_ATTR_ENCRYPTED; - else - fn->file_attributes &= ~FILE_ATTR_ENCRYPTED; - if (NInoSparse(ni)) - fn->file_attributes |= FILE_ATTR_SPARSE_FILE; - else - fn->file_attributes &= ~FILE_ATTR_SPARSE_FILE; - if (ni->allocated_size != -1) - fn->allocated_size = cpu_to_sle64(ni->allocated_size); - if (ni->data_size != -1) - fn->data_size = cpu_to_sle64(ni->data_size); + fn->file_attributes = + (fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) | + (ni->flags & FILE_ATTR_VALID_FLAGS); + fn->allocated_size = cpu_to_sle64(ni->allocated_size); + fn->data_size = cpu_to_sle64(ni->data_size); fn->creation_time = utc2ntfs(ni->creation_time); fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); diff --git a/libntfs/mft.c b/libntfs/mft.c index d33fb91e..32974328 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -1459,7 +1459,8 @@ mft_rec_already_initialized: /* Make sure the allocated inode is written out to disk later. */ ntfs_inode_mark_dirty(ni); /* Initialize time, allocated and data size in ntfs_inode struct. */ - ni->data_size = ni->allocated_size = -1; + ni->data_size = ni->allocated_size = 0; + ni->flags = 0; ni->creation_time = ni->last_data_change_time = ni->last_mft_change_time = ni->last_access_time = time(NULL); diff --git a/ntfsprogs/ntfsmount.8.in b/ntfsprogs/ntfsmount.8.in index 68b94b7a..c1625e6c 100644 --- a/ntfsprogs/ntfsmount.8.in +++ b/ntfsprogs/ntfsmount.8.in @@ -22,9 +22,11 @@ is recommended, but not mandatory. .TP .B Fully implemented ntfsmount features are: -* Read-only access to normal, sparse and compressed files. +* Read-write access to normal and sparse files. -* Overwrite normal and sparse files *with* changes to size. +* Read-only access to compressed files. + +* Access to special Interix files (symlinks, devices, FIFOs). * List/Read/Write/Add/Remove named data streams. diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 6ac47667..1925da85 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -312,13 +312,40 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) } stbuf->st_nlink = 1; /* Needed for correct find work. */ } else { - /* Regular or INTX file. */ + /* Regular or Interix (INTX) file. */ stbuf->st_mode = S_IFREG; - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (na) { - /* Check whether it's special INTX file. */ - if ((ni->flags & FILE_ATTR_SYSTEM) && na->data_size <= - sizeof(INTX_FILE_TYPES) + sizeof( + stbuf->st_size = ni->data_size; + stbuf->st_blocks = ni->allocated_size >> vol->sector_size_bits; + stbuf->st_mode |= (0777 & ~ctx->fmask); + 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 = na->allocated_size >> + vol->sector_size_bits; + } + /* Check whether it's Interix fifo or socket. */ + if (!(ni->flags & FILE_ATTR_HIDDEN) && + !stream_name_len) { + /* FIFO. */ + if (na->data_size == 0) + stbuf->st_mode = S_IFIFO; + /* Socket link. */ + if (na->data_size == 1) + stbuf->st_mode = S_IFSOCK; + } + /* + * Check wheter it's Interix symbolic link, block or + * character device. + */ + if (na->data_size <= sizeof(INTX_FILE_TYPES) + sizeof( ntfschar) * MAX_PATH && na->data_size > sizeof(INTX_FILE_TYPES) && !stream_name_len) { @@ -359,18 +386,8 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf) stbuf->st_mode = S_IFLNK; free(intx_file); } - stbuf->st_size = na->data_size; - stbuf->st_blocks = na->allocated_size >> - vol->sector_size_bits; ntfs_attr_close(na); - } else { - stbuf->st_size = 0; - stbuf->st_blocks = 0; - if (stream_name_len) - res = -ENOENT; } - stbuf->st_mode |= (0777 & ~ctx->fmask); - stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count); } stbuf->st_uid = ctx->uid; stbuf->st_gid = ctx->gid;