mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-12-22 09:51:55 +01:00
* Added NTFS write support! (Thanks dimok, for fixing the bugs)
* Added additional folder layout on FAT/NTFS (GAMEID_Text or Text [GAMEID])
This commit is contained in:
parent
0ab26eaa6e
commit
57ecea56e9
@ -2,8 +2,8 @@
|
||||
<app version="1">
|
||||
<name> USB Loader GX</name>
|
||||
<coder>USB Loader GX Team</coder>
|
||||
<version>1.0 r898</version>
|
||||
<release_date>201001191410</release_date>
|
||||
<version>1.0 r900</version>
|
||||
<release_date>201001311842</release_date>
|
||||
<short_description>Loads games from USB-devices</short_description>
|
||||
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
|
||||
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.
|
||||
|
33
Makefile
33
Makefile
@ -16,11 +16,31 @@ include $(DEVKITPPC)/wii_rules
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := boot
|
||||
BUILD := build
|
||||
SOURCES := source source/libwiigui source/images source/fonts source/sounds \
|
||||
source/libwbfs source/unzip source/language source/mload source/patches \
|
||||
source/usbloader source/xml source/network source/settings source/prompts \
|
||||
source/ramdisk source/wad source/banner source/cheats source/homebrewboot \
|
||||
source/themes source/menu source/libfat source/memory source/libntfs
|
||||
SOURCES := source \
|
||||
source/libwiigui \
|
||||
source/images \
|
||||
source/fonts \
|
||||
source/sounds \
|
||||
source/libwbfs \
|
||||
source/unzip \
|
||||
source/language \
|
||||
source/mload \
|
||||
source/patches \
|
||||
source/usbloader \
|
||||
source/xml \
|
||||
source/network \
|
||||
source/settings \
|
||||
source/prompts \
|
||||
source/ramdisk \
|
||||
source/wad \
|
||||
source/banner \
|
||||
source/cheats \
|
||||
source/homebrewboot \
|
||||
source/themes \
|
||||
source/menu \
|
||||
source/libfat \
|
||||
source/memory \
|
||||
source/libntfs
|
||||
DATA := data
|
||||
INCLUDES := source
|
||||
|
||||
@ -28,7 +48,8 @@ INCLUDES := source
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -ffast-math -g -O3 -pipe -mrvl -mcpu=750 -meabi -mhard-float -Wall $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H -DGEKKO -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
CFLAGS = -ffast-math -g -O3 -pipe -mrvl -mcpu=750 -meabi -mhard-float -Wall $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H -DGEKKO \
|
||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
CXXFLAGS = -Xassembler -aln=$@.lst $(CFLAGS)
|
||||
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00000,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size
|
||||
-include $(PROJECTDIR)/Make.config
|
||||
|
2
gui.pnps
2
gui.pnps
@ -1 +1 @@
|
||||
<pd><ViewState><e p="gui\source\mload" x="false"></e><e p="gui\source\settings" x="true"></e><e p="gui\source\images" x="false"></e><e p="gui\source\libfat" x="false"></e><e p="gui\source\prompts" x="false"></e><e p="gui\source\banner" x="false"></e><e p="gui\source\cheats" x="false"></e><e p="gui\source\libntfs" x="false"></e><e p="gui\source\network" x="false"></e><e p="gui\source\fonts" x="false"></e><e p="gui\source\menu" x="false"></e><e p="gui\source\ramdisk" x="false"></e><e p="gui\source\sounds" x="false"></e><e p="gui\source\wad" x="false"></e><e p="gui" x="true"></e><e p="gui\source\homebrewboot" x="false"></e><e p="gui\source\language" x="false"></e><e p="gui\source" x="true"></e><e p="gui\source\libwbfs" x="false"></e><e p="gui\source\libwiigui" x="false"></e><e p="gui\source\patches" x="false"></e><e p="gui\source\themes" x="false"></e><e p="gui\source\memory" x="false"></e><e p="gui\source\unzip" x="false"></e><e p="gui\source\usbloader" x="false"></e><e p="gui\source\xml" x="false"></e></ViewState></pd>
|
||||
<pd><ViewState><e p="gui\source\mload" x="false"></e><e p="gui\source\settings" x="true"></e><e p="gui\source\images" x="false"></e><e p="gui\source\libfat" x="false"></e><e p="gui\source\prompts" x="false"></e><e p="gui\source\banner" x="false"></e><e p="gui\source\cheats" x="false"></e><e p="gui\source\libntfs" x="false"></e><e p="gui\source\network" x="false"></e><e p="gui\source\fonts" x="false"></e><e p="gui\source\menu" x="false"></e><e p="gui\source\ramdisk" x="false"></e><e p="gui\source\sounds" x="false"></e><e p="gui\source\wad" x="false"></e><e p="gui" x="true"></e><e p="gui\source\homebrewboot" x="false"></e><e p="gui\source\language" x="false"></e><e p="gui\source" x="true"></e><e p="gui\source\libwbfs" x="false"></e><e p="gui\source\libwiigui" x="false"></e><e p="gui\source\patches" x="false"></e><e p="gui\source\themes" x="false"></e><e p="gui\source\memory" x="false"></e><e p="gui\source\unzip" x="false"></e><e p="gui\source\usbloader" x="true"></e><e p="gui\source\xml" x="false"></e></ViewState></pd>
|
@ -24,9 +24,6 @@
|
||||
|
||||
/* Disc interfaces */
|
||||
extern const DISC_INTERFACE __io_sdhc;
|
||||
// read-only
|
||||
extern const DISC_INTERFACE __io_sdhc_ro;
|
||||
extern const DISC_INTERFACE __io_usbstorage_ro;
|
||||
|
||||
void _FAT_mem_init();
|
||||
extern sec_t _FAT_startSector;
|
||||
@ -82,7 +79,7 @@ int WBFSDevice_Init(u32 sector) {
|
||||
//right now mounts first FAT-partition
|
||||
|
||||
//try first mount with cIOS
|
||||
if (!fatMount("USB", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
if (!fatMount("WBFS", &__io_wiiums, 0, CACHE, SECTORS)) {
|
||||
//try now mount with libogc
|
||||
if (!fatMount("WBFS", &__io_usbstorage, 0, CACHE, SECTORS)) {
|
||||
return -1;
|
||||
@ -154,7 +151,7 @@ s32 MountNTFS(u32 sector)
|
||||
//printf("mounting NTFS\n");
|
||||
//Wpad_WaitButtons();
|
||||
_FAT_mem_init();
|
||||
ntfsInit();
|
||||
|
||||
// ntfsInit resets locale settings
|
||||
// which breaks unicode in console
|
||||
// so we change it back to C-UTF-8
|
||||
@ -170,22 +167,21 @@ s32 MountNTFS(u32 sector)
|
||||
}
|
||||
}
|
||||
/* Mount device */
|
||||
if (!ntfsMount("NTFS", &__io_wiiums_ro, sector, CACHE, SECTORS, NTFS_DEFAULT)) {
|
||||
ret = ntfsMount("NTFS", &__io_usbstorage_ro, sector, CACHE, SECTORS, NTFS_DEFAULT);
|
||||
if (!ntfsMount("NTFS", &__io_wiiums, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER)) {
|
||||
ret = ntfsMount("NTFS", &__io_usbstorage, sector, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
if (!ret) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
} else if (wbfsDev == WBFS_DEVICE_SDHC) {
|
||||
if (sdhc_mode_sd == 0) {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc_ro, 0, CACHE, SECTORS, NTFS_DEFAULT);
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
} else {
|
||||
ret = ntfsMount("NTFS", &__io_sdhc_ro, 0, CACHE, SECTORS_SD, NTFS_DEFAULT);
|
||||
ret = ntfsMount("NTFS", &__io_sdhc, 0, CACHE, SECTORS_SD, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER);
|
||||
}
|
||||
if (!ret) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fs_ntfs_mount = 1;
|
||||
@ -197,7 +193,7 @@ s32 MountNTFS(u32 sector)
|
||||
s32 UnmountNTFS(void)
|
||||
{
|
||||
/* Unmount device */
|
||||
fatUnmount("NTFS:/");
|
||||
ntfsUnmount("NTFS:/", true);
|
||||
|
||||
fs_ntfs_mount = 0;
|
||||
fs_ntfs_sec = 0;
|
||||
|
@ -40,6 +40,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
@ -1,11 +1,12 @@
|
||||
/**
|
||||
* attrib.c - Attribute handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2000-2010 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2007-2009 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* 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
|
||||
@ -39,6 +40,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "attrib.h"
|
||||
@ -59,7 +63,6 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
#include "ntfs.h"
|
||||
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
|
||||
@ -70,6 +73,17 @@ ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('S'),
|
||||
const_cpu_to_le16('\0') };
|
||||
|
||||
ntfschar TXF_DATA[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('T'),
|
||||
const_cpu_to_le16('X'),
|
||||
const_cpu_to_le16('F'),
|
||||
const_cpu_to_le16('_'),
|
||||
const_cpu_to_le16('D'),
|
||||
const_cpu_to_le16('A'),
|
||||
const_cpu_to_le16('T'),
|
||||
const_cpu_to_le16('A'),
|
||||
const_cpu_to_le16('\0') };
|
||||
|
||||
static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
|
||||
{
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED)
|
||||
@ -1057,7 +1071,6 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count)
|
||||
{
|
||||
char *buf;
|
||||
@ -1870,6 +1883,7 @@ int ntfs_attr_pclose(ntfs_attr *na)
|
||||
}
|
||||
|
||||
retry:
|
||||
written = 0;
|
||||
if (!NVolReadOnly(vol)) {
|
||||
|
||||
written = ntfs_compressed_close(na, rl, ofs);
|
||||
@ -3010,10 +3024,14 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
|
||||
/**
|
||||
* ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
|
||||
* @vol: ntfs volume to which the attribute belongs
|
||||
* @type: attribute type which to check
|
||||
* @type: attribute type to check
|
||||
* @name: attribute name to check
|
||||
* @name_len: attribute name length
|
||||
*
|
||||
* Check whether the attribute of @type on the ntfs volume @vol is allowed to
|
||||
* be non-resident. This information is obtained from $AttrDef system file.
|
||||
* Check whether the attribute of @type and @name with name length @name_len on
|
||||
* the ntfs volume @vol is allowed to be non-resident. This information is
|
||||
* obtained from $AttrDef system file and is augmented by rules imposed by
|
||||
* Microsoft (e.g. see http://support.microsoft.com/kb/974729/).
|
||||
*
|
||||
* Return 0 if the attribute is allowed to be non-resident and -1 if not or an
|
||||
* error occurred. On error the error code is stored in errno. The following
|
||||
@ -3022,16 +3040,34 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
|
||||
* ENOENT - The attribute @type is not specified in $AttrDef.
|
||||
* EINVAL - Invalid parameters (e.g. @vol is not valid).
|
||||
*/
|
||||
int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type)
|
||||
static int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type,
|
||||
const ntfschar *name, int name_len)
|
||||
{
|
||||
ATTR_DEF *ad;
|
||||
BOOL allowed;
|
||||
|
||||
/* Find the attribute definition record in $AttrDef. */
|
||||
ad = ntfs_attr_find_in_attrdef(vol, type);
|
||||
if (!ad)
|
||||
return -1;
|
||||
/* Check the flags and return the result. */
|
||||
if (ad->flags & ATTR_DEF_RESIDENT) {
|
||||
/*
|
||||
* Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a
|
||||
* name of $TXF_DATA must be resident despite the entry for
|
||||
* $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident.
|
||||
* Failure to obey this on the root directory mft record of a volume
|
||||
* causes Windows Vista and later to see the volume as a RAW volume and
|
||||
* thus cannot mount it at all.
|
||||
*/
|
||||
if ((type == AT_LOGGED_UTILITY_STREAM)
|
||||
&& name
|
||||
&& ntfs_names_are_equal(TXF_DATA, 9, name, name_len,
|
||||
CASE_SENSITIVE, vol->upcase, vol->upcase_len))
|
||||
allowed = FALSE;
|
||||
else {
|
||||
/* Find the attribute definition record in $AttrDef. */
|
||||
ad = ntfs_attr_find_in_attrdef(vol, type);
|
||||
if (!ad)
|
||||
return -1;
|
||||
/* Check the flags and return the result. */
|
||||
allowed = !(ad->flags & ATTR_DEF_RESIDENT);
|
||||
}
|
||||
if (!allowed) {
|
||||
errno = EPERM;
|
||||
ntfs_log_trace("Attribute can't be non-resident\n");
|
||||
return -1;
|
||||
@ -3296,7 +3332,7 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ntfs_attr_can_be_non_resident(ni->vol, type)) {
|
||||
if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) {
|
||||
if (errno == EPERM)
|
||||
ntfs_log_perror("Attribute can't be non resident");
|
||||
else
|
||||
@ -3591,7 +3627,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
}
|
||||
|
||||
/* Sanity checks for always resident attributes. */
|
||||
if (ntfs_attr_can_be_non_resident(ni->vol, type)) {
|
||||
if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) {
|
||||
if (errno != EPERM) {
|
||||
err = errno;
|
||||
ntfs_log_perror("ntfs_attr_can_be_non_resident failed");
|
||||
@ -4156,7 +4192,7 @@ int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
}
|
||||
|
||||
/* Check that the attribute is allowed to be non-resident. */
|
||||
if (ntfs_attr_can_be_non_resident(vol, na->type))
|
||||
if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len))
|
||||
return -1;
|
||||
|
||||
new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size
|
||||
|
@ -39,6 +39,9 @@ typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx;
|
||||
extern ntfschar AT_UNNAMED[];
|
||||
extern ntfschar STREAM_SDS[];
|
||||
|
||||
/* The little endian Unicode string $TXF_DATA as a global constant. */
|
||||
extern ntfschar TXF_DATA[10];
|
||||
|
||||
/**
|
||||
* enum ntfs_lcn_special_values - special return values for ntfs_*_vcn_to_lcn()
|
||||
*
|
||||
@ -281,8 +284,6 @@ extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
|
57
source/libntfs/bit_ops.h
Normal file
57
source/libntfs/bit_ops.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
bit_ops.h
|
||||
Functions for dealing with conversion of data between types
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _BIT_OPS_H
|
||||
#define _BIT_OPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8));
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
|
||||
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
item[offset + 2] = (uint8_t)(value >> 16);
|
||||
item[offset + 3] = (uint8_t)(value >> 24);
|
||||
}
|
||||
|
||||
#endif // _BIT_OPS_H
|
@ -10,7 +10,8 @@
|
||||
too many stale pages around.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
Copyright (c) 2009 shareese, rodries
|
||||
Copyright (c) 2009 shareese, rodries
|
||||
Copyright (c) 2010 Dimok
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
@ -39,6 +40,7 @@
|
||||
|
||||
//#include "common.h"
|
||||
#include "cache.h"
|
||||
#include "bit_ops.h"
|
||||
//#include "disc.h"
|
||||
|
||||
#include "mem_allocate.h"
|
||||
@ -95,9 +97,9 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
|
||||
|
||||
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
|
||||
|
||||
if(cache==NULL) return;
|
||||
|
||||
|
||||
// Clear out cache before destroying it
|
||||
_NTFS_cache_flush(cache);
|
||||
|
||||
@ -119,6 +121,7 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
@ -127,14 +130,15 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
|
||||
if((cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(cacheEntries[oldUsed].dirty==true) {
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
|
||||
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
@ -151,6 +155,33 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
return &(cacheEntries[oldUsed]);
|
||||
}
|
||||
|
||||
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
|
||||
|
||||
unsigned int i;
|
||||
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
NTFS_CACHE_ENTRY *entry = NULL;
|
||||
sec_t lowest = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++) {
|
||||
if (cacheEntries[i].sector != CACHE_FREE) {
|
||||
bool intersect;
|
||||
if (sector > cacheEntries[i].sector) {
|
||||
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
|
||||
} else {
|
||||
intersect = cacheEntries[i].sector - sector < count;
|
||||
}
|
||||
|
||||
if ( intersect && (cacheEntries[i].sector < lowest)) {
|
||||
lowest = cacheEntries[i].sector;
|
||||
entry = &cacheEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
@ -179,8 +210,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
|
||||
/*
|
||||
Reads some data from a cache page, determined by the sector number
|
||||
*/
|
||||
/*
|
||||
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
|
||||
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
@ -208,12 +239,12 @@ bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
/*
|
||||
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
|
||||
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
@ -242,12 +273,12 @@ bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value
|
||||
|
||||
return _NTFS_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
/*
|
||||
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
|
||||
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
NTFS_CACHE_ENTRY *entry;
|
||||
@ -264,16 +295,17 @@ bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer,
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
|
||||
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
NTFS_CACHE_ENTRY* entry;
|
||||
const uint8_t *src = buffer;
|
||||
|
||||
|
||||
while(numSectors>0)
|
||||
{
|
||||
/*
|
||||
entry = _NTFS_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
@ -288,6 +320,38 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
*/
|
||||
entry = _NTFS_cache_findPage(cache,sector,numSectors);
|
||||
|
||||
if(entry!=NULL) {
|
||||
|
||||
if ( entry->sector > sector) {
|
||||
|
||||
secs_to_write = entry->sector - sector;
|
||||
|
||||
cache->disc->writeSectors(sector,secs_to_write,src);
|
||||
src += (secs_to_write*BYTES_PER_READ);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
}
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
|
||||
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||
|
||||
memcpy(entry->cache + (sec*BYTES_PER_READ),src,(secs_to_write*BYTES_PER_READ));
|
||||
|
||||
src += (secs_to_write*BYTES_PER_READ);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
|
||||
} else {
|
||||
cache->disc->writeSectors(sector,numSectors,src);
|
||||
numSectors=0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -313,7 +377,9 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
|
||||
|
||||
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
|
||||
unsigned int i;
|
||||
if(cache==NULL) return;
|
||||
if(cache==NULL)
|
||||
return;
|
||||
|
||||
_NTFS_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
|
@ -66,7 +66,6 @@ extern char *strsep(char **stringp, const char *delim);
|
||||
#ifdef GEKKO
|
||||
|
||||
#include "mem_allocate.h"
|
||||
#include <limits.h>
|
||||
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_REPLACE 2
|
||||
|
@ -4,9 +4,11 @@
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
//#define DEBUG
|
||||
/* Define to 1 if debug should be enabled */
|
||||
#ifdef DEBUG
|
||||
# define ENABLE_DEBUG
|
||||
#define ENABLE_DEBUG
|
||||
#define NTFS_ENABLE_LOG
|
||||
#endif
|
||||
|
||||
/* Define to 1 if using internal fuse */
|
||||
|
@ -21,6 +21,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef GEKKO
|
||||
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
|
||||
#ifndef __CYGWIN32__
|
||||
|
||||
/* Not on Cygwin; use standard Unix style low level device operations. */
|
||||
#include "unix_io.c"
|
||||
|
||||
#else /* __CYGWIN32__ */
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
#include "win32_io.c"
|
||||
|
||||
#endif /* __CYGWIN32__ */
|
||||
|
||||
#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */
|
||||
#endif /* GEKKO */
|
||||
|
@ -58,6 +58,8 @@
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('E'),
|
||||
@ -337,3 +339,5 @@ err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
@ -2,6 +2,7 @@
|
||||
* gekko_io.c - Gekko style disk io functions.
|
||||
*
|
||||
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
||||
* Copyright (c) 2010 Dimok
|
||||
*
|
||||
* 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
|
||||
@ -83,14 +84,14 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Start the device interface and ensure that it is inserted
|
||||
if (!interface->startup()) {
|
||||
ntfs_log_perror("device failed to start\n");
|
||||
@ -102,7 +103,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Check that the device isn't already open (used by another volume?)
|
||||
if (NDevOpen(dev)) {
|
||||
ntfs_log_perror("device is busy (already open)\n");
|
||||
@ -122,7 +123,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Parse the boot sector
|
||||
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
|
||||
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
|
||||
@ -130,7 +131,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
fd->pos = 0;
|
||||
fd->len = (fd->sectorCount * fd->sectorSize);
|
||||
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
||||
|
||||
|
||||
// If the device sector size is not 512 bytes then we cannot continue,
|
||||
// gekko disc I/O works on the assumption that sectors are always 512 bytes long.
|
||||
// TODO: Implement support for non-512 byte sector sizes through some fancy maths!?
|
||||
@ -144,14 +145,14 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
if (flags & O_RDONLY) {
|
||||
NDevSetReadOnly(dev);
|
||||
}
|
||||
|
||||
|
||||
// Create the cache
|
||||
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount);
|
||||
|
||||
// Mark the device as open
|
||||
NDevSetBlock(dev);
|
||||
NDevSetOpen(dev);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -161,7 +162,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
{
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
@ -175,20 +176,20 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Mark the device as closed
|
||||
NDevClearOpen(dev);
|
||||
NDevClearBlock(dev);
|
||||
|
||||
|
||||
// Flush the device (if dirty and not read-only)
|
||||
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
||||
ntfs_log_debug("device is dirty, will now sync\n");
|
||||
|
||||
// ...?
|
||||
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty(dev);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Flush and destroy the cache (if required)
|
||||
@ -196,7 +197,7 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
_NTFS_cache_flush(fd->cache);
|
||||
_NTFS_cache_destructor(fd->cache);
|
||||
}
|
||||
|
||||
|
||||
// Shutdown the device interface
|
||||
/*const DISC_INTERFACE* interface = fd->interface;
|
||||
if (interface) {
|
||||
@ -206,7 +207,7 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
// Free the device driver private data
|
||||
ntfs_free(dev->d_private);
|
||||
dev->d_private = NULL;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -216,14 +217,14 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
||||
static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int whence)
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %Li, whence %i\n", dev, offset, whence);
|
||||
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Set the current position on the device (in bytes)
|
||||
switch(whence) {
|
||||
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
||||
@ -259,7 +260,7 @@ static s64 ntfs_device_gekko_io_pread(struct ntfs_device *dev, void *buf, s64 co
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
|
||||
{
|
||||
@ -271,119 +272,129 @@ static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf,
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
||||
|
||||
//ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
||||
ntfs_log_trace("dev %p, offset %d, count %d\n", dev, (u32)offset, (u32)count);
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sec_t sec_start = fd->startSector;
|
||||
|
||||
if(!count)
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u16 buffer_offset = 0;
|
||||
u8 *buffer;
|
||||
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this read
|
||||
if (offset > 0) {
|
||||
sec_start += floor(offset / fd->sectorSize);
|
||||
buffer_offset = offset % fd->sectorSize;
|
||||
sec_start += (sec_t) floor(offset / fd->sectorSize);
|
||||
buffer_offset = (sec_t) offset % fd->sectorSize;
|
||||
}
|
||||
if (count > fd->sectorSize) {
|
||||
sec_count = ceil(count / fd->sectorSize);
|
||||
sec_count = (sec_t) ceil(count / (float)fd->sectorSize);
|
||||
}
|
||||
|
||||
|
||||
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
||||
|
||||
if((offset % fd->sectorSize == 0) && (count % fd->sectorSize == 0)) {
|
||||
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
||||
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Else read into a buffer and copy over only what was requested
|
||||
} else {
|
||||
|
||||
} else
|
||||
{
|
||||
|
||||
// Allocate a buffer to hold the read data
|
||||
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Read from the device
|
||||
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Copy what was requested to the destination buffer
|
||||
memcpy(buf, buffer + buffer_offset, count);
|
||||
ntfs_free(buffer);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
|
||||
{
|
||||
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
||||
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Get the device interface
|
||||
const DISC_INTERFACE* interface = fd->interface;
|
||||
if (!interface) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sec_t sec_start = fd->startSector;
|
||||
|
||||
if(!count)
|
||||
return 0;
|
||||
|
||||
sec_t sec_start = (sec_t) fd->startSector;
|
||||
sec_t sec_count = 1;
|
||||
u16 buffer_offset = 0;
|
||||
u8 *buffer;
|
||||
|
||||
u32 buffer_offset = 0;
|
||||
u8 *buffer = NULL;
|
||||
|
||||
// Determine the range of sectors required for this write
|
||||
if (offset > 0) {
|
||||
sec_start += floor(offset / fd->sectorSize);
|
||||
buffer_offset = offset % fd->sectorSize;
|
||||
sec_start += (sec_t) floor(offset / fd->sectorSize);
|
||||
buffer_offset = (u32) ceil(offset % fd->sectorSize);
|
||||
}
|
||||
if (count > fd->sectorSize) {
|
||||
sec_count = ceil(count / fd->sectorSize);
|
||||
sec_count = (sec_t) ceil((float) count / (float)fd->sectorSize);
|
||||
}
|
||||
|
||||
|
||||
// If this write happens to be on the sector boundaries then do the write straight to disc
|
||||
if((offset % fd->sectorSize == 0) && (count % fd->sectorSize == 0)) {
|
||||
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
||||
@ -391,21 +402,20 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Else write from a buffer aligned to the sector boundaries
|
||||
} else {
|
||||
|
||||
|
||||
// Allocate a buffer to hold the write data
|
||||
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
||||
buffer = (u8*)ntfs_alloc((sec_count+1) * fd->sectorSize);
|
||||
if (!buffer) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the first and last sectors of the buffer from disc (if required)
|
||||
// NOTE: This is done because the data does not line up with the sector boundaries,
|
||||
// NOTE: This is done because the data does not line up with the sector boundaries,
|
||||
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
||||
if((offset % fd->sectorSize == 0)) {
|
||||
if(offset % fd->sectorSize != 0) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
@ -413,36 +423,36 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if((count % fd->sectorSize == 0)) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count, 1, buffer + ((sec_count - 1) * fd->sectorSize))) {
|
||||
if(count % fd->sectorSize != 0) {
|
||||
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count-1, 1, buffer + ((sec_count - 1) * fd->sectorSize))) {
|
||||
ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Copy the data into the write buffer
|
||||
memcpy(buffer + buffer_offset, buf, count);
|
||||
|
||||
|
||||
// Write to the device
|
||||
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
||||
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free the buffer
|
||||
ntfs_free(buffer);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Mark the device as dirty (if we actually wrote anything)
|
||||
if (count)
|
||||
if (count > 0)
|
||||
NDevSetDirty(dev);
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -454,13 +464,12 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the sectors from disc (or cache, if enabled)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
|
||||
return fd->interface->readSectors(sector, numSectors, buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -470,15 +479,15 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Write the sectors to disc (or cache, if enabled)
|
||||
if (fd->cache)
|
||||
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
||||
else
|
||||
return fd->interface->writeSectors(sector, numSectors, buffer);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -489,7 +498,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
{
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
ntfs_log_trace("dev %p\n", dev);
|
||||
|
||||
|
||||
// Check that the device can be written to
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
@ -498,7 +507,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
|
||||
// Mark the device as clean
|
||||
NDevClearDirty(dev);
|
||||
|
||||
|
||||
// Flush any sectors in the disc cache (if required)
|
||||
if (fd->cache) {
|
||||
if (!_NTFS_cache_flush(fd->cache)) {
|
||||
@ -506,7 +515,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -516,18 +525,18 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
||||
static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
{
|
||||
ntfs_log_trace("dev %p, buf %p\n", dev, buf);
|
||||
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
|
||||
// Build the device mode
|
||||
mode_t mode = (S_IFBLK) |
|
||||
(S_IRUSR | S_IRGRP | S_IROTH) |
|
||||
@ -543,7 +552,7 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
buf->st_rdev = fd->interface->ioType;
|
||||
buf->st_blksize = fd->sectorSize;
|
||||
buf->st_blocks = fd->sectorCount;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -553,17 +562,17 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void *argp)
|
||||
{
|
||||
ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);
|
||||
|
||||
|
||||
// Get the device driver descriptor
|
||||
gekko_fd *fd = DEV_FD(dev);
|
||||
if (!fd) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Figure out which i/o control was requested
|
||||
switch (request) {
|
||||
|
||||
|
||||
// Get block device size (sectors)
|
||||
#if defined(BLKGETSIZE)
|
||||
case BLKGETSIZE: {
|
||||
@ -571,7 +580,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Get block device size (bytes)
|
||||
#if defined(BLKGETSIZE64)
|
||||
case BLKGETSIZE64: {
|
||||
@ -579,7 +588,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Get hard drive geometry
|
||||
#if defined(HDIO_GETGEO)
|
||||
case HDIO_GETGEO: {
|
||||
@ -591,7 +600,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Get block device sector size (bytes)
|
||||
#if defined(BLKSSZGET)
|
||||
case BLKSSZGET: {
|
||||
@ -599,7 +608,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Set block device block size (bytes)
|
||||
#if defined(BLKBSZSET)
|
||||
case BLKBSZSET: {
|
||||
@ -613,16 +622,16 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Unimplemented ioctrl
|
||||
default: {
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1197,6 +1197,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get high precision NTFS times
|
||||
*
|
||||
@ -1344,3 +1346,5 @@ int ntfs_inode_set_times(const char *path __attribute__((unused)),
|
||||
errno = EEXIST;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
@ -699,8 +699,8 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
*/
|
||||
int ntfs_empty_logfile(ntfs_attr *na)
|
||||
{
|
||||
s64 pos, count;
|
||||
char buf[NTFS_BUF_SIZE];
|
||||
/*s64 pos, count;
|
||||
char buf[NTFS_BUF_SIZE];*/
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
@ -713,7 +713,7 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, -1, NTFS_BUF_SIZE);
|
||||
/*memset(buf, -1, NTFS_BUF_SIZE);
|
||||
|
||||
pos = 0;
|
||||
while ((count = na->data_size - pos) > 0) {
|
||||
@ -729,7 +729,7 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
return -1;
|
||||
}
|
||||
pos += count;
|
||||
}
|
||||
}*/
|
||||
|
||||
NVolSetLogFileEmpty(na->ni->vol);
|
||||
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef _NTFS_SYS_MEM_ALLOC
|
||||
|
||||
static inline void* ntfs_alloc (size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
@ -42,14 +40,4 @@ static inline void ntfs_free (void* mem) {
|
||||
free(mem);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void* ntfs_alloc (size_t size);
|
||||
void* ntfs_align (size_t size);
|
||||
void ntfs_free (void* mem);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* _MEM_ALLOCATE_H */
|
||||
|
@ -38,6 +38,9 @@
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
@ -81,7 +81,6 @@ void ntfsInit (void)
|
||||
#else
|
||||
ntfs_log_set_handler(ntfs_log_handler_null);
|
||||
#endif
|
||||
|
||||
// Set our current local
|
||||
ntfs_set_locale();
|
||||
|
||||
@ -481,10 +480,15 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
}
|
||||
|
||||
// Build the mount flags
|
||||
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_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)
|
||||
@ -553,6 +557,9 @@ void ntfsUnmount (const char *name, bool force)
|
||||
const char *ntfsGetVolumeName (const char *name)
|
||||
{
|
||||
ntfs_vd *vd = NULL;
|
||||
//ntfs_attr *na = NULL;
|
||||
//ntfschar *ulabel = NULL;
|
||||
//char *volumeName = NULL;
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
@ -564,11 +571,67 @@ const char *ntfsGetVolumeName (const char *name)
|
||||
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;
|
||||
}
|
||||
|
||||
// Get the volumes name
|
||||
return vd->vol->vol_name;
|
||||
// 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)
|
||||
@ -577,8 +640,7 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
ntfs_attr *na = NULL;
|
||||
ntfschar *ulabel = NULL;
|
||||
int ulabel_len;
|
||||
char *label = NULL;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
@ -594,23 +656,10 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
// Allocate a buffer to hold the new volume name
|
||||
label = ntfs_alloc(strlen(volumeName) + 1);
|
||||
if (!label) {
|
||||
ntfsUnlock(vd);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the new volume name
|
||||
memset(label, 0, strlen(volumeName) + 1);
|
||||
strcpy(label, volumeName);
|
||||
|
||||
|
||||
// Convert the new volume name to unicode
|
||||
ulabel_len = ntfsLocalToUnicode(label, &ulabel) * sizeof(ntfschar);
|
||||
ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
|
||||
if (ulabel_len < 0) {
|
||||
ntfs_free(label);
|
||||
ntfsUnlock(vd);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
@ -622,7 +671,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// It does, resize it to match the length of the new volume name
|
||||
if (ntfs_attr_truncate(na, ulabel_len)) {
|
||||
ntfs_free(label);
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
@ -630,7 +678,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// Write the new volume name
|
||||
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
|
||||
ntfs_free(label);
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
@ -640,7 +687,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
// 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(label);
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
@ -648,12 +694,9 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
|
||||
}
|
||||
|
||||
// Update the volumes name (as it has now been changed)
|
||||
if(vd->vol->vol_name) {
|
||||
ntfs_free(vd->vol->vol_name);
|
||||
vd->vol->vol_name = label;
|
||||
}
|
||||
|
||||
// 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);
|
||||
@ -678,4 +721,3 @@ const devoptab_t *ntfsGetDevOpTab (void)
|
||||
{
|
||||
return &devops_ntfs;
|
||||
}
|
||||
|
||||
|
@ -1,161 +1,162 @@
|
||||
/**
|
||||
* ntfs.h - 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
|
||||
*/
|
||||
|
||||
#ifndef _LIBNTFS_H
|
||||
#define _LIBNTFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
#include <gccore.h>
|
||||
#include <ogc/disc_io.h>
|
||||
|
||||
/* NTFS errno values */
|
||||
#define ENOPART 3000 /* No partition was found */
|
||||
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
|
||||
#define EDIRTY 3002 /* Volume is dirty and NTFS_RECOVER was not specified during mount */
|
||||
#define EHIBERNATED 3003 /* Volume is hibernated and NTFS_IGNORE_HIBERFILE was not specified during mount */
|
||||
|
||||
/* NTFS cache options */
|
||||
#define CACHE_DEFAULT_PAGE_COUNT 8 /* The default number of pages in the cache */
|
||||
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
|
||||
|
||||
/* NTFS mount flags */
|
||||
#define NTFS_DEFAULT 0x00000000 /* Standard mount, expects a clean, non-hibernated volume */
|
||||
#define NTFS_SHOW_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
|
||||
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
|
||||
#define NTFS_UPDATE_ACCESS_TIMES 0x00000004 /* Update file and directory access times */
|
||||
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
|
||||
#define NTFS_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
|
||||
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
|
||||
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
|
||||
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md {
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
} ntfs_md;
|
||||
|
||||
/**
|
||||
* Find all NTFS partitions on a block device.
|
||||
*
|
||||
* @param INTERFACE The block device to search
|
||||
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
|
||||
*
|
||||
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing PARTITIONS when finished with it
|
||||
*/
|
||||
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on all inserted block devices.
|
||||
*
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note All device caches are setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on a block devices.
|
||||
*
|
||||
* @param INTERFACE The block device to mount.
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note The device cache is setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount a NTFS partition from a specific sector on a block device.
|
||||
*
|
||||
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
|
||||
* @param INTERFACE The block device to mount
|
||||
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
|
||||
* @param CACHEPAGECOUNT The total number of pages in the device cache
|
||||
* @param CACHEPAGESIZE The number of sectors per cache page
|
||||
* @param FLAGS Additional mounting flags (see above)
|
||||
*
|
||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
||||
* @note ntfsFindPartitions should be used first to locate the partitions start sector
|
||||
*/
|
||||
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
|
||||
|
||||
/**
|
||||
* Unmount a NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
|
||||
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
|
||||
*/
|
||||
extern void ntfsUnmount (const char *name, bool force);
|
||||
|
||||
/**
|
||||
* Get the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
*
|
||||
* @return The volumes name if successful or NULL if an error occurred (see errno)
|
||||
*/
|
||||
extern const char *ntfsGetVolumeName (const char *name);
|
||||
|
||||
/**
|
||||
* Set the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
* @param VOLUMENAME The new volume name
|
||||
*
|
||||
* @return True if mount was successful, false if an error occurred (see errno)
|
||||
* @note The mount must be write-enabled else this will fail
|
||||
*/
|
||||
extern bool ntfsSetVolumeName (const char *name, const char *volumeName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBNTFS_H */
|
||||
|
||||
/*
|
||||
typedef struct _FileInfo FileInfo;
|
||||
|
||||
struct _FileInfo
|
||||
{
|
||||
u64 offset[64];
|
||||
s64 sector[64];
|
||||
u64 count[64];
|
||||
u32 num;
|
||||
u64 filesize;
|
||||
};
|
||||
*/
|
||||
typedef int (*_ntfs_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count);
|
||||
int _NTFS_get_fragments (const char *path, _ntfs_frag_append_t append_fragment, void *callback_data);
|
||||
|
||||
/**
|
||||
* ntfs.h - 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
|
||||
*/
|
||||
|
||||
#ifndef _LIBNTFS_H
|
||||
#define _LIBNTFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gctypes.h>
|
||||
#include <gccore.h>
|
||||
#include <ogc/disc_io.h>
|
||||
|
||||
/* NTFS errno values */
|
||||
#define ENOPART 3000 /* No partition was found */
|
||||
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
|
||||
#define EDIRTY 3002 /* Volume is dirty and NTFS_RECOVER was not specified during mount */
|
||||
#define EHIBERNATED 3003 /* Volume is hibernated and NTFS_IGNORE_HIBERFILE was not specified during mount */
|
||||
|
||||
/* NTFS cache options */
|
||||
#define CACHE_DEFAULT_PAGE_COUNT 8 /* The default number of pages in the cache */
|
||||
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
|
||||
|
||||
/* NTFS mount flags */
|
||||
#define NTFS_DEFAULT 0x00000000 /* Standard mount, expects a clean, non-hibernated volume */
|
||||
#define NTFS_SHOW_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
|
||||
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
|
||||
#define NTFS_UPDATE_ACCESS_TIMES 0x00000004 /* Update file and directory access times */
|
||||
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
|
||||
#define NTFS_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
|
||||
#define NTFS_READ_ONLY 0x00000020 /* Mount in read only mode */
|
||||
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
|
||||
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
|
||||
|
||||
/**
|
||||
* ntfs_md - NTFS mount descriptor
|
||||
*/
|
||||
typedef struct _ntfs_md {
|
||||
char name[32]; /* Mount name (can be accessed as "name:/") */
|
||||
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
|
||||
sec_t startSector; /* Local block address to first sector of partition */
|
||||
} ntfs_md;
|
||||
|
||||
/**
|
||||
* Find all NTFS partitions on a block device.
|
||||
*
|
||||
* @param INTERFACE The block device to search
|
||||
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
|
||||
*
|
||||
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing PARTITIONS when finished with it
|
||||
*/
|
||||
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on all inserted block devices.
|
||||
*
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note All device caches are setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount all NTFS partitions on a block devices.
|
||||
*
|
||||
* @param INTERFACE The block device to mount.
|
||||
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
|
||||
* @param FLAGS Additional mounting flags. (see above)
|
||||
*
|
||||
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
|
||||
* @note The caller is responsible for freeing MOUNTS when finished with it
|
||||
* @note The device cache is setup using default values (see above)
|
||||
*/
|
||||
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
|
||||
|
||||
/**
|
||||
* Mount a NTFS partition from a specific sector on a block device.
|
||||
*
|
||||
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
|
||||
* @param INTERFACE The block device to mount
|
||||
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
|
||||
* @param CACHEPAGECOUNT The total number of pages in the device cache
|
||||
* @param CACHEPAGESIZE The number of sectors per cache page
|
||||
* @param FLAGS Additional mounting flags (see above)
|
||||
*
|
||||
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
|
||||
* @note ntfsFindPartitions should be used first to locate the partitions start sector
|
||||
*/
|
||||
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
|
||||
|
||||
/**
|
||||
* Unmount a NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
|
||||
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
|
||||
*/
|
||||
extern void ntfsUnmount (const char *name, bool force);
|
||||
|
||||
/**
|
||||
* Get the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
*
|
||||
* @return The volumes name if successful or NULL if an error occurred (see errno)
|
||||
*/
|
||||
extern const char *ntfsGetVolumeName (const char *name);
|
||||
|
||||
/**
|
||||
* Set the volume name of a mounted NTFS partition.
|
||||
*
|
||||
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
|
||||
* @param VOLUMENAME The new volume name
|
||||
*
|
||||
* @return True if mount was successful, false if an error occurred (see errno)
|
||||
* @note The mount must be write-enabled else this will fail
|
||||
*/
|
||||
extern bool ntfsSetVolumeName (const char *name, const char *volumeName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBNTFS_H */
|
||||
|
||||
/*
|
||||
typedef struct _FileInfo FileInfo;
|
||||
|
||||
struct _FileInfo
|
||||
{
|
||||
u64 offset[64];
|
||||
s64 sector[64];
|
||||
u64 count[64];
|
||||
u32 num;
|
||||
u64 filesize;
|
||||
};
|
||||
*/
|
||||
typedef int (*_ntfs_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count);
|
||||
int _NTFS_get_fragments (const char *path, _ntfs_frag_append_t append_fragment, void *callback_data);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* ntfs_dir.c - devoptab directory routines for NTFS-based devices.
|
||||
*
|
||||
* Copyright (c) 2010 Dimok
|
||||
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
||||
* Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
*
|
||||
@ -51,7 +52,7 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd)
|
||||
return;
|
||||
|
||||
|
||||
// Free the directory entries (if any)
|
||||
while (dir->first) {
|
||||
ntfs_dir_entry *next = dir->first->next;
|
||||
@ -59,40 +60,47 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
ntfs_free(dir->first);
|
||||
dir->first = next;
|
||||
}
|
||||
|
||||
|
||||
// Close the directory (if open)
|
||||
if (dir->ni)
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
|
||||
|
||||
// Reset the directory state
|
||||
dir->ni = NULL;
|
||||
dir->first = NULL;
|
||||
dir->current = NULL;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!st || !path)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace("path %s, st %p\n", path, st);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!st)
|
||||
|
||||
if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
|
||||
{
|
||||
memset(st, 0, sizeof(struct stat));
|
||||
st->st_mode = S_IFDIR;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry(vd, path);
|
||||
if (!ni) {
|
||||
@ -109,26 +117,28 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
// Close the entry
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
{
|
||||
ntfs_log_trace("existing %s, newLink %s\n", existing, newLink);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(existing);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Create a symbolic link between the two paths
|
||||
ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
|
||||
if (!ni) {
|
||||
@ -136,10 +146,10 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Close the symbolic link
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
@ -161,10 +171,10 @@ int ntfs_unlink_r (struct _reent *r, const char *name)
|
||||
int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
{
|
||||
ntfs_log_trace("name %s\n", name);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(name);
|
||||
if (!vd) {
|
||||
@ -174,7 +184,7 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Find the directory
|
||||
ni = ntfsOpenEntry(vd, name);
|
||||
if (!ni) {
|
||||
@ -182,7 +192,7 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
ntfsCloseEntry(vd, ni);
|
||||
@ -190,27 +200,27 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Close the old current directory (if any)
|
||||
if (vd->cwd_ni)
|
||||
ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
|
||||
|
||||
// Set the new current directory
|
||||
vd->cwd_ni = ni;
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
{
|
||||
ntfs_log_trace("oldName %s, newName %s\n", oldName, newName);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(oldName);
|
||||
if (!vd) {
|
||||
@ -220,14 +230,14 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// You cannot rename between devices
|
||||
if(vd != ntfsGetVolume(newName)) {
|
||||
ntfsUnlock(vd);
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Check that there is no existing entry with the new name
|
||||
ni = ntfsOpenEntry(vd, newName);
|
||||
if (ni) {
|
||||
@ -242,7 +252,7 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Unlink the old entry
|
||||
if (ntfsUnlink(vd, oldName)) {
|
||||
if (ntfsUnlink(vd, newName)) {
|
||||
@ -252,17 +262,17 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
ntfsUnlock(vd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
{
|
||||
ntfs_log_trace("path %s, mode %i\n", path, mode);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
@ -272,10 +282,10 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Create the directory
|
||||
ni = ntfsCreate(vd, path, S_IFDIR, NULL);
|
||||
if (!ni) {
|
||||
@ -283,80 +293,80 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
r->_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Close the directory
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
{
|
||||
ntfs_log_trace("path %s, buf %p\n", path, buf);
|
||||
|
||||
|
||||
ntfs_vd *vd = NULL;
|
||||
s64 size;
|
||||
int delta_bits;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
vd = ntfsGetVolume(path);
|
||||
if (!vd) {
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset(buf, 0, sizeof(struct statvfs));
|
||||
|
||||
|
||||
// File system block size
|
||||
buf->f_bsize = vd->vol->cluster_size;
|
||||
|
||||
|
||||
// Fundamental file system block size
|
||||
buf->f_frsize = vd->vol->cluster_size;
|
||||
|
||||
|
||||
// Total number of blocks on file system in units of f_frsize
|
||||
buf->f_blocks = vd->vol->nr_clusters;
|
||||
|
||||
|
||||
// Free blocks available for all and for non-privileged processes
|
||||
size = MAX(vd->vol->free_clusters, 0);
|
||||
buf->f_bfree = buf->f_bavail = size;
|
||||
|
||||
|
||||
// Free inodes on the free space
|
||||
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
|
||||
if (delta_bits >= 0)
|
||||
size <<= delta_bits;
|
||||
else
|
||||
size >>= -delta_bits;
|
||||
|
||||
|
||||
// Number of inodes at this point in time
|
||||
buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;
|
||||
|
||||
|
||||
// Free inodes available for all and for non-privileged processes
|
||||
size += vd->vol->free_mft_records;
|
||||
buf->f_ffree = buf->f_favail = MAX(size, 0);
|
||||
|
||||
|
||||
// File system id
|
||||
buf->f_fsid = vd->id;
|
||||
|
||||
|
||||
// Bit mask of f_flag values.
|
||||
buf->f_flag = (NVolReadOnly(vd->vol) ? ST_RDONLY : 0);
|
||||
|
||||
|
||||
// Maximum length of filenames
|
||||
buf->f_namemax = NTFS_MAX_NAME_LEN;
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -369,7 +379,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
ntfs_dir_state *dir = STATE(dirState);
|
||||
ntfs_dir_entry *entry = NULL;
|
||||
char *entry_name = NULL;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd) {
|
||||
errno = EINVAL;
|
||||
@ -383,7 +393,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
|
||||
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
|
||||
|
||||
|
||||
// Convert the entry name to our current local
|
||||
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
|
||||
ntfs_free(entry);
|
||||
@ -392,7 +402,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
|
||||
// If this is not the parent or self directory reference
|
||||
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
|
||||
|
||||
|
||||
// Open the entry
|
||||
ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name);
|
||||
if (!ni) {
|
||||
@ -406,21 +416,21 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
ntfs_inode_close(ni);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Close the entry
|
||||
ntfs_inode_close(ni);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Allocate a new directory entry
|
||||
entry = ntfs_alloc(sizeof(ntfs_dir_entry));
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
|
||||
// Setup the entry
|
||||
entry->name = entry_name;
|
||||
entry->next = NULL;
|
||||
|
||||
|
||||
// Link the entry to the directory
|
||||
if (!dir->first) {
|
||||
dir->first = entry;
|
||||
@ -429,7 +439,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
|
||||
while (last->next) last = last->next;
|
||||
last->next = entry;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -441,7 +451,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
s64 position = 0;
|
||||
|
||||
|
||||
// Get the volume descriptor for this path
|
||||
dir->vd = ntfsGetVolume(path);
|
||||
if (!dir->vd) {
|
||||
@ -451,7 +461,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Lock
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
|
||||
// Find the directory
|
||||
dir->ni = ntfsOpenEntry(dir->vd, path);
|
||||
if (!dir->ni) {
|
||||
@ -459,7 +469,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Ensure that this directory is indeed a directory
|
||||
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
|
||||
ntfsCloseEntry(dir->vd, dir->ni);
|
||||
@ -467,7 +477,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
r->_errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Read the directory
|
||||
dir->first = dir->current = NULL;
|
||||
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
|
||||
@ -479,10 +489,10 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
|
||||
// Move to the first entry in the directory
|
||||
dir->current = dir->first;
|
||||
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
|
||||
// Insert the directory into the double-linked FILO list of open directories
|
||||
if (dir->vd->firstOpenDir) {
|
||||
dir->nextOpenDir = dir->vd->firstOpenDir;
|
||||
@ -491,59 +501,59 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
|
||||
dir->nextOpenDir = NULL;
|
||||
}
|
||||
dir->prevOpenDir = NULL;
|
||||
dir->vd->cwd_ni = dir->ni;
|
||||
dir->vd->firstOpenDir = dir;
|
||||
dir->vd->openDirCount++;
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
|
||||
return dirState;
|
||||
}
|
||||
|
||||
int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
ntfs_log_trace("dirState %p\n", dirState);
|
||||
|
||||
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
// Move to the first entry in the directory
|
||||
dir->current = dir->first;
|
||||
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||||
{
|
||||
ntfs_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat);
|
||||
//printf("dirnext %p %p %p\n", dirState, filename, filestat);
|
||||
|
||||
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
ntfs_inode *ni = NULL;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!dir || !dir->vd || !dir->ni) {
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
|
||||
// Check that there is a entry waiting to be fetched
|
||||
if (!dir->current) {
|
||||
ntfsUnlock(dir->vd);
|
||||
@ -553,36 +563,39 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
|
||||
|
||||
// Fetch the current entry
|
||||
strcpy(filename, dir->current->name);
|
||||
if(filestat != NULL) {
|
||||
// ntfsOpenEntry requires full path, or path relative to cwd
|
||||
// so we set cwd temporarily
|
||||
ntfs_inode *tmp_cwd_ni = dir->vd->cwd_ni;
|
||||
dir->vd->cwd_ni = dir->ni;
|
||||
ni = ntfsOpenEntry(dir->vd, dir->current->name);
|
||||
dir->vd->cwd_ni = tmp_cwd_ni;
|
||||
//printf("openEn: %p\n", ni);
|
||||
if (ni) {
|
||||
ntfsStat(dir->vd, ni, filestat);
|
||||
ntfsCloseEntry(dir->vd, ni);
|
||||
if(filestat != NULL)
|
||||
{
|
||||
if(strcmp(dir->current->name, ".") == 0 || strcmp(dir->current->name, "..") == 0)
|
||||
{
|
||||
memset(filestat, 0, sizeof(struct stat));
|
||||
filestat->st_mode = S_IFDIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ni = ntfsOpenEntry(dir->vd, dir->current->name);
|
||||
if (ni) {
|
||||
ntfsStat(dir->vd, ni, filestat);
|
||||
ntfsCloseEntry(dir->vd, ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Move to the next entry in the directory
|
||||
dir->current = dir->current->next;
|
||||
|
||||
|
||||
// Update directory times
|
||||
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
ntfs_log_trace("dirState %p\n", dirState);
|
||||
|
||||
|
||||
ntfs_dir_state* dir = STATE(dirState);
|
||||
|
||||
// Sanity check
|
||||
@ -590,13 +603,13 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(dir->vd);
|
||||
|
||||
|
||||
// Close the directory
|
||||
ntfsCloseDir(dir);
|
||||
|
||||
|
||||
// Remove the directory from the double-linked FILO list of open directories
|
||||
dir->vd->openDirCount--;
|
||||
if (dir->nextOpenDir)
|
||||
@ -605,9 +618,9 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
|
||||
else
|
||||
dir->vd->firstOpenDir = dir->nextOpenDir;
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(dir->vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -41,7 +41,6 @@
|
||||
|
||||
#include "ntfsinternal.h"
|
||||
#include "ntfsfile.h"
|
||||
#include "ntfs.h"
|
||||
|
||||
#define STATE(x) ((ntfs_file_state*)x)
|
||||
|
||||
@ -53,10 +52,11 @@ void ntfsCloseFile (ntfs_file_state *file)
|
||||
|
||||
// Special case fix ups for compressed and/or encrypted files
|
||||
if (file->compressed)
|
||||
ntfs_attr_pclose(file->data_na);
|
||||
ntfs_attr_pclose(file->data_na);
|
||||
#ifdef HAVE_SETXATTR
|
||||
if (file->encrypted)
|
||||
ntfs_efs_fixup_attribute(NULL, file->data_na);
|
||||
|
||||
#endif
|
||||
// Close the file data attribute (if open)
|
||||
if (file->data_na)
|
||||
ntfs_attr_close(file->data_na);
|
||||
@ -198,6 +198,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
// Set the files current position and length
|
||||
file->pos = 0;
|
||||
file->len = file->data_na->data_size;
|
||||
|
||||
ntfs_log_trace("file->len %d\n", file->len);
|
||||
|
||||
// Update file times
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
@ -354,8 +356,11 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
if (file->pos + len > file->len) {
|
||||
r->_errno = EOVERFLOW;
|
||||
len = file->len - file->pos;
|
||||
ntfs_log_trace("EOVERFLOW");
|
||||
}
|
||||
|
||||
ntfs_log_trace("file->pos:%d, len:%d, file->len:%d \n", (u32)file->pos, (u32)len, (u32)file->len);
|
||||
|
||||
// Read from the files data attribute
|
||||
while (len) {
|
||||
ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
|
||||
@ -369,7 +374,7 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||
file->pos += ret;
|
||||
read += ret;
|
||||
}
|
||||
|
||||
//ntfs_log_trace("file->pos: %d \n", (u32)file->pos);
|
||||
// Update file times (if we actually read something)
|
||||
if (read)
|
||||
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
|
||||
|
@ -43,9 +43,7 @@ typedef struct _ntfs_file_state {
|
||||
bool compressed; /* True if file data is compressed */
|
||||
bool encrypted; /* True if file data is encryted */
|
||||
off_t pos; /* Current position within the file (in bytes) */
|
||||
//size_t len; /* Total length of the file (in bytes) */
|
||||
//size_t is 32 bit, off_t is signed, so use u64 for len!
|
||||
u64 len; /* Total length of the file (in bytes) */
|
||||
size_t len; /* Total length of the file (in bytes) */
|
||||
struct _ntfs_file_state *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */
|
||||
struct _ntfs_file_state *nextOpenFile; /* The next entry in a double-linked FILO list of open files */
|
||||
} ntfs_file_state;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* ntfsinternal.h - Internal support routines for NTFS-based devices.
|
||||
*
|
||||
* Copyright (c) 2010 Dimok
|
||||
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
||||
* Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
*
|
||||
@ -67,24 +68,24 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
||||
devoptab_t *dev = NULL;
|
||||
char *devname = NULL;
|
||||
int i;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!name || !deviceData || !devoptab_ntfs) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Allocate a devoptab for this device
|
||||
dev = ntfs_alloc(sizeof(devoptab_t) + strlen(name) + 1);
|
||||
if (!dev) {
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Use the space allocated at the end of the devoptab for storing the device name
|
||||
devname = (char*)(dev + 1);
|
||||
strcpy(devname, name);
|
||||
|
||||
|
||||
// Setup the devoptab
|
||||
memcpy(dev, devoptab_ntfs, sizeof(devoptab_t));
|
||||
dev->name = devname;
|
||||
@ -97,7 +98,7 @@ int ntfsAddDevice (const char *name, void *deviceData)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we reach here then there are no free slots in the devoptab table for this device
|
||||
errno = EADDRNOTAVAIL;
|
||||
return -1;
|
||||
@ -108,11 +109,11 @@ void ntfsRemoveDevice (const char *path)
|
||||
const devoptab_t *devoptab = NULL;
|
||||
char name[128] = {0};
|
||||
int i;
|
||||
|
||||
|
||||
// Get the device name from the path
|
||||
strncpy(name, path, 127);
|
||||
strtok(name, ":/");
|
||||
|
||||
|
||||
// Find and remove the specified device from the devoptab table
|
||||
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
||||
// which ignores names with suffixes and causes names
|
||||
@ -127,7 +128,7 @@ void ntfsRemoveDevice (const char *path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -136,13 +137,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
|
||||
const devoptab_t *devoptab = NULL;
|
||||
char name[128] = {0};
|
||||
int i;
|
||||
|
||||
|
||||
// Get the device name from the path
|
||||
strncpy(name, path, 127);
|
||||
strtok(name, ":/");
|
||||
|
||||
|
||||
// Search the devoptab table for the specified device name
|
||||
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
||||
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
||||
// which ignores names with suffixes and causes names
|
||||
// like "ntfs" and "ntfs1" to be seen as equals
|
||||
for (i = 0; i < STD_MAX; i++) {
|
||||
@ -153,13 +154,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we reach here then we couldn't find the device name,
|
||||
// chances are that this path has no device name in it.
|
||||
// chances are that this path has no device name in it.
|
||||
// Call GetDeviceOpTab to get our default device (chdir).
|
||||
if (useDefaultDevice)
|
||||
return GetDeviceOpTab("");
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -176,7 +177,7 @@ ntfs_vd *ntfsGetVolume (const char *path)
|
||||
const devoptab_t *devoptab = ntfsGetDevice(path, true);
|
||||
if (devoptab && devoptab_ntfs && (devoptab->open_r == devoptab_ntfs->open_r))
|
||||
return (ntfs_vd*)devoptab->deviceData;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -187,19 +188,22 @@ int ntfsInitVolume (ntfs_vd *vd)
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Initialise the volume lock
|
||||
LWP_MutexInit(&vd->lock, false);
|
||||
|
||||
|
||||
// Reset the volumes name cache
|
||||
vd->name[0] = '\0';
|
||||
|
||||
// Reset the volumes current directory
|
||||
vd->cwd_ni = NULL;
|
||||
|
||||
|
||||
// Reset open directory and file stats
|
||||
vd->openDirCount = 0;
|
||||
vd->openFileCount = 0;
|
||||
vd->firstOpenDir = NULL;
|
||||
vd->firstOpenFile = NULL;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -210,7 +214,7 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
errno = ENODEV;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
@ -221,7 +225,7 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
ntfsCloseDir(nextDir);
|
||||
nextDir = nextDir->nextOpenDir;
|
||||
}
|
||||
|
||||
|
||||
// Close any files which are still open (lazy programmers!)
|
||||
ntfs_file_state *nextFile = vd->firstOpenFile;
|
||||
while (nextFile) {
|
||||
@ -229,28 +233,28 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
ntfsCloseFile(nextFile);
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
}
|
||||
|
||||
|
||||
// Reset open directory and file stats
|
||||
vd->openDirCount = 0;
|
||||
vd->openFileCount = 0;
|
||||
vd->firstOpenDir = NULL;
|
||||
vd->firstOpenFile = NULL;
|
||||
|
||||
|
||||
// Close the volumes current directory (if any)
|
||||
if (vd->cwd_ni) {
|
||||
ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
vd->cwd_ni = NULL;
|
||||
}
|
||||
|
||||
//if (vd->cwd_ni) {
|
||||
//ntfsCloseEntry(vd, vd->cwd_ni);
|
||||
//vd->cwd_ni = NULL;
|
||||
//}
|
||||
|
||||
// Force the underlying device to sync
|
||||
vd->dev->d_ops->sync(vd->dev);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
// Deinitialise the volume lock
|
||||
LWP_MutexDestroy(vd->lock);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -264,13 +268,13 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
||||
ntfs_inode *ni = NULL;
|
||||
char *target = NULL;
|
||||
int attr_size;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Get the actual path of the entry
|
||||
path = ntfsRealPath(path);
|
||||
if (!path) {
|
||||
@ -285,26 +289,26 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
||||
ni = ntfs_pathname_to_inode(vd->vol, vd->cwd_ni, path++);
|
||||
else
|
||||
ni = ntfs_pathname_to_inode(vd->vol, NULL, path);
|
||||
|
||||
|
||||
// If the entry was found and it has reparse data then parse its true path;
|
||||
// this resolves the true location of symbolic links and directory junctions
|
||||
if (ni && (ni->flags & FILE_ATTR_REPARSE_POINT)) {
|
||||
if (ntfs_possible_symlink(ni)) {
|
||||
|
||||
|
||||
// Sanity check, give up if we are parsing to deep
|
||||
if (reparseLevel > NTFS_MAX_SYMLINK_DEPTH) {
|
||||
ntfsCloseEntry(vd, ni);
|
||||
errno = ELOOP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Get the target path of this entry
|
||||
target = ntfs_make_symlink(path, ni, &attr_size);
|
||||
if (!target) {
|
||||
ntfsCloseEntry(vd, ni);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Close the entry (we are no longer interested in it)
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
@ -313,10 +317,10 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
|
||||
|
||||
// Clean up
|
||||
ntfs_free(target);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
@ -327,23 +331,24 @@ void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni)
|
||||
errno = ENODEV;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Sync the entry (if it is dirty)
|
||||
if (NInoDirty(ni))
|
||||
ntfsSync(vd, ni);
|
||||
|
||||
|
||||
// Close the entry
|
||||
ntfs_inode_close(ni);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target)
|
||||
{
|
||||
ntfs_inode *dir_ni = NULL, *ni = NULL;
|
||||
@ -357,7 +362,7 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// You cannot link between devices
|
||||
if(target) {
|
||||
if(vd != ntfsGetVolume(target)) {
|
||||
@ -369,14 +374,14 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
// Get the actual paths of the entry
|
||||
path = ntfsRealPath(path);
|
||||
target = ntfsRealPath(target);
|
||||
if (!path || !target) {
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Get the unicode name for the entry and find its parent directory
|
||||
// TODO: This looks horrible, clean it up
|
||||
dir = strdup(path);
|
||||
@ -394,8 +399,13 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
*name = 0;
|
||||
|
||||
name = strrchr(dir, '/');
|
||||
if(name)
|
||||
{
|
||||
name++;
|
||||
name[0] = 0;
|
||||
}
|
||||
|
||||
// Open the entries parent directory
|
||||
dir_ni = ntfsOpenEntry(vd, dir);
|
||||
if (!dir_ni) {
|
||||
@ -404,9 +414,13 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
|
||||
// Create the entry
|
||||
switch (type) {
|
||||
|
||||
|
||||
// Symbolic link
|
||||
case S_IFLNK:
|
||||
if (!target) {
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
utarget_len = ntfsLocalToUnicode(target, &utarget);
|
||||
if (utarget_len < 0) {
|
||||
errno = EINVAL;
|
||||
@ -414,49 +428,49 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
}
|
||||
ni = ntfs_create_symlink(dir_ni, 0, uname, uname_len, utarget, utarget_len);
|
||||
break;
|
||||
|
||||
|
||||
// Directory or file
|
||||
case S_IFDIR:
|
||||
case S_IFREG:
|
||||
ni = ntfs_create(dir_ni, 0, uname, uname_len, type);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// If the entry was created
|
||||
if (ni) {
|
||||
|
||||
|
||||
// Mark the entry for archiving
|
||||
ni->flags |= FILE_ATTR_ARCHIVE;
|
||||
|
||||
|
||||
// Mark the entry as dirty
|
||||
NInoSetDirty(ni);
|
||||
|
||||
|
||||
// Sync the entry to disc
|
||||
ntfsSync(vd, ni);
|
||||
|
||||
|
||||
// Update parent directories times
|
||||
ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
if(dir_ni)
|
||||
ntfsCloseEntry(vd, dir_ni);
|
||||
|
||||
|
||||
if(utarget)
|
||||
ntfs_free(utarget);
|
||||
|
||||
|
||||
if(uname)
|
||||
ntfs_free(uname);
|
||||
|
||||
|
||||
if(dir)
|
||||
ntfs_free(dir);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
@ -468,13 +482,13 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
ntfschar *uname = NULL;
|
||||
int uname_len;
|
||||
int res = 0;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// You cannot link between devices
|
||||
if(vd != ntfsGetVolume(new_path)) {
|
||||
errno = EXDEV;
|
||||
@ -491,7 +505,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Get the unicode name for the entry and find its parent directory
|
||||
// TODO: This looks horrible, clean it up
|
||||
dir = strdup(new_path);
|
||||
@ -510,7 +524,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
goto cleanup;
|
||||
}
|
||||
*name = 0;
|
||||
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry(vd, old_path);
|
||||
if (!ni) {
|
||||
@ -518,7 +532,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Open the entries new parent directory
|
||||
dir_ni = ntfsOpenEntry(vd, dir);
|
||||
if (!dir_ni) {
|
||||
@ -526,37 +540,37 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Link the entry to its new parent
|
||||
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Update entry times
|
||||
ntfsUpdateTimes(vd, ni, NTFS_UPDATE_CTIME);
|
||||
ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);
|
||||
|
||||
|
||||
// Sync the entry to disc
|
||||
ntfsSync(vd, ni);
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
|
||||
if(dir_ni)
|
||||
ntfsCloseEntry(vd, dir_ni);
|
||||
|
||||
if(ni)
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
|
||||
if(uname)
|
||||
ntfs_free(uname);
|
||||
|
||||
|
||||
if(dir)
|
||||
ntfs_free(dir);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -568,23 +582,23 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
ntfschar *uname = NULL;
|
||||
int uname_len;
|
||||
int res = 0;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Get the actual path of the entry
|
||||
path = ntfsRealPath(path);
|
||||
if (!path) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Get the unicode name for the entry and find its parent directory
|
||||
// TODO: This looks horrible
|
||||
dir = strdup(path);
|
||||
@ -602,8 +616,13 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
*name = 0;
|
||||
|
||||
name = strrchr(dir, '/');
|
||||
if(name)
|
||||
{
|
||||
name++;
|
||||
name[0] = 0;
|
||||
}
|
||||
|
||||
// Find the entry
|
||||
ni = ntfsOpenEntry(vd, path);
|
||||
if (!ni) {
|
||||
@ -611,7 +630,7 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Open the entries parent directory
|
||||
dir_ni = ntfsOpenEntry(vd, dir);
|
||||
if (!dir_ni) {
|
||||
@ -619,76 +638,75 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
|
||||
res = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
// Unlink the entry from its parent
|
||||
if (ntfs_delete(vd->vol, path, ni, dir_ni, uname, uname_len)) {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
|
||||
// Force the underlying device to sync
|
||||
vd->dev->d_ops->sync(vd->dev);
|
||||
|
||||
|
||||
// ntfs_delete() ALWAYS closes ni and dir_ni; so no need for us to anymore
|
||||
dir_ni = ni = NULL;
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
|
||||
if(dir_ni)
|
||||
ntfsCloseEntry(vd, dir_ni);
|
||||
|
||||
|
||||
if(ni)
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
|
||||
if(uname)
|
||||
ntfs_free(uname);
|
||||
|
||||
|
||||
if(dir)
|
||||
ntfs_free(dir);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
vd->dev->d_ops->sync(vd->dev);
|
||||
|
||||
vd->dev->d_ops->sync(vd->dev);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return res;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
{
|
||||
//printf("ntfsStat %p %p %p\n", vd, ni, st);
|
||||
ntfs_attr *na = NULL;
|
||||
int res = 0;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!vd) {
|
||||
errno = ENODEV;
|
||||
@ -700,22 +718,22 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Short circuit cases were we don't actually have to do anything
|
||||
if (!st)
|
||||
return 0;
|
||||
|
||||
|
||||
// Lock
|
||||
ntfsLock(vd);
|
||||
|
||||
|
||||
// Zero out the stat buffer
|
||||
memset(st, 0, sizeof(struct stat));
|
||||
|
||||
|
||||
// Is this entry a directory
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||
st->st_mode = S_IFDIR | (0777 & ~vd->dmask);
|
||||
st->st_nlink = 1;
|
||||
|
||||
|
||||
// Open the directories index allocation table attribute
|
||||
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
|
||||
if (na) {
|
||||
@ -723,7 +741,7 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
st->st_blocks = na->allocated_size >> 9;
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
|
||||
|
||||
// Else it must be a file
|
||||
} else {
|
||||
st->st_mode = S_IFREG | (0777 & ~vd->fmask);
|
||||
@ -731,7 +749,7 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
st->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
st->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
}
|
||||
|
||||
|
||||
// Fill in the generic entry stats
|
||||
st->st_dev = vd->id;
|
||||
st->st_uid = vd->uid;
|
||||
@ -740,13 +758,13 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
|
||||
st->st_atime = ni->last_access_time;
|
||||
st->st_ctime = ni->last_mft_change_time;
|
||||
st->st_mtime = ni->last_data_change_time;
|
||||
|
||||
|
||||
// Update entry times
|
||||
ntfsUpdateTimes(vd, ni, NTFS_UPDATE_ATIME);
|
||||
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -759,7 +777,7 @@ void ntfsUpdateTimes (ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask)
|
||||
// Update entry times
|
||||
if (ni && mask)
|
||||
ntfs_inode_update_times(ni, mask);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -768,7 +786,7 @@ const char *ntfsRealPath (const char *path)
|
||||
// Sanity check
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
|
||||
// Move the path pointer to the start of the actual path
|
||||
if (strchr(path, ':') != NULL) {
|
||||
path = strchr(path, ':') + 1;
|
||||
@ -776,7 +794,7 @@ const char *ntfsRealPath (const char *path)
|
||||
if (strchr(path, ':') != NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -784,15 +802,15 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
|
||||
{
|
||||
int len = 0;
|
||||
int i;
|
||||
|
||||
|
||||
// Sanity check
|
||||
if (!ins || !ins_len || !outs)
|
||||
return 0;
|
||||
|
||||
|
||||
// Convert the unicode string to our current local
|
||||
len = ntfs_ucstombs(ins, ins_len, outs, outs_len);
|
||||
len = ntfs_ucstombs(ins, ins_len, outs, outs_len);
|
||||
if (len == -1 && errno == EILSEQ) {
|
||||
|
||||
|
||||
// The string could not be converted to the current local,
|
||||
// do it manually by replacing non-ASCII characters with underscores
|
||||
if (!*outs || outs_len >= ins_len) {
|
||||
@ -812,9 +830,9 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
|
||||
*outs[ins_len] = (ntfschar)'\0';
|
||||
len = ins_len;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -823,7 +841,7 @@ int ntfsLocalToUnicode (const char *ins, ntfschar **outs)
|
||||
// Sanity check
|
||||
if (!ins || !outs)
|
||||
return 0;
|
||||
|
||||
|
||||
// Convert the local string to unicode
|
||||
return ntfs_mbstoucs(ins, outs);
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ typedef struct _ntfs_vd {
|
||||
mutex_t lock; /* Volume lock mutex */
|
||||
s64 id; /* Filesystem id */
|
||||
u32 flags; /* Mount flags */
|
||||
char name[128]; /* Volume name (cached) */
|
||||
u16 uid; /* User id for entry creation */
|
||||
u16 gid; /* Group id for entry creation */
|
||||
u16 fmask; /* Unix style permission mask for file creation */
|
||||
|
@ -598,7 +598,7 @@ static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction,
|
||||
if (*p == '/')
|
||||
level++;
|
||||
fulltarget = (char*)ntfs_malloc(3*level
|
||||
+ sizeof(mappingdir) + count - 4);
|
||||
+ sizeof(mappingdir) + strlen(target) - 3);
|
||||
if (fulltarget) {
|
||||
fulltarget[0] = 0;
|
||||
if (level > 1) {
|
||||
@ -721,7 +721,7 @@ static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
|
||||
if (*p == '/')
|
||||
level++;
|
||||
fulltarget = (char*)ntfs_malloc(3*level
|
||||
+ sizeof(mappingdir) + count - 4);
|
||||
+ sizeof(mappingdir) + strlen(target) - 3);
|
||||
if (fulltarget) {
|
||||
fulltarget[0] = 0;
|
||||
if (level > 1) {
|
||||
@ -914,6 +914,8 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
|
||||
return (possible);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Set the index for new reparse data
|
||||
*
|
||||
@ -951,6 +953,8 @@ static int set_reparse_index(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
return (ntfs_ie_add(xr,(INDEX_ENTRY*)&indx));
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Remove a reparse data index entry if attribute present
|
||||
*
|
||||
@ -1015,6 +1019,8 @@ static ntfs_index_context *open_reparse_index(ntfs_volume *vol)
|
||||
return (xr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Update the reparse data and index
|
||||
*
|
||||
@ -1079,6 +1085,8 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Delete a reparse index entry
|
||||
*
|
||||
@ -1116,6 +1124,8 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
|
||||
return (res);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs reparse data into an extended attribute
|
||||
*
|
||||
@ -1294,3 +1304,5 @@ int ntfs_remove_ntfs_reparse_data(const char *path __attribute__((unused)),
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
@ -41,6 +41,9 @@
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
@ -2893,6 +2896,8 @@ BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx,
|
||||
return (allowed);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
/*
|
||||
@ -3074,6 +3079,8 @@ int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx,
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Set new permissions to a file
|
||||
* Checks user mapping has been defined before request for setting
|
||||
@ -3988,6 +3995,8 @@ int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path)
|
||||
return (!scx->mapping[MAPUSERS] || link_group_members(scx));
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs attribute into an extended attribute
|
||||
* The attribute is returned according to cpu endianness
|
||||
@ -4073,6 +4082,8 @@ int ntfs_set_ntfs_attrib(const char *path __attribute__((unused)),
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Open $Secure once for all
|
||||
* returns zero if it succeeds
|
||||
|
@ -577,8 +577,9 @@ int MenuDiscList() {
|
||||
w.Append(&sdcardBtn);
|
||||
w.Append(&poweroffBtn);
|
||||
w.Append(&gameInfo);
|
||||
if (Settings.godmode && load_from_fs != PART_FS_NTFS)
|
||||
w.Append(&installBtn);
|
||||
if (Settings.godmode) {
|
||||
w.Append(&installBtn);
|
||||
}
|
||||
w.Append(&homeBtn);
|
||||
w.Append(&settingsBtn);
|
||||
w.Append(&DownloadBtn);
|
||||
@ -819,12 +820,8 @@ int MenuDiscList() {
|
||||
gprintf("\n\tNew Disc Detected");
|
||||
choice = WindowPrompt(tr("New Disc Detected"),0,tr("Install"),tr("Mount DVD drive"),tr("Cancel"));
|
||||
if (choice == 1) {
|
||||
if (load_from_fs == PART_FS_NTFS) {
|
||||
WindowPrompt(tr("Install not possible"), tr("You are using NTFS filesystem. Due to possible write errors to a NTFS partition, installing a game is not possible."), tr("OK"));
|
||||
} else {
|
||||
menu = MENU_INSTALL;
|
||||
break;
|
||||
}
|
||||
menu = MENU_INSTALL;
|
||||
break;
|
||||
}
|
||||
else if (choice ==2)
|
||||
{
|
||||
|
@ -97,6 +97,7 @@ int MenuInstall() {
|
||||
|
||||
sprintf(gametxt, "%s", tr("Installing game:"));
|
||||
|
||||
/*
|
||||
if (gamesize > freespace) {
|
||||
char errortxt[50];
|
||||
sprintf(errortxt, "%s: %.2fGB, %s: %.2fGB",tr("Game Size"), gamesize, tr("Free Space"), freespace);
|
||||
@ -104,6 +105,7 @@ int MenuInstall() {
|
||||
menu = MENU_DISCLIST;
|
||||
break;
|
||||
} else {
|
||||
*/
|
||||
USBStorage_Watchdog(0);
|
||||
SetupGameInstallProgress(gametxt, name);
|
||||
ret = WBFS_AddGame();
|
||||
@ -129,7 +131,7 @@ int MenuInstall() {
|
||||
menu = MENU_DISCLIST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// }
|
||||
} else {
|
||||
menu = MENU_DISCLIST;
|
||||
break;
|
||||
|
@ -49,7 +49,8 @@ static const char *opts_language[settings_language_max] = {trNOOP("Console Defau
|
||||
static const char *opts_cios[settings_ios_max] = {"IOS 249","IOS 222", "IOS 223", "IOS 250"};
|
||||
static const char *opts_parentalcontrol[5] = {trNOOP("0 (Everyone)"),trNOOP("1 (Child 7+)"),trNOOP("2 (Teen 12+)"),trNOOP("3 (Mature 16+)"),trNOOP("4 (Adults Only 18+)")};
|
||||
static const char *opts_error002[settings_error002_max] = {trNOOP("No"),trNOOP("Yes"),trNOOP("Anti")};
|
||||
static const char *opts_partitions[settings_partitions_max] = {trNOOP("Game partition"),trNOOP("All partitions")};
|
||||
static const char *opts_partitions[settings_partitions_max] = {trNOOP("Game partition"),trNOOP("All partitions"), trNOOP("Remove update")};
|
||||
static const char *opts_installdir[settings_installdir_max] = {trNOOP("None"), trNOOP("GAMEID_Gamename"), trNOOP("Gamename [GAMEID]")};
|
||||
|
||||
bool IsValidPartition(int fs_type, int cios) {
|
||||
if (cios == 249 || cios == 250) {
|
||||
@ -1035,10 +1036,9 @@ int MenuSettings()
|
||||
if (ret == ++Idx || firstRun)
|
||||
{
|
||||
if (firstRun) options2.SetName(Idx, "%s", tr("FAT: Use directories"));
|
||||
if (ret == Idx) {
|
||||
Settings.FatInstallToDir = Settings.FatInstallToDir == 0 ? 1 : 0;
|
||||
}
|
||||
options2.SetValue(Idx, "%s", tr(opts_no_yes[Settings.FatInstallToDir]));
|
||||
if (ret == Idx && ++Settings.FatInstallToDir >= settings_installdir_max)
|
||||
Settings.FatInstallToDir = 0;
|
||||
options2.SetValue(Idx, "%s", tr(opts_installdir[Settings.FatInstallToDir]));
|
||||
}
|
||||
|
||||
if(ret == ++Idx || firstRun)
|
||||
|
@ -283,8 +283,7 @@ extern "C" {
|
||||
settings_error002_max // always the last entry
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
enum {
|
||||
wiilight_off=0,
|
||||
wiilight_on,
|
||||
wiilight_forInstall,
|
||||
@ -378,8 +377,15 @@ extern "C" {
|
||||
enum {
|
||||
install_game_only,
|
||||
install_all,
|
||||
install_all_but_update,
|
||||
settings_partitions_max // always the last entry
|
||||
};
|
||||
enum {
|
||||
not_install_to_dir,
|
||||
install_to_gameid_name,
|
||||
install_to_name_gameid,
|
||||
settings_installdir_max // always the last entry
|
||||
};
|
||||
struct SParental {
|
||||
u8 enabled;
|
||||
u8 rating;
|
||||
|
@ -624,11 +624,22 @@ f32 WBFS_EstimeGameSize(void) {
|
||||
return WBFS_FAT_EstimateGameSize();
|
||||
}
|
||||
|
||||
partition_selector_t part_sel;
|
||||
partition_selector_t part_sel = ONLY_GAME_PARTITION;
|
||||
if (Settings.fullcopy) {
|
||||
part_sel = ALL_PARTITIONS;
|
||||
} else {
|
||||
part_sel = Settings.partitions_to_install == install_game_only ? ONLY_GAME_PARTITION : ALL_PARTITIONS;
|
||||
switch(Settings.partitions_to_install)
|
||||
{
|
||||
case install_game_only:
|
||||
part_sel = ONLY_GAME_PARTITION;
|
||||
break;
|
||||
case install_all:
|
||||
part_sel = ALL_PARTITIONS;
|
||||
break;
|
||||
case install_all_but_update:
|
||||
part_sel = REMOVE_UPDATE_PARTITION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return wbfs_estimate_disc(hdd, __WBFS_ReadDVD, NULL, part_sel);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
char wbfs_fs_drive[16];
|
||||
char wbfs_fat_dir[16] = "/wbfs";
|
||||
char invalid_path[] = "/\\:|<>?*\"'";
|
||||
|
||||
int wbfs_fat_vfs_have = 0;
|
||||
int wbfs_fat_vfs_lba = 0;
|
||||
@ -99,15 +100,23 @@ s32 _WBFS_FAT_GetHeadersCount()
|
||||
is_dir = S_ISDIR(st.st_mode);
|
||||
//printf("mode: %d %d %x\n", is_dir, st.st_mode, st.st_mode);
|
||||
if (is_dir) {
|
||||
int lay_a = 0;
|
||||
int lay_b = 0;
|
||||
if (fname[6] == '_' && is_gameid((char*)id)) {
|
||||
// usb:/wbfs/GAMEID_TITLE/GAMEID.wbfs
|
||||
lay_a = 1;
|
||||
}
|
||||
if (fname[len-8] == '[' && fname[len-1] == ']' && is_gameid(&fname[len-7])) {
|
||||
// usb:/wbfs/TITLE[GAMEID]/GAMEID.wbfs
|
||||
lay_b = 1;
|
||||
}
|
||||
if (!lay_a && !lay_b) continue;
|
||||
if (lay_a) {
|
||||
strncpy(dir_title, &fname[7], sizeof(dir_title));
|
||||
} else {
|
||||
// usb:/wbfs/TITLE[GAMEID]/GAMEID.wbfs
|
||||
if (fname[len-8] != '[' || fname[len-1] != ']') continue;
|
||||
try_lay_b:
|
||||
memcpy(id, &fname[len-7], 6);
|
||||
id[6] = 0;
|
||||
if (!is_gameid((char*)id)) continue;
|
||||
strncpy(dir_title, fname, sizeof(dir_title));
|
||||
dir_title[len-8] = 0; // cut at '['
|
||||
int n = strlen(dir_title);
|
||||
@ -116,24 +125,30 @@ s32 _WBFS_FAT_GetHeadersCount()
|
||||
if (dir_title[n - 1] == ' ' || dir_title[n - 1] == '_' ) {
|
||||
dir_title[n - 1] = 0;
|
||||
}
|
||||
if (strlen(dir_title) == 0) continue;
|
||||
}
|
||||
snprintf(fpath, sizeof(fpath), "%s/%s/%s.wbfs", path, fname, id);
|
||||
//printf("path2: %s\n", fpath);
|
||||
// if more than 50 games, skip second stat to improve speed
|
||||
if (fat_hdr_count < 50) {
|
||||
do_stat2:
|
||||
// but if ambiguous layout check anyway
|
||||
if (fat_hdr_count < 50 || (lay_a && lay_b)) {
|
||||
if (stat(fpath, &st) == -1) {
|
||||
//printf("missing: %s\n", fpath);
|
||||
// try .iso
|
||||
strcpy(strrchr(fpath, '.'), ".iso"); // replace .wbfs with .iso
|
||||
if (stat(fpath, &st) == -1) {
|
||||
//printf("missing: %s\n", fpath);
|
||||
if (lay_a && lay_b == 1) {
|
||||
// mark lay_b so that the stat check is still done,
|
||||
// but lay_b is not re-tried again
|
||||
lay_b = 2;
|
||||
// retry with layout b
|
||||
goto try_lay_b;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just check if gameid is valid (alphanum)
|
||||
if (!is_gameid((char*)id)) goto do_stat2;
|
||||
st.st_size = 1024*1024;
|
||||
}
|
||||
} else {
|
||||
@ -347,23 +362,51 @@ void WBFS_FAT_fname(u8 *id, char *fname, int len, char *path)
|
||||
}
|
||||
}
|
||||
|
||||
void mk_gameid_title(struct discHdr *header, char *name, int re_space)
|
||||
// format title so that it is usable in a filename
|
||||
void title_filename(char *title)
|
||||
{
|
||||
int i, len;
|
||||
// trim leading space
|
||||
len = strlen(title);
|
||||
while (*title == ' ') {
|
||||
memmove(title, title+1, len);
|
||||
len--;
|
||||
}
|
||||
// trim trailing space - not allowed on windows directories
|
||||
while (len && title[len-1] == ' ') {
|
||||
title[len-1] = 0;
|
||||
len--;
|
||||
}
|
||||
// replace silly chars with '_'
|
||||
for (i=0; i<len; i++) {
|
||||
if(strchr(invalid_path, title[i]) || iscntrl((int) title[i])) {
|
||||
title[i] = '_';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mk_gameid_title(struct discHdr *header, char *name, int re_space, int layout)
|
||||
{
|
||||
int i, len;
|
||||
char title[65];
|
||||
char id[8];
|
||||
|
||||
memcpy(name, header->id, 6);
|
||||
name[6] = 0;
|
||||
strcat(name, "_");
|
||||
strcat(name, get_title(header));
|
||||
strncpy(title, get_title(header), sizeof(title));
|
||||
title_filename(title);
|
||||
|
||||
// replace silly chars with '_'
|
||||
len = strlen(name);
|
||||
for (i = 0; i < len; i++) {
|
||||
if(strchr("\\/:<>|\"", name[i]) || iscntrl((u32) name[i])) {
|
||||
name[i] = '_';
|
||||
}
|
||||
if(re_space && name[i]==' ') {
|
||||
name[i] = '_';
|
||||
if (layout == 0) {
|
||||
sprintf(name, "%s_%s", id, title);
|
||||
} else {
|
||||
sprintf(name, "%s [%s]", title, id);
|
||||
}
|
||||
|
||||
// replace space with '_'
|
||||
if (re_space) {
|
||||
len = strlen(name);
|
||||
for (i = 0; i < len; i++) {
|
||||
if(name[i]==' ') name[i] = '_';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,7 +417,9 @@ void WBFS_FAT_get_dir(struct discHdr *header, char *path)
|
||||
strcat(path, wbfs_fat_dir);
|
||||
if (Settings.FatInstallToDir) {
|
||||
strcat(path, "/");
|
||||
mk_gameid_title(header, path + strlen(path), 0);
|
||||
int layout = 0;
|
||||
if (Settings.FatInstallToDir == 2) layout = 1;
|
||||
mk_gameid_title(header, path + strlen(path), 0, layout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,7 +430,7 @@ void mk_title_txt(struct discHdr *header, char *path)
|
||||
|
||||
strcpy(fname, path);
|
||||
strcat(fname, "/");
|
||||
mk_gameid_title(header, fname+strlen(fname), 1);
|
||||
mk_gameid_title(header, fname+strlen(fname), 1, 0);
|
||||
strcat(fname, ".txt");
|
||||
|
||||
f = fopen(fname, "wb");
|
||||
@ -550,6 +595,7 @@ s32 WBFS_FAT_RemoveGame(u8 *discid)
|
||||
}
|
||||
dirclose(dir_iter);
|
||||
// remove game subdir
|
||||
unlink(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -579,6 +625,9 @@ s32 WBFS_FAT_AddGame(void)
|
||||
case install_all:
|
||||
part_sel = ALL_PARTITIONS;
|
||||
break;
|
||||
case install_all_but_update:
|
||||
part_sel = REMOVE_UPDATE_PARTITION;
|
||||
break;
|
||||
}
|
||||
if (copy_1_1) {
|
||||
part_sel = ALL_PARTITIONS;
|
||||
|
Loading…
Reference in New Issue
Block a user