diff --git a/HBC/META.XML b/HBC/META.XML index 6c135372..52e5ff53 100644 --- a/HBC/META.XML +++ b/HBC/META.XML @@ -2,8 +2,8 @@ USB Loader GX USB Loader GX Team - 1.0 r898 - 201001191410 + 1.0 r900 + 201001311842 Loads games from USB-devices 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. diff --git a/Makefile b/Makefile index 421a5e78..61c9458d 100644 --- a/Makefile +++ b/Makefile @@ -16,11 +16,31 @@ include $(DEVKITPPC)/wii_rules #--------------------------------------------------------------------------------- TARGET := boot BUILD := build -SOURCES := source source/libwiigui source/images source/fonts source/sounds \ - source/libwbfs source/unzip source/language source/mload source/patches \ - source/usbloader source/xml source/network source/settings source/prompts \ - source/ramdisk source/wad source/banner source/cheats source/homebrewboot \ - source/themes source/menu source/libfat source/memory source/libntfs +SOURCES := source \ + source/libwiigui \ + source/images \ + source/fonts \ + source/sounds \ + source/libwbfs \ + source/unzip \ + source/language \ + source/mload \ + source/patches \ + source/usbloader \ + source/xml \ + source/network \ + source/settings \ + source/prompts \ + source/ramdisk \ + source/wad \ + source/banner \ + source/cheats \ + source/homebrewboot \ + source/themes \ + source/menu \ + source/libfat \ + source/memory \ + source/libntfs DATA := data INCLUDES := source @@ -28,7 +48,8 @@ INCLUDES := source # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -ffast-math -g -O3 -pipe -mrvl -mcpu=750 -meabi -mhard-float -Wall $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H -DGEKKO -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE +CFLAGS = -ffast-math -g -O3 -pipe -mrvl -mcpu=750 -meabi -mhard-float -Wall $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H -DGEKKO \ + -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE CXXFLAGS = -Xassembler -aln=$@.lst $(CFLAGS) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00000,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size -include $(PROJECTDIR)/Make.config diff --git a/gui.pnps b/gui.pnps index e3cd56db..9c9f0964 100644 --- a/gui.pnps +++ b/gui.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/fatmounter.c b/source/fatmounter.c index 90cfd1e0..9622b343 100644 --- a/source/fatmounter.c +++ b/source/fatmounter.c @@ -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; diff --git a/source/libntfs/acls.c b/source/libntfs/acls.c index 887d75ae..4bfd3652 100644 --- a/source/libntfs/acls.c +++ b/source/libntfs/acls.c @@ -40,6 +40,9 @@ #ifdef HAVE_ERRNO_H #include #endif +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_FCNTL_H #include #endif diff --git a/source/libntfs/attrib.c b/source/libntfs/attrib.c index fa0423bc..41e4dcf0 100644 --- a/source/libntfs/attrib.c +++ b/source/libntfs/attrib.c @@ -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 #endif +#ifdef HAVE_LIMITS_H +#include +#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 diff --git a/source/libntfs/attrib.h b/source/libntfs/attrib.h index a11f7b6b..bcdb0117 100644 --- a/source/libntfs/attrib.h +++ b/source/libntfs/attrib.h @@ -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, diff --git a/source/libntfs/bit_ops.h b/source/libntfs/bit_ops.h new file mode 100644 index 00000000..762be0b3 --- /dev/null +++ b/source/libntfs/bit_ops.h @@ -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 + +/*----------------------------------------------------------------- +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 diff --git a/source/libntfs/cache.c b/source/libntfs/cache.c index 8d31b74c..0fe46543 100644 --- a/source/libntfs/cache.c +++ b/source/libntfs/cache.c @@ -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_accessdisc->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 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; diff --git a/source/libntfs/compat.h b/source/libntfs/compat.h index b623d0ea..957752a0 100644 --- a/source/libntfs/compat.h +++ b/source/libntfs/compat.h @@ -66,7 +66,6 @@ extern char *strsep(char **stringp, const char *delim); #ifdef GEKKO #include "mem_allocate.h" -#include #define XATTR_CREATE 1 #define XATTR_REPLACE 2 diff --git a/source/libntfs/config.h b/source/libntfs/config.h index e320107c..67109a10 100644 --- a/source/libntfs/config.h +++ b/source/libntfs/config.h @@ -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 */ diff --git a/source/libntfs/device_io.c b/source/libntfs/device_io.c index 4151d89e..f76bf703 100644 --- a/source/libntfs/device_io.c +++ b/source/libntfs/device_io.c @@ -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 */ diff --git a/source/libntfs/efs.c b/source/libntfs/efs.c index 3b7e53ae..e7a134a2 100644 --- a/source/libntfs/efs.c +++ b/source/libntfs/efs.c @@ -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 */ diff --git a/source/libntfs/gekko_io.c b/source/libntfs/gekko_io.c index 27abc806..61db831e 100644 --- a/source/libntfs/gekko_io.c +++ b/source/libntfs/gekko_io.c @@ -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; } diff --git a/source/libntfs/inode.c b/source/libntfs/inode.c index d1a10849..ad554b36 100644 --- a/source/libntfs/inode.c +++ b/source/libntfs/inode.c @@ -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 */ diff --git a/source/libntfs/logfile.c b/source/libntfs/logfile.c index 277ad142..4a129cb4 100644 --- a/source/libntfs/logfile.c +++ b/source/libntfs/logfile.c @@ -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); diff --git a/source/libntfs/mem_allocate.h b/source/libntfs/mem_allocate.h index beb3e7f1..600e5a93 100644 --- a/source/libntfs/mem_allocate.h +++ b/source/libntfs/mem_allocate.h @@ -24,8 +24,6 @@ #include -#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 */ diff --git a/source/libntfs/mft.c b/source/libntfs/mft.c index 09aaaee9..ce138d2e 100644 --- a/source/libntfs/mft.c +++ b/source/libntfs/mft.c @@ -38,6 +38,9 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_LIMITS_H +#include +#endif #include #include "compat.h" diff --git a/source/libntfs/ntfs.c b/source/libntfs/ntfs.c index 9df4d559..85a01159 100644 --- a/source/libntfs/ntfs.c +++ b/source/libntfs/ntfs.c @@ -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; } - diff --git a/source/libntfs/ntfs.h b/source/libntfs/ntfs.h index 5dd0c12d..3df8ed75 100644 --- a/source/libntfs/ntfs.h +++ b/source/libntfs/ntfs.h @@ -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 -#include -#include - -/* 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 +#include +#include + +/* 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); + diff --git a/source/libntfs/ntfsdir.c b/source/libntfs/ntfsdir.c index c8ae4279..cf6e275b 100644 --- a/source/libntfs/ntfsdir.c +++ b/source/libntfs/ntfsdir.c @@ -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; } diff --git a/source/libntfs/ntfsfile.c b/source/libntfs/ntfsfile.c index c1142013..beeb7cf4 100644 --- a/source/libntfs/ntfsfile.c +++ b/source/libntfs/ntfsfile.c @@ -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); diff --git a/source/libntfs/ntfsfile.h b/source/libntfs/ntfsfile.h index 88a8dc6c..275c745a 100644 --- a/source/libntfs/ntfsfile.h +++ b/source/libntfs/ntfsfile.h @@ -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; diff --git a/source/libntfs/ntfsinternal.c b/source/libntfs/ntfsinternal.c index f6880c22..2b11c724 100644 --- a/source/libntfs/ntfsinternal.c +++ b/source/libntfs/ntfsinternal.c @@ -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); } diff --git a/source/libntfs/ntfsinternal.h b/source/libntfs/ntfsinternal.h index 5b06b9c0..11dfb8fd 100644 --- a/source/libntfs/ntfsinternal.h +++ b/source/libntfs/ntfsinternal.h @@ -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 */ diff --git a/source/libntfs/reparse.c b/source/libntfs/reparse.c index 20934436..80a25acb 100644 --- a/source/libntfs/reparse.c +++ b/source/libntfs/reparse.c @@ -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 */ diff --git a/source/libntfs/security.c b/source/libntfs/security.c index aed9ff1b..38acce40 100644 --- a/source/libntfs/security.c +++ b/source/libntfs/security.c @@ -41,6 +41,9 @@ #ifdef HAVE_FCNTL_H #include #endif +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_SETXATTR #include #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 diff --git a/source/menu/menu_disclist.cpp b/source/menu/menu_disclist.cpp index dbd37bce..d015d54a 100644 --- a/source/menu/menu_disclist.cpp +++ b/source/menu/menu_disclist.cpp @@ -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) { diff --git a/source/menu/menu_install.cpp b/source/menu/menu_install.cpp index a9b8fe21..adfc6b1e 100644 --- a/source/menu/menu_install.cpp +++ b/source/menu/menu_install.cpp @@ -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; diff --git a/source/settings/Settings.cpp b/source/settings/Settings.cpp index 3e1d7384..98be0a75 100644 --- a/source/settings/Settings.cpp +++ b/source/settings/Settings.cpp @@ -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) diff --git a/source/settings/cfg.h b/source/settings/cfg.h index a2a1c764..3aac08ba 100644 --- a/source/settings/cfg.h +++ b/source/settings/cfg.h @@ -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; diff --git a/source/usbloader/wbfs.c b/source/usbloader/wbfs.c index 415c5242..accbbbae 100644 --- a/source/usbloader/wbfs.c +++ b/source/usbloader/wbfs.c @@ -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); } diff --git a/source/usbloader/wbfs_fat.c b/source/usbloader/wbfs_fat.c index 483d22cc..adb0ca91 100644 --- a/source/usbloader/wbfs_fat.c +++ b/source/usbloader/wbfs_fat.c @@ -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; iid, 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;