Support the case where $Volume does not have a $VOLUME_NAME

attribute in ntfs_device_mount() and let ntfslabel create the
attribute when it is not present.

(Logical change 1.339)
edge.strict_endians
cantab.net!aia21 2004-03-19 10:21:05 +00:00
parent 93acd345a7
commit ae7789dcd0
3 changed files with 125 additions and 68 deletions

View File

@ -764,7 +764,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag)
Dperror("Failed to open inode");
goto error_exit;
}
/* Get an ntfs attribute for $UpCase/$DATA. */
/* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
Dputs(FAILED);
@ -807,46 +807,70 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long rwflag)
/* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are
defined using cpu_to_le16() macro and hence are consistent. */
vol->flags = vinf->flags;
/* Find the $VOLUME_NAME attribute. */
/*
* Reinitialize the search context for the $Volume/$VOLUME_NAME lookup.
*/
ntfs_attr_reinit_search_ctx(ctx);
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
Dputs(FAILED);
Dputs("$VOLUME_NAME attribute not found in $Volume?!?");
goto error_exit;
}
a = ctx->attr;
/* Has to be resident. */
if (a->non_resident) {
Dputs(FAILED);
Dputs("Error: Attribute $VOLUME_NAME must be resident!");
errno = EIO;
goto error_exit;
}
/* Get a pointer to the value of the attribute. */
vname = (uchar_t*)(le16_to_cpu(a->value_offset) + (char*)a);
u = le32_to_cpu(a->value_length) / 2;
/* Convert Unicode volume name to current locale multibyte format. */
vol->vol_name = NULL;
if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
Dperror("Error: Volume name could not be converted to "
"current locale");
Dputs("Forcing name into ASCII by replacing non-ASCII "
"characters with underscores.");
vol->vol_name = malloc(u + 1);
if (errno != ENOENT) {
Dputs(FAILED);
Dputs("Error: Lookup of $VOLUME_NAME attribute in "
"$Volume failed. This probably means "
"something is corrupt. Run chkdsk.");
goto error_exit;
}
/*
* Attribute not present. This has been seen in the field.
* Treat this the same way as if the attribute was present but
* had zero length.
*/
vol->vol_name = malloc(1);
if (!vol->vol_name) {
Dputs(FAILED);
Dputs("Error: Unable to allocate memory for volume "
"name!");
goto error_exit;
}
for (j = 0; j < (s32)u; j++) {
uchar_t uc = le16_to_cpu(vname[j]);
if (uc > 0xff)
uc = (uchar_t)'_';
vol->vol_name[j] = (char)uc;
vol->vol_name[0] = '\0';
} else {
a = ctx->attr;
/* Has to be resident. */
if (a->non_resident) {
Dputs(FAILED);
Dputs("Error: Attribute $VOLUME_NAME must be "
"resident!");
errno = EIO;
goto error_exit;
}
/* Get a pointer to the value of the attribute. */
vname = (uchar_t*)(le16_to_cpu(a->value_offset) + (char*)a);
u = le32_to_cpu(a->value_length) / 2;
/*
* Convert Unicode volume name to current locale multibyte
* format.
*/
vol->vol_name = NULL;
if (ntfs_ucstombs(vname, u, &vol->vol_name, 0) == -1) {
Dperror("Error: Volume name could not be converted to "
"current locale");
Dputs("Forcing name into ASCII by replacing non-ASCII "
"characters with underscores.");
vol->vol_name = malloc(u + 1);
if (!vol->vol_name) {
Dputs(FAILED);
Dputs("Error: Unable to allocate memory for "
"volume name!");
goto error_exit;
}
for (j = 0; j < (s32)u; j++) {
uchar_t uc = le16_to_cpu(vname[j]);
if (uc > 0xff)
uc = (uchar_t)'_';
vol->vol_name[j] = (char)uc;
}
vol->vol_name[u] = '\0';
}
vol->vol_name[u] = '\0';
}
Dputs(OK);
ntfs_attr_put_search_ctx(ctx);

View File

