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

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

@ -10,7 +10,8 @@
too many stale pages around.
Copyright (c) 2006 Michael "Chishm" Chisholm
Copyright (c) 2009 shareese, rodries
Copyright (c) 2009 shareese, rodries
Copyright (c) 2010 Dimok
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@ -39,6 +40,7 @@
//#include "common.h"
#include "cache.h"
#include "bit_ops.h"
//#include "disc.h"
#include "mem_allocate.h"
@ -95,9 +97,9 @@ NTFS_CACHE* _NTFS_cache_constructor (unsigned int numberOfPages, unsigned int se
void _NTFS_cache_destructor (NTFS_CACHE* cache) {
unsigned int i;
if(cache==NULL) return;
// Clear out cache before destroying it
_NTFS_cache_flush(cache);
@ -119,6 +121,7 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
unsigned int numberOfPages = cache->numberOfPages;
unsigned int sectorsPerPage = cache->sectorsPerPage;
bool foundFree = false;
unsigned int oldUsed = 0;
unsigned int oldAccess = UINT_MAX;
@ -127,14 +130,15 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
cacheEntries[i].last_access = accessTime();
return &(cacheEntries[i]);
}
if((cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess)) {
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
oldUsed = i;
oldAccess = cacheEntries[i].last_access;
}
}
if(cacheEntries[oldUsed].dirty==true) {
if(foundFree==false && cacheEntries[oldUsed].dirty==true) {
if(!cache->disc->writeSectors(cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
cacheEntries[oldUsed].dirty = false;
}
@ -151,6 +155,33 @@ static NTFS_CACHE_ENTRY* _NTFS_cache_getPage(NTFS_CACHE *cache,sec_t sector)
return &(cacheEntries[oldUsed]);
}
static NTFS_CACHE_ENTRY* _NTFS_cache_findPage(NTFS_CACHE *cache, sec_t sector, sec_t count) {
unsigned int i;
NTFS_CACHE_ENTRY* cacheEntries = cache->cacheEntries;
unsigned int numberOfPages = cache->numberOfPages;
NTFS_CACHE_ENTRY *entry = NULL;
sec_t lowest = UINT_MAX;
for(i=0;i<numberOfPages;i++) {
if (cacheEntries[i].sector != CACHE_FREE) {
bool intersect;
if (sector > cacheEntries[i].sector) {
intersect = sector - cacheEntries[i].sector < cacheEntries[i].count;
} else {
intersect = cacheEntries[i].sector - sector < count;
}
if ( intersect && (cacheEntries[i].sector < lowest)) {
lowest = cacheEntries[i].sector;
entry = &cacheEntries[i];
}
}
}
return entry;
}
bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
{
sec_t sec;
@ -179,8 +210,8 @@ bool _NTFS_cache_readSectors(NTFS_CACHE *cache,sec_t sector,sec_t numSectors,voi
/*
Reads some data from a cache page, determined by the sector number
*/
/*
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
bool _NTFS_cache_readPartialSector (NTFS_CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
{
sec_t sec;
NTFS_CACHE_ENTRY *entry;
@ -208,12 +239,12 @@ bool _NTFS_cache_readLittleEndianValue (NTFS_CACHE* cache, uint32_t *value, sec_
}
return true;
}
*/
/*
Writes some data to a cache page, making sure it is loaded into memory first.
*/
/*
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
bool _NTFS_cache_writePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
{
sec_t sec;
NTFS_CACHE_ENTRY *entry;
@ -242,12 +273,12 @@ bool _NTFS_cache_writeLittleEndianValue (NTFS_CACHE* cache, const uint32_t value
return _NTFS_cache_writePartialSector(cache, buf, sector, offset, size);
}
*/
/*
Writes some data to a cache page, zeroing out the page first
*/
/*
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
{
sec_t sec;
NTFS_CACHE_ENTRY *entry;
@ -264,16 +295,17 @@ bool _NTFS_cache_eraseWritePartialSector (NTFS_CACHE* cache, const void* buffer,
entry->dirty = true;
return true;
}
*/
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
{
sec_t sec;
sec_t secs_to_write;
NTFS_CACHE_ENTRY* entry;
const uint8_t *src = buffer;
while(numSectors>0)
{
/*
entry = _NTFS_cache_getPage(cache,sector);
if(entry==NULL) return false;
@ -288,6 +320,38 @@ bool _NTFS_cache_writeSectors (NTFS_CACHE* cache, sec_t sector, sec_t numSectors
numSectors -= secs_to_write;
entry->dirty = true;
*/
entry = _NTFS_cache_findPage(cache,sector,numSectors);
if(entry!=NULL) {
if ( entry->sector > sector) {
secs_to_write = entry->sector - sector;
cache->disc->writeSectors(sector,secs_to_write,src);
src += (secs_to_write*BYTES_PER_READ);
sector += secs_to_write;
numSectors -= secs_to_write;
}
sec = sector - entry->sector;
secs_to_write = entry->count - sec;
if(secs_to_write>numSectors) secs_to_write = numSectors;
memcpy(entry->cache + (sec*BYTES_PER_READ),src,(secs_to_write*BYTES_PER_READ));
src += (secs_to_write*BYTES_PER_READ);
sector += secs_to_write;
numSectors -= secs_to_write;
entry->dirty = true;
} else {
cache->disc->writeSectors(sector,numSectors,src);
numSectors=0;
}
}
return true;
}
@ -313,7 +377,9 @@ bool _NTFS_cache_flush (NTFS_CACHE* cache) {
void _NTFS_cache_invalidate (NTFS_CACHE* cache) {
unsigned int i;
if(cache==NULL) return;
if(cache==NULL)
return;
_NTFS_cache_flush(cache);
for (i = 0; i < cache->numberOfPages; i++) {
cache->cacheEntries[i].sector = CACHE_FREE;

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 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
@ -83,14 +84,14 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
errno = EBADF;
return -1;
}
// Get the device interface
const DISC_INTERFACE* interface = fd->interface;
if (!interface) {
errno = ENODEV;
return -1;
}
// Start the device interface and ensure that it is inserted
if (!interface->startup()) {
ntfs_log_perror("device failed to start\n");
@ -102,7 +103,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
errno = EIO;
return -1;
}
// Check that the device isn't already open (used by another volume?)
if (NDevOpen(dev)) {
ntfs_log_perror("device is busy (already open)\n");
@ -122,7 +123,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
errno = EIO;
return -1;
}
// Parse the boot sector
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
@ -130,7 +131,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
fd->pos = 0;
fd->len = (fd->sectorCount * fd->sectorSize);
fd->ino = le64_to_cpu(boot.volume_serial_number);
// If the device sector size is not 512 bytes then we cannot continue,
// gekko disc I/O works on the assumption that sectors are always 512 bytes long.
// TODO: Implement support for non-512 byte sector sizes through some fancy maths!?
@ -144,14 +145,14 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
if (flags & O_RDONLY) {
NDevSetReadOnly(dev);
}
// Create the cache
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount);
// Mark the device as open
NDevSetBlock(dev);
NDevSetOpen(dev);
return 0;
}
@ -161,7 +162,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
{
ntfs_log_trace("dev %p\n", dev);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
@ -175,20 +176,20 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
errno = EIO;
return -1;
}
// Mark the device as closed
NDevClearOpen(dev);
NDevClearBlock(dev);
// Flush the device (if dirty and not read-only)
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
ntfs_log_debug("device is dirty, will now sync\n");
// ...?
// Mark the device as clean
NDevClearDirty(dev);
}
// Flush and destroy the cache (if required)
@ -196,7 +197,7 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
_NTFS_cache_flush(fd->cache);
_NTFS_cache_destructor(fd->cache);
}
// Shutdown the device interface
/*const DISC_INTERFACE* interface = fd->interface;
if (interface) {
@ -206,7 +207,7 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
// Free the device driver private data
ntfs_free(dev->d_private);
dev->d_private = NULL;
return 0;
}
@ -216,14 +217,14 @@ static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int whence)
{
ntfs_log_trace("dev %p, offset %Li, whence %i\n", dev, offset, whence);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
}
// Set the current position on the device (in bytes)
switch(whence) {
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
@ -259,7 +260,7 @@ static s64 ntfs_device_gekko_io_pread(struct ntfs_device *dev, void *buf, s64 co
}
/**
*
*
*/
static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
{
@ -271,119 +272,129 @@ static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf,
*/
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
{
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
//ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
ntfs_log_trace("dev %p, offset %d, count %d\n", dev, (u32)offset, (u32)count);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
}
// Get the device interface
const DISC_INTERFACE* interface = fd->interface;
if (!interface) {
errno = ENODEV;
return -1;
}
sec_t sec_start = fd->startSector;
if(!count)
return 0;
sec_t sec_start = (sec_t) fd->startSector;
sec_t sec_count = 1;
u16 buffer_offset = 0;
u8 *buffer;
u8 *buffer = NULL;
// Determine the range of sectors required for this read
if (offset > 0) {
sec_start += floor(offset / fd->sectorSize);
buffer_offset = offset % fd->sectorSize;
sec_start += (sec_t) floor(offset / fd->sectorSize);
buffer_offset = (sec_t) offset % fd->sectorSize;
}
if (count > fd->sectorSize) {
sec_count = ceil(count / fd->sectorSize);
sec_count = (sec_t) ceil(count / (float)fd->sectorSize);
}
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
if((offset % fd->sectorSize == 0) && (count % fd->sectorSize == 0)) {
// Read from the device
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
errno = EIO;
return -1;
}
// Else read into a buffer and copy over only what was requested
} else {
} else
{
// Allocate a buffer to hold the read data
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
if (!buffer) {
errno = ENOMEM;
return -1;
}
// Read from the device
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
ntfs_free(buffer);
errno = EIO;
return -1;
}
// Copy what was requested to the destination buffer
memcpy(buf, buffer + buffer_offset, count);
ntfs_free(buffer);
}
return count;
}
/**
*
*
*/
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
{
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
}
// Get the device interface
const DISC_INTERFACE* interface = fd->interface;
if (!interface) {
errno = ENODEV;
return -1;
}
// Check that the device can be written to
if (NDevReadOnly(dev)) {
errno = EROFS;
return -1;
}
sec_t sec_start = fd->startSector;
if(!count)
return 0;
sec_t sec_start = (sec_t) fd->startSector;
sec_t sec_count = 1;
u16 buffer_offset = 0;
u8 *buffer;
u32 buffer_offset = 0;
u8 *buffer = NULL;
// Determine the range of sectors required for this write
if (offset > 0) {
sec_start += floor(offset / fd->sectorSize);
buffer_offset = offset % fd->sectorSize;
sec_start += (sec_t) floor(offset / fd->sectorSize);
buffer_offset = (u32) ceil(offset % fd->sectorSize);
}
if (count > fd->sectorSize) {
sec_count = ceil(count / fd->sectorSize);
sec_count = (sec_t) ceil((float) count / (float)fd->sectorSize);
}
// If this write happens to be on the sector boundaries then do the write straight to disc
if((offset % fd->sectorSize == 0) && (count % fd->sectorSize == 0)) {
// Write to the device
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
@ -391,21 +402,20 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
errno = EIO;
return -1;
}
// Else write from a buffer aligned to the sector boundaries
} else {
// Allocate a buffer to hold the write data
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
buffer = (u8*)ntfs_alloc((sec_count+1) * fd->sectorSize);
if (!buffer) {
errno = ENOMEM;
return -1;
}
// Read the first and last sectors of the buffer from disc (if required)
// NOTE: This is done because the data does not line up with the sector boundaries,
// NOTE: This is done because the data does not line up with the sector boundaries,
// we just read in the buffer edges where the data overlaps with the rest of the disc
if((offset % fd->sectorSize == 0)) {
if(offset % fd->sectorSize != 0) {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
ntfs_log_perror("read failure @ sector %d\n", sec_start);
ntfs_free(buffer);
@ -413,36 +423,36 @@ static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset,
return -1;
}
}
if((count % fd->sectorSize == 0)) {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count, 1, buffer + ((sec_count - 1) * fd->sectorSize))) {
if(count % fd->sectorSize != 0) {
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count-1, 1, buffer + ((sec_count - 1) * fd->sectorSize))) {
ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count);
ntfs_free(buffer);
errno = EIO;
return -1;
}
}
}
// Copy the data into the write buffer
memcpy(buffer + buffer_offset, buf, count);
// Write to the device
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
ntfs_free(buffer);
errno = EIO;
return false;
return -1;
}
// Free the buffer
ntfs_free(buffer);
}
// Mark the device as dirty (if we actually wrote anything)
if (count)
if (count > 0)
NDevSetDirty(dev);
return count;
}
@ -454,13 +464,12 @@ static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sect
errno = EBADF;
return false;
}
// Read the sectors from disc (or cache, if enabled)
if (fd->cache)
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
else
return fd->interface->readSectors(sector, numSectors, buffer);
return fd->interface->readSectors(sector, numSectors, buffer);
return false;
}
@ -470,15 +479,15 @@ static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sec
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
return false;
}
// Write the sectors to disc (or cache, if enabled)
if (fd->cache)
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
else
return fd->interface->writeSectors(sector, numSectors, buffer);
return false;
}
@ -489,7 +498,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
{
gekko_fd *fd = DEV_FD(dev);
ntfs_log_trace("dev %p\n", dev);
// Check that the device can be written to
if (NDevReadOnly(dev)) {
errno = EROFS;
@ -498,7 +507,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
// Mark the device as clean
NDevClearDirty(dev);
// Flush any sectors in the disc cache (if required)
if (fd->cache) {
if (!_NTFS_cache_flush(fd->cache)) {
@ -506,7 +515,7 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
return -1;
}
}
return 0;
}
@ -516,18 +525,18 @@ static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
{
ntfs_log_trace("dev %p, buf %p\n", dev, buf);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
}
// Short circuit cases were we don't actually have to do anything
if (!buf)
return 0;
// Build the device mode
mode_t mode = (S_IFBLK) |
(S_IRUSR | S_IRGRP | S_IROTH) |
@ -543,7 +552,7 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
buf->st_rdev = fd->interface->ioType;
buf->st_blksize = fd->sectorSize;
buf->st_blocks = fd->sectorCount;
return 0;
}
@ -553,17 +562,17 @@ static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void *argp)
{
ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);
// Get the device driver descriptor
gekko_fd *fd = DEV_FD(dev);
if (!fd) {
errno = EBADF;
return -1;
}
// Figure out which i/o control was requested
switch (request) {
// Get block device size (sectors)
#if defined(BLKGETSIZE)
case BLKGETSIZE: {
@ -571,7 +580,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
return 0;
}
#endif
// Get block device size (bytes)
#if defined(BLKGETSIZE64)
case BLKGETSIZE64: {
@ -579,7 +588,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
return 0;
}
#endif
// Get hard drive geometry
#if defined(HDIO_GETGEO)
case HDIO_GETGEO: {
@ -591,7 +600,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
return -1;
}
#endif
// Get block device sector size (bytes)
#if defined(BLKSSZGET)
case BLKSSZGET: {
@ -599,7 +608,7 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
return 0;
}
#endif
// Set block device block size (bytes)
#if defined(BLKBSZSET)
case BLKBSZSET: {
@ -613,16 +622,16 @@ static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void
return 0;
}
#endif
// Unimplemented ioctrl
default: {
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
errno = EOPNOTSUPP;
return -1;
}
}
return 0;
}

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 (!(interface->features & FEATURE_MEDIUM_CANWRITE))
vd->flags |= MS_RDONLY;
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
vd->flags |= MS_EXCLUSIVE;
if (flags & NTFS_READ_ONLY)
vd->flags |= MS_RDONLY;
else
{
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
vd->flags |= MS_RDONLY;
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
vd->flags |= MS_EXCLUSIVE;
}
if (flags & NTFS_RECOVER)
vd->flags |= MS_RECOVER;
if (flags & NTFS_IGNORE_HIBERFILE)
@ -553,6 +557,9 @@ void ntfsUnmount (const char *name, bool force)
const char *ntfsGetVolumeName (const char *name)
{
ntfs_vd *vd = NULL;
//ntfs_attr *na = NULL;
//ntfschar *ulabel = NULL;
//char *volumeName = NULL;
// Sanity check
if (!name) {
@ -564,11 +571,67 @@ const char *ntfsGetVolumeName (const char *name)
vd = ntfsGetVolume(name);
if (!vd) {
errno = ENODEV;
return NULL;
}
return vd->vol->vol_name;
/*
// If the volume name has already been cached then just use that
if (vd->name[0])
return vd->name;
// Lock
ntfsLock(vd);
// Check if the volume name attribute exists
na = ntfs_attr_open(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0);
if (!na) {
ntfsUnlock(vd);
errno = ENOENT;
return false;
}
// Allocate a buffer to store the raw volume name
ulabel = ntfs_alloc(na->data_size * sizeof(ntfschar));
if (!ulabel) {
ntfsUnlock(vd);
errno = ENOMEM;
return false;
}
// Get the volumes name
return vd->vol->vol_name;
// Read the volume name
if (ntfs_attr_pread(na, 0, na->data_size, ulabel) != na->data_size) {
ntfs_free(ulabel);
ntfsUnlock(vd);
errno = EIO;
return false;
}
// Convert the volume name to the current local
if (ntfsUnicodeToLocal(ulabel, na->data_size, &volumeName, 0) < 0) {
errno = EINVAL;
ntfs_free(ulabel);
ntfsUnlock(vd);
return false;
}
// If the volume name was read then cache it (for future fetches)
if (volumeName)
strcpy(vd->name, volumeName);
// Close the volume name attribute
if (na)
ntfs_attr_close(na);
// Clean up
ntfs_free(volumeName);
ntfs_free(ulabel);
// Unlock
ntfsUnlock(vd);
return vd->name;
*/
}
bool ntfsSetVolumeName (const char *name, const char *volumeName)
@ -577,8 +640,7 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
ntfs_attr *na = NULL;
ntfschar *ulabel = NULL;
int ulabel_len;
char *label = NULL;
// Sanity check
if (!name) {
errno = EINVAL;
@ -594,23 +656,10 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// Lock
ntfsLock(vd);
// Allocate a buffer to hold the new volume name
label = ntfs_alloc(strlen(volumeName) + 1);
if (!label) {
ntfsUnlock(vd);
errno = EINVAL;
return false;
}
// Copy the new volume name
memset(label, 0, strlen(volumeName) + 1);
strcpy(label, volumeName);
// Convert the new volume name to unicode
ulabel_len = ntfsLocalToUnicode(label, &ulabel) * sizeof(ntfschar);
ulabel_len = ntfsLocalToUnicode(volumeName, &ulabel) * sizeof(ntfschar);
if (ulabel_len < 0) {
ntfs_free(label);
ntfsUnlock(vd);
errno = EINVAL;
return false;
@ -622,7 +671,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// It does, resize it to match the length of the new volume name
if (ntfs_attr_truncate(na, ulabel_len)) {
ntfs_free(label);
ntfs_free(ulabel);
ntfsUnlock(vd);
return false;
@ -630,7 +678,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// Write the new volume name
if (ntfs_attr_pwrite(na, 0, ulabel_len, ulabel) != ulabel_len) {
ntfs_free(label);
ntfs_free(ulabel);
ntfsUnlock(vd);
return false;
@ -640,7 +687,6 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
// It doesn't, create it now
if (ntfs_attr_add(vd->vol->vol_ni, AT_VOLUME_NAME, NULL, 0, (u8*)ulabel, ulabel_len)) {
ntfs_free(label);
ntfs_free(ulabel);
ntfsUnlock(vd);
return false;
@ -648,12 +694,9 @@ bool ntfsSetVolumeName (const char *name, const char *volumeName)
}
// Update the volumes name (as it has now been changed)
if(vd->vol->vol_name) {
ntfs_free(vd->vol->vol_name);
vd->vol->vol_name = label;
}
// Reset the volumes name cache (as it has now been changed)
vd->name[0] = '\0';
// Close the volume name attribute
if (na)
ntfs_attr_close(na);
@ -678,4 +721,3 @@ const devoptab_t *ntfsGetDevOpTab (void)
{
return &devops_ntfs;
}

View File

@ -1,161 +1,162 @@
/**
* ntfs.h - Simple functionality for startup, mounting and unmounting of NTFS-based devices.
*
* Copyright (c) 2009 Rhys "Shareese" Koedijk
* Copyright (c) 2006 Michael "Chishm" Chisholm
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LIBNTFS_H
#define _LIBNTFS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <gctypes.h>
#include <gccore.h>
#include <ogc/disc_io.h>
/* NTFS errno values */
#define ENOPART 3000 /* No partition was found */
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
#define EDIRTY 3002 /* Volume is dirty and NTFS_RECOVER was not specified during mount */
#define EHIBERNATED 3003 /* Volume is hibernated and NTFS_IGNORE_HIBERFILE was not specified during mount */
/* NTFS cache options */
#define CACHE_DEFAULT_PAGE_COUNT 8 /* The default number of pages in the cache */
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
/* NTFS mount flags */
#define NTFS_DEFAULT 0x00000000 /* Standard mount, expects a clean, non-hibernated volume */
#define NTFS_SHOW_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
#define NTFS_UPDATE_ACCESS_TIMES 0x00000004 /* Update file and directory access times */
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
#define NTFS_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
/**
* ntfs_md - NTFS mount descriptor
*/
typedef struct _ntfs_md {
char name[32]; /* Mount name (can be accessed as "name:/") */
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
sec_t startSector; /* Local block address to first sector of partition */
} ntfs_md;
/**
* Find all NTFS partitions on a block device.
*
* @param INTERFACE The block device to search
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
*
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing PARTITIONS when finished with it
*/
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
/**
* Mount all NTFS partitions on all inserted block devices.
*
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
* @param FLAGS Additional mounting flags. (see above)
*
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing MOUNTS when finished with it
* @note All device caches are setup using default values (see above)
*/
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
/**
* Mount all NTFS partitions on a block devices.
*
* @param INTERFACE The block device to mount.
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
* @param FLAGS Additional mounting flags. (see above)
*
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing MOUNTS when finished with it
* @note The device cache is setup using default values (see above)
*/
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
/**
* Mount a NTFS partition from a specific sector on a block device.
*
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
* @param INTERFACE The block device to mount
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
* @param CACHEPAGECOUNT The total number of pages in the device cache
* @param CACHEPAGESIZE The number of sectors per cache page
* @param FLAGS Additional mounting flags (see above)
*
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
* @note ntfsFindPartitions should be used first to locate the partitions start sector
*/
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
/**
* Unmount a NTFS partition.
*
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
*/
extern void ntfsUnmount (const char *name, bool force);
/**
* Get the volume name of a mounted NTFS partition.
*
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
*
* @return The volumes name if successful or NULL if an error occurred (see errno)
*/
extern const char *ntfsGetVolumeName (const char *name);
/**
* Set the volume name of a mounted NTFS partition.
*
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
* @param VOLUMENAME The new volume name
*
* @return True if mount was successful, false if an error occurred (see errno)
* @note The mount must be write-enabled else this will fail
*/
extern bool ntfsSetVolumeName (const char *name, const char *volumeName);
#ifdef __cplusplus
}
#endif
#endif /* _LIBNTFS_H */
/*
typedef struct _FileInfo FileInfo;
struct _FileInfo
{
u64 offset[64];
s64 sector[64];
u64 count[64];
u32 num;
u64 filesize;
};
*/
typedef int (*_ntfs_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count);
int _NTFS_get_fragments (const char *path, _ntfs_frag_append_t append_fragment, void *callback_data);
/**
* ntfs.h - Simple functionality for startup, mounting and unmounting of NTFS-based devices.
*
* Copyright (c) 2009 Rhys "Shareese" Koedijk
* Copyright (c) 2006 Michael "Chishm" Chisholm
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LIBNTFS_H
#define _LIBNTFS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <gctypes.h>
#include <gccore.h>
#include <ogc/disc_io.h>
/* NTFS errno values */
#define ENOPART 3000 /* No partition was found */
#define EINVALPART 3001 /* Specified partition is invalid or not supported */
#define EDIRTY 3002 /* Volume is dirty and NTFS_RECOVER was not specified during mount */
#define EHIBERNATED 3003 /* Volume is hibernated and NTFS_IGNORE_HIBERFILE was not specified during mount */
/* NTFS cache options */
#define CACHE_DEFAULT_PAGE_COUNT 8 /* The default number of pages in the cache */
#define CACHE_DEFAULT_PAGE_SIZE 128 /* The default number of sectors per cache page */
/* NTFS mount flags */
#define NTFS_DEFAULT 0x00000000 /* Standard mount, expects a clean, non-hibernated volume */
#define NTFS_SHOW_HIDDEN_FILES 0x00000001 /* Display hidden files when enumerating directories */
#define NTFS_SHOW_SYSTEM_FILES 0x00000002 /* Display system files when enumerating directories */
#define NTFS_UPDATE_ACCESS_TIMES 0x00000004 /* Update file and directory access times */
#define NTFS_RECOVER 0x00000008 /* Reset $LogFile if dirty (i.e. from unclean disconnect) */
#define NTFS_IGNORE_HIBERFILE 0x00000010 /* Mount even if volume is hibernated */
#define NTFS_READ_ONLY 0x00000020 /* Mount in read only mode */
#define NTFS_SU NTFS_SHOW_HIDDEN_FILES & NTFS_SHOW_SYSTEM_FILES
#define NTFS_FORCE NTFS_RECOVER & NTFS_IGNORE_HIBERFILE
/**
* ntfs_md - NTFS mount descriptor
*/
typedef struct _ntfs_md {
char name[32]; /* Mount name (can be accessed as "name:/") */
const DISC_INTERFACE *interface; /* Block device containing the mounted partition */
sec_t startSector; /* Local block address to first sector of partition */
} ntfs_md;
/**
* Find all NTFS partitions on a block device.
*
* @param INTERFACE The block device to search
* @param PARTITIONS (out) A pointer to receive the array of partition start sectors
*
* @return The number of entries in PARTITIONS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing PARTITIONS when finished with it
*/
extern int ntfsFindPartitions (const DISC_INTERFACE *interface, sec_t **partitions);
/**
* Mount all NTFS partitions on all inserted block devices.
*
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
* @param FLAGS Additional mounting flags. (see above)
*
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing MOUNTS when finished with it
* @note All device caches are setup using default values (see above)
*/
extern int ntfsMountAll (ntfs_md **mounts, u32 flags);
/**
* Mount all NTFS partitions on a block devices.
*
* @param INTERFACE The block device to mount.
* @param MOUNTS (out) A pointer to receive the array of mount descriptors
* @param FLAGS Additional mounting flags. (see above)
*
* @return The number of entries in MOUNTS or -1 if an error occurred (see errno)
* @note The caller is responsible for freeing MOUNTS when finished with it
* @note The device cache is setup using default values (see above)
*/
extern int ntfsMountDevice (const DISC_INTERFACE* interface, ntfs_md **mounts, u32 flags);
/**
* Mount a NTFS partition from a specific sector on a block device.
*
* @param NAME The name to mount the device under (can then be accessed as "NAME:/")
* @param INTERFACE The block device to mount
* @param STARTSECTOR The sector the partition begins at (see @ntfsFindPartitions)
* @param CACHEPAGECOUNT The total number of pages in the device cache
* @param CACHEPAGESIZE The number of sectors per cache page
* @param FLAGS Additional mounting flags (see above)
*
* @return True if mount was successful, false if no partition was found or an error occurred (see errno)
* @note ntfsFindPartitions should be used first to locate the partitions start sector
*/
extern bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSector, u32 cachePageCount, u32 cachePageSize, u32 flags);
/**
* Unmount a NTFS partition.
*
* @param NAME The name of mount used in ntfsMountSimple() and ntfsMount()
* @param FORCE If true unmount even if the device is busy (may lead to data lose)
*/
extern void ntfsUnmount (const char *name, bool force);
/**
* Get the volume name of a mounted NTFS partition.
*
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
*
* @return The volumes name if successful or NULL if an error occurred (see errno)
*/
extern const char *ntfsGetVolumeName (const char *name);
/**
* Set the volume name of a mounted NTFS partition.
*
* @param NAME The name of mount (see @ntfsMountAll, @ntfsMountDevice, and @ntfsMount)
* @param VOLUMENAME The new volume name
*
* @return True if mount was successful, false if an error occurred (see errno)
* @note The mount must be write-enabled else this will fail
*/
extern bool ntfsSetVolumeName (const char *name, const char *volumeName);
#ifdef __cplusplus
}
#endif
#endif /* _LIBNTFS_H */
/*
typedef struct _FileInfo FileInfo;
struct _FileInfo
{
u64 offset[64];
s64 sector[64];
u64 count[64];
u32 num;
u64 filesize;
};
*/
typedef int (*_ntfs_frag_append_t)(void *ff, u32 offset, u32 sector, u32 count);
int _NTFS_get_fragments (const char *path, _ntfs_frag_append_t append_fragment, void *callback_data);

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
*
@ -51,7 +52,7 @@ void ntfsCloseDir (ntfs_dir_state *dir)
// Sanity check
if (!dir || !dir->vd)
return;
// Free the directory entries (if any)
while (dir->first) {
ntfs_dir_entry *next = dir->first->next;
@ -59,40 +60,47 @@ void ntfsCloseDir (ntfs_dir_state *dir)
ntfs_free(dir->first);
dir->first = next;
}
// Close the directory (if open)
if (dir->ni)
ntfsCloseEntry(dir->vd, dir->ni);
// Reset the directory state
dir->ni = NULL;
dir->first = NULL;
dir->current = NULL;
return;
}
int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
{
// Short circuit cases were we don't actually have to do anything
if (!st || !path)
return 0;
ntfs_log_trace("path %s, st %p\n", path, st);
ntfs_vd *vd = NULL;
ntfs_inode *ni = NULL;
// Get the volume descriptor for this path
vd = ntfsGetVolume(path);
if (!vd) {
r->_errno = ENODEV;
return -1;
}
// Short circuit cases were we don't actually have to do anything
if (!st)
if(strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
{
memset(st, 0, sizeof(struct stat));
st->st_mode = S_IFDIR;
return 0;
}
// Lock
ntfsLock(vd);
// Find the entry
ni = ntfsOpenEntry(vd, path);
if (!ni) {
@ -109,26 +117,28 @@ int ntfs_stat_r (struct _reent *r, const char *path, struct stat *st)
// Close the entry
ntfsCloseEntry(vd, ni);
ntfsUnlock(vd);
return 0;
}
int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
{
ntfs_log_trace("existing %s, newLink %s\n", existing, newLink);
ntfs_vd *vd = NULL;
ntfs_inode *ni = NULL;
// Get the volume descriptor for this path
vd = ntfsGetVolume(existing);
if (!vd) {
r->_errno = ENODEV;
return -1;
}
// Lock
ntfsLock(vd);
// Create a symbolic link between the two paths
ni = ntfsCreate(vd, existing, S_IFLNK, newLink);
if (!ni) {
@ -136,10 +146,10 @@ int ntfs_link_r (struct _reent *r, const char *existing, const char *newLink)
r->_errno = errno;
return -1;
}
// Close the symbolic link
ntfsCloseEntry(vd, ni);
// Unlock
ntfsUnlock(vd);
@ -161,10 +171,10 @@ int ntfs_unlink_r (struct _reent *r, const char *name)
int ntfs_chdir_r (struct _reent *r, const char *name)
{
ntfs_log_trace("name %s\n", name);
ntfs_vd *vd = NULL;
ntfs_inode *ni = NULL;
// Get the volume descriptor for this path
vd = ntfsGetVolume(name);
if (!vd) {
@ -174,7 +184,7 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
// Lock
ntfsLock(vd);
// Find the directory
ni = ntfsOpenEntry(vd, name);
if (!ni) {
@ -182,7 +192,7 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
r->_errno = ENOENT;
return -1;
}
// Ensure that this directory is indeed a directory
if (!(ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
ntfsCloseEntry(vd, ni);
@ -190,27 +200,27 @@ int ntfs_chdir_r (struct _reent *r, const char *name)
r->_errno = ENOTDIR;
return -1;
}
// Close the old current directory (if any)
if (vd->cwd_ni)
ntfsCloseEntry(vd, vd->cwd_ni);
// Set the new current directory
vd->cwd_ni = ni;
// Unlock
ntfsUnlock(vd);
return 0;
}
int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
{
ntfs_log_trace("oldName %s, newName %s\n", oldName, newName);
ntfs_vd *vd = NULL;
ntfs_inode *ni = NULL;
// Get the volume descriptor for this path
vd = ntfsGetVolume(oldName);
if (!vd) {
@ -220,14 +230,14 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
// Lock
ntfsLock(vd);
// You cannot rename between devices
if(vd != ntfsGetVolume(newName)) {
ntfsUnlock(vd);
r->_errno = EXDEV;
return -1;
}
// Check that there is no existing entry with the new name
ni = ntfsOpenEntry(vd, newName);
if (ni) {
@ -242,7 +252,7 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
ntfsUnlock(vd);
return -1;
}
// Unlink the old entry
if (ntfsUnlink(vd, oldName)) {
if (ntfsUnlink(vd, newName)) {
@ -252,17 +262,17 @@ int ntfs_rename_r (struct _reent *r, const char *oldName, const char *newName)
ntfsUnlock(vd);
return -1;
}
// Unlock
ntfsUnlock(vd);
return 0;
}
int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
{
ntfs_log_trace("path %s, mode %i\n", path, mode);
ntfs_vd *vd = NULL;
ntfs_inode *ni = NULL;
@ -272,10 +282,10 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
r->_errno = ENODEV;
return -1;
}
// Lock
ntfsLock(vd);
// Create the directory
ni = ntfsCreate(vd, path, S_IFDIR, NULL);
if (!ni) {
@ -283,80 +293,80 @@ int ntfs_mkdir_r (struct _reent *r, const char *path, int mode)
r->_errno = errno;
return -1;
}
// Close the directory
ntfsCloseEntry(vd, ni);
// Unlock
ntfsUnlock(vd);
return 0;
}
int ntfs_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
{
ntfs_log_trace("path %s, buf %p\n", path, buf);
ntfs_vd *vd = NULL;
s64 size;
int delta_bits;
// Get the volume descriptor for this path
vd = ntfsGetVolume(path);
if (!vd) {
r->_errno = ENODEV;
return -1;
}
// Short circuit cases were we don't actually have to do anything
if (!buf)
return 0;
// Lock
ntfsLock(vd);
// Zero out the stat buffer
memset(buf, 0, sizeof(struct statvfs));
// File system block size
buf->f_bsize = vd->vol->cluster_size;
// Fundamental file system block size
buf->f_frsize = vd->vol->cluster_size;
// Total number of blocks on file system in units of f_frsize
buf->f_blocks = vd->vol->nr_clusters;
// Free blocks available for all and for non-privileged processes
size = MAX(vd->vol->free_clusters, 0);
buf->f_bfree = buf->f_bavail = size;
// Free inodes on the free space
delta_bits = vd->vol->cluster_size_bits - vd->vol->mft_record_size_bits;
if (delta_bits >= 0)
size <<= delta_bits;
else
size >>= -delta_bits;
// Number of inodes at this point in time
buf->f_files = (vd->vol->mftbmp_na->allocated_size << 3) + size;
// Free inodes available for all and for non-privileged processes
size += vd->vol->free_mft_records;
buf->f_ffree = buf->f_favail = MAX(size, 0);
// File system id
buf->f_fsid = vd->id;
// Bit mask of f_flag values.
buf->f_flag = (NVolReadOnly(vd->vol) ? ST_RDONLY : 0);
// Maximum length of filenames
buf->f_namemax = NTFS_MAX_NAME_LEN;
// Unlock
ntfsUnlock(vd);
return 0;
}
@ -369,7 +379,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
ntfs_dir_state *dir = STATE(dirState);
ntfs_dir_entry *entry = NULL;
char *entry_name = NULL;
// Sanity check
if (!dir || !dir->vd) {
errno = EINVAL;
@ -383,7 +393,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
// Preliminary check that this entry can be enumerated (as described by the volume descriptor)
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user || dir->vd->showSystemFiles) {
// Convert the entry name to our current local
if (ntfsUnicodeToLocal(name, name_len, &entry_name, 0) < 0) {
ntfs_free(entry);
@ -392,7 +402,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
// If this is not the parent or self directory reference
if ((strcmp(entry_name, ".") != 0) && (strcmp(entry_name, "..") != 0)) {
// Open the entry
ntfs_inode *ni = ntfs_pathname_to_inode(dir->vd->vol, dir->ni, entry_name);
if (!ni) {
@ -406,21 +416,21 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
ntfs_inode_close(ni);
return 0;
}
// Close the entry
ntfs_inode_close(ni);
}
// Allocate a new directory entry
entry = ntfs_alloc(sizeof(ntfs_dir_entry));
if (!entry)
return -1;
// Setup the entry
entry->name = entry_name;
entry->next = NULL;
// Link the entry to the directory
if (!dir->first) {
dir->first = entry;
@ -429,7 +439,7 @@ int ntfs_readdir_filler (DIR_ITER *dirState, const ntfschar *name, const int nam
while (last->next) last = last->next;
last->next = entry;
}
}
return 0;
@ -441,7 +451,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
ntfs_dir_state* dir = STATE(dirState);
s64 position = 0;
// Get the volume descriptor for this path
dir->vd = ntfsGetVolume(path);
if (!dir->vd) {
@ -451,7 +461,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
// Lock
ntfsLock(dir->vd);
// Find the directory
dir->ni = ntfsOpenEntry(dir->vd, path);
if (!dir->ni) {
@ -459,7 +469,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
r->_errno = ENOENT;
return NULL;
}
// Ensure that this directory is indeed a directory
if (!(dir->ni->mrec->flags && MFT_RECORD_IS_DIRECTORY)) {
ntfsCloseEntry(dir->vd, dir->ni);
@ -467,7 +477,7 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
r->_errno = ENOTDIR;
return NULL;
}
// Read the directory
dir->first = dir->current = NULL;
if (ntfs_readdir(dir->ni, &position, dirState, (ntfs_filldir_t)ntfs_readdir_filler)) {
@ -479,10 +489,10 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
// Move to the first entry in the directory
dir->current = dir->first;
// Update directory times
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
// Insert the directory into the double-linked FILO list of open directories
if (dir->vd->firstOpenDir) {
dir->nextOpenDir = dir->vd->firstOpenDir;
@ -491,59 +501,59 @@ DIR_ITER *ntfs_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path
dir->nextOpenDir = NULL;
}
dir->prevOpenDir = NULL;
dir->vd->cwd_ni = dir->ni;
dir->vd->firstOpenDir = dir;
dir->vd->openDirCount++;
// Unlock
ntfsUnlock(dir->vd);
return dirState;
}
int ntfs_dirreset_r (struct _reent *r, DIR_ITER *dirState)
{
ntfs_log_trace("dirState %p\n", dirState);
ntfs_dir_state* dir = STATE(dirState);
// Sanity check
if (!dir || !dir->vd || !dir->ni) {
r->_errno = EBADF;
return -1;
}
// Lock
ntfsLock(dir->vd);
// Move to the first entry in the directory
dir->current = dir->first;
// Update directory times
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
// Unlock
ntfsUnlock(dir->vd);
return 0;
}
int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
{
ntfs_log_trace("dirState %p, filename %p, filestat %p\n", dirState, filename, filestat);
//printf("dirnext %p %p %p\n", dirState, filename, filestat);
ntfs_dir_state* dir = STATE(dirState);
ntfs_inode *ni = NULL;
// Sanity check
if (!dir || !dir->vd || !dir->ni) {
r->_errno = EBADF;
return -1;
}
// Lock
ntfsLock(dir->vd);
// Check that there is a entry waiting to be fetched
if (!dir->current) {
ntfsUnlock(dir->vd);
@ -553,36 +563,39 @@ int ntfs_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
// Fetch the current entry
strcpy(filename, dir->current->name);
if(filestat != NULL) {
// ntfsOpenEntry requires full path, or path relative to cwd
// so we set cwd temporarily
ntfs_inode *tmp_cwd_ni = dir->vd->cwd_ni;
dir->vd->cwd_ni = dir->ni;
ni = ntfsOpenEntry(dir->vd, dir->current->name);
dir->vd->cwd_ni = tmp_cwd_ni;
//printf("openEn: %p\n", ni);
if (ni) {
ntfsStat(dir->vd, ni, filestat);
ntfsCloseEntry(dir->vd, ni);
if(filestat != NULL)
{
if(strcmp(dir->current->name, ".") == 0 || strcmp(dir->current->name, "..") == 0)
{
memset(filestat, 0, sizeof(struct stat));
filestat->st_mode = S_IFDIR;
}
else
{
ni = ntfsOpenEntry(dir->vd, dir->current->name);
if (ni) {
ntfsStat(dir->vd, ni, filestat);
ntfsCloseEntry(dir->vd, ni);
}
}
}
// Move to the next entry in the directory
dir->current = dir->current->next;
// Update directory times
ntfsUpdateTimes(dir->vd, dir->ni, NTFS_UPDATE_ATIME);
// Unlock
ntfsUnlock(dir->vd);
return 0;
}
int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
{
ntfs_log_trace("dirState %p\n", dirState);
ntfs_dir_state* dir = STATE(dirState);
// Sanity check
@ -590,13 +603,13 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
r->_errno = EBADF;
return -1;
}
// Lock
ntfsLock(dir->vd);
// Close the directory
ntfsCloseDir(dir);
// Remove the directory from the double-linked FILO list of open directories
dir->vd->openDirCount--;
if (dir->nextOpenDir)
@ -605,9 +618,9 @@ int ntfs_dirclose_r (struct _reent *r, DIR_ITER *dirState)
dir->prevOpenDir->nextOpenDir = dir->nextOpenDir;
else
dir->vd->firstOpenDir = dir->nextOpenDir;
// Unlock
ntfsUnlock(dir->vd);
return 0;
}

View File

@ -41,7 +41,6 @@
#include "ntfsinternal.h"
#include "ntfsfile.h"
#include "ntfs.h"
#define STATE(x) ((ntfs_file_state*)x)
@ -53,10 +52,11 @@ void ntfsCloseFile (ntfs_file_state *file)
// Special case fix ups for compressed and/or encrypted files
if (file->compressed)
ntfs_attr_pclose(file->data_na);
ntfs_attr_pclose(file->data_na);
#ifdef HAVE_SETXATTR
if (file->encrypted)
ntfs_efs_fixup_attribute(NULL, file->data_na);
#endif
// Close the file data attribute (if open)
if (file->data_na)
ntfs_attr_close(file->data_na);
@ -198,6 +198,8 @@ int ntfs_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Set the files current position and length
file->pos = 0;
file->len = file->data_na->data_size;
ntfs_log_trace("file->len %d\n", file->len);
// Update file times
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);
@ -354,8 +356,11 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
if (file->pos + len > file->len) {
r->_errno = EOVERFLOW;
len = file->len - file->pos;
ntfs_log_trace("EOVERFLOW");
}
ntfs_log_trace("file->pos:%d, len:%d, file->len:%d \n", (u32)file->pos, (u32)len, (u32)file->len);
// Read from the files data attribute
while (len) {
ssize_t ret = ntfs_attr_pread(file->data_na, file->pos, len, ptr);
@ -369,7 +374,7 @@ ssize_t ntfs_read_r (struct _reent *r, int fd, char *ptr, size_t len)
file->pos += ret;
read += ret;
}
//ntfs_log_trace("file->pos: %d \n", (u32)file->pos);
// Update file times (if we actually read something)
if (read)
ntfsUpdateTimes(file->vd, file->ni, NTFS_UPDATE_ATIME);

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
*
@ -67,24 +68,24 @@ int ntfsAddDevice (const char *name, void *deviceData)
devoptab_t *dev = NULL;
char *devname = NULL;
int i;
// Sanity check
if (!name || !deviceData || !devoptab_ntfs) {
errno = EINVAL;
return -1;
}
// Allocate a devoptab for this device
dev = ntfs_alloc(sizeof(devoptab_t) + strlen(name) + 1);
if (!dev) {
errno = ENOMEM;
return false;
}
// Use the space allocated at the end of the devoptab for storing the device name
devname = (char*)(dev + 1);
strcpy(devname, name);
// Setup the devoptab
memcpy(dev, devoptab_ntfs, sizeof(devoptab_t));
dev->name = devname;
@ -97,7 +98,7 @@ int ntfsAddDevice (const char *name, void *deviceData)
return 0;
}
}
// If we reach here then there are no free slots in the devoptab table for this device
errno = EADDRNOTAVAIL;
return -1;
@ -108,11 +109,11 @@ void ntfsRemoveDevice (const char *path)
const devoptab_t *devoptab = NULL;
char name[128] = {0};
int i;
// Get the device name from the path
strncpy(name, path, 127);
strtok(name, ":/");
// Find and remove the specified device from the devoptab table
// NOTE: We do this manually due to a 'bug' in RemoveDevice
// which ignores names with suffixes and causes names
@ -127,7 +128,7 @@ void ntfsRemoveDevice (const char *path)
}
}
}
return;
}
@ -136,13 +137,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
const devoptab_t *devoptab = NULL;
char name[128] = {0};
int i;
// Get the device name from the path
strncpy(name, path, 127);
strtok(name, ":/");
// Search the devoptab table for the specified device name
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
// which ignores names with suffixes and causes names
// like "ntfs" and "ntfs1" to be seen as equals
for (i = 0; i < STD_MAX; i++) {
@ -153,13 +154,13 @@ const devoptab_t *ntfsGetDevice (const char *path, bool useDefaultDevice)
}
}
}
// If we reach here then we couldn't find the device name,
// chances are that this path has no device name in it.
// chances are that this path has no device name in it.
// Call GetDeviceOpTab to get our default device (chdir).
if (useDefaultDevice)
return GetDeviceOpTab("");
return NULL;
}
@ -176,7 +177,7 @@ ntfs_vd *ntfsGetVolume (const char *path)
const devoptab_t *devoptab = ntfsGetDevice(path, true);
if (devoptab && devoptab_ntfs && (devoptab->open_r == devoptab_ntfs->open_r))
return (ntfs_vd*)devoptab->deviceData;
return NULL;
}
@ -187,19 +188,22 @@ int ntfsInitVolume (ntfs_vd *vd)
errno = ENODEV;
return -1;
}
// Initialise the volume lock
LWP_MutexInit(&vd->lock, false);
// Reset the volumes name cache
vd->name[0] = '\0';
// Reset the volumes current directory
vd->cwd_ni = NULL;
// Reset open directory and file stats
vd->openDirCount = 0;
vd->openFileCount = 0;
vd->firstOpenDir = NULL;
vd->firstOpenFile = NULL;
return 0;
}
@ -210,7 +214,7 @@ void ntfsDeinitVolume (ntfs_vd *vd)
errno = ENODEV;
return;
}
// Lock
ntfsLock(vd);
@ -221,7 +225,7 @@ void ntfsDeinitVolume (ntfs_vd *vd)
ntfsCloseDir(nextDir);
nextDir = nextDir->nextOpenDir;
}
// Close any files which are still open (lazy programmers!)
ntfs_file_state *nextFile = vd->firstOpenFile;
while (nextFile) {
@ -229,28 +233,28 @@ void ntfsDeinitVolume (ntfs_vd *vd)
ntfsCloseFile(nextFile);
nextFile = nextFile->nextOpenFile;
}
// Reset open directory and file stats
vd->openDirCount = 0;
vd->openFileCount = 0;
vd->firstOpenDir = NULL;
vd->firstOpenFile = NULL;
// Close the volumes current directory (if any)
if (vd->cwd_ni) {
ntfsCloseEntry(vd, vd->cwd_ni);
vd->cwd_ni = NULL;
}
//if (vd->cwd_ni) {
//ntfsCloseEntry(vd, vd->cwd_ni);
//vd->cwd_ni = NULL;
//}
// Force the underlying device to sync
vd->dev->d_ops->sync(vd->dev);
// Unlock
ntfsUnlock(vd);
// Deinitialise the volume lock
LWP_MutexDestroy(vd->lock);
return;
}
@ -264,13 +268,13 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
ntfs_inode *ni = NULL;
char *target = NULL;
int attr_size;
// Sanity check
if (!vd) {
errno = ENODEV;
return NULL;
}
// Get the actual path of the entry
path = ntfsRealPath(path);
if (!path) {
@ -285,26 +289,26 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
ni = ntfs_pathname_to_inode(vd->vol, vd->cwd_ni, path++);
else
ni = ntfs_pathname_to_inode(vd->vol, NULL, path);
// If the entry was found and it has reparse data then parse its true path;
// this resolves the true location of symbolic links and directory junctions
if (ni && (ni->flags & FILE_ATTR_REPARSE_POINT)) {
if (ntfs_possible_symlink(ni)) {
// Sanity check, give up if we are parsing to deep
if (reparseLevel > NTFS_MAX_SYMLINK_DEPTH) {
ntfsCloseEntry(vd, ni);
errno = ELOOP;
return NULL;
}
// Get the target path of this entry
target = ntfs_make_symlink(path, ni, &attr_size);
if (!target) {
ntfsCloseEntry(vd, ni);
return NULL;
}
// Close the entry (we are no longer interested in it)
ntfsCloseEntry(vd, ni);
@ -313,10 +317,10 @@ ntfs_inode *ntfsParseEntry (ntfs_vd *vd, const char *path, int reparseLevel)
// Clean up
ntfs_free(target);
}
}
return ni;
}
@ -327,23 +331,24 @@ void ntfsCloseEntry (ntfs_vd *vd, ntfs_inode *ni)
errno = ENODEV;
return;
}
// Lock
ntfsLock(vd);
// Sync the entry (if it is dirty)
if (NInoDirty(ni))
ntfsSync(vd, ni);
// Close the entry
ntfs_inode_close(ni);
// Unlock
ntfsUnlock(vd);
return;
}
ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *target)
{
ntfs_inode *dir_ni = NULL, *ni = NULL;
@ -357,7 +362,7 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
errno = ENODEV;
return NULL;
}
// You cannot link between devices
if(target) {
if(vd != ntfsGetVolume(target)) {
@ -369,14 +374,14 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
// Get the actual paths of the entry
path = ntfsRealPath(path);
target = ntfsRealPath(target);
if (!path || !target) {
if (!path) {
errno = EINVAL;
return NULL;
}
// Lock
ntfsLock(vd);
// Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible, clean it up
dir = strdup(path);
@ -394,8 +399,13 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
errno = EINVAL;
goto cleanup;
}
*name = 0;
name = strrchr(dir, '/');
if(name)
{
name++;
name[0] = 0;
}
// Open the entries parent directory
dir_ni = ntfsOpenEntry(vd, dir);
if (!dir_ni) {
@ -404,9 +414,13 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
// Create the entry
switch (type) {
// Symbolic link
case S_IFLNK:
if (!target) {
errno = EINVAL;
goto cleanup;
}
utarget_len = ntfsLocalToUnicode(target, &utarget);
if (utarget_len < 0) {
errno = EINVAL;
@ -414,49 +428,49 @@ ntfs_inode *ntfsCreate (ntfs_vd *vd, const char *path, mode_t type, const char *
}
ni = ntfs_create_symlink(dir_ni, 0, uname, uname_len, utarget, utarget_len);
break;
// Directory or file
case S_IFDIR:
case S_IFREG:
ni = ntfs_create(dir_ni, 0, uname, uname_len, type);
break;
}
// If the entry was created
if (ni) {
// Mark the entry for archiving
ni->flags |= FILE_ATTR_ARCHIVE;
// Mark the entry as dirty
NInoSetDirty(ni);
// Sync the entry to disc
ntfsSync(vd, ni);
// Update parent directories times
ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);
}
cleanup:
if(dir_ni)
ntfsCloseEntry(vd, dir_ni);
if(utarget)
ntfs_free(utarget);
if(uname)
ntfs_free(uname);
if(dir)
ntfs_free(dir);
// Unlock
ntfsUnlock(vd);
return ni;
}
@ -468,13 +482,13 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
ntfschar *uname = NULL;
int uname_len;
int res = 0;
// Sanity check
if (!vd) {
errno = ENODEV;
return -1;
}
// You cannot link between devices
if(vd != ntfsGetVolume(new_path)) {
errno = EXDEV;
@ -491,7 +505,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
// Lock
ntfsLock(vd);
// Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible, clean it up
dir = strdup(new_path);
@ -510,7 +524,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
goto cleanup;
}
*name = 0;
// Find the entry
ni = ntfsOpenEntry(vd, old_path);
if (!ni) {
@ -518,7 +532,7 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
res = -1;
goto cleanup;
}
// Open the entries new parent directory
dir_ni = ntfsOpenEntry(vd, dir);
if (!dir_ni) {
@ -526,37 +540,37 @@ int ntfsLink (ntfs_vd *vd, const char *old_path, const char *new_path)
res = -1;
goto cleanup;
}
// Link the entry to its new parent
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
res = -1;
goto cleanup;
}
// Update entry times
ntfsUpdateTimes(vd, ni, NTFS_UPDATE_CTIME);
ntfsUpdateTimes(vd, dir_ni, NTFS_UPDATE_MCTIME);
// Sync the entry to disc
ntfsSync(vd, ni);
cleanup:
if(dir_ni)
ntfsCloseEntry(vd, dir_ni);
if(ni)
ntfsCloseEntry(vd, ni);
if(uname)
ntfs_free(uname);
if(dir)
ntfs_free(dir);
// Unlock
ntfsUnlock(vd);
return res;
}
@ -568,23 +582,23 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
ntfschar *uname = NULL;
int uname_len;
int res = 0;
// Sanity check
if (!vd) {
errno = ENODEV;
return -1;
}
// Get the actual path of the entry
path = ntfsRealPath(path);
if (!path) {
errno = EINVAL;
return -1;
}
// Lock
ntfsLock(vd);
// Get the unicode name for the entry and find its parent directory
// TODO: This looks horrible
dir = strdup(path);
@ -602,8 +616,13 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
errno = EINVAL;
goto cleanup;
}
*name = 0;
name = strrchr(dir, '/');
if(name)
{
name++;
name[0] = 0;
}
// Find the entry
ni = ntfsOpenEntry(vd, path);
if (!ni) {
@ -611,7 +630,7 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
res = -1;
goto cleanup;
}
// Open the entries parent directory
dir_ni = ntfsOpenEntry(vd, dir);
if (!dir_ni) {
@ -619,76 +638,75 @@ int ntfsUnlink (ntfs_vd *vd, const char *path)
res = -1;
goto cleanup;
}
// Unlink the entry from its parent
if (ntfs_delete(vd->vol, path, ni, dir_ni, uname, uname_len)) {
res = -1;
}
// Force the underlying device to sync
vd->dev->d_ops->sync(vd->dev);
// ntfs_delete() ALWAYS closes ni and dir_ni; so no need for us to anymore
dir_ni = ni = NULL;
cleanup:
if(dir_ni)
ntfsCloseEntry(vd, dir_ni);
if(ni)
ntfsCloseEntry(vd, ni);
if(uname)
ntfs_free(uname);
if(dir)
ntfs_free(dir);
// Unlock
ntfsUnlock(vd);
return 0;
}
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
{
int res = 0;
// Sanity check
if (!vd) {
errno = ENODEV;
return -1;
}
// Sanity check
if (!ni) {
errno = ENOENT;
return -1;
}
// Lock
ntfsLock(vd);
// Sync the entry
res = ntfs_inode_sync(ni);
// Force the underlying device to sync
vd->dev->d_ops->sync(vd->dev);
vd->dev->d_ops->sync(vd->dev);
// Unlock
ntfsUnlock(vd);
return res;
}
int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
{
//printf("ntfsStat %p %p %p\n", vd, ni, st);
ntfs_attr *na = NULL;
int res = 0;
// Sanity check
if (!vd) {
errno = ENODEV;
@ -700,22 +718,22 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
errno = ENOENT;
return -1;
}
// Short circuit cases were we don't actually have to do anything
if (!st)
return 0;
// Lock
ntfsLock(vd);
// Zero out the stat buffer
memset(st, 0, sizeof(struct stat));
// Is this entry a directory
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
st->st_mode = S_IFDIR | (0777 & ~vd->dmask);
st->st_nlink = 1;
// Open the directories index allocation table attribute
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
if (na) {
@ -723,7 +741,7 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
st->st_blocks = na->allocated_size >> 9;
ntfs_attr_close(na);
}
// Else it must be a file
} else {
st->st_mode = S_IFREG | (0777 & ~vd->fmask);
@ -731,7 +749,7 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
st->st_blocks = (ni->allocated_size + 511) >> 9;
st->st_nlink = le16_to_cpu(ni->mrec->link_count);
}
// Fill in the generic entry stats
st->st_dev = vd->id;
st->st_uid = vd->uid;
@ -740,13 +758,13 @@ int ntfsStat (ntfs_vd *vd, ntfs_inode *ni, struct stat *st)
st->st_atime = ni->last_access_time;
st->st_ctime = ni->last_mft_change_time;
st->st_mtime = ni->last_data_change_time;
// Update entry times
ntfsUpdateTimes(vd, ni, NTFS_UPDATE_ATIME);
// Unlock
ntfsUnlock(vd);
return res;
}
@ -759,7 +777,7 @@ void ntfsUpdateTimes (ntfs_vd *vd, ntfs_inode *ni, ntfs_time_update_flags mask)
// Update entry times
if (ni && mask)
ntfs_inode_update_times(ni, mask);
return;
}
@ -768,7 +786,7 @@ const char *ntfsRealPath (const char *path)
// Sanity check
if (!path)
return NULL;
// Move the path pointer to the start of the actual path
if (strchr(path, ':') != NULL) {
path = strchr(path, ':') + 1;
@ -776,7 +794,7 @@ const char *ntfsRealPath (const char *path)
if (strchr(path, ':') != NULL) {
return NULL;
}
return path;
}
@ -784,15 +802,15 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
{
int len = 0;
int i;
// Sanity check
if (!ins || !ins_len || !outs)
return 0;
// Convert the unicode string to our current local
len = ntfs_ucstombs(ins, ins_len, outs, outs_len);
len = ntfs_ucstombs(ins, ins_len, outs, outs_len);
if (len == -1 && errno == EILSEQ) {
// The string could not be converted to the current local,
// do it manually by replacing non-ASCII characters with underscores
if (!*outs || outs_len >= ins_len) {
@ -812,9 +830,9 @@ int ntfsUnicodeToLocal (const ntfschar *ins, const int ins_len, char **outs, int
*outs[ins_len] = (ntfschar)'\0';
len = ins_len;
}
}
return len;
}
@ -823,7 +841,7 @@ int ntfsLocalToUnicode (const char *ins, ntfschar **outs)
// Sanity check
if (!ins || !outs)
return 0;
// Convert the local string to unicode
return ntfs_mbstoucs(ins, outs);
}

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

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

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 '_'
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;