*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:
dimok789 2013-01-15 18:42:00 +00:00
parent 4408cc80f9
commit 968dee4aef
23 changed files with 731 additions and 207 deletions

View File

@ -22,8 +22,13 @@ wii-release:
clean: clean:
$(MAKE) -C source clean $(MAKE) -C source clean
install: cube-release wii-release cube-install: cube-release
$(MAKE) -C source install $(MAKE) -C source cube-install PLATFORM=cube
wii-install: wii-release
$(MAKE) -C source wii-install PLATFORM=wii
install: wii-install
run: install run: install
$(MAKE) -C example $(MAKE) -C example

View File

@ -97,14 +97,13 @@ clean:
all: $(NTFSBIN) all: $(NTFSBIN)
install: cube-install:
cp ../include/ntfs.h $(DEVKITPRO)/libogc/include 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 cp ../lib/cube/libntfs.a $(DEVKITPRO)/libogc/lib/cube
wii-install: wii-install:
cp ../include/ntfs.h $(DEVKITPRO)/libogc/include cp ../include/ntfs.h $(PORTLIBS)/include
cp ../lib/wii/libntfs.a $(DEVKITPRO)/libogc/lib/wii cp ../lib/wii/libntfs.a $(PORTLIBS)/lib
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
else else

View File

