From 2a104d8eda4aaf6b9b589bf58d5f164c13f0cb5e Mon Sep 17 00:00:00 2001 From: antona Date: Sat, 24 Sep 2005 22:54:55 +0000 Subject: [PATCH] Megapatch!!! Check evecrything!!! I probably broke everything!!! --- ChangeLog | 11 +- include/ntfs/unistr.h | 2 + include/ntfs/volume.h | 5 +- libntfs/Makefile.am | 2 +- libntfs/attrib.c | 48 ++++--- libntfs/unistr.c | 66 +++++++++ libntfs/volume.c | 92 ++++++------ ntfsprogs/cluster.c | 2 +- ntfsprogs/mkntfs.c | 309 +++++++++++++++++++++++++++++++++++++++-- ntfsprogs/ntfsclone.c | 6 +- ntfsprogs/ntfscmp.c | 8 +- ntfsprogs/ntfsfix.8.in | 7 +- ntfsprogs/ntfsfix.c | 33 ----- ntfsprogs/ntfsinfo.c | 2 +- ntfsprogs/ntfslabel.c | 36 ++--- ntfsprogs/ntfsls.c | 4 +- ntfsprogs/ntfsmove.c | 4 +- ntfsprogs/ntfsresize.c | 2 +- ntfsprogs/ntfsrm.c | 4 +- ntfsprogs/ntfswipe.c | 5 - ntfsprogs/utils.c | 2 +- 21 files changed, 488 insertions(+), 162 deletions(-) diff --git a/ChangeLog b/ChangeLog index 86aa397d..e33b3424 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,13 +44,22 @@ xx/xx/2005 - 1.12.0-WIP - ntfsmount: Fix 'df' output. (Yuval) - Support journals which have been modified by chkdsk. (Anton, Szaka) - Support journals ($LogFile) with only one restart page as well as - journals with two different restart pages. (Anton, Szaka) + journals with two different restart pages. (Anton, Szaka) - Add @val parameter to ntfs_attr_add and @val and @size parameters to ntfs_resident_attr_record_add. (Yura) - Fix attribute list adding for always resident attributes. (Yura) - New API for hard link creating: dir.[ch]::ntfs_link. (Yura) - ntfsresize: emphasize that disk partitioning must use sector as the unit instead of cylinder to avoid shifting of the partition. (Szaka) + - Rename API: ntfs_volume_set_flags() as it is misleading. It does not + set a flag, it overwrites the flags! Rename it to + ntfs_volume_write_flags() and clean it up a lot. Update all + callers. (Anton) + - Change ntfsfix to no longer set the volume dirty. + - Change everything to supply an ntfs_inode and NULL for mft record + when calling ntfs_attr_get_search_ctx() except a very few cases which + genuinely need this functionality as they work on a too low level. + Make sure all those cases are ok. 08/08/2005 - 1.11.2 - ntfsdecrypt now works and lots of fixes and improvements. diff --git a/include/ntfs/unistr.h b/include/ntfs/unistr.h index 4dea192a..7fdbc678 100644 --- a/include/ntfs/unistr.h +++ b/include/ntfs/unistr.h @@ -61,5 +61,7 @@ extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs, int outs_len); extern int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len); +extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len); + #endif /* defined _NTFS_UNISTR_H */ diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 95593a6c..3c126732 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -117,6 +117,8 @@ struct _ntfs_volume { char *vol_name; /* Name of the volume. */ unsigned long state; /* NTFS specific flags describing this volume. See ntfs_volume_state_bits above. */ + + ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */ u8 major_ver; /* Ntfs major version of volume. */ u8 minor_ver; /* Ntfs minor version of volume. */ u16 flags; /* Bit array of VOLUME_* flags. */ @@ -198,7 +200,8 @@ 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_set_flags(ntfs_volume *v, const u16 flags); + +extern int ntfs_volume_write_flags(ntfs_volume *v, const u16 flags); #endif /* defined _NTFS_VOLUME_H */ diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index 40cc0fd9..12282845 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -25,7 +25,7 @@ # - If the interface is the same as the previous version, change to C:R+1:A # -LTVERSION_LIBNTFS = 7:1:0 +LTVERSION_LIBNTFS = 8:0:0 LTVERSION_LIBNTFS_GNOMEVFS = 1:0:0 diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 3c04870c..4e6f2bf0 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1559,10 +1559,23 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) { ATTR_RECORD *a; - ntfs_volume *vol = ctx->ntfs_ino->vol; - ntfschar *upcase = vol->upcase; - u32 upcase_len = vol->upcase_len; + ntfs_volume *vol; + ntfschar *upcase; + u32 upcase_len; + if (ctx->ntfs_ino) { + vol = ctx->ntfs_ino->vol; + upcase = vol->upcase; + upcase_len = vol->upcase_len; + } else { + if (name) { + errno = EINVAL; + return -1; + } + vol = NULL; + upcase = NULL; + upcase_len = 0; + } /* * Iterate over attributes in mft record starting at @ctx->attr, or the * attribute following that, if @ctx->is_first is TRUE. @@ -2196,7 +2209,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, static __inline__ void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, ntfs_inode *ni, MFT_RECORD *mrec) { - if (ni && !mrec) + if (!mrec) mrec = ni->mrec; ctx->mrec = mrec; /* Sanity checks are performed elsewhere. */ @@ -2245,19 +2258,22 @@ void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) * Allocate a new attribute search context, initialize it with @ni and @mrec, * and return it. Return NULL on error with errno set to ENOMEM. * - * @ni can be NULL if the search context is only going to be used for searching - * for the attribute list attribute and for searches ignoring the contents of - * the attribute list attribute. + * @mrec can be NULL, in which case the mft record is taken from @ni. * - * If @ni is specified, @mrec can be NULL, in which case the mft record is - * taken from @ni. - * - * If both @ni and @mrec are specified, the mft record is taken from @mrec and - * the value of @ni->mrec is ignored. + * Note: For low level utilities which know what they are doing we allow @ni to + * be NULL and @mrec to be set. Do NOT do this unless you understand the + * implications!!! For example it is no longer safe to call ntfs_attr_lookup() + * if you */ ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) { - ntfs_attr_search_ctx *ctx = malloc(sizeof(ntfs_attr_search_ctx)); + ntfs_attr_search_ctx *ctx; + + if (!ni && !mrec) { + errno = EINVAL; + return NULL; + } + ctx = malloc(sizeof(ntfs_attr_search_ctx)); if (ctx) ntfs_attr_init_search_ctx(ctx, ni, mrec); return ctx; @@ -2530,7 +2546,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, } /* Locate place where record should be. */ - ctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; if (!ntfs_attr_lookup(type, name, name_len, @@ -2655,7 +2671,7 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, } /* Locate place where record should be. */ - ctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; if (!ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, @@ -3318,7 +3334,7 @@ int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) /* Find place in MFT record where attribute will be moved. */ a = ctx->attr; - nctx = ntfs_attr_get_search_ctx(NULL, ni->mrec); + nctx = ntfs_attr_get_search_ctx(ni, NULL); if (!nctx) { err = errno; Dprintf("%s(): Couldn't obtain search context.\n", diff --git a/libntfs/unistr.c b/libntfs/unistr.c index 7fc7f64f..cb46dd2e 100644 --- a/libntfs/unistr.c +++ b/libntfs/unistr.c @@ -591,3 +591,69 @@ err_out: } return -1; } + +/** + * ntfs_upcase_table_build - build the default upcase table for NTFS + * @uc: destination buffer where to store the built table + * @uc_len: size of destination buffer in bytes + * + * ntfs_upcase_table_build() builds the default upcase table for NTFS and + * stores it in the caller supplied buffer @uc of size @uc_len. + * + * Note, @uc_len must be at least 128kiB in size or bad things will happen! + */ +void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) +{ + static int uc_run_table[][3] = { /* Start, End, Add */ + {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, + {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, + {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, + {0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128}, + {0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112}, + {0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126}, + {0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8}, + {0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8}, + {0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8}, + {0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7}, + {0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16}, + {0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26}, + {0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32}, + {0} + }; + static int uc_dup_table[][2] = { /* Start, End */ + {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, + {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, + {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, + {0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9}, + {0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95}, + {0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9}, + {0} + }; + static int uc_byte_table[][2] = { /* Offset, Value */ + {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, + {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, + {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, + {0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F}, + {0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9}, + {0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE}, + {0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7}, + {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197}, + {0} + }; + int i, r; + + memset((char*)uc, 0, uc_len); + uc_len >>= 1; + if (uc_len > 65536) + uc_len = 65536; + for (i = 0; (u32)i < uc_len; i++) + uc[i] = i; + for (r = 0; uc_run_table[r][0]; r++) + for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) + uc[i] += uc_run_table[r][2]; + for (r = 0; uc_dup_table[r][0]; r++) + for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) + uc[i + 1]--; + for (r = 0; uc_byte_table[r][0]; r++) + uc[uc_byte_table[r][0]] = uc_byte_table[r][1]; +} diff --git a/libntfs/volume.c b/libntfs/volume.c index f5ddff7a..ceb75af8 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -79,6 +79,8 @@ ntfs_volume *ntfs_volume_alloc(void) */ static void __ntfs_volume_release(ntfs_volume *v) { + if (v->vol_ni && NInoDirty(v->vol_ni)) + ntfs_inode_close(v->vol_ni); if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni)) ntfs_inode_sync(v->lcnbmp_ni); if (v->lcnbmp_na) @@ -166,7 +168,7 @@ static int ntfs_mft_load(ntfs_volume *vol) Dputs("Error: $MFT has invalid magic."); goto io_error_exit; } - ctx = ntfs_attr_get_search_ctx(vol->mft_ni, mb); + ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL); if (!ctx) { Dperror("Failed to allocate attribute search context"); goto error_exit; @@ -416,6 +418,15 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long rwflag) 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) { + Dperror("Error allocating memory for upcase table."); + goto error_exit; + } + ntfs_upcase_table_build(vol->upcase, + vol->upcase_len * sizeof(ntfschar)); if ((rwflag & MS_RDONLY) == MS_RDONLY) NVolSetReadOnly(vol); Dprintf("Reading bootsector... "); @@ -889,12 +900,16 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) errno = EINVAL; goto error_exit; } - vol->upcase_len = na->data_size >> 1; - vol->upcase = (ntfschar*)malloc(na->data_size); - if (!vol->upcase) { - Dputs(FAILED); - Dputs("Not enough memory to load $UpCase."); - goto error_exit; + if (vol->upcase_len != na->data_size >> 1) { + vol->upcase_len = na->data_size >> 1; + /* Throw away default table. */ + free(vol->upcase); + vol->upcase = (ntfschar*)malloc(na->data_size); + if (!vol->upcase) { + Dputs(FAILED); + Dputs("Not enough memory to load $UpCase."); + goto error_exit; + } } /* Read in the $DATA attribute value into the buffer. */ l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); @@ -916,14 +931,14 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) * vol structure accordingly. */ Dprintf("Loading $Volume... "); - ni = ntfs_inode_open(vol, FILE_Volume); - if (!ni) { + vol->vol_ni = ntfs_inode_open(vol, FILE_Volume); + if (!vol->vol_ni) { Dputs(FAILED); Dperror("Failed to open inode"); goto error_exit; } /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */ - ctx = ntfs_attr_get_search_ctx(ni, NULL); + ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { Dputs(FAILED); Dperror("Failed to allocate attribute search context"); @@ -1033,9 +1048,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) Dputs(OK); ntfs_attr_put_search_ctx(ctx); ctx = NULL; - if (ntfs_inode_close(ni)) - Dperror("Failed to close inode, leaking memory"); - /* Now load the attribute definitions from $AttrDef. */ Dprintf("Loading $AttrDef... "); ni = ntfs_inode_open(vol, FILE_AttrDef); @@ -1080,7 +1092,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag) ntfs_attr_close(na); if (ntfs_inode_close(ni)) Dperror("Failed to close inode, leaking memory"); - /* * Check for dirty logfile and hibernated Windows. * We care only about read-write mounts. @@ -1429,7 +1440,7 @@ error_exit: } /** - * ntfs_volume_set_flags - set the flags of an ntfs volume + * ntfs_volume_write_flags - set the flags of an ntfs volume * @vol: ntfs volume where we set the volume flags * @flags: new flags * @@ -1438,37 +1449,22 @@ error_exit: * * Return 0 if successful and -1 if not with errno set to the error code. */ -int ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) +int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags) { - MFT_RECORD *m = NULL; - ATTR_RECORD *r; + ATTR_RECORD *a; VOLUME_INFORMATION *c; ntfs_attr_search_ctx *ctx; int ret = -1; /* failure */ - if (!vol) { + if (!vol || !vol->vol_ni) { errno = EINVAL; return -1; } - - if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) { - Dperror("Failed to read $Volume"); - return -1; - } - - /* Sanity check */ - if (!(m->flags & MFT_RECORD_IN_USE)) { - Dprintf("Error: $Volume has been deleted. Cannot " - "handle this yet. Run chkdsk to fix this.\n"); - errno = EIO; - goto err_exit; - } - /* Get a pointer to the volume information attribute. */ - ctx = ntfs_attr_get_search_ctx(NULL, m); + ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { Dperror("Failed to allocate attribute search context"); - goto err_exit; + return -1; } if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { @@ -1476,40 +1472,36 @@ int ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags) "$Volume!"); goto err_out; } - r = ctx->attr; + a = ctx->attr; /* Sanity check. */ - if (r->non_resident) { + if (a->non_resident) { Dputs("Error: Attribute $VOLUME_INFORMATION must be resident " "(and it isn't)!"); errno = EIO; goto err_out; } /* Get a pointer to the value of the attribute. */ - c = (VOLUME_INFORMATION*)(le16_to_cpu(r->value_offset) + (char*)r); + c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); /* Sanity checks. */ - if ((char*)c + le32_to_cpu(r->value_length) > - le16_to_cpu(m->bytes_in_use) + (char*)m || - le16_to_cpu(r->value_offset) + - le32_to_cpu(r->value_length) > le32_to_cpu(r->length)) { + if ((char*)c + le32_to_cpu(a->value_length) > + le16_to_cpu(ctx->mrec->bytes_in_use) + + (char*)ctx->mrec || le16_to_cpu(a->value_offset) + + le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) { Dputs("Error: Attribute $VOLUME_INFORMATION in $Volume is " "corrupt!"); errno = EIO; goto err_out; } /* Set the volume flags. */ - vol->flags = c->flags = cpu_to_le16(flags); - - if (ntfs_mft_record_write(vol, FILE_Volume, m)) { + vol->flags = c->flags = flags & VOLUME_FLAGS_MASK; + /* Write them to disk. */ + ntfs_inode_mark_dirty(vol->vol_ni); + if (ntfs_inode_sync(vol->vol_ni)) { Dperror("Error writing $Volume"); goto err_out; } - ret = 0; /* success */ err_out: ntfs_attr_put_search_ctx(ctx); -err_exit: - if (m) - free(m); return ret; } - diff --git a/ntfsprogs/cluster.c b/ntfsprogs/cluster.c index 15a7895a..ce83aa0d 100644 --- a/ntfsprogs/cluster.c +++ b/ntfsprogs/cluster.c @@ -81,7 +81,7 @@ int cluster_find (ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void Vprintf ("Inode: %llu\n", (unsigned long long) m_ctx->inode->mft_no); - a_ctx = ntfs_attr_get_search_ctx (NULL, m_ctx->inode->mrec); + a_ctx = ntfs_attr_get_search_ctx (m_ctx->inode, NULL); while ((rec = find_attribute (AT_UNUSED, a_ctx))) { diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index f368a06e..d5e50db5 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -1180,6 +1180,297 @@ err_end: return NULL; } +/** + * Internal: + * + * ntfs_attr_find - find (next) attribute in mft record + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) + * @val: attribute value to find (optional, resident attributes only) + * @val_len: attribute value length + * @ctx: search context with mft record and attribute to search from + * + * You shouldn't need to call this function directly. Use lookup_attr() instead. + * + * ntfs_attr_find() takes a search context @ctx as parameter and searches the + * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an + * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() + * returns 0 and @ctx->attr will point to the found attribute. + * + * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and + * @ctx->attr will point to the attribute before which the attribute being + * searched for would need to be inserted if such an action were to be desired. + * + * On actual error, ntfs_attr_find() returns -1 with errno set to the error + * code but not to ENOENT. In this case @ctx->attr is undefined and in + * particular do not rely on it not changing. + * + * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it + * is FALSE, the search begins after @ctx->attr. + * + * If @type is AT_UNUSED, return the first found attribute, i.e. one can + * enumerate all attributes by setting @type to AT_UNUSED and then calling + * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to + * indicate that there are no more entries. During the enumeration, each + * successful call of ntfs_attr_find() will return the next attribute in the + * mft record @ctx->mrec. + * + * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. + * AT_END is not a valid attribute, its length is zero for example, thus it is + * safer to return error instead of success in this case. This also allows us + * to interoperate cleanly with ntfs_external_attr_find(). + * + * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present + * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, + * match both named and unnamed attributes. + * + * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and + * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record + * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at + * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case + * sensitive. When @name is present, @name_len is the @name length in Unicode + * characters. + * + * If @name is not present (NULL), we assume that the unnamed attribute is + * being searched for. + * + * Finally, the resident attribute value @val is looked for, if present. + * If @val is not present (NULL), @val_len is ignored. + * + * ntfs_attr_find() only searches the specified mft record and it ignores the + * presence of an attribute list attribute (unless it is the one being searched + * for, obviously). If you need to take attribute lists into consideration, use + * ntfs_attr_lookup() instead (see below). This also means that you cannot use + * ntfs_attr_find() to search for extent records of non-resident attributes, as + * extents with lowest_vcn != 0 are usually described by the attribute list + * attribute only. - Note that it is possible that the first extent is only in + * the attribute list while the last extent is in the base mft record, so don't + * rely on being able to find the first extent in the base mft record. + * + * Warning: Never use @val when looking for attribute types which can be + * non-resident as this most likely will result in a crash! + */ +static int mkntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) +{ + ATTR_RECORD *a; + ntfschar *upcase = vol->upcase; + u32 upcase_len = vol->upcase_len; + + /* + * Iterate over attributes in mft record starting at @ctx->attr, or the + * attribute following that, if @ctx->is_first is TRUE. + */ + if (ctx->is_first) { + a = ctx->attr; + ctx->is_first = FALSE; + } else + a = (ATTR_RECORD*)((char*)ctx->attr + + le32_to_cpu(ctx->attr->length)); + for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { + if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + + le32_to_cpu(ctx->mrec->bytes_allocated)) + break; + ctx->attr = a; + if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > + le32_to_cpu(type))) || + (a->type == AT_END)) { + errno = ENOENT; + return -1; + } + if (!a->length) + break; + /* If this is an enumeration return this attribute. */ + if (type == AT_UNUSED) + return 0; + if (a->type != type) + continue; + /* + * If @name is AT_UNNAMED we want an unnamed attribute. + * If @name is present, compare the two names. + * Otherwise, match any attribute. + */ + if (name == AT_UNNAMED) { + /* The search failed if the found attribute is named. */ + if (a->name_length) { + errno = ENOENT; + return -1; + } + } else if (name && !ntfs_names_are_equal(name, name_len, + (ntfschar*)((char*)a + le16_to_cpu(a->name_offset)), + a->name_length, ic, upcase, upcase_len)) { + register int rc; + + rc = ntfs_names_collate(name, name_len, + (ntfschar*)((char*)a + + le16_to_cpu(a->name_offset)), + a->name_length, 1, IGNORE_CASE, + upcase, upcase_len); + /* + * If @name collates before a->name, there is no + * matching attribute. + */ + if (rc == -1) { + errno = ENOENT; + return -1; + } + /* If the strings are not equal, continue search. */ + if (rc) + continue; + rc = ntfs_names_collate(name, name_len, + (ntfschar*)((char*)a + + le16_to_cpu(a->name_offset)), + a->name_length, 1, CASE_SENSITIVE, + upcase, upcase_len); + if (rc == -1) { + errno = ENOENT; + return -1; + } + if (rc) + continue; + } + /* + * The names match or @name not present and attribute is + * unnamed. If no @val specified, we have found the attribute + * and are done. + */ + if (!val) + return 0; + /* @val is present; compare values. */ + else { + register int rc; + + rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), + min(val_len, + le32_to_cpu(a->value_length))); + /* + * If @val collates before the current attribute's + * value, there is no matching attribute. + */ + if (!rc) { + register u32 avl; + avl = le32_to_cpu(a->value_length); + if (val_len == avl) + return 0; + if (val_len < avl) { + errno = ENOENT; + return -1; + } + } else if (rc < 0) { + errno = ENOENT; + return -1; + } + } + } + Dputs("mkntfs_attr_find(): File is corrupt. Run chkdsk."); + errno = EIO; + return -1; +} + +/** + * ntfs_attr_lookup - find an attribute in an ntfs inode + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) + * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) + * @val: attribute value to find (optional, resident attributes only) + * @val_len: attribute value length + * @ctx: search context with mft record and attribute to search from + * + * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must + * be the base mft record and @ctx must have been obtained from a call to + * ntfs_attr_get_search_ctx(). + * + * This function transparently handles attribute lists and @ctx is used to + * continue searches where they were left off at. + * + * If @type is AT_UNUSED, return the first found attribute, i.e. one can + * enumerate all attributes by setting @type to AT_UNUSED and then calling + * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT + * to indicate that there are no more entries. During the enumeration, each + * successful call of ntfs_attr_lookup() will return the next attribute, with + * the current attribute being described by the search context @ctx. + * + * If @type is AT_END, seek to the end of the base mft record ignoring the + * attribute list completely and return -1 with errno set to ENOENT. AT_END is + * not a valid attribute, its length is zero for example, thus it is safer to + * return error instead of success in this case. It should never ne needed to + * do this, but we implement the functionality because it allows for simpler + * code inside ntfs_external_attr_find(). + * + * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present + * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, + * match both named and unnamed attributes. + * + * After finishing with the attribute/mft record you need to call + * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any + * mapped extent inodes, etc). + * + * Return 0 if the search was successful and -1 if not, with errno set to the + * error code. + * + * On success, @ctx->attr is the found attribute, it is in mft record + * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this + * attribute with @ctx->base_* being the base mft record to which @ctx->attr + * belongs. If no attribute list attribute is present @ctx->al_entry and + * @ctx->base_* are NULL. + * + * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the + * attribute which collates just after the attribute being searched for in the + * base ntfs inode, i.e. if one wants to add the attribute to the mft record + * this is the correct place to insert it into, and if there is not enough + * space, the attribute should be placed in an extent mft record. + * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list + * at which the new attribute's attribute list entry should be inserted. The + * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. + * The only exception to this is when @type is AT_END, in which case + * @ctx->al_entry is set to NULL also (see above). + * + * + * The following error codes are defined: + * ENOENT Attribute not found, not an error as such. + * EINVAL Invalid arguments. + * EIO I/O error or corrupt data structures found. + * ENOMEM Not enough memory to allocate necessary buffers. + */ +int mkntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, + const u32 name_len, const IGNORE_CASE_BOOL ic, + const VCN lowest_vcn, const u8 *val, const u32 val_len, + ntfs_attr_search_ctx *ctx) +{ + ntfs_inode *base_ni; + + if (!ctx || !ctx->mrec || !ctx->attr) { + errno = EINVAL; + return -1; + } + if (ctx->base_ntfs_ino) + base_ni = ctx->base_ntfs_ino; + else + base_ni = ctx->ntfs_ino; + if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) + return mkntfs_attr_find(type, name, name_len, ic, val, val_len, + ctx); + errno = EOPNOTSUPP; + return -1; +} + +/** + * ntfs_attr_put_search_ctx - release an attribute search context + * @ctx: attribute search context to free + * + * Release the attribute search context @ctx. + */ +void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) +{ + free(ctx); + return; +} + /** * insert_positioned_attr_in_mft_record * Create a non-resident attribute with a predefined on disk location @@ -1229,7 +1520,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, err = -EOPNOTSUPP; goto err_out; } - if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { + if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { err = -EEXIST; goto err_out; } @@ -1414,7 +1705,7 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, err = -EOPNOTSUPP; goto err_out; } - if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { + if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, NULL, 0, ctx)) { err = -EEXIST; goto err_out; } @@ -1576,7 +1867,7 @@ static int insert_resident_attr_in_mft_record(MFT_RECORD *m, ntfschar *uname; /* if (base record) - ntfs_attr_lookup(); + mkntfs_attr_lookup(); else */ if (name_len) { @@ -1603,7 +1894,7 @@ static int insert_resident_attr_in_mft_record(MFT_RECORD *m, err = -EOPNOTSUPP; goto err_out; } - if (!ntfs_attr_lookup(type, uname, name_len, ic, 0, val, val_len, + if (!mkntfs_attr_lookup(type, uname, name_len, ic, 0, val, val_len, ctx)) { err = -EEXIST; goto err_out; @@ -1726,7 +2017,7 @@ static int add_attr_file_name(MFT_RECORD *m, const MFT_REF parent_dir, Eprintf("Failed to allocate attribute search context.\n"); return -ENOMEM; } - if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, + if (mkntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { int eo = errno; Eprintf("BUG: Standard information attribute not present in " @@ -2126,7 +2417,7 @@ static int upgrade_to_large_index(MFT_RECORD *m, const char *name, free(uname); goto err_out; } - err = ntfs_attr_lookup(AT_INDEX_ROOT, uname, name_len, ic, 0, NULL, 0, + err = mkntfs_attr_lookup(AT_INDEX_ROOT, uname, name_len, ic, 0, NULL, 0, ctx); if (uname) free(uname); @@ -3399,7 +3690,7 @@ static void mkntfs_create_root_structures(void) err_exit("Failed to allocate attribute search " "context: %s\n", strerror(errno)); /* There is exactly one file name so this is ok. */ - if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, + if (mkntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { ntfs_attr_put_search_ctx(ctx); err_exit("BUG: $FILE_NAME attribute not found.\n"); @@ -3780,7 +4071,7 @@ int main(int argc, char **argv) err_exit("Failed to allocate attribute search context: %s\n", strerror(errno)); // FIXME: This should be IGNORE_CASE! - if (ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4, 0, 0, + if (mkntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4, 0, 0, NULL, 0, ctx)) { ntfs_attr_put_search_ctx(ctx); err_exit("BUG: $INDEX_ALLOCATION attribute not found.\n"); @@ -3814,7 +4105,7 @@ int main(int argc, char **argv) if (!ctx) err_exit("Failed to allocate attribute search context: %s\n", strerror(errno)); - if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + if (mkntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { ntfs_attr_put_search_ctx(ctx); err_exit("BUG: $DATA attribute not found.\n"); } diff --git a/ntfsprogs/ntfsclone.c b/ntfsprogs/ntfsclone.c index 722616a3..6e929e43 100644 --- a/ntfsprogs/ntfsclone.c +++ b/ntfsprogs/ntfsclone.c @@ -1335,11 +1335,11 @@ static void check_output_device(s64 input_size) set_filesize(input_size); } -static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) +static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) { ntfs_attr_search_ctx *ret; - if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) + if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) perr_printf("ntfs_attr_get_search_ctx"); return ret; @@ -1371,7 +1371,7 @@ static ntfs_attr_search_ctx *lookup_data_attr(ntfs_inode *ni, const char *aname) ntfschar *ustr = NULL; int len = 0; - if ((ctx = attr_get_search_ctx(ni, NULL)) == NULL) + if ((ctx = attr_get_search_ctx(ni)) == NULL) return NULL; if (str2unicode(aname, &ustr, &len) == -1) diff --git a/ntfsprogs/ntfscmp.c b/ntfsprogs/ntfscmp.c index ba59af34..2463d308 100644 --- a/ntfsprogs/ntfscmp.c +++ b/ntfsprogs/ntfscmp.c @@ -237,11 +237,11 @@ static void parse_options(int argc, char **argv) #endif } -static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) +static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni) { ntfs_attr_search_ctx *ret; - if ((ret = ntfs_attr_get_search_ctx(ni, mrec)) == NULL) + if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL) perr_println("ntfs_attr_get_search_ctx"); return ret; @@ -612,9 +612,9 @@ static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2) ATTR_TYPES prev_atype, atype1, atype2; ntfs_attr_search_ctx *ctx1, *ctx2; - if (!(ctx1 = attr_get_search_ctx(ni1, NULL))) + if (!(ctx1 = attr_get_search_ctx(ni1))) return -1; - if (!(ctx2 = attr_get_search_ctx(ni2, NULL))) + if (!(ctx2 = attr_get_search_ctx(ni2))) goto out; atype1 = ctx1->attr->type; diff --git a/ntfsprogs/ntfsfix.8.in b/ntfsprogs/ntfsfix.8.in index b7d1466e..af5a79b4 100644 --- a/ntfsprogs/ntfsfix.8.in +++ b/ntfsprogs/ntfsfix.8.in @@ -16,16 +16,15 @@ .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME -ntfsfix \- fix common errors and force Windows to check NTFS +ntfsfix \- fix common errors .SH SYNOPSIS .B ntfsfix .I device .SH DESCRIPTION \fBntfsfix\fP is a utility that fixes some common NTFS problems. \fBntfsfix\fP is \fBNOT\fP 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. +version of chkdsk. It only repairs some fundamental NTFS inconsistencies and +resets the NTFS journal file. .sp You may run .B ntfsfix diff --git a/ntfsprogs/ntfsfix.c b/ntfsprogs/ntfsfix.c index 49eab6c7..cdc99c2f 100644 --- a/ntfsprogs/ntfsfix.c +++ b/ntfsprogs/ntfsfix.c @@ -73,7 +73,6 @@ GEN_PRINTF(Qprintf, stdout, NULL, FALSE) static const char *EXEC_NAME = "ntfsfix"; static const char *OK = "OK"; static const char *FAILED = "FAILED"; -static BOOL vol_is_dirty = FALSE; static BOOL journal_is_empty = FALSE; struct { @@ -146,32 +145,6 @@ static void parse_options(int argc, char **argv) } } -static int set_dirty_flag(ntfs_volume *vol) -{ - u16 flags; - - if (vol_is_dirty == TRUE) - return 0; - - printf("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_set_flags(vol, flags)) { - puts(FAILED); - fprintf(stderr, "Error setting volume flags.\n"); - return -1; - } - puts(OK); - vol_is_dirty = TRUE; - return 0; -} - static int empty_journal(ntfs_volume *vol) { if (journal_is_empty == TRUE) @@ -349,9 +322,6 @@ int main(int argc, char **argv) printf("Processing of $MFT and $MFTMirr completed successfully.\n"); - if (set_dirty_flag(vol) < 0) - goto error_exit; - if (empty_journal(vol) < 0) goto error_exit; @@ -374,9 +344,6 @@ mount_ok: goto error_exit; } - if (set_dirty_flag(vol) < 0) - goto error_exit; - if (empty_journal(vol) < 0) goto error_exit; diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index c2744c68..bef1d302 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1253,7 +1253,7 @@ static int get_type_and_size_of_indx(ntfs_inode *ni, ATTR_RECORD *attr, memcpy(name, (u8 *)attr + attr->name_offset, attr->name_length * sizeof(ntfschar)); } - ctx = ntfs_attr_get_search_ctx(ni, 0); + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { perror("ntfs_get_search_ctx failed"); free(name); diff --git a/ntfsprogs/ntfslabel.c b/ntfsprogs/ntfslabel.c index 32e98712..c4bc7e82 100644 --- a/ntfsprogs/ntfslabel.c +++ b/ntfsprogs/ntfslabel.c @@ -248,9 +248,8 @@ static int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a, */ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force) { - ntfs_attr_search_ctx *ctx = NULL; + ntfs_attr_search_ctx *ctx; ntfschar *new_label = NULL; - MFT_RECORD *mrec = NULL; ATTR_RECORD *a; int label_len; int result = 0; @@ -269,17 +268,7 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, } } } - - if (ntfs_file_record_read(vol, (MFT_REF)FILE_Volume, &mrec, NULL)) { - perror("Error reading file record"); - goto err_out; - } - if (!(mrec->flags & MFT_RECORD_IN_USE)) { - fprintf(stderr, "Error: $Volume has been deleted. Run " - "chkdsk to fix this.\n"); - goto err_out; - } - ctx = ntfs_attr_get_search_ctx(NULL, mrec); + ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { perror("Failed to get attribute search context"); goto err_out; @@ -314,39 +303,38 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0'); } if (a) { - if (resize_resident_attribute_value(mrec, a, label_len)) { + if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { perror("Error resizing resident attribute"); goto err_out; } } else { /* sizeof(resident attribute record header) == 24 */ int asize = (24 + label_len + 7) & ~7; - u32 biu = le32_to_cpu(mrec->bytes_in_use); - if (biu + asize > le32_to_cpu(mrec->bytes_allocated)) { + u32 biu = le32_to_cpu(ctx->mrec->bytes_in_use); + if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) { errno = ENOSPC; perror("Error adding resident attribute"); goto err_out; } a = ctx->attr; - memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)mrec)); - mrec->bytes_in_use = cpu_to_le32(biu + asize); + memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)ctx->mrec)); + ctx->mrec->bytes_in_use = cpu_to_le32(biu + asize); a->type = AT_VOLUME_NAME; a->length = cpu_to_le32(asize); a->non_resident = 0; a->name_length = 0; a->name_offset = cpu_to_le16(24); a->flags = cpu_to_le16(0); - a->instance = mrec->next_attr_instance; - mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( - mrec->next_attr_instance) + 1) & 0xffff); + a->instance = ctx->mrec->next_attr_instance; + ctx->mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( + ctx->mrec->next_attr_instance) + 1) & 0xffff); a->value_length = cpu_to_le32(label_len); a->value_offset = a->name_offset; a->resident_flags = 0; a->reservedR = 0; } memcpy((u8*)a + le16_to_cpu(a->value_offset), new_label, label_len); - if (!opts.noaction && - ntfs_mft_record_write(vol, (MFT_REF)FILE_Volume, mrec)) { + if (!opts.noaction && ntfs_inode_sync(vol->vol_ni)) { perror("Error writing MFT Record to disk"); goto err_out; } @@ -354,8 +342,6 @@ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, err_out: if (new_label) free(new_label); - if (mrec) - free(mrec); return result; } diff --git a/ntfsprogs/ntfsls.c b/ntfsprogs/ntfsls.c index e51fa8f9..230ad3b7 100644 --- a/ntfsprogs/ntfsls.c +++ b/ntfsprogs/ntfsls.c @@ -534,7 +534,7 @@ static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name, if (!ni) goto release; - ctx = ntfs_attr_get_search_ctx(ni, ni->mrec); + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) goto release; @@ -658,7 +658,7 @@ int main(int argc, char **argv) ntfschar *name = NULL; int name_len = 0;; - ctx = ntfs_attr_get_search_ctx (NULL, ni->mrec); + ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index 742ad1fa..b6c81a18 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -867,7 +867,8 @@ int main (int argc, char *argv[]) count = move_file (vol, inode, opts.location, 0); if ((count > 0) && (!opts.nodirty)) { - if (ntfs_volume_set_flags (vol, VOLUME_IS_DIRTY) < 0) { + if (ntfs_volume_set_flags (vol, vol->flags | VOLUME_IS_DIRTY) < + 0) { Eprintf ("Couldn't mark volume dirty\n"); } printf ("Relocated %lld bytes\n", count); @@ -884,4 +885,3 @@ int main (int argc, char *argv[]) ntfs_umount (vol, FALSE); return result; } - diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 10b2c993..e97cd35c 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -2249,7 +2249,7 @@ static void prepare_volume_fixup(ntfs_volume *vol) printf("Schedule chkdsk for NTFS consistency check at Windows " "boot time ...\n"); - if (ntfs_volume_set_flags(vol, flags)) + if (ntfs_volume_write_flags(vol, flags)) perr_exit("Failed to set $Volume dirty"); if (vol->dev->d_ops->sync(vol->dev) == -1) diff --git a/ntfsprogs/ntfsrm.c b/ntfsprogs/ntfsrm.c index d4a23833..8ba0167b 100644 --- a/ntfsprogs/ntfsrm.c +++ b/ntfsprogs/ntfsrm.c @@ -2301,7 +2301,7 @@ static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp) if (!bmp) return -1; - ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec); + ctx = ntfs_attr_get_search_ctx (inode, NULL); if (!ctx) { printf ("can't create a search context\n"); return -1; @@ -2480,7 +2480,7 @@ static int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfscha //printf ("mft_free = %d\n", mft_free); //printf ("\n"); - ctx = ntfs_attr_get_search_ctx (NULL, mrec); + ctx = ntfs_attr_get_search_ctx (inode, NULL); if (!ctx) goto done; diff --git a/ntfsprogs/ntfswipe.c b/ntfsprogs/ntfswipe.c index facdc123..0557690d 100644 --- a/ntfsprogs/ntfswipe.c +++ b/ntfsprogs/ntfswipe.c @@ -1391,10 +1391,6 @@ int main (int argc, char *argv[]) printf ("%lld bytes were wiped\n", (long long)total); } - if (ntfs_volume_set_flags (vol, VOLUME_IS_DIRTY) < 0) { - Eprintf ("Couldn't mark volume dirty\n"); - } - result = 0; umount: ntfs_umount (vol, FALSE); @@ -1403,4 +1399,3 @@ free: free (opts.bytes); return result; } - diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index c00bfcdb..363cfa5c 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -903,7 +903,7 @@ int mft_next_record (struct mft_search_ctx *ctx) ctx->flags_match |= FEMR_FILE; if (ctx->flags_search & FEMR_DIR) { - attr_ctx = ntfs_attr_get_search_ctx (NULL, ctx->inode->mrec); + attr_ctx = ntfs_attr_get_search_ctx (ctx->inode, NULL); if (attr_ctx) { if (ntfs_attr_lookup (AT_INDEX_ROOT, I30, 4, 0, 0, NULL, 0, attr_ctx) == 0) ctx->flags_match |= FEMR_DIR;