Megapatch!!! Check evecrything!!! I probably broke everything!!!

edge.strict_endians
antona 2005-09-24 22:54:55 +00:00
parent 99e18269b7
commit 2a104d8eda
21 changed files with 488 additions and 162 deletions

View File

@ -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.

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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",

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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))) {

View File

@ -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");
}

View File

@ -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)

View File

@ -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;

View File

@ -16,16 +16,15 @@
.\" .sp <n> 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

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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;