* 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:
e.bovendeur 2010-01-31 23:14:14 +00:00
parent 0ab26eaa6e
commit 57ecea56e9
33 changed files with 1004 additions and 635 deletions

View File

@ -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.

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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;
/*
* 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. */
if (ad->flags & ATTR_DEF_RESIDENT) {
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

View File

@ -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
View 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

View File

@ -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;

View File

@ -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

View File

@ -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 NTFS_ENABLE_LOG
#endif
/* Define to 1 if using internal fuse */

View File

@ -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 */

View File

@ -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 */

View File

@ -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,8 +423,8 @@ 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;
@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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 */

View File

@ -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"

View File

@ -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 (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;
}

View File

@ -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

View File

@ -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,19 +563,22 @@ 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;
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);
dir->vd->cwd_ni = tmp_cwd_ni;
//printf("openEn: %p\n", ni);
if (ni) {
ntfsStat(dir->vd, ni, filestat);
ntfsCloseEntry(dir->vd, ni);
}
}
}
// Move to the next entry in the directory
dir->current = dir->current->next;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -577,8 +577,9 @@ int MenuDiscList() {
w.Append(&sdcardBtn);
w.Append(&poweroffBtn);
w.Append(&gameInfo);
if (Settings.godmode && load_from_fs != PART_FS_NTFS)
if (Settings.godmode) {
w.Append(&installBtn);
}
w.Append(&homeBtn);
w.Append(&settingsBtn);
w.Append(&DownloadBtn);
@ -819,13 +820,9 @@ 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;
}
}
else if (choice ==2)
{
dvdBtn.SetState(STATE_CLICKED);

View File

@ -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;

View File

@ -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)

View File

@ -283,7 +283,6 @@ extern "C" {
settings_error002_max // always the last entry
};
enum {
wiilight_off=0,
wiilight_on,
@ -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;

View File

@ -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);
}

View File

@ -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 '_'
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(strchr("\\/:<>|\"", name[i]) || iscntrl((u32) name[i])) {
name[i] = '_';
}
if(re_space && name[i]==' ') {
name[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;