mirror of
https://github.com/wiiu-env/libntfs.git
synced 2024-11-13 05:35:07 +01:00
*Update to version 2013.1.13 of NTFS-3G
Changelog can be found here: http://www.tuxera.com/community/release-history/ *fixed bug where deleting a file / directory returned always success (0) *change make install to default to wii-install and seperated cube-install *wii-install copies files to $PORTLIBS path now
This commit is contained in:
parent
4408cc80f9
commit
968dee4aef
9
Makefile
9
Makefile
@ -22,8 +22,13 @@ wii-release:
|
||||
clean:
|
||||
$(MAKE) -C source clean
|
||||
|
||||
install: cube-release wii-release
|
||||
$(MAKE) -C source install
|
||||
cube-install: cube-release
|
||||
$(MAKE) -C source cube-install PLATFORM=cube
|
||||
|
||||
wii-install: wii-release
|
||||
$(MAKE) -C source wii-install PLATFORM=wii
|
||||
|
||||
install: wii-install
|
||||
|
||||
run: install
|
||||
$(MAKE) -C example
|
||||
|
@ -97,14 +97,13 @@ clean:
|
||||
|
||||
all: $(NTFSBIN)
|
||||
|
||||
install:
|
||||
cube-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
|
||||
cp ../include/ntfs.h $(PORTLIBS)/include
|
||||
cp ../lib/wii/libntfs.a $(PORTLIBS)/lib
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
167
source/acls.c
167
source/acls.c
@ -4,7 +4,7 @@
|
||||
* This module is part of ntfs-3g library, but may also be
|
||||
* integrated in tools running over Linux or Windows
|
||||
*
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2012 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@ -136,6 +136,19 @@ static const char worldsidbytes[] = {
|
||||
0, 0, 0, 0 /* 1st level */
|
||||
} ;
|
||||
|
||||
/*
|
||||
* SID for authenticated user (S-1-5-11)
|
||||
*/
|
||||
|
||||
static const char authsidbytes[] = {
|
||||
1, /* revision */
|
||||
1, /* auth count */
|
||||
0, 0, 0, 0, 0, 5, /* base */
|
||||
11, 0, 0, 0 /* 1st level */
|
||||
};
|
||||
|
||||
static const SID *authsid = (const SID*)authsidbytes;
|
||||
|
||||
const SID *worldsid = (const SID*)worldsidbytes;
|
||||
|
||||
/*
|
||||
@ -235,6 +248,12 @@ static int is_world_sid(const SID * usid)
|
||||
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
|
||||
&& (usid->sub_authority[0] == const_cpu_to_le32(32))
|
||||
&& (usid->sub_authority[1] == const_cpu_to_le32(545)))
|
||||
|
||||
/* check whether S-1-5-11 : authenticated user */
|
||||
|| ((usid->sub_authority_count == 1)
|
||||
&& (usid->identifier_authority.high_part == const_cpu_to_be16(0))
|
||||
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
|
||||
&& (usid->sub_authority[0] == const_cpu_to_le32(11)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -623,7 +642,7 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz)
|
||||
&& (offdacl+sizeof(ACL) < attrsz)))
|
||||
&& (!offsacl
|
||||
|| ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
|
||||
&& (offsacl+sizeof(ACL) < attrsz)))
|
||||
&& (offsacl+sizeof(ACL) <= attrsz)))
|
||||
&& !(phead->owner & const_cpu_to_le32(3))
|
||||
&& !(phead->group & const_cpu_to_le32(3))
|
||||
&& !(phead->dacl & const_cpu_to_le32(3))
|
||||
@ -664,7 +683,8 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz)
|
||||
*/
|
||||
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir)
|
||||
const SID *usid, const SID *gsid, BOOL fordir,
|
||||
le16 inherited)
|
||||
{
|
||||
unsigned int src;
|
||||
unsigned int dst;
|
||||
@ -677,7 +697,9 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
int gsidsz;
|
||||
const ACCESS_ALLOWED_ACE *poldace;
|
||||
ACCESS_ALLOWED_ACE *pnewace;
|
||||
ACCESS_ALLOWED_ACE *pauthace;
|
||||
|
||||
pauthace = (ACCESS_ALLOWED_ACE*)NULL;
|
||||
usidsz = ntfs_sid_size(usid);
|
||||
gsidsz = ntfs_sid_size(gsid);
|
||||
|
||||
@ -694,25 +716,19 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
for (nace = 0; nace < oldcnt; nace++) {
|
||||
poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src);
|
||||
acesz = le16_to_cpu(poldace->size);
|
||||
/* inheritance for access */
|
||||
if (poldace->flags & selection) {
|
||||
src += acesz;
|
||||
/*
|
||||
* Inheritance for access, unless this is inheriting
|
||||
* an inherited ACL to a directory.
|
||||
*/
|
||||
if ((poldace->flags & selection)
|
||||
&& !(fordir && inherited)
|
||||
&& !ntfs_same_sid(&poldace->sid, ownersid)
|
||||
&& !ntfs_same_sid(&poldace->sid, groupsid)) {
|
||||
pnewace = (ACCESS_ALLOWED_ACE*)
|
||||
((char*)newacl + dst);
|
||||
memcpy(pnewace,poldace,acesz);
|
||||
/*
|
||||
* Replace generic creator-owner and
|
||||
* creator-group by owner and group
|
||||
*/
|
||||
if (ntfs_same_sid(&pnewace->sid, ownersid)) {
|
||||
memcpy(&pnewace->sid, usid, usidsz);
|
||||
acesz = usidsz + 8;
|
||||
pnewace->size = cpu_to_le16(acesz);
|
||||
}
|
||||
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
|
||||
memcpy(&pnewace->sid, gsid, gsidsz);
|
||||
acesz = gsidsz + 8;
|
||||
pnewace->size = cpu_to_le16(acesz);
|
||||
}
|
||||
/* reencode GENERIC_ALL */
|
||||
if (pnewace->mask & GENERIC_ALL) {
|
||||
pnewace->mask &= ~GENERIC_ALL;
|
||||
if (fordir)
|
||||
@ -730,17 +746,71 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
| FILE_WRITE
|
||||
| FILE_EXEC
|
||||
| cpu_to_le32(0x40);
|
||||
}
|
||||
/* reencode GENERIC_READ (+ EXECUTE) */
|
||||
if (pnewace->mask & GENERIC_READ) {
|
||||
if (fordir)
|
||||
pnewace->mask |= OWNER_RIGHTS
|
||||
| DIR_READ
|
||||
| DIR_EXEC;
|
||||
else
|
||||
pnewace->mask |= OWNER_RIGHTS
|
||||
| FILE_READ
|
||||
| FILE_EXEC;
|
||||
pnewace->mask &= ~(GENERIC_READ
|
||||
| GENERIC_EXECUTE
|
||||
| WRITE_DAC
|
||||
| WRITE_OWNER
|
||||
| DELETE | FILE_WRITE_EA
|
||||
| FILE_WRITE_ATTRIBUTES);
|
||||
}
|
||||
/* reencode GENERIC_WRITE */
|
||||
if (pnewace->mask & GENERIC_WRITE) {
|
||||
if (fordir)
|
||||
pnewace->mask |= OWNER_RIGHTS
|
||||
| DIR_WRITE;
|
||||
else
|
||||
pnewace->mask |= OWNER_RIGHTS
|
||||
| FILE_WRITE;
|
||||
pnewace->mask &= ~(GENERIC_WRITE
|
||||
| WRITE_DAC
|
||||
| WRITE_OWNER
|
||||
| FILE_DELETE_CHILD);
|
||||
}
|
||||
/* remove inheritance flags */
|
||||
pnewace->flags &= ~(OBJECT_INHERIT_ACE
|
||||
| CONTAINER_INHERIT_ACE
|
||||
| INHERIT_ONLY_ACE);
|
||||
dst += acesz;
|
||||
newcnt++;
|
||||
/*
|
||||
* Group similar ACE for authenticated users
|
||||
* (should probably be done for other SIDs)
|
||||
*/
|
||||
if (!fordir
|
||||
&& (poldace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& ntfs_same_sid(&poldace->sid, authsid)) {
|
||||
if (pauthace) {
|
||||
pauthace->flags |= pnewace->flags;
|
||||
pauthace->mask |= pnewace->mask;
|
||||
} else {
|
||||
pauthace = pnewace;
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += acesz;
|
||||
newcnt++;
|
||||
}
|
||||
} else {
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += acesz;
|
||||
newcnt++;
|
||||
}
|
||||
}
|
||||
/* inheritance for further inheritance */
|
||||
if (fordir
|
||||
&& (poldace->flags
|
||||
/*
|
||||
* Inheritance for access, specific to
|
||||
* creator-owner (and creator-group)
|
||||
*/
|
||||
if (fordir || !inherited
|
||||
|| (poldace->flags
|
||||
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) {
|
||||
pnewace = (ACCESS_ALLOWED_ACE*)
|
||||
((char*)newacl + dst);
|
||||
@ -748,19 +818,46 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
/*
|
||||
* Replace generic creator-owner and
|
||||
* creator-group by owner and group
|
||||
* (but keep for further inheritance)
|
||||
*/
|
||||
if (ntfs_same_sid(&pnewace->sid, ownersid)) {
|
||||
memcpy(&pnewace->sid, usid, usidsz);
|
||||
acesz = usidsz + 8;
|
||||
pnewace->size = cpu_to_le16(usidsz + 8);
|
||||
/* remove inheritance flags */
|
||||
pnewace->flags &= ~(OBJECT_INHERIT_ACE
|
||||
| CONTAINER_INHERIT_ACE
|
||||
| INHERIT_ONLY_ACE);
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += usidsz + 8;
|
||||
newcnt++;
|
||||
}
|
||||
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
|
||||
memcpy(&pnewace->sid, gsid, gsidsz);
|
||||
acesz = gsidsz + 8;
|
||||
pnewace->size = cpu_to_le16(gsidsz + 8);
|
||||
/* remove inheritance flags */
|
||||
pnewace->flags &= ~(OBJECT_INHERIT_ACE
|
||||
| CONTAINER_INHERIT_ACE
|
||||
| INHERIT_ONLY_ACE);
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += gsidsz + 8;
|
||||
newcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* inheritance for further inheritance */
|
||||
if (fordir
|
||||
&& (poldace->flags
|
||||
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) {
|
||||
pnewace = (ACCESS_ALLOWED_ACE*)
|
||||
((char*)newacl + dst);
|
||||
memcpy(pnewace,poldace,acesz);
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += acesz;
|
||||
newcnt++;
|
||||
}
|
||||
src += acesz;
|
||||
}
|
||||
/*
|
||||
* Adjust header if something was inherited
|
||||
@ -3059,6 +3156,7 @@ static int build_owngrp_permissions(const char *securattr,
|
||||
int nace;
|
||||
le32 special;
|
||||
BOOL grppresent;
|
||||
BOOL ownpresent;
|
||||
le32 allowown, allowgrp, allowall;
|
||||
le32 denyown, denygrp, denyall;
|
||||
|
||||
@ -3068,21 +3166,26 @@ static int build_owngrp_permissions(const char *securattr,
|
||||
special = const_cpu_to_le32(0);
|
||||
allowown = allowgrp = allowall = const_cpu_to_le32(0);
|
||||
denyown = denygrp = denyall = const_cpu_to_le32(0);
|
||||
ownpresent = FALSE;
|
||||
grppresent = FALSE;
|
||||
if (offdacl) {
|
||||
acecnt = le16_to_cpu(pacl->ace_count);
|
||||
offace = offdacl + sizeof(ACL);
|
||||
} else
|
||||
} else {
|
||||
acecnt = 0;
|
||||
offace = 0;
|
||||
}
|
||||
for (nace = 0; nace < acecnt; nace++) {
|
||||
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
|
||||
if (!(pace->flags & INHERIT_ONLY_ACE)) {
|
||||
if ((ntfs_same_sid(usid, &pace->sid)
|
||||
|| ntfs_same_sid(ownersid, &pace->sid))
|
||||
&& (pace->mask & WRITE_OWNER)) {
|
||||
if (pace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) {
|
||||
allowown |= pace->mask;
|
||||
} else
|
||||
ownpresent = TRUE;
|
||||
}
|
||||
} else
|
||||
if (ntfs_same_sid(usid, &pace->sid)
|
||||
&& (!(pace->mask & WRITE_OWNER))) {
|
||||
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) {
|
||||
@ -3103,6 +3206,8 @@ static int build_owngrp_permissions(const char *securattr,
|
||||
}
|
||||
offace += le16_to_cpu(pace->size);
|
||||
}
|
||||
if (!ownpresent)
|
||||
allowown = allowall;
|
||||
if (!grppresent)
|
||||
allowgrp = allowall;
|
||||
return (merge_permissions(isdir,
|
||||
@ -3705,7 +3810,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
pxace->perms |= POSIX_PERM_DENIAL;
|
||||
else
|
||||
if (pxace->tag == POSIX_ACL_OTHER)
|
||||
pctx->permswrld = pxace->perms;
|
||||
pctx->permswrld |= pxace->perms;
|
||||
pctx->tagsset |= pxace->tag;
|
||||
if (pace->flags & INHERIT_ONLY_ACE) {
|
||||
l--;
|
||||
|
@ -185,7 +185,8 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const SID *usid, const SID *gsid, BOOL fordir);
|
||||
const SID *usid, const SID *gsid,
|
||||
BOOL fordir, le16 inherited);
|
||||
int ntfs_build_permissions(const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
char *ntfs_build_descr(mode_t mode,
|
||||
|
@ -1849,6 +1849,13 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
ntfs_log_perror("Failed to enlarge attribute");
|
||||
goto errno_set;
|
||||
}
|
||||
/*
|
||||
* If we avoided updating the runlist, we must be sure
|
||||
* to cancel the enlargement and put back the runlist to
|
||||
* a clean state if we get into some error.
|
||||
*/
|
||||
if (NAttrDataAppending(na))
|
||||
need_to.undo_data_size = 1;
|
||||
#else
|
||||
if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) {
|
||||
ntfs_log_perror("Failed to enlarge attribute");
|
||||
@ -3732,8 +3739,8 @@ int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size)
|
||||
* EIO - I/O error occurred or damaged filesystem.
|
||||
*/
|
||||
int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||
ATTR_FLAGS data_flags)
|
||||
const ntfschar *name, u8 name_len, const u8 *val,
|
||||
u32 size, ATTR_FLAGS data_flags)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
u32 length;
|
||||
@ -3864,7 +3871,7 @@ put_err_out:
|
||||
* EIO - I/O error occurred or damaged filesystem.
|
||||
*/
|
||||
int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
const ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
ATTR_FLAGS flags)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
@ -4147,7 +4154,7 @@ int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx)
|
||||
* On success return 0. On error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size)
|
||||
ntfschar *name, u8 name_len, const u8 *val, s64 size)
|
||||
{
|
||||
u32 attr_rec_size;
|
||||
int err, i, offset;
|
||||
@ -4342,8 +4349,8 @@ err_out:
|
||||
* Change an attribute flag
|
||||
*/
|
||||
|
||||
int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask)
|
||||
int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, const ntfschar *name,
|
||||
u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
int res;
|
||||
@ -6232,10 +6239,18 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize,
|
||||
|
||||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
/* Write mapping pairs for new runlist. */
|
||||
#if PARTIAL_RUNLIST_UPDATING
|
||||
if (ntfs_attr_update_mapping_pairs_i(na, start_update, holes)) {
|
||||
/*
|
||||
* Write mapping pairs for new runlist, unless this is
|
||||
* a temporary state before appending data.
|
||||
* If the update is not done, we must be sure to do
|
||||
* it later, and to get to a clean state even on errors.
|
||||
*/
|
||||
if ((holes != HOLES_DELAY)
|
||||
&& ntfs_attr_update_mapping_pairs_i(na, start_update,
|
||||
holes)) {
|
||||
#else
|
||||
/* Write mapping pairs for new runlist. */
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0)) {
|
||||
#endif
|
||||
err = errno;
|
||||
@ -6646,9 +6661,8 @@ exit:
|
||||
* Returns the amount of data written, negative if there was an error
|
||||
*/
|
||||
|
||||
int ntfs_attr_data_write(ntfs_inode *ni,
|
||||
ntfschar *stream_name, int stream_name_len,
|
||||
char *buf, size_t size, off_t offset)
|
||||
int ntfs_attr_data_write(ntfs_inode *ni, ntfschar *stream_name,
|
||||
int stream_name_len, const char *buf, size_t size, off_t offset)
|
||||
{
|
||||
ntfs_attr *na = NULL;
|
||||
int res, total = 0;
|
||||
@ -6680,7 +6694,7 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||
int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, const ntfschar *name,
|
||||
u32 name_len)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
@ -320,17 +320,18 @@ int ntfs_attr_force_non_resident(ntfs_attr *na);
|
||||
extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
|
||||
|
||||
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, u32 size,
|
||||
const ntfschar *name, u8 name_len, const u8 *val, u32 size,
|
||||
ATTR_FLAGS flags);
|
||||
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
|
||||
ATTR_FLAGS flags);
|
||||
const ntfschar *name, u8 name_len, VCN lowest_vcn,
|
||||
int dataruns_size, ATTR_FLAGS flags);
|
||||
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, u8 *val, s64 size);
|
||||
ntfschar *name, u8 name_len, const u8 *val, s64 size);
|
||||
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
|
||||
const ntfschar *name, u8 name_len, ATTR_FLAGS flags,
|
||||
ATTR_FLAGS mask);
|
||||
extern int ntfs_attr_rm(ntfs_attr *na);
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
@ -379,7 +380,7 @@ extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
|
||||
extern void ntfs_attr_name_free(char **name);
|
||||
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
||||
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
const ntfschar *name, u32 name_len);
|
||||
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
|
||||
@ -388,7 +389,7 @@ extern int ntfs_attr_data_read(ntfs_inode *ni,
|
||||
char *buf, size_t size, off_t offset);
|
||||
extern int ntfs_attr_data_write(ntfs_inode *ni,
|
||||
ntfschar *stream_name, int stream_name_len,
|
||||
char *buf, size_t size, off_t offset);
|
||||
const char *buf, size_t size, off_t offset);
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
||||
|
@ -215,8 +215,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
if ((vol->mft_lcn < 0 || vol->mft_lcn > vol->nr_clusters) ||
|
||||
(vol->mftmirr_lcn < 0 || vol->mftmirr_lcn > vol->nr_clusters)) {
|
||||
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
|
||||
"greater than the number of clusters (%lld).\n",
|
||||
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,
|
||||
|
@ -31,6 +31,12 @@
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h> /* ENODATA */
|
||||
|
||||
#ifndef ENODATA
|
||||
#define ENODATA ENOENT
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
@ -107,8 +107,8 @@
|
||||
/* Define to 1 if you have the <machine/endian.h> header file. */
|
||||
#define HAVE_MACHINE_ENDIAN_H 1
|
||||
|
||||
/* Define to 1 if you have the <math.h> header file. */
|
||||
#define HAVE_MATH_H 1
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
|
||||
#define HAVE_MBRTOWC 1
|
||||
@ -116,6 +116,9 @@
|
||||
/* Define to 1 if you have the `mbsinit' function. */
|
||||
#define HAVE_MBSINIT 1
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#define HAVE_MEMCPY 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
@ -131,6 +134,9 @@
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `random' function. */
|
||||
#undef HAVE_RANDOM
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
@ -143,9 +149,12 @@
|
||||
/* Define to 1 if you have the `setxattr' function. */
|
||||
#undef HAVE_SETXATTR
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#define HAVE_STAT_EMPTY_STRING_BUG 1
|
||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#define HAVE_STDARG_H 1
|
||||
@ -312,13 +321,13 @@
|
||||
#define PACKAGE_NAME "ntfs-3g"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "ntfs-3g 2012.1.15"
|
||||
#define PACKAGE_STRING "ntfs-3g 2013.1.13"
|
||||
|
||||
/* 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 "2012.1.15"
|
||||
#define PACKAGE_VERSION "2013.1.13"
|
||||
|
||||
/* POSIX ACL support */
|
||||
#undef POSIXACLS
|
||||
@ -326,29 +335,8 @@
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# define _ALL_SOURCE 1
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# define __EXTENSIONS__ 1
|
||||
#endif
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2012.1.15"
|
||||
#define VERSION "2013.1.13"
|
||||
|
||||
/* Define to 1 if this is a Windows OS */
|
||||
#undef WINDOWS
|
||||
@ -392,3 +380,6 @@
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to 1 if you have the <math.h> header file. */
|
||||
#define HAVE_MATH_H 1
|
||||
|
171
source/dir.c
171
source/dir.c
@ -867,6 +867,87 @@ typedef enum {
|
||||
INDEX_TYPE_ALLOCATION, /* index allocation */
|
||||
} INDEX_TYPE;
|
||||
|
||||
/*
|
||||
* Decode Interix file types
|
||||
*
|
||||
* Non-Interix types are returned as plain files, because a
|
||||
* Windows user may force patterns very similar to Interix,
|
||||
* and most metadata files have such similar patters.
|
||||
*/
|
||||
|
||||
static u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
u32 dt_type;
|
||||
le64 magic;
|
||||
|
||||
dt_type = NTFS_DT_UNKNOWN;
|
||||
na = ntfs_attr_open(ni, AT_DATA, NULL, 0);
|
||||
if (na) {
|
||||
/* Unrecognized patterns (eg HID + SYST) are plain files */
|
||||
dt_type = NTFS_DT_REG;
|
||||
if (na->data_size <= 1) {
|
||||
if (!(ni->flags & FILE_ATTR_HIDDEN))
|
||||
dt_type = (na->data_size ?
|
||||
NTFS_DT_SOCK : NTFS_DT_FIFO);
|
||||
} else {
|
||||
if ((na->data_size >= (s64)sizeof(magic))
|
||||
&& (ntfs_attr_pread(na, 0, sizeof(magic), &magic)
|
||||
== sizeof(magic))) {
|
||||
if (magic == INTX_SYMBOLIC_LINK)
|
||||
dt_type = NTFS_DT_LNK;
|
||||
else if (magic == INTX_BLOCK_DEVICE)
|
||||
dt_type = NTFS_DT_BLK;
|
||||
else if (magic == INTX_CHARACTER_DEVICE)
|
||||
dt_type = NTFS_DT_CHR;
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
return (dt_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode file types
|
||||
*
|
||||
* Better only use for Interix types and junctions,
|
||||
* unneeded complexity when used for plain files or directories
|
||||
*
|
||||
* Error cases are logged and returned as unknown.
|
||||
*/
|
||||
|
||||
static u32 ntfs_dir_entry_type(ntfs_inode *dir_ni, MFT_REF mref,
|
||||
FILE_ATTR_FLAGS attributes)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
u32 dt_type;
|
||||
|
||||
dt_type = NTFS_DT_UNKNOWN;
|
||||
ni = ntfs_inode_open(dir_ni->vol, mref);
|
||||
if (ni) {
|
||||
if ((attributes & FILE_ATTR_REPARSE_POINT)
|
||||
&& ntfs_possible_symlink(ni))
|
||||
dt_type = NTFS_DT_LNK;
|
||||
else
|
||||
if ((attributes & FILE_ATTR_SYSTEM)
|
||||
&& !(attributes & FILE_ATTR_I30_INDEX_PRESENT))
|
||||
dt_type = ntfs_interix_types(ni);
|
||||
else
|
||||
dt_type = (attributes
|
||||
& FILE_ATTR_I30_INDEX_PRESENT
|
||||
? NTFS_DT_DIR : NTFS_DT_REG);
|
||||
if (ntfs_inode_close(ni)) {
|
||||
/* anything special worth doing ? */
|
||||
ntfs_log_error("Failed to close inode %lld\n",
|
||||
(long long)MREF(mref));
|
||||
}
|
||||
}
|
||||
if (dt_type == NTFS_DT_UNKNOWN)
|
||||
ntfs_log_error("Could not decode the type of inode %lld\n",
|
||||
(long long)MREF(mref));
|
||||
return (dt_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_filldir - ntfs specific filldir method
|
||||
* @dir_ni: ntfs inode of current directory
|
||||
@ -901,19 +982,23 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
|
||||
dir_ni->vol->mft_record_size;
|
||||
else /* if (index_type == INDEX_TYPE_ROOT) */
|
||||
*pos = (u8*)ie - (u8*)iu.ir;
|
||||
mref = le64_to_cpu(ie->indexed_file);
|
||||
metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user);
|
||||
/* Skip root directory self reference entry. */
|
||||
if (MREF_LE(ie->indexed_file) == FILE_root)
|
||||
return 0;
|
||||
if (ie->key.file_name.file_attributes & FILE_ATTR_I30_INDEX_PRESENT)
|
||||
if ((ie->key.file_name.file_attributes
|
||||
& (FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYSTEM))
|
||||
&& !metadata)
|
||||
dt_type = ntfs_dir_entry_type(dir_ni, mref,
|
||||
ie->key.file_name.file_attributes);
|
||||
else if (ie->key.file_name.file_attributes
|
||||
& FILE_ATTR_I30_INDEX_PRESENT)
|
||||
dt_type = NTFS_DT_DIR;
|
||||
else if (fn->file_attributes & FILE_ATTR_SYSTEM)
|
||||
dt_type = NTFS_DT_UNKNOWN;
|
||||
else
|
||||
dt_type = NTFS_DT_REG;
|
||||
|
||||
/* return metadata files and hidden files if requested */
|
||||
mref = le64_to_cpu(ie->indexed_file);
|
||||
metadata = (MREF(mref) != FILE_root) && (MREF(mref) < FILE_first_user);
|
||||
if ((!metadata && (NVolShowHidFiles(dir_ni->vol)
|
||||
|| !(fn->file_attributes & FILE_ATTR_HIDDEN)))
|
||||
|| (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol)
|
||||
@ -1397,8 +1482,8 @@ err_out:
|
||||
* on error with errno set to the error code.
|
||||
*/
|
||||
static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev,
|
||||
ntfschar *target, int target_len)
|
||||
const ntfschar *name, u8 name_len, mode_t type, dev_t dev,
|
||||
const ntfschar *target, int target_len)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
int rollback_data = 0, rollback_sd = 0;
|
||||
@ -1667,7 +1752,7 @@ err_out:
|
||||
* Some wrappers around __ntfs_create() ...
|
||||
*/
|
||||
|
||||
ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, ntfschar *name,
|
||||
ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, const ntfschar *name,
|
||||
u8 name_len, mode_t type)
|
||||
{
|
||||
if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO &&
|
||||
@ -1679,7 +1764,7 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, ntfschar *name,
|
||||
}
|
||||
|
||||
ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev)
|
||||
const ntfschar *name, u8 name_len, mode_t type, dev_t dev)
|
||||
{
|
||||
if (type != S_IFCHR && type != S_IFBLK) {
|
||||
ntfs_log_error("Invalid arguments.\n");
|
||||
@ -1689,7 +1774,8 @@ ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
}
|
||||
|
||||
ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len)
|
||||
const ntfschar *name, u8 name_len, const ntfschar *target,
|
||||
int target_len)
|
||||
{
|
||||
if (!target || !target_len) {
|
||||
ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__,
|
||||
@ -1764,7 +1850,8 @@ no_hardlink:
|
||||
* Return 0 on success or -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
u8 name_len)
|
||||
{
|
||||
ntfs_attr_search_ctx *actx = NULL;
|
||||
FILE_NAME_ATTR *fn = NULL;
|
||||
@ -1878,8 +1965,18 @@ search:
|
||||
if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length)))
|
||||
goto err_out;
|
||||
|
||||
if (ntfs_attr_record_rm(actx))
|
||||
goto err_out;
|
||||
/*
|
||||
* Keep the last name in place, this is useful for undeletion
|
||||
* (Windows also does so), however delete the name if it were
|
||||
* in an extent, to avoid leaving an attribute list.
|
||||
*/
|
||||
if ((ni->mrec->link_count == cpu_to_le16(1)) && !actx->base_ntfs_ino) {
|
||||
/* make sure to not loop to another search */
|
||||
looking_for_dos_name = FALSE;
|
||||
} else {
|
||||
if (ntfs_attr_record_rm(actx))
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
|
||||
ni->mrec->link_count) - 1);
|
||||
@ -2002,6 +2099,7 @@ search:
|
||||
"Leaving inconsistent metadata.\n");
|
||||
}
|
||||
#endif
|
||||
debug_double_inode(ni->mft_no,0);
|
||||
if (ntfs_mft_record_free(ni->vol, ni)) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to free base MFT record. "
|
||||
@ -2044,7 +2142,7 @@ err_out:
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code.
|
||||
*/
|
||||
static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
u8 name_len, FILE_NAME_TYPE_FLAGS nametype)
|
||||
{
|
||||
FILE_NAME_ATTR *fn = NULL;
|
||||
@ -2064,6 +2162,15 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
if (NVolHideDotFiles(dir_ni->vol)) {
|
||||
/* Set hidden flag according to the latest name */
|
||||
if ((name_len > 1)
|
||||
&& (name[0] == const_cpu_to_le16('.'))
|
||||
&& (name[1] != const_cpu_to_le16('.')))
|
||||
ni->flags |= FILE_ATTR_HIDDEN;
|
||||
else
|
||||
ni->flags &= ~FILE_ATTR_HIDDEN;
|
||||
}
|
||||
|
||||
/* Create FILE_NAME attribute. */
|
||||
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
|
||||
@ -2121,7 +2228,8 @@ err_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
|
||||
int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
u8 name_len)
|
||||
{
|
||||
return (ntfs_link_i(ni, dir_ni, name, name_len, FILE_NAME_POSIX));
|
||||
}
|
||||
@ -2172,6 +2280,8 @@ ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni)
|
||||
/*
|
||||
* Get a DOS name for a file in designated directory
|
||||
*
|
||||
* Not allowed if there are several non-dos names (EMLINK)
|
||||
*
|
||||
* Returns size if found
|
||||
* 0 if not found
|
||||
* -1 if there was an error (described by errno)
|
||||
@ -2180,6 +2290,7 @@ ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni)
|
||||
static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
|
||||
{
|
||||
size_t outsize = 0;
|
||||
int namecount = 0;
|
||||
FILE_NAME_ATTR *fn;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
@ -2194,6 +2305,8 @@ static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
|
||||
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
|
||||
if (fn->file_name_type != FILE_NAME_DOS)
|
||||
namecount++;
|
||||
if ((fn->file_name_type & FILE_NAME_DOS)
|
||||
&& (MREF_LE(fn->parent_directory) == dnum)) {
|
||||
/*
|
||||
@ -2208,6 +2321,10 @@ static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
|
||||
}
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if ((outsize > 0) && (namecount > 1)) {
|
||||
outsize = -1;
|
||||
errno = EMLINK; /* this error implies there is a dos name */
|
||||
}
|
||||
return (outsize);
|
||||
}
|
||||
|
||||
@ -2215,6 +2332,8 @@ static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
|
||||
/*
|
||||
* Get a long name for a file in designated directory
|
||||
*
|
||||
* Not allowed if there are several non-dos names (EMLINK)
|
||||
*
|
||||
* Returns size if found
|
||||
* 0 if not found
|
||||
* -1 if there was an error (described by errno)
|
||||
@ -2223,6 +2342,7 @@ static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
|
||||
static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname)
|
||||
{
|
||||
size_t outsize = 0;
|
||||
int namecount = 0;
|
||||
FILE_NAME_ATTR *fn;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
@ -2238,6 +2358,8 @@ static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname)
|
||||
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
|
||||
if (fn->file_name_type != FILE_NAME_DOS)
|
||||
namecount++;
|
||||
if ((fn->file_name_type & FILE_NAME_WIN32)
|
||||
&& (MREF_LE(fn->parent_directory) == dnum)) {
|
||||
/*
|
||||
@ -2247,6 +2369,11 @@ static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname)
|
||||
outsize = fn->file_name_length;
|
||||
memcpy(longname,fn->file_name,outsize*sizeof(ntfschar));
|
||||
}
|
||||
}
|
||||
if (namecount > 1) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
/* if not found search for POSIX names */
|
||||
if (!outsize) {
|
||||
@ -2324,7 +2451,7 @@ int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
*/
|
||||
|
||||
static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
ntfschar *name, int len,
|
||||
const ntfschar *name, int len,
|
||||
FILE_NAME_TYPE_FLAGS nametype)
|
||||
{
|
||||
ntfs_attr_search_ctx *actx;
|
||||
@ -2398,9 +2525,9 @@ static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
*/
|
||||
|
||||
static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
ntfschar *shortname, int shortlen,
|
||||
ntfschar *longname, int longlen,
|
||||
ntfschar *deletename, int deletelen, BOOL existed)
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen,
|
||||
const ntfschar *deletename, int deletelen, BOOL existed)
|
||||
{
|
||||
unsigned int linkcount;
|
||||
ntfs_volume *vol;
|
||||
@ -2568,7 +2695,8 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
res = -1;
|
||||
} else {
|
||||
res = -1;
|
||||
errno = ENOENT;
|
||||
if (!longlen)
|
||||
errno = ENOENT;
|
||||
}
|
||||
free(shortname);
|
||||
if (!closed) {
|
||||
@ -2644,7 +2772,8 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errno = ENOENT;
|
||||
if (!longlen)
|
||||
errno = ENOENT;
|
||||
res = -1;
|
||||
}
|
||||
if (!deleted) {
|
||||
|
11
source/dir.h
11
source/dir.h
@ -68,17 +68,18 @@ extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
|
||||
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
const char *pathname);
|
||||
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type);
|
||||
const ntfschar *name, u8 name_len, mode_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||
const ntfschar *name, u8 name_len, mode_t type, dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
|
||||
const ntfschar *name, u8 name_len, const ntfschar *target,
|
||||
int target_len);
|
||||
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||
extern int ntfs_delete(ntfs_volume *vol, const char *path,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
/*
|
||||
|
@ -2398,18 +2398,19 @@ typedef enum {
|
||||
IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001),
|
||||
IO_REPARSE_TAG_RESERVED_RANGE = const_cpu_to_le32(0x00000001),
|
||||
|
||||
IO_REPARSE_TAG_NSS = const_cpu_to_le32(0x68000005),
|
||||
IO_REPARSE_TAG_NSS_RECOVER = const_cpu_to_le32(0x68000006),
|
||||
IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x68000007),
|
||||
IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x68000008),
|
||||
IO_REPARSE_TAG_CSV = const_cpu_to_le32(0x80000009),
|
||||
IO_REPARSE_TAG_DEDUP = const_cpu_to_le32(0x80000013),
|
||||
IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x8000000A),
|
||||
IO_REPARSE_TAG_DFSR = const_cpu_to_le32(0x80000012),
|
||||
IO_REPARSE_TAG_HSM = const_cpu_to_le32(0xC0000004),
|
||||
IO_REPARSE_TAG_HSM2 = const_cpu_to_le32(0x80000006),
|
||||
IO_REPARSE_TAG_MOUNT_POINT = const_cpu_to_le32(0xA0000003),
|
||||
IO_REPARSE_TAG_NFS = const_cpu_to_le32(0x80000014),
|
||||
IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x80000007),
|
||||
IO_REPARSE_TAG_SYMLINK = const_cpu_to_le32(0xA000000C),
|
||||
IO_REPARSE_TAG_WIM = const_cpu_to_le32(0x80000008),
|
||||
|
||||
IO_REPARSE_TAG_MOUNT_POINT = const_cpu_to_le32(0x88000003),
|
||||
|
||||
IO_REPARSE_TAG_HSM = const_cpu_to_le32(0xa8000004),
|
||||
|
||||
IO_REPARSE_TAG_SYMBOLIC_LINK = const_cpu_to_le32(0xe8000000),
|
||||
|
||||
IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xe000ffff),
|
||||
IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xf000ffff),
|
||||
} PREDEFINED_REPARSE_TAGS;
|
||||
|
||||
/**
|
||||
|
@ -84,13 +84,21 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
"position in $LogFile.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* We only know how to handle version 1.1. */
|
||||
if (sle16_to_cpu(rp->major_ver) != 1 ||
|
||||
sle16_to_cpu(rp->minor_ver) != 1) {
|
||||
/*
|
||||
* We only know how to handle version 1.1 and 2.0, though
|
||||
* version 2.0 is probably related to cached metadata in
|
||||
* Windows 8, and we will refuse to mount.
|
||||
* Nevertheless, do all the relevant checks before rejecting.
|
||||
*/
|
||||
if (((rp->major_ver != const_cpu_to_le16(1))
|
||||
|| (rp->minor_ver != const_cpu_to_le16(1)))
|
||||
&& ((rp->major_ver != const_cpu_to_le16(2))
|
||||
|| (rp->minor_ver != const_cpu_to_le16(0)))) {
|
||||
ntfs_log_error("$LogFile version %i.%i is not "
|
||||
"supported. (This driver supports version "
|
||||
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
|
||||
(int)sle16_to_cpu(rp->minor_ver));
|
||||
"supported.\n (This driver supports version "
|
||||
"1.1 and 2.0 only.)\n",
|
||||
(int)sle16_to_cpu(rp->major_ver),
|
||||
(int)sle16_to_cpu(rp->minor_ver));
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
|
@ -475,20 +475,20 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
|
||||
|
||||
// Build the mount flags
|
||||
if (flags & NTFS_READ_ONLY)
|
||||
vd->flags |= MS_RDONLY;
|
||||
vd->flags |= NTFS_MNT_RDONLY;
|
||||
else
|
||||
{
|
||||
if (!(interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_RDONLY;
|
||||
vd->flags |= NTFS_MNT_RDONLY;
|
||||
if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
|
||||
vd->flags |= MS_EXCLUSIVE;
|
||||
vd->flags |= NTFS_MNT_EXCLUSIVE;
|
||||
}
|
||||
if (flags & NTFS_RECOVER)
|
||||
vd->flags |= MS_RECOVER;
|
||||
vd->flags |= NTFS_MNT_RECOVER;
|
||||
if (flags & NTFS_IGNORE_HIBERFILE)
|
||||
vd->flags |= MS_IGNORE_HIBERFILE;
|
||||
vd->flags |= NTFS_MNT_IGNORE_HIBERFILE;
|
||||
|
||||
if (vd->flags & MS_RDONLY)
|
||||
if (vd->flags & NTFS_MNT_RDONLY)
|
||||
ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
|
||||
|
||||
// Mount the device
|
||||
|
@ -670,7 +670,7 @@ cleanup:
|
||||
// Unlock
|
||||
ntfsUnlock(vd);
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "attrib.h"
|
||||
|
@ -44,12 +44,18 @@ enum {
|
||||
*/
|
||||
|
||||
/* default option for compression */
|
||||
#define DEFAULT_COMPRESSION FALSE
|
||||
#define DEFAULT_COMPRESSION 0
|
||||
/* (log2 of) number of clusters in a compression block for new files */
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
/* maximum cluster size for allowing compression for new files */
|
||||
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
|
||||
|
||||
/*
|
||||
* Parameters for default options
|
||||
*/
|
||||
|
||||
#define DEFAULT_DMTIME 60 /* default 1mn for delay_mtime */
|
||||
|
||||
/*
|
||||
* Use of big write buffers
|
||||
*
|
||||
@ -109,7 +115,11 @@ enum {
|
||||
* of 6 is added in the mount report.
|
||||
*/
|
||||
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
#define HPERMSCONFIG 4 /* access control by kernel is broken on OpenIndiana */
|
||||
#else
|
||||
#define HPERMSCONFIG 1
|
||||
#endif
|
||||
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
|
||||
#define LPERMSCONFIG 5
|
||||
#else
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2008-2009 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2012 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@ -46,8 +46,10 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "dir.h"
|
||||
@ -59,18 +61,6 @@
|
||||
#include "misc.h"
|
||||
#include "reparse.h"
|
||||
|
||||
/* the definitions in layout.h are wrong, we use names defined in
|
||||
http://msdn.microsoft.com/en-us/library/aa365740(VS.85).aspx
|
||||
*/
|
||||
|
||||
#define IO_REPARSE_TAG_DFS const_cpu_to_le32(0x8000000A)
|
||||
#define IO_REPARSE_TAG_DFSR const_cpu_to_le32(0x80000012)
|
||||
#define IO_REPARSE_TAG_HSM const_cpu_to_le32(0xC0000004)
|
||||
#define IO_REPARSE_TAG_HSM2 const_cpu_to_le32(0x80000006)
|
||||
#define IO_REPARSE_TAG_MOUNT_POINT const_cpu_to_le32(0xA0000003)
|
||||
#define IO_REPARSE_TAG_SIS const_cpu_to_le32(0x80000007)
|
||||
#define IO_REPARSE_TAG_SYMLINK const_cpu_to_le32(0xA000000C)
|
||||
|
||||
struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
|
||||
le16 subst_name_offset;
|
||||
le16 subst_name_length;
|
||||
@ -235,6 +225,17 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
|
||||
ni = ntfs_inode_open(vol, (MFT_REF)FILE_root);
|
||||
if (ni) {
|
||||
start = 0;
|
||||
/*
|
||||
* Examine and translate the path, until we reach either
|
||||
* - the end,
|
||||
* - an unknown item
|
||||
* - a non-directory
|
||||
* - another reparse point,
|
||||
* A reparse point is not dereferenced, it will be
|
||||
* examined later when the translated path is dereferenced,
|
||||
* however the final part of the path will not be adjusted
|
||||
* to correct case.
|
||||
*/
|
||||
do {
|
||||
len = 0;
|
||||
while (((start + len) < count)
|
||||
@ -252,9 +253,11 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
|
||||
}
|
||||
} while (ni
|
||||
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
&& !(ni->flags & FILE_ATTR_REPARSE_POINT)
|
||||
&& (start < count));
|
||||
if (ni
|
||||
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir))
|
||||
&& ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir)
|
||||
|| (ni->flags & FILE_ATTR_REPARSE_POINT)))
|
||||
if (ntfs_ucstombs(path, count, &target, 0) < 0) {
|
||||
if (target) {
|
||||
free(target);
|
||||
@ -288,12 +291,25 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
||||
int pos;
|
||||
int lth;
|
||||
BOOL ok;
|
||||
BOOL morelinks;
|
||||
int max = 32; /* safety */
|
||||
|
||||
pos = 0;
|
||||
ok = TRUE;
|
||||
morelinks = FALSE;
|
||||
curni = ntfs_dir_parent_inode(ni);
|
||||
while (curni && ok && (pos < (count - 1)) && --max) {
|
||||
/*
|
||||
* Examine and translate the path, until we reach either
|
||||
* - the end,
|
||||
* - an unknown item
|
||||
* - a non-directory
|
||||
* - another reparse point,
|
||||
* A reparse point is not dereferenced, it will be
|
||||
* examined later when the translated path is dereferenced,
|
||||
* however the final part of the path will not be adjusted
|
||||
* to correct case.
|
||||
*/
|
||||
while (curni && ok && !morelinks && (pos < (count - 1)) && --max) {
|
||||
if ((count >= (pos + 2))
|
||||
&& (path[pos] == const_cpu_to_le16('.'))
|
||||
&& (path[pos+1] == const_cpu_to_le16('\\'))) {
|
||||
@ -331,12 +347,18 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
|
||||
if (!curni)
|
||||
ok = FALSE;
|
||||
else {
|
||||
if (curni->flags & FILE_ATTR_REPARSE_POINT)
|
||||
morelinks = TRUE;
|
||||
if (ok && ((pos + lth) < count)) {
|
||||
path[pos + lth] = const_cpu_to_le16('/');
|
||||
pos += lth + 1;
|
||||
if (morelinks
|
||||
&& ntfs_inode_close(curni))
|
||||
ok = FALSE;
|
||||
} else {
|
||||
pos += lth;
|
||||
if ((ni->mrec->flags ^ curni->mrec->flags)
|
||||
if (!morelinks
|
||||
&& (ni->mrec->flags ^ curni->mrec->flags)
|
||||
& MFT_RECORD_IS_DIRECTORY)
|
||||
ok = FALSE;
|
||||
if (ntfs_inode_close(curni))
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2012 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@ -52,6 +52,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "param.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
@ -1128,10 +1129,86 @@ static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid
|
||||
return (ingroup);
|
||||
}
|
||||
|
||||
#if defined(__sun) && defined (__SVR4)
|
||||
|
||||
/*
|
||||
* Check whether current thread owner is member of file group
|
||||
* Solaris/OpenIndiana version
|
||||
* Should not be called for user root, however the group may be root
|
||||
*
|
||||
* The group list is available in "/proc/$PID/cred"
|
||||
*
|
||||
*/
|
||||
|
||||
static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
{
|
||||
typedef struct prcred {
|
||||
uid_t pr_euid; /* effective user id */
|
||||
uid_t pr_ruid; /* real user id */
|
||||
uid_t pr_suid; /* saved user id (from exec) */
|
||||
gid_t pr_egid; /* effective group id */
|
||||
gid_t pr_rgid; /* real group id */
|
||||
gid_t pr_sgid; /* saved group id (from exec) */
|
||||
int pr_ngroups; /* number of supplementary groups */
|
||||
gid_t pr_groups[1]; /* array of supplementary groups */
|
||||
} prcred_t;
|
||||
enum { readset = 16 };
|
||||
|
||||
prcred_t basecreds;
|
||||
gid_t groups[readset];
|
||||
char filename[64];
|
||||
int fd;
|
||||
int k;
|
||||
int cnt;
|
||||
gid_t *p;
|
||||
BOOL ismember;
|
||||
int got;
|
||||
pid_t tid;
|
||||
|
||||
if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
|
||||
ismember = staticgroupmember(scx, uid, gid);
|
||||
else {
|
||||
ismember = FALSE; /* default return */
|
||||
tid = scx->tid;
|
||||
sprintf(filename,"/proc/%u/cred",tid);
|
||||
fd = open(filename,O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
got = read(fd, &basecreds, sizeof(prcred_t));
|
||||
if (got == sizeof(prcred_t)) {
|
||||
if (basecreds.pr_egid == gid)
|
||||
ismember = TRUE;
|
||||
p = basecreds.pr_groups;
|
||||
cnt = 1;
|
||||
k = 0;
|
||||
while (!ismember
|
||||
&& (k < basecreds.pr_ngroups)
|
||||
&& (cnt > 0)
|
||||
&& (*p != gid)) {
|
||||
k++;
|
||||
cnt--;
|
||||
p++;
|
||||
if (cnt <= 0) {
|
||||
got = read(fd, groups,
|
||||
readset*sizeof(gid_t));
|
||||
cnt = got/sizeof(gid_t);
|
||||
p = groups;
|
||||
}
|
||||
}
|
||||
if ((cnt > 0)
|
||||
&& (k < basecreds.pr_ngroups))
|
||||
ismember = TRUE;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return (ismember);
|
||||
}
|
||||
|
||||
#else /* defined(__sun) && defined (__SVR4) */
|
||||
|
||||
/*
|
||||
* Check whether current thread owner is member of file group
|
||||
* Linux version
|
||||
* Should not be called for user root, however the group may be root
|
||||
*
|
||||
* As indicated by Miklos Szeredi :
|
||||
@ -1234,6 +1311,8 @@ static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
return (ismember);
|
||||
}
|
||||
|
||||
#endif /* defined(__sun) && defined (__SVR4) */
|
||||
|
||||
/*
|
||||
* Cacheing is done two-way :
|
||||
* - from uid, gid and perm to securid (CACHED_SECURID)
|
||||
@ -1797,7 +1876,7 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
if (!scx->uid) {
|
||||
/* root access if owner or other execution */
|
||||
if (perms & 0101)
|
||||
perms = 07777;
|
||||
perms |= 01777;
|
||||
else {
|
||||
/* root access if some group execution */
|
||||
groupperms = 0;
|
||||
@ -2213,7 +2292,7 @@ static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
|
||||
if (!scx->uid) {
|
||||
/* root access and execution */
|
||||
if (perm & 0111)
|
||||
perm = 07777;
|
||||
perm |= 01777;
|
||||
else
|
||||
perm = 0;
|
||||
} else
|
||||
@ -3316,6 +3395,56 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
|
||||
return (allow);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether user can create a file (or directory)
|
||||
*
|
||||
* Returns TRUE if access is allowed,
|
||||
* Also returns the gid and dsetgid applicable to the created file
|
||||
*/
|
||||
|
||||
int ntfs_allowed_create(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *dir_ni, gid_t *pgid, mode_t *pdsetgid)
|
||||
{
|
||||
int perm;
|
||||
int res;
|
||||
int allow;
|
||||
struct stat stbuf;
|
||||
|
||||
/*
|
||||
* Always allow for root.
|
||||
* Also always allow if no mapping has been defined
|
||||
*/
|
||||
if (!scx->mapping[MAPUSERS])
|
||||
perm = 0777;
|
||||
else
|
||||
perm = ntfs_get_perm(scx, dir_ni, S_IWRITE + S_IEXEC);
|
||||
if (!scx->mapping[MAPUSERS]
|
||||
|| !scx->uid) {
|
||||
allow = 1;
|
||||
} else {
|
||||
perm = ntfs_get_perm(scx, dir_ni, S_IWRITE + S_IEXEC);
|
||||
if (perm >= 0) {
|
||||
res = EACCES;
|
||||
allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
|
||||
&& ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
|
||||
if (!allow)
|
||||
errno = res;
|
||||
} else
|
||||
allow = 0;
|
||||
}
|
||||
*pgid = scx->gid;
|
||||
*pdsetgid = 0;
|
||||
/* return directory group if S_ISGID is set */
|
||||
if (allow && (perm & S_ISGID)) {
|
||||
if (ntfs_get_owner_mode(scx, dir_ni, &stbuf) >= 0) {
|
||||
*pdsetgid = stbuf.st_mode & S_ISGID;
|
||||
if (perm & S_ISGID)
|
||||
*pgid = stbuf.st_gid;
|
||||
}
|
||||
}
|
||||
return (allow);
|
||||
}
|
||||
|
||||
#if 0 /* not needed any more */
|
||||
|
||||
/*
|
||||
@ -3467,10 +3596,12 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
uid = fileuid;
|
||||
if ((int)gid < 0)
|
||||
gid = filegid;
|
||||
#if !defined(__sun) || !defined (__SVR4)
|
||||
/* clear setuid and setgid if owner has changed */
|
||||
/* unless request originated by root */
|
||||
if (uid && (fileuid != uid))
|
||||
mode &= 01777;
|
||||
#endif
|
||||
#if POSIXACLS
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
||||
mode, pxdesc);
|
||||
@ -3679,7 +3810,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
|
||||
pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
|
||||
pnhead->alignment = 0;
|
||||
pnhead->control = SE_SELF_RELATIVE;
|
||||
pnhead->control = (pphead->control
|
||||
& (SE_DACL_AUTO_INHERITED | SE_SACL_AUTO_INHERITED))
|
||||
| SE_SELF_RELATIVE;
|
||||
pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
|
||||
/*
|
||||
* locate and inherit DACL
|
||||
@ -3690,7 +3823,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
offpacl = le32_to_cpu(pphead->dacl);
|
||||
ppacl = (const ACL*)&parentattr[offpacl];
|
||||
pnacl = (ACL*)&newattr[pos];
|
||||
aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
|
||||
aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid,
|
||||
fordir, pphead->control
|
||||
& SE_DACL_AUTO_INHERITED);
|
||||
if (aclsz) {
|
||||
pnhead->dacl = cpu_to_le32(pos);
|
||||
pos += aclsz;
|
||||
@ -3705,7 +3840,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
offpacl = le32_to_cpu(pphead->sacl);
|
||||
ppacl = (const ACL*)&parentattr[offpacl];
|
||||
pnacl = (ACL*)&newattr[pos];
|
||||
aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
|
||||
aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid,
|
||||
fordir, pphead->control
|
||||
& SE_SACL_AUTO_INHERITED);
|
||||
if (aclsz) {
|
||||
pnhead->sacl = cpu_to_le32(pos);
|
||||
pos += aclsz;
|
||||
@ -3723,7 +3860,7 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
*/
|
||||
memcpy(&newattr[pos],gsid,gsidsz);
|
||||
pnhead->group = cpu_to_le32(pos);
|
||||
pos += usidsz;
|
||||
pos += gsidsz;
|
||||
securid = setsecurityattr(scx->vol,
|
||||
(SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
|
||||
free(newattr);
|
||||
|
@ -255,6 +255,8 @@ int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode);
|
||||
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
|
||||
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, int accesstype);
|
||||
int ntfs_allowed_create(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, gid_t *pgid, mode_t *pdsetgid);
|
||||
BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
||||
const char *path, int accesstype);
|
||||
|
||||
|
@ -710,9 +710,9 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
||||
| ((u32)(s[1] & 0x3F) << 12)
|
||||
| ((u32)(s[2] & 0x3F) << 6)
|
||||
| ((u32)(s[3] & 0x3F));
|
||||
/* Check valid ranges */
|
||||
if ((*wc <= 0x10ffff) && (*wc >= 0x10000))
|
||||
return 4;
|
||||
/* Check valid ranges */
|
||||
if ((*wc <= 0x10ffff) && (*wc >= 0x10000))
|
||||
return 4;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
135
source/volume.c
135
source/volume.c
@ -54,6 +54,10 @@
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && defined (__SVR4)
|
||||
#include <sys/mnttab.h>
|
||||
#endif
|
||||
|
||||
#include "param.h"
|
||||
#include "compat.h"
|
||||
#include "volume.h"
|
||||
@ -89,13 +93,9 @@ static const char *corrupt_volume_msg =
|
||||
"for more details.\n";
|
||||
|
||||
static const char *hibernated_volume_msg =
|
||||
"The NTFS partition is hibernated. Please resume and shutdown Windows\n"
|
||||
"properly, or mount the volume read-only with the 'ro' mount option, or\n"
|
||||
"mount the volume read-write with the 'remove_hiberfile' mount option.\n"
|
||||
"For example type on the command line:\n"
|
||||
"\n"
|
||||
" mount -t ntfs-3g -o remove_hiberfile %s %s\n"
|
||||
"\n";
|
||||
"The NTFS partition is in an unsafe state. Please resume and shutdown\n"
|
||||
"Windows fully (no hibernation or fast restarting), or mount the volume\n"
|
||||
"read-only with the 'ro' mount option.\n";
|
||||
|
||||
static const char *unclean_journal_msg =
|
||||
"Write access is denied because the disk wasn't safely powered\n"
|
||||
@ -466,7 +466,8 @@ error_exit:
|
||||
* Return the allocated volume structure on success and NULL on error with
|
||||
* errno set to the error code.
|
||||
*/
|
||||
ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
ntfs_mount_flags flags)
|
||||
{
|
||||
LCN mft_zone_size, mft_lcn;
|
||||
s64 br;
|
||||
@ -508,13 +509,25 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
#else
|
||||
NVolClearCompression(vol);
|
||||
#endif
|
||||
if (flags & MS_RDONLY)
|
||||
if (flags & NTFS_MNT_RDONLY)
|
||||
NVolSetReadOnly(vol);
|
||||
|
||||
/* ...->open needs bracketing to compile with glibc 2.7 */
|
||||
if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
|
||||
ntfs_log_perror("Error opening '%s'", dev->d_name);
|
||||
goto error_exit;
|
||||
if (!NVolReadOnly(vol) && (errno == EROFS)) {
|
||||
if ((dev->d_ops->open)(dev, O_RDONLY)) {
|
||||
ntfs_log_perror("Error opening read-only '%s'",
|
||||
dev->d_name);
|
||||
goto error_exit;
|
||||
} else {
|
||||
ntfs_log_info("Can only open '%s' as read-only\n",
|
||||
dev->d_name);
|
||||
NVolSetReadOnly(vol);
|
||||
}
|
||||
} else {
|
||||
ntfs_log_perror("Error opening '%s'", dev->d_name);
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
/* Attach the device to the volume. */
|
||||
vol->dev = dev;
|
||||
@ -649,6 +662,24 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol)
|
||||
|
||||
if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
|
||||
err = EOPNOTSUPP;
|
||||
/*
|
||||
* If the latest restart page was identified as version
|
||||
* 2.0, then Windows may have kept a cached copy of
|
||||
* metadata for fast restarting, and we should not mount.
|
||||
* Hibernation will be seen the same way on a non
|
||||
* Windows-system partition, so we have to use the same
|
||||
* error code (EPERM).
|
||||
* The restart page may also be identified as version 2.0
|
||||
* when access to the file system is terminated abruptly
|
||||
* by unplugging or power cut, so mounting is also rejected
|
||||
* after such an event.
|
||||
*/
|
||||
if (rp
|
||||
&& (rp->major_ver == const_cpu_to_le16(2))
|
||||
&& (rp->minor_ver == const_cpu_to_le16(0))) {
|
||||
ntfs_log_error("Metadata kept in Windows cache, refused to mount.\n");
|
||||
err = EPERM;
|
||||
}
|
||||
free(rp);
|
||||
ntfs_attr_close(na);
|
||||
out:
|
||||
@ -762,7 +793,8 @@ int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
|
||||
errno = EPERM;
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(buf, "hibr", 4) == 0) {
|
||||
if ((memcmp(buf, "hibr", 4) == 0)
|
||||
|| (memcmp(buf, "HIBR", 4) == 0)) {
|
||||
if (verbose)
|
||||
ntfs_log_error("Windows is hibernated, refused to mount.\n");
|
||||
errno = EPERM;
|
||||
@ -856,7 +888,7 @@ static int fix_txf_data(ntfs_volume *vol)
|
||||
* @flags is an optional second parameter. The same flags are used as for
|
||||
* the mount system call (man 2 mount). Currently only the following flag
|
||||
* is implemented:
|
||||
* MS_RDONLY - mount volume read-only
|
||||
* NTFS_MNT_RDONLY - mount volume read-only
|
||||
*
|
||||
* The function opens the device @dev and verifies that it contains a valid
|
||||
* bootsector. Then, it allocates an ntfs_volume structure and initializes
|
||||
@ -867,7 +899,7 @@ static int fix_txf_data(ntfs_volume *vol)
|
||||
* Return the allocated volume structure on success and NULL on error with
|
||||
* errno set to the error code.
|
||||
*/
|
||||
ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
{
|
||||
s64 l;
|
||||
ntfs_volume *vol;
|
||||
@ -1195,12 +1227,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
*/
|
||||
if (!(flags & (MS_RDONLY | MS_FORENSIC))) {
|
||||
if (!(flags & MS_IGNORE_HIBERFILE) &&
|
||||
if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) {
|
||||
if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) &&
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0)
|
||||
goto error_exit;
|
||||
if (ntfs_volume_check_logfile(vol) < 0) {
|
||||
if (!(flags & MS_RECOVER))
|
||||
/* Always reject cached metadata for now */
|
||||
if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM))
|
||||
goto error_exit;
|
||||
ntfs_log_info("The file system wasn't safely "
|
||||
"closed on Windows. Fixing.\n");
|
||||
@ -1289,7 +1322,7 @@ int ntfs_set_ignore_case(ntfs_volume *vol)
|
||||
* @flags is an optional second parameter. The same flags are used as for
|
||||
* the mount system call (man 2 mount). Currently only the following flags
|
||||
* is implemented:
|
||||
* MS_RDONLY - mount volume read-only
|
||||
* NTFS_MNT_RDONLY - mount volume read-only
|
||||
*
|
||||
* The function opens the device or file @name and verifies that it contains a
|
||||
* valid bootsector. Then, it allocates an ntfs_volume structure and initializes
|
||||
@ -1304,7 +1337,7 @@ int ntfs_set_ignore_case(ntfs_volume *vol)
|
||||
* soon as the function returns.
|
||||
*/
|
||||
ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
|
||||
unsigned long flags __attribute__((unused)))
|
||||
ntfs_mount_flags flags __attribute__((unused)))
|
||||
{
|
||||
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
struct ntfs_device *dev;
|
||||
@ -1429,6 +1462,60 @@ exit:
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* HAVE_MNTENT_H */
|
||||
|
||||
#if defined(__sun) && defined (__SVR4)
|
||||
|
||||
static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
|
||||
{
|
||||
struct mnttab *mnt = NULL;
|
||||
char *real_file = NULL, *real_fsname = NULL;
|
||||
FILE *f;
|
||||
int err = 0;
|
||||
|
||||
real_file = (char*)ntfs_malloc(PATH_MAX + 1);
|
||||
if (!real_file)
|
||||
return -1;
|
||||
real_fsname = (char*)ntfs_malloc(PATH_MAX + 1);
|
||||
mnt = (struct mnttab*)ntfs_malloc(MNT_LINE_MAX + 1);
|
||||
if (!real_fsname || !mnt) {
|
||||
err = errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!ntfs_realpath_canonicalize(file, real_file)) {
|
||||
err = errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!(f = fopen(MNTTAB, "r"))) {
|
||||
err = errno;
|
||||
goto exit;
|
||||
}
|
||||
while (!getmntent(f, mnt)) {
|
||||
if (!ntfs_realpath_canonicalize(mnt->mnt_special, real_fsname))
|
||||
continue;
|
||||
if (!strcmp(real_file, real_fsname)) {
|
||||
*mnt_flags = NTFS_MF_MOUNTED;
|
||||
if (!strcmp(mnt->mnt_mountp, "/"))
|
||||
*mnt_flags |= NTFS_MF_ISROOT;
|
||||
if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
|
||||
*mnt_flags |= NTFS_MF_READONLY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
exit:
|
||||
free(mnt);
|
||||
free(real_file);
|
||||
free(real_fsname);
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(__sun) && defined (__SVR4) */
|
||||
#endif /* HAVE_MNTENT_H */
|
||||
|
||||
/**
|
||||
@ -1460,7 +1547,7 @@ int ntfs_check_if_mounted(const char *file __attribute__((unused)),
|
||||
unsigned long *mnt_flags)
|
||||
{
|
||||
*mnt_flags = 0;
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#if defined(HAVE_MNTENT_H) || (defined(__sun) && defined (__SVR4))
|
||||
return ntfs_mntent_check(file, mnt_flags);
|
||||
#else
|
||||
return 0;
|
||||
@ -1642,6 +1729,10 @@ int ntfs_volume_error(int err)
|
||||
ret = NTFS_VOLUME_CORRUPT;
|
||||
break;
|
||||
case EPERM:
|
||||
/*
|
||||
* Hibernation and fast restarting are seen the
|
||||
* same way on a non Windows-system partition.
|
||||
*/
|
||||
ret = NTFS_VOLUME_HIBERNATED;
|
||||
break;
|
||||
case EOPNOTSUPP:
|
||||
@ -1742,7 +1833,7 @@ int ntfs_volume_get_free_space(ntfs_volume *vol)
|
||||
*
|
||||
* Change the label on the volume @vol to @label.
|
||||
*/
|
||||
int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len)
|
||||
int ntfs_volume_rename(ntfs_volume *vol, const ntfschar *label, int label_len)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
char *old_vol_name;
|
||||
@ -1777,7 +1868,7 @@ int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len)
|
||||
|
||||
/* 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))
|
||||
(const u8*) label, label_len))
|
||||
{
|
||||
err = errno;
|
||||
ntfs_log_perror("Encountered error while adding "
|
||||
|
@ -43,23 +43,6 @@
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY,
|
||||
* so we define them ourselves.
|
||||
*/
|
||||
#ifndef MS_RDONLY
|
||||
#define MS_RDONLY 1
|
||||
#endif
|
||||
|
||||
#define MS_EXCLUSIVE 0x08000000
|
||||
|
||||
#ifndef MS_RECOVER
|
||||
#define MS_RECOVER 0x10000000
|
||||
#endif
|
||||
|
||||
#define MS_IGNORE_HIBERFILE 0x20000000
|
||||
#define MS_FORENSIC 0x04000000 /* No modification during mount */
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
@ -74,13 +57,29 @@ typedef struct _ntfs_volume ntfs_volume;
|
||||
/**
|
||||
* enum ntfs_mount_flags -
|
||||
*
|
||||
* Flags for the ntfs_mount() function.
|
||||
*/
|
||||
enum {
|
||||
NTFS_MNT_NONE = 0x00000000,
|
||||
NTFS_MNT_RDONLY = 0x00000001,
|
||||
NTFS_MNT_FORENSIC = 0x04000000, /* No modification during
|
||||
* mount. */
|
||||
NTFS_MNT_EXCLUSIVE = 0x08000000,
|
||||
NTFS_MNT_RECOVER = 0x10000000,
|
||||
NTFS_MNT_IGNORE_HIBERFILE = 0x20000000,
|
||||
};
|
||||
typedef unsigned long ntfs_mount_flags;
|
||||
|
||||
/**
|
||||
* enum ntfs_mounted_flags -
|
||||
*
|
||||
* Flags returned by the ntfs_check_if_mounted() function.
|
||||
*/
|
||||
typedef enum {
|
||||
NTFS_MF_MOUNTED = 1, /* Device is mounted. */
|
||||
NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
|
||||
NTFS_MF_READONLY = 4, /* Device is mounted read-only. */
|
||||
} ntfs_mount_flags;
|
||||
} ntfs_mounted_flags;
|
||||
|
||||
extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
|
||||
|
||||
@ -284,12 +283,12 @@ extern const char *ntfs_home;
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
||||
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
ntfs_mount_flags flags);
|
||||
|
||||
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
ntfs_mount_flags flags);
|
||||
|
||||
extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags);
|
||||
extern ntfs_volume *ntfs_mount(const char *name, ntfs_mount_flags flags);
|
||||
extern int ntfs_umount(ntfs_volume *vol, const BOOL force);
|
||||
|
||||
extern int ntfs_version_is_supported(ntfs_volume *vol);
|
||||
@ -302,7 +301,8 @@ 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_volume_rename(ntfs_volume *vol, const 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