diff --git a/libcustomext2fs/CREDITS b/libcustomext2fs/CREDITS index 32fb026f..29e76282 100644 --- a/libcustomext2fs/CREDITS +++ b/libcustomext2fs/CREDITS @@ -6,4 +6,5 @@ to the Nintendo GameCube/Wii port of ext2fs. Michael "Chishm" Chisholm rodries -Rhys "Shareese" Koedijk \ No newline at end of file +Rhys "Shareese" Koedijk +Dimok diff --git a/libcustomext2fs/Makefile b/libcustomext2fs/Makefile index 8745416d..da9780e0 100644 --- a/libcustomext2fs/Makefile +++ b/libcustomext2fs/Makefile @@ -25,7 +25,3 @@ clean: install: cube-release wii-release $(MAKE) -C source install -run: install - $(MAKE) -C example - $(MAKE) -C example run - diff --git a/libcustomext2fs/source/Makefile b/libcustomext2fs/source/Makefile index 93fb8aa0..6c4c348a 100644 --- a/libcustomext2fs/source/Makefile +++ b/libcustomext2fs/source/Makefile @@ -28,7 +28,7 @@ LIBDIR := ../lib #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -Os -Wall -Wno-unused $(MACHDEP) $(INCLUDE) -DGEKKO -DWORDS_BIGENDIAN +CFLAGS = -O2 -Wall -Wno-unused $(MACHDEP) $(INCLUDE) -DGEKKO -DWORDS_BIGENDIAN CXXFLAGS = $(CFLAGS) ASFLAGS := -g export EXT2BIN := $(LIBDIR)/$(PLATFORM)/libext2fs.a diff --git a/libcustomext2fs/source/ext2_err.c b/libcustomext2fs/source/ext2_err.c index 0b45e958..a58b6866 100644 --- a/libcustomext2fs/source/ext2_err.c +++ b/libcustomext2fs/source/ext2_err.c @@ -8,7 +8,7 @@ #define N_(a) a static const char * const text[] = { - N_( "EXT2FS Library version 1.42-WIP"), + N_( "EXT2FS Library version 1.42"), N_( "Wrong magic number for ext2_filsys structure"), N_( "Wrong magic number for badblocks_list structure"), N_( "Wrong magic number for badblocks_iterate structure"), diff --git a/libcustomext2fs/source/ext2fs.h b/libcustomext2fs/source/ext2fs.h index 703ff0c7..85ac7a2b 100644 --- a/libcustomext2fs/source/ext2fs.h +++ b/libcustomext2fs/source/ext2fs.h @@ -247,6 +247,13 @@ struct struct_ext2_filsys { struct ext2_inode_cache *icache; io_channel image_io; + /* + * More callback functions + */ + errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal, + blk64_t *ret); + void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse); + /* * Buffers for Multiple mount protection(MMP) block. */ @@ -258,13 +265,6 @@ struct struct_ext2_filsys { * Time at which e2fsck last updated the MMP block. */ long mmp_last_written; - - /* - * More callback functions - */ - errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal, - blk64_t *ret); - void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse); }; #include "bitops.h" @@ -558,6 +558,7 @@ typedef struct ext2_icount *ext2_icount_t; EXT4_FEATURE_INCOMPAT_MMP|\ EXT4_FEATURE_INCOMPAT_64BIT) #endif +#ifdef CONFIG_QUOTA #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\ EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ @@ -566,6 +567,15 @@ typedef struct ext2_icount *ext2_icount_t; EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ EXT4_FEATURE_RO_COMPAT_BIGALLOC|\ EXT4_FEATURE_RO_COMPAT_QUOTA) +#else +#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ + EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ + EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ + EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ + EXT4_FEATURE_RO_COMPAT_BIGALLOC) +#endif /* * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed @@ -585,7 +595,7 @@ typedef struct ext2_icount *ext2_icount_t; #define EXT2FS_NUM_B2C(fs, blks) (((blks) + EXT2FS_CLUSTER_MASK(fs)) >> \ (fs)->cluster_ratio_bits) -#if defined(HAVE_STAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) typedef struct stat64 ext2fs_struct_stat; #else typedef struct stat ext2fs_struct_stat; @@ -1679,7 +1689,7 @@ _INLINE_ int ext2fs_open_file(const char *pathname, int flags, mode_t mode) _INLINE_ int ext2fs_stat(const char *path, ext2fs_struct_stat *buf) { -#if defined(HAVE_STAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) return stat64(path, buf); #else return stat(path, buf); @@ -1688,7 +1698,7 @@ _INLINE_ int ext2fs_stat(const char *path, ext2fs_struct_stat *buf) _INLINE_ int ext2fs_fstat(int fd, ext2fs_struct_stat *buf) { -#if defined(HAVE_STAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) return fstat64(fd, buf); #else return fstat(fd, buf); diff --git a/libcustomext2fs/source/ext2fsP.h b/libcustomext2fs/source/ext2fsP.h index b182d7fe..82e1ba0e 100644 --- a/libcustomext2fs/source/ext2fsP.h +++ b/libcustomext2fs/source/ext2fsP.h @@ -11,6 +11,8 @@ #include "ext2fs.h" +#define EXT2FS_MAX_NESTED_LINKS 8 + /* * Badblocks list */ diff --git a/libcustomext2fs/source/finddev.c b/libcustomext2fs/source/finddev.c index 13ef14bf..311608de 100644 --- a/libcustomext2fs/source/finddev.c +++ b/libcustomext2fs/source/finddev.c @@ -34,6 +34,7 @@ #include "ext2_fs.h" #include "ext2fs.h" +#include "ext2fsP.h" struct dir_list { char *name; @@ -128,6 +129,7 @@ char *ext2fs_find_block_device(dev_t device) struct dir_list *list = 0, *new_list = 0; struct dir_list *current; char *ret_path = 0; + int level = 0; /* * Add the starting directories to search... @@ -154,6 +156,9 @@ char *ext2fs_find_block_device(dev_t device) if (list == 0) { list = new_list; new_list = 0; + /* Avoid infinite loop */ + if (++level >= EXT2FS_MAX_NESTED_LINKS) + break; } } free_dirlist(&list); diff --git a/libcustomext2fs/source/icount.c b/libcustomext2fs/source/icount.c index 1a18b377..5d64ac43 100644 --- a/libcustomext2fs/source/icount.c +++ b/libcustomext2fs/source/icount.c @@ -180,6 +180,7 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, ext2_icount_t icount; errcode_t retval; char *fn, uuid[40]; + ext2_ino_t num_inodes; int fd; retval = alloc_icount(fs, flags, &icount); @@ -193,8 +194,18 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); fd = mkstemp(fn); + /* + * This is an overestimate of the size that we will need; the + * ideal value is the number of used inodes with a count + * greater than 1. OTOH the times when we really need this is + * with the backup programs that use lots of hard links, in + * which case the number of inodes in use approaches the ideal + * value. + */ + num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count; + icount->tdb_fn = fn; - icount->tdb = tdb_open(fn, 0, TDB_CLEAR_IF_FIRST, + icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC, O_RDWR | O_CREAT | O_TRUNC, 0600); if (icount->tdb) { close(fd); diff --git a/libcustomext2fs/source/ismounted.c b/libcustomext2fs/source/ismounted.c index bc1134fc..89d0d9a0 100644 --- a/libcustomext2fs/source/ismounted.c +++ b/libcustomext2fs/source/ismounted.c @@ -9,6 +9,7 @@ * %End-Header% */ +#include "config.h" #include #if HAVE_UNISTD_H #include diff --git a/libcustomext2fs/source/mmp.c b/libcustomext2fs/source/mmp.c index 72c349e2..dbbbdb2b 100644 --- a/libcustomext2fs/source/mmp.c +++ b/libcustomext2fs/source/mmp.c @@ -130,7 +130,7 @@ errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf) /* I was tempted to make this use O_DIRECT and the mmp_fd, but * this caused no end of grief, while leaving it as-is works. */ - retval = io_channel_write_blk64(fs->io, mmp_blk, -fs->blocksize, buf); + retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf); #ifdef WORDS_BIGENDIAN ext2fs_swap_mmp(mmp_s); diff --git a/libcustomext2fs/source/namei.c b/libcustomext2fs/source/namei.c index 6bbb1240..efcc02b7 100644 --- a/libcustomext2fs/source/namei.c +++ b/libcustomext2fs/source/namei.c @@ -20,6 +20,7 @@ #include "ext2_fs.h" #include "ext2fs.h" +#include "ext2fsP.h" static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base, const char *pathname, size_t pathlen, int follow, @@ -45,9 +46,9 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, *res_inode = inode; return 0; } - if (link_count++ > 5) { + if (link_count++ >= EXT2FS_MAX_NESTED_LINKS) return EXT2_ET_SYMLINK_LOOP; - } + /* FIXME-64: Actually, this is FIXME EXTENTS */ if (ext2fs_inode_data_blocks(fs,&ei)) { retval = ext2fs_get_mem(fs->blocksize, &buffer); diff --git a/libcustomext2fs/source/openfs.c b/libcustomext2fs/source/openfs.c index e09952eb..f5c736ff 100644 --- a/libcustomext2fs/source/openfs.c +++ b/libcustomext2fs/source/openfs.c @@ -358,8 +358,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, goto cleanup; #ifdef WORDS_BIGENDIAN for (j=0; j < groups_per_block; j++) { - /* The below happens to work... be careful. */ - gdp = ext2fs_group_desc(fs, fs->group_desc, j); + gdp = ext2fs_group_desc(fs, fs->group_desc, + i * groups_per_block + j); ext2fs_swap_group_desc2(fs, gdp); } #endif diff --git a/libcustomext2fs/source/tdb.c b/libcustomext2fs/source/tdb.c index 8fe66891..73d54b6b 100644 --- a/libcustomext2fs/source/tdb.c +++ b/libcustomext2fs/source/tdb.c @@ -108,6 +108,8 @@ typedef int bool; #include "tdb.h" +static TDB_DATA tdb_null; + #ifndef u32 #define u32 unsigned #endif @@ -1752,7 +1754,7 @@ static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n")); return -1; } -#ifdef MS_SYNC +#if defined(HAVE_MSYNC) && defined(MS_SYNC) if (tdb->map_ptr) { tdb_off_t moffset = offset & ~(tdb->page_size-1); if (msync(moffset + (char *)tdb->map_ptr, @@ -3060,8 +3062,6 @@ int tdb_printfreelist(struct tdb_context *tdb) /* file: tdb.c */ -TDB_DATA tdb_null; - /* non-blocking increment of the tdb sequence number if the tdb has been opened using the TDB_SEQNUM flag @@ -3713,17 +3713,17 @@ void tdb_enable_seqnum(struct tdb_context *tdb) static struct tdb_context *tdbs = NULL; -/* This is based on the hash algorithm from gdbm */ +/* This is from a hash algorithm suggested by Rogier Wolff */ static unsigned int default_tdb_hash(TDB_DATA *key) { u32 value; /* Used to compute the hash value. */ u32 i; /* Used to cycle through random values. */ /* Set the initial value from the key size. */ - for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++) - value = (value + (key->dptr[i] << (i*5 % 24))); + for (value = 0, i=0; i < key->dsize; i++) + value = value * 256 + key->dptr[i] + (value >> 24) * 241; - return (1103515243 * value + 12345); + return value; } diff --git a/libcustomext2fs/source/tdb.h b/libcustomext2fs/source/tdb.h index bfcd9436..732ef0ec 100644 --- a/libcustomext2fs/source/tdb.h +++ b/libcustomext2fs/source/tdb.h @@ -206,8 +206,6 @@ void tdb_dump_all(struct tdb_context *tdb); int tdb_printfreelist(struct tdb_context *tdb); int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); -extern TDB_DATA tdb_null; - #ifdef __cplusplus } #endif diff --git a/libcustomext2fs/source/version.c b/libcustomext2fs/source/version.c index 667c0c89..3acfe3f9 100644 --- a/libcustomext2fs/source/version.c +++ b/libcustomext2fs/source/version.c @@ -20,9 +20,10 @@ #include "ext2_fs.h" #include "ext2fs.h" +#include "version.h" -static const char *lib_version = ""; -static const char *lib_date = ""; +static const char *lib_version = E2FSPROGS_VERSION; +static const char *lib_date = E2FSPROGS_DATE; int ext2fs_parse_version_string(const char *ver_string) { diff --git a/libcustomext2fs/source/version.h b/libcustomext2fs/source/version.h new file mode 100644 index 00000000..10c4d84b --- /dev/null +++ b/libcustomext2fs/source/version.h @@ -0,0 +1,11 @@ +/* + * version.h --- controls the version number printed by the e2fs + * programs. + * + * Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + * 2004, 2005, 2006, 2007, 2008, 2009, 2010 by Theodore Ts'o. This + * file may be redistributed under the GNU Public License v2. + */ + +#define E2FSPROGS_VERSION "1.42" +#define E2FSPROGS_DATE "29-Nov-2011" diff --git a/libcustomfat/Makefile b/libcustomfat/Makefile index 5c081a6d..d909ca3b 100644 --- a/libcustomfat/Makefile +++ b/libcustomfat/Makefile @@ -1,32 +1,31 @@ -# Quick'n'dirty makefile [BC] v2 - -ifeq ($(strip $(DEVKITPPC)),) -$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPro) endif + +export TOPDIR := $(CURDIR) + +export LIBFAT_MAJOR := 1 +export LIBFAT_MINOR := 0 +export LIBFAT_PATCH := 10 -include $(DEVKITPPC)/wii_rules +export VERSTRING := $(LIBFAT_MAJOR).$(LIBFAT_MINOR).$(LIBFAT_PATCH) -LIBOGC_INC := $(DEVKITPRO)/libogc/include -LIBOGC_LIB := $(DEVKITPRO)/libogc/lib/wii -CFLAGS := -O3 $(MACHDEP) -I$(LIBOGC_INC) +default: release -LIB := fat -CFILES := $(wildcard *.c) -OFILES := $(CFILES:.c=.o) -ARC := lib$(LIB).a -HDR := fat.h +all: release -all : $(OFILES) - $(AR) -r $(ARC) $(OFILES) +release: include/libfatversion.h wii-release -clean : - rm -f $(OFILES) $(ARC) +wii-release: + $(MAKE) -C libogc PLATFORM=wii BUILD=wii_release -install : - mkdir -p $(LIBOGC_LIB) $(LIBOGC_INC) - cp -f $(ARC) $(LIBOGC_LIB)/ - cp -f $(HDR) $(LIBOGC_INC)/ +clean: ogc-clean -%.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ \ No newline at end of file +ogc-clean: + $(MAKE) -C libogc clean + +install: ogc-install + +ogc-install: cube-release wii-release + $(MAKE) -C libogc install diff --git a/libcustomfat/fat.h b/libcustomfat/include/fat.h similarity index 99% rename from libcustomfat/fat.h rename to libcustomfat/include/fat.h index 82c973d3..b0ffc13a 100644 --- a/libcustomfat/fat.h +++ b/libcustomfat/include/fat.h @@ -1,7 +1,7 @@ /* fat.h Simple functionality for startup, mounting and unmounting of FAT-based devices. - + Copyright (c) 2006 - 2009 Michael "Chishm" Chisholm Dave "WinterMute" Murphy @@ -71,7 +71,7 @@ extern bool fatInitDefault (void); /* Mount the device pointed to by interface, and set up a devoptab entry for it as "name:". You can then access the filesystem using "name:/". -This will mount the active partition or the first valid partition on the disc, +This will mount the active partition or the first valid partition on the disc, and will use a cache size optimized for the host system. */ extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface); diff --git a/libcustomfat/include/libfatversion.h b/libcustomfat/include/libfatversion.h new file mode 100644 index 00000000..82c3187b --- /dev/null +++ b/libcustomfat/include/libfatversion.h @@ -0,0 +1,10 @@ +#ifndef __LIBFATVERSION_H__ +#define __LIBFATVERSION_H__ + +#define _LIBFAT_MAJOR_ 1 +#define _LIBFAT_MINOR_ 0 +#define _LIBFAT_PATCH_ 10 + +#define _LIBFAT_STRING "libFAT Release 1.0.10" + +#endif // __LIBFATVERSION_H__ diff --git a/libcustomfat/libfat.pnproj b/libcustomfat/libfat.pnproj new file mode 100644 index 00000000..9b35658d --- /dev/null +++ b/libcustomfat/libfat.pnproj @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libcustomfat/libfat.pnps b/libcustomfat/libfat.pnps new file mode 100644 index 00000000..bb191eba --- /dev/null +++ b/libcustomfat/libfat.pnps @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libcustomfat/libogc/Makefile b/libcustomfat/libogc/Makefile new file mode 100644 index 00000000..30a396b8 --- /dev/null +++ b/libcustomfat/libogc/Makefile @@ -0,0 +1,132 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC) +endif + +ifeq ($(PLATFORM),wii) +include $(DEVKITPPC)/wii_rules +endif + +ifeq ($(PLATFORM),cube) +include $(DEVKITPPC)/gamecube_rules +endif + +#--------------------------------------------------------------------------------- +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +# DATA is a list of directories containing binary files +# LIBDIR is where the built library will be placed +# all directories are relative to this makefile +#--------------------------------------------------------------------------------- +BUILD ?= wii_release +SOURCES := ../source +INCLUDES := ../include +DATA := +LIBDIR := $(TOPDIR)/libogc/lib + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +ASFLAGS := -g + +ifneq ($(BUILD),debug) +export CUBEBIN := $(LIBDIR)/$(PLATFORM)/libfat.a +else +export CUBEBIN := $(LIBDIR)/$(PLATFORM)/libfatd.a +CFLAGS += -DFAT_DEBUG +endif + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export TOPDIR ?= $(CURDIR)/.. + + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr wii_debug wii_release cube_debug cube_release $(LIBDIR) + +all: $(CUBEBIN) + +dist-bin: + @tar --exclude=.svn --exclude=*CVS* -cvjf $(TOPDIR)/distribute/$(VERSTRING)/libfat-ogc-$(VERSTRING).tar.bz2 include lib + +install: + cp lib/wii/libfat.a $(DEVKITPRO)/libogc/lib/wii + cp lib/cube/libfat.a $(DEVKITPRO)/libogc/lib/cube + cp include/fat.h $(DEVKITPRO)/libogc/include + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(CUBEBIN) : $(OFILES) $(LIBDIR)/$(PLATFORM) + @rm -f "$(CUBEBIN)" + @$(AR) rcs "$(CUBEBIN)" $(OFILES) + @echo built ... $(notdir $@) + +$(LIBDIR)/$(PLATFORM): + mkdir -p $(LIBDIR)/$(PLATFORM) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- + diff --git a/libcustomfat/libogc/include/fat.h b/libcustomfat/libogc/include/fat.h new file mode 100644 index 00000000..31efbe02 --- /dev/null +++ b/libcustomfat/libogc/include/fat.h @@ -0,0 +1,86 @@ +/* + fat.h + Simple functionality for startup, mounting and unmounting of FAT-based devices. + + 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 _LIBFAT_H +#define _LIBFAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* +Initialise any inserted block-devices. +Add the fat device driver to the devoptab, making it available for standard file functions. +cacheSize: The number of pages to allocate for each inserted block-device +setAsDefaultDevice: if true, make this the default device driver for file operations +*/ +extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice); + +/* +Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system. +*/ +extern bool fatInitDefault (void); + +/* +Mount the device pointed to by interface, and set up a devoptab entry for it as "name:". +You can then access the filesystem using "name:/". +This will mount the active partition or the first valid partition on the disc, +and will use a cache size optimized for the host system. +*/ +extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface); + +/* +Mount the device pointed to by interface, and set up a devoptab entry for it as "name:". +You can then access the filesystem using "name:/". +If startSector = 0, it will mount the active partition of the first valid partition on +the disc. Otherwise it will try to mount the partition starting at startSector. +cacheSize specifies the number of pages to allocate for the cache. +This will not startup the disc, so you need to call interface->startup(); first. +*/ +extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage); + +/* +Unmount the partition specified by name. +If there are open files, it will attempt to synchronise them to disc. +*/ +extern void fatUnmount (const char* name); + +/* +Get Volume Label +*/ +extern void fatGetVolumeLabel (const char* name, char *label); + +#ifdef __cplusplus +} +#endif + +#endif // _LIBFAT_H diff --git a/libcustomfat/bit_ops.h b/libcustomfat/source/bit_ops.h similarity index 100% rename from libcustomfat/bit_ops.h rename to libcustomfat/source/bit_ops.h diff --git a/libcustomfat/cache.c b/libcustomfat/source/cache.c similarity index 100% rename from libcustomfat/cache.c rename to libcustomfat/source/cache.c diff --git a/libcustomfat/cache.h b/libcustomfat/source/cache.h similarity index 100% rename from libcustomfat/cache.h rename to libcustomfat/source/cache.h diff --git a/libcustomfat/common.h b/libcustomfat/source/common.h similarity index 100% rename from libcustomfat/common.h rename to libcustomfat/source/common.h diff --git a/libcustomfat/directory.c b/libcustomfat/source/directory.c similarity index 98% rename from libcustomfat/directory.c rename to libcustomfat/source/directory.c index 55de3bb9..c09debe6 100644 --- a/libcustomfat/directory.c +++ b/libcustomfat/source/directory.c @@ -204,8 +204,10 @@ static int _FAT_directory_mbsncasecmp (const char* s1, const char* s2, size_t le static bool _FAT_directory_entryGetAlias (const u8* entryData, char* destName) { - int i=0; - int j=0; + char c; + bool caseInfo; + int i = 0; + int j = 0; destName[0] = '\0'; if (entryData[0] != DIR_ENTRY_FREE) { @@ -219,14 +221,18 @@ static bool _FAT_directory_entryGetAlias (const u8* entryData, char* destName) { } } else { // Copy the filename from the dirEntry to the string + caseInfo = entryData[DIR_ENTRY_caseInfo] & CASE_LOWER_BASE; for (i = 0; (i < 8) && (entryData[DIR_ENTRY_name + i] != ' '); i++) { - destName[i] = entryData[DIR_ENTRY_name + i]; + c = entryData[DIR_ENTRY_name + i]; + destName[i] = (caseInfo ? tolower((unsigned char)c) : c); } // Copy the extension from the dirEntry to the string if (entryData[DIR_ENTRY_extension] != ' ') { destName[i++] = '.'; + caseInfo = entryData[DIR_ENTRY_caseInfo] & CASE_LOWER_EXT; for ( j = 0; (j < 3) && (entryData[DIR_ENTRY_extension + j] != ' '); j++) { - destName[i++] = entryData[DIR_ENTRY_extension + j]; + c = entryData[DIR_ENTRY_extension + j]; + destName[i++] = (caseInfo ? tolower((unsigned char)c) : c); } } destName[i] = '\0'; diff --git a/libcustomfat/directory.h b/libcustomfat/source/directory.h similarity index 97% rename from libcustomfat/directory.h rename to libcustomfat/source/directory.h index 93429217..ac66c781 100644 --- a/libcustomfat/directory.h +++ b/libcustomfat/source/directory.h @@ -57,6 +57,9 @@ #define ATTRIB_HID 0x02 // Hidden #define ATTRIB_RO 0x01 // Read only +#define CASE_LOWER_EXT 0x10 // WinNT lowercase extension +#define CASE_LOWER_BASE 0x08 // WinNT lowercase basename + typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE; typedef struct { @@ -77,7 +80,7 @@ enum DIR_ENTRY_offset { DIR_ENTRY_name = 0x00, DIR_ENTRY_extension = 0x08, DIR_ENTRY_attributes = 0x0B, - DIR_ENTRY_reserved = 0x0C, + DIR_ENTRY_caseInfo = 0x0C, DIR_ENTRY_cTime_ms = 0x0D, DIR_ENTRY_cTime = 0x0E, DIR_ENTRY_cDate = 0x10, diff --git a/libcustomfat/disc.c b/libcustomfat/source/disc.c similarity index 100% rename from libcustomfat/disc.c rename to libcustomfat/source/disc.c diff --git a/libcustomfat/disc.h b/libcustomfat/source/disc.h similarity index 100% rename from libcustomfat/disc.h rename to libcustomfat/source/disc.h diff --git a/libcustomfat/fatdir.c b/libcustomfat/source/fatdir.c similarity index 98% rename from libcustomfat/fatdir.c rename to libcustomfat/source/fatdir.c index 52a6fb51..fe0e781e 100644 --- a/libcustomfat/fatdir.c +++ b/libcustomfat/source/fatdir.c @@ -465,16 +465,16 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) _FAT_lock(&partition->lock); - if(memcmp(&buf->f_flag, "SCAN", 4) == 0) - { - //Special command was given to sync the numberFreeCluster - _FAT_partition_createFSinfo(partition); - } + if(memcmp(&buf->f_flag, "SCAN", 4) == 0) + { + //Special command was given to sync the numberFreeCluster + _FAT_partition_createFSinfo(partition); + } - if(partition->filesysType == FS_FAT32) - freeClusterCount = partition->fat.numberFreeCluster; - else - freeClusterCount = _FAT_fat_freeClusterCount (partition); + if(partition->filesysType == FS_FAT32) + freeClusterCount = partition->fat.numberFreeCluster; + else + freeClusterCount = _FAT_fat_freeClusterCount (partition); // FAT clusters = POSIX blocks buf->f_bsize = partition->bytesPerCluster; // File system block size. diff --git a/libcustomfat/fatdir.h b/libcustomfat/source/fatdir.h similarity index 100% rename from libcustomfat/fatdir.h rename to libcustomfat/source/fatdir.h diff --git a/libcustomfat/fatfile.c b/libcustomfat/source/fatfile.c similarity index 97% rename from libcustomfat/fatfile.c rename to libcustomfat/source/fatfile.c index e2a99f6a..f1e6d43e 100644 --- a/libcustomfat/fatfile.c +++ b/libcustomfat/source/fatfile.c @@ -45,6 +45,37 @@ #include "filetime.h" #include "lock.h" +bool _FAT_findEntry(const char *path, DIR_ENTRY *dirEntry) { + PARTITION *partition = _FAT_partition_getPartitionFromPath(path); + + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) { + path = strchr (path, ':') + 1; + } + if (strchr (path, ':') != NULL) { + return false; + } + + // Search for the file on the disc + return _FAT_directory_entryFromPath (partition, dirEntry, path, NULL); + +} + +int FAT_getAttr(const char *file) { + DIR_ENTRY dirEntry; + if (!_FAT_findEntry(file,&dirEntry)) return -1; + + return dirEntry.entryData[DIR_ENTRY_attributes]; +} + +int FAT_setAttr(const char *file, int attr) { + DIR_ENTRY dirEntry; + if (!_FAT_findEntry(file,&dirEntry)) return -1; + + return 0; +} + + int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { PARTITION* partition = NULL; bool fileExists; diff --git a/libcustomfat/fatfile.h b/libcustomfat/source/fatfile.h similarity index 100% rename from libcustomfat/fatfile.h rename to libcustomfat/source/fatfile.h diff --git a/libcustomfat/fatfile_frag.c b/libcustomfat/source/fatfile_frag.c similarity index 100% rename from libcustomfat/fatfile_frag.c rename to libcustomfat/source/fatfile_frag.c diff --git a/libcustomfat/fatfile_frag.h b/libcustomfat/source/fatfile_frag.h similarity index 100% rename from libcustomfat/fatfile_frag.h rename to libcustomfat/source/fatfile_frag.h diff --git a/libcustomfat/file_allocation_table.c b/libcustomfat/source/file_allocation_table.c similarity index 97% rename from libcustomfat/file_allocation_table.c rename to libcustomfat/source/file_allocation_table.c index 9a3cc884..72f8aa74 100644 --- a/libcustomfat/file_allocation_table.c +++ b/libcustomfat/source/file_allocation_table.c @@ -247,7 +247,7 @@ uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) { } partition->fat.firstFree = firstFree; if(partition->fat.numberFreeCluster) - partition->fat.numberFreeCluster--; + partition->fat.numberFreeCluster--; partition->fat.numberLastAllocCluster = firstFree; if ((cluster >= CLUSTER_FIRST) && (cluster <= lastCluster)) @@ -279,7 +279,7 @@ uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster return CLUSTER_ERROR; } - emptySector = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); + emptySector = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); // Clear all the sectors within the cluster memset (emptySector, 0, partition->bytesPerSector); @@ -317,8 +317,8 @@ bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) { // Erase the link _FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE); - if(partition->fat.numberFreeCluster < (partition->numberOfSectors/partition->sectorsPerCluster)) - partition->fat.numberFreeCluster++; + if(partition->fat.numberFreeCluster < (partition->numberOfSectors/partition->sectorsPerCluster)) + partition->fat.numberFreeCluster++; // Move onto next cluster cluster = nextCluster; } diff --git a/libcustomfat/file_allocation_table.h b/libcustomfat/source/file_allocation_table.h similarity index 100% rename from libcustomfat/file_allocation_table.h rename to libcustomfat/source/file_allocation_table.h diff --git a/libcustomfat/filetime.c b/libcustomfat/source/filetime.c similarity index 100% rename from libcustomfat/filetime.c rename to libcustomfat/source/filetime.c diff --git a/libcustomfat/filetime.h b/libcustomfat/source/filetime.h similarity index 100% rename from libcustomfat/filetime.h rename to libcustomfat/source/filetime.h diff --git a/libcustomfat/libfat.c b/libcustomfat/source/libfat.c similarity index 100% rename from libcustomfat/libfat.c rename to libcustomfat/source/libfat.c diff --git a/libcustomfat/lock.c b/libcustomfat/source/lock.c similarity index 100% rename from libcustomfat/lock.c rename to libcustomfat/source/lock.c diff --git a/libcustomfat/lock.h b/libcustomfat/source/lock.h similarity index 100% rename from libcustomfat/lock.h rename to libcustomfat/source/lock.h diff --git a/libcustomfat/mem2.h b/libcustomfat/source/mem2.h similarity index 100% rename from libcustomfat/mem2.h rename to libcustomfat/source/mem2.h diff --git a/libcustomfat/mem_allocate.h b/libcustomfat/source/mem_allocate.h similarity index 100% rename from libcustomfat/mem_allocate.h rename to libcustomfat/source/mem_allocate.h diff --git a/libcustomfat/partition.c b/libcustomfat/source/partition.c similarity index 72% rename from libcustomfat/partition.c rename to libcustomfat/source/partition.c index 41b9d761..9d220413 100644 --- a/libcustomfat/partition.c +++ b/libcustomfat/source/partition.c @@ -38,8 +38,6 @@ #include #include -sec_t _FAT_startSector; - /* Data offsets */ @@ -93,10 +91,10 @@ enum BPB { // File system information block offsets enum FSIB { - FSIB_SIG1 = 0x00, - FSIB_SIG2 = 0x1e4, - FSIB_numberOfFreeCluster = 0x1e8, - FSIB_numberLastAllocCluster = 0x1ec, + FSIB_SIG1 = 0x00, + FSIB_SIG2 = 0x1e4, + FSIB_numberOfFreeCluster = 0x1e8, + FSIB_numberLastAllocCluster = 0x1ec, FSIB_bootSig_55 = 0x1FE, FSIB_bootSig_AA = 0x1FF }; @@ -105,20 +103,14 @@ static const char FAT_SIG[3] = {'F', 'A', 'T'}; static const char FS_INFO_SIG1[4] = {'R', 'R', 'a', 'A'}; static const char FS_INFO_SIG2[4] = {'r', 'r', 'A', 'a'}; -sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) +sec_t FindFirstValidPartition_buf(const DISC_INTERFACE* disc, uint8_t *sectorBuffer) { uint8_t part_table[16*4]; uint8_t *ptr; int i; - uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_allocate(MAX_SECTOR_SIZE); - if(!sectorBuffer) { - return 0; - } - // Read first sector of disc if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); return 0; } @@ -130,7 +122,6 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { - _FAT_mem_free(sectorBuffer); return part_lba; } @@ -143,61 +134,53 @@ sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) for(n=0;n<8;n++) // max 8 logic partitions { - if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); - return 0; - } + if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0; part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ; next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6); - if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); - return 0; - } + if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) return 0; if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || - !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { - _FAT_mem_free(sectorBuffer); + !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) + { return part_lba2; } if(next_lba2==0) break; } } else { - if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); - return 0; - } + if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) return 0; if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { - _FAT_mem_free(sectorBuffer); return part_lba; } } } - _FAT_mem_free(sectorBuffer); return 0; } +sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) +{ + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE); + if (!sectorBuffer) return 0; + sec_t ret = FindFirstValidPartition_buf(disc, sectorBuffer); + _FAT_mem_free(sectorBuffer); + return ret; +} -PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) { + +PARTITION* _FAT_partition_constructor_buf (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector, uint8_t *sectorBuffer) +{ PARTITION* partition; - uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_allocate(MAX_SECTOR_SIZE); - if(!sectorBuffer) { - return NULL; - } - // Read first sector of disc if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); return NULL; } // Make sure it is a valid MBR or boot sector if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) { - _FAT_mem_free(sectorBuffer); return NULL; } @@ -210,25 +193,21 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach // Check for FAT32 startSector = 0; } else { - startSector = FindFirstValidPartition(disc); + startSector = FindFirstValidPartition_buf(disc, sectorBuffer); if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); return NULL; } } - _FAT_startSector = startSector; - // Now verify that this is indeed a FAT partition if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) && - memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { - _FAT_mem_free(sectorBuffer); + memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) + { return NULL; } partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION)); if (partition == NULL) { - _FAT_mem_free(sectorBuffer); return NULL; } @@ -255,19 +234,14 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors); } - if(disc->features & FEATURE_WII_USB) - partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector); - else - partition->bytesPerSector = MIN_SECTOR_SIZE; - + partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector); if(partition->bytesPerSector < MIN_SECTOR_SIZE || partition->bytesPerSector > MAX_SECTOR_SIZE) { - // Unsupported sector size - _FAT_mem_free(sectorBuffer); - _FAT_mem_free(partition); - return NULL; - } + // Unsupported sector size + _FAT_mem_free(partition); + return NULL; + } - partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16(sectorBuffer, BPB_bytesPerSector) / partition->bytesPerSector; + partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster]; partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster; partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors); @@ -277,14 +251,14 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector; - //FS info sector - partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1); + //FS info sector + partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1); // Store info about FAT uint32_t clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster; partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1; partition->fat.firstFree = CLUSTER_FIRST; - partition->fat.numberFreeCluster = 0; + partition->fat.numberFreeCluster = 0; partition->fat.numberLastAllocCluster = 0; if (clusterCount < CLUSTERS_PER_FAT12) { @@ -322,11 +296,20 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach _FAT_partition_readFSinfo(partition); - _FAT_mem_free(sectorBuffer); - return partition; } +PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) +{ + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE); + if (!sectorBuffer) return NULL; + PARTITION *ret = _FAT_partition_constructor_buf(disc, cacheSize, + sectorsPerPage, startSector, sectorBuffer); + _FAT_mem_free(sectorBuffer); + return ret; +} + + void _FAT_partition_destructor (PARTITION* partition) { FILE_STRUCT* nextFile; @@ -339,8 +322,8 @@ void _FAT_partition_destructor (PARTITION* partition) { nextFile = nextFile->nextOpenFile; } - // Write out the fs info sector - _FAT_partition_writeFSinfo(partition); + // Write out the fs info sector + _FAT_partition_writeFSinfo(partition); // Free memory used by the cache, writing it to disc at the same time _FAT_cache_destructor (partition->cache); @@ -367,89 +350,82 @@ PARTITION* _FAT_partition_getPartitionFromPath (const char* path) { void _FAT_partition_createFSinfo(PARTITION * partition) { - if(partition->readOnly || partition->filesysType != FS_FAT32) - return; + if(partition->readOnly || partition->filesysType != FS_FAT32) + return; - uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); - if(!sectorBuffer) { - return; + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); + + int i; + for(i = 0; i < 4; ++i) + { + sectorBuffer[FSIB_SIG1+i] = FS_INFO_SIG1[i]; + sectorBuffer[FSIB_SIG2+i] = FS_INFO_SIG2[i]; } - memset(sectorBuffer, 0, partition->bytesPerSector); - int i; - for(i = 0; i < 4; ++i) - { - sectorBuffer[FSIB_SIG1+i] = FS_INFO_SIG1[i]; - sectorBuffer[FSIB_SIG2+i] = FS_INFO_SIG2[i]; - } + partition->fat.numberFreeCluster = _FAT_fat_freeClusterCount(partition); + u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); + u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); - partition->fat.numberFreeCluster = _FAT_fat_freeClusterCount(partition); - u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); - u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); + sectorBuffer[FSIB_bootSig_55] = 0x55; + sectorBuffer[FSIB_bootSig_AA] = 0xAA; - sectorBuffer[FSIB_bootSig_55] = 0x55; - sectorBuffer[FSIB_bootSig_AA] = 0xAA; + _FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer); - _FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer); - - _FAT_mem_free(sectorBuffer); + _FAT_mem_free(sectorBuffer); } void _FAT_partition_readFSinfo(PARTITION * partition) { - if(partition->filesysType != FS_FAT32) - return; + if(partition->filesysType != FS_FAT32) + return; - uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); - if(!sectorBuffer) { - return; - } - memset(sectorBuffer, 0, partition->bytesPerSector); + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); // Read first sector of disc if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); + _FAT_mem_free(sectorBuffer); return; } - if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 || - memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 || - u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0) { - //sector does not yet exist, create one! - _FAT_partition_createFSinfo(partition); - _FAT_mem_free(sectorBuffer); - return; - } - - partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); - partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster); - _FAT_mem_free(sectorBuffer); + if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 || + memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 || + u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0) + { + //sector does not yet exist, create one! + _FAT_partition_createFSinfo(partition); + } else { + partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); + partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster); + } + _FAT_mem_free(sectorBuffer); } void _FAT_partition_writeFSinfo(PARTITION * partition) { - if(partition->filesysType != FS_FAT32) - return; + if(partition->filesysType != FS_FAT32) + return; - uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector); - if(!sectorBuffer) { - return; - } - memset(sectorBuffer, 0, partition->bytesPerSector); + uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); + if (!sectorBuffer) return; + memset(sectorBuffer, 0, partition->bytesPerSector); // Read first sector of disc if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer)) { - _FAT_mem_free(sectorBuffer); + _FAT_mem_free(sectorBuffer); return; } if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) || memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4)) { - _FAT_mem_free(sectorBuffer); - return; + _FAT_mem_free(sectorBuffer); + return; } - u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); - u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); + u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster); + u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster); - // Read first sector of disc + // Write first sector of disc _FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer); _FAT_mem_free(sectorBuffer); } diff --git a/libcustomfat/partition.h b/libcustomfat/source/partition.h similarity index 100% rename from libcustomfat/partition.h rename to libcustomfat/source/partition.h diff --git a/libcustomntfs/AUTHORS b/libcustomntfs/AUTHORS new file mode 100644 index 00000000..b0ae639f --- /dev/null +++ b/libcustomntfs/AUTHORS @@ -0,0 +1,27 @@ + +Present authors of ntfs-3g in alphabetical order: + +Jean-Pierre Andre +Alon Bar-Lev +Dominique L Bouix +Csaba Henk +Bernhard Kaindl +Erik Larsson +Alejandro Pulver +Szabolcs Szakacsits +Miklos Szeredi + + +Past authors in alphabetical order: + +Anton Altaparmakov +Mario Emmenlauer +Yuval Fledel +Yura Pakhuchiy +Richard Russon + + +Nintendo GameCube/Wii port authors in alphabetical order: + +Rhys "Shareese" Koedijk +Dimok diff --git a/libcustomntfs/CREDITS b/libcustomntfs/CREDITS new file mode 100644 index 00000000..3c1bc7c3 --- /dev/null +++ b/libcustomntfs/CREDITS @@ -0,0 +1,50 @@ +The following people have contributed directly or indirectly +to the ntfs-3g project. + +Please let ntfs-3g-devel@lists.sf.net know if you believe +someone is missing, or if you prefer not to be listed. + +Dominique L Bouix +Csaba Henk +Max Khon +Auri Hautam�ki +Gergely Erdelyi +Anton Altaparmakov +Peter Boross +Don Bright +Mario Emmenlauer +Yuval Fledel +Kano from Kanotix +Roland Kletzing +Maarten Lankhorst +Gergely Madarasz +Patrick McLean +Florent Mertens +Yura Pakhuchiy +Miklos Szeredi +Bartosz Taudul +Zhanglinbao +Wade Fitzpatrick +Carsten Einig +Adam Cecile +Bruno Damour +Ales Fruman +Curt McDowell +Thomas Franken +Jonatan Lambert +Klaus Knopper +Zhanglinbao +Ismail Donmez +Laszlo Dvornik +Pallaghy Ajtony +Szabolcs Szakacsits +Jean-Pierre Andre +Alejandro Pulver +Erik Larsson +Alon Bar-Lev + +The following people have contributed directly or indirectly +to the Nintendo GameCube/Wii port of ntfs-3g. + +Michael "Chishm" Chisholm +rodries diff --git a/libcustomntfs/LICENSE b/libcustomntfs/LICENSE new file mode 100644 index 00000000..623b6258 --- /dev/null +++ b/libcustomntfs/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/libcustomntfs/Makefile b/libcustomntfs/Makefile index cad3aa6b..8745416d 100644 --- a/libcustomntfs/Makefile +++ b/libcustomntfs/Makefile @@ -1,32 +1,31 @@ -# Quick'n'dirty makefile [BC] v2 -ifeq ($(strip $(DEVKITPPC)),) -$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") -endif +default: cube-release wii-release -include $(DEVKITPPC)/wii_rules +all: debug release -LIBOGC_INC := $(DEVKITPRO)/libogc/include -LIBOGC_LIB := $(DEVKITPRO)/libogc/lib/wii +debug: cube-debug wii-debug -CFLAGS := -O3 $(MACHDEP) -I$(LIBOGC_INC) -DHAVE_CONFIG_H +release: cube-release wii-release -LIB := ntfs -CFILES := $(wildcard *.c) -OFILES := $(CFILES:.c=.o) -ARC := lib$(LIB).a -HDR := ntfs.h +cube-debug: + $(MAKE) -C source PLATFORM=cube BUILD=cube_debug -all : $(OFILES) - $(AR) -r $(ARC) $(OFILES) +wii-debug: + $(MAKE) -C source PLATFORM=wii BUILD=wii_debug -clean : - rm -f $(OFILES) $(ARC) +cube-release: + $(MAKE) -C source PLATFORM=cube BUILD=cube_release -install : - mkdir -p $(LIBOGC_LIB) $(LIBOGC_INC) - cp -f $(ARC) $(LIBOGC_LIB)/ - cp -f $(HDR) $(LIBOGC_INC)/ +wii-release: + $(MAKE) -C source PLATFORM=wii BUILD=wii_release + +clean: + $(MAKE) -C source clean + +install: cube-release wii-release + $(MAKE) -C source install + +run: install + $(MAKE) -C example + $(MAKE) -C example run -%.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ \ No newline at end of file diff --git a/libcustomntfs/READMII b/libcustomntfs/READMII new file mode 100644 index 00000000..ca8f1abe --- /dev/null +++ b/libcustomntfs/READMII @@ -0,0 +1,54 @@ + +INTRODUCTION +============ + +The NTFS-3G driver is an open source, freely available read/write NTFS driver +for Linux, FreeBSD, Mac OS X, NetBSD, Solaris and Haiku. It provides safe and +fast handling of the Windows XP, Windows Server 2003, Windows 2000, Windows +Vista, and Windows Server 2008 file systems. + +The purpose of the project is to develop, continuously quality test and +support a trustable, featureful and high performance solution for hardware +platforms and operating systems whose users need to reliably interoperate +with NTFS. Besides this practical goal, the project also aims to explore +the limits of the hybrid, kernel/user space filesystem driver approach, +performance, reliability and feature richness per invested effort wise. + +The driver is in STABLE status. The test methods, the test suites used +can be found at + + http://ntfs-3g.org/quality.html + +News, support answers, problem submission instructions, support and discussion +forums, performance numbers and other information are available on the project +web site at + + http://ntfs-3g.org + +For more details on the NTFS-3G project see the 'original' folder included +with this package. + +COMPILING AND INSTALLATION +========================== + +Make sure you have devKitPPC and the latest libogc installed. Then type: + + make + make install # or 'sudo make install' if you aren't root. + + +USAGE +===== + +NTFS related routines can be accessed by adding the following line to your +source file(s). + + #include + +When compiling you must also link against the libntfs. To do this add -lntfs +to the LIBS section of your application Makefile. For example: + + LIBS := -lwiiuse -lbte -lntfs -lfat -logc -lm + +For a more practical example of using NTFS in your application, +see the included 'example' folder. diff --git a/libcustomntfs/include/ntfs.h b/libcustomntfs/include/ntfs.h new file mode 100644 index 00000000..62f2f719 --- /dev/null +++ b/libcustomntfs/include/ntfs.h @@ -0,0 +1,148 @@ +/** + * ntfs.h - Simple functionality for startup, mounting and unmounting of NTFS-based devices. + * + * Copyright (c) 2010 Dimok + * 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_IGNORE_CASE 0x00000040 /* Ignore case sensitivity. Everything must be and will be provided in lowercase. */ +#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 */ diff --git a/libcustomntfs/source/Makefile b/libcustomntfs/source/Makefile new file mode 100644 index 00000000..f922254d --- /dev/null +++ b/libcustomntfs/source/Makefile @@ -0,0 +1,130 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +ifeq ($(PLATFORM),wii) +include $(DEVKITPPC)/wii_rules +endif + +ifeq ($(PLATFORM),cube) +include $(DEVKITPPC)/gamecube_rules +endif + +#--------------------------------------------------------------------------------- +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +BUILD ?= wii_release +SOURCES := . +INCLUDES := ../include +LIBDIR := ../lib + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS = -O2 -Wall -ffast-math -pipe $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H +CXXFLAGS = $(CFLAGS) +ASFLAGS := -g +export NTFSBIN := $(LIBDIR)/$(PLATFORM)/libntfs.a + +ifeq ($(BUILD),cube_debug) +CFLAGS += -DDEBUG +CXXFLAGS += -DDEBUG +endif +ifeq ($(BUILD),wii_debug) +CFLAGS += -DDEBUG +CXXFLAGS += -DDEBUG +endif + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr wii_debug wii_release cube_debug cube_release $(LIBDIR) + +all: $(NTFSBIN) + +install: + cp ../include/ntfs.h $(DEVKITPRO)/libogc/include + cp ../lib/wii/libntfs.a $(DEVKITPRO)/libogc/lib/wii + cp ../lib/cube/libntfs.a $(DEVKITPRO)/libogc/lib/cube + +wii-install: + cp ../include/ntfs.h $(DEVKITPRO)/libogc/include + cp ../lib/wii/libntfs.a $(DEVKITPRO)/libogc/lib/wii + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(NTFSBIN): $(OFILES) $(LIBDIR)/$(PLATFORM) + @rm -f "../$(NTFSBIN)" + @$(AR) rcs "../$(NTFSBIN)" $(OFILES) + @echo built ... $(notdir $@) + +$(LIBDIR)/$(PLATFORM): + mkdir -p ../$(LIBDIR)/$(PLATFORM) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- + diff --git a/libcustomntfs/acls.c b/libcustomntfs/source/acls.c similarity index 99% rename from libcustomntfs/acls.c rename to libcustomntfs/source/acls.c index 2a58eeaf..070d7575 100644 --- a/libcustomntfs/acls.c +++ b/libcustomntfs/source/acls.c @@ -522,9 +522,7 @@ gid_t ntfs_find_group(const struct MAPPING* groupmapping, const SID * gsid) { gid_t gid; const struct MAPPING *p; - int gsidsz; - gsidsz = ntfs_sid_size(gsid); p = groupmapping; while (p && p->xid && !ntfs_same_sid(gsid, p->sid)) p = p->next; @@ -880,7 +878,7 @@ BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc) } } if ((pxdesc->acccnt > 0) - && ((checks[0].owners != 1) || (checks[0].groups != 1) + && ((checks[0].owners != 1) || (checks[0].groups != 1) || (checks[0].others != 1))) ok = FALSE; /* do not check owner, group or other are present in */ @@ -1806,7 +1804,7 @@ static BOOL build_group_denials_grant(ACL *pacl, * - grants to owner (always present - first grant) * + grants to designated user * + mask denial to group (unless mask allows all) - * - denials to group (preventing grants to world to apply) + * - denials to group (preventing grants to world to apply) * - grants to group (unless group has no more than world rights) * + mask denials to designated group (unless mask allows all) * + grants to designated group @@ -1901,7 +1899,6 @@ static int buildacls_posix(struct MAPPING* const mapping[], const SID *sid; int acecnt; int usidsz; - int gsidsz; int wsidsz; int asidsz; int ssidsz; @@ -1909,7 +1906,6 @@ static int buildacls_posix(struct MAPPING* const mapping[], le32 grants; usidsz = ntfs_sid_size(usid); - gsidsz = ntfs_sid_size(gsid); wsidsz = ntfs_sid_size(worldsid); asidsz = ntfs_sid_size(adminsid); ssidsz = ntfs_sid_size(systemsid); @@ -3132,7 +3128,6 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc, u16 tag; u16 tagsset; struct POSIX_ACE *pxace; - int acccnt; mode_t denywrld; mode_t allow; mode_t deny; @@ -3141,7 +3136,6 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc, mode = 0; pxace = posix_desc->acl.ace; - acccnt = posix_desc->acccnt; tagsset = 0; denywrld = 0; /* @@ -3881,12 +3875,10 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix( int ntfs_build_permissions(const char *securattr, const SID *usid, const SID *gsid, BOOL isdir) { - const SECURITY_DESCRIPTOR_RELATIVE *phead; int perm; BOOL adminowns; BOOL groupowns; - phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr; adminowns = ntfs_same_sid(usid,adminsid) || ntfs_same_sid(gsid,adminsid); groupowns = !adminowns && ntfs_same_sid(gsid,usid); @@ -3969,7 +3961,6 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid, { int src; int dst; - char *p; char *q; char *pu; char *pg; @@ -4003,7 +3994,6 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid, if (gotend) { pu = pg = (char*)NULL; /* decompose into uid, gid and sid */ - p = item->maptext; item->uidstr = item->maptext; item->gidstr = strchr(item->uidstr, ':'); if (item->gidstr) { diff --git a/libcustomntfs/acls.h b/libcustomntfs/source/acls.h similarity index 100% rename from libcustomntfs/acls.h rename to libcustomntfs/source/acls.h diff --git a/libcustomntfs/attrib.c b/libcustomntfs/source/attrib.c similarity index 99% rename from libcustomntfs/attrib.c rename to libcustomntfs/source/attrib.c index e6f614f0..281a6205 100644 --- a/libcustomntfs/attrib.c +++ b/libcustomntfs/source/attrib.c @@ -475,9 +475,10 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, } cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); - + + /* a file may be sparse though its unnamed data is not (cf $UsnJrnl) */ if (na->type == AT_DATA && na->name == AT_UNNAMED && - ((!(a->flags & ATTR_IS_SPARSE) != !NAttrSparse(na)) || + (((a->flags & ATTR_IS_SPARSE) && !NAttrSparse(na)) || (!(a->flags & ATTR_IS_ENCRYPTED) != !NAttrEncrypted(na)))) { errno = EIO; ntfs_log_perror("Inode %lld has corrupt attribute flags " @@ -1774,7 +1775,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) } need_to = { 0, 0 }; BOOL wasnonresident = FALSE; BOOL compressed; - BOOL sparse; BOOL updatemap; ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count " @@ -1850,7 +1850,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) goto errno_set; } #else - if (ntfs_attr_truncate(na, pos + count)) { + if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) { ntfs_log_perror("Failed to enlarge attribute"); goto errno_set; } @@ -1860,7 +1860,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) != const_cpu_to_le16(0); need_to.undo_data_size = 1; } - sparse = (na->data_flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0); /* * For compressed data, a single full block was allocated * to deal with compression, possibly in a previous call. @@ -2221,7 +2220,7 @@ done: updatemap = (compressed ? NAttrFullyMapped(na) != 0 : update_from != -1); #endif - if (updatemap) + if (updatemap) { if (ntfs_attr_update_mapping_pairs(na, (update_from < 0 ? 0 : update_from))) { /* @@ -2231,6 +2230,10 @@ done: total = -1; goto out; } + if (!wasnonresident) + NAttrClearBeingNonResident(na); + NAttrClearDataAppending(na); + } out: ntfs_log_leave("\n"); return total; @@ -2292,7 +2295,8 @@ err_out: if (updatemap) ntfs_attr_update_mapping_pairs(na, 0); /* Restore original data_size if needed. */ - if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) + if (need_to.undo_data_size + && ntfs_attr_truncate_i(na, old_data_size, HOLES_OK)) ntfs_log_perror("Failed to restore data_size"); errno = eo; errno_set: @@ -2310,7 +2314,6 @@ int ntfs_attr_pclose(ntfs_attr *na) ntfs_attr_search_ctx *ctx = NULL; runlist_element *rl; int eo; - s64 hole; int compressed_part; BOOL compressed; @@ -2422,7 +2425,6 @@ int ntfs_attr_pclose(ntfs_attr *na) goto rl_err_out; } if (rl->lcn < (LCN)0) { - hole = rl->vcn + rl->length; if (rl->lcn != (LCN)LCN_HOLE) { errno = EIO; ntfs_log_perror("%s: Unexpected LCN (%lld)", @@ -2475,6 +2477,7 @@ retry: goto out; } out: + NAttrClearComprClosing(na); ntfs_log_leave("\n"); return (!ok); rl_err_out: @@ -2531,6 +2534,7 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, { s64 br; u8 *end; + BOOL warn; ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, @@ -2544,9 +2548,11 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, if (br <= 0) return br; br /= bk_size; + /* log errors unless silenced */ + warn = !na->ni || !na->ni->vol || !NVolNoFixupWarn(na->ni->vol); for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst + bk_size) - ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size); + ntfs_mst_post_read_fixup_warn((NTFS_RECORD*)dst, bk_size, warn); /* Finally, return the number of blocks read. */ return br; } @@ -3544,6 +3550,14 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, min_size = sle64_to_cpu(ad->min_size); max_size = sle64_to_cpu(ad->max_size); + + /* The $AttrDef generated by Windows specifies 2 as min_size for the + * volume name attribute, but in reality Windows sets it to 0 when + * clearing the volume name. If we want to be able to clear the volume + * name we must also accept 0 as min_size, despite the $AttrDef + * definition. */ + if(type == AT_VOLUME_NAME) + min_size = 0; if ((min_size && (size < min_size)) || ((max_size > 0) && (size > max_size))) { @@ -4296,7 +4310,7 @@ add_non_resident: goto rm_attr_err_out; } /* Resize and set attribute value. */ - if (ntfs_attr_truncate(na, size) || + if (ntfs_attr_truncate_i(na, size, HOLES_OK) || (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) { err = errno; ntfs_log_perror("Failed to initialize just added attribute"); @@ -4877,6 +4891,7 @@ cluster_free_err_out: ntfs_log_trace("Eeek! Failed to release allocated clusters in error " "code path. Leaving inconsistent metadata...\n"); NAttrClearNonResident(na); + NAttrClearFullyMapped(na); na->allocated_size = na->data_size; na->rl = NULL; free(rl); @@ -5000,7 +5015,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize, return (ret); } /* Resize non-resident attribute */ - return ntfs_attr_truncate(na, newsize); + return ntfs_attr_truncate_i(na, newsize, HOLES_OK); } else if (errno != ENOSPC && errno != EPERM) { err = errno; ntfs_log_perror("Failed to make attribute non-resident"); @@ -5348,7 +5363,6 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) * record is in a transiently corrupted state at this moment in time. */ if (ntfs_cluster_free(vol, na, 0, -1) < 0) { - err = errno; ntfs_log_perror("Eeek! Failed to release allocated clusters"); ntfs_log_trace("Ignoring error and leaving behind wasted " "clusters.\n"); @@ -5360,6 +5374,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) /* Update in-memory struct ntfs_attr. */ NAttrClearNonResident(na); + NAttrClearFullyMapped(na); NAttrClearSparse(na); NAttrClearEncrypted(na); na->initialized_size = na->data_size; @@ -5453,6 +5468,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m, NAttrClearSparse(na); a->flags &= ~ATTR_IS_SPARSE; + na->data_flags = a->flags; a->compression_unit = 0; memmove((u8*)a + le16_to_cpu(a->name_offset) - 8, @@ -6422,7 +6438,12 @@ out: int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) { - return (ntfs_attr_truncate_i(na, newsize, HOLES_OK)); + int r; + + r = ntfs_attr_truncate_i(na, newsize, HOLES_OK); + NAttrClearDataAppending(na); + NAttrClearBeingNonResident(na); + return (r); } /* diff --git a/libcustomntfs/attrib.h b/libcustomntfs/source/attrib.h similarity index 100% rename from libcustomntfs/attrib.h rename to libcustomntfs/source/attrib.h diff --git a/libcustomntfs/attrib_frag.c b/libcustomntfs/source/attrib_frag.c similarity index 100% rename from libcustomntfs/attrib_frag.c rename to libcustomntfs/source/attrib_frag.c diff --git a/libcustomntfs/attrlist.c b/libcustomntfs/source/attrlist.c similarity index 100% rename from libcustomntfs/attrlist.c rename to libcustomntfs/source/attrlist.c diff --git a/libcustomntfs/attrlist.h b/libcustomntfs/source/attrlist.h similarity index 100% rename from libcustomntfs/attrlist.h rename to libcustomntfs/source/attrlist.h diff --git a/libcustomntfs/bit_ops.h b/libcustomntfs/source/bit_ops.h similarity index 100% rename from libcustomntfs/bit_ops.h rename to libcustomntfs/source/bit_ops.h diff --git a/libcustomntfs/bitmap.c b/libcustomntfs/source/bitmap.c similarity index 100% rename from libcustomntfs/bitmap.c rename to libcustomntfs/source/bitmap.c diff --git a/libcustomntfs/bitmap.h b/libcustomntfs/source/bitmap.h similarity index 100% rename from libcustomntfs/bitmap.h rename to libcustomntfs/source/bitmap.h diff --git a/libcustomntfs/bootsect.c b/libcustomntfs/source/bootsect.c similarity index 100% rename from libcustomntfs/bootsect.c rename to libcustomntfs/source/bootsect.c diff --git a/libcustomntfs/bootsect.h b/libcustomntfs/source/bootsect.h similarity index 100% rename from libcustomntfs/bootsect.h rename to libcustomntfs/source/bootsect.h diff --git a/libcustomntfs/cache.c b/libcustomntfs/source/cache.c similarity index 99% rename from libcustomntfs/cache.c rename to libcustomntfs/source/cache.c index b1ae2915..faabe628 100644 --- a/libcustomntfs/cache.c +++ b/libcustomntfs/source/cache.c @@ -376,7 +376,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache, int flags) { struct CACHED_GENERIC *current; - struct CACHED_GENERIC *previous; struct CACHED_GENERIC *next; struct HASH_ENTRY *link; int count; @@ -412,7 +411,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache, * Search sequentially in LRU list */ current = cache->most_recent_entry; - previous = (struct CACHED_GENERIC*)NULL; while (current) { if (!compare(current, item)) { next = current->next; @@ -423,7 +421,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache, current = next; count++; } else { - previous = current; current = current->next; } } diff --git a/libcustomntfs/cache.h b/libcustomntfs/source/cache.h similarity index 100% rename from libcustomntfs/cache.h rename to libcustomntfs/source/cache.h diff --git a/libcustomntfs/cache2.c b/libcustomntfs/source/cache2.c similarity index 100% rename from libcustomntfs/cache2.c rename to libcustomntfs/source/cache2.c diff --git a/libcustomntfs/cache2.h b/libcustomntfs/source/cache2.h similarity index 100% rename from libcustomntfs/cache2.h rename to libcustomntfs/source/cache2.h diff --git a/libcustomntfs/collate.c b/libcustomntfs/source/collate.c similarity index 100% rename from libcustomntfs/collate.c rename to libcustomntfs/source/collate.c diff --git a/libcustomntfs/collate.h b/libcustomntfs/source/collate.h similarity index 100% rename from libcustomntfs/collate.h rename to libcustomntfs/source/collate.h diff --git a/libcustomntfs/compat.c b/libcustomntfs/source/compat.c similarity index 100% rename from libcustomntfs/compat.c rename to libcustomntfs/source/compat.c diff --git a/libcustomntfs/compat.h b/libcustomntfs/source/compat.h similarity index 100% rename from libcustomntfs/compat.h rename to libcustomntfs/source/compat.h diff --git a/libcustomntfs/compress.c b/libcustomntfs/source/compress.c similarity index 88% rename from libcustomntfs/compress.c rename to libcustomntfs/source/compress.c index 73d493e1..aeb082d5 100644 --- a/libcustomntfs/compress.c +++ b/libcustomntfs/source/compress.c @@ -28,7 +28,7 @@ * this was put into public domain in 1988 by Haruhiko OKUMURA). * * LZHUF.C English version 1.0 - * Based on Japanese version 29-NOV-1988 + * Based on Japanese version 29-NOV-1988 * LZSS coded by Haruhiko OKUMURA * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI * Edited and translated to English by Kenji RIKITAKE @@ -62,8 +62,8 @@ #include "logging.h" #include "misc.h" -#undef le16_to_cpup -/* the standard le16_to_cpup() crashes for unaligned data on some processors */ +#undef le16_to_cpup +/* the standard le16_to_cpup() crashes for unaligned data on some processors */ #define le16_to_cpup(p) (*(u8*)(p) + (((u8*)(p))[1] << 8)) /** @@ -81,259 +81,215 @@ typedef enum { NTFS_SB_IS_COMPRESSED = 0x8000, } ntfs_compression_constants; -#define THRESHOLD 3 /* minimal match length for compression */ -#define NIL NTFS_SB_SIZE /* End of tree's node */ - struct COMPRESS_CONTEXT { const unsigned char *inbuf; - unsigned int len; - unsigned int nbt; - int match_position; - unsigned int match_length; - u16 lson[NTFS_SB_SIZE + 1]; - u16 rson[NTFS_SB_SIZE + 257]; - u16 dad[NTFS_SB_SIZE + 1]; + int bufsize; + int size; + int rel; + int mxsz; + s16 head[256]; + s16 lson[NTFS_SB_SIZE]; + s16 rson[NTFS_SB_SIZE]; } ; /* - * Initialize the match tree - */ - -static void ntfs_init_compress_tree(struct COMPRESS_CONTEXT *pctx) -{ - int i; - - for (i = NTFS_SB_SIZE + 1; i <= NTFS_SB_SIZE + 256; i++) - pctx->rson[i] = NIL; /* root */ - for (i = 0; i < NTFS_SB_SIZE; i++) - pctx->dad[i] = NIL; /* node */ -} - -/* - * Insert a new node into match tree for quickly locating - * further similar strings - */ - -static void ntfs_new_node (struct COMPRESS_CONTEXT *pctx, - unsigned int r) -{ - unsigned int pp; - BOOL less; - BOOL done; - const unsigned char *key; - int c; - unsigned long mxi; - unsigned int mxl; - - mxl = (1 << (16 - pctx->nbt)) + 2; - less = FALSE; - done = FALSE; - key = &pctx->inbuf[r]; - pp = NTFS_SB_SIZE + 1 + key[0]; - pctx->rson[r] = pctx->lson[r] = NIL; - pctx->match_length = 0; - do { - if (!less) { - if (pctx->rson[pp] != NIL) - pp = pctx->rson[pp]; - else { - pctx->rson[pp] = r; - pctx->dad[r] = pp; - done = TRUE; - } - } else { - if (pctx->lson[pp] != NIL) - pp = pctx->lson[pp]; - else { - pctx->lson[pp] = r; - pctx->dad[r] = pp; - done = TRUE; - } - } - if (!done) { - register unsigned long i; - register const unsigned char *p1,*p2; - - i = 1; - mxi = NTFS_SB_SIZE - r; - if (mxi < 2) - less = FALSE; - else { - p1 = key; - p2 = &pctx->inbuf[pp]; - /* this loop has a significant impact on performances */ - do { - } while ((p1[i] == p2[i]) && (++i < mxi)); - less = (i < mxi) && (p1[i] < p2[i]); - } - if (i >= THRESHOLD) { - if (i > pctx->match_length) { - pctx->match_position = - r - pp + 2*NTFS_SB_SIZE - 1; - if ((pctx->match_length = i) > mxl) { - i = pctx->rson[pp]; - pctx->rson[r] = i; - pctx->dad[i] = r; - i = pctx->lson[pp]; - pctx->lson[r] = i; - pctx->dad[i] = r; - i = pctx->dad[pp]; - pctx->dad[r] = i; - if (pctx->rson[i] == pp) - pctx->rson[i] = r; - else - pctx->lson[i] = r; - /* remove pp */ - pctx->dad[pp] = NIL; - done = TRUE; - pctx->match_length = mxl; - } - } else - if ((i == pctx->match_length) - && ((c = (r - pp + 2*NTFS_SB_SIZE - 1)) - < pctx->match_position)) - pctx->match_position = c; - } - } - } while (!done); -} - -/* - * Search for the longest previous string matching the - * current one + * Search for the longest sequence matching current position * - * Returns the end of the longest current string which matched - * or zero if there was a bug + * A binary tree is maintained to locate all previously met sequences, + * and this function has to be called for all of them. + * + * This function is heavily used, it has to be optimized carefully + * + * Returns the size of the longest match, + * zero if no match is found. */ -static unsigned int ntfs_nextmatch(struct COMPRESS_CONTEXT *pctx, - unsigned int rr, int dd) +static int ntfs_best_match(struct COMPRESS_CONTEXT *pctx, int i) { - unsigned int bestlen = 0; + s16 *prev; + int node; + register long j; + long maxpos; + long startj; + long bestj; + int bufsize; + int bestnode; + register const unsigned char *p1,*p2; - do { - rr++; - if (pctx->match_length > 0) - pctx->match_length--; - if (!pctx->len) { - ntfs_log_error("compress bug : void run\n"); - goto bug; - } - if (--pctx->len) { - if (rr >= NTFS_SB_SIZE) { - ntfs_log_error("compress bug : buffer overflow\n"); - goto bug; - } - if (((rr + bestlen) < NTFS_SB_SIZE)) { - while ((unsigned int)(1 << pctx->nbt) - <= (rr - 1)) - pctx->nbt++; - ntfs_new_node(pctx,rr); - if (pctx->match_length > bestlen) - bestlen = pctx->match_length; - } else - if (dd > 0) { - rr += dd; - if ((int)pctx->match_length > dd) - pctx->match_length -= dd; - else - pctx->match_length = 0; - if ((int)pctx->len < dd) { - ntfs_log_error("compress bug : run overflows\n"); - goto bug; + p1 = pctx->inbuf; + node = pctx->head[p1[i] & 255]; + if (node >= 0) { + /* search the best match at current position */ + bestnode = node; + bufsize = pctx->bufsize; + /* restrict matches to the longest allowed sequence */ + maxpos = bufsize; + if ((i + pctx->mxsz) < maxpos) + maxpos = i + pctx->mxsz; + startj = i + 1 - maxpos; + bestj = startj; + /* make indexes relative to end of allowed position */ + p1 = &p1[maxpos]; + if (startj < 0) { + do { + /* indexes are negative */ + p2 = &p1[node - i]; + /* no need to compare the first byte */ + j = startj; + /* the second byte cannot lead to useful compression */ + if (p1[j] == p2[j]) { + j++; + if (j < 0) { + do { + } while ((p1[j] == p2[j]) + && (++j < 0)); + } + /* remember the match, if better */ + if (j > bestj) { + bestj = j; + bestnode = node; } - pctx->len -= dd; - dd = 0; } + /* walk in the tree in the right direction */ + if ((j < 0) && (p1[j] < p2[j])) + prev = &pctx->lson[node]; + else + prev = &pctx->rson[node]; + node = *prev; + /* stop if reaching a leaf or maximum length */ + } while ((node >= 0) && (j < 0)); + /* put the node into the tree if we reached a leaf */ + if (node < 0) + *prev = i; } - } while (dd-- > 0); - return (rr); -bug : - return (0); + /* done, return the best match */ + pctx->size = bestj + maxpos - i; + pctx->rel = bestnode - i; + } else { + pctx->head[p1[i] & 255] = i; + pctx->size = 0; + pctx->rel = 0; + } + return (pctx->size); } /* - * Compress an input block + * Compress a 4096-byte block * - * Returns the size of the compressed block (including header) - * or zero if there was an error + * Returns a header of two bytes followed by the compressed data. + * If compression is not effective, the header and an uncompressed + * block is returned. + * + * Note : two bytes may be output before output buffer overflow + * is detected, so a 4100-bytes output buffer must be reserved. + * + * Returns the size of the compressed block, including the + * header (minimal size is 2, maximum size is 4098) + * 0 if an error has been met. */ -static unsigned int ntfs_compress_block(const char *inbuf, - unsigned int size, char *outbuf) +static unsigned int ntfs_compress_block(const char *inbuf, int bufsize, + char *outbuf) { struct COMPRESS_CONTEXT *pctx; - char *ptag; - int dd; - unsigned int rr; - unsigned int last_match_length; - unsigned int q; + int i; /* current position */ + int j; /* end of best match from current position */ + int k; /* end of best match from next position */ + int offs; /* offset to best match */ + int n; + int bp; /* bits to store offset */ + int mxoff; /* max match offset : 1 << bp */ + int mxsz2; unsigned int xout; - unsigned int ntag; + unsigned int q; /* aggregated offset and size */ + int done; + char *ptag; /* location reserved for a tag */ + int tag; /* current value of tag */ + int ntag; /* count of bits still undefined in tag */ pctx = (struct COMPRESS_CONTEXT*)ntfs_malloc(sizeof(struct COMPRESS_CONTEXT)); if (pctx) { + for (n=0; nlson[n] = pctx->rson[n] = -1; + for (n=0; n<256; n++) + pctx->head[n] = -1; pctx->inbuf = (const unsigned char*)inbuf; - ntfs_init_compress_tree(pctx); + pctx->bufsize = bufsize; xout = 2; - ntag = 0; + n = 0; + i = 0; + bp = 4; + mxoff = 1 << bp; + pctx->mxsz = (1 << (16 - bp)) + 2; + tag = 0; + done = -1; + ntag = 8; ptag = &outbuf[xout++]; - *ptag = 0; - rr = 0; - pctx->nbt = 4; - pctx->len = size; - pctx->match_length = 0; - ntfs_new_node(pctx,0); - do { - if (pctx->match_length > pctx->len) - pctx->match_length = pctx->len; - if (pctx->match_length < THRESHOLD) { - pctx->match_length = 1; - if (ntag >= 8) { - ntag = 0; - ptag = &outbuf[xout++]; - *ptag = 0; + while ((i < bufsize) && (xout < (NTFS_SB_SIZE + 2))) { + /* adjust the longest match we can output */ + while (mxoff < i) { + bp++; + mxoff <<= 1; + pctx->mxsz = (pctx->mxsz + 2) >> 1; + } + /* search the best match at current position */ + if (done < i) + do { + ntfs_best_match(pctx,++done); + } while (done < i); + j = i + pctx->size; + if ((j - i) > pctx->mxsz) + j = i + pctx->mxsz; + + if ((j - i) > 2) { + offs = pctx->rel; + /* check whether there is a better run at i+1 */ + ntfs_best_match(pctx,i+1); + done = i+1; + k = i + 1 + pctx->size; + mxsz2 = pctx->mxsz; + if (mxoff <= i) + mxsz2 = (pctx->mxsz + 2) >> 1; + if ((k - i) > mxsz2) + k = i + mxsz2; + if (k > (j + 1)) { + /* issue a single byte */ + outbuf[xout++] = inbuf[i]; + i++; + } else { + q = (~offs << (16 - bp)) + + (j - i - 3); + outbuf[xout++] = q & 255; + outbuf[xout++] = (q >> 8) & 255; + tag |= (1 << (8 - ntag)); + i = j; } - outbuf[xout++] = inbuf[rr]; - ntag++; } else { - while ((unsigned int)(1 << pctx->nbt) - <= (rr - 1)) - pctx->nbt++; - q = (pctx->match_position << (16 - pctx->nbt)) - + pctx->match_length - THRESHOLD; - if (ntag >= 8) { - ntag = 0; - ptag = &outbuf[xout++]; - *ptag = 0; - } - *ptag |= 1 << ntag++; - outbuf[xout++] = q & 255; - outbuf[xout++] = (q >> 8) & 255; + outbuf[xout++] = inbuf[i]; + i++; } - last_match_length = pctx->match_length; - dd = last_match_length; - if (dd-- > 0) { - rr = ntfs_nextmatch(pctx,rr,dd); - if (!rr) - goto bug; + /* store the tag if fully used */ + if (!--ntag) { + *ptag = tag; + ntag = 8; + ptag = &outbuf[xout++]; + tag = 0; } - /* - * stop if input is exhausted or output has exceeded - * the maximum size. Two extra bytes have to be - * reserved in output buffer, as 3 bytes may be - * output in a loop. - */ - } while ((pctx->len > 0) - && (rr < size) && (xout < (NTFS_SB_SIZE + 2))); - /* uncompressed must be full size, so accept if better */ - if (xout < (NTFS_SB_SIZE + 2)) { + } + /* store the last tag, if partially used */ + if (ntag == 8) + xout--; + else + *ptag = tag; + /* uncompressed must be full size, accept if better */ + if ((i >= bufsize) && (xout < (NTFS_SB_SIZE + 2))) { outbuf[0] = (xout - 3) & 255; outbuf[1] = 0xb0 + (((xout - 3) >> 8) & 15); } else { - memcpy(&outbuf[2],inbuf,size); - if (size < NTFS_SB_SIZE) - memset(&outbuf[size+2],0,NTFS_SB_SIZE - size); + memcpy(&outbuf[2],inbuf,bufsize); + if (bufsize < NTFS_SB_SIZE) + memset(&outbuf[bufsize+2], 0, + NTFS_SB_SIZE - bufsize); outbuf[0] = 0xff; outbuf[1] = 0x3f; xout = NTFS_SB_SIZE + 2; @@ -343,9 +299,7 @@ static unsigned int ntfs_compress_block(const char *inbuf, xout = 0; errno = ENOMEM; } - return (xout); /* 0 for an error, > size if cannot compress */ -bug : - return (0); + return (xout); } /** @@ -547,7 +501,7 @@ return_overflow: * code. Might be a bit confusing to debug but there really should never be * errors coming from here. */ -static BOOL ntfs_is_cb_compressed(ntfs_attr *na, runlist_element *rl, +static BOOL ntfs_is_cb_compressed(ntfs_attr *na, runlist_element *rl, VCN cb_start_vcn, int cb_clusters) { /* @@ -667,12 +621,12 @@ s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b) cb_size = na->compression_block_size; cb_size_mask = cb_size - 1UL; cb_clusters = na->compression_block_clusters; - + /* Need a temporary buffer for each loaded compression block. */ cb = (u8*)ntfs_malloc(cb_size); if (!cb) return -1; - + /* Need a temporary buffer for each uncompressed block. */ dest = (u8*)ntfs_malloc(cb_size); if (!dest) { @@ -1512,12 +1466,12 @@ static int ntfs_read_append(ntfs_attr *na, const runlist_element *rl, * or -1 if there were an irrecoverable error (errno set) */ -static int ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs, +static s32 ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs, const char *outbuf, s32 count, BOOL compress, BOOL appending, VCN *update_from) { - int rounded; - int written; + s32 rounded; + s32 written; int clsz; if (compress) { @@ -1655,7 +1609,7 @@ s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *wrl, s64 wpos, * (we are reopening an existing file to append to it) * Decompress the data and append */ - compsz = compressed_part << vol->cluster_size_bits; + compsz = (s32)compressed_part << vol->cluster_size_bits; outbuf = (char*)ntfs_malloc(na->compression_block_size); if (outbuf) { if (appending) { diff --git a/libcustomntfs/compress.h b/libcustomntfs/source/compress.h similarity index 100% rename from libcustomntfs/compress.h rename to libcustomntfs/source/compress.h diff --git a/libcustomntfs/config.h b/libcustomntfs/source/config.h similarity index 97% rename from libcustomntfs/config.h rename to libcustomntfs/source/config.h index a0a5da00..f145094c 100644 --- a/libcustomntfs/config.h +++ b/libcustomntfs/source/config.h @@ -226,6 +226,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BYTEORDER_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DISK_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ENDIAN_H @@ -309,13 +312,13 @@ #define PACKAGE_NAME "ntfs-3g" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "ntfs-3g 2011.4.12" +#define PACKAGE_STRING "ntfs-3g 2012.1.15" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "ntfs-3g" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2011.4.12" +#define PACKAGE_VERSION "2012.1.15" /* POSIX ACL support */ #undef POSIXACLS @@ -345,7 +348,7 @@ #endif /* Version number of package */ -#define VERSION "2011.4.12" +#define VERSION "2012.1.15" /* Define to 1 if this is a Windows OS */ #undef WINDOWS @@ -375,6 +378,9 @@ /* Required define if using POSIX threads */ #undef _REENTRANT +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus diff --git a/libcustomntfs/debug.c b/libcustomntfs/source/debug.c similarity index 100% rename from libcustomntfs/debug.c rename to libcustomntfs/source/debug.c diff --git a/libcustomntfs/debug.h b/libcustomntfs/source/debug.h similarity index 96% rename from libcustomntfs/debug.h rename to libcustomntfs/source/debug.h index cf39b625..f7f3c6fb 100644 --- a/libcustomntfs/debug.h +++ b/libcustomntfs/source/debug.h @@ -38,10 +38,10 @@ static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl #define NTFS_BUG(msg) \ { \ - int ___i; \ + int ___i = 1; \ ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \ ntfs_log_debug("Forcing segmentation fault!"); \ - ___i = ((int*)NULL)[1]; \ + ___i = ((int*)NULL)[___i]; \ } #endif /* defined _NTFS_DEBUG_H */ diff --git a/libcustomntfs/device.c b/libcustomntfs/source/device.c similarity index 94% rename from libcustomntfs/device.c rename to libcustomntfs/source/device.c index db840108..274abacb 100644 --- a/libcustomntfs/device.c +++ b/libcustomntfs/source/device.c @@ -58,6 +58,9 @@ #ifdef HAVE_SYS_MOUNT_H #include #endif +#ifdef HAVE_SYS_DISK_H +#include +#endif #ifdef HAVE_LINUX_FD_H #include #endif @@ -556,6 +559,36 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) return (s64)this_floppy.size * 512 / block_size; } } +#endif +#ifdef DIOCGMEDIASIZE + { + /* FreeBSD */ + off_t size; + + if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) { + ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n", + (unsigned long long)size, + (unsigned long long)size); + return (s64)size / block_size; + } + } +#endif +#ifdef DKIOCGETBLOCKCOUNT + { + /* Mac OS X */ + uint64_t blocks; + int sector_size; + + sector_size = ntfs_device_sector_size_get(dev); + if (sector_size >= 0 && dev->d_ops->ioctl(dev, + DKIOCGETBLOCKCOUNT, &blocks) >= 0) + { + ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n", + (unsigned long long) blocks, + (unsigned long long) blocks); + return blocks * sector_size / block_size; + } + } #endif /* * We couldn't figure it out by using a specialized ioctl, @@ -705,6 +738,28 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev) return sect_size; } } +#elif defined(DIOCGSECTORSIZE) + { + /* FreeBSD */ + size_t sect_size = 0; + + if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, §_size)) { + ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n", + (int) sect_size); + return sect_size; + } + } +#elif defined(DKIOCGETBLOCKSIZE) + { + /* Mac OS X */ + uint32_t sect_size = 0; + + if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, §_size)) { + ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n", + (int) sect_size); + return sect_size; + } + } #else errno = EOPNOTSUPP; #endif diff --git a/libcustomntfs/device.h b/libcustomntfs/source/device.h similarity index 100% rename from libcustomntfs/device.h rename to libcustomntfs/source/device.h diff --git a/libcustomntfs/device_io.c b/libcustomntfs/source/device_io.c similarity index 100% rename from libcustomntfs/device_io.c rename to libcustomntfs/source/device_io.c diff --git a/libcustomntfs/device_io.h b/libcustomntfs/source/device_io.h similarity index 100% rename from libcustomntfs/device_io.h rename to libcustomntfs/source/device_io.h diff --git a/libcustomntfs/dir.c b/libcustomntfs/source/dir.c similarity index 99% rename from libcustomntfs/dir.c rename to libcustomntfs/source/dir.c index 198bc29d..ccae47c3 100644 --- a/libcustomntfs/dir.c +++ b/libcustomntfs/source/dir.c @@ -257,7 +257,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, u8 *index_end; ntfs_attr *ia_na; int eo, rc; - u32 index_block_size, index_vcn_size; + u32 index_block_size; u8 index_vcn_size_bits; ntfs_log_trace("Entering\n"); @@ -378,11 +378,9 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, /* Determine the size of a vcn in the directory index. */ if (vol->cluster_size <= index_block_size) { - index_vcn_size = vol->cluster_size; index_vcn_size_bits = vol->cluster_size_bits; } else { - index_vcn_size = vol->sector_size; - index_vcn_size_bits = vol->sector_size_bits; + index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS; } /* Get the starting vcn of the index_block holding the child node. */ @@ -1039,7 +1037,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, INDEX_ENTRY *ie; INDEX_ALLOCATION *ia = NULL; int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo; - u32 index_block_size, index_vcn_size; + u32 index_block_size; u8 index_block_size_bits, index_vcn_size_bits; ntfs_log_trace("Entering.\n"); @@ -1131,11 +1129,9 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, } index_block_size_bits = ffs(index_block_size) - 1; if (vol->cluster_size <= index_block_size) { - index_vcn_size = vol->cluster_size; index_vcn_size_bits = vol->cluster_size_bits; } else { - index_vcn_size = vol->sector_size; - index_vcn_size_bits = vol->sector_size_bits; + index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS; } /* Are we jumping straight into the index allocation attribute? */ @@ -1517,7 +1513,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, else ir->clusters_per_index_block = ni->vol->indx_record_size >> - ni->vol->sector_size_bits; + NTFS_BLOCK_SIZE_BITS; ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER)); ir->index.index_length = cpu_to_le32(index_len); ir->index.allocated_size = cpu_to_le32(index_len); @@ -2508,24 +2504,24 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, int res = 0; int longlen = 0; int shortlen = 0; - char newname[MAX_DOS_NAME_LENGTH + 1]; + char newname[3*MAX_DOS_NAME_LENGTH + 1]; ntfschar oldname[MAX_DOS_NAME_LENGTH]; int oldlen; - ntfs_volume *vol; - u64 fnum; u64 dnum; BOOL closed = FALSE; ntfschar *shortname = NULL; ntfschar longname[NTFS_MAX_NAME_LEN]; - vol = ni->vol; - fnum = ni->mft_no; - /* convert the string to the NTFS wide chars */ - if (size > MAX_DOS_NAME_LENGTH) - size = MAX_DOS_NAME_LENGTH; + /* copy the string to insert a null char, and truncate */ + if (size > 3*MAX_DOS_NAME_LENGTH) + size = 3*MAX_DOS_NAME_LENGTH; strncpy(newname, value, size); + /* a long name may be truncated badly and be untranslatable */ newname[size] = 0; + /* convert the string to the NTFS wide chars, and truncate */ shortlen = ntfs_mbstoucs(newname, &shortname); + if (shortlen > MAX_DOS_NAME_LENGTH) + shortlen = MAX_DOS_NAME_LENGTH; /* make sure the short name has valid chars */ if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) { ntfs_inode_close_in_dir(ni,dir_ni); diff --git a/libcustomntfs/dir.h b/libcustomntfs/source/dir.h similarity index 100% rename from libcustomntfs/dir.h rename to libcustomntfs/source/dir.h diff --git a/libcustomntfs/efs.c b/libcustomntfs/source/efs.c similarity index 99% rename from libcustomntfs/efs.c rename to libcustomntfs/source/efs.c index 6ccec20a..7957005b 100644 --- a/libcustomntfs/efs.c +++ b/libcustomntfs/source/efs.c @@ -139,7 +139,6 @@ static int fixup_loop(ntfs_inode *ni) ntfs_attr *na; ATTR_RECORD *a; BOOL restart; - BOOL first; int cnt; int maxcnt; int res = 0; @@ -200,7 +199,6 @@ static int fixup_loop(ntfs_inode *ni) if (na) ntfs_attr_close(na); } - first = FALSE; } while (restart && !res); if (ctx) ntfs_attr_put_search_ctx(ctx); diff --git a/libcustomntfs/efs.h b/libcustomntfs/source/efs.h similarity index 100% rename from libcustomntfs/efs.h rename to libcustomntfs/source/efs.h diff --git a/libcustomntfs/endians.h b/libcustomntfs/source/endians.h similarity index 100% rename from libcustomntfs/endians.h rename to libcustomntfs/source/endians.h diff --git a/libcustomntfs/gekko_io.c b/libcustomntfs/source/gekko_io.c similarity index 100% rename from libcustomntfs/gekko_io.c rename to libcustomntfs/source/gekko_io.c diff --git a/libcustomntfs/gekko_io.h b/libcustomntfs/source/gekko_io.h similarity index 100% rename from libcustomntfs/gekko_io.h rename to libcustomntfs/source/gekko_io.h diff --git a/libcustomntfs/index.c b/libcustomntfs/source/index.c similarity index 97% rename from libcustomntfs/index.c rename to libcustomntfs/source/index.c index 8080b889..b0c0a4e6 100644 --- a/libcustomntfs/index.c +++ b/libcustomntfs/source/index.c @@ -83,9 +83,9 @@ static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos) static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib) { s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn); - + ntfs_log_trace("vcn: %lld\n", (long long)vcn); - + ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), 1, icx->block_size, ib); if (ret != 1) { @@ -93,7 +93,7 @@ static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib) (long long)vcn, (unsigned long long)icx->ni->mft_no); return STATUS_ERROR; } - + return STATUS_OK; } @@ -101,9 +101,9 @@ static int ntfs_icx_ib_write(ntfs_index_context *icx) { if (ntfs_ib_write(icx, icx->ib)) return STATUS_ERROR; - + icx->ib_dirty = FALSE; - + return STATUS_OK; } @@ -122,7 +122,7 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, ntfs_index_context *icx; ntfs_log_trace("Entering\n"); - + if (!ni) { errno = EINVAL; return NULL; @@ -142,7 +142,7 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni, static void ntfs_index_ctx_free(ntfs_index_context *icx) { ntfs_log_trace("Entering\n"); - + if (!icx->entry) return; @@ -156,7 +156,7 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx) } free(icx->ib); } - + ntfs_attr_close(icx->ia_na); } @@ -181,9 +181,9 @@ void ntfs_index_ctx_put(ntfs_index_context *icx) void ntfs_index_ctx_reinit(ntfs_index_context *icx) { ntfs_log_trace("Entering\n"); - + ntfs_index_ctx_free(icx); - + *icx = (ntfs_index_context) { .ni = icx->ni, .name = icx->name, @@ -225,30 +225,30 @@ static int ntfs_ie_end(INDEX_ENTRY *ie) return ie->ie_flags & INDEX_ENTRY_END || !ie->length; } -/** +/** * Find the last entry in the index block */ static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end) { ntfs_log_trace("Entering\n"); - + while ((char *)ie < ies_end && !ntfs_ie_end(ie)) ie = ntfs_ie_get_next(ie); - + return ie; } static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos) { INDEX_ENTRY *ie; - + ntfs_log_trace("pos: %d\n", pos); - + ie = ntfs_ie_get_first(ih); - + while (pos-- > 0) ie = ntfs_ie_get_next(ie); - + return ie; } @@ -256,16 +256,16 @@ static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie) { INDEX_ENTRY *ie_prev = NULL; INDEX_ENTRY *tmp; - + ntfs_log_trace("Entering\n"); - + tmp = ntfs_ie_get_first(ih); - + while (tmp != ie) { ie_prev = tmp; tmp = ntfs_ie_get_next(tmp); } - + return ie_prev; } @@ -289,9 +289,9 @@ void ntfs_ie_filename_dump(INDEX_ENTRY *ie) void ntfs_ih_filename_dump(INDEX_HEADER *ih) { INDEX_ENTRY *ie; - + ntfs_log_trace("Entering\n"); - + ie = ntfs_ie_get_first(ih); while (!ntfs_ie_end(ie)) { ntfs_ie_filename_dump(ie); @@ -304,9 +304,9 @@ static int ntfs_ih_numof_entries(INDEX_HEADER *ih) int n; INDEX_ENTRY *ie; u8 *end; - + ntfs_log_trace("Entering\n"); - + end = ntfs_ie_get_end(ih); ie = ntfs_ie_get_first(ih); for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++) @@ -327,9 +327,9 @@ static int ntfs_ih_zero_entry(INDEX_HEADER *ih) static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie) { u32 new_size; - + ntfs_log_trace("Entering\n"); - + new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length); ih->index_length = cpu_to_le32(new_size); memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), @@ -347,9 +347,9 @@ static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn) static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) { int ie_size = le16_to_cpu(ie->length); - + ntfs_log_trace("Entering\n"); - + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size); memmove((u8 *)pos + ie_size, pos, le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size); @@ -359,13 +359,13 @@ static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos) static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie) { INDEX_ENTRY *dup; - + ntfs_log_trace("Entering\n"); - + dup = ntfs_malloc(le16_to_cpu(ie->length)); if (dup) memcpy(dup, ie, le16_to_cpu(ie->length)); - + return dup; } @@ -373,12 +373,12 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) { INDEX_ENTRY *dup; int size = le16_to_cpu(ie->length); - + ntfs_log_trace("Entering\n"); - + if (ie->ie_flags & INDEX_ENTRY_NODE) size -= sizeof(VCN); - + dup = ntfs_malloc(size); if (dup) { memcpy(dup, ie, size); @@ -391,19 +391,19 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie) static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) { u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; - + ntfs_log_trace("Entering\n"); - + if (!ntfs_is_indx_record(ib->magic)) { - + ntfs_log_error("Corrupt index block signature: vcn %lld inode " "%llu\n", (long long)vcn, (unsigned long long)icx->ni->mft_no); return -1; } - + if (sle64_to_cpu(ib->index_block_vcn) != vcn) { - + ntfs_log_error("Corrupt index block: VCN (%lld) is different " "from expected VCN (%lld) in inode %llu\n", (long long)sle64_to_cpu(ib->index_block_vcn), @@ -411,12 +411,12 @@ static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) (unsigned long long)icx->ni->mft_no); return -1; } - + if (ib_size != icx->block_size) { - + ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " "has a size (%u) differing from the index " - "specified size (%u)\n", (long long)vcn, + "specified size (%u)\n", (long long)vcn, (unsigned long long)icx->ni->mft_no, ib_size, icx->block_size); return -1; @@ -431,24 +431,24 @@ static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name, INDEX_ROOT *ir = NULL; ntfs_log_trace("Entering\n"); - + *ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!*ctx) return NULL; - - if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, + + if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE, 0, NULL, 0, *ctx)) { ntfs_log_perror("Failed to lookup $INDEX_ROOT"); goto err_out; } - + a = (*ctx)->attr; if (a->non_resident) { errno = EINVAL; ntfs_log_perror("Non-resident $INDEX_ROOT detected"); goto err_out; } - + ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset)); err_out: if (!ir) { @@ -469,11 +469,11 @@ static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len) return ir; } -/** +/** * Find a key in the index block. - * + * * Return values: - * STATUS_OK with errno set to ESUCCESS if we know for sure that the + * STATUS_OK with errno set to ESUCCESS if we know for sure that the * entry exists and @ie_out points to this entry. * STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the * entry doesn't exist and @ie_out is the insertion point. @@ -488,11 +488,11 @@ static int ntfs_ie_lookup(const void *key, const int key_len, INDEX_ENTRY *ie; u8 *index_end; int rc, item = 0; - + ntfs_log_trace("Entering\n"); - + index_end = ntfs_ie_get_end(ih); - + /* * Loop until we exceed valid memory (corruption case) or until we * reach the last entry. @@ -537,14 +537,14 @@ static int ntfs_ie_lookup(const void *key, const int key_len, */ if (rc == -1) break; - + if (!rc) { *ie_out = ie; errno = 0; icx->parent_pos[icx->pindex] = item; return STATUS_OK; } - + item++; } /* @@ -558,7 +558,7 @@ static int ntfs_ie_lookup(const void *key, const int key_len, errno = ENOENT; return STATUS_NOT_FOUND; } - + /* Get the starting vcn of the index_block holding the child node. */ *vcn = ntfs_ie_get_vcn(ie); if (*vcn < 0) { @@ -570,21 +570,21 @@ static int ntfs_ie_lookup(const void *key, const int key_len, ntfs_log_trace("Parent entry number %d\n", item); icx->parent_pos[icx->pindex] = item; - + return STATUS_KEEP_SEARCHING; } static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni) { ntfs_attr *na; - + na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open index allocation of inode " "%llu", (unsigned long long)ni->mft_no); return NULL; } - + return na; } @@ -593,22 +593,22 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) s64 pos, ret; ntfs_log_trace("vcn: %lld\n", (long long)vcn); - + pos = ntfs_ib_vcn_to_pos(icx, vcn); ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, (u8 *)dst); if (ret != 1) { if (ret == -1) ntfs_log_perror("Failed to read index block"); - else + else ntfs_log_error("Failed to read full index block at " "%lld\n", (long long)pos); return -1; } - + if (ntfs_ia_check(icx, dst, vcn)) return -1; - + return 0; } @@ -633,7 +633,7 @@ static int ntfs_icx_parent_dec(ntfs_index_context *icx) } return STATUS_OK; } - + /** * ntfs_index_lookup - find a key in an index and return its index entry * @key: [IN] key for which to search in the index @@ -676,7 +676,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic int ret, err = 0; ntfs_log_trace("Entering\n"); - + if (!key || key_len <= 0) { errno = EINVAL; ntfs_log_perror("key: %p key_len: %d", key, key_len); @@ -689,7 +689,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic errno = EIO; return -1; } - + icx->block_size = le32_to_cpu(ir->index_block_size); if (icx->block_size < NTFS_BLOCK_SIZE) { errno = EINVAL; @@ -701,18 +701,18 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic if (ni->vol->cluster_size <= icx->block_size) icx->vcn_size_bits = ni->vol->cluster_size_bits; else - icx->vcn_size_bits = ni->vol->sector_size_bits; + icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS; /* get the appropriate collation function */ icx->collate = ntfs_get_collate_function(ir->collation_rule); if (!icx->collate) { err = errno = EOPNOTSUPP; - ntfs_log_perror("Unknown collation rule 0x%x", + ntfs_log_perror("Unknown collation rule 0x%x", (unsigned)le32_to_cpu(ir->collation_rule)); goto err_out; } - + old_vcn = VCN_INDEX_ROOT_PARENT; - /* + /* * FIXME: check for both ir and ib that the first index entry is * within the index block. */ @@ -721,9 +721,9 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic err = errno; goto err_out; } - + icx->ir = ir; - + if (ret != STATUS_KEEP_SEARCHING) { /* STATUS_OK or STATUS_NOT_FOUND */ err = errno; @@ -731,19 +731,19 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic icx->parent_vcn[icx->pindex] = old_vcn; goto done; } - + /* Child node present, descend into it. */ - + icx->ia_na = ntfs_ia_open(icx, ni); if (!icx->ia_na) goto err_out; - + ib = ntfs_malloc(icx->block_size); if (!ib) { err = errno; goto err_out; } - + descend_into_child_node: icx->parent_vcn[icx->pindex] = old_vcn; @@ -754,16 +754,16 @@ descend_into_child_node: old_vcn = vcn; ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn); - + if (ntfs_ib_read(icx, vcn, ib)) goto err_out; - + ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie); if (ret != STATUS_KEEP_SEARCHING) { err = errno; if (ret == STATUS_ERROR) goto err_out; - + /* STATUS_OK or STATUS_NOT_FOUND */ icx->is_in_root = FALSE; icx->ib = ib; @@ -777,7 +777,7 @@ descend_into_child_node: (unsigned long long)ni->mft_no); goto err_out; } - + goto descend_into_child_node; err_out: free(ib); @@ -798,38 +798,38 @@ done: } -static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, +static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, INDEX_HEADER_FLAGS node_type) { INDEX_BLOCK *ib; int ih_size = sizeof(INDEX_HEADER); - + ntfs_log_trace("ib_vcn: %lld ib_size: %u\n", (long long)ib_vcn, ib_size); - + ib = ntfs_calloc(ib_size); if (!ib) return NULL; - + ib->magic = magic_INDX; ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK)); ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1); /* Set USN to 1 */ *(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1); ib->lsn = cpu_to_le64(0); - + ib->index_block_vcn = cpu_to_sle64(ib_vcn); - + ib->index.entries_offset = cpu_to_le32((ih_size + le16_to_cpu(ib->usa_count) * 2 + 7) & ~7); ib->index.index_length = 0; - ib->index.allocated_size = cpu_to_le32(ib_size - + ib->index.allocated_size = cpu_to_le32(ib_size - (sizeof(INDEX_BLOCK) - ih_size)); ib->index.ih_flags = node_type; - + return ib; -} +} -/** +/** * Find the median by going through all the entries */ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) @@ -837,12 +837,12 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) INDEX_ENTRY *ie, *ie_start; u8 *ie_end; int i = 0, median; - + ntfs_log_trace("Entering\n"); - + ie = ie_start = ntfs_ie_get_first(ih); ie_end = (u8 *)ntfs_ie_get_end(ih); - + while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) { ie = ntfs_ie_get_next(ie); i++; @@ -851,12 +851,12 @@ static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih) * NOTE: this could be also the entry at the half of the index block. */ median = i / 2 - 1; - + ntfs_log_trace("Entries: %d median: %d\n", i, median); - + for (i = 0, ie = ie_start; i <= median; i++) ie = ntfs_ie_get_next(ie); - + return ie; } @@ -875,7 +875,7 @@ static int ntfs_ibm_add(ntfs_index_context *icx) u8 bmp[8]; ntfs_log_trace("Entering\n"); - + if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len)) return STATUS_OK; /* @@ -887,7 +887,7 @@ static int ntfs_ibm_add(ntfs_index_context *icx) ntfs_log_perror("Failed to add AT_BITMAP"); return STATUS_ERROR; } - + return STATUS_OK; } @@ -901,7 +901,7 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) int ret = STATUS_ERROR; ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn); - + na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open $BITMAP attribute"); @@ -916,17 +916,17 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) } } } - + if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) { ntfs_log_perror("Failed to read $BITMAP"); goto err_na; } - if (set) + if (set) byte |= bit; else byte &= ~bit; - + if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) { ntfs_log_perror("Failed to write $Bitmap"); goto err_na; @@ -956,17 +956,17 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx) s64 vcn, byte, size; ntfs_log_trace("Entering\n"); - + bm = ntfs_attr_readall(icx->ni, AT_BITMAP, icx->name, icx->name_len, &size); if (!bm) return (VCN)-1; - + for (byte = 0; byte < size; byte++) { - + if (bm[byte] == 255) continue; - + for (bit = 0; bit < 8; bit++) { if (!(bm[byte] & (1 << bit))) { vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit); @@ -974,14 +974,14 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx) } } } - + vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); -out: +out: ntfs_log_trace("allocated vcn: %lld\n", (long long)vcn); if (ntfs_ibm_set(icx, vcn)) vcn = (VCN)-1; - + free(bm); return vcn; } @@ -992,23 +992,23 @@ static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) INDEX_ENTRY *ie_last; char *ies_start, *ies_end; int i; - + ntfs_log_trace("Entering\n"); - + ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), LEAF_NODE); if (!ib) return NULL; - + ies_start = (char *)ntfs_ie_get_first(&ir->index); ies_end = (char *)ntfs_ie_get_end(&ir->index); ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); - /* + /* * Copy all entries, including the termination entry * as well, which can never have any data. */ i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); - + ib->index.ih_flags = ir->index.ih_flags; ib->index.index_length = cpu_to_le32(i + le32_to_cpu(ib->index.entries_offset)); @@ -1019,7 +1019,7 @@ static void ntfs_ir_nill(INDEX_ROOT *ir) { INDEX_ENTRY *ie_last; char *ies_start, *ies_end; - + ntfs_log_trace("Entering\n"); /* * TODO: This function could be much simpler. @@ -1027,7 +1027,7 @@ static void ntfs_ir_nill(INDEX_ROOT *ir) ies_start = (char *)ntfs_ie_get_first(&ir->index); ies_end = (char *)ntfs_ie_get_end(&ir->index); ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); - /* + /* * Move the index root termination entry forward */ if ((char *)ie_last > ies_start) { @@ -1043,21 +1043,21 @@ static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, INDEX_ENTRY *ie_head; /* first entry after the median */ int tail_size, ret; INDEX_BLOCK *dst; - + ntfs_log_trace("Entering\n"); - - dst = ntfs_ib_alloc(new_vcn, icx->block_size, + + dst = ntfs_ib_alloc(new_vcn, icx->block_size, src->index.ih_flags & NODE_MASK); if (!dst) return STATUS_ERROR; - + ie_head = ntfs_ie_get_next(median); - + ies_end = (u8 *)ntfs_ie_get_end(&src->index); tail_size = ies_end - (u8 *)ie_head; memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); - - dst->index.index_length = cpu_to_le32(tail_size + + + dst->index.index_length = cpu_to_le32(tail_size + le32_to_cpu(dst->index.entries_offset)); ret = ntfs_ib_write(icx, dst); @@ -1070,43 +1070,43 @@ static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *ib, { char *ies_start, *ies_end; INDEX_ENTRY *ie_last; - + ntfs_log_trace("Entering\n"); - + ies_start = (char *)ntfs_ie_get_first(&ib->index); ies_end = (char *)ntfs_ie_get_end(&ib->index); - + ie_last = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end); if (ie_last->ie_flags & INDEX_ENTRY_NODE) ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie)); - + memcpy(ie, ie_last, le16_to_cpu(ie_last->length)); - - ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) + + + ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) + le16_to_cpu(ie->length) + le32_to_cpu(ib->index.entries_offset)); - + if (ntfs_ib_write(icx, ib)) return STATUS_ERROR; - + return STATUS_OK; } - + static int ntfs_ia_add(ntfs_index_context *icx) { ntfs_log_trace("Entering\n"); if (ntfs_ibm_add(icx)) return -1; - + if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) { - + if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len, NULL, 0)) { ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION"); return -1; } } - + icx->ia_na = ntfs_ia_open(icx, icx->ni); if (!icx->ia_na) return -1; @@ -1125,43 +1125,43 @@ static int ntfs_ir_reparent(ntfs_index_context *icx) int ret = STATUS_ERROR; ntfs_log_trace("Entering\n"); - + ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!ir) goto out; - + if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX) if (ntfs_ia_add(icx)) goto out; - + new_ib_vcn = ntfs_ibm_get_free(icx); if (new_ib_vcn == -1) goto out; - + ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!ir) goto clear_bmp; - + ib = ntfs_ir_to_ib(ir, new_ib_vcn); if (ib == NULL) { ntfs_log_perror("Failed to move index root to index block"); goto clear_bmp; } - + if (ntfs_ib_write(icx, ib)) goto clear_bmp; - + retry : ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); if (!ir) goto clear_bmp; - + ntfs_ir_nill(ir); - + ie = ntfs_ie_get_first(&ir->index); ie->ie_flags |= INDEX_ENTRY_NODE; ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN)); - + ir->index.ih_flags = LARGE_INDEX; ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset) + le16_to_cpu(ie->length)); @@ -1197,7 +1197,7 @@ retry : * so in error case we wouldn't lose the IB. */ ntfs_ie_set_vcn(ie, new_ib_vcn); - + ret = STATUS_OK; err_out: free(ib); @@ -1211,56 +1211,56 @@ clear_bmp: /** * ntfs_ir_truncate - Truncate index root attribute - * + * * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR. */ static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size) -{ +{ ntfs_attr *na; int ret; ntfs_log_trace("Entering\n"); - + na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len); if (!na) { ntfs_log_perror("Failed to open INDEX_ROOT"); return STATUS_ERROR; } /* - * INDEX_ROOT must be resident and its entries can be moved to + * INDEX_ROOT must be resident and its entries can be moved to * INDEX_BLOCK, so ENOSPC isn't a real error. */ ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index)); if (ret == STATUS_OK) { - + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; - + icx->ir->index.allocated_size = cpu_to_le32(data_size); - + } else if (ret == STATUS_ERROR) ntfs_log_perror("Failed to truncate INDEX_ROOT"); - + ntfs_attr_close(na); return ret; } - + /** * ntfs_ir_make_space - Make more space for the index root attribute - * + * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return STATUS_ERROR. */ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) -{ +{ int ret; ntfs_log_trace("Entering\n"); ret = ntfs_ir_truncate(icx, data_size); if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { - + ret = ntfs_ir_reparent(icx); if (ret == STATUS_OK) ret = STATUS_KEEP_SEARCHING; @@ -1277,31 +1277,31 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) static int ntfs_ie_add_vcn(INDEX_ENTRY **ie) { INDEX_ENTRY *p, *old = *ie; - + old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN)); p = MEM2_realloc(old, le16_to_cpu(old->length)); if (!p) return STATUS_ERROR; - + p->ie_flags |= INDEX_ENTRY_NODE; *ie = p; return STATUS_OK; } -static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, +static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, int pos) { INDEX_ENTRY *ie_node, *ie; int ret = STATUS_ERROR; VCN old_vcn; - + ntfs_log_trace("Entering\n"); - + ie = ntfs_ie_dup(orig_ie); if (!ie) return STATUS_ERROR; - + if (!(ie->ie_flags & INDEX_ENTRY_NODE)) if (ntfs_ie_add_vcn(&ie)) goto out; @@ -1309,13 +1309,13 @@ static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn, ie_node = ntfs_ie_get_by_pos(ih, pos); old_vcn = ntfs_ie_get_vcn(ie_node); ntfs_ie_set_vcn(ie_node, new_vcn); - + ntfs_ie_insert(ih, ie, ie_node); ntfs_ie_set_vcn(ie_node, old_vcn); ret = STATUS_OK; -out: +out: free(ie); - + return ret; } @@ -1335,14 +1335,14 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, { u32 new_size; int ret; - + ntfs_log_trace("Entering\n"); - + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; - new_size = le32_to_cpu(icx->ir->index.index_length) + + new_size = le32_to_cpu(icx->ir->index.index_length) + le16_to_cpu(median->length); if (!(median->ie_flags & INDEX_ENTRY_NODE)) new_size += sizeof(VCN); @@ -1350,12 +1350,12 @@ static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median, ret = ntfs_ir_make_space(icx, new_size); if (ret != STATUS_OK) return ret; - + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len); if (!icx->ir) return STATUS_ERROR; - return ntfs_ih_insert(&icx->ir->index, median, new_vcn, + return ntfs_ih_insert(&icx->ir->index, median, new_vcn, ntfs_icx_parent_pos(icx)); } @@ -1366,20 +1366,20 @@ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib); * On error return STATUS_ERROR. */ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) -{ +{ INDEX_BLOCK *ib; u32 idx_size, allocated_size; int err = STATUS_ERROR; VCN old_vcn; ntfs_log_trace("Entering\n"); - + ib = ntfs_malloc(icx->block_size); if (!ib) return -1; - + old_vcn = ntfs_icx_parent_vcn(icx); - + if (ntfs_ib_read(icx, old_vcn, ib)) goto err_out; @@ -1392,58 +1392,58 @@ static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn) err = STATUS_KEEP_SEARCHING; goto err_out; } - + if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx))) goto err_out; - + if (ntfs_ib_write(icx, ib)) goto err_out; - + err = STATUS_OK; -err_out: +err_out: free(ib); return err; } /** * ntfs_ib_split - Split an index block - * + * * On success return STATUS_OK or STATUS_KEEP_SEARCHING. * On error return is STATUS_ERROR. */ static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib) -{ +{ INDEX_ENTRY *median; VCN new_vcn; int ret; ntfs_log_trace("Entering\n"); - + if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; - + median = ntfs_ie_get_median(&ib->index); new_vcn = ntfs_ibm_get_free(icx); if (new_vcn == -1) return STATUS_ERROR; - + if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) { ntfs_ibm_clear(icx, new_vcn); return STATUS_ERROR; } - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) ret = ntfs_ir_insert_median(icx, median, new_vcn); else ret = ntfs_ib_insert(icx, median, new_vcn); - + if (ret != STATUS_OK) { ntfs_ibm_clear(icx, new_vcn); return ret; } - + ret = ntfs_ib_cut_tail(icx, ib, median); - + return ret; } @@ -1453,7 +1453,7 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) INDEX_HEADER *ih; int allocated_size, new_size; int ret = STATUS_ERROR; - + #ifdef DEBUG /* removed by JPA to make function usable for security indexes char *fn; @@ -1462,9 +1462,9 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) ntfs_attr_name_free(&fn); */ #endif - + while (1) { - + if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) { errno = EEXIST; ntfs_log_perror("Index already have such entry"); @@ -1474,21 +1474,21 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) ntfs_log_perror("Failed to find place for new entry"); goto err_out; } - + if (icx->is_in_root) ih = &icx->ir->index; else ih = &icx->ib->index; - + allocated_size = le32_to_cpu(ih->allocated_size); new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length); - + if (new_size <= allocated_size) break; - + ntfs_log_trace("index block sizes: allocated: %d needed: %d\n", allocated_size, new_size); - + if (icx->is_in_root) { if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR) goto err_out; @@ -1496,14 +1496,14 @@ int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie) if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR) goto err_out; } - + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } - + ntfs_ie_insert(ih, ie, icx->entry); ntfs_index_entry_mark_dirty(icx); - + ret = STATUS_OK; err_out: ntfs_log_trace("%s\n", ret ? "Failed" : "Done"); @@ -1525,17 +1525,17 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) int fn_size, ie_size, err, ret = -1; ntfs_log_trace("Entering\n"); - + if (!ni || !fn) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; return -1; } - + fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR); ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7; - + ie = ntfs_calloc(ie_size); if (!ie) return -1; @@ -1544,11 +1544,11 @@ int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref) ie->length = cpu_to_le16(ie_size); ie->key_length = cpu_to_le16(fn_size); memcpy(&ie->key, fn, fn_size); - + icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4); if (!icx) goto out; - + ret = ntfs_ie_add(icx, ie); err = errno; ntfs_index_ctx_put(icx); @@ -1563,9 +1563,9 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, { INDEX_ENTRY *ie_roam; int ret = STATUS_ERROR; - + ntfs_log_trace("Entering\n"); - + ie_roam = ntfs_ie_dup_novcn(ie); if (!ie_roam) return STATUS_ERROR; @@ -1577,7 +1577,7 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih, else if (ntfs_ib_write(icx, ib)) goto out; - + ntfs_index_ctx_reinit(icx); ret = ntfs_ie_add(icx, ie_roam); @@ -1593,36 +1593,36 @@ out: static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih) { INDEX_ENTRY *ie; - + ntfs_log_trace("Entering\n"); - + ie = ntfs_ie_get_first(ih); ie->ie_flags &= ~INDEX_ENTRY_NODE; ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN)); - + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - sizeof(VCN)); ih->ih_flags &= ~LARGE_INDEX; - + /* Not fatal error */ ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); } /** - * Used if an empty index block to be deleted has END entry as the parent + * Used if an empty index block to be deleted has END entry as the parent * in the INDEX_ROOT which is not the only one there. */ static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih, INDEX_BLOCK *ib) { INDEX_ENTRY *ie, *ie_prev; - + ntfs_log_trace("Entering\n"); - + ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx)); ie_prev = ntfs_ie_prev(ih, ie); - + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev)); - + return ntfs_ih_takeout(icx, ih, ie_prev, ib); } @@ -1632,48 +1632,48 @@ static int ntfs_index_rm_leaf(ntfs_index_context *icx) INDEX_HEADER *parent_ih; INDEX_ENTRY *ie; int ret = STATUS_ERROR; - + ntfs_log_trace("pindex: %d\n", icx->pindex); - + if (ntfs_icx_parent_dec(icx)) return STATUS_ERROR; if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1])) return STATUS_ERROR; - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) parent_ih = &icx->ir->index; else { ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; - + if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib)) goto out; - + parent_ih = &ib->index; } - + ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx)); if (!ntfs_ie_end(ie)) { ret = ntfs_ih_takeout(icx, parent_ih, ie, ib); goto out; } - + if (ntfs_ih_zero_entry(parent_ih)) { - + if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) { ntfs_ir_leafify(icx, parent_ih); goto ok; } - + ret = ntfs_index_rm_leaf(icx); goto out; } - + if (ntfs_ih_reparent_end(icx, parent_ih, ib)) goto out; -ok: +ok: ret = STATUS_OK; out: free(ib); @@ -1691,7 +1691,7 @@ static int ntfs_index_rm_node(ntfs_index_context *icx) int delta, ret = STATUS_ERROR; ntfs_log_trace("Entering\n"); - + if (!icx->ia_na) { icx->ia_na = ntfs_ia_open(icx, icx->ni); if (!icx->ia_na) @@ -1701,7 +1701,7 @@ static int ntfs_index_rm_node(ntfs_index_context *icx) ib = ntfs_malloc(icx->block_size); if (!ib) return STATUS_ERROR; - + ie_succ = ntfs_ie_get_next(icx->entry); entry_pos = icx->parent_pos[icx->pindex]++; pindex = icx->pindex; @@ -1709,12 +1709,12 @@ descend: vcn = ntfs_ie_get_vcn(ie_succ); if (ntfs_ib_read(icx, vcn, ib)) goto out; - + ie_succ = ntfs_ie_get_first(&ib->index); if (ntfs_icx_parent_inc(icx)) goto out; - + icx->parent_vcn[icx->pindex] = vcn; icx->parent_pos[icx->pindex] = 0; @@ -1730,7 +1730,7 @@ descend: ie = ntfs_ie_dup(ie_succ); if (!ie) goto out; - + if (ntfs_ie_add_vcn(&ie)) goto out2; @@ -1748,10 +1748,10 @@ descend: ret = ntfs_ir_make_space(icx, new_size); if (ret != STATUS_OK) goto out2; - + ih = &icx->ir->index; entry = ntfs_ie_get_by_pos(ih, entry_pos); - + } else if (new_size > le32_to_cpu(ih->allocated_size)) { icx->pindex = pindex; ret = ntfs_ib_split(icx, icx->ib); @@ -1763,20 +1763,20 @@ descend: ntfs_ie_delete(ih, entry); ntfs_ie_insert(ih, ie, entry); - + if (icx->is_in_root) { if (ntfs_ir_truncate(icx, new_size)) goto out2; } else if (ntfs_icx_ib_write(icx)) goto out2; - + ntfs_ie_delete(&ib->index, ie_succ); - + if (ntfs_ih_zero_entry(&ib->index)) { if (ntfs_index_rm_leaf(icx)) goto out2; - } else + } else if (ntfs_ib_write(icx, ib)) goto out2; @@ -1792,8 +1792,8 @@ out: * ntfs_index_rm - remove entry from the index * @icx: index context describing entry to delete * - * Delete entry described by @icx from the index. Index context is always - * reinitialized after use of this function, so it can be used for index + * Delete entry described by @icx from the index. Index context is always + * reinitialized after use of this function, so it can be used for index * lookup once again. * * Return 0 on success or -1 on error with errno set to the error code. @@ -1805,7 +1805,7 @@ int ntfs_index_rm(ntfs_index_context *icx) int err, ret = STATUS_OK; ntfs_log_trace("Entering\n"); - + if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; @@ -1815,15 +1815,15 @@ int ntfs_index_rm(ntfs_index_context *icx) ih = &icx->ir->index; else ih = &icx->ib->index; - + if (icx->entry->ie_flags & INDEX_ENTRY_NODE) { - + ret = ntfs_index_rm_node(icx); } else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) { - + ntfs_ie_delete(ih, icx->entry); - + if (icx->is_in_root) { err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length)); if (err != STATUS_OK) @@ -1853,7 +1853,7 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, return -1; while (1) { - + if (ntfs_index_lookup(key, keylen, icx)) goto err_out; @@ -1869,13 +1869,13 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni, goto err_out; else if (ret == STATUS_OK) break; - + ntfs_inode_mark_dirty(icx->actx->ntfs_ino); ntfs_index_ctx_reinit(icx); } ntfs_inode_mark_dirty(icx->actx->ntfs_ino); -out: +out: ntfs_index_ctx_put(icx); return ret; err_out: @@ -1887,7 +1887,7 @@ err_out: /** * ntfs_index_root_get - read the index root of an attribute * @ni: open ntfs inode in which the ntfs attribute resides - * @attr: attribute for which we want its index root + * @attr: attribute for which we want its index root * * This function will read the related index root an ntfs attribute. * @@ -1906,14 +1906,14 @@ INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr) if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx)) return NULL; - + root = ntfs_malloc(sizeof(INDEX_ROOT)); if (!root) goto out; - + *root = *((INDEX_ROOT *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset))); -out: +out: ntfs_attr_put_search_ctx(ctx); return root; } @@ -1945,7 +1945,7 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie, } else { /* down from non-zero level */ - + ictx->pindex++; } ictx->parent_pos[ictx->pindex] = 0; diff --git a/libcustomntfs/index.h b/libcustomntfs/source/index.h similarity index 100% rename from libcustomntfs/index.h rename to libcustomntfs/source/index.h diff --git a/libcustomntfs/inode.c b/libcustomntfs/source/inode.c similarity index 96% rename from libcustomntfs/inode.c rename to libcustomntfs/source/inode.c index bdc12a30..a4a01348 100644 --- a/libcustomntfs/inode.c +++ b/libcustomntfs/source/inode.c @@ -124,7 +124,7 @@ ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol) static void __ntfs_inode_release(ntfs_inode *ni) { if (NInoDirty(ni)) - ntfs_log_error("Releasing dirty inode %lld!\n", + ntfs_log_error("Releasing dirty inode %lld!\n", (long long)ni->mft_no); if (NInoAttrList(ni) && ni->attr_list) free(ni->attr_list); @@ -243,7 +243,7 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref) if (l != ni->attr_list_size) { errno = EIO; ntfs_log_perror("Unexpected attrlist size (%lld <> %u), inode " - "%lld", (long long)l, ni->attr_list_size, + "%lld", (long long)l, ni->attr_list_size, (long long)MREF(mref)); goto put_err_out; } @@ -273,7 +273,7 @@ get_size: set_nino_flag(ni,KnownSize); } ntfs_attr_put_search_ctx(ctx); -out: +out: ntfs_log_leave("\n"); return ni; @@ -313,7 +313,7 @@ err_out: int ntfs_inode_real_close(ntfs_inode *ni) { int ret = -1; - + if (!ni) return 0; @@ -365,7 +365,7 @@ int ntfs_inode_real_close(ntfs_inode *ni) */ if (base_ni->nr_extents) { /* Resize the memory buffer. */ - tmp_nis = MEM2_realloc(tmp_nis, base_ni->nr_extents * + tmp_nis = realloc(tmp_nis, base_ni->nr_extents * sizeof(ntfs_inode *)); /* Ignore errors, they don't really matter. */ if (tmp_nis) @@ -378,8 +378,8 @@ int ntfs_inode_real_close(ntfs_inode *ni) i = -1; break; } - - /* + + /* * We could successfully sync, so only log this error * and try to sync other inode extents too. */ @@ -387,7 +387,7 @@ int ntfs_inode_real_close(ntfs_inode *ni) ntfs_log_error("Extent inode %lld was not found\n", (long long)ni->mft_no); } - + __ntfs_inode_release(ni); ret = 0; err: @@ -437,13 +437,12 @@ static int idata_cache_compare(const struct CACHED_GENERIC *cached, void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref) { struct CACHED_NIDATA item; - int count; item.inum = MREF(mref); item.ni = (ntfs_inode*)NULL; item.pathname = (const char*)NULL; item.varsize = 0; - count = ntfs_invalidate_cache(vol->nidata_cache, + ntfs_invalidate_cache(vol->nidata_cache, GENERIC(&item),idata_cache_compare,CACHE_FREE); } @@ -574,6 +573,9 @@ int ntfs_inode_close(ntfs_inode *ni) ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) { u64 mft_no = MREF_LE(mref); + VCN extent_vcn; + runlist_element *rl; + ntfs_volume *vol; ntfs_inode *ni = NULL; ntfs_inode **extent_nis; int i; @@ -583,10 +585,41 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) ntfs_log_perror("%s", __FUNCTION__); return NULL; } - + ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n", (unsigned long long)mft_no, (unsigned long long)base_ni->mft_no); + + if (!base_ni->mft_no) { + /* + * When getting extents of MFT, we must be sure + * they are in the MFT part which has already + * been mapped, otherwise we fall into an endless + * recursion. + * Situations have been met where extents locations + * are described in themselves. + * This is a severe error which chkdsk cannot fix. + */ + vol = base_ni->vol; + extent_vcn = mft_no << vol->mft_record_size_bits + >> vol->cluster_size_bits; + rl = vol->mft_na->rl; + if (rl) { + while (rl->length + && ((rl->vcn + rl->length) <= extent_vcn)) + rl++; + } + if (!rl || (rl->lcn < 0)) { + ntfs_log_error("MFT is corrupt, cannot read" + " its unmapped extent record %lld\n", + (long long)mft_no); + ntfs_log_error("Note : chkdsk cannot fix this," + " try ntfsfix\n"); + errno = EIO; + ni = (ntfs_inode*)NULL; + goto out; + } + } /* Is the extent inode already open and attached to the base inode? */ if (base_ni->nr_extents > 0) { @@ -800,7 +833,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) if (dir_ni) index_ni = dir_ni; else - index_ni = ntfs_inode_open(ni->vol, + index_ni = ntfs_inode_open(ni->vol, le64_to_cpu(fn->parent_directory)); if (!index_ni) { if (!err) @@ -963,8 +996,8 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) } NInoAttrListSetDirty(ni); goto sync_inode; - } - + } + if (na->data_size == ni->attr_list_size) { if (ntfs_attr_pwrite(na, 0, ni->attr_list_size, ni->attr_list) != ni->attr_list_size) { @@ -986,7 +1019,7 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) } ntfs_attr_close(na); } - + sync_inode: /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ if (NInoTestAndClearDirty(ni)) { @@ -1012,8 +1045,8 @@ sync_inode: eni = ni->extent_nis[i]; if (!NInoTestAndClearDirty(eni)) continue; - - if (ntfs_mft_record_write(eni->vol, eni->mft_no, + + if (ntfs_mft_record_write(eni->vol, eni->mft_no, eni->mrec)) { if (!err || errno == EIO) { err = errno; @@ -1033,7 +1066,7 @@ sync_inode: errno = err; ret = -1; } - + ntfs_log_leave("\n"); return ret; } @@ -1102,20 +1135,20 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) } /* Walk through all attributes. */ while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { - + int ale_size; - + if (ctx->attr->type == AT_ATTRIBUTE_LIST) { err = EIO; ntfs_log_perror("Attribute list already present"); goto put_err_out; } - + ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7; al_len += ale_size; - - aln = MEM2_realloc(al, al_len); + + aln = realloc(al, al_len); if (!aln) { err = errno; ntfs_log_perror("Failed to realloc %d bytes", al_len); @@ -1123,9 +1156,9 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) } ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); al = aln; - + memset(ale, 0, ale_size); - + /* Add attribute to attribute list. */ ale->type = ctx->attr->type; ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) + @@ -1192,7 +1225,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni) ntfs_attr_close(na); goto remove_attrlist_record;; } - + ntfs_attr_put_search_ctx(ctx); ntfs_attr_close(na); return 0; @@ -1293,12 +1326,12 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size) * find next, because we don't need such. */ while (ctx->ntfs_ino->mft_no != ni->mft_no) { -retry: +retry: if (ntfs_attr_position(AT_UNUSED, ctx)) goto put_err_out; } - if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && + if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && ctx->attr->type == AT_DATA) goto retry; @@ -1319,10 +1352,10 @@ retry: return 0; } /* - * Reposition to first attribute after $STANDARD_INFORMATION - * and $ATTRIBUTE_LIST instead of simply skipping this attribute - * because in the case when we have got only in-memory attribute - * list then ntfs_attr_lookup will fail when it tries to find + * Reposition to first attribute after $STANDARD_INFORMATION + * and $ATTRIBUTE_LIST instead of simply skipping this attribute + * because in the case when we have got only in-memory attribute + * list then ntfs_attr_lookup will fail when it tries to find * $ATTRIBUTE_LIST. */ ntfs_attr_reinit_search_ctx(ctx); @@ -1364,7 +1397,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) ni->last_data_change_time = now; if (mask & NTFS_UPDATE_CTIME) ni->last_mft_change_time = now; - + NInoFileNameSetDirty(ni); NInoSetDirty(ni); } @@ -1377,7 +1410,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) * Check if the mft record given by @mft_no and @attr contains the bad sector * list. Please note that mft record numbers describing $Badclus extent inodes * will not match the current $Badclus:$Bad check. - * + * * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. * On error return -1 with errno set to the error code. */ @@ -1391,7 +1424,7 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) errno = EINVAL; return -1; } - + if (mft_no != FILE_BadClus) return 0; @@ -1465,7 +1498,7 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size) ret = -ERANGE; } ntfs_attr_put_search_ctx(ctx); - } + } return (ret ? ret : -errno); } diff --git a/libcustomntfs/inode.h b/libcustomntfs/source/inode.h similarity index 100% rename from libcustomntfs/inode.h rename to libcustomntfs/source/inode.h diff --git a/libcustomntfs/layout.h b/libcustomntfs/source/layout.h similarity index 99% rename from libcustomntfs/layout.h rename to libcustomntfs/source/layout.h index daff97d1..c167135f 100644 --- a/libcustomntfs/layout.h +++ b/libcustomntfs/source/layout.h @@ -2223,11 +2223,11 @@ typedef struct { /* The below field is NOT present for the quota defaults entry. */ SID sid; /* The SID of the user/object associated with this quota entry. If this field is missing - then the INDEX_ENTRY is padded with zeros - to multiply of 8 which are not counted in + then the INDEX_ENTRY is padded to a multiple + of 8 with zeros which are not counted in the data_length field. If the sid is present then this structure is padded with zeros to - multiply of 8 and the padding is counted in + a multiple of 8 and the padding is counted in the INDEX_ENTRY's data_length. */ } __attribute__((__packed__)) QUOTA_CONTROL_ENTRY; diff --git a/libcustomntfs/lcnalloc.c b/libcustomntfs/source/lcnalloc.c similarity index 92% rename from libcustomntfs/lcnalloc.c rename to libcustomntfs/source/lcnalloc.c index a27d43a1..23bbb23d 100644 --- a/libcustomntfs/lcnalloc.c +++ b/libcustomntfs/source/lcnalloc.c @@ -48,7 +48,7 @@ /* * Plenty possibilities for big optimizations all over in the cluster - * allocation, however at the moment the dominant bottleneck (~ 90%) is + * allocation, however at the moment the dominant bottleneck (~ 90%) is * the update of the mapping pairs which converges to the cubic Faulhaber's * formula as the function of the number of extents (fragments, runs). */ @@ -74,7 +74,7 @@ static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc) static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc) { ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone); - + if (zone == ZONE_MFT) ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end, &vol->mft_zone_pos, tc); @@ -82,7 +82,7 @@ static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc) ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters, &vol->data1_zone_pos, tc); else /* zone == ZONE_DATA2 */ - ntfs_cluster_set_zone_pos(0, vol->mft_zone_start, + ntfs_cluster_set_zone_pos(0, vol->mft_zone_start, &vol->data2_zone_pos, tc); } @@ -112,15 +112,15 @@ static void update_full_status(ntfs_volume *vol, LCN lcn) } } } - + static s64 max_empty_bit_range(unsigned char *buf, int size) { int i, j, run = 0; int max_range = 0; s64 start_pos = -1; - + ntfs_log_trace("Entering\n"); - + i = 0; while (i < size) { switch (*buf) { @@ -144,42 +144,42 @@ static s64 max_empty_bit_range(unsigned char *buf, int size) break; default : for (j = 0; j < 8; j++) { - + int bit = *buf & (1 << j); - + if (bit) { if (run > max_range) { max_range = run; start_pos = (s64)i * 8 + (j - run); } run = 0; - } else + } else run++; } i++; buf++; - + } } - + if (run > max_range) start_pos = (s64)i * 8 - run; - + return start_pos; } -static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b, +static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b, u8 *writeback) { s64 written; - + ntfs_log_trace("Entering\n"); - + if (!*writeback) return 0; - + *writeback = 0; - + written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b); if (written != size) { if (!written) @@ -220,16 +220,16 @@ static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b, * expanded to cover the start of the volume in order to reserve space for the * mft bitmap attribute. * - * The complexity stems from the need of implementing the mft vs data zoned - * approach and from the fact that we have access to the lcn bitmap via up to - * NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over - * boundaries of two buffers. Further, the fact that the allocator allows for - * caller supplied hints as to the location of where allocation should begin - * and the fact that the allocator keeps track of where in the data zones the - * next natural allocation should occur, contribute to the complexity of the - * function. But it should all be worthwhile, because this allocator: + * The complexity stems from the need of implementing the mft vs data zoned + * approach and from the fact that we have access to the lcn bitmap via up to + * NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over + * boundaries of two buffers. Further, the fact that the allocator allows for + * caller supplied hints as to the location of where allocation should begin + * and the fact that the allocator keeps track of where in the data zones the + * next natural allocation should occur, contribute to the complexity of the + * function. But it should all be worthwhile, because this allocator: * 1) implements MFT zone reservation - * 2) causes reduction in fragmentation. + * 2) causes reduction in fragmentation. * The code is not optimized for speed. */ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, @@ -251,12 +251,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, ntfs_log_enter("Entering with count = 0x%llx, start_lcn = 0x%llx, " "zone = %s_ZONE.\n", (long long)count, (long long) start_lcn, zone == MFT_ZONE ? "MFT" : "DATA"); - + if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na || (s8)zone < FIRST_ZONE || zone > LAST_ZONE) { errno = EINVAL; - ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld", - __FUNCTION__, (long long)start_vcn, + ntfs_log_perror("%s: vcn: %lld, count: %lld, lcn: %lld", + __FUNCTION__, (long long)start_vcn, (long long)count, (long long)start_lcn); goto out; } @@ -281,7 +281,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, */ has_guess = 1; zone_start = start_lcn; - + if (zone_start < 0) { if (zone == DATA_ZONE) zone_start = vol->data1_zone_pos; @@ -289,13 +289,13 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, zone_start = vol->mft_zone_pos; has_guess = 0; } - + used_zone_pos = has_guess ? 0 : 1; - + if (!zone_start || zone_start == vol->mft_zone_start || zone_start == vol->mft_zone_end) pass = 2; - + if (zone_start < vol->mft_zone_start) { zone_end = vol->mft_zone_start; search_zone = ZONE_DATA2; @@ -306,7 +306,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, zone_end = vol->nr_clusters; search_zone = ZONE_DATA1; } - + bmp_pos = zone_start; /* Loop until all clusters are allocated. */ @@ -317,7 +317,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, if (search_zone & vol->full_zones) goto zone_pass_done; last_read_pos = bmp_pos >> 3; - br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, + br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, NTFS_LCNALLOC_BSIZE, buf); if (br <= 0) { if (!br) @@ -334,7 +334,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, lcn = bmp_pos & 7; bmp_pos &= ~7; writeback = 0; - + while (lcn < buf_size) { byte = buf + (lcn >> 3); bit = 1 << (lcn & 7); @@ -352,7 +352,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, } /* First free bit is at lcn + bmp_pos. */ - + /* Reallocate memory if necessary. */ if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) { rlsize += 4096; @@ -364,17 +364,17 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, } rl = trl; } - + /* Allocate the bitmap bit. */ *byte |= bit; writeback = 1; - if (vol->free_clusters <= 0) + if (vol->free_clusters <= 0) ntfs_log_error("Non-positive free clusters " "(%lld)!\n", (long long)vol->free_clusters); - else - vol->free_clusters--; - + else + vol->free_clusters--; + /* * Coalesce with previous run if adjacent LCNs. * Otherwise, append a new run. @@ -382,9 +382,9 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { ntfs_log_debug("Cluster coalesce: prev_lcn: " "%lld lcn: %lld bmp_pos: %lld " - "prev_run_len: %lld\n", - (long long)prev_lcn, - (long long)lcn, (long long)bmp_pos, + "prev_run_len: %lld\n", + (long long)prev_lcn, + (long long)lcn, (long long)bmp_pos, (long long)prev_run_len); rl[rlpos - 1].length = ++prev_run_len; } else { @@ -393,54 +393,54 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, prev_run_len; else { rl[rlpos].vcn = start_vcn; - ntfs_log_debug("Start_vcn: %lld\n", + ntfs_log_debug("Start_vcn: %lld\n", (long long)start_vcn); } - + rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; rl[rlpos].length = prev_run_len = 1; rlpos++; } - - ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n", - (long long)rl[rlpos - 1].vcn, - (long long)rl[rlpos - 1].lcn, + + ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n", + (long long)rl[rlpos - 1].vcn, + (long long)rl[rlpos - 1].lcn, (long long)rl[rlpos - 1].length); /* Done? */ if (!--clusters) { if (used_zone_pos) - ntfs_cluster_update_zone_pos(vol, + ntfs_cluster_update_zone_pos(vol, search_zone, lcn + bmp_pos + 1 + NTFS_LCNALLOC_SKIP); goto done_ret; } - + lcn++; } - + if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) { err = errno; goto err_ret; } - + if (!used_zone_pos) { - + used_zone_pos = 1; - + if (search_zone == ZONE_MFT) zone_start = vol->mft_zone_pos; else if (search_zone == ZONE_DATA1) zone_start = vol->data1_zone_pos; else zone_start = vol->data2_zone_pos; - + if (!zone_start || zone_start == vol->mft_zone_start || zone_start == vol->mft_zone_end) pass = 2; bmp_pos = zone_start; } else bmp_pos += buf_size; - + if (bmp_pos < zone_end) continue; @@ -449,22 +449,22 @@ zone_pass_done: if (pass == 1) { pass = 2; zone_end = zone_start; - + if (search_zone == ZONE_MFT) zone_start = vol->mft_zone_start; else if (search_zone == ZONE_DATA1) zone_start = vol->mft_zone_end; else zone_start = 0; - + /* Sanity check. */ if (zone_end < zone_start) zone_end = zone_start; - + bmp_pos = zone_start; - + continue; - } + } /* pass == 2 */ done_zones_check: done_zones |= search_zone; @@ -473,14 +473,14 @@ done_zones_check: ntfs_log_trace("Switching zone.\n"); pass = 1; if (rlpos) { - LCN tc = rl[rlpos - 1].lcn + + LCN tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP; - + if (used_zone_pos) - ntfs_cluster_update_zone_pos(vol, + ntfs_cluster_update_zone_pos(vol, search_zone, tc); } - + switch (search_zone) { case ZONE_MFT: ntfs_log_trace("Zone switch: mft -> data1\n"); @@ -511,17 +511,17 @@ switch_to_data1_zone: search_zone = ZONE_DATA1; pass = 2; break; } - + bmp_pos = zone_start; - + if (zone_start == zone_end) { ntfs_log_trace("Empty zone, skipped.\n"); goto done_zones_check; } - + continue; } - + ntfs_log_trace("All zones are finished, no space on device.\n"); err = ENOSPC; goto err_ret; @@ -543,7 +543,7 @@ done_err_ret: ntfs_log_perror("Failed to allocate clusters"); rl = NULL; } -out: +out: ntfs_log_leave("\n"); return rl; @@ -585,26 +585,26 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl) ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n", (long long)rl->lcn, (long long)rl->length); - if (rl->lcn >= 0) { + if (rl->lcn >= 0) { update_full_status(vol,rl->lcn); - if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, + if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, rl->length)) { ntfs_log_perror("Cluster deallocation failed " "(%lld, %lld)", - (long long)rl->lcn, + (long long)rl->lcn, (long long)rl->length); goto out; } - nr_freed += rl->length ; + nr_freed += rl->length ; } } ret = 0; out: - vol->free_clusters += nr_freed; + vol->free_clusters += nr_freed; if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!", - (long long)vol->free_clusters, + (long long)vol->free_clusters, (long long)vol->nr_clusters); return ret; } @@ -623,24 +623,24 @@ int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count) ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n", (long long)lcn, (long long)count); - if (lcn >= 0) { + if (lcn >= 0) { update_full_status(vol,lcn); - if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn, + if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn, count)) { ntfs_log_perror("Cluster deallocation failed " "(%lld, %lld)", - (long long)lcn, + (long long)lcn, (long long)count); goto out; } - nr_freed += count; + nr_freed += count; } ret = 0; out: vol->free_clusters += nr_freed; if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!", - (long long)vol->free_clusters, + (long long)vol->free_clusters, (long long)vol->nr_clusters); return ret; } @@ -673,7 +673,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) errno = EINVAL; return -1; } - + ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, " "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, (long long)count, (long long)start_vcn); @@ -687,7 +687,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { errno = EIO; - ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__, + ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__, (long long)rl->lcn); goto leave; } @@ -707,7 +707,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) to_free)) goto leave; nr_freed = to_free; - } + } /* Go to the next run and adjust the number of clusters left to free. */ ++rl; @@ -724,7 +724,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { // FIXME: Eeek! We need rollback! (AIA) errno = EIO; - ntfs_log_perror("%s: Invalid lcn (%lli)", + ntfs_log_perror("%s: Invalid lcn (%lli)", __FUNCTION__, (long long)rl->lcn); goto out; } @@ -760,12 +760,12 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count) ret = nr_freed; out: - vol->free_clusters += nr_freed ; + vol->free_clusters += nr_freed ; if (vol->free_clusters > vol->nr_clusters) ntfs_log_error("Too many free clusters (%lld > %lld)!", - (long long)vol->free_clusters, + (long long)vol->free_clusters, (long long)vol->nr_clusters); -leave: +leave: ntfs_log_leave("\n"); return ret; } diff --git a/libcustomntfs/lcnalloc.h b/libcustomntfs/source/lcnalloc.h similarity index 100% rename from libcustomntfs/lcnalloc.h rename to libcustomntfs/source/lcnalloc.h diff --git a/libcustomntfs/logfile.c b/libcustomntfs/source/logfile.c similarity index 99% rename from libcustomntfs/logfile.c rename to libcustomntfs/source/logfile.c index 0f8bce96..53d8d68e 100644 --- a/libcustomntfs/logfile.c +++ b/libcustomntfs/source/logfile.c @@ -468,7 +468,7 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp) u8 *kaddr = NULL; RESTART_PAGE_HEADER *rstr1_ph = NULL; RESTART_PAGE_HEADER *rstr2_ph = NULL; - int log_page_size, log_page_mask, err; + int log_page_size, err; BOOL logfile_is_empty = TRUE; u8 log_page_bits; @@ -481,7 +481,6 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp) if (size > (s64)MaxLogFileSize) size = MaxLogFileSize; log_page_size = DefaultLogPageSize; - log_page_mask = log_page_size - 1; /* * Use generic_ffs() instead of ffs() to enable the compiler to * optimize log_page_size and log_page_bits into constants. @@ -703,7 +702,7 @@ int ntfs_empty_logfile(ntfs_attr *na) char buf[NTFS_BUF_SIZE]; ntfs_log_trace("Entering.\n"); - + if (NVolLogFileEmpty(na->ni->vol)) return 0; @@ -717,7 +716,7 @@ int ntfs_empty_logfile(ntfs_attr *na) pos = 0; while ((count = na->data_size - pos) > 0) { - + if (count > NTFS_BUF_SIZE) count = NTFS_BUF_SIZE; @@ -733,6 +732,6 @@ int ntfs_empty_logfile(ntfs_attr *na) } NVolSetLogFileEmpty(na->ni->vol); - + return 0; } diff --git a/libcustomntfs/logfile.h b/libcustomntfs/source/logfile.h similarity index 100% rename from libcustomntfs/logfile.h rename to libcustomntfs/source/logfile.h diff --git a/libcustomntfs/logging.c b/libcustomntfs/source/logging.c similarity index 100% rename from libcustomntfs/logging.c rename to libcustomntfs/source/logging.c diff --git a/libcustomntfs/logging.h b/libcustomntfs/source/logging.h similarity index 100% rename from libcustomntfs/logging.h rename to libcustomntfs/source/logging.h diff --git a/libcustomntfs/mem2.h b/libcustomntfs/source/mem2.h similarity index 100% rename from libcustomntfs/mem2.h rename to libcustomntfs/source/mem2.h diff --git a/libcustomntfs/mem_allocate.h b/libcustomntfs/source/mem_allocate.h similarity index 100% rename from libcustomntfs/mem_allocate.h rename to libcustomntfs/source/mem_allocate.h diff --git a/libcustomntfs/mft.c b/libcustomntfs/source/mft.c similarity index 99% rename from libcustomntfs/mft.c rename to libcustomntfs/source/mft.c index e93c6646..0640efe9 100644 --- a/libcustomntfs/mft.c +++ b/libcustomntfs/source/mft.c @@ -216,8 +216,10 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref, int ret = -1; if (!ntfs_is_file_record(m->magic)) { - ntfs_log_error("Record %llu has no FILE magic (0x%x)\n", - (unsigned long long)MREF(mref), *(le32 *)m); + if (!NVolNoFixupWarn(vol)) + ntfs_log_error("Record %llu has no FILE magic (0x%x)\n", + (unsigned long long)MREF(mref), + (int)le32_to_cpu(*(le32*)m)); goto err_out; } @@ -1190,7 +1192,7 @@ undo_alloc: static int ntfs_mft_record_init(ntfs_volume *vol, s64 size) { int ret = -1; - ntfs_attr *mft_na, *mftbmp_na; + ntfs_attr *mft_na; s64 old_data_initialized, old_data_size; ntfs_attr_search_ctx *ctx; @@ -1199,7 +1201,6 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size) /* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */ mft_na = vol->mft_na; - mftbmp_na = vol->mftbmp_na; /* * The mft record is outside the initialized data. Extend the mft data @@ -1295,14 +1296,13 @@ undo_data_init: static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size) { int ret = -1; - ntfs_attr *mft_na, *mftbmp_na; + ntfs_attr *mft_na; s64 old_data_initialized, old_data_size; ntfs_attr_search_ctx *ctx; ntfs_log_enter("Entering\n"); mft_na = vol->mft_na; - mftbmp_na = vol->mftbmp_na; if (size > mft_na->allocated_size || size > mft_na->initialized_size) { errno = EIO; diff --git a/libcustomntfs/mft.h b/libcustomntfs/source/mft.h similarity index 100% rename from libcustomntfs/mft.h rename to libcustomntfs/source/mft.h diff --git a/libcustomntfs/misc.c b/libcustomntfs/source/misc.c similarity index 100% rename from libcustomntfs/misc.c rename to libcustomntfs/source/misc.c diff --git a/libcustomntfs/misc.h b/libcustomntfs/source/misc.h similarity index 100% rename from libcustomntfs/misc.h rename to libcustomntfs/source/misc.h diff --git a/libcustomntfs/mst.c b/libcustomntfs/source/mst.c similarity index 94% rename from libcustomntfs/mst.c rename to libcustomntfs/source/mst.c index 470942d6..b7937b7a 100644 --- a/libcustomntfs/mst.c +++ b/libcustomntfs/source/mst.c @@ -47,7 +47,8 @@ * EIO Multi sector transfer error was detected. Magic of the NTFS * record in @b will have been set to "BAAD". */ -int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) +int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size, + BOOL warn) { u16 usa_ofs, usa_count, usn; u16 *usa_pos, *data_pos; @@ -63,9 +64,14 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) (u32)(usa_ofs + (usa_count * 2)) > size || (size >> NTFS_BLOCK_SIZE_BITS) != usa_count) { errno = EINVAL; - ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d " - "usa_count: %d", __FUNCTION__, *(le32 *)b, - size, usa_ofs, usa_count); + if (warn) { + ntfs_log_perror("%s: magic: 0x%08lx size: %ld " + " usa_ofs: %d usa_count: %u", + __FUNCTION__, + (long)le32_to_cpu(*(le32 *)b), + (long)size, (int)usa_ofs, + (unsigned int)usa_count); + } return -1; } /* Position of usn in update sequence array. */ @@ -118,6 +124,16 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) return 0; } +/* + * Deprotect multi sector transfer protected data + * with a warning if an error is found. + */ + +int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) +{ + return (ntfs_mst_post_read_fixup_warn(b,size,TRUE)); +} + /** * ntfs_mst_pre_write_fixup - apply multi sector transfer protection * @b: pointer to the data to protect diff --git a/libcustomntfs/mst.h b/libcustomntfs/source/mst.h similarity index 92% rename from libcustomntfs/mst.h rename to libcustomntfs/source/mst.h index ca813821..d6ca6f27 100644 --- a/libcustomntfs/mst.h +++ b/libcustomntfs/source/mst.h @@ -25,8 +25,11 @@ #include "types.h" #include "layout.h" +#include "volume.h" extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size); +extern int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size, + BOOL warn); extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size); extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b); diff --git a/libcustomntfs/ntfs.c b/libcustomntfs/source/ntfs.c similarity index 100% rename from libcustomntfs/ntfs.c rename to libcustomntfs/source/ntfs.c diff --git a/libcustomntfs/ntfs.h b/libcustomntfs/source/ntfs.h similarity index 100% rename from libcustomntfs/ntfs.h rename to libcustomntfs/source/ntfs.h diff --git a/libcustomntfs/ntfsdir.c b/libcustomntfs/source/ntfsdir.c similarity index 100% rename from libcustomntfs/ntfsdir.c rename to libcustomntfs/source/ntfsdir.c diff --git a/libcustomntfs/ntfsdir.h b/libcustomntfs/source/ntfsdir.h similarity index 100% rename from libcustomntfs/ntfsdir.h rename to libcustomntfs/source/ntfsdir.h diff --git a/libcustomntfs/ntfsfile.c b/libcustomntfs/source/ntfsfile.c similarity index 100% rename from libcustomntfs/ntfsfile.c rename to libcustomntfs/source/ntfsfile.c diff --git a/libcustomntfs/ntfsfile.h b/libcustomntfs/source/ntfsfile.h similarity index 100% rename from libcustomntfs/ntfsfile.h rename to libcustomntfs/source/ntfsfile.h diff --git a/libcustomntfs/ntfsfile_frag.c b/libcustomntfs/source/ntfsfile_frag.c similarity index 100% rename from libcustomntfs/ntfsfile_frag.c rename to libcustomntfs/source/ntfsfile_frag.c diff --git a/libcustomntfs/ntfsfile_frag.h b/libcustomntfs/source/ntfsfile_frag.h similarity index 100% rename from libcustomntfs/ntfsfile_frag.h rename to libcustomntfs/source/ntfsfile_frag.h diff --git a/libcustomntfs/ntfsinternal.c b/libcustomntfs/source/ntfsinternal.c similarity index 100% rename from libcustomntfs/ntfsinternal.c rename to libcustomntfs/source/ntfsinternal.c diff --git a/libcustomntfs/ntfsinternal.h b/libcustomntfs/source/ntfsinternal.h similarity index 100% rename from libcustomntfs/ntfsinternal.h rename to libcustomntfs/source/ntfsinternal.h diff --git a/libcustomntfs/ntfstime.h b/libcustomntfs/source/ntfstime.h similarity index 94% rename from libcustomntfs/ntfstime.h rename to libcustomntfs/source/ntfstime.h index 426269d7..21c222d9 100644 --- a/libcustomntfs/ntfstime.h +++ b/libcustomntfs/source/ntfstime.h @@ -36,6 +36,18 @@ #include "types.h" +#ifndef GEKKO +/* + * assume "struct timespec" is not defined if st_mtime is not defined + */ +#if !defined(st_mtime) & !defined(__timespec_defined) +struct timespec { + time_t tv_sec; + long tv_nsec; +} ; +#endif +#endif + /* * There are four times more conversions of internal representation * to ntfs representation than any other conversion, so the most diff --git a/libcustomntfs/object_id.c b/libcustomntfs/source/object_id.c similarity index 99% rename from libcustomntfs/object_id.c rename to libcustomntfs/source/object_id.c index 8799ddba..059e8822 100644 --- a/libcustomntfs/object_id.c +++ b/libcustomntfs/source/object_id.c @@ -287,7 +287,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo, if (size >= (s64)sizeof(GUID)) { memcpy(&key.object_id, &old_attr->object_id,sizeof(GUID)); - size = sizeof(GUID); if (!ntfs_index_lookup(&key, sizeof(OBJECT_ID_INDEX_KEY), xo)) { entry = (struct OBJECT_ID_INDEX*)xo->entry; @@ -300,7 +299,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo, memcpy(&old_attr->domain_id, &entry->data.domain_id, sizeof(GUID)); - size = sizeof(OBJECT_ID_ATTR); if (ntfs_index_rm(xo)) ret = -1; } diff --git a/libcustomntfs/object_id.h b/libcustomntfs/source/object_id.h similarity index 100% rename from libcustomntfs/object_id.h rename to libcustomntfs/source/object_id.h diff --git a/libcustomntfs/param.h b/libcustomntfs/source/param.h similarity index 86% rename from libcustomntfs/param.h rename to libcustomntfs/source/param.h index 7420c79f..c3675b72 100644 --- a/libcustomntfs/param.h +++ b/libcustomntfs/source/param.h @@ -50,6 +50,19 @@ enum { /* maximum cluster size for allowing compression for new files */ #define MAX_COMPRESSION_CLUSTER_SIZE 4096 +/* + * Use of big write buffers + * + * With small volumes, the cluster allocator may fail to allocate + * enough clusters when the volume is nearly full. At most a run + * can be allocated per bitmap chunk. So, there is a danger when the + * number of chunks (capacity/(32768*clsiz)) is less than the number + * of clusters in the biggest write buffer (131072/clsiz). Hence + * a safe minimal capacity is 4GB + */ + +#define SAFE_CAPACITY_FOR_BIG_WRITES 0x100000000LL + /* * Parameters for runlists */ @@ -63,6 +76,11 @@ enum { #define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */ +/* + * Parameters for path canonicalization + */ + +#define MAPPERNAMELTH 256 /* * Permission checking modes for high level and low level diff --git a/libcustomntfs/source/realpath.c b/libcustomntfs/source/realpath.c new file mode 100644 index 00000000..a93bc698 --- /dev/null +++ b/libcustomntfs/source/realpath.c @@ -0,0 +1,103 @@ +/* + * realpath.c - realpath() aware of device mapper + * Originated from the util-linux project. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif + +#include "param.h" +#include "realpath.h" + +/* If there is no realpath() on the system, provide a dummy one. */ +#ifndef HAVE_REALPATH +char *ntfs_realpath(const char *path, char *resolved_path) +{ + strncpy(resolved_path, path, PATH_MAX); + resolved_path[PATH_MAX] = '\0'; + return resolved_path; +} +#endif + + +#ifdef linux + +/* + * Converts private "dm-N" names to "/dev/mapper/" + * + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block//dm/name + */ +static char * +canonicalize_dm_name(const char *ptname, char *canonical) +{ + FILE *f; + size_t sz; + char path[MAPPERNAMELTH + 24]; + char name[MAPPERNAMELTH + 16]; + char *res = NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if (!(f = fopen(path, "r"))) + return NULL; + + /* read "\n" from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { + name[sz - 1] = '\0'; + snprintf(path, sizeof(path), "/dev/mapper/%s", name); + res = strcpy(canonical, path); + } + fclose(f); + return res; +} + +/* + * Canonicalize a device path + * + * Workaround from "basinilya" for fixing device mapper paths. + * + * Background (Phillip Susi, 2011-04-09) + * - ntfs-3g canonicalizes the device name so that if you mount with + * /dev/mapper/foo, the device name listed in mtab is /dev/dm-n, + * so you can not umount /dev/mapper/foo + * - umount won't even recognize and translate /dev/dm-n to the mount + * point, apparently because of the '-' involved. Editing mtab and + * removing the '-' allows you to umount /dev/dmn successfully. + * + * This code restores the devmapper name after canonicalization, + * until a proper fix is implemented. + */ + +char *ntfs_realpath_canonicalize(const char *path, char *canonical) +{ + char *p; + + if (path == NULL) + return NULL; + + if (!ntfs_realpath(path, canonical)) + return NULL; + + p = strrchr(canonical, '/'); + if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { + p = canonicalize_dm_name(p+1, canonical); + if (p) + return p; + } + + return canonical; +} + +#endif diff --git a/libcustomntfs/source/realpath.h b/libcustomntfs/source/realpath.h new file mode 100644 index 00000000..970d2af8 --- /dev/null +++ b/libcustomntfs/source/realpath.h @@ -0,0 +1,24 @@ +/* + * realpath.h - realpath() aware of device mapper + */ + +#ifndef REALPATH_H +#define REALPATH_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_REALPATH +#define ntfs_realpath realpath +#else +extern char *ntfs_realpath(const char *path, char *resolved_path); +#endif + +#ifdef linux +extern char *ntfs_realpath_canonicalize(const char *path, char *resolved_path); +#else +#define ntfs_realpath_canonicalize ntfs_realpath +#endif + +#endif /* REALPATH_H */ diff --git a/libcustomntfs/reparse.c b/libcustomntfs/source/reparse.c similarity index 100% rename from libcustomntfs/reparse.c rename to libcustomntfs/source/reparse.c diff --git a/libcustomntfs/reparse.h b/libcustomntfs/source/reparse.h similarity index 100% rename from libcustomntfs/reparse.h rename to libcustomntfs/source/reparse.h diff --git a/libcustomntfs/runlist.c b/libcustomntfs/source/runlist.c similarity index 99% rename from libcustomntfs/runlist.c rename to libcustomntfs/source/runlist.c index 383a80b2..7e158d44 100644 --- a/libcustomntfs/runlist.c +++ b/libcustomntfs/source/runlist.c @@ -136,9 +136,10 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl, if (!newrl) { errno = ENOMEM; rl = (runlist_element*)NULL; - } else + } else { na->rl = newrl; rl = &newrl[irl]; + } } else { ntfs_log_error("Cannot extend unmapped runlist"); errno = EIO; @@ -1623,7 +1624,7 @@ errno_set: int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) { runlist *rl; - BOOL is_end = FALSE; + /* BOOL is_end = FALSE; */ if (!arl || !*arl) { errno = EINVAL; @@ -1666,8 +1667,10 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) */ if (rl->length) { ++rl; +/* if (!rl->length) is_end = TRUE; +*/ rl->vcn = start_vcn; rl->length = 0; } @@ -1675,7 +1678,7 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn) /** * Reallocate memory if necessary. * FIXME: Below code is broken, because runlist allocations must be - * a multiply of 4096. The code caused crashes and corruptions. + * a multiple of 4096. The code caused crashes and corruptions. */ /* if (!is_end) { diff --git a/libcustomntfs/runlist.h b/libcustomntfs/source/runlist.h similarity index 100% rename from libcustomntfs/runlist.h rename to libcustomntfs/source/runlist.h diff --git a/libcustomntfs/security.c b/libcustomntfs/source/security.c similarity index 99% rename from libcustomntfs/security.c rename to libcustomntfs/source/security.c index c7a87efb..5e70c214 100644 --- a/libcustomntfs/security.c +++ b/libcustomntfs/source/security.c @@ -127,8 +127,8 @@ struct SDH { /* this is an image of an $SDH index entry */ static ntfschar sii_stream[] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), - const_cpu_to_le16('I'), - const_cpu_to_le16('I'), + const_cpu_to_le16('I'), + const_cpu_to_le16('I'), const_cpu_to_le16(0) }; static ntfschar sdh_stream[] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'), @@ -684,7 +684,7 @@ static le32 entersecurityattr(ntfs_volume *vol, retries = 0; while (entry) { next = ntfs_index_next(entry,xsii); - if (next) { + if (next) { psii = (struct SII*)next; /* save last key and */ /* available position */ @@ -1024,7 +1024,7 @@ static int update_secur_descr(ntfs_volume *vol, * This is intended to allow graceful upgrades for files which * were created in previous versions, with a security attributes * and no security id. - * + * * It will allocate a security id and replace the individual * security attribute by a reference to the global one * @@ -1064,7 +1064,6 @@ static int upgrade_secur_desc(ntfs_volume *vol, na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0); if (na) { - res = 0; /* expand standard information attribute to v3.x */ res = ntfs_attr_truncate(na, (s64)sizeof(STANDARD_INFORMATION)); @@ -1373,7 +1372,7 @@ static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached, /* * Resize permission cache table * do not call unless resizing is needed - * + * * If allocation fails, the cache size is not updated * Lack of memory is not considered as an error, the cache is left * consistent and errno is not set. @@ -1469,7 +1468,7 @@ static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, if (pxdesc) { pxsize = sizeof(struct POSIX_SECURITY) + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); - pxcached = (struct POSIX_SECURITY*)ntfs_malloc(pxsize); + pxcached = (struct POSIX_SECURITY*)malloc(pxsize); if (pxcached) { memcpy(pxcached, pxdesc, pxsize); cacheentry->pxdesc = pxcached; @@ -1500,7 +1499,7 @@ static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, /* allocate block, if cache table was allocated */ if (pcache && (index1 <= pcache->head.last)) { cacheblock = (struct CACHED_PERMISSIONS*) - ntfs_malloc(sizeof(struct CACHED_PERMISSIONS) + malloc(sizeof(struct CACHED_PERMISSIONS) << CACHE_PERMISSIONS_BITS); pcache->cachetable[index1] = cacheblock; for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++) @@ -1513,7 +1512,7 @@ static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx, if (pxdesc) { pxsize = sizeof(struct POSIX_SECURITY) + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE); - pxcached = (struct POSIX_SECURITY*)ntfs_malloc(pxsize); + pxcached = (struct POSIX_SECURITY*)malloc(pxsize); if (pxcached) { memcpy(pxcached, pxdesc, pxsize); cacheentry->pxdesc = pxcached; @@ -2003,7 +2002,7 @@ static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, */ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, - const char *name, char *value, size_t size) + const char *name, char *value, size_t size) { const SECURITY_DESCRIPTOR_RELATIVE *phead; struct POSIX_SECURITY *pxdesc; @@ -2013,7 +2012,6 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, const SID *gsid; /* group of file/directory */ uid_t uid; gid_t gid; - int perm; BOOL isdir; size_t outsize; @@ -2048,7 +2046,6 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, * fetch owner and group for cacheing */ if (pxdesc) { - perm = pxdesc->mode & 07777; /* * Create a security id if there were none * and upgrade option is selected @@ -2062,11 +2059,10 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, #if OWNERFROMACL uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); #else - if (!perm && ntfs_same_sid(usid, adminsid)) { + if (!(pxdesc->mode & 07777) + && ntfs_same_sid(usid, adminsid)) { uid = find_tenant(scx, securattr); - if (uid) - perm = 0700; } else uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); #endif @@ -2344,7 +2340,7 @@ int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx, stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); #else if (!perm && ntfs_same_sid(usid, adminsid)) { - stbuf->st_uid = + stbuf->st_uid = find_tenant(scx, securattr); if (stbuf->st_uid) @@ -2456,7 +2452,7 @@ static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx, /* * Allocate a security_id for a file being created - * + * * Returns zero if not possible (NTFS v3.x required) */ @@ -2678,7 +2674,7 @@ le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, /* * Update ownership and mode of a file, reusing an existing * security descriptor when possible - * + * * Returns zero if successful */ @@ -2893,7 +2889,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, uid_t uid; uid_t gid; int res; - mode_t mode; BOOL isdir; BOOL deflt; BOOL exist; @@ -2919,7 +2914,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, gid = cached->gid; oldpxdesc = cached->pxdesc; if (oldpxdesc) { - mode = oldpxdesc->mode; newpxdesc = ntfs_replace_acl(oldpxdesc, (const struct POSIX_ACL*)value,count,deflt); } @@ -2946,7 +2940,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, || (!exist && (flags & XATTR_REPLACE))) { errno = (exist ? EEXIST : ENODATA); } else { - mode = oldpxdesc->mode; newpxdesc = ntfs_replace_acl(oldpxdesc, (const struct POSIX_ACL*)value,count,deflt); } @@ -3092,7 +3085,7 @@ int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode) /* must copy before merging */ pxsize = sizeof(struct POSIX_SECURITY) + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); - newpxdesc = (struct POSIX_SECURITY*)ntfs_malloc(pxsize); + newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); if (newpxdesc) { memcpy(newpxdesc, oldpxdesc, pxsize); if (ntfs_merge_mode_posix(newpxdesc, mode)) @@ -3180,7 +3173,7 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) ACCESS_ALLOWED_ACE *ace; SID *sid; int ret, sd_len; - + /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */ /* * Calculate security descriptor length. We have 2 sub-authorities in @@ -3188,14 +3181,14 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) * 4 bytes to every SID. */ sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) + - sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len); if (!sd) return -1; - + sd->revision = SECURITY_DESCRIPTOR_REVISION; sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE; - + sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR)); sid->revision = SID_REVISION; sid->sub_authority_count = 2; @@ -3203,21 +3196,21 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); sid->identifier_authority.value[5] = 5; sd->owner = cpu_to_le32((u8*)sid - (u8*)sd); - - sid = (SID*)((u8*)sid + sizeof(SID) + 4); + + sid = (SID*)((u8*)sid + sizeof(SID) + 4); sid->revision = SID_REVISION; sid->sub_authority_count = 2; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); sid->identifier_authority.value[5] = 5; sd->group = cpu_to_le32((u8*)sid - (u8*)sd); - + acl = (ACL*)((u8*)sid + sizeof(SID) + 4); acl->revision = ACL_REVISION; acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)); acl->ace_count = const_cpu_to_le16(1); sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd); - + ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; @@ -3232,7 +3225,7 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) sd_len); if (ret) ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR"); - + free(sd); return ret; } @@ -3331,7 +3324,7 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, * * Returns true if access is allowed, including user is root and * no user mapping defined - * + * * Sets errno if there is a problem or if not allowed * * This is used for Posix ACL and checking creation of DOS file names @@ -3479,7 +3472,7 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, if (uid && (fileuid != uid)) mode &= 01777; #if POSIXACLS - res = ntfs_set_owner_mode(scx, ni, uid, gid, + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode, pxdesc); #else res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); @@ -3513,16 +3506,16 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, uid_t uid, gid_t gid, const mode_t mode) { - const SECURITY_DESCRIPTOR_RELATIVE *phead; const struct CACHED_PERMISSIONS *cached; char *oldattr; - const SID *usid; - const SID *gsid; uid_t fileuid; uid_t filegid; - BOOL isdir; int res; #if POSIXACLS + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const SID *usid; + const SID *gsid; + BOOL isdir; const struct POSIX_SECURITY *oldpxdesc; struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL; int pxsize; @@ -3541,7 +3534,7 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, /* must copy before merging */ pxsize = sizeof(struct POSIX_SECURITY) + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE); - newpxdesc = (struct POSIX_SECURITY*)ntfs_malloc(pxsize); + newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize); if (newpxdesc) { memcpy(newpxdesc, oldpxdesc, pxsize); if (ntfs_merge_mode_posix(newpxdesc, mode)) @@ -3555,6 +3548,7 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, filegid = 0; oldattr = getsecurityattr(scx->vol, ni); if (oldattr) { +#if POSIXACLS isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); phead = (const SECURITY_DESCRIPTOR_RELATIVE*) @@ -3567,7 +3561,6 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, usid = (const SID*) &oldattr[le32_to_cpu(phead->owner)]; #endif -#if POSIXACLS newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr, usid, gsid, isdir); if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode)) @@ -3595,7 +3588,7 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, if ((int)gid < 0) gid = filegid; #if POSIXACLS - res = ntfs_set_owner_mode(scx, ni, uid, gid, + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode, newpxdesc); #else res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); @@ -3826,9 +3819,9 @@ static int link_single_group(struct MAPPING *usermapping, struct passwd *user, grmem++; if (*grmem) { if (!grcnt) - groups = (gid_t*)ntfs_malloc(sizeof(gid_t)); + groups = (gid_t*)malloc(sizeof(gid_t)); else - groups = (gid_t*)MEM2_realloc(groups, + groups = (gid_t*)realloc(groups, (grcnt+1)*sizeof(gid_t)); if (groups) groups[grcnt++] = gid; @@ -4238,7 +4231,7 @@ void ntfs_close_secure(struct SECURITY_CONTEXT *scx) ntfs_index_ctx_put(vol->secure_xsii); ntfs_index_ctx_put(vol->secure_xsdh); ntfs_inode_close(vol->secure_ni); - + } ntfs_free_mapping(scx->mapping); free_caches(scx); @@ -4784,6 +4777,7 @@ BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, ni->flags = (ni->flags & ~settable) | (cpu_to_le32(attrib) & settable); NInoSetDirty(ni); + NInoFileNameSetDirty(ni); } if (!ntfs_inode_close(ni)) res = -1; diff --git a/libcustomntfs/security.h b/libcustomntfs/source/security.h similarity index 100% rename from libcustomntfs/security.h rename to libcustomntfs/source/security.h diff --git a/libcustomntfs/support.h b/libcustomntfs/source/support.h similarity index 100% rename from libcustomntfs/support.h rename to libcustomntfs/source/support.h diff --git a/libcustomntfs/types.h b/libcustomntfs/source/types.h similarity index 99% rename from libcustomntfs/types.h rename to libcustomntfs/source/types.h index 77758eaf..fcd13604 100644 --- a/libcustomntfs/types.h +++ b/libcustomntfs/source/types.h @@ -1,5 +1,5 @@ /* - * types.h - Misc type definitions not related to on-disk structure. + * types.h - Misc type definitions not related to on-disk structure. * Originated from the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov diff --git a/libcustomntfs/unistr.c b/libcustomntfs/source/unistr.c similarity index 98% rename from libcustomntfs/unistr.c rename to libcustomntfs/source/unistr.c index 343e7a34..c033ee12 100644 --- a/libcustomntfs/unistr.c +++ b/libcustomntfs/source/unistr.c @@ -432,18 +432,18 @@ void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr, so this patch fixes the resulting issues for systems which use UTF-8 and for others, specifying the locale in fstab brings them the encoding which they want. - + If no locale is defined or there was a problem with setting one up and whenever nl_langinfo(CODESET) returns a sting starting with "ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix the bug where NTFS-3G does not show any path names which include international characters!!! (and also fails on creating them) as result. - + Author: Bernhard Kaindl Jean-Pierre Andre made it compliant with RFC3629/RFC2781. */ - -/* + +/* * Return the amount of 8-bit elements in UTF-8 needed (without the terminating * null) to store a given UTF-16LE string. * @@ -462,7 +462,7 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l if ((c >= 0xdc00) && (c < 0xe000)) { surrog = FALSE; count += 4; - } else + } else goto fail; } else if (c < 0x80) @@ -479,14 +479,14 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l else if (c >= 0xe000) #endif count += 3; - else + else goto fail; if (count > outs_len) { errno = ENAMETOOLONG; goto out; } } - if (surrog) + if (surrog) goto fail; ret = count; @@ -548,7 +548,7 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len, *t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4); *t++ = 0x80 + (c & 63); halfpair = 0; - } else + } else goto fail; } else if (c < 0x80) { *t++ = c; @@ -566,12 +566,12 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len, *t++ = 0xe0 | (c >> 12); *t++ = 0x80 | ((c >> 6) & 0x3f); *t++ = 0x80 | (c & 0x3f); - } else + } else goto fail; } } *t = '\0'; - + #if defined(__APPLE__) || defined(__DARWIN__) #ifdef ENABLE_NFCONV if(nfconvert_utf8 && (t - *outs) > 0) { @@ -600,7 +600,7 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len, } #endif /* ENABLE_NFCONV */ #endif /* defined(__APPLE__) || defined(__DARWIN__) */ - + ret = t - *outs; out: return ret; @@ -609,8 +609,8 @@ fail: goto out; } -/* - * Return the amount of 16-bit elements in UTF-16LE needed +/* + * Return the amount of 16-bit elements in UTF-16LE needed * (without the terminating null) to store given UTF-8 string. * * Return -1 with errno set if it's longer than PATH_MAX or string is invalid. @@ -625,22 +625,22 @@ static int utf8_to_utf16_size(const char *s) size_t count = 0; while ((byte = *((const unsigned char *)s++))) { - if (++count >= PATH_MAX) + if (++count >= PATH_MAX) goto fail; if (byte >= 0xc0) { if (byte >= 0xF5) { errno = EILSEQ; goto out; } - if (!*s) + if (!*s) break; - if (byte >= 0xC0) + if (byte >= 0xC0) s++; - if (!*s) + if (!*s) break; - if (byte >= 0xE0) + if (byte >= 0xE0) s++; - if (!*s) + if (!*s) break; if (byte >= 0xF0) { s++; @@ -656,11 +656,11 @@ fail: errno = ENAMETOOLONG; goto out; } -/* +/* * This converts one UTF-8 sequence to cpu-endian Unicode value * within range U+0 .. U+10ffff and excluding U+D800 .. U+DFFF * - * Return the number of used utf8 bytes or -1 with errno set + * Return the number of used utf8 bytes or -1 with errno set * if sequence is invalid. */ static int utf8_to_unicode(u32 *wc, const char *s) @@ -726,7 +726,7 @@ fail: * @ins: input multibyte string buffer * @outs: on return contains the (allocated) output utf16 string * @outs_len: length of output buffer in utf16 characters - * + * * Return -1 with errno set. */ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs) @@ -787,7 +787,7 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs) } t += m; } - + ret = --outpos - *outs; fail: #if defined(__APPLE__) || defined(__DARWIN__) @@ -930,7 +930,7 @@ err_out: * Convert the input multibyte string @ins, from the current locale into the * corresponding little endian, 2-byte Unicode string. * - * The function allocates the string and the caller is responsible for calling + * The function allocates the string and the caller is responsible for calling * free(*@outs); when finished with it. * * On success the function returns the number of Unicode characters written to @@ -961,7 +961,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs) errno = EINVAL; return -1; } - + if (use_utf8) return ntfs_utf8_to_utf16(ins, outs); @@ -1137,8 +1137,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) * value of "Add" added to it. */ static int uc_run_table[][3] = { /* Start, End, Add */ - {0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32}, - {0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130}, + {0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32}, + {0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130}, {0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32}, {0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64}, {0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80}, @@ -1262,7 +1262,7 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len) u32 ntfs_upcase_build_default(ntfschar **upcase) { - u32 upcase_len; + u32 upcase_len = 0; *upcase = (ntfschar*)ntfs_malloc(UPCASE_LEN*2); if (*upcase) { @@ -1310,12 +1310,12 @@ ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt) * @len: length of output buffer in Unicode characters * * Convert the input @s string into the corresponding little endian, - * 2-byte Unicode string. The length of the converted string is less + * 2-byte Unicode string. The length of the converted string is less * or equal to the maximum length allowed by the NTFS format (255). * * If @s is NULL then return AT_UNNAMED. * - * On success the function returns the Unicode string in an allocated + * On success the function returns the Unicode string in an allocated * buffer and the caller is responsible to free it when it's not needed * anymore. * @@ -1406,16 +1406,18 @@ BOOL ntfs_collapsible_chars(ntfs_volume *vol, { BOOL collapsible; unsigned int ch; + unsigned int cs; int i; collapsible = shortlen == longlen; - if (collapsible) - for (i=0; i= vol->upcase_len) - || ((shortname[i] != longname[i]) - && (shortname[i] != vol->upcase[ch]))) - collapsible = FALSE; + for (i=0; collapsible && (i= vol->upcase_len) + || (cs >= vol->upcase_len) + || (vol->upcase[cs] != vol->upcase[ch]))) + collapsible = FALSE; } return (collapsible); } @@ -1454,7 +1456,7 @@ int ntfs_macosx_normalize_filenames(int normalize) { #else return -1; #endif /* ENABLE_NFCONV */ -} +} int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, int composed) { @@ -1466,14 +1468,14 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, CFIndex requiredBufferLength; char *result = NULL; int resultLength = -1; - + /* Convert the UTF-8 string to a CFString. */ cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8); if(cfSourceString == NULL) { ntfs_log_error("CFStringCreateWithCString failed!\n"); return -2; } - + /* Create a mutable string from cfSourceString that we are free to modify. */ cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfSourceString); CFRelease(cfSourceString); /* End-of-life. */ @@ -1481,16 +1483,16 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, ntfs_log_error("CFStringCreateMutableCopy failed!\n"); return -3; } - + /* Normalize the mutable string to the desired normalization form. */ CFStringNormalize(cfMutableString, (composed != 0 ? kCFStringNormalizationFormC : kCFStringNormalizationFormD)); - + /* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */ rangeToProcess = CFRangeMake(0, CFStringGetLength(cfMutableString)); if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) { resultLength = sizeof(char)*(requiredBufferLength + 1); result = ntfs_calloc(resultLength); - + if(result != NULL) { if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) { @@ -1505,9 +1507,9 @@ int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target, else ntfs_log_error("Could not perform check for required length of UTF-8 conversion of normalized CFMutableString.\n"); - + CFRelease(cfMutableString); - + if(result != NULL) { *target = result; return resultLength - 1; diff --git a/libcustomntfs/unistr.h b/libcustomntfs/source/unistr.h similarity index 100% rename from libcustomntfs/unistr.h rename to libcustomntfs/source/unistr.h diff --git a/libcustomntfs/volume.c b/libcustomntfs/source/volume.c similarity index 94% rename from libcustomntfs/volume.c rename to libcustomntfs/source/volume.c index 28e4c907..a18109f1 100644 --- a/libcustomntfs/volume.c +++ b/libcustomntfs/source/volume.c @@ -54,6 +54,7 @@ #include #endif +#include "param.h" #include "compat.h" #include "volume.h" #include "attrib.h" @@ -67,6 +68,7 @@ #include "dir.h" #include "logging.h" #include "cache.h" +#include "realpath.h" #include "misc.h" const char *ntfs_home = @@ -373,6 +375,12 @@ mft_has_no_attr_list: /* Done with the $Mft mft record. */ ntfs_attr_put_search_ctx(ctx); ctx = NULL; + + /* Update the size fields in the inode. */ + vol->mft_ni->data_size = vol->mft_na->data_size; + vol->mft_ni->allocated_size = vol->mft_na->allocated_size; + set_nino_flag(vol->mft_ni, KnownSize); + /* * The volume is now setup so we can use all read access functions. */ @@ -494,6 +502,12 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags) NVolSetShowSysFiles(vol); NVolSetShowHidFiles(vol); NVolClearHideDotFiles(vol); + /* set default compression */ +#if DEFAULT_COMPRESSION + NVolSetCompression(vol); +#else + NVolClearCompression(vol); +#endif if (flags & MS_RDONLY) NVolSetReadOnly(vol); @@ -1359,18 +1373,6 @@ int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused))) #ifdef HAVE_MNTENT_H -#ifndef HAVE_REALPATH -/** - * realpath - If there is no realpath on the system - */ -static char *realpath(const char *path, char *resolved_path) -{ - strncpy(resolved_path, path, PATH_MAX); - resolved_path[PATH_MAX] = '\0'; - return resolved_path; -} -#endif - /** * ntfs_mntent_check - desc * @@ -1394,7 +1396,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) err = errno; goto exit; } - if (!realpath(file, real_file)) { + if (!ntfs_realpath_canonicalize(file, real_file)) { err = errno; goto exit; } @@ -1403,7 +1405,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) goto exit; } while ((mnt = getmntent(f))) { - if (!realpath(mnt->mnt_fsname, real_fsname)) + if (!ntfs_realpath_canonicalize(mnt->mnt_fsname, real_fsname)) continue; if (!strcmp(real_file, real_fsname)) break; @@ -1730,3 +1732,113 @@ int ntfs_volume_get_free_space(ntfs_volume *vol) } return (ret); } + +/** + * ntfs_volume_rename - change the current label on a volume + * @vol: volume to change the label on + * @label: the new label + * @label_len: the length of @label in ntfschars including the terminating NULL + * character, which is mandatory (the value can not exceed 128) + * + * Change the label on the volume @vol to @label. + */ +int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len) +{ + ntfs_attr *na; + char *old_vol_name; + char *new_vol_name = NULL; + int new_vol_name_len; + int err; + + if (NVolReadOnly(vol)) { + ntfs_log_error("Refusing to change label on read-only mounted " + "volume.\n"); + errno = EROFS; + return -1; + } + + label_len *= sizeof(ntfschar); + if (label_len > 0x100) { + ntfs_log_error("New label is too long. Maximum %u characters " + "allowed.\n", + (unsigned)(0x100 / sizeof(ntfschar))); + errno = ERANGE; + return -1; + } + + na = ntfs_attr_open(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0); + if (!na) { + if (errno != ENOENT) { + err = errno; + ntfs_log_perror("Lookup of $VOLUME_NAME attribute " + "failed"); + goto err_out; + } + + /* The volume name attribute does not exist. Need to add it. */ + if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0, + (u8*) label, label_len)) + { + err = errno; + ntfs_log_perror("Encountered error while adding " + "$VOLUME_NAME attribute"); + goto err_out; + } + } + else { + s64 written; + + if (NAttrNonResident(na)) { + err = errno; + ntfs_log_error("Error: Attribute $VOLUME_NAME must be " + "resident.\n"); + goto err_out; + } + + if (na->data_size != label_len) { + if (ntfs_attr_truncate(na, label_len)) { + err = errno; + ntfs_log_perror("Error resizing resident " + "attribute"); + goto err_out; + } + } + + if (label_len) { + written = ntfs_attr_pwrite(na, 0, label_len, label); + if (written == -1) { + err = errno; + ntfs_log_perror("Error when writing " + "$VOLUME_NAME data"); + goto err_out; + } + else if (written != label_len) { + err = EIO; + ntfs_log_error("Partial write when writing " + "$VOLUME_NAME data."); + goto err_out; + + } + } + } + + new_vol_name_len = + ntfs_ucstombs(label, label_len, &new_vol_name, 0); + if (new_vol_name_len == -1) { + err = errno; + ntfs_log_perror("Error while decoding new volume name"); + goto err_out; + } + + old_vol_name = vol->vol_name; + vol->vol_name = new_vol_name; + free(old_vol_name); + + err = 0; +err_out: + if (na) + ntfs_attr_close(na); + if (err) + errno = err; + return err ? -1 : 0; +} diff --git a/libcustomntfs/volume.h b/libcustomntfs/source/volume.h similarity index 97% rename from libcustomntfs/volume.h rename to libcustomntfs/source/volume.h index b3f47bf9..9d62d668 100644 --- a/libcustomntfs/volume.h +++ b/libcustomntfs/source/volume.h @@ -113,6 +113,7 @@ typedef enum { NV_ShowHidFiles, /* 1: Show files marked hidden. */ NV_HideDotFiles, /* 1: Set hidden flag on dot files */ NV_Compression, /* 1: allow compression */ + NV_NoFixupWarn, /* 1: Do not log fixup errors */ } ntfs_volume_state_bits; #define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state) @@ -147,6 +148,10 @@ typedef enum { #define NVolSetCompression(nv) set_nvol_flag(nv, Compression) #define NVolClearCompression(nv) clear_nvol_flag(nv, Compression) +#define NVolNoFixupWarn(nv) test_nvol_flag(nv, NoFixupWarn) +#define NVolSetNoFixupWarn(nv) set_nvol_flag(nv, NoFixupWarn) +#define NVolClearNoFixupWarn(nv) clear_nvol_flag(nv, NoFixupWarn) + /* * NTFS version 1.1 and 1.2 are used by Windows NT4. * NTFS version 2.x is used by Windows 2000 Beta @@ -297,6 +302,7 @@ extern int ntfs_volume_error(int err); extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err); extern int ntfs_volume_get_free_space(ntfs_volume *vol); +extern int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len); extern int ntfs_set_shown_files(ntfs_volume *vol, BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files); diff --git a/libcustomntfs/xattrs.c b/libcustomntfs/source/xattrs.c similarity index 100% rename from libcustomntfs/xattrs.c rename to libcustomntfs/source/xattrs.c diff --git a/libcustomntfs/xattrs.h b/libcustomntfs/source/xattrs.h similarity index 100% rename from libcustomntfs/xattrs.h rename to libcustomntfs/source/xattrs.h