Megapatch!!! Check evecrything!!! I probably broke everything!!!
parent
99e18269b7
commit
2a104d8eda
11
ChangeLog
11
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.
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))) {
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue