mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-22 11:19:17 +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
|
@ -11,6 +11,7 @@
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
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"
|
||||
@ -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;
|
||||
|
||||
@ -128,13 +131,14 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
|
||||
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,7 +210,7 @@ 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)
|
||||
{
|
||||
sec_t sec;
|
||||
@ -208,11 +239,11 @@ 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)
|
||||
{
|
||||
sec_t sec;
|
||||
@ -242,11 +273,11 @@ 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)
|
||||
{
|
||||
sec_t sec;
|
||||
@ -264,7 +295,7 @@ 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)
|
||||
{
|
||||
sec_t sec;
|
||||
@ -274,6 +305,7 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
|
||||
|
||||
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
|
||||
@ -271,7 +272,8 @@ 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);
|
||||
@ -287,21 +289,25 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
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
|
||||
@ -313,7 +319,8 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
}
|
||||
|
||||
// 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);
|
||||
@ -324,6 +331,7 @@ static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s
|
||||
|
||||
// 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);
|
||||
@ -367,18 +375,21 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
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
|
||||
@ -396,16 +407,15 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
} 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,
|
||||
// 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,14 +423,14 @@ 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);
|
||||
@ -431,7 +441,7 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
||||
ntfs_free(buffer);
|
||||
errno = EIO;
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free the buffer
|
||||
@ -440,7 +450,7 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
|
||||
}
|
||||
|
||||
// Mark the device as dirty (if we actually wrote anything)
|
||||
if (count)
|
||||
if (count > 0)
|
||||
NDevSetDirty(dev);
|
||||
|
||||
return count;
|
||||
@ -454,7 +464,6 @@ 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);
|
||||
@ -470,7 +479,7 @@ 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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// Get the volumes name
|
||||
return vd->vol->vol_name;
|
||||
// Allocate a buffer to store the raw volume name
|
||||
ulabel = ntfs_alloc(na->data_size * sizeof(ntfschar));
|
||||
if (!ulabel) {
|
||||
ntfsUnlock(vd);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the volume name
|
||||
if (ntfs_attr_pread(na, 0, na->data_size, ulabel) != na->data_size) {
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
errno = EIO;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert the volume name to the current local
|
||||
if (ntfsUnicodeToLocal(ulabel, na->data_size, &volumeName, 0) < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_free(ulabel);
|
||||
ntfsUnlock(vd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the volume name was read then cache it (for future fetches)
|
||||
if (volumeName)
|
||||
strcpy(vd->name, volumeName);
|
||||
|
||||
// Close the volume name attribute
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
||||
// Clean up
|
||||
ntfs_free(volumeName);
|
||||
ntfs_free(ulabel);
|
||||
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return vd->name;
|
||||
*/
|
||||
}
|
||||
|
||||
bool ntfsSetVolumeName (const char *name, const char *volumeName)
|
||||
@ -577,7 +640,6 @@ 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) {
|
||||
@ -595,22 +657,9 @@ 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,11 +694,8 @@ 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)
|
||||
@ -678,4 +721,3 @@ const devoptab_t *ntfsGetDevOpTab (void)
|
||||
{
|
||||
return &devops_ntfs;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ extern "C" {
|
||||
#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
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
@ -74,6 +75,10 @@ void ntfsCloseDir (ntfs_dir_state *dir)
|
||||
|
||||
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;
|
||||
@ -86,9 +91,12 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
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);
|
||||
@ -109,6 +117,8 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
// Close the entry
|
||||
ntfsCloseEntry(vd, ni);
|
||||
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -491,6 +501,7 @@ 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++;
|
||||
|
||||
@ -530,7 +541,6 @@ int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
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;
|
||||
@ -553,17 +563,20 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
|
||||
#include "ntfsinternal.h"
|
||||
#include "ntfsfile.h"
|
||||
#include "ntfs.h"
|
||||
|
||||
#define STATE(x) ((ntfs_file_state*)x)
|
||||
|
||||
@ -54,9 +53,10 @@ 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);
|
||||
#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);
|
||||
@ -199,6 +199,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
||||
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
|
||||
*
|
||||
@ -191,6 +192,9 @@ int ntfsInitVolume (ntfs_vd *vd)
|
||||
// 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;
|
||||
|
||||
@ -237,10 +241,10 @@ void ntfsDeinitVolume (ntfs_vd *vd)
|
||||
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);
|
||||
@ -344,6 +348,7 @@ void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target)
|
||||
{
|
||||
ntfs_inode *dir_ni = NULL, *ni = NULL;
|
||||
@ -369,7 +374,7 @@ 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;
|
||||
}
|
||||
@ -394,7 +399,12 @@ 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);
|
||||
@ -407,6 +417,10 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
|
||||
|
||||
// Symbolic link
|
||||
case S_IFLNK:
|
||||
if (!target) {
|
||||
errno = EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
utarget_len = ntfsLocalToUnicode(target, &utarget);
|
||||
if (utarget_len < 0) {
|
||||
errno = EINVAL;
|
||||
@ -602,7 +616,12 @@ 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);
|
||||
@ -685,7 +704,6 @@ int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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