/** * change_label - change the current label on a device * @dev: device to change the label on * @mnt_flags: mount flags of the device or 0 if not mounted * @mnt_point: mount point of the device or NULL * @label: the new label * * Change the label on the device @dev to @label. */ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force) { ntfs_attr_search_ctx *ctx; ntfschar *new_label = NULL; ATTR_RECORD *a; int label_len; int result = 0; //XXX significant? if (mnt_flags & NTFS_MF_MOUNTED) { /* If not the root fs or mounted read/write, refuse change. */ if (!(mnt_flags & NTFS_MF_ISROOT) || !(mnt_flags & NTFS_MF_READONLY)) { if (!force) { ntfs_log_error("Refusing to change label on " "read-%s mounted device %s.\n", mnt_flags & NTFS_MF_READONLY ? "only" : "write", opts.device); return 1; } } } ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { ntfs_log_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)) { if (errno != ENOENT) { ntfs_log_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) { ntfs_log_error("Error: Attribute $VOLUME_NAME must be " "resident.\n"); goto err_out; } } label_len = ntfs_mbstoucs(label, &new_label, 0); if (label_len == -1) { ntfs_log_perror("Unable to convert label string to Unicode"); goto err_out; } label_len *= sizeof(ntfschar); if (label_len > 0x100) { ntfs_log_error("New label is too long. Maximum %u characters " "allowed. Truncating excess characters.\n", (unsigned)(0x100 / sizeof(ntfschar))); label_len = 0x100; new_label[label_len / sizeof(ntfschar)] = 0; } if (a) { if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { ntfs_log_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(ctx->mrec->bytes_in_use); if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) { errno = ENOSPC; ntfs_log_perror("Error adding resident attribute"); goto err_out; } a = ctx->attr; 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 = ctx->mrec->next_attr_instance; ctx->mrec->next_attr_instance = cpu_to_le16((le16_to_cpu( ctx->mrec->next_attr_instance) + 1) & 0xffff); a->u.res.value_length = cpu_to_le32(label_len); a->u.res.value_offset = a->name_offset; a->u.res.resident_flags = 0; a->u.res.reservedR = 0; } memcpy((u8*)a + le16_to_cpu(a->u.res.value_offset), new_label, label_len); if (!opts.noaction && ntfs_inode_sync(vol->vol_ni)) { ntfs_log_perror("Error writing MFT Record to disk"); goto err_out; } result = 0; err_out: free(new_label); return result; }
int ntfs_change_label(ntfs_volume *vol, char *label) { ntfs_attr_search_ctx *ctx; ntfschar *new_label = NULL; ATTR_RECORD *a; int label_len; int result = 0; ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { ntfs_log_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)) { if (errno != ENOENT) { ntfs_log_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) { ntfs_log_error("Error: Attribute $VOLUME_NAME must be " "resident.\n"); goto err_out; } } label_len = ntfs_mbstoucs(label, &new_label); if (label_len == -1) { ntfs_log_perror("Unable to convert label string to Unicode"); goto err_out; } label_len *= sizeof(ntfschar); if (label_len > 0x100) { ntfs_log_error("New label is too long. Maximum %u characters " "allowed. Truncating excess characters.\n", (unsigned)(0x100 / sizeof(ntfschar))); label_len = 0x100; new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0'); } if (a) { if (resize_resident_attribute_value(ctx->mrec, a, label_len)) { ntfs_log_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(ctx->mrec->bytes_in_use); if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) { errno = ENOSPC; ntfs_log_perror("Error adding resident attribute"); goto err_out; } a = ctx->attr; 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 = 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 (ntfs_inode_sync(vol->vol_ni)) { ntfs_log_perror("Error writing MFT Record to disk"); goto err_out; } result = 0; err_out: ntfs_attr_put_search_ctx(ctx); free(new_label); return result; }