Checked and fixed the upcase table in ntfsfix.c

edge.strict_endians
Jean-Pierre André 2011-02-08 13:52:12 +01:00
parent 4c6cf9d977
commit 2842936b74
1 changed files with 154 additions and 3 deletions

View File

@ -449,6 +449,153 @@ error_exit:
return ret;
}
/*
* Rewrite the $UpCase file as default
*
* Returns 0 if could be written
*/
static int rewrite_upcase(ntfs_volume *vol, ntfs_attr *na)
{
s64 l;
int res;
/* writing the $UpCase may require bitmap updates */
res = -1;
vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap);
if (!vol->lcnbmp_ni) {
ntfs_log_perror("Failed to open bitmap inode");
} else {
vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA,
AT_UNNAMED, 0);
if (!vol->lcnbmp_na) {
ntfs_log_perror("Failed to open bitmap data attribute");
} else {
/* minimal consistency check on the bitmap */
if (((vol->lcnbmp_na->data_size << 3)
< vol->nr_clusters)
|| ((vol->lcnbmp_na->data_size << 3)
>= (vol->nr_clusters << 1))
|| (vol->lcnbmp_na->data_size
> vol->lcnbmp_na->allocated_size)) {
ntfs_log_error("Corrupt cluster map size %lld"
" (allocated %lld minimum %lld)\n",
(long long)vol->lcnbmp_na->data_size,
(long long)vol->lcnbmp_na->allocated_size,
(long long)(vol->nr_clusters + 7) >> 3);
} else {
ntfs_log_info("Rewriting $UpCase file\n");
l = ntfs_attr_pwrite(na, 0, vol->upcase_len*2,
vol->upcase);
if (l != vol->upcase_len*2) {
ntfs_log_error("Failed to rewrite $UpCase\n");
} else {
ntfs_log_info("$UpCase has been set to default\n");
res = 0;
}
}
ntfs_attr_close(vol->lcnbmp_na);
vol->lcnbmp_na = (ntfs_attr*)NULL;
}
ntfs_inode_close(vol->lcnbmp_ni);
vol->lcnbmp_ni = (ntfs_inode*)NULL;
}
return (res);
}
/*
* Fix the $UpCase file
*
* Returns 0 if the table is valid or has been fixed
*/
static int fix_upcase(ntfs_volume *vol)
{
ntfs_inode *ni;
ntfs_attr *na;
ntfschar *upcase;
s64 l;
u32 upcase_len;
u32 k;
int res;
res = -1;
ni = (ntfs_inode*)NULL;
na = (ntfs_attr*)NULL;
/* Now load the upcase table from $UpCase. */
ntfs_log_debug("Loading $UpCase...\n");
ni = ntfs_inode_open(vol, FILE_UpCase);
if (!ni) {
ntfs_log_perror("Failed to open inode FILE_UpCase");
goto error_exit;
}
/* Get an ntfs attribute for $UpCase/$DATA. */
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na) {
ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit;
}
/*
* Note: Normally, the upcase table has a length equal to 65536
* 2-byte Unicode characters but allow for different cases, so no
* checks done. Just check we don't overflow 32-bits worth of Unicode
* characters.
*/
if (na->data_size & ~0x1ffffffffULL) {
ntfs_log_error("Error: Upcase table is too big (max 32-bit "
"allowed).\n");
errno = EINVAL;
goto error_exit;
}
upcase_len = na->data_size >> 1;
upcase = (ntfschar*)ntfs_malloc(na->data_size);
if (!upcase)
goto error_exit;
/* Read in the $DATA attribute value into the buffer. */
l = ntfs_attr_pread(na, 0, na->data_size, upcase);
if (l != na->data_size) {
ntfs_log_error("Failed to read $UpCase, unexpected length "
"(%lld != %lld).\n", (long long)l,
(long long)na->data_size);
errno = EIO;
goto error_exit;
}
/* Consistency check of $UpCase, restricted to plain ASCII chars */
k = 0x20;
while ((k < upcase_len)
&& (k < 0x7f)
&& (le16_to_cpu(upcase[k])
== ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a')))
k++;
if (k < 0x7f) {
ntfs_log_error("Corrupted file $UpCase\n");
if (!opt.no_action) {
/* rewrite the $UpCase file from default */
res = rewrite_upcase(vol, na);
/* free the bad upcase record */
if (!res)
free(upcase);
} else {
/* keep the default upcase but return an error */
free(upcase);
}
} else {
/* accept the upcase table read from $UpCase */
free(vol->upcase);
vol->upcase = upcase;
vol->upcase_len = upcase_len;
res = 0;
}
error_exit :
/* Done with the $UpCase mft record. */
if (na)
ntfs_attr_close(na);
if (ni && ntfs_inode_close(ni)) {
ntfs_log_perror("Failed to close $UpCase");
}
return (res);
}
/*
* Rewrite the boot sector
*
@ -668,13 +815,17 @@ static int fix_mount(void)
/* if option -n proceed despite errors, to display them all */
if ((!ret || opt.no_action) && (fix_mftmirr(vol) < 0))
ret = -1;
if ((!ret || opt.no_action) && (fix_upcase(vol) < 0))
ret = -1;
if ((!ret || opt.no_action) && (set_dirty_flag(vol) < 0))
ret = -1;
if ((!ret || opt.no_action) && (empty_journal(vol) < 0))
ret = -1;
/* ntfs_umount() will invoke ntfs_device_free() for us. */
if (ntfs_umount(vol, 0))
ntfs_umount(vol, 1);
/*
* ntfs_umount() will invoke ntfs_device_free() for us.
* Ignore the returned error resulting from partial mounting.
*/
ntfs_umount(vol, 1);
return ret;
}