mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-16 00:15:08 +01:00
0f17471b27
*Added sources of the custom libs to the branches *Fixed crash when switching from list layout to grid/carousel layout *Removed 1:1 copy option because its meaningless and almost the same as installing all partitions *Fixed install partition selection. This option needs a reset. Go to settings and reselect your option for this. *Fixed schinese and tchinese language modes (filename bugs. has to be schinese.lang and tchinese.lang like on SVN) *Fixed bug in sound buffer circle *Fixed incorrect behaviour of x-flip when selecting system like (thx Cyan for the patch) *Accept ios revision 65535 for Waninkokos IOSes (thx to PPSainity for pointing it out) *Merged the new theming style branch into trunk. Just as a reminder: ALL old themes will not work until the themers did port it to the new style! *Removed old theme style completely Theme example: The example file of the theme is the Default.them file. It can be found in the SVN trunk. Change in loading of themes: When selecting a theme now a list of all .them files in a folder is displayed. The image folder of that theme has to be in the same folder as the .them file. The image path is defined in the head of the .them file in the line with "Image-Folder: Example\n".
727 lines
21 KiB
C
727 lines
21 KiB
C
/**
|
|
* ntfs.c - Simple functionality for startup, mounting and unmounting of NTFS-based devices.
|
|
*
|
|
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
|
* Copyright (c) 2006 Michael "Chishm" Chisholm
|
|
*
|
|
* This program/include file is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program/include file is distributed in the hope that it will be
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "ntfs.h"
|
|
#include "ntfsinternal.h"
|
|
#include "ntfsfile.h"
|
|
#include "ntfsdir.h"
|
|
#include "gekko_io.h"
|
|
#include "cache.h"
|
|
|
|
// NTFS device driver devoptab
|
|
static const devoptab_t devops_ntfs = {
|
|
NULL, /* Device name */
|
|
sizeof (ntfs_file_state),
|
|
ntfs_open_r,
|
|
ntfs_close_r,
|
|
ntfs_write_r,
|
|
ntfs_read_r,
|
|
ntfs_seek_r,
|
|
ntfs_fstat_r,
|
|
ntfs_stat_r,
|
|
ntfs_link_r,
|
|
ntfs_unlink_r,
|
|
ntfs_chdir_r,
|
|
ntfs_rename_r,
|
|
ntfs_mkdir_r,
|
|
sizeof (ntfs_dir_state),
|
|
ntfs_diropen_r,
|
|
ntfs_dirreset_r,
|
|
ntfs_dirnext_r,
|
|
ntfs_dirclose_r,
|
|
ntfs_statvfs_r,
|
|
ntfs_ftruncate_r,
|
|
ntfs_fsync_r,
|
|
NULL /* Device data */
|
|
};
|
|
|
|
void ntfsInit (void)
|
|
{
|
|
static bool isInit = false;
|
|
|
|
// Initialise ntfs-3g (if not already done so)
|
|
if (!isInit) {
|
|
isInit = true;
|
|
|
|
// Set the log handler
|
|
#ifdef NTFS_ENABLE_LOG
|
|
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
|
#else
|
|
ntfs_log_set_handler(ntfs_log_handler_null);
|
|
#endif
|
|
// Set our current local
|
|
ntfs_set_locale();
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions)
|
|
{
|
|
MASTER_BOOT_RECORD mbr;
|
|
PARTITION_RECORD *partition = NULL;
|
|
sec_t partition_starts[NTFS_MAX_PARTITIONS] = {0};
|
|
int partition_count = 0;
|
|
sec_t part_lba = 0;
|
|
int i;
|
|
|
|
union {
|
|
u8 buffer[512];
|
|
MASTER_BOOT_RECORD mbr;
|
|
EXTENDED_BOOT_RECORD ebr;
|
|
NTFS_BOOT_SECTOR boot;
|
|
} sector;
|
|
|
|
// Sanity check
|
|
if (!interface) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (!partitions)
|
|
return 0;
|
|
|
|
// Initialise ntfs-3g
|
|
ntfsInit();
|
|
|
|
// Start the device and check that it is inserted
|
|
if (!interface->startup()) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
if (!interface->isInserted()) {
|
|
return 0;
|
|
}
|
|
|
|
// Read the first sector on the device
|
|
if (!interface->readSectors(0, 1, §or.buffer)) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// If this is the devices master boot record
|
|
if (sector.mbr.signature == MBR_SIGNATURE) {
|
|
memcpy(&mbr, §or, sizeof(MASTER_BOOT_RECORD));
|
|
ntfs_log_debug("Valid Master Boot Record found\n");
|
|
|
|
// Search the partition table for all NTFS partitions (max. 4 primary partitions)
|
|
for (i = 0; i < 4; i++) {
|
|
partition = &mbr.partitions[i];
|
|
part_lba = le32_to_cpu(mbr.partitions[i].lba_start);
|
|
|
|
ntfs_log_debug("Partition %i: %s, sector %d, type 0x%x\n", i + 1,
|
|
partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
|
part_lba, partition->type);
|
|
|
|
// Figure out what type of partition this is
|
|
switch (partition->type) {
|
|
|
|
// Ignore empty partitions
|
|
case PARTITION_TYPE_EMPTY:
|
|
continue;
|
|
|
|
// NTFS partition
|
|
case PARTITION_TYPE_NTFS: {
|
|
ntfs_log_debug("Partition %i: Claims to be NTFS\n", i + 1);
|
|
|
|
// Read and validate the NTFS partition
|
|
if (interface->readSectors(part_lba, 1, §or)) {
|
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
|
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
|
partition_starts[partition_count] = part_lba;
|
|
partition_count++;
|
|
}
|
|
} else {
|
|
ntfs_log_debug("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// DOS 3.3+ or Windows 95 extended partition
|
|
case PARTITION_TYPE_DOS33_EXTENDED:
|
|
case PARTITION_TYPE_WIN95_EXTENDED: {
|
|
ntfs_log_debug("Partition %i: Claims to be Extended\n", i + 1);
|
|
|
|
// Walk the extended partition chain, finding all NTFS partitions within it
|
|
sec_t ebr_lba = part_lba;
|
|
sec_t next_erb_lba = 0;
|
|
do {
|
|
|
|
// Read and validate the extended boot record
|
|
if (interface->readSectors(ebr_lba + next_erb_lba, 1, §or)) {
|
|
if (sector.ebr.signature == EBR_SIGNATURE) {
|
|
ntfs_log_debug("Logical Partition @ %d: type 0x%x\n", ebr_lba + next_erb_lba,
|
|
sector.ebr.partition.status == PARTITION_STATUS_BOOTABLE ? "bootable (active)" : "non-bootable",
|
|
sector.ebr.partition.type);
|
|
|
|
// Get the start sector of the current partition
|
|
// and the next extended boot record in the chain
|
|
part_lba = ebr_lba + next_erb_lba + le32_to_cpu(sector.ebr.partition.lba_start);
|
|
next_erb_lba = le32_to_cpu(sector.ebr.next_ebr.lba_start);
|
|
|
|
// Check if this partition has a valid NTFS boot record
|
|
if (interface->readSectors(part_lba, 1, §or)) {
|
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
|
ntfs_log_debug("Logical Partition @ %d: Valid NTFS boot sector found\n", part_lba);
|
|
if(sector.ebr.partition.type != PARTITION_TYPE_NTFS) {
|
|
ntfs_log_warning("Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n", part_lba, sector.ebr.partition.type, PARTITION_TYPE_NTFS);
|
|
}
|
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
|
partition_starts[partition_count] = part_lba;
|
|
partition_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
next_erb_lba = 0;
|
|
}
|
|
}
|
|
|
|
} while (next_erb_lba);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Unknown or unsupported partition type
|
|
default: {
|
|
|
|
// Check if this partition has a valid NTFS boot record anyway,
|
|
// it might be misrepresented due to a lazy partition editor
|
|
if (interface->readSectors(part_lba, 1, §or)) {
|
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
|
ntfs_log_debug("Partition %i: Valid NTFS boot sector found\n", i + 1);
|
|
if(partition->type != PARTITION_TYPE_NTFS) {
|
|
ntfs_log_warning("Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n", i + 1, partition->type, PARTITION_TYPE_NTFS);
|
|
}
|
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
|
partition_starts[partition_count] = part_lba;
|
|
partition_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Else it is assumed this device has no master boot record
|
|
} else {
|
|
ntfs_log_debug("No Master Boot Record was found!\n");
|
|
|
|
// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS partitions
|
|
for (i = 0; i < 64; i++) {
|
|
if (interface->readSectors(i, 1, §or)) {
|
|
if (sector.boot.oem_id == NTFS_OEM_ID) {
|
|
ntfs_log_debug("Valid NTFS boot sector found at sector %d!\n", i);
|
|
if (partition_count < NTFS_MAX_PARTITIONS) {
|
|
partition_starts[partition_count] = i;
|
|
partition_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Shutdown the device
|
|
/*interface->shutdown();*/
|
|
|
|
// Return the found partitions (if any)
|
|
if (partition_count > 0) {
|
|
*partitions = (sec_t*)ntfs_alloc(sizeof(sec_t) * partition_count);
|
|
if (*partitions) {
|
|
memcpy(*partitions, &partition_starts, sizeof(sec_t) * partition_count);
|
|
return partition_count;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ntfsMountAll (ntfs_md **mounts, u32 flags)
|
|
{
|
|
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
|
const INTERFACE_ID *disc = NULL;
|
|
ntfs_md mount_points[NTFS_MAX_MOUNTS];
|
|
sec_t *partitions = NULL;
|
|
int mount_count = 0;
|
|
int partition_count = 0;
|
|
char name[128];
|
|
int i, j, k;
|
|
|
|
// Initialise ntfs-3g
|
|
ntfsInit();
|
|
|
|
// Find and mount all NTFS partitions on all known devices
|
|
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
|
disc = &discs[i];
|
|
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
|
if (partition_count > 0 && partitions) {
|
|
for (j = 0, k = 0; j < partition_count; j++) {
|
|
|
|
// Find the next unused mount name
|
|
do {
|
|
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
|
if (k >= NTFS_MAX_MOUNTS) {
|
|
ntfs_free(partitions);
|
|
errno = EADDRNOTAVAIL;
|
|
return -1;
|
|
}
|
|
} while (ntfsGetDevice(name, false));
|
|
|
|
// Mount the partition
|
|
if (mount_count < NTFS_MAX_MOUNTS) {
|
|
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
|
strcpy(mount_points[mount_count].name, name);
|
|
mount_points[mount_count].interface = disc->interface;
|
|
mount_points[mount_count].startSector = partitions[j];
|
|
mount_count++;
|
|
}
|
|
}
|
|
|
|
}
|
|
ntfs_free(partitions);
|
|
}
|
|
}
|
|
|
|
// Return the mounts (if any)
|
|
if (mount_count > 0 && mounts) {
|
|
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
|
if (*mounts) {
|
|
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
|
return mount_count;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ntfsMountDevice (const DISC_INTERFACE *interface, ntfs_md **mounts, u32 flags)
|
|
{
|
|
const INTERFACE_ID *discs = ntfsGetDiscInterfaces();
|
|
const INTERFACE_ID *disc = NULL;
|
|
ntfs_md mount_points[NTFS_MAX_MOUNTS];
|
|
sec_t *partitions = NULL;
|
|
int mount_count = 0;
|
|
int partition_count = 0;
|
|
char name[128];
|
|
int i, j, k;
|
|
|
|
// Sanity check
|
|
if (!interface) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
// Initialise ntfs-3g
|
|
ntfsInit();
|
|
|
|
// Find the specified device then find and mount all NTFS partitions on it
|
|
for (i = 0; discs[i].name != NULL && discs[i].interface != NULL; i++) {
|
|
if (discs[i].interface == interface) {
|
|
disc = &discs[i];
|
|
partition_count = ntfsFindPartitions(disc->interface, &partitions);
|
|
if (partition_count > 0 && partitions) {
|
|
for (j = 0, k = 0; j < partition_count; j++) {
|
|
|
|
// Find the next unused mount name
|
|
do {
|
|
sprintf(name, "%s%i", NTFS_MOUNT_PREFIX, k++);
|
|
if (k >= NTFS_MAX_MOUNTS) {
|
|
ntfs_free(partitions);
|
|
errno = EADDRNOTAVAIL;
|
|
return -1;
|
|
}
|
|
} while (ntfsGetDevice(name, false));
|
|
|
|
// Mount the partition
|
|
if (mount_count < NTFS_MAX_MOUNTS) {
|
|
if (ntfsMount(name, disc->interface, partitions[j], CACHE_DEFAULT_PAGE_SIZE, CACHE_DEFAULT_PAGE_COUNT, flags)) {
|
|
strcpy(mount_points[mount_count].name, name);
|
|
mount_points[mount_count].interface = disc->interface;
|
|
mount_points[mount_count].startSector = partitions[j];
|
|
mount_count++;
|
|
}
|
|
}
|
|
|
|
}
|
|
ntfs_free(partitions);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we couldn't find the device then return with error status
|
|
if (!disc) {
|
|
errno = ENODEV;
|
|
return -1;
|
|
}
|
|
|
|
// Return the mounts (if any)
|
|
if (mount_count > 0 && mounts) {
|
|
*mounts = (ntfs_md*)ntfs_alloc(sizeof(ntfs_md) * mount_count);
|
|
if (*mounts) {
|
|
memcpy(*mounts, &mount_points, sizeof(ntfs_md) * mount_count);
|
|
return mount_count;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags)
|
|
{
|
|
ntfs_vd *vd = NULL;
|
|
gekko_fd *fd = NULL;
|
|
|
|
// Sanity check
|
|
if (!name || !interface) {
|
|
errno = EINVAL;
|
|
return false;
|
|
}
|
|
|
|
// Initialise ntfs-3g
|
|
ntfsInit();
|
|
|
|
// Check that the requested mount name is free
|
|
if (ntfsGetDevice(name, false)) {
|
|
errno = EADDRINUSE;
|
|
return false;
|
|
}
|
|
|
|
// Check that we can at least read from this device
|
|
if (!(interface->features & FEATURE_MEDIUM_CANREAD)) {
|
|
errno = EPERM;
|
|
return false;
|
|
}
|
|
|
|
// Allocate the volume descriptor
|
|
vd = (ntfs_vd*)ntfs_alloc(sizeof(ntfs_vd));
|
|
if (!vd) {
|
|
errno = ENOMEM;
|
|
return false;
|
|
}
|
|
|
|
// Setup the volume descriptor
|
|
vd->id = interface->ioType;
|
|
vd->flags = 0;
|
|
vd->uid = 0;
|
|
vd->gid = 0;
|
|
vd->fmask = 0;
|
|
vd->dmask = 0;
|
|
vd->atime = ((flags & NTFS_UPDATE_ACCESS_TIMES) ? ATIME_ENABLED : ATIME_DISABLED);
|
|
vd->showHiddenFiles = (flags & NTFS_SHOW_HIDDEN_FILES);
|
|
vd->showSystemFiles = (flags & NTFS_SHOW_SYSTEM_FILES);
|
|
|
|
// Allocate the device driver descriptor
|
|
fd = (gekko_fd*)ntfs_alloc(sizeof(gekko_fd));
|
|
if (!fd) {
|
|
ntfs_free(vd);
|
|
errno = ENOMEM;
|
|
return false;
|
|
}
|
|
|
|
// Setup the device driver descriptor
|
|
fd->interface = interface;
|
|
fd->startSector = startSector;
|
|
fd->sectorSize = 0;
|
|
fd->sectorCount = 0;
|
|
fd->cachePageCount = cachePageCount;
|
|
fd->cachePageSize = cachePageSize;
|
|
|
|
// Allocate the device driver
|
|
vd->dev = ntfs_device_alloc(name, 0, &ntfs_device_gekko_io_ops, fd);
|
|
if (!vd->dev) {
|
|
ntfs_free(fd);
|
|
ntfs_free(vd);
|
|
return false;
|
|
}
|
|
|
|
// Build the mount flags
|
|
if (flags & NTFS_READ_ONLY)
|
|
vd->flags |= MS_RDONLY;
|
|
else
|
|
{
|
|
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
|
|
vd->flags |= MS_RDONLY;
|
|
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
|
|
vd->flags |= MS_EXCLUSIVE;
|
|
}
|
|
if (flags & NTFS_RECOVER)
|
|
vd->flags |= MS_RECOVER;
|
|
if (flags & NTFS_IGNORE_HIBERFILE)
|
|
vd->flags |= MS_IGNORE_HIBERFILE;
|
|
|
|
if (vd->flags & MS_RDONLY)
|
|
ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
|
|
|
|
// Mount the device
|
|
vd->vol = ntfs_device_mount(vd->dev, vd->flags);
|
|
if (!vd->vol) {
|
|
switch(ntfs_volume_error(errno)) {
|
|
case NTFS_VOLUME_NOT_NTFS: errno = EINVALPART; break;
|
|
case NTFS_VOLUME_CORRUPT: errno = EINVALPART; break;
|
|
case NTFS_VOLUME_HIBERNATED: errno = EHIBERNATED; break;
|
|
case NTFS_VOLUME_UNCLEAN_UNMOUNT: errno = EDIRTY; break;
|
|
default: errno = EINVAL; break;
|
|
}
|
|
ntfs_device_free(vd->dev);
|
|
ntfs_free(vd);
|
|
return false;
|
|
}
|
|
|
|
if (flags & NTFS_IGNORE_CASE)
|
|
ntfs_set_ignore_case(vd->vol);
|
|
|
|
// Initialise the volume descriptor
|
|
if (ntfsInitVolume(vd)) {
|
|
ntfs_umount(vd->vol, true);
|
|
ntfs_free(vd);
|
|
return false;
|
|
}
|
|
|
|
// Add the device to the devoptab table
|
|
if (ntfsAddDevice(name, vd)) {
|
|
ntfsDeinitVolume(vd);
|
|
ntfs_umount(vd->vol, true);
|
|
ntfs_free(vd);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ntfsUnmount (const char *name, bool force)
|
|
{
|
|
ntfs_vd *vd = NULL;
|
|
|
|
// Get the devices volume descriptor
|
|
vd = ntfsGetVolume(name);
|
|
if (!vd)
|
|
return;
|
|
|
|
// Remove the device from the devoptab table
|
|
ntfsRemoveDevice(name);
|
|
|
|
// Deinitialise the volume descriptor
|
|
ntfsDeinitVolume(vd);
|
|
|
|
// Unmount the volume
|
|
ntfs_umount(vd->vol, force);
|
|
|
|
// Free the volume descriptor
|
|
ntfs_free(vd);
|
|
|
|
return;
|
|
}
|
|
|
|
const char *ntfsGetVolumeName (const char *name)
|
|
{
|
|
ntfs_vd *vd = NULL;
|
|
//ntfs_attr *na = NULL;
|
|
//ntfschar *ulabel = NULL;
|
|
//char *volumeName = NULL;
|
|
|
|
// Sanity check
|
|
if (!name) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
// Get the devices volume descriptor
|
|
vd = ntfsGetVolume(name);
|
|
if (!vd) {
|
|
errno = ENODEV;
|
|
return NULL;
|
|
}
|
|
return vd->vol->vol_name;
|
|
/*
|
|
|
|
// If the volume name has already been cached then just use that
|
|
if (vd->name[0])
|
|
return vd->name;
|
|
|
|
// Lock
|
|
ntfsLock(vd);
|
|
|
|
// Check if the volume name attribute exists
|
|
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
|
|
if (!na) {
|
|
ntfsUnlock(vd);
|
|
errno = ENOENT;
|
|
return false;
|
|
}
|
|
|
|
// Allocate a buffer to store the raw volume name
|
|
ulabel = ntfs_alloc(na->data_size * sizeof(ntfschar));
|
|
if (!ulabel) {
|
|
ntfsUnlock(vd);
|
|
errno = ENOMEM;
|
|
return false;
|
|
}
|
|
|
|
// Read the volume name
|
|
if (ntfs_attr_pread(na, 0, na->data_size, ulabel) != na->data_size) {
|
|
ntfs_free(ulabel);
|
|
ntfsUnlock(vd);
|
|
errno = EIO;
|
|
return false;
|
|
}
|
|
|
|
// Convert the volume name to the current local
|
|
if (ntfsUnicodeToLocal(ulabel, na->data_size, &volumeName, 0) < 0) {
|
|
errno = EINVAL;
|
|
ntfs_free(ulabel);
|
|
ntfsUnlock(vd);
|
|
return false;
|
|
}
|
|
|
|
// If the volume name was read then cache it (for future fetches)
|
|
if (volumeName)
|
|
strcpy(vd->name, volumeName);
|
|
|
|
// Close the volume name attribute
|
|
if (na)
|
|
ntfs_attr_close(na);
|
|
|
|
// Clean up
|
|
ntfs_free(volumeName);
|
|
ntfs_free(ulabel);
|
|
|
|
// Unlock
|
|
ntfsUnlock(vd);
|
|
|
|
return vd->name;
|
|
*/
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
const devoptab_t *ntfsGetDevOpTab (void)
|
|
{
|
|
return &devops_ntfs;
|
|
}
|