@ -517,29 +517,28 @@ void ntfs_dump_object_id_attr(ntfs_inode *inode)
*/
void ntfs_dump_volume_name_attr(ntfs_inode *inode)
{
VOLUME_NAME *vol_name = NULL;
ATTR_RECORD *attr = NULL;
ntfs_attr_search_ctx *ctx = NULL;
VOLUME_NAME *vol_name = NULL;
ATTR_RECORD *attr = NULL;
ntfs_attr_search_ctx *ctx = NULL;
ctx = ntfs_attr_get_search_ctx(inode, NULL);
if(ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
if (errno != ENOENT)
fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_VOLUME_NAME: %s\n",
strerror(errno));
ctx = ntfs_attr_get_search_ctx(inode, NULL);
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
if (errno != ENOENT)
fprintf(stderr, "ntfsinfo error: cannot look up "
"attribute AT_VOLUME_NAME: %s\n",
strerror(errno));
ntfs_attr_put_search_ctx(ctx);
return;
}
attr = ctx->attr;
vol_name = (VOLUME_NAME*)((char *)attr +
le16_to_cpu(attr->value_offset));
printf("Dumping $VOLUME_NAME (0x60)\n");
// FIXME: convert the name to current locale multibyte sequence
// then output the converted name.
//printf("\tVolume Name: \t\t\t %s\n", vol_name->name);
ntfs_attr_put_search_ctx(ctx);
return;
}
attr = ctx->attr;
vol_name = (VOLUME_NAME*)((char *)attr + le16_to_cpu(attr->value_offset));
printf("Dumping $VOLUME_NAME (0x60)\n");
//printf("\tVolume Name: \t\t\t %s\n", vol_name->name);
ntfs_attr_put_search_ctx(ctx);
}

View File

@ -2,7 +2,7 @@
* ntfslabel - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Matthew J. Fanto
* Copyright (c) 2002 Anton Altaparmakov
* Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2002-2003 Richard Russon
*
* This utility will display/change the label on an NTFS partition.
@ -64,7 +64,7 @@ void version (void)
EXEC_NAME, VERSION);
printf ("Copyright (c)\n");
printf (" 2002 Matthew J. Fanto\n");
printf (" 2002 Anton Altaparmakov\n");
printf (" 2002-2004 Anton Altaparmakov\n");
printf (" 2002-2003 Richard Russon\n");
printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
@ -164,7 +164,8 @@ int parse_options (int argc, char *argv[])
}
if (opts.quiet && opts.verbose) {
Eprintf ("You may not use --quiet and --verbose at the same time.\n");
Eprintf ("You may not use --quiet and --verbose at "
"the same time.\n");
err++;
}
}
@ -283,15 +284,21 @@ int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL fo
perror("Failed to get attribute search context");
goto err_out;
}
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
perror("Lookup of $VOLUME_NAME attribute failed");
goto err_out;
}
a = ctx->attr;
if (a->non_resident) {
fprintf(stderr, "Error: Attribute $VOLUME_NAME must be "
"resident.\n");
goto err_out;
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
if (errno != ENOENT) {
perror("Lookup of $VOLUME_NAME attribute failed");
goto err_out;
}
/* The volume name attribute does not exist. Need to add it. */
a = NULL;
} else {
a = ctx->attr;
if (a->non_resident) {
fprintf(stderr, "Error: Attribute $VOLUME_NAME must be "
"resident.\n");
goto err_out;
}
}
label_len = ntfs_mbstoucs(label, &new_label, 0);
if (label_len == -1) {
@ -306,11 +313,38 @@ int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL fo
label_len = 0x100;
new_label[label_len / sizeof(uchar_t)] = cpu_to_le16(L'\0');
}
if (resize_resident_attribute_value(mrec, a, label_len)) {
perror("Error resizing resident attribute");
goto err_out;
if (a) {
if (resize_resident_attribute_value(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)) {
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);
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->value_length = cpu_to_le32(label_len);
a->value_offset = a->name_offset;
a->resident_flags = 0;
a->reservedR = 0;
}
memcpy((char*)a + le16_to_cpu(a->value_offset), new_label, label_len);
memcpy((u8*)a + le16_to_cpu(a->value_offset), new_label, label_len);
if (ntfs_mft_record_write(vol, (MFT_REF)FILE_Volume, mrec)) {
perror("Error writing MFT Record to disk");
goto err_out;