@ -4,7 +4,7 @@
* This module is part of ntfs-3g library, but may also be * This module is part of ntfs-3g library, but may also be
* integrated in tools running over Linux or Windows * 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 * 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 * 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 */ 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; 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->identifier_authority.low_part == const_cpu_to_be32(5))
&& (usid->sub_authority[0] == const_cpu_to_le32(32)) && (usid->sub_authority[0] == const_cpu_to_le32(32))
&& (usid->sub_authority[1] == const_cpu_to_le32(545))) && (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))) && (offdacl+sizeof(ACL) < attrsz)))
&& (!offsacl && (!offsacl
|| ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) || ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
&& (offsacl+sizeof(ACL) < attrsz))) && (offsacl+sizeof(ACL) <= attrsz)))
&& !(phead->owner & const_cpu_to_le32(3)) && !(phead->owner & const_cpu_to_le32(3))
&& !(phead->group & const_cpu_to_le32(3)) && !(phead->group & const_cpu_to_le32(3))
&& !(phead->dacl & 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, 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 src;
unsigned int dst; unsigned int dst;
@ -677,7 +697,9 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
int gsidsz; int gsidsz;
const ACCESS_ALLOWED_ACE *poldace; const ACCESS_ALLOWED_ACE *poldace;
ACCESS_ALLOWED_ACE *pnewace; ACCESS_ALLOWED_ACE *pnewace;
ACCESS_ALLOWED_ACE *pauthace;
pauthace = (ACCESS_ALLOWED_ACE*)NULL;
usidsz = ntfs_sid_size(usid); usidsz = ntfs_sid_size(usid);
gsidsz = ntfs_sid_size(gsid); gsidsz = ntfs_sid_size(gsid);
@ -694,25 +716,19 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
for (nace = 0; nace < oldcnt; nace++) { for (nace = 0; nace < oldcnt; nace++) {
poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src); poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src);
acesz = le16_to_cpu(poldace->size); acesz = le16_to_cpu(poldace->size);
/* inheritance for access */ src += acesz;
if (poldace->flags & selection) { /*
* 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*) pnewace = (ACCESS_ALLOWED_ACE*)
((char*)newacl + dst); ((char*)newacl + dst);
memcpy(pnewace,poldace,acesz); memcpy(pnewace,poldace,acesz);
/* /* reencode GENERIC_ALL */
* 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);
}
if (pnewace->mask & GENERIC_ALL) { if (pnewace->mask & GENERIC_ALL) {
pnewace->mask &= ~GENERIC_ALL; pnewace->mask &= ~GENERIC_ALL;
if (fordir) if (fordir)
@ -730,17 +746,71 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
| FILE_WRITE | FILE_WRITE
| FILE_EXEC | FILE_EXEC
| cpu_to_le32(0x40); | 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 */ /* remove inheritance flags */
pnewace->flags &= ~(OBJECT_INHERIT_ACE pnewace->flags &= ~(OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE | CONTAINER_INHERIT_ACE
| INHERIT_ONLY_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 * Inheritance for access, specific to
&& (poldace->flags * creator-owner (and creator-group)
*/
if (fordir || !inherited
|| (poldace->flags
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) { & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) {
pnewace = (ACCESS_ALLOWED_ACE*) pnewace = (ACCESS_ALLOWED_ACE*)
((char*)newacl + dst); ((char*)newacl + dst);
@ -748,19 +818,46 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
/* /*
* Replace generic creator-owner and * Replace generic creator-owner and
* creator-group by owner and group * creator-group by owner and group
* (but keep for further inheritance)
*/ */
if (ntfs_same_sid(&pnewace->sid, ownersid)) { if (ntfs_same_sid(&pnewace->sid, ownersid)) {
memcpy(&pnewace->sid, usid, usidsz); 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)) { if (ntfs_same_sid(&pnewace->sid, groupsid)) {
memcpy(&pnewace->sid, gsid, gsidsz); 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; dst += acesz;
newcnt++; newcnt++;
} }
src += acesz;
} }
/* /*
* Adjust header if something was inherited * Adjust header if something was inherited
@ -3059,6 +3156,7 @@ static int build_owngrp_permissions(const char *securattr,
int nace; int nace;
le32 special; le32 special;
BOOL grppresent; BOOL grppresent;
BOOL ownpresent;
le32 allowown, allowgrp, allowall; le32 allowown, allowgrp, allowall;
le32 denyown, denygrp, denyall; le32 denyown, denygrp, denyall;
@ -3068,21 +3166,26 @@ static int build_owngrp_permissions(const char *securattr,
special = const_cpu_to_le32(0); special = const_cpu_to_le32(0);
allowown = allowgrp = allowall = const_cpu_to_le32(0); allowown = allowgrp = allowall = const_cpu_to_le32(0);
denyown = denygrp = denyall = const_cpu_to_le32(0); denyown = denygrp = denyall = const_cpu_to_le32(0);
ownpresent = FALSE;
grppresent = FALSE; grppresent = FALSE;
if (offdacl) { if (offdacl) {
acecnt = le16_to_cpu(pacl->ace_count); acecnt = le16_to_cpu(pacl->ace_count);
offace = offdacl + sizeof(ACL); offace = offdacl + sizeof(ACL);
} else } else {
acecnt = 0; acecnt = 0;
offace = 0;
}
for (nace = 0; nace < acecnt; nace++) { for (nace = 0; nace < acecnt; nace++) {
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace]; pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
if (!(pace->flags & INHERIT_ONLY_ACE)) { if (!(pace->flags & INHERIT_ONLY_ACE)) {
if ((ntfs_same_sid(usid, &pace->sid) if ((ntfs_same_sid(usid, &pace->sid)
|| ntfs_same_sid(ownersid, &pace->sid)) || ntfs_same_sid(ownersid, &pace->sid))
&& (pace->mask & WRITE_OWNER)) { && (pace->mask & WRITE_OWNER)) {
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) if (pace->type == ACCESS_ALLOWED_ACE_TYPE) {
allowown |= pace->mask; allowown |= pace->mask;
} else ownpresent = TRUE;
}
} else
if (ntfs_same_sid(usid, &pace->sid) if (ntfs_same_sid(usid, &pace->sid)
&& (!(pace->mask & WRITE_OWNER))) { && (!(pace->mask & WRITE_OWNER))) {
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) { 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); offace += le16_to_cpu(pace->size);
} }
if (!ownpresent)
allowown = allowall;
if (!grppresent) if (!grppresent)
allowgrp = allowall; allowgrp = allowall;
return (merge_permissions(isdir, return (merge_permissions(isdir,
@ -3705,7 +3810,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
pxace->perms |= POSIX_PERM_DENIAL; pxace->perms |= POSIX_PERM_DENIAL;
else else
if (pxace->tag == POSIX_ACL_OTHER) if (pxace->tag == POSIX_ACL_OTHER)
pctx->permswrld = pxace->perms; pctx->permswrld |= pxace->perms;
pctx->tagsset |= pxace->tag; pctx->tagsset |= pxace->tag;
if (pace->flags & INHERIT_ONLY_ACE) { if (pace->flags & INHERIT_ONLY_ACE) {
l--; l--;

View File

@ -185,7 +185,8 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
#endif /* POSIXACLS */ #endif /* POSIXACLS */
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, 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, int ntfs_build_permissions(const char *securattr,
const SID *usid, const SID *gsid, BOOL isdir); const SID *usid, const SID *gsid, BOOL isdir);
char *ntfs_build_descr(mode_t mode, char *ntfs_build_descr(mode_t mode,

View File

@ -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"); ntfs_log_perror("Failed to enlarge attribute");
goto errno_set; 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 #else
if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) { if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) {
ntfs_log_perror("Failed to enlarge attribute"); 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. * EIO - I/O error occurred or damaged filesystem.
*/ */
int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, 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,
ATTR_FLAGS data_flags) u32 size, ATTR_FLAGS data_flags)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
u32 length; u32 length;
@ -3864,7 +3871,7 @@ put_err_out:
* EIO - I/O error occurred or damaged filesystem. * EIO - I/O error occurred or damaged filesystem.
*/ */
int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, 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) ATTR_FLAGS flags)
{ {
ntfs_attr_search_ctx *ctx; 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. * 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, 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; u32 attr_rec_size;
int err, i, offset; int err, i, offset;
@ -4342,8 +4349,8 @@ err_out:
* Change an attribute flag * Change an attribute flag
*/ */
int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, const ntfschar *name,
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask) u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;
int res; 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. */ /* Prepare to mapping pairs update. */
na->allocated_size = first_free_vcn << vol->cluster_size_bits; na->allocated_size = first_free_vcn << vol->cluster_size_bits;
/* Write mapping pairs for new runlist. */
#if PARTIAL_RUNLIST_UPDATING #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 #else
/* Write mapping pairs for new runlist. */
if (ntfs_attr_update_mapping_pairs(na, 0)) { if (ntfs_attr_update_mapping_pairs(na, 0)) {
#endif #endif
err = errno; err = errno;
@ -6646,9 +6661,8 @@ exit:
* Returns the amount of data written, negative if there was an error * Returns the amount of data written, negative if there was an error
*/ */
int ntfs_attr_data_write(ntfs_inode *ni, int ntfs_attr_data_write(ntfs_inode *ni, ntfschar *stream_name,
ntfschar *stream_name, int stream_name_len, int stream_name_len, const char *buf, size_t size, off_t offset)
char *buf, size_t size, off_t offset)
{ {
ntfs_attr *na = NULL; ntfs_attr *na = NULL;
int res, total = 0; 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) u32 name_len)
{ {
ntfs_attr_search_ctx *ctx; ntfs_attr_search_ctx *ctx;

View File

@ -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_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, 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); ATTR_FLAGS flags);
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, 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, const ntfschar *name, u8 name_len, VCN lowest_vcn,
ATTR_FLAGS flags); int dataruns_size, ATTR_FLAGS flags);
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx); extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, 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, 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_rm(ntfs_attr *na);
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); 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 void ntfs_attr_name_free(char **name);
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len); 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, 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, extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
ntfschar *name, u32 name_len); ntfschar *name, u32 name_len);
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na); 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); char *buf, size_t size, off_t offset);
extern int ntfs_attr_data_write(ntfs_inode *ni, extern int ntfs_attr_data_write(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len, 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 */ #endif /* defined _NTFS_ATTRIB_H */

View File

@ -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); vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_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); ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
if (vol->mft_lcn > vol->nr_clusters || if ((vol->mft_lcn < 0 || vol->mft_lcn > vol->nr_clusters) ||
vol->mftmirr_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 " ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
"greater than the number of clusters (%lld).\n", "greater than the number of clusters (%lld).\n",
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn, (long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,

View File

@ -31,6 +31,12 @@
#include <sys/param.h> #include <sys/param.h>
#endif #endif
#include <errno.h> /* ENODATA */
#ifndef ENODATA
#define ENODATA ENOENT
#endif
#ifndef PATH_MAX #ifndef PATH_MAX
#define PATH_MAX 4096 #define PATH_MAX 4096
#endif #endif

View File

@ -107,8 +107,8 @@
/* Define to 1 if you have the <machine/endian.h> header file. */ /* Define to 1 if you have the <machine/endian.h> header file. */
#define HAVE_MACHINE_ENDIAN_H 1 #define HAVE_MACHINE_ENDIAN_H 1
/* Define to 1 if you have the <math.h> header file. */ /* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MATH_H 1 #define HAVE_MALLOC_H 1
/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ /* Define to 1 if mbrtowc and mbstate_t are properly declared. */
#define HAVE_MBRTOWC 1 #define HAVE_MBRTOWC 1
@ -116,6 +116,9 @@
/* Define to 1 if you have the `mbsinit' function. */ /* Define to 1 if you have the `mbsinit' function. */
#define HAVE_MBSINIT 1 #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 to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1 #define HAVE_MEMMOVE 1
@ -131,6 +134,9 @@
/* Define to 1 if you have the <pwd.h> header file. */ /* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1 #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. */ /* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH #undef HAVE_REALPATH
@ -143,9 +149,12 @@
/* Define to 1 if you have the `setxattr' function. */ /* Define to 1 if you have the `setxattr' function. */
#undef HAVE_SETXATTR #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 /* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */ 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 to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1 #define HAVE_STDARG_H 1
@ -312,13 +321,13 @@
#define PACKAGE_NAME "ntfs-3g" #define PACKAGE_NAME "ntfs-3g"
/* Define to the full name and version of this package. */ /* 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 to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ntfs-3g" #define PACKAGE_TARNAME "ntfs-3g"
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "2012.1.15" #define PACKAGE_VERSION "2013.1.13"
/* POSIX ACL support */ /* POSIX ACL support */
#undef POSIXACLS #undef POSIXACLS
@ -326,29 +335,8 @@
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1 #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 */ /* Version number of package */
#define VERSION "2012.1.15" #define VERSION "2013.1.13"
/* Define to 1 if this is a Windows OS */ /* Define to 1 if this is a Windows OS */
#undef WINDOWS #undef WINDOWS
@ -392,3 +380,6 @@
/* Define to `unsigned int' if <sys/types.h> does not define. */ /* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t #undef size_t
/* Define to 1 if you have the <math.h> header file. */
#define HAVE_MATH_H 1

View File

@ -867,6 +867,87 @@ typedef enum {
INDEX_TYPE_ALLOCATION, /* index allocation */ INDEX_TYPE_ALLOCATION, /* index allocation */
} INDEX_TYPE; } 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 * ntfs_filldir - ntfs specific filldir method
* @dir_ni: ntfs inode of current directory * @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; dir_ni->vol->mft_record_size;
else /* if (index_type == INDEX_TYPE_ROOT) */ else /* if (index_type == INDEX_TYPE_ROOT) */
*pos = (u8*)ie - (u8*)iu.ir; *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. */ /* Skip root directory self reference entry. */
if (MREF_LE(ie->indexed_file) == FILE_root) if (MREF_LE(ie->indexed_file) == FILE_root)
return 0; 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; dt_type = NTFS_DT_DIR;
else if (fn->file_attributes & FILE_ATTR_SYSTEM)
dt_type = NTFS_DT_UNKNOWN;
else else
dt_type = NTFS_DT_REG; dt_type = NTFS_DT_REG;
/* return metadata files and hidden files if requested */ /* 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) if ((!metadata && (NVolShowHidFiles(dir_ni->vol)
|| !(fn->file_attributes & FILE_ATTR_HIDDEN))) || !(fn->file_attributes & FILE_ATTR_HIDDEN)))
|| (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol) || (NVolShowSysFiles(dir_ni->vol) && (NVolShowHidFiles(dir_ni->vol)
@ -1397,8 +1482,8 @@ err_out:
* on error with errno set to the error code. * on error with errno set to the error code.
*/ */
static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, static ntfs_inode *__ntfs_create(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,
ntfschar *target, int target_len) const ntfschar *target, int target_len)
{ {
ntfs_inode *ni; ntfs_inode *ni;
int rollback_data = 0, rollback_sd = 0; int rollback_data = 0, rollback_sd = 0;
@ -1667,7 +1752,7 @@ err_out:
* Some wrappers around __ntfs_create() ... * 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) u8 name_len, mode_t type)
{ {
if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO && 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, 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) { if (type != S_IFCHR && type != S_IFBLK) {
ntfs_log_error("Invalid arguments.\n"); 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, 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) { if (!target || !target_len) {
ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__, 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. * Return 0 on success or -1 on error with errno set to the error code.
*/ */
int ntfs_delete(ntfs_volume *vol, const char *pathname, 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; ntfs_attr_search_ctx *actx = NULL;
FILE_NAME_ATTR *fn = 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))) if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length)))
goto err_out; 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 = cpu_to_le16(le16_to_cpu(
ni->mrec->link_count) - 1); ni->mrec->link_count) - 1);
@ -2002,6 +2099,7 @@ search:
"Leaving inconsistent metadata.\n"); "Leaving inconsistent metadata.\n");
} }
#endif #endif
debug_double_inode(ni->mft_no,0);
if (ntfs_mft_record_free(ni->vol, ni)) { if (ntfs_mft_record_free(ni->vol, ni)) {
err = errno; err = errno;
ntfs_log_error("Failed to free base MFT record. " 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. * 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) u8 name_len, FILE_NAME_TYPE_FLAGS nametype)
{ {
FILE_NAME_ATTR *fn = NULL; 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; err = EOPNOTSUPP;
goto err_out; 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. */ /* Create FILE_NAME attribute. */
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
@ -2121,7 +2228,8 @@ err_out:
return -1; 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)); 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 * Get a DOS name for a file in designated directory
* *
* Not allowed if there are several non-dos names (EMLINK)
*
* Returns size if found * Returns size if found
* 0 if not found * 0 if not found
* -1 if there was an error (described by errno) * -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) static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname)
{ {
size_t outsize = 0; size_t outsize = 0;
int namecount = 0;
FILE_NAME_ATTR *fn; FILE_NAME_ATTR *fn;
ntfs_attr_search_ctx *ctx; 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 + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->value_offset)); le16_to_cpu(ctx->attr->value_offset));
if (fn->file_name_type != FILE_NAME_DOS)
namecount++;
if ((fn->file_name_type & FILE_NAME_DOS) if ((fn->file_name_type & FILE_NAME_DOS)
&& (MREF_LE(fn->parent_directory) == dnum)) { && (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); 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); 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 * Get a long name for a file in designated directory
* *
* Not allowed if there are several non-dos names (EMLINK)
*
* Returns size if found * Returns size if found
* 0 if not found * 0 if not found
* -1 if there was an error (described by errno) * -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) static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname)
{ {
size_t outsize = 0; size_t outsize = 0;
int namecount = 0;
FILE_NAME_ATTR *fn; FILE_NAME_ATTR *fn;
ntfs_attr_search_ctx *ctx; 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 + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->value_offset)); le16_to_cpu(ctx->attr->value_offset));
if (fn->file_name_type != FILE_NAME_DOS)
namecount++;
if ((fn->file_name_type & FILE_NAME_WIN32) if ((fn->file_name_type & FILE_NAME_WIN32)
&& (MREF_LE(fn->parent_directory) == dnum)) { && (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; outsize = fn->file_name_length;
memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); 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 not found search for POSIX names */
if (!outsize) { 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, 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) FILE_NAME_TYPE_FLAGS nametype)
{ {
ntfs_attr_search_ctx *actx; 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, static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
ntfschar *shortname, int shortlen, const ntfschar *shortname, int shortlen,
ntfschar *longname, int longlen, const ntfschar *longname, int longlen,
ntfschar *deletename, int deletelen, BOOL existed) const ntfschar *deletename, int deletelen, BOOL existed)
{ {
unsigned int linkcount; unsigned int linkcount;
ntfs_volume *vol; ntfs_volume *vol;
@ -2568,7 +2695,8 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
res = -1; res = -1;
} else { } else {
res = -1; res = -1;
errno = ENOENT; if (!longlen)
errno = ENOENT;
} }
free(shortname); free(shortname);
if (!closed) { if (!closed) {
@ -2644,7 +2772,8 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
} }
} }
} else { } else {
errno = ENOENT; if (!longlen)
errno = ENOENT;
res = -1; res = -1;
} }
if (!deleted) { if (!deleted) {

View File

@ -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, extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
const char *pathname); const char *pathname);
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid, 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, 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, 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_check_empty_dir(ntfs_inode *ni);
extern int ntfs_delete(ntfs_volume *vol, const char *path, 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); 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); u8 name_len);
/* /*

View File

@ -2398,18 +2398,19 @@ typedef enum {
IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001), IO_REPARSE_TAG_RESERVED_ONE = const_cpu_to_le32(0x00000001),
IO_REPARSE_TAG_RESERVED_RANGE = 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_CSV = const_cpu_to_le32(0x80000009),
IO_REPARSE_TAG_NSS_RECOVER = const_cpu_to_le32(0x68000006), IO_REPARSE_TAG_DEDUP = const_cpu_to_le32(0x80000013),
IO_REPARSE_TAG_SIS = const_cpu_to_le32(0x68000007), IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x8000000A),
IO_REPARSE_TAG_DFS = const_cpu_to_le32(0x68000008), 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_VALID_VALUES = const_cpu_to_le32(0xf000ffff),
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),
} PREDEFINED_REPARSE_TAGS; } PREDEFINED_REPARSE_TAGS;
/** /**

View File

@ -84,13 +84,21 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
"position in $LogFile.\n"); "position in $LogFile.\n");
return FALSE; return FALSE;
} }
/* We only know how to handle version 1.1. */ /*
if (sle16_to_cpu(rp->major_ver) != 1 || * We only know how to handle version 1.1 and 2.0, though
sle16_to_cpu(rp->minor_ver) != 1) { * 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 " ntfs_log_error("$LogFile version %i.%i is not "
"supported. (This driver supports version " "supported.\n (This driver supports version "
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver), "1.1 and 2.0 only.)\n",
(int)sle16_to_cpu(rp->minor_ver)); (int)sle16_to_cpu(rp->major_ver),
(int)sle16_to_cpu(rp->minor_ver));
return FALSE; return FALSE;
} }
/* /*

View File

@ -475,20 +475,20 @@ bool ntfsMount (const char *name, const DISC_INTERFACE *interface, sec_t startSe
// Build the mount flags // Build the mount flags
if (flags & NTFS_READ_ONLY) if (flags & NTFS_READ_ONLY)
vd->flags |= MS_RDONLY; vd->flags |= NTFS_MNT_RDONLY;
else else
{ {
if (!(interface->features & FEATURE_MEDIUM_CANWRITE)) 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)) if ((interface->features & FEATURE_MEDIUM_CANREAD) && (interface->features & FEATURE_MEDIUM_CANWRITE))
vd->flags |= MS_EXCLUSIVE; vd->flags |= NTFS_MNT_EXCLUSIVE;
} }
if (flags & NTFS_RECOVER) if (flags & NTFS_RECOVER)
vd->flags |= MS_RECOVER; vd->flags |= NTFS_MNT_RECOVER;
if (flags & NTFS_IGNORE_HIBERFILE) 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); ntfs_log_debug("Mounting \"%s\" as read-only\n", name);
// Mount the device // Mount the device

View File

@ -670,7 +670,7 @@ cleanup:
// Unlock // Unlock
ntfsUnlock(vd); ntfsUnlock(vd);
return 0; return res;
} }
int ntfsSync (ntfs_vd *vd, ntfs_inode *ni) int ntfsSync (ntfs_vd *vd, ntfs_inode *ni)

View File

@ -46,6 +46,7 @@
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#endif #endif
#include "compat.h"
#include "types.h" #include "types.h"
#include "debug.h" #include "debug.h"
#include "attrib.h" #include "attrib.h"

View File

@ -44,12 +44,18 @@ enum {
*/ */
/* default option for compression */ /* default option for compression */
#define DEFAULT_COMPRESSION FALSE #define DEFAULT_COMPRESSION 0
/* (log2 of) number of clusters in a compression block for new files */ /* (log2 of) number of clusters in a compression block for new files */
#define STANDARD_COMPRESSION_UNIT 4 #define STANDARD_COMPRESSION_UNIT 4
/* maximum cluster size for allowing compression for new files */ /* maximum cluster size for allowing compression for new files */
#define MAX_COMPRESSION_CLUSTER_SIZE 4096 #define MAX_COMPRESSION_CLUSTER_SIZE 4096
/*
* Parameters for default options
*/
#define DEFAULT_DMTIME 60 /* default 1mn for delay_mtime */
/* /*
* Use of big write buffers * Use of big write buffers
* *
@ -109,7 +115,11 @@ enum {
* of 6 is added in the mount report. * 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 #define HPERMSCONFIG 1
#endif
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28) #if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
#define LPERMSCONFIG 5 #define LPERMSCONFIG 5
#else #else

View File

@ -3,7 +3,7 @@
* *
* This module is part of ntfs-3g library * 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 * 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 * modify it under the terms of the GNU General Public License as published
@ -46,8 +46,10 @@
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#endif #endif
#include "compat.h"
#include "types.h" #include "types.h"
#include "debug.h" #include "debug.h"
#include "layout.h"
#include "attrib.h" #include "attrib.h"
#include "inode.h" #include "inode.h"
#include "dir.h" #include "dir.h"
@ -59,18 +61,6 @@
#include "misc.h" #include "misc.h"
#include "reparse.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 */ struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
le16 subst_name_offset; le16 subst_name_offset;
le16 subst_name_length; 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); ni = ntfs_inode_open(vol, (MFT_REF)FILE_root);
if (ni) { if (ni) {
start = 0; 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 { do {
len = 0; len = 0;
while (((start + len) < count) while (((start + len) < count)
@ -252,9 +253,11 @@ static char *search_absolute(ntfs_volume *vol, ntfschar *path,
} }
} while (ni } while (ni
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
&& !(ni->flags & FILE_ATTR_REPARSE_POINT)
&& (start < count)); && (start < count));
if (ni 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 (ntfs_ucstombs(path, count, &target, 0) < 0) {
if (target) { if (target) {
free(target); free(target);
@ -288,12 +291,25 @@ static char *search_relative(ntfs_inode *ni, ntfschar *path, int count)
int pos; int pos;
int lth; int lth;
BOOL ok; BOOL ok;
BOOL morelinks;
int max = 32; /* safety */ int max = 32; /* safety */
pos = 0; pos = 0;
ok = TRUE; ok = TRUE;
morelinks = FALSE;
curni = ntfs_dir_parent_inode(ni); 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)) if ((count >= (pos + 2))
&& (path[pos] == const_cpu_to_le16('.')) && (path[pos] == const_cpu_to_le16('.'))
&& (path[pos+1] == 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) if (!curni)
ok = FALSE; ok = FALSE;
else { else {
if (curni->flags & FILE_ATTR_REPARSE_POINT)
morelinks = TRUE;
if (ok && ((pos + lth) < count)) { if (ok && ((pos + lth) < count)) {
path[pos + lth] = const_cpu_to_le16('/'); path[pos + lth] = const_cpu_to_le16('/');
pos += lth + 1; pos += lth + 1;
if (morelinks
&& ntfs_inode_close(curni))
ok = FALSE;
} else { } else {
pos += lth; pos += lth;
if ((ni->mrec->flags ^ curni->mrec->flags) if (!morelinks
&& (ni->mrec->flags ^ curni->mrec->flags)
& MFT_RECORD_IS_DIRECTORY) & MFT_RECORD_IS_DIRECTORY)
ok = FALSE; ok = FALSE;
if (ntfs_inode_close(curni)) if (ntfs_inode_close(curni))

View File

@ -4,7 +4,7 @@
* Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2006 Yura Pakhuchiy * 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 * 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 * modify it under the terms of the GNU General Public License as published
@ -52,6 +52,7 @@
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#include "compat.h"
#include "param.h" #include "param.h"
#include "types.h" #include "types.h"
#include "layout.h" #include "layout.h"
@ -1128,10 +1129,86 @@ static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid
return (ingroup); return (ingroup);
} }
#if defined(__sun) && defined (__SVR4)
/* /*
* Check whether current thread owner is member of file group * 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 * Should not be called for user root, however the group may be root
* *
* As indicated by Miklos Szeredi : * As indicated by Miklos Szeredi :
@ -1234,6 +1311,8 @@ static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
return (ismember); return (ismember);
} }
#endif /* defined(__sun) && defined (__SVR4) */
/* /*
* Cacheing is done two-way : * Cacheing is done two-way :
* - from uid, gid and perm to securid (CACHED_SECURID) * - 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) { if (!scx->uid) {
/* root access if owner or other execution */ /* root access if owner or other execution */
if (perms & 0101) if (perms & 0101)
perms = 07777; perms |= 01777;
else { else {
/* root access if some group execution */ /* root access if some group execution */
groupperms = 0; groupperms = 0;
@ -2213,7 +2292,7 @@ static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
if (!scx->uid) { if (!scx->uid) {
/* root access and execution */ /* root access and execution */
if (perm & 0111) if (perm & 0111)
perm = 07777; perm |= 01777;
else else
perm = 0; perm = 0;
} else } else
@ -3316,6 +3395,56 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
return (allow); 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 */ #if 0 /* not needed any more */
/* /*
@ -3467,10 +3596,12 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
uid = fileuid; uid = fileuid;
if ((int)gid < 0) if ((int)gid < 0)
gid = filegid; gid = filegid;
#if !defined(__sun) || !defined (__SVR4)
/* clear setuid and setgid if owner has changed */ /* clear setuid and setgid if owner has changed */
/* unless request originated by root */ /* unless request originated by root */
if (uid && (fileuid != uid)) if (uid && (fileuid != uid))
mode &= 01777; mode &= 01777;
#endif
#if POSIXACLS #if POSIXACLS
res = ntfs_set_owner_mode(scx, ni, uid, gid, res = ntfs_set_owner_mode(scx, ni, uid, gid,
mode, pxdesc); mode, pxdesc);
@ -3679,7 +3810,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr; pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
pnhead->revision = SECURITY_DESCRIPTOR_REVISION; pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
pnhead->alignment = 0; 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); pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
/* /*
* locate and inherit DACL * locate and inherit DACL
@ -3690,7 +3823,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
offpacl = le32_to_cpu(pphead->dacl); offpacl = le32_to_cpu(pphead->dacl);
ppacl = (const ACL*)&parentattr[offpacl]; ppacl = (const ACL*)&parentattr[offpacl];
pnacl = (ACL*)&newattr[pos]; 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) { if (aclsz) {
pnhead->dacl = cpu_to_le32(pos); pnhead->dacl = cpu_to_le32(pos);
pos += aclsz; pos += aclsz;
@ -3705,7 +3840,9 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
offpacl = le32_to_cpu(pphead->sacl); offpacl = le32_to_cpu(pphead->sacl);
ppacl = (const ACL*)&parentattr[offpacl]; ppacl = (const ACL*)&parentattr[offpacl];
pnacl = (ACL*)&newattr[pos]; 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) { if (aclsz) {
pnhead->sacl = cpu_to_le32(pos); pnhead->sacl = cpu_to_le32(pos);
pos += aclsz; pos += aclsz;
@ -3723,7 +3860,7 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
*/ */
memcpy(&newattr[pos],gsid,gsidsz); memcpy(&newattr[pos],gsid,gsidsz);
pnhead->group = cpu_to_le32(pos); pnhead->group = cpu_to_le32(pos);
pos += usidsz; pos += gsidsz;
securid = setsecurityattr(scx->vol, securid = setsecurityattr(scx->vol,
(SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos); (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
free(newattr); free(newattr);

View File

@ -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); BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, int accesstype); 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, BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
const char *path, int accesstype); const char *path, int accesstype);

View File

@ -710,9 +710,9 @@ static int utf8_to_unicode(u32 *wc, const char *s)
| ((u32)(s[1] & 0x3F) << 12) | ((u32)(s[1] & 0x3F) << 12)
| ((u32)(s[2] & 0x3F) << 6) | ((u32)(s[2] & 0x3F) << 6)
| ((u32)(s[3] & 0x3F)); | ((u32)(s[3] & 0x3F));
/* Check valid ranges */ /* Check valid ranges */
if ((*wc <= 0x10ffff) && (*wc >= 0x10000)) if ((*wc <= 0x10ffff) && (*wc >= 0x10000))
return 4; return 4;
} }
goto fail; goto fail;
} }

View File

@ -54,6 +54,10 @@
#include <locale.h> #include <locale.h>
#endif #endif
#if defined(__sun) && defined (__SVR4)
#include <sys/mnttab.h>
#endif
#include "param.h" #include "param.h"
#include "compat.h" #include "compat.h"
#include "volume.h" #include "volume.h"
@ -89,13 +93,9 @@ static const char *corrupt_volume_msg =
"for more details.\n"; "for more details.\n";
static const char *hibernated_volume_msg = static const char *hibernated_volume_msg =
"The NTFS partition is hibernated. Please resume and shutdown Windows\n" "The NTFS partition is in an unsafe state. Please resume and shutdown\n"
"properly, or mount the volume read-only with the 'ro' mount option, or\n" "Windows fully (no hibernation or fast restarting), or mount the volume\n"
"mount the volume read-write with the 'remove_hiberfile' mount option.\n" "read-only with the 'ro' mount option.\n";
"For example type on the command line:\n"
"\n"
" mount -t ntfs-3g -o remove_hiberfile %s %s\n"
"\n";
static const char *unclean_journal_msg = static const char *unclean_journal_msg =
"Write access is denied because the disk wasn't safely powered\n" "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 * Return the allocated volume structure on success and NULL on error with
* errno set to the error code. * 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; LCN mft_zone_size, mft_lcn;
s64 br; s64 br;
@ -508,13 +509,25 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
#else #else
NVolClearCompression(vol); NVolClearCompression(vol);
#endif #endif
if (flags & MS_RDONLY) if (flags & NTFS_MNT_RDONLY)
NVolSetReadOnly(vol); NVolSetReadOnly(vol);
/* ...->open needs bracketing to compile with glibc 2.7 */ /* ...->open needs bracketing to compile with glibc 2.7 */
if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) { if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
ntfs_log_perror("Error opening '%s'", dev->d_name); if (!NVolReadOnly(vol) && (errno == EROFS)) {
goto error_exit; 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. */ /* Attach the device to the volume. */
vol->dev = dev; 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)) if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
err = EOPNOTSUPP; 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); free(rp);
ntfs_attr_close(na); ntfs_attr_close(na);
out: out:
@ -762,7 +793,8 @@ int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
errno = EPERM; errno = EPERM;
goto out; goto out;
} }
if (memcmp(buf, "hibr", 4) == 0) { if ((memcmp(buf, "hibr", 4) == 0)
|| (memcmp(buf, "HIBR", 4) == 0)) {
if (verbose) if (verbose)
ntfs_log_error("Windows is hibernated, refused to mount.\n"); ntfs_log_error("Windows is hibernated, refused to mount.\n");
errno = EPERM; 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 * @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 * the mount system call (man 2 mount). Currently only the following flag
* is implemented: * 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 * The function opens the device @dev and verifies that it contains a valid
* bootsector. Then, it allocates an ntfs_volume structure and initializes * 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 * Return the allocated volume structure on success and NULL on error with
* errno set to the error code. * 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; s64 l;
ntfs_volume *vol; 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. * Check for dirty logfile and hibernated Windows.
* We care only about read-write mounts. * We care only about read-write mounts.
*/ */
if (!(flags & (MS_RDONLY | MS_FORENSIC))) { if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) {
if (!(flags & MS_IGNORE_HIBERFILE) && if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) &&
ntfs_volume_check_hiberfile(vol, 1) < 0) ntfs_volume_check_hiberfile(vol, 1) < 0)
goto error_exit; goto error_exit;
if (ntfs_volume_check_logfile(vol) < 0) { 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; goto error_exit;
ntfs_log_info("The file system wasn't safely " ntfs_log_info("The file system wasn't safely "
"closed on Windows. Fixing.\n"); "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 * @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 * the mount system call (man 2 mount). Currently only the following flags
* is implemented: * 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 * 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 * 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. * soon as the function returns.
*/ */
ntfs_volume *ntfs_mount(const char *name __attribute__((unused)), 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 #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
struct ntfs_device *dev; struct ntfs_device *dev;
@ -1429,6 +1462,60 @@ exit:
} }
return 0; 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 */ #endif /* HAVE_MNTENT_H */
/** /**
@ -1460,7 +1547,7 @@ int ntfs_check_if_mounted(const char *file __attribute__((unused)),
unsigned long *mnt_flags) unsigned long *mnt_flags)
{ {
*mnt_flags = 0; *mnt_flags = 0;
#ifdef HAVE_MNTENT_H #if defined(HAVE_MNTENT_H) || (defined(__sun) && defined (__SVR4))
return ntfs_mntent_check(file, mnt_flags); return ntfs_mntent_check(file, mnt_flags);
#else #else
return 0; return 0;
@ -1642,6 +1729,10 @@ int ntfs_volume_error(int err)
ret = NTFS_VOLUME_CORRUPT; ret = NTFS_VOLUME_CORRUPT;
break; break;
case EPERM: case EPERM:
/*
* Hibernation and fast restarting are seen the
* same way on a non Windows-system partition.
*/
ret = NTFS_VOLUME_HIBERNATED; ret = NTFS_VOLUME_HIBERNATED;
break; break;
case EOPNOTSUPP: case EOPNOTSUPP:
@ -1742,7 +1833,7 @@ int ntfs_volume_get_free_space(ntfs_volume *vol)
* *
* Change the label on the volume @vol to @label. * 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; ntfs_attr *na;
char *old_vol_name; 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. */ /* The volume name attribute does not exist. Need to add it. */
if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0, if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0,
(u8*) label, label_len)) (const u8*) label, label_len))
{ {
err = errno; err = errno;
ntfs_log_perror("Encountered error while adding " ntfs_log_perror("Encountered error while adding "

View File

@ -43,23 +43,6 @@
#include <mntent.h> #include <mntent.h>
#endif #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 */ /* Forward declaration */
typedef struct _ntfs_volume ntfs_volume; typedef struct _ntfs_volume ntfs_volume;
@ -74,13 +57,29 @@ typedef struct _ntfs_volume ntfs_volume;
/** /**
* enum ntfs_mount_flags - * 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. * Flags returned by the ntfs_check_if_mounted() function.
*/ */
typedef enum { typedef enum {
NTFS_MF_MOUNTED = 1, /* Device is mounted. */ NTFS_MF_MOUNTED = 1, /* Device is mounted. */
NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */ NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
NTFS_MF_READONLY = 4, /* Device is mounted read-only. */ 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); 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_alloc(void);
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, 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, 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_umount(ntfs_volume *vol, const BOOL force);
extern int ntfs_version_is_supported(ntfs_volume *vol); 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 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_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, extern int ntfs_set_shown_files(ntfs_volume *vol,
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files); BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files);