mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-01 00:55:06 +01:00
*Update libcustomntfs again to 2012.1.15 and fixed mtime bug
Wiiflow should now recoginize NTFS partitions on 3tb hdd's again
This commit is contained in:
parent
85a7f32e49
commit
bb478d1377
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
Binary file not shown.
130
portlibs/sources/libcustomntfs/source/Makefile
Normal file
130
portlibs/sources/libcustomntfs/source/Makefile
Normal file
@ -0,0 +1,130 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# Clear the implicit built in rules
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(DEVKITPPC)),)
|
||||
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>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
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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; n<NTFS_SB_SIZE; n++)
|
||||
pctx->lson[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) {
|
||||
|
@ -226,6 +226,9 @@
|
||||
/* Define to 1 if you have the <sys/byteorder.h> header file. */
|
||||
#undef HAVE_SYS_BYTEORDER_H
|
||||
|
||||
/* Define to 1 if you have the <sys/disk.h> header file. */
|
||||
#undef HAVE_SYS_DISK_H
|
||||
|
||||
/* Define to 1 if you have the <sys/endian.h> 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
|
||||
|
@ -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 */
|
||||
|
@ -58,6 +58,9 @@
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISK_H
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <linux/fd.h>
|
||||
#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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -82,7 +82,7 @@ void ntfsInit (void)
|
||||
ntfs_log_set_handler(ntfs_log_handler_null);
|
||||
#endif
|
||||
// Set our current local
|
||||
ntfs_set_locale();
|
||||
//ntfs_set_locale();
|
||||
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
103
portlibs/sources/libcustomntfs/source/realpath.c
Normal file
103
portlibs/sources/libcustomntfs/source/realpath.c
Normal file
@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#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/<name>"
|
||||
*
|
||||
* Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
|
||||
* provides the real DM device names in /sys/block/<ptname>/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 "<name>\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
|
24
portlibs/sources/libcustomntfs/source/realpath.h
Normal file
24
portlibs/sources/libcustomntfs/source/realpath.h
Normal file
@ -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 */
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 <bk@suse.de>
|
||||
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<shortlen; i++) {
|
||||
ch = le16_to_cpu(longname[i]);
|
||||
if ((ch >= vol->upcase_len)
|
||||
|| ((shortname[i] != longname[i])
|
||||
&& (shortname[i] != vol->upcase[ch])))
|
||||
collapsible = FALSE;
|
||||
for (i=0; collapsible && (i<shortlen); i++) {
|
||||
ch = le16_to_cpu(longname[i]);
|
||||
cs = le16_to_cpu(shortname[i]);
|
||||
if ((cs != ch)
|
||||
&& ((ch >= 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;
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include <locale.h>
|
||||
#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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user