ntfs: Update ntfs3g
This commit is contained in:
@@ -264,7 +264,7 @@ fs_identify_partition(int fd, partition_data *partition, void **_cookie)
|
||||
// get path for device
|
||||
if (ioctl(fd, B_GET_PATH_FOR_DEVICE, devpath) != 0) {
|
||||
// try mount
|
||||
ntVolume = utils_mount_volume(devpath, MS_RDONLY | MS_RECOVER);
|
||||
ntVolume = utils_mount_volume(devpath, NTFS_MNT_RDONLY | NTFS_MNT_RECOVER);
|
||||
if (ntVolume != NULL) {
|
||||
if (ntVolume->vol_name && ntVolume->vol_name[0] != '\0')
|
||||
strcpy(cookie->label, ntVolume->vol_name);
|
||||
@@ -384,7 +384,7 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args,
|
||||
|
||||
if (ns->ro || (flags & B_MOUNT_READ_ONLY) != 0
|
||||
|| is_device_read_only(device)) {
|
||||
mountFlags |= MS_RDONLY;
|
||||
mountFlags |= NTFS_MNT_RDONLY;
|
||||
ns->flags |= B_FS_IS_READONLY;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ fs_mount(fs_volume *_vol, const char *device, ulong flags, const char *args,
|
||||
gNTFSVnodeOps.remove_attr = fs_remove_attrib;
|
||||
}
|
||||
|
||||
ns->ntvol = utils_mount_volume(device, mountFlags | MS_RECOVER);
|
||||
ns->ntvol = utils_mount_volume(device, mountFlags | NTFS_MNT_RECOVER);
|
||||
if (ns->ntvol != NULL)
|
||||
result = B_NO_ERROR;
|
||||
else
|
||||
|
||||
@@ -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
|
||||
@@ -108,7 +108,6 @@
|
||||
#include "secaudit.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define getgrnam(x) NULL
|
||||
#define getpwnam(x) NULL
|
||||
@@ -142,6 +141,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;
|
||||
|
||||
/*
|
||||
@@ -241,6 +253,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)))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -629,7 +647,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))
|
||||
@@ -670,7 +688,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;
|
||||
@@ -683,7 +702,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);
|
||||
|
||||
@@ -700,25 +721,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)
|
||||
@@ -736,17 +751,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);
|
||||
@@ -754,19 +823,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
|
||||
@@ -3065,6 +3161,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;
|
||||
|
||||
@@ -3074,21 +3171,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) {
|
||||
@@ -3109,6 +3211,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,
|
||||
@@ -3711,7 +3815,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--;
|
||||
@@ -3901,7 +4005,6 @@ int ntfs_build_permissions(const char *securattr,
|
||||
/*
|
||||
* The following must be in some library...
|
||||
*/
|
||||
|
||||
#ifndef __HAIKU__
|
||||
static unsigned long atoul(const char *p)
|
||||
{ /* must be somewhere ! */
|
||||
@@ -3914,7 +4017,6 @@ static unsigned long atoul(const char *p)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Build an internal representation of a SID
|
||||
* Returns a copy in allocated memory if it succeeds
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -962,7 +1047,7 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
|
||||
* Return the mft reference of the parent directory on success or -1 on error
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
static MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
|
||||
MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
|
||||
{
|
||||
MFT_REF mref;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
@@ -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) {
|
||||
|
||||
@@ -74,17 +74,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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* list.h - Linked list implementation. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov and others
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the NTFS-3G
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_LIST_H
|
||||
#define _NTFS_LIST_H
|
||||
|
||||
/**
|
||||
* struct list_head - Simple doubly linked list implementation.
|
||||
*
|
||||
* Copied from Linux kernel 2.4.2-ac18 into Linux-NTFS (with minor
|
||||
* modifications). - AIA
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* __list_add - Insert a new entry between two known consecutive entries.
|
||||
* @new:
|
||||
* @prev:
|
||||
* @next:
|
||||
*
|
||||
* This is only for internal list manipulation where we know the prev/next
|
||||
* entries already!
|
||||
*/
|
||||
static void __list_add(struct list_head * new,
|
||||
struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* __list_del -
|
||||
* @prev:
|
||||
* @next:
|
||||
*
|
||||
* Delete a list entry by making the prev/next entries point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know the prev/next
|
||||
* entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*
|
||||
* Note: list_empty on entry does not return true after this, the entry is in
|
||||
* an undefined state.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
#endif /* defined _NTFS_LIST_H */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -188,7 +188,6 @@ u32 ntfs_log_clear_flags(u32 flags)
|
||||
return old;
|
||||
}
|
||||
|
||||
#ifndef __HAIKU__
|
||||
/**
|
||||
* ntfs_log_get_stream - Default output streams for logging levels
|
||||
* @level: Log level
|
||||
@@ -198,6 +197,7 @@ u32 ntfs_log_clear_flags(u32 flags)
|
||||
*
|
||||
* Returns: "string" Prefix to be used
|
||||
*/
|
||||
#ifndef __HAIKU__
|
||||
static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
FILE *stream;
|
||||
@@ -276,8 +276,7 @@ static const char * ntfs_log_get_prefix(u32 level)
|
||||
|
||||
return prefix;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //__HAIKU___
|
||||
|
||||
/**
|
||||
* ntfs_log_set_handler - Provide an alternate logging handler
|
||||
@@ -399,7 +398,7 @@ out:
|
||||
|
||||
void ntfs_log_early_error(const char *format, ...)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
#ifndef __HAIKU__
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
@@ -412,10 +411,9 @@ void ntfs_log_early_error(const char *format, ...)
|
||||
vfprintf(stderr,format,args);
|
||||
#endif
|
||||
va_end(args);
|
||||
#endif
|
||||
#endif //__HAIKU__
|
||||
}
|
||||
|
||||
#ifndef __HAIKU__
|
||||
/**
|
||||
* ntfs_log_handler_fprintf - Basic logging handler
|
||||
* @function: Function in which the log line occurred
|
||||
@@ -437,6 +435,7 @@ void ntfs_log_early_error(const char *format, ...)
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
#ifndef __HAIKU__
|
||||
int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
@@ -491,7 +490,6 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
errno = olderr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // __HAIKU__
|
||||
|
||||
/**
|
||||
@@ -516,8 +514,6 @@ int ntfs_log_handler_null(const char *function __attribute__((unused)), const ch
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef __HAIKU__
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_stdout - All logs go to stdout
|
||||
* @function: Function in which the log line occurred
|
||||
@@ -539,6 +535,7 @@ int ntfs_log_handler_null(const char *function __attribute__((unused)), const ch
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
#ifndef __HAIKU__
|
||||
int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
@@ -608,8 +605,7 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
#endif // __HAIKU__
|
||||
#endif //__HAIKU__
|
||||
|
||||
/**
|
||||
* ntfs_log_parse_option - Act upon command line options
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, va_list args);
|
||||
|
||||
#ifndef __HAIKU__
|
||||
/* Set the logging handler from one of the functions, below. */
|
||||
#ifndef __HAIKU__
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler
|
||||
__attribute__((format(printf, 6, 0))));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Logging handlers */
|
||||
ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0)));
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "types.h"
|
||||
#include "debug.h"
|
||||
#include "attrib.h"
|
||||
|
||||
@@ -50,6 +50,12 @@ enum {
|
||||
/* 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"
|
||||
@@ -69,6 +70,7 @@
|
||||
#define getpwuid(a) NULL
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* JPA NTFS constants or structs
|
||||
* should be moved to layout.h
|
||||
@@ -1133,10 +1135,93 @@ 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);
|
||||
}
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#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 :
|
||||
@@ -1155,12 +1240,6 @@ static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid
|
||||
* contains the same data.
|
||||
*/
|
||||
|
||||
#ifdef __HAIKU__
|
||||
static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
{
|
||||
static char key[] = "\nGroups:";
|
||||
@@ -1244,7 +1323,8 @@ static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
}
|
||||
return (ismember);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(__sun) && defined (__SVR4) */
|
||||
|
||||
/*
|
||||
* Cacheing is done two-way :
|
||||
@@ -1809,7 +1889,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;
|
||||
@@ -2225,7 +2305,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
|
||||
@@ -3328,6 +3408,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 */
|
||||
|
||||
/*
|
||||
@@ -3479,10 +3609,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);
|
||||
@@ -3691,7 +3823,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
|
||||
@@ -3702,7 +3836,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;
|
||||
@@ -3717,7 +3853,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;
|
||||
@@ -3735,7 +3873,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);
|
||||
|
||||
|
||||
@@ -719,9 +719,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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -1693,7 +1784,7 @@ void ntfs_mount_error(const char *volume, const char *mntpoint, int err)
|
||||
|
||||
int ntfs_set_locale(void)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
#ifndef __HAIKU__
|
||||
const char *locale;
|
||||
|
||||
locale = setlocale(LC_ALL, "");
|
||||
@@ -1703,7 +1794,7 @@ int ntfs_set_locale(void)
|
||||
"'%s'.\n", locale);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1744,7 +1835,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;
|
||||
@@ -1779,7 +1870,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);
|
||||
|
||||
@@ -275,11 +275,11 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags)
|
||||
*
|
||||
* libntfs-3g only has safety check number 2. The dirty flag is simply
|
||||
* ignored because we are confident that we can handle a dirty volume.
|
||||
* So we treat MS_RECOVER like NTFS_MNT_FORCE, knowing that the first
|
||||
* check is always bypassed.
|
||||
* So we treat NTFS_MNT_RECOVER like NTFS_MNT_FORCE, knowing that the
|
||||
* first check is always bypassed.
|
||||
*/
|
||||
|
||||
if (!utils_valid_device(device, flags & MS_RECOVER))
|
||||
if (!utils_valid_device(device, flags & NTFS_MNT_RECOVER))
|
||||
return NULL;
|
||||
|
||||
vol = ntfs_mount(device, flags);
|
||||
@@ -305,7 +305,7 @@ ntfs_volume * utils_mount_volume(const char *device, unsigned long flags)
|
||||
* before mount, so we can only warn if the VOLUME_IS_DIRTY flag is set
|
||||
* in VOLUME_INFORMATION. */
|
||||
if (vol->flags & VOLUME_IS_DIRTY) {
|
||||
if (!(flags & MS_RECOVER)) {
|
||||
if (!(flags & NTFS_MNT_RECOVER)) {
|
||||
ntfs_log_error("%s", dirty_volume_msg);
|
||||
ntfs_umount(vol, FALSE);
|
||||
return NULL;
|
||||
@@ -1122,69 +1122,4 @@ int mft_next_record(struct mft_search_ctx *ctx)
|
||||
return (ctx->inode == NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_get_parent_ref - find mft reference of parent directory of an inode
|
||||
* @ni: ntfs inode whose parent directory to find
|
||||
*
|
||||
* Find the parent directory of the ntfs inode @ni. To do this, find the first
|
||||
* file name attribute in the mft record of @ni and return the parent mft
|
||||
* reference from that.
|
||||
*
|
||||
* Note this only makes sense for directories, since files can be hard linked
|
||||
* from multiple directories and there is no way for us to tell which one is
|
||||
* being looked for.
|
||||
*
|
||||
* Technically directories can have hard links, too, but we consider that as
|
||||
* illegal as Linux/UNIX do not support directory hard links.
|
||||
*
|
||||
* Return the mft reference of the parent directory on success or -1 on error
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
|
||||
{
|
||||
MFT_REF mref;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
FILE_NAME_ATTR *fn;
|
||||
int eo;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
if (!ni) {
|
||||
errno = EINVAL;
|
||||
return ERR_MREF(-1);
|
||||
}
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx)
|
||||
return ERR_MREF(-1);
|
||||
if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("No file name found in inode %lld\n",
|
||||
(unsigned long long)ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
if (ctx->attr->non_resident) {
|
||||
ntfs_log_error("File name attribute must be resident (inode "
|
||||
"%lld)\n", (unsigned long long)ni->mft_no);
|
||||
goto io_err_out;
|
||||
}
|
||||
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
if ((u8*)fn + le32_to_cpu(ctx->attr->value_length) >
|
||||
(u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) {
|
||||
ntfs_log_error("Corrupt file name attribute in inode %lld.\n",
|
||||
(unsigned long long)ni->mft_no);
|
||||
goto io_err_out;
|
||||
}
|
||||
mref = le64_to_cpu(fn->parent_directory);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return mref;
|
||||
io_err_out:
|
||||
errno = EIO;
|
||||
err_out:
|
||||
eo = errno;
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
errno = eo;
|
||||
return ERR_MREF(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ struct mft_search_ctx {
|
||||
struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol);
|
||||
void mft_put_search_ctx(struct mft_search_ctx *ctx);
|
||||
int mft_next_record(struct mft_search_ctx *ctx);
|
||||
MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni);
|
||||
|
||||
// Flags for dump mem
|
||||
#define DM_DEFAULTS 0
|
||||
|
||||
Reference in New Issue
Block a user