int ntfsSync (ntfs_vd *vd, ntfs_inode *ni) { int res = 0; // Sanity check if (!vd) { errno = ENODEV; return -1; } // Sanity check if (!ni) { errno = ENOENT; return -1; } // Lock ntfsLock(vd); // Sync the entry res = ntfs_inode_sync(ni); // Force the underlying device to sync ntfs_device_sync(vd->dev); // Unlock ntfsUnlock(vd); return res; }
int ntfs_inode_close(ntfs_inode *ni) { int res; #if CACHE_NIDATA_SIZE BOOL dirty; struct CACHED_NIDATA item; if (ni) { debug_double_inode(ni->mft_no,0); /* do not cache system files : could lead to double entries */ if (ni->vol && ni->vol->nidata_cache && ((ni->mft_no == FILE_root) || ((ni->mft_no >= FILE_first_user) && !(ni->mrec->flags & MFT_RECORD_IS_4)))) { /* If we have dirty metadata, write it out. */ dirty = NInoDirty(ni) || NInoAttrListDirty(ni); if (dirty) { res = ntfs_inode_sync(ni); /* do a real close if sync failed */ if (res) ntfs_inode_real_close(ni); } else res = 0; if (!res) { /* feed idata into cache */ item.inum = ni->mft_no; item.ni = ni; item.pathname = (const char*)NULL; item.varsize = 0; debug_cached_inode(ni); ntfs_enter_cache(ni->vol->nidata_cache, GENERIC(&item), idata_cache_compare); } } else { /* cache not ready or system file, really close */ res = ntfs_inode_real_close(ni); } } else res = 0; #else res = ntfs_inode_real_close(ni); #endif return (res); }
bool ntfsSetVolumeName (const char *name, const char *volumeName) { ntfs_vd *vd = NULL; ntfs_attr *na = NULL; ntfschar *ulabel = NULL; int ulabel_len; // Sanity check if (!name) { errno = EINVAL; return false; } // Get the devices volume descriptor vd = ntfsGetVolume(name); if (!vd) { errno = ENODEV; return false; } // Lock ntfsLock(vd); // Convert the new volume name to unicode ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar); if (ulabel_len < 0) { ntfsUnlock(vd); errno = EINVAL; return false; } // Check if the volume name attribute exists na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0); if (na) { // It does, resize it to match the length of the new volume name if (ntfs_attr_truncate(na, ulabel_len)) { ntfs_free(ulabel); ntfsUnlock(vd); return false; } // Write the new volume name if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) { ntfs_free(ulabel); ntfsUnlock(vd); return false; } } else { // It doesn't, create it now if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) { ntfs_free(ulabel); ntfsUnlock(vd); return false; } } // Reset the volumes name cache (as it has now been changed) vd->name[0] = '\0'; // Close the volume name attribute if (na) ntfs_attr_close(na); // Sync the volume node if (ntfs_inode_sync(vd->vol->vol_ni)) { ntfs_free(ulabel); ntfsUnlock(vd); return false; } // Clean up ntfs_free(ulabel); // Unlock ntfsUnlock(vd); return true; }
/** * ntfs_inode_close - close an ntfs inode and free all associated memory * @ni: ntfs inode to close * * Make sure the ntfs inode @ni is clean. * * If the ntfs inode @ni is a base inode, close all associated extent inodes, * then deallocate all memory attached to it, and finally free the ntfs inode * structure itself. * * If it is an extent inode, we disconnect it from its base inode before we * destroy it. * * It is OK to pass NULL to this function, it is just noop in this case. * * Return 0 on success or -1 on error with errno set to the error code. On * error, @ni has not been freed. The user should attempt to handle the error * and call ntfs_inode_close() again. The following error codes are defined: * * EBUSY @ni and/or its attribute list runlist is/are dirty and the * attempt to write it/them to disk failed. * EINVAL @ni is invalid (probably it is an extent inode). * EIO I/O error while trying to write inode to disk. */ int ntfs_inode_close(ntfs_inode *ni) { int ret = -1; if (!ni) return 0; ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); /* If we have dirty metadata, write it out. */ if (NInoDirty(ni) || NInoAttrListDirty(ni)) { if (ntfs_inode_sync(ni)) { if (errno != EIO) errno = EBUSY; goto err; } } /* Is this a base inode with mapped extent inodes? */ if (ni->nr_extents > 0) { while (ni->nr_extents > 0) { if (ntfs_inode_close(ni->extent_nis[0])) { if (errno != EIO) errno = EBUSY; goto err; } } } else if (ni->nr_extents == -1) { ntfs_inode **tmp_nis; ntfs_inode *base_ni; s32 i; /* * If the inode is an extent inode, disconnect it from the * base inode before destroying it. */ base_ni = ni->base_ni; for (i = 0; i < base_ni->nr_extents; ++i) { tmp_nis = base_ni->extent_nis; if (tmp_nis[i] != ni) continue; /* Found it. Disconnect. */ memmove(tmp_nis + i, tmp_nis + i + 1, (base_ni->nr_extents - i - 1) * sizeof(ntfs_inode *)); /* Buffer should be for multiple of four extents. */ if ((--base_ni->nr_extents) & 3) { i = -1; break; } /* * ElectricFence is unhappy with realloc(x,0) as free(x) * thus we explicitly separate these two cases. */ if (base_ni->nr_extents) { /* Resize the memory buffer. */ tmp_nis = realloc(tmp_nis, base_ni->nr_extents * sizeof(ntfs_inode *)); /* Ignore errors, they don't really matter. */ if (tmp_nis) base_ni->extent_nis = tmp_nis; } else if (tmp_nis) free(tmp_nis); /* Allow for error checking. */ i = -1; break; } /* * We could successfully sync, so only log this error * and try to sync other inode extents too. */ if (i != -1) ntfs_log_error("Extent inode %lld was not found\n", (long long)ni->mft_no); } __ntfs_inode_release(ni); ret = 0; err: ntfs_log_leave("\n"); return ret; }
/** * 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; }