NTFS: Update libntfs from 2014.2.15 to 2017.3.23.
I rewrote the "config.h" at the same time, which enables usage of gettimeofday and some other API functions we didn't have whenever this port was first done, enabling more accurate timestamp handling, among other things.
This commit is contained in:
@@ -27,12 +27,7 @@ KernelAddon ntfs :
|
||||
libntfs.a
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
kernel_cpp.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
||||
|
||||
SEARCH on [ FGristFiles mime_ext_table.c ]
|
||||
+= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel file_systems ntfs libntfs ;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ KernelStaticLibrary libntfs.a :
|
||||
debug.c
|
||||
device.c
|
||||
dir.c
|
||||
ea.c
|
||||
efs.c
|
||||
index.c
|
||||
inode.c
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This module is part of ntfs-3g library, but may also be
|
||||
* integrated in tools running over Linux or Windows
|
||||
*
|
||||
* Copyright (c) 2007-2012 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2016 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
|
||||
@@ -22,10 +22,6 @@
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
/*
|
||||
* integration into ntfs-3g
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
@@ -53,65 +49,18 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define getgrgid(a) NULL
|
||||
#define getpwuid(a) NULL
|
||||
#define getgrnam(x) NULL
|
||||
#define getpwnam(x) NULL
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "security.h"
|
||||
#include "acls.h"
|
||||
#include "misc.h"
|
||||
#else
|
||||
|
||||
/*
|
||||
* integration into secaudit, check whether Win32,
|
||||
* may have to be adapted to compiler or something else
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC)
|
||||
#define WIN32 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* integration into secaudit/Win32
|
||||
*/
|
||||
#ifdef WIN32
|
||||
#include <fcntl.h>
|
||||
#include <windows.h>
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#else
|
||||
/*
|
||||
* integration into secaudit/STSC
|
||||
*/
|
||||
#ifdef STSC
|
||||
#include <stat.h>
|
||||
#undef __BYTE_ORDER
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
#else
|
||||
/*
|
||||
* integration into secaudit/Linux
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <endian.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#endif /* STSC */
|
||||
#endif /* WIN32 */
|
||||
#include "secaudit.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define getgrnam(x) NULL
|
||||
#define getpwnam(x) NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A few useful constants
|
||||
@@ -141,6 +90,8 @@ static const char worldsidbytes[] = {
|
||||
0, 0, 0, 0 /* 1st level */
|
||||
} ;
|
||||
|
||||
const SID *worldsid = (const SID*)worldsidbytes;
|
||||
|
||||
/*
|
||||
* SID for authenticated user (S-1-5-11)
|
||||
*/
|
||||
@@ -149,12 +100,10 @@ static const char authsidbytes[] = {
|
||||
1, /* revision */
|
||||
1, /* auth count */
|
||||
0, 0, 0, 0, 0, 5, /* base */
|
||||
11, 0, 0, 0 /* 1st level */
|
||||
11, 0, 0, 0 /* 1st level */
|
||||
};
|
||||
|
||||
static const SID *authsid = (const SID*)authsidbytes;
|
||||
|
||||
const SID *worldsid = (const SID*)worldsidbytes;
|
||||
static const SID *authsid = (const SID*)authsidbytes;
|
||||
|
||||
/*
|
||||
* SID for administrator
|
||||
@@ -235,7 +184,11 @@ BOOL ntfs_same_sid(const SID *first, const SID *second)
|
||||
|
||||
/*
|
||||
* Test whether a SID means "world user"
|
||||
* Local users group also recognized as world
|
||||
* Local users group recognized as world
|
||||
* Also interactive users so that /Users/Public is world accessible,
|
||||
* but only if Posix ACLs are not enabled (if Posix ACLs are enabled,
|
||||
* access to /Users/Public should be done by defining interactive users
|
||||
* as a mapped group.)
|
||||
*/
|
||||
|
||||
static int is_world_sid(const SID * usid)
|
||||
@@ -259,6 +212,14 @@ static int is_world_sid(const SID * usid)
|
||||
&& (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)))
|
||||
|
||||
#if !POSIXACLS
|
||||
/* check whether S-1-5-4 : interactive 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(4)))
|
||||
#endif /* !POSIXACLS */
|
||||
);
|
||||
}
|
||||
|
||||
@@ -276,6 +237,25 @@ BOOL ntfs_is_user_sid(const SID *usid)
|
||||
&& (usid->sub_authority[0] == const_cpu_to_le32(21)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether a SID means "some special group"
|
||||
* Currently we only check for a few S-1-5-n but we should
|
||||
* probably test for other configurations.
|
||||
*
|
||||
* This is useful for granting access to /Users/Public for
|
||||
* specific users when the Posix ACLs are enabled.
|
||||
*/
|
||||
|
||||
static BOOL ntfs_known_group_sid(const SID *usid)
|
||||
{
|
||||
/* count == 1 excludes S-1-5-5-X-Y (logon) */
|
||||
return ((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))
|
||||
&& (le32_to_cpu(usid->sub_authority[0]) >= 1)
|
||||
&& (le32_to_cpu(usid->sub_authority[0]) <= 6));
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the size of a security attribute
|
||||
* whatever the order of fields
|
||||
@@ -336,16 +316,18 @@ unsigned int ntfs_attr_size(const char *attr)
|
||||
return (attrsz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do sanity checks on a SID read from storage
|
||||
* (just check revision and number of authorities)
|
||||
/**
|
||||
* ntfs_valid_sid - determine if a SID is valid
|
||||
* @sid: SID for which to determine if it is valid
|
||||
*
|
||||
* Determine if the SID pointed to by @sid is valid.
|
||||
*
|
||||
* Return TRUE if it is valid and FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL ntfs_valid_sid(const SID *sid)
|
||||
{
|
||||
return ((sid->revision == SID_REVISION)
|
||||
&& (sid->sub_authority_count >= 1)
|
||||
&& (sid->sub_authority_count <= 8));
|
||||
return sid && sid->revision == SID_REVISION &&
|
||||
sid->sub_authority_count <= SID_MAX_SUB_AUTHORITIES;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -571,6 +553,7 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end)
|
||||
unsigned int acecnt;
|
||||
unsigned int acesz;
|
||||
unsigned int nace;
|
||||
unsigned int wantsz;
|
||||
BOOL ok;
|
||||
|
||||
ok = TRUE;
|
||||
@@ -585,9 +568,16 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end)
|
||||
&((const char*)pacl)[offace];
|
||||
acesz = le16_to_cpu(pace->size);
|
||||
if (((offace + acesz) > end)
|
||||
|| !ntfs_valid_sid(&pace->sid)
|
||||
|| ((ntfs_sid_size(&pace->sid) + 8) != (int)acesz))
|
||||
|| !ntfs_valid_sid(&pace->sid))
|
||||
ok = FALSE;
|
||||
else {
|
||||
/* Win10 may insert garbage in the last ACE */
|
||||
wantsz = ntfs_sid_size(&pace->sid) + 8;
|
||||
if (((nace < (acecnt - 1))
|
||||
&& (wantsz != acesz))
|
||||
|| (wantsz > acesz))
|
||||
ok = FALSE;
|
||||
}
|
||||
offace += acesz;
|
||||
}
|
||||
}
|
||||
@@ -703,8 +693,10 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
const ACCESS_ALLOWED_ACE *poldace;
|
||||
ACCESS_ALLOWED_ACE *pnewace;
|
||||
ACCESS_ALLOWED_ACE *pauthace;
|
||||
ACCESS_ALLOWED_ACE *pownerace;
|
||||
|
||||
pauthace = (ACCESS_ALLOWED_ACE*)NULL;
|
||||
pownerace = (ACCESS_ALLOWED_ACE*)NULL;
|
||||
usidsz = ntfs_sid_size(usid);
|
||||
gsidsz = ntfs_sid_size(gsid);
|
||||
|
||||
@@ -722,12 +714,24 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src);
|
||||
acesz = le16_to_cpu(poldace->size);
|
||||
src += acesz;
|
||||
/*
|
||||
* Inheritance for access, unless this is inheriting
|
||||
* an inherited ACL to a directory.
|
||||
*/
|
||||
/*
|
||||
* Extract inheritance for access, including inheritance for
|
||||
* access from an ACE with is both applied and inheritable.
|
||||
*
|
||||
* must not output OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
|
||||
*
|
||||
* According to MSDN :
|
||||
* "For a case in which a container object inherits an ACE
|
||||
* "that is both effective on the container and inheritable
|
||||
* "by its descendants, the container may inherit two ACEs.
|
||||
* "This occurs if the inheritable ACE contains generic
|
||||
* "information."
|
||||
*/
|
||||
if ((poldace->flags & selection)
|
||||
&& !(fordir && inherited)
|
||||
&& (!fordir
|
||||
|| (poldace->flags & NO_PROPAGATE_INHERIT_ACE)
|
||||
|| (poldace->mask & (GENERIC_ALL | GENERIC_READ
|
||||
| GENERIC_WRITE | GENERIC_EXECUTE)))
|
||||
&& !ntfs_same_sid(&poldace->sid, ownersid)
|
||||
&& !ntfs_same_sid(&poldace->sid, groupsid)) {
|
||||
pnewace = (ACCESS_ALLOWED_ACE*)
|
||||
@@ -750,7 +754,7 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
| FILE_READ
|
||||
| FILE_WRITE
|
||||
| FILE_EXEC
|
||||
| cpu_to_le32(0x40);
|
||||
| const_cpu_to_le32(0x40);
|
||||
}
|
||||
/* reencode GENERIC_READ (+ EXECUTE) */
|
||||
if (pnewace->mask & GENERIC_READ) {
|
||||
@@ -790,8 +794,7 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
* Group similar ACE for authenticated users
|
||||
* (should probably be done for other SIDs)
|
||||
*/
|
||||
if (!fordir
|
||||
&& (poldace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& ntfs_same_sid(&poldace->sid, authsid)) {
|
||||
if (pauthace) {
|
||||
pauthace->flags |= pnewace->flags;
|
||||
@@ -834,8 +837,14 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
| INHERIT_ONLY_ACE);
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
dst += usidsz + 8;
|
||||
newcnt++;
|
||||
if ((pnewace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& pownerace
|
||||
&& !(pnewace->flags & ~pownerace->flags)) {
|
||||
pownerace->mask |= pnewace->mask;
|
||||
} else {
|
||||
dst += usidsz + 8;
|
||||
newcnt++;
|
||||
}
|
||||
}
|
||||
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
|
||||
memcpy(&pnewace->sid, gsid, gsidsz);
|
||||
@@ -851,15 +860,52 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
|
||||
}
|
||||
}
|
||||
|
||||
/* inheritance for further inheritance */
|
||||
/*
|
||||
* inheritance for further inheritance
|
||||
*
|
||||
* Situations leading to output CONTAINER_INHERIT_ACE
|
||||
* or OBJECT_INHERIT_ACE
|
||||
*/
|
||||
if (fordir
|
||||
&& (poldace->flags
|
||||
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) {
|
||||
pnewace = (ACCESS_ALLOWED_ACE*)
|
||||
((char*)newacl + dst);
|
||||
memcpy(pnewace,poldace,acesz);
|
||||
if ((poldace->flags & OBJECT_INHERIT_ACE)
|
||||
&& !(poldace->flags & (CONTAINER_INHERIT_ACE
|
||||
| NO_PROPAGATE_INHERIT_ACE)))
|
||||
pnewace->flags |= INHERIT_ONLY_ACE;
|
||||
if ((poldace->flags & CONTAINER_INHERIT_ACE)
|
||||
&& !(poldace->flags & NO_PROPAGATE_INHERIT_ACE)
|
||||
&& !ntfs_same_sid(&poldace->sid, ownersid)
|
||||
&& !ntfs_same_sid(&poldace->sid, groupsid)) {
|
||||
if ((poldace->mask & (GENERIC_ALL | GENERIC_READ
|
||||
| GENERIC_WRITE | GENERIC_EXECUTE)))
|
||||
pnewace->flags |= INHERIT_ONLY_ACE;
|
||||
else
|
||||
pnewace->flags &= ~INHERIT_ONLY_ACE;
|
||||
}
|
||||
if (inherited)
|
||||
pnewace->flags |= INHERITED_ACE;
|
||||
/*
|
||||
* Prepare grouping similar ACE for authenticated users
|
||||
*/
|
||||
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& !pauthace
|
||||
&& !(pnewace->flags & INHERIT_ONLY_ACE)
|
||||
&& ntfs_same_sid(&poldace->sid, authsid)) {
|
||||
pauthace = pnewace;
|
||||
}
|
||||
/*
|
||||
* Prepare grouping similar ACE for owner
|
||||
*/
|
||||
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& !pownerace
|
||||
&& !(pnewace->flags & INHERIT_ONLY_ACE)
|
||||
&& ntfs_same_sid(&poldace->sid, usid)) {
|
||||
pownerace = pnewace;
|
||||
}
|
||||
dst += acesz;
|
||||
newcnt++;
|
||||
}
|
||||
@@ -980,7 +1026,7 @@ BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc)
|
||||
}
|
||||
}
|
||||
if ((pxdesc->acccnt > 0)
|
||||
&& ((checks[0].owners != 1) || (checks[0].groups != 1)
|
||||
&& ((checks[0].owners != 1) || (checks[0].groups != 1)
|
||||
|| (checks[0].others != 1)))
|
||||
ok = FALSE;
|
||||
/* do not check owner, group or other are present in */
|
||||
@@ -1221,6 +1267,45 @@ struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
||||
return (newpxdesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a basic Posix ACL from a mode and umask,
|
||||
* ignoring inheritance from the parent directory
|
||||
*/
|
||||
|
||||
struct POSIX_SECURITY *ntfs_build_basic_posix(
|
||||
const struct POSIX_SECURITY *pxdesc __attribute__((unused)),
|
||||
mode_t mode, mode_t mask, BOOL isdir __attribute__((unused)))
|
||||
{
|
||||
struct POSIX_SECURITY *pydesc;
|
||||
struct POSIX_ACE *pyace;
|
||||
|
||||
pydesc = (struct POSIX_SECURITY*)malloc(
|
||||
sizeof(struct POSIX_SECURITY) + 3*sizeof(struct POSIX_ACE));
|
||||
if (pydesc) {
|
||||
pyace = &pydesc->acl.ace[0];
|
||||
pyace->tag = POSIX_ACL_USER_OBJ;
|
||||
pyace->perms = ((mode & ~mask) >> 6) & 7;
|
||||
pyace->id = -1;
|
||||
pyace = &pydesc->acl.ace[1];
|
||||
pyace->tag = POSIX_ACL_GROUP_OBJ;
|
||||
pyace->perms = ((mode & ~mask) >> 3) & 7;
|
||||
pyace->id = -1;
|
||||
pyace = &pydesc->acl.ace[2];
|
||||
pyace->tag = POSIX_ACL_OTHER;
|
||||
pyace->perms = (mode & ~mask) & 7;
|
||||
pyace->id = -1;
|
||||
pydesc->mode = mode;
|
||||
pydesc->tagsset = POSIX_ACL_USER_OBJ
|
||||
| POSIX_ACL_GROUP_OBJ
|
||||
| POSIX_ACL_OTHER;
|
||||
pydesc->acccnt = 3;
|
||||
pydesc->defcnt = 0;
|
||||
pydesc->firstdef = 6;
|
||||
} else
|
||||
errno = ENOMEM;
|
||||
return (pydesc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build an inherited Posix descriptor from parent
|
||||
* descriptor (if any) restricted to creation mode
|
||||
@@ -1515,7 +1600,7 @@ static BOOL build_user_denials(ACL *pacl,
|
||||
grants = OWNER_RIGHTS;
|
||||
} else {
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
grants = WORLD_RIGHTS;
|
||||
} else {
|
||||
@@ -1671,7 +1756,7 @@ static BOOL build_user_grants(ACL *pacl,
|
||||
grants = OWNER_RIGHTS;
|
||||
} else {
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid)
|
||||
sidsz = ntfs_sid_size(sid);
|
||||
@@ -1757,7 +1842,7 @@ static BOOL build_group_denials_grant(ACL *pacl,
|
||||
sid = gsid;
|
||||
else
|
||||
if (pxace->id)
|
||||
sid = NTFS_FIND_GSID(mapping[MAPGROUPS],
|
||||
sid = ntfs_find_gsid(mapping[MAPGROUPS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
else {
|
||||
sid = adminsid;
|
||||
@@ -1906,7 +1991,7 @@ static BOOL build_group_denials_grant(ACL *pacl,
|
||||
* - grants to owner (always present - first grant)
|
||||
* + grants to designated user
|
||||
* + mask denial to group (unless mask allows all)
|
||||
* - denials to group (preventing grants to world to apply)
|
||||
* - denials to group (preventing grants to world to apply)
|
||||
* - grants to group (unless group has no more than world rights)
|
||||
* + mask denials to designated group (unless mask allows all)
|
||||
* + grants to designated group
|
||||
@@ -2062,7 +2147,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
|
||||
case POSIX_ACL_USER :
|
||||
pset->designates++;
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid && ntfs_same_sid(sid,usid))
|
||||
pset->selfuserperms |= pxace->perms;
|
||||
@@ -2073,7 +2158,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
|
||||
case POSIX_ACL_GROUP :
|
||||
pset->designates++;
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_GSID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_gsid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid && ntfs_same_sid(sid,gsid))
|
||||
pset->selfgrpperms |= pxace->perms;
|
||||
@@ -2193,10 +2278,21 @@ return (0);
|
||||
mapping,flags,pxace,pset);
|
||||
break;
|
||||
|
||||
case POSIX_ACL_GROUP :
|
||||
case POSIX_ACL_GROUP_OBJ :
|
||||
/* denials and grants for group when needed */
|
||||
if (pset->groupowns && !pset->adminowns
|
||||
&& (pset->grpperms == pset->othperms)
|
||||
&& !pset->designates && !pset->withmask) {
|
||||
ok = TRUE;
|
||||
} else {
|
||||
ok = build_group_denials_grant(pacl,gsid,
|
||||
mapping,flags,pxace,pset);
|
||||
}
|
||||
break;
|
||||
|
||||
/* denials and grants for groups */
|
||||
case POSIX_ACL_GROUP :
|
||||
|
||||
/* denials and grants for designated groups */
|
||||
|
||||
ok = build_group_denials_grant(pacl,gsid,
|
||||
mapping,flags,pxace,pset);
|
||||
@@ -2453,7 +2549,6 @@ static int buildacls(char *secattr, int offs, mode_t mode, int isdir,
|
||||
/* this ACE will be inserted after denials for group */
|
||||
|
||||
if (adminowns
|
||||
|| groupowns
|
||||
|| (((mode >> 3) ^ mode) & 7)) {
|
||||
grants = WORLD_RIGHTS;
|
||||
if (isdir) {
|
||||
@@ -2657,10 +2752,10 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
for (k=0; k<pxdesc->acccnt; k++) {
|
||||
if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER)
|
||||
|| (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP))
|
||||
newattrsz += 3*40; /* fixme : maximum size */
|
||||
newattrsz += 3*MAX_SID_SIZE;
|
||||
}
|
||||
/* account for default ACE's */
|
||||
newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */
|
||||
newattrsz += 2*MAX_SID_SIZE*pxdesc->defcnt;
|
||||
newattr = (char*)ntfs_malloc(newattrsz);
|
||||
if (newattr) {
|
||||
/* build the main header part */
|
||||
@@ -3514,7 +3609,7 @@ static uid_t find_tenant(struct MAPPING *const mapping[],
|
||||
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
|
||||
if ((pace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& (pace->mask & DIR_WRITE)) {
|
||||
xid = NTFS_FIND_USER(mapping[MAPUSERS], &pace->sid);
|
||||
xid = ntfs_find_user(mapping[MAPUSERS], &pace->sid);
|
||||
if (xid) tid = xid;
|
||||
}
|
||||
offace += le16_to_cpu(pace->size);
|
||||
@@ -3649,13 +3744,13 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
} else {
|
||||
if (ntfs_same_sid(&pace->sid,usid))
|
||||
groupowns = TRUE;
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
pxace->tag = POSIX_ACL_GROUP;
|
||||
pxace->id = gid;
|
||||
pctx->prevgid = gid;
|
||||
} else {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
if (uid) {
|
||||
pxace->tag = POSIX_ACL_USER;
|
||||
pxace->id = uid;
|
||||
@@ -3678,7 +3773,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
if (pace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
pctx->gotowner = TRUE;
|
||||
if (pctx->gotownermask && !pctx->gotowner) {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
pxace->id = uid;
|
||||
pxace->tag = POSIX_ACL_USER;
|
||||
} else
|
||||
@@ -3710,7 +3805,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
pctx->groupmasks++;
|
||||
} else {
|
||||
if (pctx->gotgroup || (pctx->groupmasks > 1)) {
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
pxace->id = gid;
|
||||
pxace->tag = POSIX_ACL_GROUP;
|
||||
@@ -3744,7 +3839,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
pxace->id = -1;
|
||||
pxace->tag = POSIX_ACL_SPECIAL;
|
||||
} else {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
if (uid) {
|
||||
if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
||||
&& (pace->mask & WRITE_OWNER)
|
||||
@@ -3757,7 +3852,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
}
|
||||
pctx->prevuid = uid;
|
||||
} else {
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
||||
&& (pace->mask & WRITE_OWNER)
|
||||
@@ -4005,7 +4100,7 @@ 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 ! */
|
||||
unsigned long v;
|
||||
@@ -4015,7 +4110,6 @@ static unsigned long atoul(const char *p)
|
||||
v = v * 10 + (*p++) - '0';
|
||||
return (v);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Build an internal representation of a SID
|
||||
@@ -4050,7 +4144,8 @@ static SID *encodesid(const char *sidstr)
|
||||
cnt++;
|
||||
}
|
||||
bsid->sub_authority_count = cnt;
|
||||
if ((cnt > 0) && ntfs_valid_sid(bsid) && ntfs_is_user_sid(bsid)) {
|
||||
if ((cnt > 0) && ntfs_valid_sid(bsid)
|
||||
&& (ntfs_is_user_sid(bsid) || ntfs_known_group_sid(bsid))) {
|
||||
sid = (SID*) ntfs_malloc(4 * cnt + 8);
|
||||
if (sid)
|
||||
memcpy(sid, bsid, 4 * cnt + 8);
|
||||
@@ -4259,6 +4354,12 @@ struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem)
|
||||
if (uid
|
||||
|| (!item->uidstr[0] && !item->gidstr[0])) {
|
||||
sid = encodesid(item->sidstr);
|
||||
if (sid && ntfs_known_group_sid(sid)) {
|
||||
ntfs_log_error("Bad user SID %s\n",
|
||||
item->sidstr);
|
||||
free(sid);
|
||||
sid = (SID*)NULL;
|
||||
}
|
||||
if (sid && !item->uidstr[0] && !item->gidstr[0]
|
||||
&& !ntfs_valid_pattern(sid)) {
|
||||
ntfs_log_error("Bad implicit SID pattern %s\n",
|
||||
@@ -4351,7 +4452,15 @@ struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem)
|
||||
if (mapping) {
|
||||
mapping->sid = sid;
|
||||
mapping->xid = gid;
|
||||
mapping->grcnt = 0;
|
||||
/* special groups point to themselves */
|
||||
if (ntfs_known_group_sid(sid)) {
|
||||
mapping->groups =
|
||||
(gid_t*)&mapping->xid;
|
||||
mapping->grcnt = 1;
|
||||
} else
|
||||
mapping->grcnt = 0;
|
||||
|
||||
|
||||
mapping->next = (struct MAPPING*)NULL;
|
||||
if (lastmapping)
|
||||
lastmapping->next = mapping;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef ACLS_H
|
||||
#define ACLS_H
|
||||
|
||||
#include "endians.h"
|
||||
|
||||
/*
|
||||
* JPA configuration modes for security.c / acls.c
|
||||
* should be moved to some config file
|
||||
@@ -35,28 +37,6 @@
|
||||
#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */
|
||||
#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */
|
||||
|
||||
/*
|
||||
* JPA The following must be in some library...
|
||||
* but did not found out where
|
||||
*/
|
||||
|
||||
#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8))
|
||||
#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \
|
||||
| ((x & 0xff00) << 8) | ((x & 255) << 24))
|
||||
|
||||
#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x))
|
||||
#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x))
|
||||
|
||||
/*
|
||||
* Macro definitions needed to share code with secaudit
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf)
|
||||
#define NTFS_FIND_GSID(map,gid,buf) ntfs_find_gsid(map,gid,buf)
|
||||
#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid)
|
||||
#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
||||
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
@@ -112,10 +92,11 @@
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
|
||||
/*
|
||||
* A type large enough to hold any SID
|
||||
* Maximum SID size and a type large enough to hold it
|
||||
*/
|
||||
|
||||
typedef char BIGSID[40];
|
||||
#define MAX_SID_SIZE (8 + SID_MAX_SUB_AUTHORITIES*4)
|
||||
typedef char BIGSID[MAX_SID_SIZE];
|
||||
|
||||
/*
|
||||
* Struct to hold the input mapping file
|
||||
@@ -170,6 +151,9 @@ int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
|
||||
struct POSIX_SECURITY *ntfs_build_inherited_posix(
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_build_basic_posix(
|
||||
const struct POSIX_SECURITY *pxdesc, mode_t mode,
|
||||
mode_t umask, BOOL isdir);
|
||||
struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
||||
const struct POSIX_ACL *newacl, int count, BOOL deflt);
|
||||
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2007-2013 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -96,7 +96,7 @@ static void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
|
||||
na->ni->flags |= flag;
|
||||
else
|
||||
ntfs_log_trace("Denied setting flag %d for not unnamed data "
|
||||
"attribute\n", flag);
|
||||
"attribute\n", le32_to_cpu(flag));
|
||||
}
|
||||
|
||||
static void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
|
||||
@@ -405,7 +405,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
le16 cs;
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n",
|
||||
(unsigned long long)ni->mft_no, type);
|
||||
(unsigned long long)ni->mft_no, le32_to_cpu(type));
|
||||
|
||||
if (!ni || !ni->vol || !ni->mrec) {
|
||||
errno = EINVAL;
|
||||
@@ -452,7 +452,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
* does not detect or fix them so we need to cope with it, too.
|
||||
*/
|
||||
if (type == AT_ATTRIBUTE_LIST)
|
||||
a->flags = 0;
|
||||
a->flags = const_cpu_to_le16(0);
|
||||
|
||||
if ((type == AT_DATA)
|
||||
&& (a->non_resident ? !a->initialized_size : !a->value_length)) {
|
||||
@@ -484,7 +484,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Inode %lld has corrupt attribute flags "
|
||||
"(0x%x <> 0x%x)",(unsigned long long)ni->mft_no,
|
||||
a->flags, na->ni->flags);
|
||||
le16_to_cpu(a->flags), le32_to_cpu(na->ni->flags));
|
||||
goto put_err_out;
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Compressed inode %lld attr 0x%x has "
|
||||
"no compression unit",
|
||||
(unsigned long long)ni->mft_no, type);
|
||||
(unsigned long long)ni->mft_no, le32_to_cpu(type));
|
||||
goto put_err_out;
|
||||
}
|
||||
ntfs_attr_init(na, TRUE, a->flags,
|
||||
@@ -561,7 +561,7 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type, (long long)vcn);
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), (long long)vcn);
|
||||
|
||||
lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
|
||||
if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
|
||||
@@ -601,22 +601,19 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
|
||||
|
||||
static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
|
||||
{
|
||||
LCN lcn;
|
||||
VCN last_vcn;
|
||||
VCN highest_vcn;
|
||||
VCN needed;
|
||||
VCN existing_vcn;
|
||||
runlist_element *rl;
|
||||
ATTR_RECORD *a;
|
||||
BOOL startseen;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
BOOL done;
|
||||
BOOL newrunlist;
|
||||
|
||||
lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
|
||||
if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
|
||||
if (NAttrFullyMapped(na))
|
||||
return 0;
|
||||
|
||||
existing_vcn = (na->rl ? na->rl->vcn : -1);
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx)
|
||||
return -1;
|
||||
@@ -627,37 +624,56 @@ static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
|
||||
needed = vcn;
|
||||
highest_vcn = 0;
|
||||
startseen = FALSE;
|
||||
done = FALSE;
|
||||
rl = (runlist_element*)NULL;
|
||||
do {
|
||||
newrunlist = FALSE;
|
||||
/* Find the attribute in the mft record. */
|
||||
if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
|
||||
needed, NULL, 0, ctx)) {
|
||||
|
||||
a = ctx->attr;
|
||||
/* Decode and merge the runlist. */
|
||||
rl = ntfs_mapping_pairs_decompress(na->ni->vol, a,
|
||||
na->rl);
|
||||
/* Decode and merge the runlist. */
|
||||
if (ntfs_rl_vcn_to_lcn(na->rl, needed)
|
||||
== LCN_RL_NOT_MAPPED) {
|
||||
rl = ntfs_mapping_pairs_decompress(na->ni->vol,
|
||||
a, na->rl);
|
||||
newrunlist = TRUE;
|
||||
} else
|
||||
rl = na->rl;
|
||||
if (rl) {
|
||||
na->rl = rl;
|
||||
highest_vcn = le64_to_cpu(a->highest_vcn);
|
||||
/* corruption detection */
|
||||
if (((highest_vcn + 1) < last_vcn)
|
||||
&& ((highest_vcn + 1) <= needed)) {
|
||||
ntfs_log_error("Corrupt attribute list\n");
|
||||
rl = (runlist_element*)NULL;
|
||||
highest_vcn = sle64_to_cpu(a->highest_vcn);
|
||||
if (highest_vcn < needed) {
|
||||
/* corruption detection on unchanged runlists */
|
||||
if (newrunlist
|
||||
&& ((highest_vcn + 1) < last_vcn)) {
|
||||
ntfs_log_error("Corrupt attribute list\n");
|
||||
rl = (runlist_element*)NULL;
|
||||
errno = EIO;
|
||||
}
|
||||
done = TRUE;
|
||||
}
|
||||
needed = highest_vcn + 1;
|
||||
if (!a->lowest_vcn)
|
||||
startseen = TRUE;
|
||||
/* reaching a previously allocated part ? */
|
||||
if ((existing_vcn >= 0)
|
||||
&& (needed >= existing_vcn)) {
|
||||
needed = last_vcn;
|
||||
}
|
||||
}
|
||||
} else
|
||||
rl = (runlist_element*)NULL;
|
||||
} while (rl && (needed < last_vcn));
|
||||
} else {
|
||||
done = TRUE;
|
||||
}
|
||||
} while (rl && !done && (needed < last_vcn));
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
/*
|
||||
* Make sure we reached the end, unless the last
|
||||
* runlist was modified earlier (using HOLES_DELAY
|
||||
* leads to have a visibility over attributes which
|
||||
* have not yet been fully updated)
|
||||
*/
|
||||
if (done && newrunlist && (needed < last_vcn)) {
|
||||
ntfs_log_error("End of runlist not reached\n");
|
||||
rl = (runlist_element*)NULL;
|
||||
errno = EIO;
|
||||
}
|
||||
/* mark fully mapped if we did so */
|
||||
if (rl && startseen)
|
||||
NAttrSetFullyMapped(na);
|
||||
@@ -685,9 +701,10 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
ntfs_volume *vol = na->ni->vol;
|
||||
ATTR_RECORD *a;
|
||||
int ret = -1;
|
||||
int not_mapped;
|
||||
|
||||
ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type);
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
/* avoid multiple full runlist mappings */
|
||||
if (NAttrFullyMapped(na)) {
|
||||
@@ -704,7 +721,7 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
while (1) {
|
||||
runlist_element *rl;
|
||||
|
||||
int not_mapped = 0;
|
||||
not_mapped = 0;
|
||||
if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED)
|
||||
not_mapped = 1;
|
||||
|
||||
@@ -759,7 +776,13 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
ntfs_log_perror("Couldn't find attribute for runlist mapping");
|
||||
goto err_out;
|
||||
}
|
||||
if (highest_vcn && highest_vcn != last_vcn - 1) {
|
||||
/*
|
||||
* Cannot check highest_vcn when the last runlist has
|
||||
* been modified earlier, as runlists and sizes may be
|
||||
* updated without highest_vcn being in sync, when
|
||||
* HOLES_DELAY is used
|
||||
*/
|
||||
if (not_mapped && highest_vcn && highest_vcn != last_vcn - 1) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Failed to load full runlist: inode: %llu "
|
||||
"highest_vcn: 0x%llx last_vcn: 0x%llx",
|
||||
@@ -808,7 +831,7 @@ LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn)
|
||||
return (LCN)LCN_EINVAL;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
|
||||
long)na->ni->mft_no, na->type);
|
||||
long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
retry:
|
||||
/* Convert vcn to lcn. If that fails map the runlist and retry once. */
|
||||
lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
|
||||
@@ -860,7 +883,7 @@ runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn)
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)vcn);
|
||||
retry:
|
||||
rl = na->rl;
|
||||
@@ -1017,7 +1040,7 @@ res_err_out:
|
||||
count--;
|
||||
total2++;
|
||||
} else {
|
||||
*(u16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length);
|
||||
*(le16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length);
|
||||
count -= 2;
|
||||
total2 +=2;
|
||||
}
|
||||
@@ -1153,7 +1176,7 @@ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count "
|
||||
"%lld\n", (unsigned long long)na->ni->mft_no,
|
||||
na->type, (long long)pos, (long long)count);
|
||||
le32_to_cpu(na->type), (long long)pos, (long long)count);
|
||||
|
||||
ret = ntfs_attr_pread_i(na, pos, count, b);
|
||||
|
||||
@@ -1244,19 +1267,15 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
|
||||
|
||||
/* Map the runlist to be able to update mapping pairs later. */
|
||||
#if PARTIAL_RUNLIST_UPDATING
|
||||
if ((!na->rl
|
||||
|| !NAttrDataAppending(na))) {
|
||||
if (!na->rl) {
|
||||
if (ntfs_attr_map_whole_runlist(na))
|
||||
goto err_out;
|
||||
} else {
|
||||
/* make sure the previous non-hole is mapped */
|
||||
rlc = *rl;
|
||||
rlc--;
|
||||
if (((*rl)->lcn == LCN_HOLE)
|
||||
&& cur_vcn
|
||||
&& (rlc->vcn < 0)) {
|
||||
if (ntfs_attr_map_partial_runlist(na, cur_vcn - 1))
|
||||
goto err_out;
|
||||
/* make sure the run ahead of hole is mapped */
|
||||
if ((*rl)->lcn == LCN_HOLE) {
|
||||
if (ntfs_attr_map_partial_runlist(na,
|
||||
(cur_vcn ? cur_vcn - 1 : cur_vcn)))
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -1343,6 +1362,7 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
|
||||
na->compressed_size += need << vol->cluster_size_bits;
|
||||
|
||||
*rl = ntfs_runlists_merge(na->rl, rlc);
|
||||
NAttrSetRunlistDirty(na);
|
||||
/*
|
||||
* For a compressed attribute, we must be sure there are two
|
||||
* available entries, so reserve them before it gets too late.
|
||||
@@ -1572,6 +1592,7 @@ ntfs_log_error("No free run, case 4\n");
|
||||
rl = ++(*prl);
|
||||
}
|
||||
}
|
||||
NAttrSetRunlistDirty(na);
|
||||
if ((*update_from == -1) || ((*prl)->vcn < *update_from))
|
||||
*update_from = (*prl)->vcn;
|
||||
}
|
||||
@@ -1708,6 +1729,7 @@ static int borrow_from_hole(ntfs_attr *na, runlist_element **prl,
|
||||
zrl->length = endblock - allocated;
|
||||
zrl[1].length -= zrl->length;
|
||||
zrl[1].vcn = zrl->vcn + zrl->length;
|
||||
NAttrSetRunlistDirty(na);
|
||||
}
|
||||
}
|
||||
if (*prl) {
|
||||
@@ -1758,7 +1780,8 @@ static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
|
||||
* appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
|
||||
* invalid arguments.
|
||||
*/
|
||||
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
static s64 ntfs_attr_pwrite_i(ntfs_attr *na, const s64 pos, s64 count,
|
||||
const void *b)
|
||||
{
|
||||
s64 written, to_write, ofs, old_initialized_size, old_data_size;
|
||||
s64 total = 0;
|
||||
@@ -1776,17 +1799,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
} need_to = { 0, 0 };
|
||||
BOOL wasnonresident = FALSE;
|
||||
BOOL compressed;
|
||||
BOOL updatemap;
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
|
||||
"0x%llx.\n", (long long)na->ni->mft_no, na->type,
|
||||
(long long)pos, (long long)count);
|
||||
|
||||
if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
goto errno_set;
|
||||
}
|
||||
vol = na->ni->vol;
|
||||
compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
!= const_cpu_to_le16(0);
|
||||
@@ -1931,8 +1944,17 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
* However, for compressed file, we need the full compression
|
||||
* block, which may be split in several extents.
|
||||
*/
|
||||
if (NAttrDataAppending(na)) {
|
||||
VCN block_begin = pos >> vol->cluster_size_bits;
|
||||
if (compressed && !NAttrDataAppending(na)) {
|
||||
if (ntfs_attr_map_whole_runlist(na))
|
||||
goto err_out;
|
||||
} else {
|
||||
VCN block_begin;
|
||||
|
||||
if (NAttrDataAppending(na)
|
||||
|| (pos < na->initialized_size))
|
||||
block_begin = pos >> vol->cluster_size_bits;
|
||||
else
|
||||
block_begin = na->initialized_size >> vol->cluster_size_bits;
|
||||
|
||||
if (compressed)
|
||||
block_begin &= -na->compression_block_clusters;
|
||||
@@ -1942,10 +1964,11 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
goto err_out;
|
||||
if ((update_from == -1) || (block_begin < update_from))
|
||||
update_from = block_begin;
|
||||
} else
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (ntfs_attr_map_whole_runlist(na))
|
||||
goto err_out;
|
||||
#endif
|
||||
/*
|
||||
* For a compressed attribute, we must be sure there is an
|
||||
* available entry, and, when reopening a compressed file,
|
||||
@@ -2192,7 +2215,7 @@ retry:
|
||||
} else
|
||||
written = ntfs_pwrite(vol->dev, wpos,
|
||||
to_write, b);
|
||||
}
|
||||
}
|
||||
} else
|
||||
written = to_write;
|
||||
/* If everything ok, update progress counters and continue. */
|
||||
@@ -2222,13 +2245,7 @@ done:
|
||||
* of the mapping list. This makes a difference only if
|
||||
* inode extents were needed.
|
||||
*/
|
||||
#if PARTIAL_RUNLIST_UPDATING
|
||||
updatemap = NAttrFullyMapped(na) || NAttrDataAppending(na);
|
||||
#else
|
||||
updatemap = (compressed
|
||||
? NAttrFullyMapped(na) != 0 : update_from != -1);
|
||||
#endif
|
||||
if (updatemap) {
|
||||
if (NAttrRunlistDirty(na)) {
|
||||
if (ntfs_attr_update_mapping_pairs(na,
|
||||
(update_from < 0 ? 0 : update_from))) {
|
||||
/*
|
||||
@@ -2243,7 +2260,6 @@ done:
|
||||
NAttrClearDataAppending(na);
|
||||
}
|
||||
out:
|
||||
ntfs_log_leave("\n");
|
||||
return total;
|
||||
rl_err_out:
|
||||
eo = errno;
|
||||
@@ -2298,9 +2314,7 @@ err_out:
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
/* Update mapping pairs if needed. */
|
||||
updatemap = (compressed
|
||||
? NAttrFullyMapped(na) != 0 : update_from != -1);
|
||||
if (updatemap)
|
||||
if (NAttrRunlistDirty(na))
|
||||
ntfs_attr_update_mapping_pairs(na, 0);
|
||||
/* Restore original data_size if needed. */
|
||||
if (need_to.undo_data_size
|
||||
@@ -2312,6 +2326,39 @@ errno_set:
|
||||
goto out;
|
||||
}
|
||||
|
||||
s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
||||
{
|
||||
s64 total;
|
||||
s64 written;
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
|
||||
"0x%llx.\n", (long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)pos, (long long)count);
|
||||
|
||||
total = 0;
|
||||
if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
written = -1;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compressed attributes may be written partially, so
|
||||
* we may have to iterate.
|
||||
*/
|
||||
do {
|
||||
written = ntfs_attr_pwrite_i(na, pos + total,
|
||||
count - total, (const u8*)b + total);
|
||||
if (written > 0)
|
||||
total += written;
|
||||
} while ((written > 0) && (total < count));
|
||||
out :
|
||||
ntfs_log_leave("\n");
|
||||
return (total > 0 ? total : written);
|
||||
}
|
||||
|
||||
|
||||
int ntfs_attr_pclose(ntfs_attr *na)
|
||||
{
|
||||
s64 ofs;
|
||||
@@ -2326,7 +2373,8 @@ int ntfs_attr_pclose(ntfs_attr *na)
|
||||
BOOL compressed;
|
||||
|
||||
ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
na->ni->mft_no, na->type);
|
||||
(unsigned long long)na->ni->mft_no,
|
||||
le32_to_cpu(na->type));
|
||||
|
||||
if (!na || !na->ni || !na->ni->vol) {
|
||||
errno = EINVAL;
|
||||
@@ -2545,7 +2593,7 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
|
||||
BOOL warn;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)pos);
|
||||
if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
|
||||
errno = EINVAL;
|
||||
@@ -2601,7 +2649,7 @@ s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt,
|
||||
s64 written, i;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)pos);
|
||||
if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
|
||||
errno = EINVAL;
|
||||
@@ -2719,7 +2767,7 @@ static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
|
||||
ntfschar *upcase;
|
||||
u32 upcase_len;
|
||||
|
||||
ntfs_log_trace("attribute type 0x%x.\n", type);
|
||||
ntfs_log_trace("attribute type 0x%x.\n", le32_to_cpu(type));
|
||||
|
||||
if (ctx->ntfs_ino) {
|
||||
vol = ctx->ntfs_ino->vol;
|
||||
@@ -2944,7 +2992,7 @@ static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name,
|
||||
ni = ctx->ntfs_ino;
|
||||
base_ni = ctx->base_ntfs_ino;
|
||||
ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n",
|
||||
(unsigned long long)ni->mft_no, type);
|
||||
(unsigned long long)ni->mft_no, le32_to_cpu(type));
|
||||
if (!base_ni) {
|
||||
/* First call happens with the base mft record. */
|
||||
base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
|
||||
@@ -3327,7 +3375,7 @@ int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
|
||||
ntfs_inode *base_ni;
|
||||
int ret = -1;
|
||||
|
||||
ntfs_log_enter("Entering for attribute type 0x%x\n", type);
|
||||
ntfs_log_enter("Entering for attribute type 0x%x\n", le32_to_cpu(type));
|
||||
|
||||
if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED &&
|
||||
(!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) ||
|
||||
@@ -3495,7 +3543,7 @@ ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
|
||||
if (!vol || !vol->attrdef || !type) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s: type=%d", __FUNCTION__, type);
|
||||
ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type));
|
||||
return NULL;
|
||||
}
|
||||
for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
|
||||
@@ -3510,7 +3558,7 @@ ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
break;
|
||||
}
|
||||
errno = ENOENT;
|
||||
ntfs_log_perror("%s: type=%d", __FUNCTION__, type);
|
||||
ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3571,7 +3619,7 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
|
||||
((max_size > 0) && (size > max_size))) {
|
||||
errno = ERANGE;
|
||||
ntfs_log_perror("Attr type %d size check failed (min,size,max="
|
||||
"%lld,%lld,%lld)", type, (long long)min_size,
|
||||
"%lld,%lld,%lld)", le32_to_cpu(type), (long long)min_size,
|
||||
(long long)size, (long long)max_size);
|
||||
return -1;
|
||||
}
|
||||
@@ -3751,7 +3799,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
ntfs_inode *base_ni;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n",
|
||||
(long long) ni->mft_no, (unsigned) type, (unsigned) data_flags);
|
||||
(long long) ni->mft_no, (unsigned) le32_to_cpu(type), (unsigned) le16_to_cpu(data_flags));
|
||||
|
||||
if (!ni || (!name && name_len)) {
|
||||
errno = EINVAL;
|
||||
@@ -3805,7 +3853,7 @@ int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
a->non_resident = 0;
|
||||
a->name_length = name_len;
|
||||
a->name_offset = (name_len
|
||||
? cpu_to_le16(offsetof(ATTR_RECORD, resident_end))
|
||||
? const_cpu_to_le16(offsetof(ATTR_RECORD, resident_end))
|
||||
: const_cpu_to_le16(0));
|
||||
a->flags = data_flags;
|
||||
a->instance = m->next_attr_instance;
|
||||
@@ -3884,8 +3932,8 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, "
|
||||
"dataruns_size %d, flags 0x%x.\n",
|
||||
(long long) ni->mft_no, (unsigned) type,
|
||||
(long long) lowest_vcn, dataruns_size, (unsigned) flags);
|
||||
(long long) ni->mft_no, (unsigned) le32_to_cpu(type),
|
||||
(long long) lowest_vcn, dataruns_size, (unsigned) le16_to_cpu(flags));
|
||||
|
||||
if (!ni || dataruns_size <= 0 || (!name && name_len)) {
|
||||
errno = EINVAL;
|
||||
@@ -3912,7 +3960,7 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0,
|
||||
ctx)) {
|
||||
err = EEXIST;
|
||||
ntfs_log_perror("Attribute 0x%x already present", type);
|
||||
ntfs_log_perror("Attribute 0x%x already present", le32_to_cpu(type));
|
||||
goto put_err_out;
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
@@ -3951,10 +3999,10 @@ int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
? STANDARD_COMPRESSION_UNIT : 0;
|
||||
/* If @lowest_vcn == 0, than setup empty attribute. */
|
||||
if (!lowest_vcn) {
|
||||
a->highest_vcn = cpu_to_sle64(-1);
|
||||
a->allocated_size = 0;
|
||||
a->data_size = 0;
|
||||
a->initialized_size = 0;
|
||||
a->highest_vcn = const_cpu_to_sle64(-1);
|
||||
a->allocated_size = const_cpu_to_sle64(0);
|
||||
a->data_size = const_cpu_to_sle64(0);
|
||||
a->initialized_size = const_cpu_to_sle64(0);
|
||||
/* Set empty mapping pairs. */
|
||||
*((u8*)a + le16_to_cpu(a->mapping_pairs_offset)) = 0;
|
||||
}
|
||||
@@ -4173,7 +4221,7 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n",
|
||||
(long long)ni->mft_no, type, (long long)size);
|
||||
(long long)ni->mft_no, le32_to_cpu(type), (long long)size);
|
||||
|
||||
if (ni->nr_extents == -1)
|
||||
ni = ni->base_ni;
|
||||
@@ -4395,7 +4443,7 @@ int ntfs_attr_rm(ntfs_attr *na)
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
(long long) na->ni->mft_no, na->type);
|
||||
(long long) na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
/* Free cluster allocation. */
|
||||
if (NAttrNonResident(na)) {
|
||||
@@ -4743,7 +4791,7 @@ int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
int mp_size, mp_ofs, name_ofs, arec_size, err;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
|
||||
long)na->ni->mft_no, na->type);
|
||||
long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
/* Some preliminary sanity checking. */
|
||||
if (NAttrNonResident(na)) {
|
||||
@@ -4851,7 +4899,7 @@ int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
a->name_offset = cpu_to_le16(name_ofs);
|
||||
|
||||
/* Setup the fields specific to non-resident attributes. */
|
||||
a->lowest_vcn = cpu_to_sle64(0);
|
||||
a->lowest_vcn = const_cpu_to_sle64(0);
|
||||
a->highest_vcn = cpu_to_sle64((new_allocated_size - 1) >>
|
||||
vol->cluster_size_bits);
|
||||
|
||||
@@ -4868,7 +4916,7 @@ int ntfs_attr_make_non_resident(ntfs_attr *na,
|
||||
if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) {
|
||||
/* support only ATTR_IS_COMPRESSED compression mode */
|
||||
a->compression_unit = STANDARD_COMPRESSION_UNIT;
|
||||
a->compressed_size = const_cpu_to_le64(0);
|
||||
a->compressed_size = const_cpu_to_sle64(0);
|
||||
} else {
|
||||
a->compression_unit = 0;
|
||||
a->flags &= ~ATTR_COMPRESSION_MASK;
|
||||
@@ -4937,7 +4985,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
|
||||
int err, ret = STATUS_ERROR;
|
||||
|
||||
ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)newsize);
|
||||
|
||||
/* Get the attribute record that needs modification. */
|
||||
@@ -5094,6 +5142,10 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
|
||||
*/
|
||||
if (na->type==AT_STANDARD_INFORMATION || na->type==AT_ATTRIBUTE_LIST) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (!NInoAttrList(na->ni) && ntfs_inode_add_attrlist(na->ni)) {
|
||||
ntfs_log_perror("Could not add attribute list");
|
||||
return -1;
|
||||
}
|
||||
if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD,
|
||||
non_resident_end) + 8)) {
|
||||
ntfs_log_perror("Could not free space in MFT record");
|
||||
@@ -5240,7 +5292,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
||||
s64 arec_size, bytes_read;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
|
||||
long)na->ni->mft_no, na->type);
|
||||
long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
/* Should be called for the first extent of the attribute. */
|
||||
if (sle64_to_cpu(a->lowest_vcn)) {
|
||||
@@ -5314,7 +5366,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
||||
|
||||
/* Convert the attribute record to describe a resident attribute. */
|
||||
a->non_resident = 0;
|
||||
a->flags = 0;
|
||||
a->flags = const_cpu_to_le16(0);
|
||||
a->value_length = cpu_to_le32(na->data_size);
|
||||
a->value_offset = cpu_to_le16(val_ofs);
|
||||
/*
|
||||
@@ -5402,7 +5454,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
|
||||
int sparse, ret = 0;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type);
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
if (a->lowest_vcn)
|
||||
goto out;
|
||||
@@ -5545,7 +5597,7 @@ retry:
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode %llu, attr 0x%x\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type);
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
|
||||
|
||||
if (!NAttrNonResident(na)) {
|
||||
errno = EINVAL;
|
||||
@@ -5847,8 +5899,12 @@ retry:
|
||||
ntfs_log_perror("%s: get mp size failed", __FUNCTION__);
|
||||
goto put_err_out;
|
||||
}
|
||||
/* Allocate new mft record. */
|
||||
ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
|
||||
/* Allocate new mft record, with special case for mft itself */
|
||||
if (!na->ni->mft_no)
|
||||
ni = ntfs_mft_rec_alloc(na->ni->vol,
|
||||
na->type == AT_DATA);
|
||||
else
|
||||
ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
|
||||
if (!ni) {
|
||||
ntfs_log_perror("Could not allocate new MFT record");
|
||||
goto put_err_out;
|
||||
@@ -5903,6 +5959,7 @@ retry:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
NAttrClearRunlistDirty(na);
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
@@ -5969,7 +6026,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
|
||||
int err;
|
||||
|
||||
ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", (unsigned long long)
|
||||
na->ni->mft_no, na->type, (long long)newsize);
|
||||
na->ni->mft_no, le32_to_cpu(na->type), (long long)newsize);
|
||||
|
||||
vol = na->ni->vol;
|
||||
|
||||
@@ -6030,6 +6087,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
|
||||
ntfs_log_trace("Eeek! Run list truncation failed.\n");
|
||||
return -1;
|
||||
}
|
||||
NAttrSetRunlistDirty(na);
|
||||
|
||||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
@@ -6080,7 +6138,8 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
|
||||
|
||||
/* If the attribute now has zero size, make it resident. */
|
||||
if (!newsize) {
|
||||
if (ntfs_attr_make_resident(na, ctx)) {
|
||||
if (!(na->data_flags & ATTR_IS_ENCRYPTED)
|
||||
&& ntfs_attr_make_resident(na, ctx)) {
|
||||
/* If couldn't make resident, just continue. */
|
||||
if (errno != EPERM)
|
||||
ntfs_log_error("Failed to make attribute "
|
||||
@@ -6125,7 +6184,7 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize,
|
||||
int err;
|
||||
|
||||
ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)newsize, (long long)na->data_size);
|
||||
|
||||
vol = na->ni->vol;
|
||||
@@ -6245,6 +6304,7 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize,
|
||||
return -1;
|
||||
}
|
||||
na->rl = rln;
|
||||
NAttrSetRunlistDirty(na);
|
||||
|
||||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
@@ -6330,6 +6390,7 @@ rollback:
|
||||
na->rl = NULL;
|
||||
ntfs_log_perror("Couldn't truncate runlist. Rollback failed");
|
||||
} else {
|
||||
NAttrSetRunlistDirty(na);
|
||||
/* Prepare to mapping pairs update. */
|
||||
na->allocated_size = org_alloc_size;
|
||||
/* Restore mapping pairs. */
|
||||
@@ -6394,7 +6455,7 @@ static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
|
||||
}
|
||||
|
||||
ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)newsize);
|
||||
|
||||
if (na->data_size == newsize) {
|
||||
@@ -6406,7 +6467,7 @@ static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
|
||||
* Encrypted attributes are not supported. We return access denied,
|
||||
* which is what Windows NT4 does, too.
|
||||
*/
|
||||
if (na->data_flags & ATTR_IS_ENCRYPTED) {
|
||||
if ((na->data_flags & ATTR_IS_ENCRYPTED) && !na->ni->vol->efs_raw) {
|
||||
errno = EACCES;
|
||||
ntfs_log_trace("Cannot truncate encrypted attribute\n");
|
||||
goto out;
|
||||
@@ -6703,6 +6764,42 @@ exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shrink the size of a data attribute if needed
|
||||
*
|
||||
* For non-resident attributes only.
|
||||
* The space remains allocated.
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* -1 if failed, with errno telling why
|
||||
*/
|
||||
|
||||
|
||||
int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name,
|
||||
int stream_name_len, off_t offset)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ATTR_RECORD *a;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (ctx) {
|
||||
if (!ntfs_attr_lookup(AT_DATA, stream_name, stream_name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
a = ctx->attr;
|
||||
|
||||
if (a->non_resident
|
||||
&& (sle64_to_cpu(a->initialized_size) > offset)) {
|
||||
a->initialized_size = cpu_to_sle64(offset);
|
||||
a->data_size = a->initialized_size;
|
||||
}
|
||||
res = 0;
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, const ntfschar *name,
|
||||
u32 name_len)
|
||||
@@ -6743,7 +6840,7 @@ int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||
/* do not log removal of non-existent stream */
|
||||
if (type != AT_DATA) {
|
||||
ntfs_log_perror("Failed to open attribute 0x%02x of inode "
|
||||
"0x%llx", type, (unsigned long long)ni->mft_no);
|
||||
"0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -6751,7 +6848,7 @@ int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||
ret = ntfs_attr_rm(na);
|
||||
if (ret)
|
||||
ntfs_log_perror("Failed to remove attribute 0x%02x of inode "
|
||||
"0x%llx", type, (unsigned long long)ni->mft_no);
|
||||
"0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no);
|
||||
ntfs_attr_close(na);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -211,6 +211,7 @@ typedef enum {
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_DataAppending, /* 1: Attribute is being appended to */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
NA_RunlistDirty, /* 1: Runlist has been updated */
|
||||
} ntfs_attr_state_bits;
|
||||
|
||||
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
||||
@@ -237,6 +238,10 @@ typedef enum {
|
||||
#define NAttrSetDataAppending(na) set_nattr_flag(na, DataAppending)
|
||||
#define NAttrClearDataAppending(na) clear_nattr_flag(na, DataAppending)
|
||||
|
||||
#define NAttrRunlistDirty(na) test_nattr_flag(na, RunlistDirty)
|
||||
#define NAttrSetRunlistDirty(na) set_nattr_flag(na, RunlistDirty)
|
||||
#define NAttrClearRunlistDirty(na) clear_nattr_flag(na, RunlistDirty)
|
||||
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
@@ -391,6 +396,8 @@ extern int ntfs_attr_data_read(ntfs_inode *ni,
|
||||
extern int ntfs_attr_data_write(ntfs_inode *ni,
|
||||
ntfschar *stream_name, int stream_name_len,
|
||||
const char *buf, size_t size, off_t offset);
|
||||
extern int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name,
|
||||
int stream_name_len, off_t offset);
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
MFT_REF mref;
|
||||
leMFT_REF mref;
|
||||
ntfs_attr *na = NULL;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
u8 *new_al;
|
||||
@@ -150,7 +150,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
|
||||
((u8*)attr + le16_to_cpu(attr->name_offset)) :
|
||||
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
|
||||
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
|
||||
(attr->non_resident) ? sle64_to_cpu(attr->lowest_vcn) :
|
||||
0, (attr->non_resident) ? NULL : ((u8*)attr +
|
||||
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
|
||||
0 : le32_to_cpu(attr->value_length), ctx)) {
|
||||
@@ -193,7 +193,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
if (attr->non_resident)
|
||||
ale->lowest_vcn = attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->lowest_vcn = const_cpu_to_sle64(0);
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
||||
@@ -265,7 +265,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
|
||||
(long long) ctx->ntfs_ino->mft_no,
|
||||
(unsigned) le32_to_cpu(ctx->al_entry->type),
|
||||
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||
(long long) sle64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||
|
||||
if (!NInoAttrList(base_ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
|
||||
@@ -65,7 +65,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
ntfs_log_debug("Beginning bootsector check.\n");
|
||||
|
||||
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||
if (b->oem_id != const_cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
|
||||
ntfs_log_error("NTFS signature is missing.\n");
|
||||
goto not_ntfs;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
|
||||
}
|
||||
}
|
||||
|
||||
if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
|
||||
if (b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
|
||||
ntfs_log_debug("Warning: Bootsector has invalid end of sector "
|
||||
"marker.\n");
|
||||
|
||||
@@ -204,7 +204,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
(sectors - 1) << vol->sector_size_bits,
|
||||
SEEK_SET) == -1) {
|
||||
ntfs_log_perror("Failed to read last sector (%lld)",
|
||||
(long long)sectors);
|
||||
(long long)(sectors - 1));
|
||||
ntfs_log_error("%s", last_sector_error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
#define ENODATA ENOENT
|
||||
#endif
|
||||
|
||||
#ifndef ELIBBAD
|
||||
#define ELIBBAD ENOEXEC
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
@@ -65,11 +69,9 @@ extern char *strsep(char **stringp, const char *delim);
|
||||
|
||||
#else /* !defined WINDOWS */
|
||||
|
||||
#ifndef __HAIKU__
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* defined WINDOWS */
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2009-2013 Jean-Pierre Andre
|
||||
* Copyright (c) 2009-2014 Jean-Pierre Andre
|
||||
* Copyright (c) 2014 Eric Biggers
|
||||
*
|
||||
* 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
|
||||
@@ -21,17 +22,6 @@
|
||||
* 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
|
||||
*
|
||||
* A part of the compression algorithm is based on lzhuf.c whose header
|
||||
* describes the roles of the original authors (with no apparent copyright
|
||||
* notice, and according to http://home.earthlink.net/~neilbawd/pall.html
|
||||
* this was put into public domain in 1988 by Haruhiko OKUMURA).
|
||||
*
|
||||
* LZHUF.C English version 1.0
|
||||
* Based on Japanese version 29-NOV-1988
|
||||
* LZSS coded by Haruhiko OKUMURA
|
||||
* Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
|
||||
* Edited and translated to English by Kenji RIKITAKE
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -81,96 +71,191 @@ typedef enum {
|
||||
NTFS_SB_IS_COMPRESSED = 0x8000,
|
||||
} ntfs_compression_constants;
|
||||
|
||||
/* Match length at or above which ntfs_best_match() will stop searching for
|
||||
* longer matches. */
|
||||
#define NICE_MATCH_LEN 18
|
||||
|
||||
/* Maximum number of potential matches that ntfs_best_match() will consider at
|
||||
* each position. */
|
||||
#define MAX_SEARCH_DEPTH 24
|
||||
|
||||
/* log base 2 of the number of entries in the hash table for match-finding. */
|
||||
#define HASH_SHIFT 14
|
||||
|
||||
/* Constant for the multiplicative hash function. */
|
||||
#define HASH_MULTIPLIER 0x1E35A7BD
|
||||
|
||||
struct COMPRESS_CONTEXT {
|
||||
const unsigned char *inbuf;
|
||||
int bufsize;
|
||||
int size;
|
||||
int rel;
|
||||
int mxsz;
|
||||
s16 head[256];
|
||||
s16 lson[NTFS_SB_SIZE];
|
||||
s16 rson[NTFS_SB_SIZE];
|
||||
s16 head[1 << HASH_SHIFT];
|
||||
s16 prev[NTFS_SB_SIZE];
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Hash the next 3-byte sequence in the input buffer
|
||||
*/
|
||||
static inline unsigned int ntfs_hash(const u8 *p)
|
||||
{
|
||||
u32 str;
|
||||
u32 hash;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/* Unaligned access allowed, and little endian CPU.
|
||||
* Callers ensure that at least 4 (not 3) bytes are remaining. */
|
||||
str = *(const u32 *)p & 0xFFFFFF;
|
||||
#else
|
||||
str = ((u32)p[0] << 0) | ((u32)p[1] << 8) | ((u32)p[2] << 16);
|
||||
#endif
|
||||
|
||||
hash = str * HASH_MULTIPLIER;
|
||||
|
||||
/* High bits are more random than the low bits. */
|
||||
return hash >> (32 - HASH_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for the longest sequence matching current position
|
||||
*
|
||||
* A binary tree is maintained to locate all previously met sequences,
|
||||
* and this function has to be called for all of them.
|
||||
* A hash table, each entry of which points to a chain of sequence
|
||||
* positions sharing the corresponding hash code, is maintained to speed up
|
||||
* searching for matches. To maintain the hash table, either
|
||||
* ntfs_best_match() or ntfs_skip_position() has to be called for each
|
||||
* consecutive position.
|
||||
*
|
||||
* This function is heavily used, it has to be optimized carefully
|
||||
* This function is heavily used; it has to be optimized carefully.
|
||||
*
|
||||
* Returns the size of the longest match,
|
||||
* zero if no match is found.
|
||||
* This function sets pctx->size and pctx->rel to the length and offset,
|
||||
* respectively, of the longest match found.
|
||||
*
|
||||
* The minimum match length is assumed to be 3, and the maximum match
|
||||
* length is assumed to be pctx->mxsz. If this function produces
|
||||
* pctx->size < 3, then no match was found.
|
||||
*
|
||||
* Note: for the following reasons, this function is not guaranteed to find
|
||||
* *the* longest match up to pctx->mxsz:
|
||||
*
|
||||
* (1) If this function finds a match of NICE_MATCH_LEN bytes or greater,
|
||||
* it ends early because a match this long is good enough and it's not
|
||||
* worth spending more time searching.
|
||||
*
|
||||
* (2) If this function considers MAX_SEARCH_DEPTH matches with a single
|
||||
* position, it ends early and returns the longest match found so far.
|
||||
* This saves a lot of time on degenerate inputs.
|
||||
*/
|
||||
|
||||
static int ntfs_best_match(struct COMPRESS_CONTEXT *pctx, int i)
|
||||
static void ntfs_best_match(struct COMPRESS_CONTEXT *pctx, const int i,
|
||||
int best_len)
|
||||
{
|
||||
s16 *prev;
|
||||
int node;
|
||||
register long j;
|
||||
long maxpos;
|
||||
long startj;
|
||||
long bestj;
|
||||
int bufsize;
|
||||
int bestnode;
|
||||
register const unsigned char *p1,*p2;
|
||||
const u8 * const inbuf = pctx->inbuf;
|
||||
const u8 * const strptr = &inbuf[i]; /* String we're matching against */
|
||||
s16 * const prev = pctx->prev;
|
||||
const int max_len = min(pctx->bufsize - i, pctx->mxsz);
|
||||
const int nice_len = min(NICE_MATCH_LEN, max_len);
|
||||
int depth_remaining = MAX_SEARCH_DEPTH;
|
||||
const u8 *best_matchptr = strptr;
|
||||
unsigned int hash;
|
||||
s16 cur_match;
|
||||
const u8 *matchptr;
|
||||
int len;
|
||||
|
||||
p1 = pctx->inbuf;
|
||||
node = pctx->head[p1[i] & 255];
|
||||
if (node >= 0) {
|
||||
/* search the best match at current position */
|
||||
bestnode = node;
|
||||
bufsize = pctx->bufsize;
|
||||
/* restrict matches to the longest allowed sequence */
|
||||
maxpos = bufsize;
|
||||
if ((i + pctx->mxsz) < maxpos)
|
||||
maxpos = i + pctx->mxsz;
|
||||
startj = i + 1 - maxpos;
|
||||
bestj = startj;
|
||||
/* make indexes relative to end of allowed position */
|
||||
p1 = &p1[maxpos];
|
||||
if (startj < 0) {
|
||||
do {
|
||||
/* indexes are negative */
|
||||
p2 = &p1[node - i];
|
||||
/* no need to compare the first byte */
|
||||
j = startj;
|
||||
/* the second byte cannot lead to useful compression */
|
||||
if (p1[j] == p2[j]) {
|
||||
j++;
|
||||
if (j < 0) {
|
||||
do {
|
||||
} while ((p1[j] == p2[j])
|
||||
&& (++j < 0));
|
||||
}
|
||||
/* remember the match, if better */
|
||||
if (j > bestj) {
|
||||
bestj = j;
|
||||
bestnode = node;
|
||||
}
|
||||
}
|
||||
/* walk in the tree in the right direction */
|
||||
if ((j < 0) && (p1[j] < p2[j]))
|
||||
prev = &pctx->lson[node];
|
||||
else
|
||||
prev = &pctx->rson[node];
|
||||
node = *prev;
|
||||
/* stop if reaching a leaf or maximum length */
|
||||
} while ((node >= 0) && (j < 0));
|
||||
/* put the node into the tree if we reached a leaf */
|
||||
if (node < 0)
|
||||
*prev = i;
|
||||
}
|
||||
/* done, return the best match */
|
||||
pctx->size = bestj + maxpos - i;
|
||||
pctx->rel = bestnode - i;
|
||||
} else {
|
||||
pctx->head[p1[i] & 255] = i;
|
||||
pctx->size = 0;
|
||||
pctx->rel = 0;
|
||||
if (max_len < 4)
|
||||
goto out;
|
||||
|
||||
/* Insert the current sequence into the appropriate hash chain. */
|
||||
hash = ntfs_hash(strptr);
|
||||
cur_match = pctx->head[hash];
|
||||
prev[i] = cur_match;
|
||||
pctx->head[hash] = i;
|
||||
|
||||
if (best_len >= max_len) {
|
||||
/* Lazy match is being attempted, but there aren't enough length
|
||||
* bits remaining to code a longer match. */
|
||||
goto out;
|
||||
}
|
||||
return (pctx->size);
|
||||
|
||||
/* Search the appropriate hash chain for matches. */
|
||||
|
||||
for (; cur_match >= 0 && depth_remaining--;
|
||||
cur_match = prev[cur_match])
|
||||
{
|
||||
|
||||
matchptr = &inbuf[cur_match];
|
||||
|
||||
/* Considering the potential match at 'matchptr': is it longer
|
||||
* than 'best_len'?
|
||||
*
|
||||
* The bytes at index 'best_len' are the most likely to differ,
|
||||
* so check them first.
|
||||
*
|
||||
* The bytes at indices 'best_len - 1' and '0' are less
|
||||
* important to check separately. But doing so still gives a
|
||||
* slight performance improvement, at least on x86_64, probably
|
||||
* because they create separate branches for the CPU to predict
|
||||
* independently of the branches in the main comparison loops.
|
||||
*/
|
||||
if (matchptr[best_len] != strptr[best_len] ||
|
||||
matchptr[best_len - 1] != strptr[best_len - 1] ||
|
||||
matchptr[0] != strptr[0])
|
||||
goto next_match;
|
||||
|
||||
for (len = 1; len < best_len - 1; len++)
|
||||
if (matchptr[len] != strptr[len])
|
||||
goto next_match;
|
||||
|
||||
/* The match is the longest found so far ---
|
||||
* at least 'best_len' + 1 bytes. Continue extending it. */
|
||||
|
||||
best_matchptr = matchptr;
|
||||
|
||||
do {
|
||||
if (++best_len >= nice_len) {
|
||||
/* 'nice_len' reached; don't waste time
|
||||
* searching for longer matches. Extend the
|
||||
* match as far as possible and terminate the
|
||||
* search. */
|
||||
while (best_len < max_len &&
|
||||
(best_matchptr[best_len] ==
|
||||
strptr[best_len]))
|
||||
{
|
||||
best_len++;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
} while (best_matchptr[best_len] == strptr[best_len]);
|
||||
|
||||
/* Found a longer match, but 'nice_len' not yet reached. */
|
||||
|
||||
next_match:
|
||||
/* Continue to next match in the chain. */
|
||||
;
|
||||
}
|
||||
|
||||
/* Reached end of chain, or ended early due to reaching the maximum
|
||||
* search depth. */
|
||||
|
||||
out:
|
||||
/* Return the longest match we were able to find. */
|
||||
pctx->size = best_len;
|
||||
pctx->rel = best_matchptr - strptr; /* given as a negative number! */
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance the match-finder, but don't search for matches.
|
||||
*/
|
||||
static void ntfs_skip_position(struct COMPRESS_CONTEXT *pctx, const int i)
|
||||
{
|
||||
unsigned int hash;
|
||||
|
||||
if (pctx->bufsize - i < 4)
|
||||
return;
|
||||
|
||||
/* Insert the current sequence into the appropriate hash chain. */
|
||||
hash = ntfs_hash(pctx->inbuf + i);
|
||||
pctx->prev[i] = pctx->head[hash];
|
||||
pctx->head[hash] = i;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -188,7 +273,7 @@ static int ntfs_best_match(struct COMPRESS_CONTEXT *pctx, int i)
|
||||
* 0 if an error has been met.
|
||||
*/
|
||||
|
||||
static unsigned int ntfs_compress_block(const char *inbuf, int bufsize,
|
||||
static unsigned int ntfs_compress_block(const char *inbuf, const int bufsize,
|
||||
char *outbuf)
|
||||
{
|
||||
struct COMPRESS_CONTEXT *pctx;
|
||||
@@ -196,109 +281,168 @@ static unsigned int ntfs_compress_block(const char *inbuf, int bufsize,
|
||||
int j; /* end of best match from current position */
|
||||
int k; /* end of best match from next position */
|
||||
int offs; /* offset to best match */
|
||||
int n;
|
||||
int bp; /* bits to store offset */
|
||||
int bp_cur; /* saved bits to store offset at current position */
|
||||
int mxoff; /* max match offset : 1 << bp */
|
||||
int mxsz2;
|
||||
unsigned int xout;
|
||||
unsigned int q; /* aggregated offset and size */
|
||||
int done;
|
||||
int have_match; /* do we have a match at the current position? */
|
||||
char *ptag; /* location reserved for a tag */
|
||||
int tag; /* current value of tag */
|
||||
int ntag; /* count of bits still undefined in tag */
|
||||
|
||||
pctx = (struct COMPRESS_CONTEXT*)ntfs_malloc(sizeof(struct COMPRESS_CONTEXT));
|
||||
if (pctx) {
|
||||
for (n=0; n<NTFS_SB_SIZE; n++)
|
||||
pctx->lson[n] = pctx->rson[n] = -1;
|
||||
for (n=0; n<256; n++)
|
||||
pctx->head[n] = -1;
|
||||
pctx->inbuf = (const unsigned char*)inbuf;
|
||||
pctx->bufsize = bufsize;
|
||||
xout = 2;
|
||||
n = 0;
|
||||
i = 0;
|
||||
bp = 4;
|
||||
mxoff = 1 << bp;
|
||||
pctx->mxsz = (1 << (16 - bp)) + 2;
|
||||
tag = 0;
|
||||
done = -1;
|
||||
ntag = 8;
|
||||
ptag = &outbuf[xout++];
|
||||
while ((i < bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
|
||||
/* adjust the longest match we can output */
|
||||
pctx = ntfs_malloc(sizeof(struct COMPRESS_CONTEXT));
|
||||
if (!pctx) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All hash chains start as empty. The special value '-1' indicates the
|
||||
* end of each hash chain. */
|
||||
memset(pctx->head, 0xFF, sizeof(pctx->head));
|
||||
|
||||
pctx->inbuf = (const unsigned char*)inbuf;
|
||||
pctx->bufsize = bufsize;
|
||||
xout = 2;
|
||||
i = 0;
|
||||
bp = 4;
|
||||
mxoff = 1 << bp;
|
||||
pctx->mxsz = (1 << (16 - bp)) + 2;
|
||||
have_match = 0;
|
||||
tag = 0;
|
||||
ntag = 8;
|
||||
ptag = &outbuf[xout++];
|
||||
|
||||
while ((i < bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
|
||||
|
||||
/* This implementation uses "lazy" parsing: it always chooses
|
||||
* the longest match, unless the match at the next position is
|
||||
* longer. This is the same strategy used by the high
|
||||
* compression modes of zlib. */
|
||||
|
||||
if (!have_match) {
|
||||
/* Find the longest match at the current position. But
|
||||
* first adjust the maximum match length if needed.
|
||||
* (This loop might need to run more than one time in
|
||||
* the case that we just output a long match.) */
|
||||
while (mxoff < i) {
|
||||
bp++;
|
||||
mxoff <<= 1;
|
||||
pctx->mxsz = (pctx->mxsz + 2) >> 1;
|
||||
}
|
||||
/* search the best match at current position */
|
||||
if (done < i)
|
||||
do {
|
||||
ntfs_best_match(pctx,++done);
|
||||
} while (done < i);
|
||||
j = i + pctx->size;
|
||||
if ((j - i) > pctx->mxsz)
|
||||
j = i + pctx->mxsz;
|
||||
ntfs_best_match(pctx, i, 2);
|
||||
}
|
||||
|
||||
if ((j - i) > 2) {
|
||||
offs = pctx->rel;
|
||||
/* check whether there is a better run at i+1 */
|
||||
ntfs_best_match(pctx,i+1);
|
||||
done = i+1;
|
||||
if (pctx->size >= 3) {
|
||||
|
||||
/* Found a match at the current position. */
|
||||
|
||||
j = i + pctx->size;
|
||||
bp_cur = bp;
|
||||
offs = pctx->rel;
|
||||
|
||||
if (pctx->size >= NICE_MATCH_LEN) {
|
||||
|
||||
/* Choose long matches immediately. */
|
||||
|
||||
q = (~offs << (16 - bp_cur)) + (j - i - 3);
|
||||
outbuf[xout++] = q & 255;
|
||||
outbuf[xout++] = (q >> 8) & 255;
|
||||
tag |= (1 << (8 - ntag));
|
||||
|
||||
if (j == bufsize) {
|
||||
/* Shortcut if the match extends to the
|
||||
* end of the buffer. */
|
||||
i = j;
|
||||
--ntag;
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
do {
|
||||
ntfs_skip_position(pctx, i);
|
||||
} while (++i != j);
|
||||
have_match = 0;
|
||||
} else {
|
||||
/* Check for a longer match at the next
|
||||
* position. */
|
||||
|
||||
/* Doesn't need to be while() since we just
|
||||
* adjusted the maximum match length at the
|
||||
* previous position. */
|
||||
if (mxoff < i + 1) {
|
||||
bp++;
|
||||
mxoff <<= 1;
|
||||
pctx->mxsz = (pctx->mxsz + 2) >> 1;
|
||||
}
|
||||
ntfs_best_match(pctx, i + 1, pctx->size);
|
||||
k = i + 1 + pctx->size;
|
||||
mxsz2 = pctx->mxsz;
|
||||
if (mxoff <= i)
|
||||
mxsz2 = (pctx->mxsz + 2) >> 1;
|
||||
if ((k - i) > mxsz2)
|
||||
k = i + mxsz2;
|
||||
|
||||
if (k > (j + 1)) {
|
||||
/* issue a single byte */
|
||||
outbuf[xout++] = inbuf[i];
|
||||
i++;
|
||||
/* Next match is longer.
|
||||
* Output a literal. */
|
||||
outbuf[xout++] = inbuf[i++];
|
||||
have_match = 1;
|
||||
} else {
|
||||
q = (~offs << (16 - bp))
|
||||
+ (j - i - 3);
|
||||
/* Next match isn't longer.
|
||||
* Output the current match. */
|
||||
q = (~offs << (16 - bp_cur)) +
|
||||
(j - i - 3);
|
||||
outbuf[xout++] = q & 255;
|
||||
outbuf[xout++] = (q >> 8) & 255;
|
||||
tag |= (1 << (8 - ntag));
|
||||
i = j;
|
||||
|
||||
/* The minimum match length is 3, and
|
||||
* we've run two bytes through the
|
||||
* matchfinder already. So the minimum
|
||||
* number of positions we need to skip
|
||||
* is 1. */
|
||||
i += 2;
|
||||
do {
|
||||
ntfs_skip_position(pctx, i);
|
||||
} while (++i != j);
|
||||
have_match = 0;
|
||||
}
|
||||
} else {
|
||||
outbuf[xout++] = inbuf[i];
|
||||
i++;
|
||||
}
|
||||
/* store the tag if fully used */
|
||||
if (!--ntag) {
|
||||
*ptag = tag;
|
||||
ntag = 8;
|
||||
ptag = &outbuf[xout++];
|
||||
tag = 0;
|
||||
}
|
||||
}
|
||||
/* store the last tag, if partially used */
|
||||
if (ntag == 8)
|
||||
xout--;
|
||||
else
|
||||
*ptag = tag;
|
||||
/* uncompressed must be full size, accept if better */
|
||||
if ((i >= bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
|
||||
outbuf[0] = (xout - 3) & 255;
|
||||
outbuf[1] = 0xb0 + (((xout - 3) >> 8) & 15);
|
||||
} else {
|
||||
memcpy(&outbuf[2],inbuf,bufsize);
|
||||
if (bufsize < NTFS_SB_SIZE)
|
||||
memset(&outbuf[bufsize+2], 0,
|
||||
NTFS_SB_SIZE - bufsize);
|
||||
outbuf[0] = 0xff;
|
||||
outbuf[1] = 0x3f;
|
||||
xout = NTFS_SB_SIZE + 2;
|
||||
/* No match at current position. Output a literal. */
|
||||
outbuf[xout++] = inbuf[i++];
|
||||
have_match = 0;
|
||||
}
|
||||
|
||||
/* Store the tag if fully used. */
|
||||
if (!--ntag) {
|
||||
*ptag = tag;
|
||||
ntag = 8;
|
||||
ptag = &outbuf[xout++];
|
||||
tag = 0;
|
||||
}
|
||||
free(pctx);
|
||||
} else {
|
||||
xout = 0;
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
/* Store the last tag if partially used. */
|
||||
if (ntag == 8)
|
||||
xout--;
|
||||
else
|
||||
*ptag = tag;
|
||||
|
||||
/* Determine whether to store the data compressed or uncompressed. */
|
||||
|
||||
if ((i >= bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
|
||||
/* Compressed. */
|
||||
outbuf[0] = (xout - 3) & 255;
|
||||
outbuf[1] = 0xb0 + (((xout - 3) >> 8) & 15);
|
||||
} else {
|
||||
/* Uncompressed. */
|
||||
memcpy(&outbuf[2], inbuf, bufsize);
|
||||
if (bufsize < NTFS_SB_SIZE)
|
||||
memset(&outbuf[bufsize + 2], 0, NTFS_SB_SIZE - bufsize);
|
||||
outbuf[0] = 0xff;
|
||||
outbuf[1] = 0x3f;
|
||||
xout = NTFS_SB_SIZE + 2;
|
||||
}
|
||||
|
||||
/* Free the compression context and return the total number of bytes
|
||||
* written to 'outbuf'. */
|
||||
free(pctx);
|
||||
return (xout);
|
||||
}
|
||||
|
||||
@@ -575,7 +719,7 @@ s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b)
|
||||
unsigned int nr_cbs, cb_clusters;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count 0x%llx.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
|
||||
(long long)pos, (long long)count);
|
||||
data_flags = na->data_flags;
|
||||
compression = na->ni->flags & FILE_ATTR_COMPRESSED;
|
||||
@@ -987,6 +1131,7 @@ static s32 ntfs_comp_set(ntfs_attr *na, runlist_element *rl,
|
||||
outbuf[compsz++] = 0;
|
||||
/* write a full cluster, to avoid partial reading */
|
||||
rounded = ((compsz - 1) | (clsz - 1)) + 1;
|
||||
memset(&outbuf[compsz], 0, rounded - compsz);
|
||||
written = write_clusters(vol, rl, offs, rounded, outbuf);
|
||||
if (written != rounded) {
|
||||
/*
|
||||
@@ -1417,6 +1562,7 @@ static int ntfs_compress_free(ntfs_attr *na, runlist_element *rl,
|
||||
ntfs_log_error("No cluster to free after compression\n");
|
||||
errno = EIO;
|
||||
}
|
||||
NAttrSetRunlistDirty(na);
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,70 @@
|
||||
/* Haiku-specific stuff */
|
||||
#ifdef __HAIKU__
|
||||
|
||||
/* major part of a device */
|
||||
#define major(x) (int)((unsigned)((x)>>8)&0x7F)
|
||||
#define bmajor(x) (int)((unsigned)((x)>>8)&0x7F)
|
||||
|
||||
/* minor part of a device */
|
||||
#define minor(x) (int)((x)&0xFF)
|
||||
#endif
|
||||
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* Define to 1 for disabling reparse plugins */
|
||||
/* #undef DISABLE_PLUGINS */
|
||||
|
||||
/* Define this to 1 if you want to enable support of encrypted files in
|
||||
libntfs and utilities. */
|
||||
/* #undef ENABLE_CRYPTO */
|
||||
|
||||
/* Define to 1 if debug should be enabled */
|
||||
/* #undef ENABLE_DEBUG */
|
||||
|
||||
/* Define this to 1 if you want to enable use of Windows compliant disk
|
||||
geometry. */
|
||||
/* #undef ENABLE_HD */
|
||||
|
||||
/* Define to 1 if the nfconv patch should be enabled */
|
||||
/* #undef ENABLE_NFCONV */
|
||||
|
||||
/* Define this to 1 if you want to enable generation of DCE compliant UUIDs.
|
||||
*/
|
||||
/* #undef ENABLE_UUID */
|
||||
|
||||
/* Define to 1 if using internal fuse */
|
||||
/* #undef FUSE_INTERNAL */
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#undef HAVE_ATEXIT
|
||||
#define HAVE_ATEXIT 1
|
||||
|
||||
/* Define to 1 if you have the `basename' function. */
|
||||
#undef HAVE_BASENAME
|
||||
#define HAVE_BASENAME 1
|
||||
|
||||
/* Define to 1 if you have the <byteswap.h> header file. */
|
||||
#undef HAVE_BYTESWAP_H
|
||||
/* #undef HAVE_BYTESWAP_H */
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
/* #undef HAVE_CLOCK_GETTIME */
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#define HAVE_CTYPE_H 1
|
||||
|
||||
/* Define to 1 if you have the `daemon' function. */
|
||||
#define HAVE_DAEMON 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
#undef HAVE_DOPRNT
|
||||
/* #undef HAVE_DOPRNT */
|
||||
|
||||
/* Define to 1 if you have the `dup2' function. */
|
||||
#undef HAVE_DUP2
|
||||
#define HAVE_DUP2 1
|
||||
|
||||
/* Define to 1 if you have the <endian.h> header file. */
|
||||
#define HAVE_ENDIAN_H 1
|
||||
@@ -33,103 +76,128 @@
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `fdatasync' function. */
|
||||
#undef HAVE_FDATASYNC
|
||||
/* #undef HAVE_FDATASYNC */
|
||||
|
||||
/* Define to 1 if you have the <features.h> header file. */
|
||||
#undef HAVE_FEATURES_H
|
||||
/* #undef HAVE_FEATURES_H */
|
||||
|
||||
/* Define to 1 if you have the <gcrypt.h> header file. */
|
||||
#undef HAVE_GCRYPT_H
|
||||
/* Define to 1 if you have the `ffs' function. */
|
||||
#define HAVE_FFS 1
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
/* #undef HAVE_FORK */
|
||||
|
||||
/* Define to 1 if you have the `getmntent' function. */
|
||||
#undef HAVE_GETMNTENT
|
||||
/* #undef HAVE_GETMNTENT */
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
#define HAVE_GETOPT_H 1
|
||||
|
||||
/* Define to 1 if you have the `getopt_long' function. */
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
|
||||
/* Define to 1 if you have the <gnutls/pkcs12.h> header file. */
|
||||
#undef HAVE_GNUTLS_PKCS12_H
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `hasmntopt' function. */
|
||||
#undef HAVE_HASMNTOPT
|
||||
/* #undef HAVE_HASMNTOPT */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `c' library (-lc). */
|
||||
/* #undef HAVE_LIBC */
|
||||
|
||||
/* Define to 1 if you have the <libgen.h> header file. */
|
||||
#undef HAVE_LIBGEN_H
|
||||
#define HAVE_LIBGEN_H 1
|
||||
|
||||
/* Define to 1 if you have the <libintl.h> header file. */
|
||||
#undef HAVE_LIBINTL_H
|
||||
/* #undef HAVE_LIBINTL_H */
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/fd.h> header file. */
|
||||
#undef HAVE_LINUX_FD_H
|
||||
/* #undef HAVE_LINUX_FD_H */
|
||||
|
||||
/* Define to 1 if you have the <linux/fs.h> header file. */
|
||||
/* #undef HAVE_LINUX_FS_H */
|
||||
|
||||
/* Define to 1 if you have the <linux/hdreg.h> header file. */
|
||||
#undef HAVE_LINUX_HDREG_H
|
||||
/* #undef HAVE_LINUX_HDREG_H */
|
||||
|
||||
/* Define to 1 if you have the <linux/major.h> header file. */
|
||||
#undef HAVE_LINUX_MAJOR_H
|
||||
/* #undef HAVE_LINUX_MAJOR_H */
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define to 1 if you have the <machine/endian.h> header file. */
|
||||
#undef HAVE_MACHINE_ENDIAN_H
|
||||
/* #undef HAVE_MACHINE_ENDIAN_H */
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
|
||||
#undef HAVE_MBRTOWC
|
||||
#define HAVE_MBRTOWC 1
|
||||
|
||||
/* Define to 1 if you have the `mbsinit' function. */
|
||||
#undef HAVE_MBSINIT
|
||||
//#define HAVE_MBSINIT 1
|
||||
/* #undef HAVE_MBSINIT */
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#define HAVE_MEMCPY 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the <mntent.h> header file. */
|
||||
#undef HAVE_MNTENT_H
|
||||
/* #undef HAVE_MNTENT_H */
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `random' function. */
|
||||
#define HAVE_RANDOM 1
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
#define HAVE_REALPATH 1
|
||||
|
||||
/* Define to 1 if you have the `regcomp' function. */
|
||||
#undef HAVE_REGCOMP
|
||||
#define HAVE_REGCOMP 1
|
||||
|
||||
/* Define to 1 if you have the <regex.h> header file. */
|
||||
#define HAVE_REGEX_H 1
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
/* #undef HAVE_SETLOCALE */
|
||||
|
||||
/* 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
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#define HAVE_STDARG_H 1
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
/* #undef HAVE_STDBOOL_H */
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#define HAVE_STDIO_H 1
|
||||
@@ -138,182 +206,254 @@
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the `strftime' function. */
|
||||
#undef HAVE_STRFTIME
|
||||
#define HAVE_STRFTIME 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strnlen' function. */
|
||||
#undef HAVE_STRNLEN
|
||||
#define HAVE_STRNLEN 1
|
||||
|
||||
/* Define to 1 if you have the `strsep' function. */
|
||||
/* #undef HAVE_STRSEP */
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#undef HAVE_STRTOL
|
||||
#define HAVE_STRTOL 1
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
#define HAVE_STRTOUL 1
|
||||
|
||||
/* Define to 1 if `st_blocks' is member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_BLOCKS
|
||||
/* Define to 1 if `st_atim' is a member of `struct stat'. */
|
||||
#define HAVE_STRUCT_STAT_ST_ATIM 1
|
||||
|
||||
/* Define to 1 if `st_rdev' is member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_RDEV
|
||||
/* Define to 1 if `st_atimensec' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIMENSEC */
|
||||
|
||||
/* Define to 1 if `st_atimespec' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIMESPEC */
|
||||
|
||||
/* Define to 1 if `st_blocks' is a member of `struct stat'. */
|
||||
#define HAVE_STRUCT_STAT_ST_BLOCKS 1
|
||||
|
||||
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
|
||||
#define HAVE_STRUCT_STAT_ST_RDEV 1
|
||||
|
||||
/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
|
||||
`HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
|
||||
#undef HAVE_ST_BLOCKS
|
||||
#define HAVE_ST_BLOCKS 1
|
||||
|
||||
/* Define to 1 if you have the `sysconf' function. */
|
||||
#undef HAVE_SYSCONF
|
||||
#define HAVE_SYSCONF 1
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
/* #undef HAVE_SYSLOG_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/byteorder.h> header file. */
|
||||
#undef HAVE_SYS_BYTEORDER_H
|
||||
/* #undef HAVE_SYS_BYTEORDER_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/disk.h> header file. */
|
||||
/* #undef HAVE_SYS_DISK_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/endian.h> header file. */
|
||||
#undef HAVE_SYS_ENDIAN_H
|
||||
/* #undef HAVE_SYS_ENDIAN_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||
#undef HAVE_SYS_MOUNT_H
|
||||
/* #undef HAVE_SYS_MOUNT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/statvfs.h> header file. */
|
||||
#undef HAVE_SYS_STATVFS_H
|
||||
#define HAVE_SYS_STATVFS_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/sysmacros.h> header file. */
|
||||
#undef HAVE_SYS_SYSMACROS_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/vfs.h> header file. */
|
||||
#undef HAVE_SYS_VFS_H
|
||||
/* #undef HAVE_SYS_VFS_H */
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
#define HAVE_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `utime' function. */
|
||||
#undef HAVE_UTIME
|
||||
#define HAVE_UTIME 1
|
||||
|
||||
/* Define to 1 if you have the `utimensat' function. */
|
||||
#define HAVE_UTIMENSAT 1
|
||||
|
||||
/* Define to 1 if you have the <utime.h> header file. */
|
||||
#undef HAVE_UTIME_H
|
||||
#define HAVE_UTIME_H 1
|
||||
|
||||
/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
|
||||
#undef HAVE_UTIME_NULL
|
||||
#define HAVE_UTIME_NULL 1
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#undef HAVE_VPRINTF
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
#define HAVE_WCHAR_H 1
|
||||
|
||||
/* Define to 1 if you have the <windows.h> header file. */
|
||||
#undef HAVE_WINDOWS_H
|
||||
/* #undef HAVE_WINDOWS_H */
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
/* #undef HAVE__BOOL */
|
||||
|
||||
/* Don't update /etc/mtab */
|
||||
/* #undef IGNORE_MTAB */
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
|
||||
*/
|
||||
/* #undef MAJOR_IN_MKDEV */
|
||||
|
||||
/* Define to 1 if `major', `minor', and `makedev' are declared in
|
||||
<sysmacros.h>. */
|
||||
/* #undef MAJOR_IN_SYSMACROS */
|
||||
|
||||
/* Don't use default IO ops */
|
||||
/* #undef NO_NTFS_DEVICE_DEFAULT_IO_OPS */
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
#define PACKAGE "ntfs-3g"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
#define PACKAGE_VERSION "2017.3.23"
|
||||
|
||||
/* POSIX ACL support */
|
||||
/* #undef POSIXACLS */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
#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 */
|
||||
#undef VERSION
|
||||
#define VERSION "2017.3.23"
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
#undef WORDS_BIGENDIAN
|
||||
/* Define to 1 if this is a Windows OS */
|
||||
/* #undef WINDOWS */
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to 1 if your processor stores words with the least significant byte
|
||||
first (like Intel and VAX, unlike Motorola and SPARC). */
|
||||
#undef WORDS_LITTLEENDIAN
|
||||
#define WORDS_LITTLEENDIAN 1
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
/* system extended attributes mappings */
|
||||
/* #undef XATTR_MAPPINGS */
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
/* #undef _POSIX_1_SOURCE */
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Required define if using POSIX threads */
|
||||
/* #undef _REENTRANT */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to `long' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
#define LOGGING_DISABLE 1
|
||||
|
||||
/* major part of a device */
|
||||
#define major(x) (int)((unsigned)((x)>>8)&0x7F)
|
||||
#define bmajor(x) (int)((unsigned)((x)>>8)&0x7F)
|
||||
|
||||
/* minor part of a device */
|
||||
#define minor(x) (int)((x)&0xFF)
|
||||
|
||||
/* make a device number */
|
||||
#define makedev(x,y) (dev_t)(((x)<<8) | (y))
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
@@ -211,14 +211,14 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
|
||||
|
||||
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
|
||||
dops = dev->d_ops;
|
||||
|
||||
for (total = 0; count; count -= br, total += br) {
|
||||
@@ -273,7 +273,7 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
errno = EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
dops = dev->d_ops;
|
||||
|
||||
NDevSetDirty(dev);
|
||||
@@ -296,7 +296,7 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
total--; /* on sync error, return partially written */
|
||||
}
|
||||
ret = total;
|
||||
out:
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -605,18 +605,19 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
|
||||
partition_info partitionInfo;
|
||||
device_geometry geometry;
|
||||
|
||||
|
||||
if (dev->d_ops->ioctl(dev, B_GET_PARTITION_INFO, &partitionInfo) == 0)
|
||||
size = partitionInfo.size;
|
||||
else if (dev->d_ops->ioctl(dev, B_GET_GEOMETRY, &geometry) == 0) {
|
||||
size = (off_t)geometry.cylinder_count * geometry.sectors_per_track
|
||||
* geometry.head_count * geometry.bytes_per_sector;
|
||||
}
|
||||
|
||||
|
||||
if (size > 0)
|
||||
return (s64)size / block_size;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We couldn't figure it out by using a specialized ioctl,
|
||||
* so do binary search to find the size of the device.
|
||||
|
||||
@@ -72,7 +72,7 @@ struct hd_geometry {
|
||||
/* A few useful functions */
|
||||
int ntfs_win32_set_sparse(int);
|
||||
int ntfs_win32_ftruncate(int fd, s64 size);
|
||||
int ntfs_win32_device_ftruncate(struct ntfs_device*, s64);
|
||||
int ntfs_device_win32_ftruncate(struct ntfs_device*, s64);
|
||||
|
||||
#endif /* HAVE_WINDOWS_H */
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2004-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2008-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2014 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
|
||||
@@ -40,7 +40,13 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
@@ -61,10 +67,7 @@
|
||||
#include "security.h"
|
||||
#include "reparse.h"
|
||||
#include "object_id.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* The little endian Unicode strings "$I30", "$SII", "$SDH", "$O"
|
||||
@@ -313,7 +316,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||
*/
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
|
||||
if (!le16_to_cpu(ie->length)) {
|
||||
ntfs_log_error("Zero length index entry in inode %lld"
|
||||
"\n", (unsigned long long)dir_ni->mft_no);
|
||||
@@ -384,7 +387,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
|
||||
}
|
||||
|
||||
/* Get the starting vcn of the index_block holding the child node. */
|
||||
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
|
||||
vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
|
||||
|
||||
descend_into_child_node:
|
||||
|
||||
@@ -441,7 +444,7 @@ descend_into_child_node:
|
||||
(u8*)ie + le16_to_cpu(ie->key_length) >
|
||||
index_end) {
|
||||
ntfs_log_error("Index entry out of bounds in directory "
|
||||
"inode %lld.\n",
|
||||
"inode %lld.\n",
|
||||
(unsigned long long)dir_ni->mft_no);
|
||||
errno = EIO;
|
||||
goto close_err_out;
|
||||
@@ -452,7 +455,7 @@ descend_into_child_node:
|
||||
*/
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
|
||||
if (!le16_to_cpu(ie->length)) {
|
||||
errno = EIO;
|
||||
ntfs_log_error("Zero length index entry in inode %lld"
|
||||
@@ -496,7 +499,7 @@ descend_into_child_node:
|
||||
goto close_err_out;
|
||||
}
|
||||
/* Child node present, descend into it. */
|
||||
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
|
||||
vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
|
||||
if (vcn >= 0)
|
||||
goto descend_into_child_node;
|
||||
ntfs_log_error("Negative child node vcn in directory inode "
|
||||
@@ -681,9 +684,9 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ntfs_log_trace("path: '%s'\n", pathname);
|
||||
|
||||
|
||||
ascii = strdup(pathname);
|
||||
if (!ascii) {
|
||||
ntfs_log_error("Out of memory.\n");
|
||||
@@ -818,7 +821,7 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
err = EIO;
|
||||
goto close;
|
||||
}
|
||||
|
||||
|
||||
free(unicode);
|
||||
unicode = NULL;
|
||||
|
||||
@@ -875,7 +878,7 @@ typedef enum {
|
||||
* and most metadata files have such similar patters.
|
||||
*/
|
||||
|
||||
static u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
u32 dt_type;
|
||||
@@ -884,8 +887,14 @@ static u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
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;
|
||||
/*
|
||||
* Unrecognized patterns (eg HID + SYST for metadata)
|
||||
* are plain files or directories
|
||||
*/
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
dt_type = NTFS_DT_DIR;
|
||||
else
|
||||
dt_type = NTFS_DT_REG;
|
||||
if (na->data_size <= 1) {
|
||||
if (!(ni->flags & FILE_ATTR_HIDDEN))
|
||||
dt_type = (na->data_size ?
|
||||
@@ -974,7 +983,7 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 ivcn_bits,
|
||||
MFT_REF mref;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
|
||||
/* Advance the position even if going to skip the entry. */
|
||||
if (index_type == INDEX_TYPE_ALLOCATION)
|
||||
*pos = (u8*)ie - (u8*)iu.ia + (sle64_to_cpu(
|
||||
@@ -1058,7 +1067,7 @@ MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
|
||||
int eo;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
|
||||
if (!ni) {
|
||||
errno = EINVAL;
|
||||
return ERR_MREF(-1);
|
||||
@@ -1068,7 +1077,7 @@ MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
|
||||
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",
|
||||
ntfs_log_error("No file name found in inode %lld\n",
|
||||
(unsigned long long)ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
@@ -1129,7 +1138,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
u8 index_block_size_bits, index_vcn_size_bits;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
|
||||
if (!dir_ni || !pos || !filldir) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -1249,10 +1258,10 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
/* The last entry cannot contain a name. */
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
|
||||
if (!le16_to_cpu(ie->length))
|
||||
goto dir_err_out;
|
||||
|
||||
|
||||
/* Skip index root entry if continuing previous readdir. */
|
||||
if (ir_pos > (u8*)ie - (u8*)ir)
|
||||
continue;
|
||||
@@ -1405,10 +1414,10 @@ find_next_index_buffer:
|
||||
/* The last entry cannot contain a name. */
|
||||
if (ie->ie_flags & INDEX_ENTRY_END)
|
||||
break;
|
||||
|
||||
|
||||
if (!le16_to_cpu(ie->length))
|
||||
goto dir_err_out;
|
||||
|
||||
|
||||
/* Skip index entry if continuing previous readdir. */
|
||||
if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
|
||||
continue;
|
||||
@@ -1495,19 +1504,19 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
int err, fn_len, si_len;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
|
||||
/* Sanity checks. */
|
||||
if (!dir_ni || !name || !name_len) {
|
||||
ntfs_log_error("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||
errno = EOPNOTSUPP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
|
||||
if (!ni)
|
||||
return NULL;
|
||||
@@ -1534,7 +1543,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
si->last_access_time = ni->last_access_time;
|
||||
if (securid) {
|
||||
set_nino_flag(ni, v3_Extensions);
|
||||
ni->owner_id = si->owner_id = 0;
|
||||
ni->owner_id = si->owner_id = const_cpu_to_le32(0);
|
||||
ni->security_id = si->security_id = securid;
|
||||
ni->quota_charged = si->quota_charged = const_cpu_to_le64(0);
|
||||
ni->usn = si->usn = const_cpu_to_le64(0);
|
||||
@@ -1599,15 +1608,15 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
ni->vol->indx_record_size >>
|
||||
ni->vol->cluster_size_bits;
|
||||
else
|
||||
ir->clusters_per_index_block =
|
||||
ir->clusters_per_index_block =
|
||||
ni->vol->indx_record_size >>
|
||||
NTFS_BLOCK_SIZE_BITS;
|
||||
ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER));
|
||||
ir->index.entries_offset = const_cpu_to_le32(sizeof(INDEX_HEADER));
|
||||
ir->index.index_length = cpu_to_le32(index_len);
|
||||
ir->index.allocated_size = cpu_to_le32(index_len);
|
||||
ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT));
|
||||
ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER));
|
||||
ie->key_length = 0;
|
||||
ie->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER));
|
||||
ie->key_length = const_cpu_to_le16(0);
|
||||
ie->ie_flags = INDEX_ENTRY_END;
|
||||
/* Add INDEX_ROOT attribute to inode. */
|
||||
if (ntfs_attr_add(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4,
|
||||
@@ -1694,7 +1703,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
fn->last_mft_change_time = ni->last_mft_change_time;
|
||||
fn->last_access_time = ni->last_access_time;
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_sle64(0);
|
||||
else {
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
@@ -1714,7 +1723,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
|
||||
goto err_out;
|
||||
}
|
||||
/* Set hard links count and directory flag. */
|
||||
ni->mrec->link_count = cpu_to_le16(1);
|
||||
ni->mrec->link_count = const_cpu_to_le16(1);
|
||||
if (S_ISDIR(type))
|
||||
ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY;
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
@@ -1728,7 +1737,7 @@ err_out:
|
||||
|
||||
if (rollback_sd)
|
||||
ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
|
||||
|
||||
|
||||
if (rollback_data)
|
||||
ntfs_attr_remove(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
/*
|
||||
@@ -1793,7 +1802,7 @@ int ntfs_check_empty_dir(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))
|
||||
return 0;
|
||||
|
||||
@@ -1803,7 +1812,7 @@ int ntfs_check_empty_dir(ntfs_inode *ni)
|
||||
ntfs_log_perror("Failed to open directory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Non-empty directory? */
|
||||
if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){
|
||||
/* Both ENOTEMPTY and EEXIST are ok. We use the more common. */
|
||||
@@ -1811,7 +1820,7 @@ int ntfs_check_empty_dir(ntfs_inode *ni)
|
||||
ntfs_log_debug("Directory is not empty\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
||||
ntfs_attr_close(na);
|
||||
return ret;
|
||||
}
|
||||
@@ -1820,23 +1829,23 @@ static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn)
|
||||
{
|
||||
int link_count = le16_to_cpu(ni->mrec->link_count);
|
||||
int ret;
|
||||
|
||||
|
||||
ret = ntfs_check_empty_dir(ni);
|
||||
if (!ret || errno != ENOTEMPTY)
|
||||
return ret;
|
||||
/*
|
||||
/*
|
||||
* Directory is non-empty, so we can unlink only if there is more than
|
||||
* one "real" hard link, i.e. links aren't different DOS and WIN32 names
|
||||
*/
|
||||
if ((link_count == 1) ||
|
||||
if ((link_count == 1) ||
|
||||
(link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) {
|
||||
errno = ENOTEMPTY;
|
||||
ntfs_log_debug("Non-empty directory without hard links\n");
|
||||
goto no_hardlink;
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
no_hardlink:
|
||||
no_hardlink:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1875,7 +1884,7 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
||||
#endif
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
|
||||
if (!ni || !dir_ni || !name || !name_len) {
|
||||
ntfs_log_error("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
@@ -1895,20 +1904,23 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
||||
if (!actx)
|
||||
goto err_out;
|
||||
search:
|
||||
while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, actx)) {
|
||||
while (!(err = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, actx))) {
|
||||
#ifdef DEBUG
|
||||
char *s;
|
||||
#endif
|
||||
IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE;
|
||||
|
||||
errno = 0;
|
||||
fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
|
||||
le16_to_cpu(actx->attr->value_offset));
|
||||
#ifdef DEBUG
|
||||
s = ntfs_attr_name_get(fn->file_name, fn->file_name_length);
|
||||
ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d "
|
||||
"case: %d\n", s, fn->file_name_type,
|
||||
looking_for_dos_name, looking_for_win32_name,
|
||||
case_sensitive_match);
|
||||
ntfs_attr_name_free(&s);
|
||||
#endif
|
||||
if (looking_for_dos_name) {
|
||||
if (fn->file_name_type == FILE_NAME_DOS)
|
||||
break;
|
||||
@@ -1921,12 +1933,12 @@ search:
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* Ignore hard links from other directories */
|
||||
if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
|
||||
ntfs_log_debug("MFT record numbers don't match "
|
||||
"(%llu != %llu)\n",
|
||||
(long long unsigned)dir_ni->mft_no,
|
||||
"(%llu != %llu)\n",
|
||||
(long long unsigned)dir_ni->mft_no,
|
||||
(long long unsigned)MREF_LE(fn->parent_directory));
|
||||
continue;
|
||||
}
|
||||
@@ -1934,11 +1946,11 @@ search:
|
||||
|| ((fn->file_name_type == FILE_NAME_POSIX)
|
||||
&& NVolCaseSensitive(ni->vol)))
|
||||
case_sensitive = CASE_SENSITIVE;
|
||||
|
||||
|
||||
if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
|
||||
name, name_len, case_sensitive,
|
||||
name, name_len, case_sensitive,
|
||||
ni->vol->upcase, ni->vol->upcase_len)){
|
||||
|
||||
|
||||
if (fn->file_name_type == FILE_NAME_WIN32) {
|
||||
looking_for_dos_name = TRUE;
|
||||
ntfs_attr_reinit_search_ctx(actx);
|
||||
@@ -1949,7 +1961,7 @@ search:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errno) {
|
||||
if (err) {
|
||||
/*
|
||||
* If case sensitive search failed, then try once again
|
||||
* ignoring case.
|
||||
@@ -1961,29 +1973,29 @@ search:
|
||||
}
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
||||
if (ntfs_check_unlinkable_dir(ni, fn) < 0)
|
||||
goto err_out;
|
||||
|
||||
|
||||
if (ntfs_index_remove(dir_ni, ni, fn, le32_to_cpu(actx->attr->value_length)))
|
||||
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) {
|
||||
if ((ni->mrec->link_count == const_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);
|
||||
|
||||
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
if (looking_for_dos_name) {
|
||||
looking_for_dos_name = FALSE;
|
||||
@@ -2109,7 +2121,7 @@ search:
|
||||
"Leaving inconsistent metadata.\n");
|
||||
}
|
||||
ni = NULL;
|
||||
ok:
|
||||
ok:
|
||||
ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
|
||||
out:
|
||||
if (actx)
|
||||
@@ -2152,19 +2164,14 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
int fn_len, err;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
if (!ni || !dir_ni || !name || !name_len ||
|
||||
|
||||
if (!ni || !dir_ni || !name || !name_len ||
|
||||
ni->mft_no == dir_ni->mft_no) {
|
||||
err = EINVAL;
|
||||
ntfs_log_perror("ntfs_link wrong arguments");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if ((ni->flags & FILE_ATTR_REPARSE_POINT)
|
||||
&& !ntfs_possible_symlink(ni)) {
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (NVolHideDotFiles(dir_ni->vol)) {
|
||||
/* Set hidden flag according to the latest name */
|
||||
if ((name_len > 1)
|
||||
@@ -2174,7 +2181,7 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
else
|
||||
ni->flags &= ~FILE_ATTR_HIDDEN;
|
||||
}
|
||||
|
||||
|
||||
/* Create FILE_NAME attribute. */
|
||||
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
|
||||
fn = ntfs_calloc(fn_len);
|
||||
@@ -2189,7 +2196,7 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
|
||||
fn->file_attributes = ni->flags;
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||
fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT;
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
|
||||
fn->data_size = fn->allocated_size = const_cpu_to_sle64(0);
|
||||
} else {
|
||||
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fn->data_size = cpu_to_sle64(ni->data_size);
|
||||
@@ -2276,8 +2283,6 @@ ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni)
|
||||
return (dir_ni);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
||||
#define MAX_DOS_NAME_LENGTH 12
|
||||
|
||||
/*
|
||||
@@ -2426,11 +2431,11 @@ int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
*/
|
||||
ntfs_name_upcase(dosname, doslen,
|
||||
ni->vol->upcase, ni->vol->upcase_len);
|
||||
if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) {
|
||||
outsize = ntfs_ucstombs(dosname, doslen, &outname, 0);
|
||||
if (outsize < 0) {
|
||||
ntfs_log_error("Cannot represent dosname in current locale.\n");
|
||||
outsize = -errno;
|
||||
} else {
|
||||
outsize = strlen(outname);
|
||||
if (value && (outsize <= (int)size))
|
||||
memcpy(value, outname, outsize);
|
||||
else
|
||||
@@ -2562,7 +2567,7 @@ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
if (set_namespace(ni, dir_ni, longname, longlen,
|
||||
FILE_NAME_WIN32_AND_DOS) >= 0) {
|
||||
if (!ntfs_delete(vol,
|
||||
(const char*)NULL, ni, dir_ni,
|
||||
(const char*)NULL, ni, dir_ni,
|
||||
deletename, deletelen))
|
||||
res = 0;
|
||||
deleted = TRUE;
|
||||
@@ -2583,7 +2588,7 @@ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
if (!ntfs_link_i(ni, dir_ni, shortname, shortlen,
|
||||
if (!ntfs_link_i(ni, dir_ni, shortname, shortlen,
|
||||
FILE_NAME_DOS)
|
||||
/* make sure a new link was recorded */
|
||||
&& (le16_to_cpu(ni->mrec->link_count) > linkcount)) {
|
||||
@@ -2652,8 +2657,12 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
shortlen = ntfs_mbstoucs(newname, &shortname);
|
||||
if (shortlen > MAX_DOS_NAME_LENGTH)
|
||||
shortlen = MAX_DOS_NAME_LENGTH;
|
||||
/* make sure the short name has valid chars */
|
||||
if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) {
|
||||
|
||||
/* Make sure the short name has valid chars.
|
||||
* Note: the short name cannot end with dot or space, but the
|
||||
* corresponding long name can. */
|
||||
if ((shortlen < 0)
|
||||
|| ntfs_forbidden_names(ni->vol,shortname,shortlen,TRUE)) {
|
||||
ntfs_inode_close_in_dir(ni,dir_ni);
|
||||
ntfs_inode_close(dir_ni);
|
||||
res = -errno;
|
||||
@@ -2664,7 +2673,8 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
if (longlen > 0) {
|
||||
oldlen = get_dos_name(ni, dnum, oldname);
|
||||
if ((oldlen >= 0)
|
||||
&& !ntfs_forbidden_chars(longname, longlen)) {
|
||||
&& !ntfs_forbidden_names(ni->vol, longname, longlen,
|
||||
FALSE)) {
|
||||
if (oldlen > 0) {
|
||||
if (flags & XATTR_CREATE) {
|
||||
res = -1;
|
||||
@@ -2759,7 +2769,7 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
} else {
|
||||
/*
|
||||
* DOS name has been found, but cannot
|
||||
* migrate to Posix : something bad
|
||||
* migrate to Posix : something bad
|
||||
* has happened
|
||||
*/
|
||||
errno = EIO;
|
||||
@@ -2785,5 +2795,3 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,12 +29,6 @@
|
||||
|
||||
#define PATH_SEP '/'
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We do not have these under DJGPP, so define our version that do not conflict
|
||||
* with other S_IFs defined under DJGPP.
|
||||
@@ -115,10 +109,8 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir);
|
||||
|
||||
ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
|
||||
|
||||
#ifdef __HAIKU__
|
||||
MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni);
|
||||
#endif
|
||||
u32 ntfs_interix_types(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size);
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* ea.c - Processing of EA's
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2014 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
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "param.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "index.h"
|
||||
#include "dir.h"
|
||||
#include "ea.h"
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* Create a needed attribute (EA or EA_INFORMATION)
|
||||
*
|
||||
* Returns 0 if successful,
|
||||
* -1 otherwise, with errno indicating why it failed.
|
||||
*/
|
||||
|
||||
static int ntfs_need_ea(ntfs_inode *ni, ATTR_TYPES type, int size, int flags)
|
||||
{
|
||||
u8 dummy;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
if (!ntfs_attr_exist(ni,type, AT_UNNAMED,0)) {
|
||||
if (!(flags & XATTR_REPLACE)) {
|
||||
/*
|
||||
* no needed attribute : add one,
|
||||
* apparently, this does not feed the new value in
|
||||
* Note : NTFS version must be >= 3
|
||||
*/
|
||||
if (ni->vol->major_ver >= 3) {
|
||||
res = ntfs_attr_add(ni, type,
|
||||
AT_UNNAMED,0,&dummy,(s64)size);
|
||||
if (!res) {
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
} else {
|
||||
errno = EOPNOTSUPP;
|
||||
res = -1;
|
||||
}
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the old EA_INFORMATION or delete the current one,
|
||||
* when EA cannot be updated.
|
||||
*
|
||||
* As this is used in the context of some other error, the caller
|
||||
* is responsible for returning the proper error, and errno is
|
||||
* left unchanged.
|
||||
* Only double errors are logged here.
|
||||
*/
|
||||
|
||||
static void restore_ea_info(ntfs_attr *nai, const EA_INFORMATION *old_ea_info)
|
||||
{
|
||||
s64 written;
|
||||
int olderrno;
|
||||
|
||||
olderrno = errno;
|
||||
if (old_ea_info) {
|
||||
written = ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
|
||||
old_ea_info);
|
||||
if ((size_t)written != sizeof(EA_INFORMATION)) {
|
||||
ntfs_log_error("Could not restore the EA_INFORMATION,"
|
||||
" possible inconsistency in inode %lld\n",
|
||||
(long long)nai->ni->mft_no);
|
||||
}
|
||||
} else {
|
||||
if (ntfs_attr_rm(nai)) {
|
||||
ntfs_log_error("Could not delete the EA_INFORMATION,"
|
||||
" possible inconsistency in inode %lld\n",
|
||||
(long long)nai->ni->mft_no);
|
||||
}
|
||||
}
|
||||
errno = olderrno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update both EA and EA_INFORMATION
|
||||
*/
|
||||
|
||||
static int ntfs_update_ea(ntfs_inode *ni, const char *value, size_t size,
|
||||
const EA_INFORMATION *ea_info,
|
||||
const EA_INFORMATION *old_ea_info)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
ntfs_attr *nai;
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
|
||||
if (nai) {
|
||||
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
|
||||
if (na) {
|
||||
/*
|
||||
* Set EA_INFORMATION first, it is easier to
|
||||
* restore the old value, if setting EA fails.
|
||||
*/
|
||||
if (ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
|
||||
ea_info)
|
||||
!= (s64)sizeof(EA_INFORMATION)) {
|
||||
res = -errno;
|
||||
} else {
|
||||
if (((na->data_size > (s64)size)
|
||||
&& ntfs_attr_truncate(na, size))
|
||||
|| (ntfs_attr_pwrite(na, 0, size, value)
|
||||
!= (s64)size)) {
|
||||
res = -errno;
|
||||
if (old_ea_info)
|
||||
restore_ea_info(nai,
|
||||
old_ea_info);
|
||||
}
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
ntfs_attr_close(nai);
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the existing EA
|
||||
*
|
||||
* The EA_INFORMATION is not examined and the consistency of the
|
||||
* existing EA is not checked.
|
||||
*
|
||||
* If successful, the full attribute is returned unchanged
|
||||
* and its size is returned.
|
||||
* If the designated buffer is too small, the needed size is
|
||||
* returned, and the buffer is left unchanged.
|
||||
* If there is an error, a negative value is returned and errno
|
||||
* is set according to the error.
|
||||
*/
|
||||
|
||||
int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size)
|
||||
{
|
||||
s64 ea_size;
|
||||
void *ea_buf;
|
||||
int res = 0;
|
||||
|
||||
if (ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)) {
|
||||
ea_buf = ntfs_attr_readall(ni, AT_EA, (ntfschar*)NULL, 0,
|
||||
&ea_size);
|
||||
if (ea_buf) {
|
||||
if (value && (ea_size <= (s64)size))
|
||||
memcpy(value, ea_buf, ea_size);
|
||||
free(ea_buf);
|
||||
res = ea_size;
|
||||
} else {
|
||||
ntfs_log_error("Failed to read EA from inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
errno = ENODATA;
|
||||
res = -errno;
|
||||
}
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a new EA, and set EA_INFORMATION accordingly
|
||||
*
|
||||
* This is roughly the same as ZwSetEaFile() on Windows, however
|
||||
* the "offset to next" of the last EA should not be cleared.
|
||||
*
|
||||
* Consistency of the new EA is first checked.
|
||||
*
|
||||
* EA_INFORMATION is set first, and it is restored to its former
|
||||
* state if setting EA fails.
|
||||
*
|
||||
* Returns 0 if successful
|
||||
* a negative value if an error occurred.
|
||||
*/
|
||||
|
||||
int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags)
|
||||
{
|
||||
EA_INFORMATION ea_info;
|
||||
EA_INFORMATION *old_ea_info;
|
||||
s64 old_ea_size;
|
||||
int res;
|
||||
size_t offs;
|
||||
size_t nextoffs;
|
||||
BOOL ok;
|
||||
int ea_count;
|
||||
int ea_packed;
|
||||
const EA_ATTR *p_ea;
|
||||
|
||||
res = -1;
|
||||
if (value && (size > 0)) {
|
||||
/* do consistency checks */
|
||||
offs = 0;
|
||||
ok = TRUE;
|
||||
ea_count = 0;
|
||||
ea_packed = 0;
|
||||
nextoffs = 0;
|
||||
while (ok && (offs < size)) {
|
||||
p_ea = (const EA_ATTR*)&value[offs];
|
||||
nextoffs = offs + le32_to_cpu(p_ea->next_entry_offset);
|
||||
/* null offset to next not allowed */
|
||||
ok = (nextoffs > offs)
|
||||
&& (nextoffs <= size)
|
||||
&& !(nextoffs & 3)
|
||||
&& p_ea->name_length
|
||||
/* zero sized value are allowed */
|
||||
&& ((offs + offsetof(EA_ATTR,name)
|
||||
+ p_ea->name_length + 1
|
||||
+ le16_to_cpu(p_ea->value_length))
|
||||
<= nextoffs)
|
||||
&& ((offs + offsetof(EA_ATTR,name)
|
||||
+ p_ea->name_length + 1
|
||||
+ le16_to_cpu(p_ea->value_length))
|
||||
>= (nextoffs - 3))
|
||||
&& !p_ea->name[p_ea->name_length];
|
||||
/* name not checked, as chkdsk accepts any chars */
|
||||
if (ok) {
|
||||
if (p_ea->flags & NEED_EA)
|
||||
ea_count++;
|
||||
/*
|
||||
* Assume ea_packed includes :
|
||||
* 4 bytes for header (flags and lengths)
|
||||
* + name length + 1
|
||||
* + value length
|
||||
*/
|
||||
ea_packed += 5 + p_ea->name_length
|
||||
+ le16_to_cpu(p_ea->value_length);
|
||||
offs = nextoffs;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* EA and REPARSE_POINT exclude each other
|
||||
* see http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx
|
||||
* Also return EINVAL if REPARSE_POINT is present.
|
||||
*/
|
||||
if (ok
|
||||
&& !ntfs_attr_exist(ni, AT_REPARSE_POINT, AT_UNNAMED,0)) {
|
||||
ea_info.ea_length = cpu_to_le16(ea_packed);
|
||||
ea_info.need_ea_count = cpu_to_le16(ea_count);
|
||||
ea_info.ea_query_length = cpu_to_le32(nextoffs);
|
||||
|
||||
old_ea_size = 0;
|
||||
old_ea_info = NULL;
|
||||
/* Try to save the old EA_INFORMATION */
|
||||
if (ntfs_attr_exist(ni, AT_EA_INFORMATION,
|
||||
AT_UNNAMED, 0)) {
|
||||
old_ea_info = ntfs_attr_readall(ni,
|
||||
AT_EA_INFORMATION,
|
||||
(ntfschar*)NULL, 0, &old_ea_size);
|
||||
}
|
||||
/*
|
||||
* no EA or EA_INFORMATION : add them
|
||||
*/
|
||||
if (!ntfs_need_ea(ni, AT_EA_INFORMATION,
|
||||
sizeof(EA_INFORMATION), flags)
|
||||
&& !ntfs_need_ea(ni, AT_EA, 0, flags)) {
|
||||
res = ntfs_update_ea(ni, value, size,
|
||||
&ea_info, old_ea_info);
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
if (old_ea_info)
|
||||
free(old_ea_info);
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -errno;
|
||||
}
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the EA (including EA_INFORMATION)
|
||||
*
|
||||
* EA_INFORMATION is removed first, and it is restored to its former
|
||||
* state if removing EA fails.
|
||||
*
|
||||
* Returns 0, or -1 if there is a problem
|
||||
*/
|
||||
|
||||
int ntfs_remove_ntfs_ea(ntfs_inode *ni)
|
||||
{
|
||||
EA_INFORMATION *old_ea_info;
|
||||
s64 old_ea_size;
|
||||
int res;
|
||||
ntfs_attr *na;
|
||||
ntfs_attr *nai;
|
||||
|
||||
res = 0;
|
||||
if (ni) {
|
||||
/*
|
||||
* open and delete the EA_INFORMATION and the EA
|
||||
*/
|
||||
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
|
||||
if (nai) {
|
||||
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
|
||||
if (na) {
|
||||
/* Try to save the old EA_INFORMATION */
|
||||
old_ea_info = ntfs_attr_readall(ni,
|
||||
AT_EA_INFORMATION,
|
||||
(ntfschar*)NULL, 0, &old_ea_size);
|
||||
res = ntfs_attr_rm(na);
|
||||
NInoFileNameSetDirty(ni);
|
||||
if (!res) {
|
||||
res = ntfs_attr_rm(nai);
|
||||
if (res && old_ea_info) {
|
||||
/*
|
||||
* Failed to remove the EA, try to
|
||||
* restore the EA_INFORMATION
|
||||
*/
|
||||
restore_ea_info(nai,
|
||||
old_ea_info);
|
||||
}
|
||||
} else {
|
||||
ntfs_log_error("Failed to remove the"
|
||||
" EA_INFORMATION from inode %lld\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
free(old_ea_info);
|
||||
ntfs_attr_close(na);
|
||||
} else {
|
||||
/* EA_INFORMATION present, but no EA */
|
||||
res = ntfs_attr_rm(nai);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
ntfs_attr_close(nai);
|
||||
} else {
|
||||
errno = ENODATA;
|
||||
res = -1;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
res = -1;
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2014 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (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 EA_H
|
||||
#define EA_H
|
||||
|
||||
int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags);
|
||||
|
||||
int ntfs_remove_ntfs_ea(ntfs_inode *ni);
|
||||
|
||||
#endif /* EA_H */
|
||||
@@ -39,10 +39,6 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
@@ -57,8 +53,7 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#include "xattrs.h"
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
@@ -321,8 +316,8 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
|
||||
|
||||
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
{
|
||||
u64 newsize;
|
||||
u64 oldsize;
|
||||
s64 newsize;
|
||||
s64 oldsize;
|
||||
le16 appended_bytes;
|
||||
u16 padding_length;
|
||||
ntfs_inode *ni;
|
||||
@@ -420,8 +415,8 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
|
||||
NInoSetDirty(ni);
|
||||
NInoFileNameSetDirty(ni);
|
||||
|
||||
ctx->attr->data_size = cpu_to_le64(newsize);
|
||||
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
ctx->attr->data_size = cpu_to_sle64(newsize);
|
||||
if (sle64_to_cpu(ctx->attr->initialized_size) > newsize)
|
||||
ctx->attr->initialized_size = ctx->attr->data_size;
|
||||
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
|
||||
if (close_ctx)
|
||||
@@ -433,5 +428,3 @@ err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
@@ -61,10 +61,16 @@
|
||||
# define __BYTE_ORDER BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN BIG_ENDIAN
|
||||
# elif defined(__BYTE_ORDER__)
|
||||
# elif defined(__BYTE_ORDER__) && defined(__LITTLE_ENDIAN__) && \
|
||||
defined(__BIG_ENDIAN__)
|
||||
# define __BYTE_ORDER __BYTE_ORDER__
|
||||
# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
|
||||
# define __BIG_ENDIAN __BIG_ENDIAN__
|
||||
# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||
defined(__ORDER_BIG_ENDIAN__)
|
||||
# define __BYTE_ORDER __BYTE_ORDER__
|
||||
# define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
|
||||
# define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
|
||||
# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_LITTLEENDIAN)
|
||||
# define __BYTE_ORDER 1
|
||||
@@ -126,6 +132,22 @@
|
||||
#define __constant_cpu_to_le32(x) (x)
|
||||
#define __constant_cpu_to_le64(x) (x)
|
||||
|
||||
#define __be16_to_cpu(x) bswap_16(x)
|
||||
#define __be32_to_cpu(x) bswap_32(x)
|
||||
#define __be64_to_cpu(x) bswap_64(x)
|
||||
|
||||
#define __cpu_to_be16(x) bswap_16(x)
|
||||
#define __cpu_to_be32(x) bswap_32(x)
|
||||
#define __cpu_to_be64(x) bswap_64(x)
|
||||
|
||||
#define __constant_be16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_be32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_be64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#define __constant_cpu_to_be16(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_cpu_to_be32(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_cpu_to_be64(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
|
||||
#define __le16_to_cpu(x) bswap_16(x)
|
||||
@@ -144,6 +166,22 @@
|
||||
#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#define __be16_to_cpu(x) (x)
|
||||
#define __be32_to_cpu(x) (x)
|
||||
#define __be64_to_cpu(x) (x)
|
||||
|
||||
#define __cpu_to_be16(x) (x)
|
||||
#define __cpu_to_be32(x) (x)
|
||||
#define __cpu_to_be64(x) (x)
|
||||
|
||||
#define __constant_be16_to_cpu(x) (x)
|
||||
#define __constant_be32_to_cpu(x) (x)
|
||||
#define __constant_be64_to_cpu(x) (x)
|
||||
|
||||
#define __constant_cpu_to_be16(x) (x)
|
||||
#define __constant_cpu_to_be32(x) (x)
|
||||
#define __constant_cpu_to_be64(x) (x)
|
||||
|
||||
#else
|
||||
|
||||
#error "You must define __BYTE_ORDER to be __LITTLE_ENDIAN or __BIG_ENDIAN."
|
||||
@@ -190,14 +228,78 @@
|
||||
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
|
||||
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
|
||||
|
||||
/* Unsigned from BE to CPU conversion. */
|
||||
|
||||
#define be16_to_cpu(x) (u16)__be16_to_cpu((u16)(x))
|
||||
#define be32_to_cpu(x) (u32)__be32_to_cpu((u32)(x))
|
||||
#define be64_to_cpu(x) (u64)__be64_to_cpu((u64)(x))
|
||||
|
||||
#define be16_to_cpup(x) (u16)__be16_to_cpu(*(const u16*)(x))
|
||||
#define be32_to_cpup(x) (u32)__be32_to_cpu(*(const u32*)(x))
|
||||
#define be64_to_cpup(x) (u64)__be64_to_cpu(*(const u64*)(x))
|
||||
|
||||
/* Signed from BE to CPU conversion. */
|
||||
|
||||
#define sbe16_to_cpu(x) (s16)__be16_to_cpu((s16)(x))
|
||||
#define sbe32_to_cpu(x) (s32)__be32_to_cpu((s32)(x))
|
||||
#define sbe64_to_cpu(x) (s64)__be64_to_cpu((s64)(x))
|
||||
|
||||
#define sbe16_to_cpup(x) (s16)__be16_to_cpu(*(s16*)(x))
|
||||
#define sbe32_to_cpup(x) (s32)__be32_to_cpu(*(s32*)(x))
|
||||
#define sbe64_to_cpup(x) (s64)__be64_to_cpu(*(s64*)(x))
|
||||
|
||||
/* Unsigned from CPU to BE conversion. */
|
||||
|
||||
#define cpu_to_be16(x) (u16)__cpu_to_be16((u16)(x))
|
||||
#define cpu_to_be32(x) (u32)__cpu_to_be32((u32)(x))
|
||||
#define cpu_to_be64(x) (u64)__cpu_to_be64((u64)(x))
|
||||
|
||||
#define cpu_to_be16p(x) (u16)__cpu_to_be16(*(u16*)(x))
|
||||
#define cpu_to_be32p(x) (u32)__cpu_to_be32(*(u32*)(x))
|
||||
#define cpu_to_be64p(x) (u64)__cpu_to_be64(*(u64*)(x))
|
||||
|
||||
/* Signed from CPU to BE conversion. */
|
||||
|
||||
#define cpu_to_sbe16(x) (s16)__cpu_to_be16((s16)(x))
|
||||
#define cpu_to_sbe32(x) (s32)__cpu_to_be32((s32)(x))
|
||||
#define cpu_to_sbe64(x) (s64)__cpu_to_be64((s64)(x))
|
||||
|
||||
#define cpu_to_sbe16p(x) (s16)__cpu_to_be16(*(s16*)(x))
|
||||
#define cpu_to_sbe32p(x) (s32)__cpu_to_be32(*(s32*)(x))
|
||||
#define cpu_to_sbe64p(x) (s64)__cpu_to_be64(*(s64*)(x))
|
||||
|
||||
/* Constant endianness conversion defines. */
|
||||
|
||||
#define const_le16_to_cpu(x) __constant_le16_to_cpu(x)
|
||||
#define const_le32_to_cpu(x) __constant_le32_to_cpu(x)
|
||||
#define const_le64_to_cpu(x) __constant_le64_to_cpu(x)
|
||||
#define const_le16_to_cpu(x) ((u16) __constant_le16_to_cpu(x))
|
||||
#define const_le32_to_cpu(x) ((u32) __constant_le32_to_cpu(x))
|
||||
#define const_le64_to_cpu(x) ((u64) __constant_le64_to_cpu(x))
|
||||
|
||||
#define const_cpu_to_le16(x) __constant_cpu_to_le16(x)
|
||||
#define const_cpu_to_le32(x) __constant_cpu_to_le32(x)
|
||||
#define const_cpu_to_le64(x) __constant_cpu_to_le64(x)
|
||||
#define const_cpu_to_le16(x) ((le16) __constant_cpu_to_le16(x))
|
||||
#define const_cpu_to_le32(x) ((le32) __constant_cpu_to_le32(x))
|
||||
#define const_cpu_to_le64(x) ((le64) __constant_cpu_to_le64(x))
|
||||
|
||||
#define const_sle16_to_cpu(x) ((s16) __constant_le16_to_cpu((le16) x))
|
||||
#define const_sle32_to_cpu(x) ((s32) __constant_le32_to_cpu((le32) x))
|
||||
#define const_sle64_to_cpu(x) ((s64) __constant_le64_to_cpu((le64) x))
|
||||
|
||||
#define const_cpu_to_sle16(x) ((sle16) __constant_cpu_to_le16((u16) x))
|
||||
#define const_cpu_to_sle32(x) ((sle32) __constant_cpu_to_le32((u32) x))
|
||||
#define const_cpu_to_sle64(x) ((sle64) __constant_cpu_to_le64((u64) x))
|
||||
|
||||
#define const_be16_to_cpu(x) ((u16) __constant_be16_to_cpu(x)))
|
||||
#define const_be32_to_cpu(x) ((u32) __constant_be32_to_cpu(x)))
|
||||
#define const_be64_to_cpu(x) ((u64) __constant_be64_to_cpu(x)))
|
||||
|
||||
#define const_cpu_to_be16(x) ((be16) __constant_cpu_to_be16(x))
|
||||
#define const_cpu_to_be32(x) ((be32) __constant_cpu_to_be32(x))
|
||||
#define const_cpu_to_be64(x) ((be64) __constant_cpu_to_be64(x))
|
||||
|
||||
#define const_sbe16_to_cpu(x) ((s16) __constant_be16_to_cpu((be16) x))
|
||||
#define const_sbe32_to_cpu(x) ((s32) __constant_be32_to_cpu((be32) x))
|
||||
#define const_sbe64_to_cpu(x) ((s64) __constant_be64_to_cpu((be64) x))
|
||||
|
||||
#define const_cpu_to_sbe16(x) ((sbe16) __constant_cpu_to_be16((u16) x))
|
||||
#define const_cpu_to_sbe32(x) ((sbe32) __constant_cpu_to_be32((u32) x))
|
||||
#define const_cpu_to_sbe64(x) ((sbe64) __constant_cpu_to_be64((u64) x))
|
||||
|
||||
#endif /* defined _NTFS_ENDIANS_H */
|
||||
|
||||
@@ -143,7 +143,7 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
|
||||
{
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
if (!icx->entry)
|
||||
if (!icx->bad_index && !icx->entry)
|
||||
return;
|
||||
|
||||
if (icx->actx)
|
||||
@@ -191,9 +191,9 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx)
|
||||
};
|
||||
}
|
||||
|
||||
static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
|
||||
static leVCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
|
||||
{
|
||||
return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN));
|
||||
return (leVCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(leVCN));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +338,7 @@ static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
|
||||
|
||||
static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn)
|
||||
{
|
||||
*ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn);
|
||||
*ntfs_ie_get_vcn_addr(ie) = cpu_to_sle64(vcn);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -719,7 +719,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
||||
ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
|
||||
if (ret == STATUS_ERROR) {
|
||||
err = errno;
|
||||
goto err_out;
|
||||
goto err_lookup;
|
||||
}
|
||||
|
||||
icx->ir = ir;
|
||||
@@ -780,6 +780,8 @@ descend_into_child_node:
|
||||
|
||||
goto descend_into_child_node;
|
||||
err_out:
|
||||
icx->bad_index = TRUE; /* Force icx->* to be freed */
|
||||
err_lookup:
|
||||
free(ib);
|
||||
if (!err)
|
||||
err = EIO;
|
||||
@@ -811,17 +813,17 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
|
||||
return NULL;
|
||||
|
||||
ib->magic = magic_INDX;
|
||||
ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK));
|
||||
ib->usa_ofs = const_cpu_to_le16(sizeof(INDEX_BLOCK));
|
||||
ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1);
|
||||
/* Set USN to 1 */
|
||||
*(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1);
|
||||
ib->lsn = cpu_to_le64(0);
|
||||
*(le16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = const_cpu_to_le16(1);
|
||||
ib->lsn = const_cpu_to_sle64(0);
|
||||
|
||||
ib->index_block_vcn = cpu_to_sle64(ib_vcn);
|
||||
|
||||
ib->index.entries_offset = cpu_to_le32((ih_size +
|
||||
le16_to_cpu(ib->usa_count) * 2 + 7) & ~7);
|
||||
ib->index.index_length = 0;
|
||||
ib->index.index_length = const_cpu_to_le32(0);
|
||||
ib->index.allocated_size = cpu_to_le32(ib_size -
|
||||
(sizeof(INDEX_BLOCK) - ih_size));
|
||||
ib->index.ih_flags = node_type;
|
||||
@@ -1160,7 +1162,7 @@ retry :
|
||||
|
||||
ie = ntfs_ie_get_first(&ir->index);
|
||||
ie->ie_flags |= INDEX_ENTRY_NODE;
|
||||
ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
|
||||
ie->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
|
||||
|
||||
ir->index.ih_flags = LARGE_INDEX;
|
||||
ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
|
||||
@@ -1175,8 +1177,7 @@ retry :
|
||||
* index, we may have to move the root to an extent
|
||||
*/
|
||||
if ((errno == ENOSPC)
|
||||
&& !ctx->al_entry
|
||||
&& !ntfs_inode_add_attrlist(icx->ni)) {
|
||||
&& (ctx->al_entry || !ntfs_inode_add_attrlist(icx->ni))) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
|
||||
@@ -1842,7 +1843,8 @@ err_out:
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
int ntfs_index_remove(ntfs_inode *dir_ni,
|
||||
ntfs_inode *ni __attribute__((unused)),
|
||||
const void *key, const int keylen)
|
||||
{
|
||||
int ret = STATUS_ERROR;
|
||||
@@ -1857,13 +1859,6 @@ int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
|
||||
if (ntfs_index_lookup(key, keylen, icx))
|
||||
goto err_out;
|
||||
|
||||
if ((((FILE_NAME_ATTR *)icx->data)->file_attributes &
|
||||
FILE_ATTR_REPARSE_POINT)
|
||||
&& !ntfs_possible_symlink(ni)) {
|
||||
errno = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = ntfs_index_rm(icx);
|
||||
if (ret == STATUS_ERROR)
|
||||
goto err_out;
|
||||
@@ -2042,7 +2037,7 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
|
||||
INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
|
||||
{
|
||||
INDEX_ENTRY *next;
|
||||
int flags;
|
||||
le16 flags;
|
||||
|
||||
/*
|
||||
* lookup() may have returned an invalid node
|
||||
|
||||
@@ -129,6 +129,7 @@ typedef struct {
|
||||
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
|
||||
int pindex; /* maximum it's the number of the parent nodes */
|
||||
BOOL ib_dirty;
|
||||
BOOL bad_index;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
||||
@@ -36,9 +36,6 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#include "param.h"
|
||||
#include "compat.h"
|
||||
@@ -57,6 +54,7 @@
|
||||
#include "ntfstime.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
ntfs_inode *ntfs_inode_base(ntfs_inode *ni)
|
||||
{
|
||||
@@ -570,7 +568,7 @@ int ntfs_inode_close(ntfs_inode *ni)
|
||||
* Note, extent inodes are never closed directly. They are automatically
|
||||
* disposed off by the closing of the base inode.
|
||||
*/
|
||||
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
||||
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const leMFT_REF mref)
|
||||
{
|
||||
u64 mft_no = MREF_LE(mref);
|
||||
VCN extent_vcn;
|
||||
@@ -806,7 +804,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
goto err_out;
|
||||
}
|
||||
/* Collect the reparse tag, if any */
|
||||
reparse_tag = cpu_to_le32(0);
|
||||
reparse_tag = const_cpu_to_le32(0);
|
||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||
if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL,
|
||||
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
@@ -874,7 +872,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
(ni->flags & FILE_ATTR_VALID_FLAGS);
|
||||
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
fnx->data_size = fnx->allocated_size
|
||||
= const_cpu_to_le64(0);
|
||||
= const_cpu_to_sle64(0);
|
||||
else {
|
||||
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fnx->data_size = cpu_to_sle64(ni->data_size);
|
||||
@@ -1168,7 +1166,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
if (ctx->attr->non_resident)
|
||||
ale->lowest_vcn = ctx->attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->lowest_vcn = const_cpu_to_sle64(0);
|
||||
ale->mft_reference = MK_LE_MREF(ni->mft_no,
|
||||
le16_to_cpu(ni->mrec->sequence_number));
|
||||
ale->instance = ctx->attr->instance;
|
||||
@@ -1206,7 +1204,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
|
||||
|
||||
/* Add $ATTRIBUTE_LIST to mft record. */
|
||||
if (ntfs_resident_attr_record_add(ni,
|
||||
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
|
||||
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, const_cpu_to_le16(0)) < 0) {
|
||||
err = errno;
|
||||
ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT");
|
||||
goto rollback;
|
||||
@@ -1446,8 +1444,6 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get high precision NTFS times
|
||||
*
|
||||
@@ -1477,18 +1473,18 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
if (value && (size >= 8)) {
|
||||
times = (u64*)value;
|
||||
times[0] = le64_to_cpu(std_info->creation_time);
|
||||
times[0] = sle64_to_cpu(std_info->creation_time);
|
||||
ret = 8;
|
||||
if (size >= 16) {
|
||||
times[1] = le64_to_cpu(std_info->last_data_change_time);
|
||||
times[1] = sle64_to_cpu(std_info->last_data_change_time);
|
||||
ret = 16;
|
||||
}
|
||||
if (size >= 24) {
|
||||
times[2] = le64_to_cpu(std_info->last_access_time);
|
||||
times[2] = sle64_to_cpu(std_info->last_access_time);
|
||||
ret = 24;
|
||||
}
|
||||
if (size >= 32) {
|
||||
times[3] = le64_to_cpu(std_info->last_mft_change_time);
|
||||
times[3] = sle64_to_cpu(std_info->last_mft_change_time);
|
||||
ret = 32;
|
||||
}
|
||||
} else
|
||||
@@ -1551,16 +1547,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
||||
* return sub-second times in getattr()
|
||||
*/
|
||||
set_nino_flag(ni, TimesSet);
|
||||
std_info->creation_time = cpu_to_le64(times[0]);
|
||||
std_info->creation_time = cpu_to_sle64(times[0]);
|
||||
ni->creation_time
|
||||
= std_info->creation_time;
|
||||
if (size >= 16) {
|
||||
std_info->last_data_change_time = cpu_to_le64(times[1]);
|
||||
std_info->last_data_change_time = cpu_to_sle64(times[1]);
|
||||
ni->last_data_change_time
|
||||
= std_info->last_data_change_time;
|
||||
}
|
||||
if (size >= 24) {
|
||||
std_info->last_access_time = cpu_to_le64(times[2]);
|
||||
std_info->last_access_time = cpu_to_sle64(times[2]);
|
||||
ni->last_access_time
|
||||
= std_info->last_access_time;
|
||||
}
|
||||
@@ -1578,13 +1574,13 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
||||
fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
fn->creation_time
|
||||
= cpu_to_le64(times[0]);
|
||||
= cpu_to_sle64(times[0]);
|
||||
if (size >= 16)
|
||||
fn->last_data_change_time
|
||||
= cpu_to_le64(times[1]);
|
||||
= cpu_to_sle64(times[1]);
|
||||
if (size >= 24)
|
||||
fn->last_access_time
|
||||
= cpu_to_le64(times[2]);
|
||||
= cpu_to_sle64(times[2]);
|
||||
fn->last_mft_change_time = now;
|
||||
cnt++;
|
||||
}
|
||||
@@ -1604,5 +1600,3 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
||||
errno = EEXIST;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
@@ -197,7 +197,7 @@ extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item);
|
||||
|
||||
|
||||
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
||||
const MFT_REF mref);
|
||||
const leMFT_REF mref);
|
||||
|
||||
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
|
||||
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* ioctl.c - Processing of ioctls
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2014-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2014 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <syslog.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_FS_H
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "debug.h"
|
||||
#include "bitmap.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "index.h"
|
||||
#include "logging.h"
|
||||
#include "ntfstime.h"
|
||||
#include "unistr.h"
|
||||
#include "dir.h"
|
||||
#include "security.h"
|
||||
#include "ioctl.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if defined(FITRIM) && defined(BLKDISCARD)
|
||||
|
||||
/* Issue a TRIM request to the underlying device for the given clusters. */
|
||||
static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length)
|
||||
{
|
||||
struct ntfs_device *dev = vol->dev;
|
||||
uint64_t range[2];
|
||||
|
||||
ntfs_log_debug("fstrim_clusters: %lld length %lld\n",
|
||||
(long long) lcn, (long long) length);
|
||||
|
||||
range[0] = lcn << vol->cluster_size_bits;
|
||||
range[1] = length << vol->cluster_size_bits;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) {
|
||||
ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_line(const char *path, char *line, size_t max_bytes)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
if (fgets(line, max_bytes, fp) == NULL) {
|
||||
int ret = -EIO; /* fgets doesn't set errno */
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
fclose (fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_u64(const char *path, u64 *n)
|
||||
{
|
||||
char line[64];
|
||||
int ret;
|
||||
|
||||
ret = read_line(path, line, sizeof line);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (sscanf(line, "%" SCNu64, n) != 1)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find discard limits for current backing device.
|
||||
*/
|
||||
static int fstrim_limits(ntfs_volume *vol,
|
||||
u64 *discard_alignment,
|
||||
u64 *discard_granularity,
|
||||
u64 *discard_max_bytes)
|
||||
{
|
||||
struct stat statbuf;
|
||||
char path1[80], path2[80];
|
||||
int ret;
|
||||
|
||||
/* Stat the backing device. Caller has ensured it is a block device. */
|
||||
if (stat(vol->dev->d_name, &statbuf) == -1) {
|
||||
ntfs_log_debug("fstrim_limits: could not stat %s\n",
|
||||
vol->dev->d_name);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* For whole devices,
|
||||
* /sys/dev/block/MAJOR:MINOR/discard_alignment
|
||||
* /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
|
||||
* /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
|
||||
* will exist.
|
||||
* For partitions, we also need to check the parent device:
|
||||
* /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
|
||||
* /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
|
||||
*/
|
||||
snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
|
||||
major(statbuf.st_rdev), minor(statbuf.st_rdev));
|
||||
|
||||
snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
|
||||
ret = read_u64(path2, discard_alignment);
|
||||
if (ret) {
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
else
|
||||
/* We would expect this file to exist on all
|
||||
* modern kernels. But for the sake of very
|
||||
* old kernels:
|
||||
*/
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
|
||||
ret = read_u64(path2, discard_granularity);
|
||||
if (ret) {
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
else {
|
||||
snprintf(path2, sizeof path2,
|
||||
"%s/../queue/discard_granularity", path1);
|
||||
ret = read_u64(path2, discard_granularity);
|
||||
if (ret) {
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
else
|
||||
goto not_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
|
||||
ret = read_u64(path2, discard_max_bytes);
|
||||
if (ret) {
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
else {
|
||||
snprintf(path2, sizeof path2,
|
||||
"%s/../queue/discard_max_bytes", path1);
|
||||
ret = read_u64(path2, discard_max_bytes);
|
||||
if (ret) {
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
else
|
||||
goto not_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
not_found:
|
||||
/* If we reach here then we didn't find the device. This is
|
||||
* not an error, but set discard_max_bytes = 0 to indicate
|
||||
* that discard is not available.
|
||||
*/
|
||||
*discard_alignment = 0;
|
||||
*discard_granularity = 0;
|
||||
*discard_max_bytes = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FSTRIM_BUFSIZ 4096
|
||||
|
||||
/* Trim the filesystem.
|
||||
*
|
||||
* Free blocks between 'start' and 'start+len-1' (both byte offsets)
|
||||
* are found and TRIM requests are sent to the block device. 'minlen'
|
||||
* is the minimum continguous free range to discard.
|
||||
*/
|
||||
static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
|
||||
{
|
||||
struct fstrim_range *range = data;
|
||||
u64 start = range->start;
|
||||
u64 len = range->len;
|
||||
u64 minlen = range->minlen;
|
||||
u64 discard_alignment, discard_granularity, discard_max_bytes;
|
||||
u8 *buf = NULL;
|
||||
LCN start_buf;
|
||||
int ret;
|
||||
|
||||
ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n",
|
||||
(unsigned long long) start,
|
||||
(unsigned long long) len,
|
||||
(unsigned long long) minlen);
|
||||
|
||||
*trimmed = 0;
|
||||
|
||||
/* Fail if user tries to use the fstrim -o/-l/-m options.
|
||||
* XXX We could fix these limitations in future.
|
||||
*/
|
||||
if (start != 0 || len != (uint64_t)-1) {
|
||||
ntfs_log_debug("fstrim: setting start or length is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (minlen > vol->cluster_size) {
|
||||
ntfs_log_debug("fstrim: minlen > cluster size is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Only block devices are supported. It would be possible to
|
||||
* support backing files (ie. without using loop) but the
|
||||
* ioctls used to punch holes in files are completely
|
||||
* different.
|
||||
*/
|
||||
if (!NDevBlock(vol->dev)) {
|
||||
ntfs_log_debug("fstrim: not supported for non-block-device\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = fstrim_limits(vol, &discard_alignment,
|
||||
&discard_granularity, &discard_max_bytes);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (discard_alignment != 0) {
|
||||
ntfs_log_debug("fstrim: backing device is not aligned for discards\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (discard_granularity > vol->cluster_size) {
|
||||
ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (discard_max_bytes == 0) {
|
||||
ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Sync the device before doing anything. */
|
||||
ret = ntfs_device_sync(vol->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read through the bitmap. */
|
||||
buf = ntfs_malloc(FSTRIM_BUFSIZ);
|
||||
if (buf == NULL)
|
||||
return -errno;
|
||||
for (start_buf = 0; start_buf < vol->nr_clusters;
|
||||
start_buf += FSTRIM_BUFSIZ * 8) {
|
||||
s64 count;
|
||||
s64 br;
|
||||
LCN end_buf, start_lcn;
|
||||
|
||||
/* start_buf is LCN of first cluster in the current buffer.
|
||||
* end_buf is LCN of last cluster + 1 in the current buffer.
|
||||
*/
|
||||
end_buf = start_buf + FSTRIM_BUFSIZ*8;
|
||||
if (end_buf > vol->nr_clusters)
|
||||
end_buf = vol->nr_clusters;
|
||||
count = (end_buf - start_buf) / 8;
|
||||
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf);
|
||||
if (br != count) {
|
||||
if (br >= 0)
|
||||
ret = -EIO;
|
||||
else
|
||||
ret = -errno;
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
/* Trim the clusters in large as possible blocks, but
|
||||
* not larger than discard_max_bytes.
|
||||
*/
|
||||
for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
|
||||
if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
|
||||
LCN end_lcn;
|
||||
|
||||
/* Cluster 'start_lcn' is not in use,
|
||||
* find end of this run.
|
||||
*/
|
||||
end_lcn = start_lcn+1;
|
||||
while (end_lcn < end_buf &&
|
||||
(u64) (end_lcn-start_lcn) << vol->cluster_size_bits
|
||||
< discard_max_bytes &&
|
||||
!ntfs_bit_get(buf, end_lcn-start_buf))
|
||||
end_lcn++;
|
||||
|
||||
ret = fstrim_clusters(vol,
|
||||
start_lcn, end_lcn-start_lcn);
|
||||
if (ret)
|
||||
goto free_out;
|
||||
|
||||
*trimmed += (end_lcn - start_lcn)
|
||||
<< vol->cluster_size_bits;
|
||||
start_lcn = end_lcn-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
free_out:
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* FITRIM && BLKDISCARD */
|
||||
|
||||
int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg __attribute__((unused)),
|
||||
unsigned int flags __attribute__((unused)), void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
#if defined(FITRIM) && defined(BLKDISCARD)
|
||||
case FITRIM:
|
||||
if (!ni || !data)
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
u64 trimmed;
|
||||
struct fstrim_range *range = (struct fstrim_range*)data;
|
||||
|
||||
ret = fstrim(ni->vol, data, &trimmed);
|
||||
range->len = trimmed;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
#warning Trimming not supported : FITRIM or BLKDISCARD not defined
|
||||
#endif
|
||||
default :
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2014 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (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 IOCTL_H
|
||||
#define IOCTL_H
|
||||
|
||||
int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg,
|
||||
unsigned int flags, void *data);
|
||||
|
||||
#endif /* IOCTL_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -676,7 +676,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
|
||||
ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
|
||||
"vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
|
||||
na->type, (long long)count, (long long)start_vcn);
|
||||
le32_to_cpu(na->type), (long long)count, (long long)start_vcn);
|
||||
|
||||
rl = ntfs_attr_find_vcn(na, start_vcn);
|
||||
if (!rl) {
|
||||
|
||||
@@ -90,10 +90,10 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
* 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)))) {
|
||||
if (((rp->major_ver != const_cpu_to_sle16(1))
|
||||
|| (rp->minor_ver != const_cpu_to_sle16(1)))
|
||||
&& ((rp->major_ver != const_cpu_to_sle16(2))
|
||||
|| (rp->minor_ver != const_cpu_to_sle16(0)))) {
|
||||
ntfs_log_error("$LogFile version %i.%i is not "
|
||||
"supported.\n (This driver supports version "
|
||||
"1.1 and 2.0 only.)\n",
|
||||
@@ -119,7 +119,7 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
/* Verify the position of the update sequence array. */
|
||||
usa_ofs = le16_to_cpu(rp->usa_ofs);
|
||||
usa_end = usa_ofs + usa_count * sizeof(u16);
|
||||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
|
||||
if (usa_ofs < offsetof(RESTART_PAGE_HEADER, usn) ||
|
||||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array offset.\n");
|
||||
@@ -134,7 +134,7 @@ skip_usa_checks:
|
||||
*/
|
||||
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
|
||||
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
|
||||
ra_ofs < offsetof(RESTART_PAGE_HEADER, usn)) ||
|
||||
ra_ofs > logfile_system_page_size) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent restart area offset.\n");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2016 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
|
||||
@@ -93,7 +94,8 @@ typedef struct {
|
||||
version is 1. */
|
||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||
version 1.1. */
|
||||
/* sizeof() = 30 (0x1e) bytes */
|
||||
/* 30*/ le16 usn;
|
||||
/* sizeof() = 32 (0x20) bytes */
|
||||
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||
|
||||
/*
|
||||
@@ -101,8 +103,8 @@ typedef struct {
|
||||
* in this particular client array. Also inside the client records themselves,
|
||||
* this means that there are no client records preceding or following this one.
|
||||
*/
|
||||
#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff)
|
||||
#define LOGFILE_NO_CLIENT_CPU 0xffff
|
||||
#define LOGFILE_NO_CLIENT const_cpu_to_le16(LOGFILE_NO_CLIENT_CPU)
|
||||
|
||||
/*
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
@@ -308,35 +310,36 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
alignment). */
|
||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
union {
|
||||
LSN last_lsn;
|
||||
s64 file_offset;
|
||||
leLSN last_lsn;
|
||||
sle64 file_offset;
|
||||
} __attribute__((__packed__)) copy;
|
||||
u32 flags;
|
||||
u16 page_count;
|
||||
u16 page_position;
|
||||
union {
|
||||
struct {
|
||||
u16 next_record_offset;
|
||||
u8 reserved[6];
|
||||
LSN last_end_lsn;
|
||||
} __attribute__((__packed__)) packed;
|
||||
} __attribute__((__packed__)) header;
|
||||
le32 flags;
|
||||
le16 page_count;
|
||||
le16 page_position;
|
||||
le16 next_record_offset;
|
||||
le16 reserved[3];
|
||||
leLSN last_end_lsn;
|
||||
} __attribute__((__packed__)) RECORD_PAGE_HEADER;
|
||||
|
||||
/**
|
||||
* enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
|
||||
*
|
||||
* Some flags describe what kind of update is being logged.
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
typedef enum {
|
||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
|
||||
/* The flags below were introduced in Windows 10 */
|
||||
LOG_RECORD_DELETING = const_cpu_to_le16(0x0002),
|
||||
LOG_RECORD_ADDING = const_cpu_to_le16(0x0004),
|
||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||
/* This has nothing to do with the log record. It is only so
|
||||
gcc knows to make the flags 16-bit. */
|
||||
@@ -346,47 +349,120 @@ typedef enum {
|
||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||
*/
|
||||
typedef struct {
|
||||
u16 seq_number;
|
||||
u16 client_index;
|
||||
le16 seq_number;
|
||||
le16 client_index;
|
||||
} __attribute__((__packed__)) LOG_CLIENT_ID;
|
||||
|
||||
/*
|
||||
* LOG_RECORD_TYPE : types of log records
|
||||
*/
|
||||
|
||||
enum {
|
||||
LOG_STANDARD = const_cpu_to_le32(1),
|
||||
LOG_CHECKPOINT = const_cpu_to_le32(2),
|
||||
LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU
|
||||
} ;
|
||||
typedef le32 LOG_RECORD_TYPE;
|
||||
|
||||
/*
|
||||
* ATTRIBUTE_FLAGS : flags describing the kind of NTFS record
|
||||
* is being updated.
|
||||
* These flags were introduced in Vista, only two flags are known?
|
||||
*/
|
||||
|
||||
enum {
|
||||
ACTS_ON_MFT = const_cpu_to_le16(2),
|
||||
ACTS_ON_INDX = const_cpu_to_le16(8),
|
||||
ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff,
|
||||
} ;
|
||||
typedef le16 ATTRIBUTE_FLAGS;
|
||||
|
||||
#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */
|
||||
|
||||
/**
|
||||
* struct LOG_RECORD - Log record header.
|
||||
*
|
||||
* Each log record seems to have a constant size of 0x70 bytes.
|
||||
*/
|
||||
typedef struct {
|
||||
LSN this_lsn;
|
||||
LSN client_previous_lsn;
|
||||
LSN client_undo_next_lsn;
|
||||
u32 client_data_length;
|
||||
leLSN this_lsn;
|
||||
leLSN client_previous_lsn;
|
||||
leLSN client_undo_next_lsn;
|
||||
le32 client_data_length;
|
||||
LOG_CLIENT_ID client_id;
|
||||
u32 record_type;
|
||||
u32 transaction_id;
|
||||
u16 flags;
|
||||
u16 reserved_or_alignment[3];
|
||||
LOG_RECORD_TYPE record_type;
|
||||
le32 transaction_id;
|
||||
LOG_RECORD_FLAGS log_record_flags;
|
||||
le16 reserved_or_alignment[3];
|
||||
/* Now are at ofs 0x30 into struct. */
|
||||
u16 redo_operation;
|
||||
u16 undo_operation;
|
||||
u16 redo_offset;
|
||||
u16 redo_length;
|
||||
u16 undo_offset;
|
||||
u16 undo_length;
|
||||
u16 target_attribute;
|
||||
u16 lcns_to_follow; /* Number of lcn_list entries
|
||||
le16 redo_operation;
|
||||
le16 undo_operation;
|
||||
le16 redo_offset;
|
||||
le16 redo_length;
|
||||
union {
|
||||
struct {
|
||||
le16 undo_offset;
|
||||
le16 undo_length;
|
||||
le16 target_attribute;
|
||||
le16 lcns_to_follow; /* Number of lcn_list entries
|
||||
following this entry. */
|
||||
/* Now at ofs 0x40. */
|
||||
u16 record_offset;
|
||||
u16 attribute_offset;
|
||||
u32 alignment_or_reserved;
|
||||
VCN target_vcn;
|
||||
le16 record_offset;
|
||||
le16 attribute_offset;
|
||||
le16 cluster_index;
|
||||
ATTRIBUTE_FLAGS attribute_flags;
|
||||
leVCN target_vcn;
|
||||
/* Now at ofs 0x50. */
|
||||
struct { /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
LCN lcn;
|
||||
} __attribute__((__packed__)) lcn_list[0];
|
||||
leLCN lcn_list[0]; /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
} __attribute__((__packed__));
|
||||
struct {
|
||||
leLSN transaction_lsn;
|
||||
leLSN attributes_lsn;
|
||||
leLSN names_lsn;
|
||||
leLSN dirty_pages_lsn;
|
||||
le64 unknown_list[0];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__)) LOG_RECORD;
|
||||
|
||||
/**
|
||||
* struct BITMAP_ACTION - Bitmap change being logged
|
||||
*/
|
||||
|
||||
struct BITMAP_ACTION {
|
||||
le32 firstbit;
|
||||
le32 count;
|
||||
} ;
|
||||
|
||||
/**
|
||||
* struct ATTR - Attribute record.
|
||||
*
|
||||
* The format of an attribute record has changed from Windows 10.
|
||||
* The old format was 44 bytes long, despite having 8 bytes fields,
|
||||
* and this leads to alignment problems in arrays.
|
||||
* This problem does not occur in the new format, which is shorter.
|
||||
* The format being used can generally be determined from size.
|
||||
*/
|
||||
typedef struct { /* Format up to Win10 (44 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
le32 unknown3;
|
||||
le32 type;
|
||||
le32 unknown4;
|
||||
} __attribute__((__packed__)) ATTR_OLD;
|
||||
|
||||
typedef struct { /* Format since Win10 (40 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le32 type;
|
||||
le32 unknown3;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
} __attribute__((__packed__)) ATTR_NEW;
|
||||
|
||||
extern BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp);
|
||||
extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp);
|
||||
extern int ntfs_empty_logfile(ntfs_attr *na);
|
||||
|
||||
@@ -226,6 +226,7 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_log_get_prefix - Default prefixes for logging levels
|
||||
@@ -297,7 +298,6 @@ void ntfs_log_set_handler(ntfs_log_handler *handler)
|
||||
} else
|
||||
ntfs_log.handler = ntfs_log_handler_null;
|
||||
}
|
||||
#endif //__HAIKU___
|
||||
|
||||
/**
|
||||
* ntfs_log_redirect - Pass on the request to the real handler
|
||||
@@ -359,9 +359,9 @@ int ntfs_log_redirect(const char *function, const char *file,
|
||||
#define LOG_LINE_LEN 512
|
||||
|
||||
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level,
|
||||
void *data __attribute__((unused)),
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level,
|
||||
void *data __attribute__((unused)),
|
||||
const char *format, va_list args)
|
||||
{
|
||||
char logbuf[LOG_LINE_LEN];
|
||||
@@ -370,20 +370,20 @@ int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
#ifndef DEBUG
|
||||
if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC)
|
||||
return 1;
|
||||
#endif
|
||||
#endif
|
||||
ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
|
||||
if (ret < 0) {
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(logbuf);
|
||||
}
|
||||
|
||||
|
||||
syslog(LOG_NOTICE, "%s", logbuf);
|
||||
out:
|
||||
errno = olderr;
|
||||
@@ -400,8 +400,10 @@ out:
|
||||
|
||||
void ntfs_log_early_error(const char *format, ...)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
va_list args;
|
||||
#ifdef __HAIKU__
|
||||
char buffer[1024];
|
||||
#endif
|
||||
|
||||
va_start(args, format);
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
@@ -409,11 +411,13 @@ void ntfs_log_early_error(const char *format, ...)
|
||||
ntfs_log_handler_syslog(NULL, NULL, 0,
|
||||
NTFS_LOG_LEVEL_ERROR, NULL,
|
||||
format, args);
|
||||
#elif defined(__HAIKU__)
|
||||
vsnprintf(buffer, sizeof(buffer) - 1, format, args);
|
||||
dprintf("%s", buffer);
|
||||
#else
|
||||
vfprintf(stderr,format,args);
|
||||
#endif
|
||||
va_end(args);
|
||||
#endif //__HAIKU__
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +441,6 @@ 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)
|
||||
{
|
||||
@@ -446,11 +449,17 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
#endif
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
|
||||
#ifndef __HAIKU__
|
||||
FILE *stream;
|
||||
|
||||
if (!data) /* Interpret data as a FILE stream. */
|
||||
return 0; /* If it's NULL, we can't do anything. */
|
||||
stream = (FILE*)data;
|
||||
#else
|
||||
#define fprintf(stream, ...) dprintf(__VA_ARGS__)
|
||||
char buffer[1024];
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_LEAVE) {
|
||||
@@ -458,10 +467,10 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
tab--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < tab; i++)
|
||||
ret += fprintf(stream, " ");
|
||||
#endif
|
||||
#endif
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
@@ -479,7 +488,12 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
(level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
#ifndef __HAIKU__
|
||||
ret += vfprintf(stream, format, args);
|
||||
#else
|
||||
ret += vsnprintf(buffer, sizeof(buffer - 1), format, args);
|
||||
dprintf("%s", buffer);
|
||||
#endif
|
||||
|
||||
if (level & NTFS_LOG_LEVEL_PERROR)
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
@@ -487,12 +501,15 @@ int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
#ifdef DEBUG
|
||||
if (level == NTFS_LOG_LEVEL_ENTER)
|
||||
tab++;
|
||||
#endif
|
||||
#endif
|
||||
#ifndef __HAIKU__
|
||||
fflush(stream);
|
||||
#else
|
||||
#undef fprintf
|
||||
#endif
|
||||
errno = olderr;
|
||||
return ret;
|
||||
}
|
||||
#endif // __HAIKU__
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_null - Null logging handler (no output)
|
||||
@@ -537,12 +554,13 @@ 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)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
if (!data)
|
||||
data = stdout;
|
||||
#endif
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
@@ -572,8 +590,10 @@ int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
if (!data)
|
||||
data = ntfs_log_get_stream(level);
|
||||
#endif
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
@@ -602,12 +622,14 @@ int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||
int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
#ifndef __HAIKU__
|
||||
if (!data)
|
||||
data = stderr;
|
||||
#endif
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
#endif //__HAIKU__
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_parse_option - Act upon command line options
|
||||
|
||||
@@ -38,10 +38,11 @@ typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, va_list args);
|
||||
|
||||
/* 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))));
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler
|
||||
#if __GNUC__ > 3
|
||||
__attribute__((format(printf, 6, 0)))
|
||||
#endif
|
||||
);
|
||||
|
||||
/* Logging handlers */
|
||||
ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0)));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2004-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2014-2015 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
|
||||
@@ -354,7 +355,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
* Set the NTFS 3.1+ specific fields while we know that the
|
||||
* volume version is 3.1+.
|
||||
*/
|
||||
mrec->reserved = cpu_to_le16(0);
|
||||
mrec->reserved = const_cpu_to_le16(0);
|
||||
mrec->mft_record_number = cpu_to_le32(MREF(mref));
|
||||
}
|
||||
mrec->magic = magic_FILE;
|
||||
@@ -362,7 +363,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
mrec->usa_count = cpu_to_le16(vol->mft_record_size /
|
||||
NTFS_BLOCK_SIZE + 1);
|
||||
else {
|
||||
mrec->usa_count = cpu_to_le16(1);
|
||||
mrec->usa_count = const_cpu_to_le16(1);
|
||||
ntfs_log_error("Sector size is bigger than MFT record size. "
|
||||
"Setting usa_count to 1. If Windows chkdsk "
|
||||
"reports this as corruption, please email %s "
|
||||
@@ -371,14 +372,14 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
"Thank you.\n", NTFS_DEV_LIST);
|
||||
}
|
||||
/* Set the update sequence number to 1. */
|
||||
*(u16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1);
|
||||
mrec->lsn = cpu_to_le64(0ull);
|
||||
mrec->sequence_number = cpu_to_le16(1);
|
||||
mrec->link_count = cpu_to_le16(0);
|
||||
*(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = const_cpu_to_le16(1);
|
||||
mrec->lsn = const_cpu_to_sle64(0ll);
|
||||
mrec->sequence_number = const_cpu_to_le16(1);
|
||||
mrec->link_count = const_cpu_to_le16(0);
|
||||
/* Aligned to 8-byte boundary. */
|
||||
mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) +
|
||||
(le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7);
|
||||
mrec->flags = cpu_to_le16(0);
|
||||
mrec->flags = const_cpu_to_le16(0);
|
||||
/*
|
||||
* Using attrs_offset plus eight bytes (for the termination attribute),
|
||||
* aligned to 8-byte boundary.
|
||||
@@ -386,11 +387,11 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 +
|
||||
7) & ~7);
|
||||
mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size);
|
||||
mrec->base_mft_record = cpu_to_le64((MFT_REF)0);
|
||||
mrec->next_attr_instance = cpu_to_le16(0);
|
||||
mrec->base_mft_record = const_cpu_to_le64((MFT_REF)0);
|
||||
mrec->next_attr_instance = const_cpu_to_le16(0);
|
||||
a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
|
||||
a->type = AT_END;
|
||||
a->length = cpu_to_le32(0);
|
||||
a->length = const_cpu_to_le32(0);
|
||||
/* Finally, clear the unused part of the mft record. */
|
||||
memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec));
|
||||
return 0;
|
||||
@@ -553,7 +554,7 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
"data_pos 0x%llx, bit 0x%llx, "
|
||||
"*byte 0x%hhx, b %u.\n", size,
|
||||
(long long)data_pos, (long long)bit,
|
||||
byte ? *byte : -1, b);
|
||||
(u8) (byte ? *byte : -1), b);
|
||||
for (; bit < size && data_pos + bit < pass_end;
|
||||
bit &= ~7ull, bit += 8) {
|
||||
/*
|
||||
@@ -580,7 +581,7 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
"data_pos 0x%llx, bit 0x%llx, "
|
||||
"*byte 0x%hhx, b %u.\n", size,
|
||||
(long long)data_pos, (long long)bit,
|
||||
byte ? *byte : -1, b);
|
||||
(u8) (byte ? *byte : -1), b);
|
||||
data_pos += size;
|
||||
/*
|
||||
* If the end of the pass has not been reached yet,
|
||||
@@ -1354,7 +1355,7 @@ undo_data_init:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
|
||||
ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data)
|
||||
{
|
||||
s64 ll, bit;
|
||||
ntfs_attr *mft_na, *mftbmp_na;
|
||||
@@ -1363,6 +1364,7 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
|
||||
ntfs_inode *base_ni;
|
||||
int err;
|
||||
le16 seq_no, usn;
|
||||
BOOL forced_mft_data;
|
||||
|
||||
ntfs_log_enter("Entering\n");
|
||||
|
||||
@@ -1371,7 +1373,38 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
|
||||
|
||||
base_ni = mft_na->ni;
|
||||
|
||||
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
|
||||
/*
|
||||
* The first extent containing $MFT:$AT_DATA is better located
|
||||
* in record 15 to make sure it can be read at mount time.
|
||||
* The record 15 is prereserved as a base inode with no
|
||||
* extents and no name, and it is marked in use.
|
||||
*/
|
||||
forced_mft_data = FALSE;
|
||||
if (mft_data) {
|
||||
ntfs_inode *ext_ni = ntfs_inode_open(vol, FILE_mft_data);
|
||||
/*
|
||||
* If record 15 cannot be opened, it is probably in
|
||||
* use as an extent. Apply standard procedure for
|
||||
* further extents.
|
||||
*/
|
||||
if (ext_ni) {
|
||||
/*
|
||||
* Make sure record 15 is a base extent and has
|
||||
* no extents.
|
||||
* Also make sure it has no name : a base inode with
|
||||
* no extents and no name cannot be in use.
|
||||
* Otherwise apply standard procedure.
|
||||
*/
|
||||
if (!ext_ni->mrec->base_mft_record
|
||||
&& !ext_ni->nr_extents)
|
||||
forced_mft_data = TRUE;
|
||||
ntfs_inode_close(ext_ni);
|
||||
}
|
||||
}
|
||||
if (forced_mft_data)
|
||||
bit = FILE_mft_data;
|
||||
else
|
||||
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
|
||||
if (bit >= 0)
|
||||
goto found_free_rec;
|
||||
|
||||
@@ -1408,7 +1441,9 @@ found_free_rec:
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
/* Sanity check that the mft record is really not in use. */
|
||||
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
|
||||
if (!forced_mft_data
|
||||
&& (ntfs_is_file_record(m->magic)
|
||||
&& (m->flags & MFT_RECORD_IN_USE))) {
|
||||
ntfs_log_error("Inode %lld is used but it wasn't marked in "
|
||||
"$MFT bitmap. Fixed.\n", (long long)bit);
|
||||
free(m);
|
||||
@@ -1475,7 +1510,7 @@ found_free_rec:
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
/* Initialize time, allocated and data size in ntfs_inode struct. */
|
||||
ni->data_size = ni->allocated_size = 0;
|
||||
ni->flags = 0;
|
||||
ni->flags = const_cpu_to_le32(0);
|
||||
ni->creation_time = ni->last_data_change_time =
|
||||
ni->last_mft_change_time =
|
||||
ni->last_access_time = ntfs_current_time();
|
||||
@@ -1524,8 +1559,9 @@ err_out:
|
||||
* @base_ni is NULL we start where we last stopped and we perform wrap around
|
||||
* when we reach the end. Note, we do not try to allocate mft records below
|
||||
* number 24 because numbers 0 to 15 are the defined system files anyway and 16
|
||||
* to 24 are special in that they are used for storing extension mft records
|
||||
* for the $DATA attribute of $MFT. This is required to avoid the possibility
|
||||
* to 24 are used for storing extension mft records or used by chkdsk to store
|
||||
* its log. However the record number 15 is dedicated to the first extent to
|
||||
* the $DATA attribute of $MFT. This is required to avoid the possibility
|
||||
* of creating a run list with a circular dependence which once written to disk
|
||||
* can never be read in again. Windows will only use records 16 to 24 for
|
||||
* normal files if the volume is completely out of space. We never use them
|
||||
@@ -1591,7 +1627,9 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
MFT_RECORD *m;
|
||||
ntfs_inode *ni = NULL;
|
||||
int err;
|
||||
u32 usa_ofs;
|
||||
le16 seq_no, usn;
|
||||
BOOL oldwarn;
|
||||
|
||||
if (base_ni)
|
||||
ntfs_log_enter("Entering (allocating an extent mft record for "
|
||||
@@ -1605,7 +1643,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
}
|
||||
|
||||
if (ntfs_is_mft(base_ni)) {
|
||||
ni = ntfs_mft_rec_alloc(vol);
|
||||
ni = ntfs_mft_rec_alloc(vol, FALSE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1705,10 +1743,22 @@ found_free_rec:
|
||||
if (!m)
|
||||
goto undo_mftbmp_alloc;
|
||||
|
||||
/*
|
||||
* As this is allocating a new record, do not expect it to have
|
||||
* been initialized previously, so do not warn over bad fixups
|
||||
* (hence avoid warn flooding when an NTFS partition has been wiped).
|
||||
*/
|
||||
oldwarn = !NVolNoFixupWarn(vol);
|
||||
NVolSetNoFixupWarn(vol);
|
||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
||||
if (oldwarn)
|
||||
NVolClearNoFixupWarn(vol);
|
||||
free(m);
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
if (oldwarn)
|
||||
NVolClearNoFixupWarn(vol);
|
||||
|
||||
/* Sanity check that the mft record is really not in use. */
|
||||
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
|
||||
ntfs_log_error("Inode %lld is used but it wasn't marked in "
|
||||
@@ -1717,7 +1767,16 @@ found_free_rec:
|
||||
goto retry;
|
||||
}
|
||||
seq_no = m->sequence_number;
|
||||
usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
|
||||
/*
|
||||
* As ntfs_mft_record_read() returns what has been read
|
||||
* even when the fixups have been found bad, we have to
|
||||
* check where we fetch the initial usn from.
|
||||
*/
|
||||
usa_ofs = le16_to_cpu(m->usa_ofs);
|
||||
if (!(usa_ofs & 1) && (usa_ofs < NTFS_BLOCK_SIZE)) {
|
||||
usn = *(le16*)((u8*)m + usa_ofs);
|
||||
} else
|
||||
usn = const_cpu_to_le16(1);
|
||||
if (ntfs_mft_record_layout(vol, bit, m)) {
|
||||
ntfs_log_error("Failed to re-format mft record.\n");
|
||||
free(m);
|
||||
@@ -1777,7 +1836,7 @@ found_free_rec:
|
||||
ntfs_inode_mark_dirty(ni);
|
||||
/* Initialize time, allocated and data size in ntfs_inode struct. */
|
||||
ni->data_size = ni->allocated_size = 0;
|
||||
ni->flags = 0;
|
||||
ni->flags = const_cpu_to_le32(0);
|
||||
ni->creation_time = ni->last_data_change_time =
|
||||
ni->last_mft_change_time =
|
||||
ni->last_access_time = ntfs_current_time();
|
||||
|
||||
@@ -124,6 +124,8 @@ extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
|
||||
|
||||
extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni);
|
||||
|
||||
extern ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data);
|
||||
|
||||
extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);
|
||||
|
||||
@@ -31,6 +31,21 @@
|
||||
#include "mst.h"
|
||||
#include "logging.h"
|
||||
|
||||
/*
|
||||
* Basic validation of a NTFS multi-sector record. The record size must be a
|
||||
* multiple of the logical sector size; and the update sequence array must be
|
||||
* properly aligned, of the expected length, and must end before the last le16
|
||||
* in the first logical sector.
|
||||
*/
|
||||
static BOOL
|
||||
is_valid_record(u32 size, u16 usa_ofs, u16 usa_count)
|
||||
{
|
||||
return size % NTFS_BLOCK_SIZE == 0 &&
|
||||
usa_ofs % 2 == 0 &&
|
||||
usa_count == 1 + (size / NTFS_BLOCK_SIZE) &&
|
||||
usa_ofs + ((u32)usa_count * 2) <= NTFS_BLOCK_SIZE - 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
@@ -57,12 +72,9 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
||||
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||
errno = EINVAL;
|
||||
if (warn) {
|
||||
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
|
||||
@@ -91,7 +103,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
||||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
if (*data_pos != usn) {
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
@@ -101,7 +113,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Incomplete multi-sector transfer: "
|
||||
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
|
||||
" %d data: %d usn: %d", *(le32 *)b, size,
|
||||
" %d data: %d usn: %d", le32_to_cpu(*(le32 *)b), size,
|
||||
usa_ofs, usa_count, *data_pos, usn);
|
||||
b->magic = magic_BAAD;
|
||||
return -1;
|
||||
@@ -109,10 +121,10 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
/* Re-setup the variables. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
@@ -157,7 +169,8 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
|
||||
int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
le16 le_usn;
|
||||
le16 *usa_pos, *data_pos;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
@@ -170,18 +183,15 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
}
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)((u8*)b + usa_ofs);
|
||||
usa_pos = (le16*)((u8*)b + usa_ofs);
|
||||
/*
|
||||
* Cyclically increment the update sequence number
|
||||
* (skipping 0 and -1, i.e. 0xffff).
|
||||
@@ -189,21 +199,21 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
usn = le16_to_cpup(usa_pos) + 1;
|
||||
if (usn == 0xffff || !usn)
|
||||
usn = 1;
|
||||
usn = cpu_to_le16(usn);
|
||||
*usa_pos = usn;
|
||||
/* Position in data of first u16 that needs fixing up. */
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
le_usn = cpu_to_le16(usn);
|
||||
*usa_pos = le_usn;
|
||||
/* Position in data of first le16 that needs fixing up. */
|
||||
data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment the position in the usa and save the
|
||||
* original data from the data buffer into the usa.
|
||||
*/
|
||||
*(++usa_pos) = *data_pos;
|
||||
/* Apply fixup to data. */
|
||||
*data_pos = usn;
|
||||
*data_pos = le_usn;
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(le16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -222,7 +232,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
u16 usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
@@ -233,7 +243,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
|
||||
@@ -102,7 +102,7 @@ static __inline__ ntfs_time timespec2ntfs(struct timespec spec)
|
||||
|
||||
units = (s64)spec.tv_sec * 10000000
|
||||
+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
|
||||
return (cpu_to_le64(units));
|
||||
return (cpu_to_sle64(units));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -37,11 +37,6 @@
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
@@ -59,6 +54,7 @@
|
||||
#include "object_id.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* Endianness considerations
|
||||
@@ -130,7 +126,6 @@ struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */
|
||||
|
||||
static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('O') };
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Set the index for a new object id
|
||||
@@ -176,8 +171,6 @@ static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
|
||||
return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Open the $Extend/$ObjId file and its index
|
||||
*
|
||||
@@ -213,7 +206,6 @@ static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
|
||||
return (xo);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Merge object_id data stored in the index into
|
||||
@@ -263,7 +255,6 @@ static int merge_index_data(ntfs_inode *ni,
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Remove an object id index entry if attribute present
|
||||
@@ -311,7 +302,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Update the object id and index
|
||||
@@ -417,7 +407,6 @@ static int add_object_id(ntfs_inode *ni, int flags)
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Delete an object_id index entry
|
||||
@@ -456,7 +445,6 @@ int ntfs_delete_object_id_index(ntfs_inode *ni)
|
||||
return (res);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs object id into an extended attribute
|
||||
@@ -636,5 +624,3 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
||||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
@@ -76,6 +76,14 @@ enum {
|
||||
/* only update the final extent of a runlist when appending data */
|
||||
#define PARTIAL_RUNLIST_UPDATING 1
|
||||
|
||||
/*
|
||||
* Parameters for upper-case table
|
||||
*/
|
||||
|
||||
/* Create upper-case tables as defined by Windows 6.1 (Win7) */
|
||||
#define UPCASE_MAJOR 6
|
||||
#define UPCASE_MINOR 1
|
||||
|
||||
/*
|
||||
* Parameters for user and xattr mappings
|
||||
*/
|
||||
@@ -99,31 +107,45 @@ enum {
|
||||
* performances, but bad on security with internal fuse or external
|
||||
* fuse older than 2.8
|
||||
*
|
||||
* On Linux, cacheing is discouraged for the high level interface
|
||||
* in order to get proper support of hard links. As a consequence,
|
||||
* having access control in the file system leads to fewer requests
|
||||
* to the file system and fewer context switches.
|
||||
*
|
||||
* Possible values for high level :
|
||||
* 1 : no cache, kernel control (recommended)
|
||||
* 4 : no cache, file system control
|
||||
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
|
||||
* 7 : no cache, kernel control for ACLs
|
||||
*
|
||||
* Possible values for low level :
|
||||
* 2 : no cache, kernel control
|
||||
* 3 : use kernel/fuse cache, kernel control (external fuse >= 2.8)
|
||||
* 5 : no cache, file system control (recommended)
|
||||
* 3 : use kernel/fuse cache, kernel control (recommended)
|
||||
* 5 : no cache, file system control
|
||||
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
|
||||
* 8 : no cache, kernel control for ACLs
|
||||
* 9 : kernel/fuse cache, kernel control for ACLs (target)
|
||||
*
|
||||
* Use of options 7 and 8 requires a patch to fuse
|
||||
* Use of options 7, 8 and 9 requires a fuse module upgrade
|
||||
* When Posix ACLs are selected in the configure options, a value
|
||||
* 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
|
||||
/*
|
||||
* Access control by kernel is not implemented on OpenIndiana,
|
||||
* however care is taken of cacheing hard-linked files.
|
||||
*/
|
||||
#define HPERMSCONFIG 6
|
||||
#define LPERMSCONFIG 6
|
||||
#else /* defined(__sun) && defined(__SVR4) */
|
||||
/*
|
||||
* Cacheing by kernel is buggy on Linux when access control is done
|
||||
* by the file system, and also when using hard-linked files on
|
||||
* the fuse high level interface.
|
||||
*/
|
||||
#define HPERMSCONFIG 1
|
||||
#endif
|
||||
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
|
||||
#define LPERMSCONFIG 5
|
||||
#else
|
||||
#define LPERMSCONFIG 3
|
||||
#endif
|
||||
#define LPERMSCONFIG 3 /* Use 9 when ACLs are supported by fuse kernel */
|
||||
#endif /* defined(__sun) && defined(__SVR4) */
|
||||
|
||||
#endif /* defined _NTFS_PARAM_H */
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* plugin.h : define interface for plugin development
|
||||
*
|
||||
* Copyright (c) 2015 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the interface to ntfs-3g plugins which
|
||||
* add support for processing some type of reparse points.
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_PLUGIN_H
|
||||
#define _NTFS_PLUGIN_H
|
||||
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
|
||||
struct fuse_file_info;
|
||||
struct stat;
|
||||
|
||||
/*
|
||||
* The plugin operations currently defined.
|
||||
* These functions should return a non-negative value when they
|
||||
* succeed, or a negative errno value when they fail.
|
||||
* They must not close or free their arguments.
|
||||
* The file system must be left in a consistent state after
|
||||
* each individual call.
|
||||
* If an operation is not defined, an EOPNOTSUPP error is
|
||||
* returned to caller.
|
||||
*/
|
||||
typedef struct plugin_operations {
|
||||
/*
|
||||
* Set the attributes st_size, st_blocks and st_mode
|
||||
* into a struct stat. The returned st_mode must at least
|
||||
* define the file type. Depending on the permissions options
|
||||
* used for mounting, the umask will be applied to the returned
|
||||
* permissions, or the permissions will be changed according
|
||||
* to the ACL set on the file.
|
||||
*/
|
||||
int (*getattr)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct stat *stbuf);
|
||||
|
||||
/*
|
||||
* Open a file for reading or writing
|
||||
* The field fi->flags indicates the kind of opening.
|
||||
* The field fi->fh may be used to store some information which
|
||||
* will be available to subsequent reads and writes. When used
|
||||
* this field must be non-null.
|
||||
* The returned value is zero for success and a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*open)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Release an open file
|
||||
* This is only called if fi->fh has been set to a non-null
|
||||
* value while opening. It may be used to free some context
|
||||
* specific to the open file.
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*release)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Read from an open file
|
||||
* The returned value is the count of bytes which were read
|
||||
* or a negative errno value for failure.
|
||||
* If the returned value is positive, the access time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*read)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Write to an open file
|
||||
* The file system must be left consistent after each write call,
|
||||
* the file itself must be at least deletable if the application
|
||||
* writing to it is killed for some reason.
|
||||
* The returned value is the count of bytes which were written
|
||||
* or a negative errno value for failure.
|
||||
* If the returned value is positive, the modified time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*write)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
const char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Get a symbolic link
|
||||
* The symbolic link must be returned in an allocated buffer,
|
||||
* encoded in a zero terminated multibyte string compatible
|
||||
* which the locale mount option.
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*readlink)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
char **pbuf);
|
||||
|
||||
/*
|
||||
* Truncate a file (shorten or append zeroes)
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
* If the returned value is zero, the modified time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*truncate)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
off_t size);
|
||||
} plugin_operations_t;
|
||||
|
||||
|
||||
/*
|
||||
* Plugin initialization routine
|
||||
* Returns the entry table if successful, otherwise returns NULL
|
||||
* and sets errno (e.g. to EINVAL if the tag is not supported by
|
||||
* the plugin.)
|
||||
*/
|
||||
typedef const struct plugin_operations *(*plugin_init_t)(le32 tag);
|
||||
const struct plugin_operations *init(le32 tag);
|
||||
|
||||
#endif /* _NTFS_PLUGIN_H */
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2008-2013 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2016 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
|
||||
@@ -37,11 +37,6 @@
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
@@ -60,6 +55,7 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "reparse.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
|
||||
le16 subst_name_offset;
|
||||
@@ -195,7 +191,7 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
||||
uname[i] = found->file_name[i];
|
||||
} else {
|
||||
for (i=0; i<found->file_name_length; i++)
|
||||
uname[i] = vol->locase[found->file_name[i]];
|
||||
uname[i] = vol->locase[le16_to_cpu(found->file_name[i])];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,8 +397,8 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
|
||||
strcpy(defines,mappingdir);
|
||||
if ((*drive >= 'a') && (*drive <= 'z'))
|
||||
*drive += 'A' - 'a';
|
||||
strlcat(defines, drive, sizeof(defines));
|
||||
strlcat(defines, ":", sizeof(defines));
|
||||
strcat(defines,drive);
|
||||
strcat(defines,":");
|
||||
olderrno = errno;
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, defines);
|
||||
if (ni && !ntfs_inode_close(ni))
|
||||
@@ -422,8 +418,10 @@ static int ntfs_drive_letter(ntfs_volume *vol, ntfschar letter)
|
||||
/*
|
||||
* Do some sanity checks on reparse data
|
||||
*
|
||||
* The only general check is about the size (at least the tag must
|
||||
* be present)
|
||||
* Microsoft reparse points have an 8-byte header whereas
|
||||
* non-Microsoft reparse points have a 24-byte header. In each case,
|
||||
* 'reparse_data_length' must equal the number of non-header bytes.
|
||||
*
|
||||
* If the reparse data looks like a junction point or symbolic
|
||||
* link, more checks can be done.
|
||||
*
|
||||
@@ -440,11 +438,19 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
||||
|
||||
ok = ni && reparse_attr
|
||||
&& (size >= sizeof(REPARSE_POINT))
|
||||
&& (reparse_attr->reparse_tag != IO_REPARSE_TAG_RESERVED_ZERO)
|
||||
&& (((size_t)le16_to_cpu(reparse_attr->reparse_data_length)
|
||||
+ sizeof(REPARSE_POINT)) == size);
|
||||
+ sizeof(REPARSE_POINT)
|
||||
+ ((reparse_attr->reparse_tag &
|
||||
IO_REPARSE_TAG_IS_MICROSOFT) ? 0 : sizeof(GUID))) == size);
|
||||
if (ok) {
|
||||
switch (reparse_attr->reparse_tag) {
|
||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||
if (size < sizeof(REPARSE_POINT) +
|
||||
sizeof(struct MOUNT_POINT_REPARSE_DATA)) {
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
mount_point_data = (const struct MOUNT_POINT_REPARSE_DATA*)
|
||||
reparse_attr->reparse_data;
|
||||
offs = le16_to_cpu(mount_point_data->subst_name_offset);
|
||||
@@ -457,6 +463,11 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
||||
ok = FALSE;
|
||||
break;
|
||||
case IO_REPARSE_TAG_SYMLINK :
|
||||
if (size < sizeof(REPARSE_POINT) +
|
||||
sizeof(struct SYMLINK_REPARSE_DATA)) {
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
symlink_data = (const struct SYMLINK_REPARSE_DATA*)
|
||||
reparse_attr->reparse_data;
|
||||
offs = le16_to_cpu(symlink_data->subst_name_offset);
|
||||
@@ -713,8 +724,7 @@ static char *ntfs_get_rellink(ntfs_inode *ni, ntfschar *junction, int count)
|
||||
* symbolic link or directory junction
|
||||
*/
|
||||
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size)
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point)
|
||||
{
|
||||
s64 attr_size = 0;
|
||||
char *target;
|
||||
@@ -809,7 +819,6 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
}
|
||||
free(reparse_attr);
|
||||
}
|
||||
*pattr_size = attr_size;
|
||||
if (bad)
|
||||
errno = EOPNOTSUPP;
|
||||
return (target);
|
||||
@@ -844,7 +853,6 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
|
||||
return (possible);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Set the index for new reparse data
|
||||
@@ -883,7 +891,6 @@ static int set_reparse_index(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
return (ntfs_ie_add(xr,(INDEX_ENTRY*)&indx));
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Remove a reparse data index entry if attribute present
|
||||
@@ -960,7 +967,6 @@ static ntfs_index_context *open_reparse_index(ntfs_volume *vol)
|
||||
return (xr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Update the reparse data and index
|
||||
@@ -1026,7 +1032,6 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Delete a reparse index entry
|
||||
@@ -1065,7 +1070,6 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
|
||||
return (res);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs reparse data into an extended attribute
|
||||
@@ -1117,7 +1121,11 @@ int ntfs_set_ntfs_reparse_data(ntfs_inode *ni,
|
||||
ntfs_index_context *xr;
|
||||
|
||||
res = 0;
|
||||
if (ni && valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) {
|
||||
/* reparse data is not compatible with EA */
|
||||
if (ni
|
||||
&& !ntfs_attr_exist(ni, AT_EA_INFORMATION, AT_UNNAMED, 0)
|
||||
&& !ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)
|
||||
&& valid_reparse_data(ni, (const REPARSE_POINT*)value, size)) {
|
||||
xr = open_reparse_index(ni->vol);
|
||||
if (xr) {
|
||||
if (!ntfs_attr_exist(ni,AT_REPARSE_POINT,
|
||||
@@ -1246,4 +1254,31 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Get the reparse data into a buffer
|
||||
*
|
||||
* Returns the buffer if the reparse data exists and is valid
|
||||
* NULL otherwise (with errno set according to the cause).
|
||||
* When a buffer is returned, it has to be freed by caller.
|
||||
*/
|
||||
|
||||
REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni)
|
||||
{
|
||||
s64 attr_size = 0;
|
||||
REPARSE_POINT *reparse_attr;
|
||||
|
||||
reparse_attr = (REPARSE_POINT*)NULL;
|
||||
if (ni) {
|
||||
reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni,
|
||||
AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size);
|
||||
if (reparse_attr
|
||||
&& !valid_reparse_data(ni, reparse_attr, attr_size)) {
|
||||
free(reparse_attr);
|
||||
reparse_attr = (REPARSE_POINT*)NULL;
|
||||
errno = ENOENT;
|
||||
}
|
||||
} else
|
||||
errno = EINVAL;
|
||||
return (reparse_attr);
|
||||
}
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
#ifndef REPARSE_H
|
||||
#define REPARSE_H
|
||||
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size);
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point);
|
||||
|
||||
BOOL ntfs_possible_symlink(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni);
|
||||
|
||||
int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni);
|
||||
|
||||
@@ -939,40 +939,45 @@ mpa_err:
|
||||
"attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Setup not mapped runlist element if this is the base extent. */
|
||||
if (!attr->lowest_vcn) {
|
||||
VCN max_cluster;
|
||||
|
||||
max_cluster = ((sle64_to_cpu(attr->allocated_size) +
|
||||
/*
|
||||
* If this is the base of runlist (if 'lowest_vcn' is 0), then
|
||||
* 'allocated_size' is valid, and we can use it to compute the total
|
||||
* number of clusters across all extents. If the runlist covers all
|
||||
* clusters, then it fits into a single extent and we can terminate
|
||||
* the runlist with LCN_NOENT. Otherwise, we must terminate the runlist
|
||||
* with LCN_RL_NOT_MAPPED and let the caller look for more extents.
|
||||
*/
|
||||
if (!attr->lowest_vcn) {
|
||||
VCN num_clusters;
|
||||
|
||||
num_clusters = ((sle64_to_cpu(attr->allocated_size) +
|
||||
vol->cluster_size - 1) >>
|
||||
vol->cluster_size_bits) - 1;
|
||||
/*
|
||||
* A highest_vcn of zero means this is a single extent
|
||||
* attribute so simply terminate the runlist with LCN_ENOENT).
|
||||
*/
|
||||
if (deltaxcn) {
|
||||
vol->cluster_size_bits);
|
||||
|
||||
if (num_clusters > vcn) {
|
||||
/*
|
||||
* If there is a difference between the highest_vcn and
|
||||
* the highest cluster, the runlist is either corrupt
|
||||
* or, more likely, there are more extents following
|
||||
* this one.
|
||||
* The runlist doesn't cover all the clusters, so there
|
||||
* must be more extents.
|
||||
*/
|
||||
if (deltaxcn < max_cluster) {
|
||||
ntfs_log_debug("More extents to follow; deltaxcn = "
|
||||
"0x%llx, max_cluster = 0x%llx\n",
|
||||
(long long)deltaxcn,
|
||||
(long long)max_cluster);
|
||||
rl[rlpos].vcn = vcn;
|
||||
vcn += rl[rlpos].length = max_cluster - deltaxcn;
|
||||
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
|
||||
rlpos++;
|
||||
} else if (deltaxcn > max_cluster) {
|
||||
ntfs_log_debug("Corrupt attribute. deltaxcn = "
|
||||
"0x%llx, max_cluster = 0x%llx\n",
|
||||
(long long)deltaxcn,
|
||||
(long long)max_cluster);
|
||||
goto mpa_err;
|
||||
}
|
||||
ntfs_log_debug("More extents to follow; vcn = 0x%llx, "
|
||||
"num_clusters = 0x%llx\n",
|
||||
(long long)vcn,
|
||||
(long long)num_clusters);
|
||||
rl[rlpos].vcn = vcn;
|
||||
vcn += rl[rlpos].length = num_clusters - vcn;
|
||||
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
|
||||
rlpos++;
|
||||
} else if (vcn > num_clusters) {
|
||||
/*
|
||||
* There are more VCNs in the runlist than expected, so
|
||||
* the runlist is corrupt.
|
||||
*/
|
||||
ntfs_log_error("Corrupt attribute. vcn = 0x%llx, "
|
||||
"num_clusters = 0x%llx\n",
|
||||
(long long)vcn,
|
||||
(long long)num_clusters);
|
||||
goto mpa_err;
|
||||
}
|
||||
rl[rlpos].lcn = (LCN)LCN_ENOENT;
|
||||
} else /* Not the base extent. There may be more extents to follow. */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2007-2012 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2015 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
|
||||
@@ -41,9 +41,6 @@
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
@@ -52,6 +49,13 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define getgrgid(a) NULL
|
||||
#define getpwuid(a) NULL
|
||||
#define getgrnam(x) NULL
|
||||
#define getpwnam(x) NULL
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "param.h"
|
||||
#include "types.h"
|
||||
@@ -64,12 +68,7 @@
|
||||
#include "acls.h"
|
||||
#include "cache.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define getgrgid(a) NULL
|
||||
#define getpwuid(a) NULL
|
||||
#endif
|
||||
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* JPA NTFS constants or structs
|
||||
@@ -134,8 +133,8 @@ struct SDH { /* this is an image of an $SDH index entry */
|
||||
|
||||
static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('S'),
|
||||
const_cpu_to_le16('I'),
|
||||
const_cpu_to_le16('I'),
|
||||
const_cpu_to_le16('I'),
|
||||
const_cpu_to_le16('I'),
|
||||
const_cpu_to_le16(0) };
|
||||
static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('S'),
|
||||
@@ -230,7 +229,7 @@ int ntfs_sid_to_mbs_size(const SID *sid)
|
||||
{
|
||||
int size, i;
|
||||
|
||||
if (!ntfs_sid_is_valid(sid)) {
|
||||
if (!ntfs_valid_sid(sid)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -304,7 +303,7 @@ char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
|
||||
* No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
|
||||
* check @sid, too. 8 is the minimum SID string size.
|
||||
*/
|
||||
if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
|
||||
if (sid_str && (sid_str_size < 8 || !ntfs_valid_sid(sid))) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -520,9 +519,18 @@ static int entersecurity_data(ntfs_volume *vol,
|
||||
STREAM_SDS, 4, fullattr, fullsz,
|
||||
offs - gap + ALIGN_SDS_BLOCK);
|
||||
if ((written1 == fullsz)
|
||||
&& (written2 == written1))
|
||||
res = 0;
|
||||
else
|
||||
&& (written2 == written1)) {
|
||||
/*
|
||||
* Make sure the data size for $SDS marks the end
|
||||
* of the last security attribute. Windows uses
|
||||
* this to determine where the next attribute will
|
||||
* be written, which causes issues if chkdsk had
|
||||
* previously deleted the last entries without
|
||||
* adjusting the size.
|
||||
*/
|
||||
res = ntfs_attr_shrink_size(vol->secure_ni,STREAM_SDS,
|
||||
4, offs - gap + ALIGN_SDS_BLOCK + fullsz);
|
||||
} else
|
||||
errno = ENOSPC;
|
||||
free(fullattr);
|
||||
} else
|
||||
@@ -693,7 +701,7 @@ static le32 entersecurityattr(ntfs_volume *vol,
|
||||
retries = 0;
|
||||
while (entry) {
|
||||
next = ntfs_index_next(entry,xsii);
|
||||
if (next) {
|
||||
if (next) {
|
||||
psii = (struct SII*)next;
|
||||
/* save last key and */
|
||||
/* available position */
|
||||
@@ -713,10 +721,24 @@ static le32 entersecurityattr(ntfs_volume *vol,
|
||||
sizeof(SII_INDEX_KEY), xsii);
|
||||
if (!found && (errno != ENOENT)) {
|
||||
ntfs_log_perror("Index $SII is broken");
|
||||
psii = (struct SII*)NULL;
|
||||
} else {
|
||||
/* restore errno */
|
||||
errno = olderrno;
|
||||
entry = xsii->entry;
|
||||
psii = (struct SII*)entry;
|
||||
}
|
||||
if (psii
|
||||
&& !(psii->flags & INDEX_ENTRY_END)) {
|
||||
/* save first key and */
|
||||
/* available position */
|
||||
keyid = psii->keysecurid;
|
||||
realign.parts.dataoffsh
|
||||
= psii->dataoffsh;
|
||||
realign.parts.dataoffsl
|
||||
= psii->dataoffsl;
|
||||
offs = le64_to_cpu(realign.all);
|
||||
size = le32_to_cpu(psii->datasize);
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
@@ -731,7 +753,8 @@ static le32 entersecurityattr(ntfs_volume *vol,
|
||||
securid = const_cpu_to_le32(0);
|
||||
na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
|
||||
if (na) {
|
||||
if ((size_t)na->data_size < sizeof(struct SII)) {
|
||||
if ((size_t)na->data_size < (sizeof(struct SII)
|
||||
+ sizeof(INDEX_ENTRY_HEADER))) {
|
||||
ntfs_log_error("Creating the first security_id\n");
|
||||
securid = const_cpu_to_le32(FIRST_SECURITY_ID);
|
||||
}
|
||||
@@ -1033,7 +1056,7 @@ static int update_secur_descr(ntfs_volume *vol,
|
||||
* This is intended to allow graceful upgrades for files which
|
||||
* were created in previous versions, with a security attributes
|
||||
* and no security id.
|
||||
*
|
||||
*
|
||||
* It will allocate a security id and replace the individual
|
||||
* security attribute by a reference to the global one
|
||||
*
|
||||
@@ -1114,7 +1137,7 @@ static int upgrade_secur_desc(ntfs_volume *vol,
|
||||
* Should not be called for user root, however the group may be root
|
||||
*
|
||||
*/
|
||||
#ifndef __HAIKU__
|
||||
|
||||
static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
{
|
||||
BOOL ingroup;
|
||||
@@ -1136,7 +1159,6 @@ static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid
|
||||
}
|
||||
return (ingroup);
|
||||
}
|
||||
#endif //__HAIKU__
|
||||
|
||||
#if defined(__sun) && defined (__SVR4)
|
||||
|
||||
@@ -1329,6 +1351,48 @@ static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
|
||||
|
||||
#endif /* defined(__sun) && defined (__SVR4) */
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
/*
|
||||
* Extract the basic permissions from a Posix ACL
|
||||
*
|
||||
* This is only to be used when Posix ACLs are compiled in,
|
||||
* but not enabled in the mount options.
|
||||
*
|
||||
* it replaces the permission mask by the group permissions.
|
||||
* If special groups are mapped, they are also considered as world.
|
||||
*/
|
||||
|
||||
static int ntfs_basic_perms(const struct SECURITY_CONTEXT *scx,
|
||||
const struct POSIX_SECURITY *pxdesc)
|
||||
{
|
||||
int k;
|
||||
int perms;
|
||||
const struct POSIX_ACE *pace;
|
||||
const struct MAPPING* group;
|
||||
|
||||
k = 0;
|
||||
perms = pxdesc->mode;
|
||||
for (k=0; k < pxdesc->acccnt; k++) {
|
||||
pace = &pxdesc->acl.ace[k];
|
||||
if (pace->tag == POSIX_ACL_GROUP_OBJ)
|
||||
perms = (perms & 07707)
|
||||
| ((pace->perms & 7) << 3);
|
||||
else
|
||||
if (pace->tag == POSIX_ACL_GROUP) {
|
||||
group = scx->mapping[MAPGROUPS];
|
||||
while (group && (group->xid != pace->id))
|
||||
group = group->next;
|
||||
if (group && group->grcnt
|
||||
&& (*(group->groups) == (gid_t)pace->id))
|
||||
perms |= pace->perms & 7;
|
||||
}
|
||||
}
|
||||
return (perms);
|
||||
}
|
||||
|
||||
#endif /* POSIXACLS */
|
||||
|
||||
/*
|
||||
* Cacheing is done two-way :
|
||||
* - from uid, gid and perm to securid (CACHED_SECURID)
|
||||
@@ -1467,7 +1531,7 @@ static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
|
||||
/*
|
||||
* Resize permission cache table
|
||||
* do not call unless resizing is needed
|
||||
*
|
||||
*
|
||||
* If allocation fails, the cache size is not updated
|
||||
* Lack of memory is not considered as an error, the cache is left
|
||||
* consistent and errno is not set.
|
||||
@@ -1829,7 +1893,7 @@ static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
|
||||
* attribute
|
||||
*/
|
||||
if (test_nino_flag(ni, v3_Extensions)
|
||||
&& vol->secure_ni && ni->security_id) {
|
||||
&& vol->secure_ni && ni->security_id) {
|
||||
/* get v3.x descriptor in $Secure */
|
||||
securid.security_id = ni->security_id;
|
||||
securattr = retrievesecurityattr(vol,securid);
|
||||
@@ -1870,7 +1934,9 @@ static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
|
||||
* Determine which access types to a file are allowed
|
||||
* according to the relation of current process to the file
|
||||
*
|
||||
* Do not call if default_permissions is set
|
||||
* When Posix ACLs are compiled in but not enabled in the mount
|
||||
* options POSIX_ACL_USER, POSIX_ACL_GROUP and POSIX_ACL_MASK
|
||||
* are ignored.
|
||||
*/
|
||||
|
||||
static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
@@ -1883,10 +1949,15 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
int mask;
|
||||
BOOL somegroup;
|
||||
BOOL needgroups;
|
||||
BOOL noacl;
|
||||
mode_t perms;
|
||||
int i;
|
||||
|
||||
perms = pxdesc->mode;
|
||||
noacl = !(scx->vol->secure_flags & (1 << SECURITY_ACL));
|
||||
if (noacl)
|
||||
perms = ntfs_basic_perms(scx, pxdesc);
|
||||
else
|
||||
perms = pxdesc->mode;
|
||||
/* owner and root access */
|
||||
if (!scx->uid || (uid == scx->uid)) {
|
||||
if (!scx->uid) {
|
||||
@@ -1902,11 +1973,16 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
switch (pxace->tag) {
|
||||
case POSIX_ACL_USER_OBJ :
|
||||
case POSIX_ACL_GROUP_OBJ :
|
||||
case POSIX_ACL_GROUP :
|
||||
groupperms |= pxace->perms;
|
||||
break;
|
||||
case POSIX_ACL_GROUP :
|
||||
if (!noacl)
|
||||
groupperms
|
||||
|= pxace->perms;
|
||||
break;
|
||||
case POSIX_ACL_MASK :
|
||||
mask = pxace->perms & 7;
|
||||
if (!noacl)
|
||||
mask = pxace->perms & 7;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
@@ -1933,18 +2009,25 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
pxace = &pxdesc->acl.ace[i];
|
||||
switch (pxace->tag) {
|
||||
case POSIX_ACL_USER :
|
||||
if ((uid_t)pxace->id == scx->uid)
|
||||
if (!noacl
|
||||
&& ((uid_t)pxace->id == scx->uid))
|
||||
userperms = pxace->perms;
|
||||
break;
|
||||
case POSIX_ACL_MASK :
|
||||
mask = pxace->perms & 7;
|
||||
if (!noacl)
|
||||
mask = pxace->perms & 7;
|
||||
break;
|
||||
case POSIX_ACL_GROUP_OBJ :
|
||||
case POSIX_ACL_GROUP :
|
||||
if (((pxace->perms & mask) ^ perms)
|
||||
& (request >> 6) & 7)
|
||||
needgroups = TRUE;
|
||||
break;
|
||||
case POSIX_ACL_GROUP :
|
||||
if (!noacl
|
||||
&& (((pxace->perms & mask) ^ perms)
|
||||
& (request >> 6) & 7))
|
||||
needgroups = TRUE;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
@@ -1960,14 +2043,14 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
&& ((gid == scx->gid)
|
||||
|| groupmember(scx, scx->uid, gid)))
|
||||
perms &= 07070;
|
||||
else {
|
||||
else if (!noacl) {
|
||||
/* other groups */
|
||||
groupperms = -1;
|
||||
somegroup = FALSE;
|
||||
for (i=pxdesc->acccnt-1; i>=0 ; i--) {
|
||||
pxace = &pxdesc->acl.ace[i];
|
||||
if ((pxace->tag == POSIX_ACL_GROUP)
|
||||
&& groupmember(scx, uid, pxace->id)) {
|
||||
&& groupmember(scx, scx->uid, pxace->id)) {
|
||||
if (!(~pxace->perms & request & mask))
|
||||
groupperms = pxace->perms;
|
||||
somegroup = TRUE;
|
||||
@@ -1980,7 +2063,8 @@ static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
||||
perms = 0;
|
||||
else
|
||||
perms &= 07007;
|
||||
}
|
||||
} else
|
||||
perms &= 07007;
|
||||
}
|
||||
}
|
||||
return (perms);
|
||||
@@ -2097,7 +2181,7 @@ static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
|
||||
*/
|
||||
|
||||
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
const char *name, char *value, size_t size)
|
||||
const char *name, char *value, size_t size)
|
||||
{
|
||||
const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
||||
struct POSIX_SECURITY *pxdesc;
|
||||
@@ -2385,7 +2469,13 @@ int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
/* check whether available in cache */
|
||||
cached = fetch_cache(scx,ni);
|
||||
if (cached) {
|
||||
perm = cached->mode;
|
||||
#if POSIXACLS
|
||||
if (!(scx->vol->secure_flags & (1 << SECURITY_ACL))
|
||||
&& cached->pxdesc)
|
||||
perm = ntfs_basic_perms(scx,cached->pxdesc);
|
||||
else
|
||||
#endif
|
||||
perm = cached->mode;
|
||||
stbuf->st_uid = cached->uid;
|
||||
stbuf->st_gid = cached->gid;
|
||||
stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
|
||||
@@ -2407,11 +2497,17 @@ int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
securattr[le32_to_cpu(phead->owner)];
|
||||
#endif
|
||||
#if POSIXACLS
|
||||
pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
|
||||
usid, gsid, isdir);
|
||||
if (pxdesc)
|
||||
perm = pxdesc->mode & 07777;
|
||||
else
|
||||
pxdesc = ntfs_build_permissions_posix(
|
||||
scx->mapping, securattr,
|
||||
usid, gsid, isdir);
|
||||
if (pxdesc) {
|
||||
if (!(scx->vol->secure_flags
|
||||
& (1 << SECURITY_ACL)))
|
||||
perm = ntfs_basic_perms(scx,
|
||||
pxdesc);
|
||||
else
|
||||
perm = pxdesc->mode & 07777;
|
||||
} else
|
||||
perm = -1;
|
||||
#else
|
||||
perm = ntfs_build_permissions(securattr,
|
||||
@@ -2435,7 +2531,7 @@ int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
|
||||
#else
|
||||
if (!perm && ntfs_same_sid(usid, adminsid)) {
|
||||
stbuf->st_uid =
|
||||
stbuf->st_uid =
|
||||
find_tenant(scx,
|
||||
securattr);
|
||||
if (stbuf->st_uid)
|
||||
@@ -2490,8 +2586,12 @@ static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
|
||||
gid = cached->gid;
|
||||
pxdesc = cached->pxdesc;
|
||||
if (pxdesc) {
|
||||
pydesc = ntfs_build_inherited_posix(pxdesc,mode,
|
||||
scx->umask,isdir);
|
||||
if (scx->vol->secure_flags & (1 << SECURITY_ACL))
|
||||
pydesc = ntfs_build_inherited_posix(pxdesc,
|
||||
mode, scx->umask, isdir);
|
||||
else
|
||||
pydesc = ntfs_build_basic_posix(pxdesc,
|
||||
mode, scx->umask, isdir);
|
||||
}
|
||||
} else {
|
||||
securattr = getsecurityattr(scx->vol, dir_ni);
|
||||
@@ -2535,8 +2635,15 @@ static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
|
||||
enter_cache(scx, dir_ni, uid,
|
||||
gid, pxdesc);
|
||||
}
|
||||
pydesc = ntfs_build_inherited_posix(pxdesc,
|
||||
mode, scx->umask, isdir);
|
||||
if (scx->vol->secure_flags
|
||||
& (1 << SECURITY_ACL))
|
||||
pydesc = ntfs_build_inherited_posix(
|
||||
pxdesc, mode,
|
||||
scx->umask, isdir);
|
||||
else
|
||||
pydesc = ntfs_build_basic_posix(
|
||||
pxdesc, mode,
|
||||
scx->umask, isdir);
|
||||
free(pxdesc);
|
||||
}
|
||||
free(securattr);
|
||||
@@ -2547,7 +2654,7 @@ static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
|
||||
|
||||
/*
|
||||
* Allocate a security_id for a file being created
|
||||
*
|
||||
*
|
||||
* Returns zero if not possible (NTFS v3.x required)
|
||||
*/
|
||||
|
||||
@@ -2769,7 +2876,7 @@ le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
||||
/*
|
||||
* Update ownership and mode of a file, reusing an existing
|
||||
* security descriptor when possible
|
||||
*
|
||||
*
|
||||
* Returns zero if successful
|
||||
*/
|
||||
|
||||
@@ -2820,6 +2927,14 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
if (cached) {
|
||||
ni->security_id = cached->securid;
|
||||
NInoSetDirty(ni);
|
||||
/* adjust Windows read-only flag */
|
||||
if (!isdir) {
|
||||
if (mode & S_IWUSR)
|
||||
ni->flags &= ~FILE_ATTR_READONLY;
|
||||
else
|
||||
ni->flags |= FILE_ATTR_READONLY;
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
}
|
||||
} else cached = (struct CACHED_SECURID*)NULL;
|
||||
|
||||
@@ -2959,7 +3074,6 @@ BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
|
||||
return (allowed);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
@@ -3138,7 +3252,6 @@ int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Set new permissions to a file
|
||||
@@ -3268,7 +3381,7 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
SID *sid;
|
||||
int ret, sd_len;
|
||||
|
||||
|
||||
/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
|
||||
/*
|
||||
* Calculate security descriptor length. We have 2 sub-authorities in
|
||||
@@ -3276,14 +3389,14 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
* 4 bytes to every SID.
|
||||
*/
|
||||
sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
|
||||
sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
|
||||
sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
|
||||
if (!sd)
|
||||
return -1;
|
||||
|
||||
|
||||
sd->revision = SECURITY_DESCRIPTOR_REVISION;
|
||||
sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
|
||||
|
||||
|
||||
sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
|
||||
sid->revision = SID_REVISION;
|
||||
sid->sub_authority_count = 2;
|
||||
@@ -3291,21 +3404,21 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
|
||||
|
||||
sid = (SID*)((u8*)sid + sizeof(SID) + 4);
|
||||
|
||||
sid = (SID*)((u8*)sid + sizeof(SID) + 4);
|
||||
sid->revision = SID_REVISION;
|
||||
sid->sub_authority_count = 2;
|
||||
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
|
||||
|
||||
|
||||
acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
|
||||
acl->revision = ACL_REVISION;
|
||||
acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
|
||||
acl->ace_count = const_cpu_to_le16(1);
|
||||
sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
|
||||
|
||||
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
||||
@@ -3320,7 +3433,7 @@ int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
sd_len);
|
||||
if (ret)
|
||||
ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
|
||||
|
||||
|
||||
free(sd);
|
||||
return ret;
|
||||
}
|
||||
@@ -3469,7 +3582,7 @@ int ntfs_allowed_create(struct SECURITY_CONTEXT *scx,
|
||||
*
|
||||
* Returns true if access is allowed, including user is root and
|
||||
* no user mapping defined
|
||||
*
|
||||
*
|
||||
* Sets errno if there is a problem or if not allowed
|
||||
*
|
||||
* This is used for Posix ACL and checking creation of DOS file names
|
||||
@@ -3619,7 +3732,7 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
mode &= 01777;
|
||||
#endif
|
||||
#if POSIXACLS
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
||||
mode, pxdesc);
|
||||
#else
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
|
||||
@@ -3735,7 +3848,7 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
||||
if ((int)gid < 0)
|
||||
gid = filegid;
|
||||
#if POSIXACLS
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
||||
mode, newpxdesc);
|
||||
#else
|
||||
res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
|
||||
@@ -3774,7 +3887,6 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
BIGSID defusid;
|
||||
BIGSID defgsid;
|
||||
int offpacl;
|
||||
int offowner;
|
||||
int offgroup;
|
||||
SECURITY_DESCRIPTOR_RELATIVE *pnhead;
|
||||
ACL *pnacl;
|
||||
@@ -3792,21 +3904,48 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
if (scx->mapping[MAPUSERS]) {
|
||||
usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
|
||||
gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
|
||||
#if OWNERFROMACL
|
||||
/* Get approximation of parent owner when cannot map */
|
||||
if (!gsid)
|
||||
gsid = adminsid;
|
||||
if (!usid) {
|
||||
usid = ntfs_acl_owner(parentattr);
|
||||
if (!ntfs_is_user_sid(gsid))
|
||||
gsid = usid;
|
||||
}
|
||||
#else
|
||||
/* Define owner as root when cannot map */
|
||||
if (!usid)
|
||||
usid = adminsid;
|
||||
if (!gsid)
|
||||
gsid = adminsid;
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* If there is no user mapping, we have to copy owner
|
||||
* and group from parent directory.
|
||||
* If there is no user mapping and this is not a root
|
||||
* user, we have to get owner and group from somewhere,
|
||||
* and the parent directory has to contribute.
|
||||
* Windows never has to do that, because it can always
|
||||
* rely on a user mapping
|
||||
*/
|
||||
offowner = le32_to_cpu(pphead->owner);
|
||||
usid = (const SID*)&parentattr[offowner];
|
||||
offgroup = le32_to_cpu(pphead->group);
|
||||
gsid = (const SID*)&parentattr[offgroup];
|
||||
if (!scx->uid)
|
||||
usid = adminsid;
|
||||
else {
|
||||
#if OWNERFROMACL
|
||||
usid = ntfs_acl_owner(parentattr);
|
||||
#else
|
||||
int offowner;
|
||||
|
||||
offowner = le32_to_cpu(pphead->owner);
|
||||
usid = (const SID*)&parentattr[offowner];
|
||||
#endif
|
||||
}
|
||||
if (!scx->gid)
|
||||
gsid = adminsid;
|
||||
else {
|
||||
offgroup = le32_to_cpu(pphead->group);
|
||||
gsid = (const SID*)&parentattr[offgroup];
|
||||
}
|
||||
}
|
||||
/*
|
||||
* new attribute is smaller than parent's
|
||||
@@ -3911,12 +4050,14 @@ le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
securid = const_cpu_to_le32(0);
|
||||
cached = (struct CACHED_PERMISSIONS*)NULL;
|
||||
/*
|
||||
* Try to get inherited id from cache
|
||||
* Try to get inherited id from cache, possible when
|
||||
* the current process owns the parent directory
|
||||
*/
|
||||
if (test_nino_flag(dir_ni, v3_Extensions)
|
||||
&& dir_ni->security_id) {
|
||||
cached = fetch_cache(scx, dir_ni);
|
||||
if (cached)
|
||||
if (cached
|
||||
&& (cached->uid == scx->uid) && (cached->gid == scx->gid))
|
||||
securid = (fordir ? cached->inh_dirid
|
||||
: cached->inh_fileid);
|
||||
}
|
||||
@@ -3932,10 +4073,13 @@ le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
free(parentattr);
|
||||
/*
|
||||
* Store the result into cache for further use
|
||||
* if the current process owns the parent directory
|
||||
*/
|
||||
if (securid) {
|
||||
cached = fetch_cache(scx, dir_ni);
|
||||
if (cached) {
|
||||
if (cached
|
||||
&& (cached->uid == scx->uid)
|
||||
&& (cached->gid == scx->gid)) {
|
||||
if (fordir)
|
||||
cached->inh_dirid = securid;
|
||||
else
|
||||
@@ -4248,7 +4392,6 @@ int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
||||
return (!scx->mapping[MAPUSERS] || link_group_members(scx));
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs attribute into an extended attribute
|
||||
@@ -4334,58 +4477,83 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Open $Secure once for all
|
||||
* returns zero if it succeeds
|
||||
* non-zero if it fails. This is not an error (on NTFS v1.x)
|
||||
* Open the volume's security descriptor index ($Secure)
|
||||
*
|
||||
* returns 0 if it succeeds
|
||||
* -1 with errno set if it fails and the volume is NTFS v3.0+
|
||||
*/
|
||||
|
||||
|
||||
int ntfs_open_secure(ntfs_volume *vol)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
int res;
|
||||
ntfs_index_context *sii;
|
||||
ntfs_index_context *sdh;
|
||||
|
||||
res = -1;
|
||||
vol->secure_ni = (ntfs_inode*)NULL;
|
||||
vol->secure_xsii = (ntfs_index_context*)NULL;
|
||||
vol->secure_xsdh = (ntfs_index_context*)NULL;
|
||||
if (vol->major_ver >= 3) {
|
||||
/* make sure this is a genuine $Secure inode 9 */
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
|
||||
if (ni && (ni->mft_no == 9)) {
|
||||
vol->secure_reentry = 0;
|
||||
vol->secure_xsii = ntfs_index_ctx_get(ni,
|
||||
sii_stream, 4);
|
||||
vol->secure_xsdh = ntfs_index_ctx_get(ni,
|
||||
sdh_stream, 4);
|
||||
if (ni && vol->secure_xsii && vol->secure_xsdh) {
|
||||
vol->secure_ni = ni;
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
if (vol->secure_ni) /* Already open? */
|
||||
return 0;
|
||||
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
|
||||
if (!ni)
|
||||
goto err;
|
||||
|
||||
if (ni->mft_no != FILE_Secure) {
|
||||
ntfs_log_error("$Secure does not have expected inode number!");
|
||||
errno = EINVAL;
|
||||
goto err_close_ni;
|
||||
}
|
||||
return (res);
|
||||
|
||||
/* Allocate the needed index contexts. */
|
||||
sii = ntfs_index_ctx_get(ni, sii_stream, 4);
|
||||
if (!sii)
|
||||
goto err_close_ni;
|
||||
|
||||
sdh = ntfs_index_ctx_get(ni, sdh_stream, 4);
|
||||
if (!sdh)
|
||||
goto err_close_sii;
|
||||
|
||||
vol->secure_xsdh = sdh;
|
||||
vol->secure_xsii = sii;
|
||||
vol->secure_ni = ni;
|
||||
return 0;
|
||||
|
||||
err_close_sii:
|
||||
ntfs_index_ctx_put(sii);
|
||||
err_close_ni:
|
||||
ntfs_inode_close(ni);
|
||||
err:
|
||||
/* Failing on NTFS pre-v3.0 is expected. */
|
||||
if (vol->major_ver < 3)
|
||||
return 0;
|
||||
ntfs_log_perror("Failed to open $Secure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final cleaning
|
||||
* Close the volume's security descriptor index ($Secure)
|
||||
*
|
||||
* returns 0 if it succeeds
|
||||
* -1 with errno set if it fails
|
||||
*/
|
||||
int ntfs_close_secure(ntfs_volume *vol)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (vol->secure_ni) {
|
||||
ntfs_index_ctx_put(vol->secure_xsdh);
|
||||
ntfs_index_ctx_put(vol->secure_xsii);
|
||||
res = ntfs_inode_close(vol->secure_ni);
|
||||
vol->secure_ni = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a security context
|
||||
* Allocated memory is freed to facilitate the detection of memory leaks
|
||||
*/
|
||||
|
||||
void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
|
||||
void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
|
||||
vol = scx->vol;
|
||||
if (vol->secure_ni) {
|
||||
ntfs_index_ctx_put(vol->secure_xsii);
|
||||
ntfs_index_ctx_put(vol->secure_xsdh);
|
||||
ntfs_inode_close(vol->secure_ni);
|
||||
|
||||
}
|
||||
ntfs_free_mapping(scx->mapping);
|
||||
free_caches(scx);
|
||||
}
|
||||
@@ -5204,7 +5372,6 @@ struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
||||
scx->vol->secure_flags = 0;
|
||||
/* accept no mapping and no $Secure */
|
||||
ntfs_build_mapping(scx,(const char*)NULL,TRUE);
|
||||
ntfs_open_secure(vol);
|
||||
} else {
|
||||
if (scapi)
|
||||
free(scapi);
|
||||
@@ -5236,7 +5403,7 @@ BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
|
||||
ok = FALSE;
|
||||
if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
|
||||
vol = scapi->security.vol;
|
||||
ntfs_close_secure(&scapi->security);
|
||||
ntfs_destroy_security_context(&scapi->security);
|
||||
free(scapi);
|
||||
if (!ntfs_umount(vol, 0))
|
||||
ok = TRUE;
|
||||
|
||||
@@ -29,23 +29,12 @@
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "dir.h"
|
||||
#include "endians.h"
|
||||
|
||||
#ifndef POSIXACLS
|
||||
#define POSIXACLS 0
|
||||
#endif
|
||||
|
||||
typedef u16 be16;
|
||||
typedef u32 be32;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define const_cpu_to_be16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L))
|
||||
#define const_cpu_to_be32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \
|
||||
+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
|
||||
#else
|
||||
#define const_cpu_to_be16(x) (x)
|
||||
#define const_cpu_to_be32(x) (x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* item in the mapping list
|
||||
*/
|
||||
@@ -184,7 +173,7 @@ struct POSIX_SECURITY {
|
||||
int defcnt;
|
||||
int firstdef;
|
||||
u16 tagsset;
|
||||
s32 alignment[0];
|
||||
u16 filler;
|
||||
struct POSIX_ACL acl;
|
||||
} ;
|
||||
|
||||
@@ -222,22 +211,6 @@ enum {
|
||||
extern BOOL ntfs_guid_is_zero(const GUID *guid);
|
||||
extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);
|
||||
|
||||
/**
|
||||
* ntfs_sid_is_valid - determine if a SID is valid
|
||||
* @sid: SID for which to determine if it is valid
|
||||
*
|
||||
* Determine if the SID pointed to by @sid is valid.
|
||||
*
|
||||
* Return TRUE if it is valid and FALSE otherwise.
|
||||
*/
|
||||
static __inline__ BOOL ntfs_sid_is_valid(const SID *sid)
|
||||
{
|
||||
if (!sid || sid->revision != SID_REVISION ||
|
||||
sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern int ntfs_sid_to_mbs_size(const SID *sid);
|
||||
extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
|
||||
size_t sid_str_size);
|
||||
@@ -283,7 +256,9 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
||||
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *dir_ni, BOOL fordir);
|
||||
int ntfs_open_secure(ntfs_volume *vol);
|
||||
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
|
||||
int ntfs_close_secure(ntfs_volume *vol);
|
||||
|
||||
void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx);
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
|
||||
@@ -48,15 +48,23 @@ typedef u16 le16;
|
||||
typedef u32 le32;
|
||||
typedef u64 le64;
|
||||
|
||||
typedef u16 be16;
|
||||
typedef u32 be32;
|
||||
typedef u64 be64;
|
||||
|
||||
/*
|
||||
* Declare sle{16,32,64} to be unsigned because we do not want sign extension
|
||||
* on BE architectures.
|
||||
* Declare s{l,b}e{16,32,64} to be unsigned because we do not want sign
|
||||
* extension on BE architectures.
|
||||
*/
|
||||
typedef u16 sle16;
|
||||
typedef u32 sle32;
|
||||
typedef u64 sle64;
|
||||
|
||||
typedef u16 ntfschar; /* 2-byte Unicode character type. */
|
||||
typedef u16 sbe16;
|
||||
typedef u32 sbe32;
|
||||
typedef u64 sbe64;
|
||||
|
||||
typedef le16 ntfschar; /* 2-byte Unicode character type. */
|
||||
#define UCHAR_T_SIZE_BITS 1
|
||||
|
||||
/*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2008-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2008 Bernhard Kaindl
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -59,16 +59,11 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */
|
||||
|
||||
// no wchar support in the Haiku kernel
|
||||
#if defined(__HAIKU__) && defined(_KERNEL_MODE)
|
||||
# include <KernelExport.h>
|
||||
# define mbstowcs(a, b, c) (panic("mbstowcs"), 0)
|
||||
# define wctomb(a, b) (panic("wctomb"), 0)
|
||||
# define mbtowc(a, b, c) (panic("mbtowc"), 0)
|
||||
# define setlocale(a, b) (panic("setlocale"), 0)
|
||||
#endif
|
||||
#ifndef ALLOW_BROKEN_UNICODE
|
||||
/* Erik allowing broken UTF-16 surrogate pairs and U+FFFE and U+FFFF by default,
|
||||
* open to debate. */
|
||||
#define ALLOW_BROKEN_UNICODE 1
|
||||
#endif /* !defined(ALLOW_BROKEN_UNICODE) */
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
@@ -148,14 +143,24 @@ BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
|
||||
* @name1_len: length of first Unicode name to compare
|
||||
* @name2: second Unicode name to compare
|
||||
* @name2_len: length of second Unicode name to compare
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE
|
||||
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
|
||||
* @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE (see below)
|
||||
* @upcase: upcase table
|
||||
* @upcase_len: upcase table size
|
||||
*
|
||||
* If @ic is CASE_SENSITIVE, then the names are compared primarily ignoring
|
||||
* case, but if the names are equal ignoring case, then they are compared
|
||||
* case-sensitively. As an example, "abc" would collate before "BCD" (since
|
||||
* "abc" and "BCD" differ ignoring case and 'A' < 'B') but after "ABC" (since
|
||||
* "ABC" and "abc" are equal ignoring case and 'A' < 'a'). This matches the
|
||||
* collation order of filenames as indexed in NTFS directories.
|
||||
*
|
||||
* If @ic is IGNORE_CASE, then the names are only compared case-insensitively
|
||||
* and are considered to match if and only if they are equal ignoring case.
|
||||
*
|
||||
* Returns:
|
||||
* -1 if the first name collates before the second one,
|
||||
* 0 if the names match,
|
||||
* 1 if the second name collates before the first one, or
|
||||
*
|
||||
* 0 if the names match, or
|
||||
* 1 if the second name collates before the first one
|
||||
*/
|
||||
int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
@@ -167,7 +172,7 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
u16 u1, u2;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
|
||||
if (!name1 || !name2 || !upcase || !upcase_len) {
|
||||
ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -210,9 +215,9 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
return 1;
|
||||
} else {
|
||||
do {
|
||||
u1 = c1 = le16_to_cpu(*name1);
|
||||
u1 = le16_to_cpu(*name1);
|
||||
name1++;
|
||||
u2 = c2 = le16_to_cpu(*name2);
|
||||
u2 = le16_to_cpu(*name2);
|
||||
name2++;
|
||||
if (u1 < upcase_len)
|
||||
u1 = le16_to_cpu(upcase[u1]);
|
||||
@@ -253,7 +258,7 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
*/
|
||||
int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
|
||||
{
|
||||
ntfschar c1, c2;
|
||||
u16 c1, c2;
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -369,7 +374,7 @@ ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
|
||||
dst = ntfs_malloc((len + 1) * sizeof(ntfschar));
|
||||
if (dst) {
|
||||
memcpy(dst, s, len * sizeof(ntfschar));
|
||||
dst[len] = cpu_to_le16(L'\0');
|
||||
dst[len] = const_cpu_to_le16(L'\0');
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -441,22 +446,27 @@ void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
|
||||
so this patch fixes the resulting issues for systems which use
|
||||
UTF-8 and for others, specifying the locale in fstab brings them
|
||||
the encoding which they want.
|
||||
|
||||
|
||||
If no locale is defined or there was a problem with setting one
|
||||
up and whenever nl_langinfo(CODESET) returns a sting starting with
|
||||
"ANSI", use an internal UCS-2LE <-> UTF-8 codeset converter to fix
|
||||
the bug where NTFS-3G does not show any path names which include
|
||||
international characters!!! (and also fails on creating them) as result.
|
||||
|
||||
|
||||
Author: Bernhard Kaindl <bk@suse.de>
|
||||
Jean-Pierre Andre made it compliant with RFC3629/RFC2781.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return the amount of 8-bit elements in UTF-8 needed (without the terminating
|
||||
* null) to store a given UTF-16LE string.
|
||||
|
||||
/*
|
||||
* Return the number of bytes in UTF-8 needed (without the terminating null) to
|
||||
* store the given UTF-16LE string.
|
||||
*
|
||||
* Return -1 with errno set if string has invalid byte sequence or too long.
|
||||
* On error, -1 is returned, and errno is set to the error code. The following
|
||||
* error codes can be expected:
|
||||
* EILSEQ The input string is not valid UTF-16LE (only possible
|
||||
* if compiled without ALLOW_BROKEN_UNICODE).
|
||||
* ENAMETOOLONG The length of the UTF-8 string in bytes (without the
|
||||
* terminating null) would exceed @outs_len.
|
||||
*/
|
||||
static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_len)
|
||||
{
|
||||
@@ -465,14 +475,28 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
||||
BOOL surrog;
|
||||
|
||||
surrog = FALSE;
|
||||
for (i = 0; i < ins_len && ins[i]; i++) {
|
||||
for (i = 0; i < ins_len && ins[i] && count <= outs_len; i++) {
|
||||
unsigned short c = le16_to_cpu(ins[i]);
|
||||
if (surrog) {
|
||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
||||
surrog = FALSE;
|
||||
count += 4;
|
||||
} else
|
||||
} else {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
/* The first UTF-16 unit of a surrogate pair has
|
||||
* a value between 0xd800 and 0xdc00. It can be
|
||||
* encoded as an individual UTF-8 sequence if we
|
||||
* cannot combine it with the next UTF-16 unit
|
||||
* unit as a surrogate pair. */
|
||||
surrog = FALSE;
|
||||
count += 3;
|
||||
|
||||
--i;
|
||||
continue;
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
} else
|
||||
if (c < 0x80)
|
||||
count++;
|
||||
@@ -482,21 +506,30 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
||||
count += 3;
|
||||
else if (c < 0xdc00)
|
||||
surrog = TRUE;
|
||||
#if NOREVBOM
|
||||
else if ((c >= 0xe000) && (c < 0xfffe))
|
||||
#else
|
||||
else if (c >= 0xe000)
|
||||
#endif
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
else if (c < 0xe000)
|
||||
count += 3;
|
||||
else
|
||||
else if (c >= 0xe000)
|
||||
#else
|
||||
else if ((c >= 0xe000) && (c < 0xfffe))
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
count += 3;
|
||||
else
|
||||
goto fail;
|
||||
if (count > outs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (surrog)
|
||||
|
||||
if (surrog && count <= outs_len) {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
count += 3; /* ending with a single surrogate */
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
|
||||
if (count > outs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
out:
|
||||
@@ -511,7 +544,7 @@ fail:
|
||||
* @ins: input utf16 string buffer
|
||||
* @ins_len: length of input string in utf16 characters
|
||||
* @outs: on return contains the (allocated) output multibyte string
|
||||
* @outs_len: length of output buffer in bytes
|
||||
* @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
|
||||
*
|
||||
* Return -1 with errno set if string has invalid byte sequence or too long.
|
||||
*/
|
||||
@@ -530,10 +563,16 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
int halfpair;
|
||||
|
||||
halfpair = 0;
|
||||
if (!*outs)
|
||||
if (!*outs) {
|
||||
/* If no output buffer was provided, we will allocate one and
|
||||
* limit its length to PATH_MAX. Note: we follow the standard
|
||||
* convention of PATH_MAX including the terminating null. */
|
||||
outs_len = PATH_MAX;
|
||||
}
|
||||
|
||||
size = utf16_to_utf8_size(ins, ins_len, outs_len);
|
||||
/* The size *with* the terminating null is limited to @outs_len,
|
||||
* so the size *without* the terminating null is limited to one less. */
|
||||
size = utf16_to_utf8_size(ins, ins_len, outs_len - 1);
|
||||
|
||||
if (size < 0)
|
||||
goto out;
|
||||
@@ -557,8 +596,24 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
|
||||
*t++ = 0x80 + (c & 63);
|
||||
halfpair = 0;
|
||||
} else
|
||||
} else {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
/* The first UTF-16 unit of a surrogate pair has
|
||||
* a value between 0xd800 and 0xdc00. It can be
|
||||
* encoded as an individual UTF-8 sequence if we
|
||||
* cannot combine it with the next UTF-16 unit
|
||||
* unit as a surrogate pair. */
|
||||
*t++ = 0xe0 | (halfpair >> 12);
|
||||
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (halfpair & 0x3f);
|
||||
halfpair = 0;
|
||||
|
||||
--i;
|
||||
continue;
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
} else if (c < 0x80) {
|
||||
*t++ = c;
|
||||
} else {
|
||||
@@ -571,16 +626,30 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
*t++ = 0x80 | (c & 0x3f);
|
||||
} else if (c < 0xdc00)
|
||||
halfpair = c;
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
else if (c < 0xe000) {
|
||||
*t++ = 0xe0 | (c >> 12);
|
||||
*t++ = 0x80 | ((c >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (c & 0x3f);
|
||||
}
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
else if (c >= 0xe000) {
|
||||
*t++ = 0xe0 | (c >> 12);
|
||||
*t++ = 0x80 | ((c >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (c & 0x3f);
|
||||
} else
|
||||
} else
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
if (halfpair) { /* ending with a single surrogate */
|
||||
*t++ = 0xe0 | (halfpair >> 12);
|
||||
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (halfpair & 0x3f);
|
||||
}
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
*t = '\0';
|
||||
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
if(nfconvert_utf8 && (t - *outs) > 0) {
|
||||
@@ -609,7 +678,7 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
||||
}
|
||||
#endif /* ENABLE_NFCONV */
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
|
||||
|
||||
ret = t - *outs;
|
||||
out:
|
||||
return ret;
|
||||
@@ -618,8 +687,8 @@ fail:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the amount of 16-bit elements in UTF-16LE needed
|
||||
/*
|
||||
* Return the amount of 16-bit elements in UTF-16LE needed
|
||||
* (without the terminating null) to store given UTF-8 string.
|
||||
*
|
||||
* Return -1 with errno set if it's longer than PATH_MAX or string is invalid.
|
||||
@@ -634,22 +703,22 @@ static int utf8_to_utf16_size(const char *s)
|
||||
size_t count = 0;
|
||||
|
||||
while ((byte = *((const unsigned char *)s++))) {
|
||||
if (++count >= PATH_MAX)
|
||||
if (++count >= PATH_MAX)
|
||||
goto fail;
|
||||
if (byte >= 0xc0) {
|
||||
if (byte >= 0xF5) {
|
||||
errno = EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
if (!*s)
|
||||
if (!*s)
|
||||
break;
|
||||
if (byte >= 0xC0)
|
||||
if (byte >= 0xC0)
|
||||
s++;
|
||||
if (!*s)
|
||||
if (!*s)
|
||||
break;
|
||||
if (byte >= 0xE0)
|
||||
if (byte >= 0xE0)
|
||||
s++;
|
||||
if (!*s)
|
||||
if (!*s)
|
||||
break;
|
||||
if (byte >= 0xF0) {
|
||||
s++;
|
||||
@@ -665,11 +734,11 @@ fail:
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
/*
|
||||
* This converts one UTF-8 sequence to cpu-endian Unicode value
|
||||
* within range U+0 .. U+10ffff and excluding U+D800 .. U+DFFF
|
||||
*
|
||||
* Return the number of used utf8 bytes or -1 with errno set
|
||||
* Return the number of used utf8 bytes or -1 with errno set
|
||||
* if sequence is invalid.
|
||||
*/
|
||||
static int utf8_to_unicode(u32 *wc, const char *s)
|
||||
@@ -700,15 +769,16 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
||||
| ((u32)(s[1] & 0x3F) << 6)
|
||||
| ((u32)(s[2] & 0x3F));
|
||||
/* Check valid ranges */
|
||||
#if NOREVBOM
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
|
||||
|| ((*wc >= 0xD800) && (*wc <= 0xDFFF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
|
||||
return 3;
|
||||
#else
|
||||
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
|
||||
return 3;
|
||||
#endif
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
goto fail;
|
||||
/* four-byte */
|
||||
@@ -735,7 +805,7 @@ fail:
|
||||
* @ins: input multibyte string buffer
|
||||
* @outs: on return contains the (allocated) output utf16 string
|
||||
* @outs_len: length of output buffer in utf16 characters
|
||||
*
|
||||
*
|
||||
* Return -1 with errno set.
|
||||
*/
|
||||
static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
||||
@@ -796,7 +866,7 @@ static int ntfs_utf8_to_utf16(const char *ins, ntfschar **outs)
|
||||
}
|
||||
t += m;
|
||||
}
|
||||
|
||||
|
||||
ret = --outpos - *outs;
|
||||
fail:
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
@@ -813,7 +883,7 @@ fail:
|
||||
* @ins: input Unicode string buffer
|
||||
* @ins_len: length of input string in Unicode characters
|
||||
* @outs: on return contains the (allocated) output multibyte string
|
||||
* @outs_len: length of output buffer in bytes
|
||||
* @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
|
||||
*
|
||||
* Convert the input little endian, 2-byte Unicode string @ins, of length
|
||||
* @ins_len into the multibyte string format dictated by the current locale.
|
||||
@@ -869,7 +939,9 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
#ifdef HAVE_MBSINIT
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
#else
|
||||
#ifndef __HAIKU__
|
||||
wctomb(NULL, 0);
|
||||
#endif
|
||||
#endif
|
||||
for (i = o = 0; i < ins_len; i++) {
|
||||
/* Reallocate memory if necessary or abort. */
|
||||
@@ -894,6 +966,8 @@ int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
/* Convert the CPU endian wide character to multibyte. */
|
||||
#ifdef HAVE_MBSINIT
|
||||
cnt = wcrtomb(mbs + o, wc, &mbstate);
|
||||
#elif defined(__HAIKU__)
|
||||
cnt = -1;
|
||||
#else
|
||||
cnt = wctomb(mbs + o, wc);
|
||||
#endif
|
||||
@@ -939,7 +1013,7 @@ err_out:
|
||||
* Convert the input multibyte string @ins, from the current locale into the
|
||||
* corresponding little endian, 2-byte Unicode string.
|
||||
*
|
||||
* The function allocates the string and the caller is responsible for calling
|
||||
* The function allocates the string and the caller is responsible for calling
|
||||
* free(*@outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of Unicode characters written to
|
||||
@@ -970,7 +1044,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (use_utf8)
|
||||
return ntfs_utf8_to_utf16(ins, outs);
|
||||
|
||||
@@ -988,7 +1062,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
ins_len = strlen(ins);
|
||||
}
|
||||
#endif
|
||||
#elif !defined(DJGPP)
|
||||
#elif !defined(DJGPP) && !defined(__HAIKU__)
|
||||
ins_len = mbstowcs(NULL, s, 0);
|
||||
#else
|
||||
/* Eeek!!! DJGPP has broken mbstowcs() implementation!!! */
|
||||
@@ -1013,7 +1087,9 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
#ifdef HAVE_MBSINIT
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
#else
|
||||
#ifndef __HAIKU__
|
||||
mbtowc(NULL, NULL, 0);
|
||||
#endif
|
||||
#endif
|
||||
for (i = o = cnt = 0; i < ins_size; i += cnt, o++) {
|
||||
/* Reallocate memory if necessary. */
|
||||
@@ -1029,6 +1105,8 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
/* Convert the multibyte character to a wide character. */
|
||||
#ifdef HAVE_MBSINIT
|
||||
cnt = mbrtowc(&wc, ins + i, ins_size - i, &mbstate);
|
||||
#elif defined(__HAIKU__)
|
||||
cnt = -1;
|
||||
#else
|
||||
cnt = mbtowc(&wc, ins + i, ins_size - i);
|
||||
#endif
|
||||
@@ -1059,7 +1137,7 @@ int ntfs_mbstoucs(const char *ins, ntfschar **outs)
|
||||
}
|
||||
#endif
|
||||
/* Now write the NULL character. */
|
||||
ucs[o] = cpu_to_le16(L'\0');
|
||||
ucs[o] = const_cpu_to_le16(L'\0');
|
||||
*outs = ucs;
|
||||
return o;
|
||||
err_out:
|
||||
@@ -1137,66 +1215,15 @@ char *ntfs_uppercase_mbs(const char *low,
|
||||
*/
|
||||
void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
||||
{
|
||||
#if 1 /* Vista */
|
||||
/*
|
||||
* This is the table as defined by Vista
|
||||
*/
|
||||
/*
|
||||
* "Start" is inclusive and "End" is exclusive, every value has the
|
||||
* value of "Add" added to it.
|
||||
*/
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32},
|
||||
{0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130},
|
||||
{0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32},
|
||||
{0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64},
|
||||
{0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80},
|
||||
{0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8},
|
||||
{0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8},
|
||||
{0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8},
|
||||
{0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74},
|
||||
{0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128},
|
||||
{0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8},
|
||||
{0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8},
|
||||
{0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8},
|
||||
{0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9},
|
||||
{0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48},
|
||||
{0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0}
|
||||
};
|
||||
/*
|
||||
* "Start" is exclusive and "End" is inclusive, every second value is
|
||||
* decremented by one.
|
||||
*/
|
||||
static int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178},
|
||||
{0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd},
|
||||
{0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220},
|
||||
{0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f},
|
||||
{0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481},
|
||||
{0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce},
|
||||
{0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513},
|
||||
{0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61},
|
||||
{0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0}
|
||||
};
|
||||
/*
|
||||
* Set the Unicode character at offset "Offset" to "Value". Note,
|
||||
* "Value" is host endian.
|
||||
*/
|
||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
||||
{0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184},
|
||||
{0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6},
|
||||
{0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7},
|
||||
{0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc},
|
||||
{0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca},
|
||||
{0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66},
|
||||
{0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190},
|
||||
{0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196},
|
||||
{0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f},
|
||||
{0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae},
|
||||
{0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9},
|
||||
{0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0}
|
||||
};
|
||||
#else /* Vista */
|
||||
struct NEWUPPERCASE {
|
||||
unsigned short first;
|
||||
unsigned short last;
|
||||
short diff;
|
||||
unsigned char step;
|
||||
unsigned char osmajor;
|
||||
unsigned char osminor;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* This is the table as defined by Windows XP
|
||||
*/
|
||||
@@ -1236,9 +1263,89 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
||||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
#endif /* Vista */
|
||||
|
||||
/*
|
||||
* Changes which were applied to later Windows versions
|
||||
*
|
||||
* md5 for $UpCase from Winxp : 6fa3db2468275286210751e869d36373
|
||||
* Vista : 2f03b5a69d486ff3864cecbd07f24440
|
||||
* Win8 : 7ff498a44e45e77374cc7c962b1b92f2
|
||||
*/
|
||||
static const struct NEWUPPERCASE newuppercase[] = {
|
||||
/* from Windows 6.0 (Vista) */
|
||||
{ 0x37b, 0x37d, 0x82, 1, 6, 0 },
|
||||
{ 0x1f80, 0x1f87, 0x8, 1, 6, 0 },
|
||||
{ 0x1f90, 0x1f97, 0x8, 1, 6, 0 },
|
||||
{ 0x1fa0, 0x1fa7, 0x8, 1, 6, 0 },
|
||||
{ 0x2c30, 0x2c5e, -0x30, 1, 6, 0 },
|
||||
{ 0x2d00, 0x2d25, -0x1c60, 1, 6, 0 },
|
||||
{ 0x2c68, 0x2c6c, -0x1, 2, 6, 0 },
|
||||
{ 0x219, 0x21f, -0x1, 2, 6, 0 },
|
||||
{ 0x223, 0x233, -0x1, 2, 6, 0 },
|
||||
{ 0x247, 0x24f, -0x1, 2, 6, 0 },
|
||||
{ 0x3d9, 0x3e1, -0x1, 2, 6, 0 },
|
||||
{ 0x48b, 0x48f, -0x1, 2, 6, 0 },
|
||||
{ 0x4fb, 0x513, -0x1, 2, 6, 0 },
|
||||
{ 0x2c81, 0x2ce3, -0x1, 2, 6, 0 },
|
||||
{ 0x3f8, 0x3fb, -0x1, 3, 6, 0 },
|
||||
{ 0x4c6, 0x4ce, -0x1, 4, 6, 0 },
|
||||
{ 0x23c, 0x242, -0x1, 6, 6, 0 },
|
||||
{ 0x4ed, 0x4f7, -0x1, 10, 6, 0 },
|
||||
{ 0x450, 0x45d, -0x50, 13, 6, 0 },
|
||||
{ 0x2c61, 0x2c76, -0x1, 21, 6, 0 },
|
||||
{ 0x1fcc, 0x1ffc, -0x9, 48, 6, 0 },
|
||||
{ 0x180, 0x180, 0xc3, 1, 6, 0 },
|
||||
{ 0x195, 0x195, 0x61, 1, 6, 0 },
|
||||
{ 0x19a, 0x19a, 0xa3, 1, 6, 0 },
|
||||
{ 0x19e, 0x19e, 0x82, 1, 6, 0 },
|
||||
{ 0x1bf, 0x1bf, 0x38, 1, 6, 0 },
|
||||
{ 0x1f9, 0x1f9, -0x1, 1, 6, 0 },
|
||||
{ 0x23a, 0x23a, 0x2a2b, 1, 6, 0 },
|
||||
{ 0x23e, 0x23e, 0x2a28, 1, 6, 0 },
|
||||
{ 0x26b, 0x26b, 0x29f7, 1, 6, 0 },
|
||||
{ 0x27d, 0x27d, 0x29e7, 1, 6, 0 },
|
||||
{ 0x280, 0x280, -0xda, 1, 6, 0 },
|
||||
{ 0x289, 0x289, -0x45, 1, 6, 0 },
|
||||
{ 0x28c, 0x28c, -0x47, 1, 6, 0 },
|
||||
{ 0x3f2, 0x3f2, 0x7, 1, 6, 0 },
|
||||
{ 0x4cf, 0x4cf, -0xf, 1, 6, 0 },
|
||||
{ 0x1d7d, 0x1d7d, 0xee6, 1, 6, 0 },
|
||||
{ 0x1fb3, 0x1fb3, 0x9, 1, 6, 0 },
|
||||
{ 0x214e, 0x214e, -0x1c, 1, 6, 0 },
|
||||
{ 0x2184, 0x2184, -0x1, 1, 6, 0 },
|
||||
/* from Windows 6.1 (Win7) */
|
||||
{ 0x23a, 0x23e, 0x0, 4, 6, 1 },
|
||||
{ 0x250, 0x250, 0x2a1f, 2, 6, 1 },
|
||||
{ 0x251, 0x251, 0x2a1c, 2, 6, 1 },
|
||||
{ 0x271, 0x271, 0x29fd, 2, 6, 1 },
|
||||
{ 0x371, 0x373, -0x1, 2, 6, 1 },
|
||||
{ 0x377, 0x377, -0x1, 2, 6, 1 },
|
||||
{ 0x3c2, 0x3c2, 0x0, 2, 6, 1 },
|
||||
{ 0x3d7, 0x3d7, -0x8, 2, 6, 1 },
|
||||
{ 0x515, 0x523, -0x1, 2, 6, 1 },
|
||||
/* below, -0x75fc stands for 0x8a04 and truncation */
|
||||
{ 0x1d79, 0x1d79, -0x75fc, 2, 6, 1 },
|
||||
{ 0x1efb, 0x1eff, -0x1, 2, 6, 1 },
|
||||
{ 0x1fc3, 0x1ff3, 0x9, 48, 6, 1 },
|
||||
{ 0x1fcc, 0x1ffc, 0x0, 48, 6, 1 },
|
||||
{ 0x2c65, 0x2c65, -0x2a2b, 2, 6, 1 },
|
||||
{ 0x2c66, 0x2c66, -0x2a28, 2, 6, 1 },
|
||||
{ 0x2c73, 0x2c73, -0x1, 2, 6, 1 },
|
||||
{ 0xa641, 0xa65f, -0x1, 2, 6, 1 },
|
||||
{ 0xa663, 0xa66d, -0x1, 2, 6, 1 },
|
||||
{ 0xa681, 0xa697, -0x1, 2, 6, 1 },
|
||||
{ 0xa723, 0xa72f, -0x1, 2, 6, 1 },
|
||||
{ 0xa733, 0xa76f, -0x1, 2, 6, 1 },
|
||||
{ 0xa77a, 0xa77c, -0x1, 2, 6, 1 },
|
||||
{ 0xa77f, 0xa787, -0x1, 2, 6, 1 },
|
||||
{ 0xa78c, 0xa78c, -0x1, 2, 6, 1 },
|
||||
/* end mark */
|
||||
{ 0 }
|
||||
} ;
|
||||
|
||||
int i, r;
|
||||
int k, off;
|
||||
const struct NEWUPPERCASE *puc;
|
||||
|
||||
memset((char*)uc, 0, uc_len);
|
||||
uc_len >>= 1;
|
||||
@@ -1258,6 +1365,16 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
||||
k = uc_byte_table[r][1];
|
||||
uc[uc_byte_table[r][0]] = cpu_to_le16(k);
|
||||
}
|
||||
for (r=0; newuppercase[r].first; r++) {
|
||||
puc = &newuppercase[r];
|
||||
if ((puc->osmajor < UPCASE_MAJOR)
|
||||
|| ((puc->osmajor == UPCASE_MAJOR)
|
||||
&& (puc->osminor <= UPCASE_MINOR))) {
|
||||
off = puc->diff;
|
||||
for (i = puc->first; i <= puc->last; i += puc->step)
|
||||
uc[i] = cpu_to_le16(i + off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1319,12 +1436,12 @@ ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt)
|
||||
* @len: length of output buffer in Unicode characters
|
||||
*
|
||||
* Convert the input @s string into the corresponding little endian,
|
||||
* 2-byte Unicode string. The length of the converted string is less
|
||||
* 2-byte Unicode string. The length of the converted string is less
|
||||
* or equal to the maximum length allowed by the NTFS format (255).
|
||||
*
|
||||
* If @s is NULL then return AT_UNNAMED.
|
||||
*
|
||||
* On success the function returns the Unicode string in an allocated
|
||||
* On success the function returns the Unicode string in an allocated
|
||||
* buffer and the caller is responsible to free it when it's not needed
|
||||
* anymore.
|
||||
*
|
||||
@@ -1368,15 +1485,19 @@ void ntfs_ucsfree(ntfschar *ucs)
|
||||
* Check whether a name contains no chars forbidden
|
||||
* for DOS or Win32 use
|
||||
*
|
||||
* If @strict is TRUE, then trailing dots and spaces are forbidden.
|
||||
* These names are technically allowed in the Win32 namespace, but
|
||||
* they can be problematic. See comment for FILE_NAME_WIN32.
|
||||
*
|
||||
* If there is a bad char, errno is set to EINVAL
|
||||
*/
|
||||
|
||||
BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
||||
BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict)
|
||||
{
|
||||
BOOL forbidden;
|
||||
int ch;
|
||||
int i;
|
||||
u32 mainset = (1L << ('\"' - 0x20))
|
||||
static const u32 mainset = (1L << ('\"' - 0x20))
|
||||
| (1L << ('*' - 0x20))
|
||||
| (1L << ('/' - 0x20))
|
||||
| (1L << (':' - 0x20))
|
||||
@@ -1384,9 +1505,9 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
||||
| (1L << ('>' - 0x20))
|
||||
| (1L << ('?' - 0x20));
|
||||
|
||||
forbidden = (len == 0)
|
||||
|| (le16_to_cpu(name[len-1]) == ' ')
|
||||
|| (le16_to_cpu(name[len-1]) == '.');
|
||||
forbidden = (len == 0) ||
|
||||
(strict && (name[len-1] == const_cpu_to_le16(' ') ||
|
||||
name[len-1] == const_cpu_to_le16('.')));
|
||||
for (i=0; i<len; i++) {
|
||||
ch = le16_to_cpu(name[i]);
|
||||
if ((ch < 0x20)
|
||||
@@ -1401,6 +1522,97 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
||||
return (forbidden);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a name contains no forbidden chars and
|
||||
* is not a reserved name for DOS or Win32 use
|
||||
*
|
||||
* The reserved names are CON, PRN, AUX, NUL, COM1..COM9, LPT1..LPT9
|
||||
* with no suffix or any suffix.
|
||||
*
|
||||
* If @strict is TRUE, then trailing dots and spaces are forbidden.
|
||||
* These names are technically allowed in the Win32 namespace, but
|
||||
* they can be problematic. See comment for FILE_NAME_WIN32.
|
||||
*
|
||||
* If the name is forbidden, errno is set to EINVAL
|
||||
*/
|
||||
|
||||
BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len,
|
||||
BOOL strict)
|
||||
{
|
||||
BOOL forbidden;
|
||||
int h;
|
||||
static const ntfschar dot = const_cpu_to_le16('.');
|
||||
static const ntfschar con[] = { const_cpu_to_le16('c'),
|
||||
const_cpu_to_le16('o'), const_cpu_to_le16('n') };
|
||||
static const ntfschar prn[] = { const_cpu_to_le16('p'),
|
||||
const_cpu_to_le16('r'), const_cpu_to_le16('n') };
|
||||
static const ntfschar aux[] = { const_cpu_to_le16('a'),
|
||||
const_cpu_to_le16('u'), const_cpu_to_le16('x') };
|
||||
static const ntfschar nul[] = { const_cpu_to_le16('n'),
|
||||
const_cpu_to_le16('u'), const_cpu_to_le16('l') };
|
||||
static const ntfschar com[] = { const_cpu_to_le16('c'),
|
||||
const_cpu_to_le16('o'), const_cpu_to_le16('m') };
|
||||
static const ntfschar lpt[] = { const_cpu_to_le16('l'),
|
||||
const_cpu_to_le16('p'), const_cpu_to_le16('t') };
|
||||
|
||||
forbidden = ntfs_forbidden_chars(name, len, strict);
|
||||
if (!forbidden && (len >= 3)) {
|
||||
/*
|
||||
* Rough hash check to tell whether the first couple of chars
|
||||
* may be one of CO PR AU NU LP or lowercase variants.
|
||||
*/
|
||||
h = ((le16_to_cpu(name[0]) & 31)*48)
|
||||
^ ((le16_to_cpu(name[1]) & 31)*165);
|
||||
if ((h % 23) == 17) {
|
||||
/* do a full check, depending on the third char */
|
||||
switch (le16_to_cpu(name[2]) & ~0x20) {
|
||||
case 'N' :
|
||||
if (((len == 3) || (name[3] == dot))
|
||||
&& (!ntfs_ucsncasecmp(name, con, 3,
|
||||
vol->upcase, vol->upcase_len)
|
||||
|| !ntfs_ucsncasecmp(name, prn, 3,
|
||||
vol->upcase, vol->upcase_len)))
|
||||
forbidden = TRUE;
|
||||
break;
|
||||
case 'X' :
|
||||
if (((len == 3) || (name[3] == dot))
|
||||
&& !ntfs_ucsncasecmp(name, aux, 3,
|
||||
vol->upcase, vol->upcase_len))
|
||||
forbidden = TRUE;
|
||||
break;
|
||||
case 'L' :
|
||||
if (((len == 3) || (name[3] == dot))
|
||||
&& !ntfs_ucsncasecmp(name, nul, 3,
|
||||
vol->upcase, vol->upcase_len))
|
||||
forbidden = TRUE;
|
||||
break;
|
||||
case 'M' :
|
||||
if ((len > 3)
|
||||
&& (le16_to_cpu(name[3]) >= '1')
|
||||
&& (le16_to_cpu(name[3]) <= '9')
|
||||
&& ((len == 4) || (name[4] == dot))
|
||||
&& !ntfs_ucsncasecmp(name, com, 3,
|
||||
vol->upcase, vol->upcase_len))
|
||||
forbidden = TRUE;
|
||||
break;
|
||||
case 'T' :
|
||||
if ((len > 3)
|
||||
&& (le16_to_cpu(name[3]) >= '1')
|
||||
&& (le16_to_cpu(name[3]) <= '9')
|
||||
&& ((len == 4) || (name[4] == dot))
|
||||
&& !ntfs_ucsncasecmp(name, lpt, 3,
|
||||
vol->upcase, vol->upcase_len))
|
||||
forbidden = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forbidden)
|
||||
errno = EINVAL;
|
||||
return (forbidden);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the same name can be used as a DOS and
|
||||
* a Win32 name
|
||||
@@ -1443,9 +1655,12 @@ int ntfs_set_char_encoding(const char *locale)
|
||||
|| strstr(locale,"utf-8") || strstr(locale,"UTF-8"))
|
||||
use_utf8 = 1;
|
||||
else
|
||||
#ifndef __HAIKU__
|
||||
if (setlocale(LC_ALL, locale))
|
||||
use_utf8 = 0;
|
||||
else {
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ntfs_log_error("Invalid locale, encoding to UTF-8\n");
|
||||
use_utf8 = 1;
|
||||
}
|
||||
@@ -1456,75 +1671,95 @@ int ntfs_set_char_encoding(const char *locale)
|
||||
|
||||
int ntfs_macosx_normalize_filenames(int normalize) {
|
||||
#ifdef ENABLE_NFCONV
|
||||
if(normalize == 0 || normalize == 1) {
|
||||
if (normalize == 0 || normalize == 1) {
|
||||
nfconvert_utf8 = normalize;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif /* ENABLE_NFCONV */
|
||||
}
|
||||
}
|
||||
|
||||
int ntfs_macosx_normalize_utf8(const char *utf8_string, char **target,
|
||||
int composed) {
|
||||
int composed)
|
||||
{
|
||||
#ifdef ENABLE_NFCONV
|
||||
/* For this code to compile, the CoreFoundation framework must be fed to the linker. */
|
||||
/* For this code to compile, the CoreFoundation framework must be fed to
|
||||
* the linker. */
|
||||
CFStringRef cfSourceString;
|
||||
CFMutableStringRef cfMutableString;
|
||||
CFRange rangeToProcess;
|
||||
CFIndex requiredBufferLength;
|
||||
char *result = NULL;
|
||||
int resultLength = -1;
|
||||
|
||||
|
||||
/* Convert the UTF-8 string to a CFString. */
|
||||
cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault, utf8_string, kCFStringEncodingUTF8);
|
||||
if(cfSourceString == NULL) {
|
||||
cfSourceString = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
utf8_string, kCFStringEncodingUTF8);
|
||||
if (cfSourceString == NULL) {
|
||||
ntfs_log_error("CFStringCreateWithCString failed!\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Create a mutable string from cfSourceString that we are free to modify. */
|
||||
cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfSourceString);
|
||||
|
||||
/* Create a mutable string from cfSourceString that we are free to
|
||||
* modify. */
|
||||
cfMutableString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
|
||||
cfSourceString);
|
||||
CFRelease(cfSourceString); /* End-of-life. */
|
||||
if(cfMutableString == NULL) {
|
||||
if (cfMutableString == NULL) {
|
||||
ntfs_log_error("CFStringCreateMutableCopy failed!\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
/* Normalize the mutable string to the desired normalization form. */
|
||||
CFStringNormalize(cfMutableString, (composed != 0 ? kCFStringNormalizationFormC : kCFStringNormalizationFormD));
|
||||
|
||||
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char* buffer. */
|
||||
CFStringNormalize(cfMutableString, (composed != 0 ?
|
||||
kCFStringNormalizationFormC : kCFStringNormalizationFormD));
|
||||
|
||||
/* Store the resulting string in a '\0'-terminated UTF-8 encoded char*
|
||||
* buffer. */
|
||||
rangeToProcess = CFRangeMake(0, CFStringGetLength(cfMutableString));
|
||||
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8, 0, false, NULL, 0, &requiredBufferLength) > 0) {
|
||||
resultLength = sizeof(char)*(requiredBufferLength + 1);
|
||||
if (CFStringGetBytes(cfMutableString, rangeToProcess,
|
||||
kCFStringEncodingUTF8, 0, false, NULL, 0,
|
||||
&requiredBufferLength) > 0)
|
||||
{
|
||||
resultLength = sizeof(char) * (requiredBufferLength + 1);
|
||||
result = ntfs_calloc(resultLength);
|
||||
|
||||
if(result != NULL) {
|
||||
if(CFStringGetBytes(cfMutableString, rangeToProcess, kCFStringEncodingUTF8,
|
||||
0, false, (UInt8*)result, resultLength-1, &requiredBufferLength) <= 0) {
|
||||
ntfs_log_error("Could not perform UTF-8 conversion of normalized CFMutableString.\n");
|
||||
|
||||
if (result != NULL) {
|
||||
if (CFStringGetBytes(cfMutableString, rangeToProcess,
|
||||
kCFStringEncodingUTF8, 0, false,
|
||||
(UInt8*) result, resultLength - 1,
|
||||
&requiredBufferLength) <= 0)
|
||||
{
|
||||
ntfs_log_error("Could not perform UTF-8 "
|
||||
"conversion of normalized "
|
||||
"CFMutableString.\n");
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
ntfs_log_error("Could not perform a ntfs_calloc of %d bytes for char *result.\n", resultLength);
|
||||
else {
|
||||
ntfs_log_error("Could not perform a ntfs_calloc of %d "
|
||||
"bytes for char *result.\n", resultLength);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ntfs_log_error("Could not perform check for required length of "
|
||||
"UTF-8 conversion of normalized CFMutableString.\n");
|
||||
}
|
||||
else
|
||||
ntfs_log_error("Could not perform check for required length of UTF-8 conversion of normalized CFMutableString.\n");
|
||||
|
||||
|
||||
CFRelease(cfMutableString);
|
||||
|
||||
if(result != NULL) {
|
||||
|
||||
if (result != NULL) {
|
||||
*target = result;
|
||||
return resultLength - 1;
|
||||
}
|
||||
else
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif /* ENABLE_NFCONV */
|
||||
|
||||
@@ -68,7 +68,9 @@ extern ntfschar *ntfs_str2ucs(const char *s, int *len);
|
||||
|
||||
extern void ntfs_ucsfree(ntfschar *ucs);
|
||||
|
||||
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len);
|
||||
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict);
|
||||
extern BOOL ntfs_forbidden_names(ntfs_volume *vol,
|
||||
const ntfschar *name, int len, BOOL strict);
|
||||
extern BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen);
|
||||
|
||||
@@ -74,8 +74,9 @@
|
||||
#include "cache.h"
|
||||
#include "realpath.h"
|
||||
#include "misc.h"
|
||||
#include "security.h"
|
||||
|
||||
const char *ntfs_home =
|
||||
const char *ntfs_home =
|
||||
"News, support and information: http://tuxera.com\n";
|
||||
|
||||
static const char *invalid_ntfs_msg =
|
||||
@@ -97,6 +98,11 @@ static const char *hibernated_volume_msg =
|
||||
"Windows fully (no hibernation or fast restarting), or mount the volume\n"
|
||||
"read-only with the 'ro' mount option.\n";
|
||||
|
||||
static const char *fallback_readonly_msg =
|
||||
"Falling back to read-only mount because the NTFS partition is in an\n"
|
||||
"unsafe state. Please resume and shutdown Windows fully (no hibernation\n"
|
||||
"or fast restarting.)\n";
|
||||
|
||||
static const char *unclean_journal_msg =
|
||||
"Write access is denied because the disk wasn't safely powered\n"
|
||||
"off and the 'norecover' mount option was specified.\n";
|
||||
@@ -108,7 +114,7 @@ static const char *opened_volume_msg =
|
||||
|
||||
static const char *fakeraid_msg =
|
||||
"Either the device is missing or it's powered down, or you have\n"
|
||||
"SoftRAID hardware and must use an activated, different device under\n"
|
||||
"SoftRAID hardware and must use an activated, different device under\n"
|
||||
"/dev/mapper/, (e.g. /dev/mapper/nvidia_eahaabcc1) to mount NTFS.\n"
|
||||
"Please see the 'dmraid' documentation for help.\n";
|
||||
|
||||
@@ -144,8 +150,8 @@ static int ntfs_inode_free(ntfs_inode **ni)
|
||||
if (ni && *ni) {
|
||||
ret = ntfs_inode_close(*ni);
|
||||
*ni = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -167,9 +173,12 @@ static int __ntfs_volume_release(ntfs_volume *v)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ntfs_close_secure(v))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
if (ntfs_inode_free(&v->vol_ni))
|
||||
ntfs_error_set(&err);
|
||||
/*
|
||||
/*
|
||||
* FIXME: Inodes must be synced before closing
|
||||
* attributes, otherwise unmount could fail.
|
||||
*/
|
||||
@@ -178,20 +187,20 @@ static int __ntfs_volume_release(ntfs_volume *v)
|
||||
ntfs_attr_free(&v->lcnbmp_na);
|
||||
if (ntfs_inode_free(&v->lcnbmp_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
|
||||
if (v->mft_ni && NInoDirty(v->mft_ni))
|
||||
ntfs_inode_sync(v->mft_ni);
|
||||
ntfs_attr_free(&v->mftbmp_na);
|
||||
ntfs_attr_free(&v->mft_na);
|
||||
if (ntfs_inode_free(&v->mft_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
|
||||
if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
|
||||
ntfs_inode_sync(v->mftmirr_ni);
|
||||
ntfs_attr_free(&v->mftmirr_na);
|
||||
if (ntfs_inode_free(&v->mftmirr_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
|
||||
if (v->dev) {
|
||||
struct ntfs_device *dev = v->dev;
|
||||
|
||||
@@ -260,10 +269,10 @@ static int ntfs_mft_load(ntfs_volume *vol)
|
||||
ntfs_log_perror("Error reading $MFT");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
if (ntfs_mft_record_check(vol, 0, mb))
|
||||
goto error_exit;
|
||||
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(vol->mft_ni, NULL);
|
||||
if (!ctx)
|
||||
goto error_exit;
|
||||
@@ -288,7 +297,7 @@ static int ntfs_mft_load(ntfs_volume *vol)
|
||||
vol->mft_ni->attr_list = ntfs_malloc(l);
|
||||
if (!vol->mft_ni->attr_list)
|
||||
goto error_exit;
|
||||
|
||||
|
||||
l = ntfs_get_attribute_value(vol, ctx->attr, vol->mft_ni->attr_list);
|
||||
if (!l) {
|
||||
ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
|
||||
@@ -304,9 +313,9 @@ static int ntfs_mft_load(ntfs_volume *vol)
|
||||
mft_has_no_attr_list:
|
||||
|
||||
ntfs_attr_setup_flag(vol->mft_ni);
|
||||
|
||||
|
||||
/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
|
||||
|
||||
|
||||
/* Get an ntfs attribute for $MFT/$DATA and set it up, too. */
|
||||
vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!vol->mft_na) {
|
||||
@@ -428,18 +437,18 @@ static int ntfs_mftmirr_load(ntfs_volume *vol)
|
||||
ntfs_log_perror("Failed to open inode $MFTMirr");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!vol->mftmirr_na) {
|
||||
ntfs_log_perror("Failed to open $MFTMirr/$DATA");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
if (ntfs_attr_map_runlist(vol->mftmirr_na, 0) < 0) {
|
||||
ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
error_exit:
|
||||
@@ -484,12 +493,12 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
bs = ntfs_malloc(sizeof(NTFS_BOOT_SECTOR));
|
||||
if (!bs)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* Allocate the volume structure. */
|
||||
vol = ntfs_volume_alloc();
|
||||
if (!vol)
|
||||
goto error_exit;
|
||||
|
||||
|
||||
/* Create the default upcase table. */
|
||||
vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
|
||||
if (!vol->upcase_len || !vol->upcase)
|
||||
@@ -498,7 +507,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
/* Default with no locase table and case sensitive file names */
|
||||
vol->locase = (ntfschar*)NULL;
|
||||
NVolSetCaseSensitive(vol);
|
||||
|
||||
|
||||
/* by default, all files are shown and not marked hidden */
|
||||
NVolSetShowSysFiles(vol);
|
||||
NVolSetShowHidFiles(vol);
|
||||
@@ -511,7 +520,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
#endif
|
||||
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)) {
|
||||
if (!NVolReadOnly(vol) && (errno == EROFS)) {
|
||||
@@ -531,7 +540,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
}
|
||||
/* Attach the device to the volume. */
|
||||
vol->dev = dev;
|
||||
|
||||
|
||||
/* Now read the bootsector. */
|
||||
br = ntfs_pread(dev, 0, sizeof(NTFS_BOOT_SECTOR), bs);
|
||||
if (br != sizeof(NTFS_BOOT_SECTOR)) {
|
||||
@@ -549,7 +558,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
}
|
||||
if (ntfs_boot_sector_parse(vol, bs) < 0)
|
||||
goto error_exit;
|
||||
|
||||
|
||||
free(bs);
|
||||
bs = NULL;
|
||||
/* Now set the device block size to the sector size. */
|
||||
@@ -558,7 +567,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
"sector size. This may affect performance "
|
||||
"but should be harmless otherwise. Error: "
|
||||
"%s\n", strerror(errno));
|
||||
|
||||
|
||||
/* We now initialize the cluster allocator. */
|
||||
vol->full_zones = 0;
|
||||
mft_zone_size = vol->nr_clusters >> 3; /* 12.5% */
|
||||
@@ -652,14 +661,14 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
|
||||
err = EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
|
||||
err = EOPNOTSUPP;
|
||||
/*
|
||||
@@ -682,7 +691,7 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol)
|
||||
}
|
||||
free(rp);
|
||||
ntfs_attr_close(na);
|
||||
out:
|
||||
out:
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_error_set(&err);
|
||||
if (err) {
|
||||
@@ -910,10 +919,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
ATTR_RECORD *a;
|
||||
VOLUME_INFORMATION *vinf;
|
||||
ntfschar *vname;
|
||||
u32 record_size;
|
||||
int i, j, eo;
|
||||
unsigned int k;
|
||||
u32 u;
|
||||
BOOL need_fallback_ro;
|
||||
|
||||
need_fallback_ro = FALSE;
|
||||
vol = ntfs_volume_startup(dev, flags);
|
||||
if (!vol)
|
||||
return NULL;
|
||||
@@ -963,13 +975,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
|
||||
mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
|
||||
if (mrec->flags & MFT_RECORD_IN_USE) {
|
||||
if (ntfs_is_baad_recordp(mrec)) {
|
||||
if (ntfs_is_baad_record(mrec->magic)) {
|
||||
ntfs_log_error("$MFT error: Incomplete multi "
|
||||
"sector transfer detected in "
|
||||
"'%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
if (!ntfs_is_mft_recordp(mrec)) {
|
||||
if (!ntfs_is_mft_record(mrec->magic)) {
|
||||
ntfs_log_error("$MFT error: Invalid mft "
|
||||
"record for '%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
@@ -977,19 +989,22 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
}
|
||||
mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
|
||||
if (mrec2->flags & MFT_RECORD_IN_USE) {
|
||||
if (ntfs_is_baad_recordp(mrec2)) {
|
||||
if (ntfs_is_baad_record(mrec2->magic)) {
|
||||
ntfs_log_error("$MFTMirr error: Incomplete "
|
||||
"multi sector transfer "
|
||||
"detected in '%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
if (!ntfs_is_mft_recordp(mrec2)) {
|
||||
if (!ntfs_is_mft_record(mrec2->magic)) {
|
||||
ntfs_log_error("$MFTMirr error: Invalid mft "
|
||||
"record for '%s'.\n", s);
|
||||
goto io_error_exit;
|
||||
}
|
||||
}
|
||||
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
|
||||
record_size = ntfs_mft_record_get_data_size(mrec);
|
||||
if ((record_size <= sizeof(MFT_RECORD))
|
||||
|| (record_size > vol->mft_record_size)
|
||||
|| memcmp(mrec, mrec2, record_size)) {
|
||||
ntfs_log_error("$MFTMirr does not match $MFT (record "
|
||||
"%d).\n", i);
|
||||
goto io_error_exit;
|
||||
@@ -1007,16 +1022,16 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
ntfs_log_perror("Failed to open inode FILE_Bitmap");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!vol->lcnbmp_na) {
|
||||
ntfs_log_perror("Failed to open ntfs attribute");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
if (vol->lcnbmp_na->data_size > vol->lcnbmp_na->allocated_size) {
|
||||
ntfs_log_error("Corrupt cluster map size (%lld > %lld)\n",
|
||||
(long long)vol->lcnbmp_na->data_size,
|
||||
(long long)vol->lcnbmp_na->data_size,
|
||||
(long long)vol->lcnbmp_na->allocated_size);
|
||||
goto io_error_exit;
|
||||
}
|
||||
@@ -1172,7 +1187,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
vol->vol_name = ntfs_malloc(u + 1);
|
||||
if (!vol->vol_name)
|
||||
goto error_exit;
|
||||
|
||||
|
||||
for (j = 0; j < (s32)u; j++) {
|
||||
u16 uc = le16_to_cpu(vname[j]);
|
||||
if (uc > 0xff)
|
||||
@@ -1223,26 +1238,46 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
ntfs_log_perror("Failed to close $AttrDef");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Open $Secure. */
|
||||
if (ntfs_open_secure(vol))
|
||||
goto error_exit;
|
||||
|
||||
/*
|
||||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
*/
|
||||
if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) {
|
||||
if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) &&
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0)
|
||||
goto error_exit;
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0) {
|
||||
if (flags & NTFS_MNT_MAY_RDONLY)
|
||||
need_fallback_ro = TRUE;
|
||||
else
|
||||
goto error_exit;
|
||||
}
|
||||
if (ntfs_volume_check_logfile(vol) < 0) {
|
||||
/* 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");
|
||||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM)) {
|
||||
if (flags & NTFS_MNT_MAY_RDONLY)
|
||||
need_fallback_ro = TRUE;
|
||||
else
|
||||
goto error_exit;
|
||||
} else {
|
||||
ntfs_log_info("The file system wasn't safely "
|
||||
"closed on Windows. Fixing.\n");
|
||||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
/* make $TXF_DATA resident if present on the root directory */
|
||||
if (fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
if (!(flags & NTFS_MNT_RDONLY) && !need_fallback_ro) {
|
||||
if (fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
if (need_fallback_ro) {
|
||||
NVolSetReadOnly(vol);
|
||||
ntfs_log_error("%s", fallback_readonly_msg);
|
||||
}
|
||||
|
||||
return vol;
|
||||
@@ -1640,7 +1675,7 @@ int ntfs_logfile_reset(ntfs_volume *vol)
|
||||
ntfs_attr_close(na);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
ntfs_attr_close(na);
|
||||
return ntfs_inode_close(ni);
|
||||
|
||||
|
||||
@@ -36,9 +36,7 @@
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
/* Do not #include <sys/mount.h> here : conflicts with <linux/fs.h> */
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
@@ -62,6 +60,7 @@ typedef struct _ntfs_volume ntfs_volume;
|
||||
enum {
|
||||
NTFS_MNT_NONE = 0x00000000,
|
||||
NTFS_MNT_RDONLY = 0x00000001,
|
||||
NTFS_MNT_MAY_RDONLY = 0x02000000, /* Allow fallback to ro */
|
||||
NTFS_MNT_FORENSIC = 0x04000000, /* No modification during
|
||||
* mount. */
|
||||
NTFS_MNT_EXCLUSIVE = 0x08000000,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2003-2004 Lode Leroy
|
||||
* Copyright (c) 2003-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yuval Fledel
|
||||
* Copyright (c) 2012-2013 Jean-Pierre Andre
|
||||
* Copyright (c) 2012-2014 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
|
||||
@@ -150,6 +150,7 @@ enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx *
|
||||
STATUS_FILE_NOT_FOUND = 0xC0000028,
|
||||
STATUS_OBJECT_NAME_INVALID = 0xC0000033,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||
STATUS_SHARING_VIOLATION = 0xC0000043,
|
||||
STATUS_INVALID_PARAMETER_1 = 0xC00000EF,
|
||||
STATUS_IO_DEVICE_ERROR = 0xC0000185,
|
||||
STATUS_GUARD_PAGE_VIOLATION = 0x80000001
|
||||
@@ -354,6 +355,8 @@ static int ntfs_ntstatus_to_errno(NTSTATUS status)
|
||||
case STATUS_IO_DEVICE_ERROR :
|
||||
case STATUS_END_OF_FILE :
|
||||
return (EIO);
|
||||
case STATUS_SHARING_VIOLATION :
|
||||
return (EBUSY);
|
||||
default:
|
||||
/* generic message */
|
||||
return ENOMSG;
|
||||
@@ -1547,6 +1550,7 @@ static int ntfs_device_win32_close(struct ntfs_device *dev)
|
||||
rvl = NtClose(fd->handle) == STATUS_SUCCESS;
|
||||
} else
|
||||
rvl = CloseHandle(fd->handle);
|
||||
NDevClearOpen(dev);
|
||||
free(fd);
|
||||
if (!rvl) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
@@ -1633,7 +1637,8 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
{
|
||||
s64 old_pos, to_write, i, bw = 0;
|
||||
win32_fd *fd = (win32_fd *)dev->d_private;
|
||||
BYTE *alignedbuffer;
|
||||
const BYTE *alignedbuffer;
|
||||
BYTE *readbuffer;
|
||||
int old_ofs, ofs;
|
||||
|
||||
old_pos = fd->pos;
|
||||
@@ -1658,15 +1663,16 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
if (!count)
|
||||
return 0;
|
||||
NDevSetDirty(dev);
|
||||
readbuffer = (BYTE*)NULL;
|
||||
if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
|
||||
!(count & (fd->geo_sector_size - 1)))
|
||||
alignedbuffer = (BYTE *)b;
|
||||
alignedbuffer = (const BYTE *)b;
|
||||
else {
|
||||
s64 end;
|
||||
|
||||
alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
|
||||
readbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
|
||||
MEM_COMMIT, PAGE_READWRITE);
|
||||
if (!alignedbuffer) {
|
||||
if (!readbuffer) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("VirtualAlloc failed for write.\n");
|
||||
return -1;
|
||||
@@ -1675,7 +1681,7 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
if (ofs) {
|
||||
i = ntfs_device_win32_pread_simple(fd,
|
||||
old_pos & ~(s64)(fd->geo_sector_size - 1),
|
||||
fd->geo_sector_size, alignedbuffer);
|
||||
fd->geo_sector_size, readbuffer);
|
||||
if (i != fd->geo_sector_size) {
|
||||
if (i >= 0)
|
||||
errno = EIO;
|
||||
@@ -1693,7 +1699,7 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
((to_write > fd->geo_sector_size) || !ofs)) {
|
||||
i = ntfs_device_win32_pread_simple(fd,
|
||||
end & ~(s64)(fd->geo_sector_size - 1),
|
||||
fd->geo_sector_size, alignedbuffer +
|
||||
fd->geo_sector_size, readbuffer +
|
||||
to_write - fd->geo_sector_size);
|
||||
if (i != fd->geo_sector_size) {
|
||||
if (i >= 0)
|
||||
@@ -1701,8 +1707,9 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
/* Copy the data to be written into @alignedbuffer. */
|
||||
memcpy(alignedbuffer + ofs, b, count);
|
||||
/* Copy the data to be written into @readbuffer. */
|
||||
memcpy(readbuffer + ofs, b, count);
|
||||
alignedbuffer = readbuffer;
|
||||
}
|
||||
if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
|
||||
s64 vol_to_write = fd->geo_size - old_pos;
|
||||
@@ -1740,8 +1747,8 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
||||
bw = count;
|
||||
fd->pos = old_pos + bw;
|
||||
write_partial:
|
||||
if (alignedbuffer != b)
|
||||
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
||||
if (readbuffer)
|
||||
VirtualFree(readbuffer, 0, MEM_RELEASE);
|
||||
return bw;
|
||||
write_error:
|
||||
bw = -1;
|
||||
@@ -1877,7 +1884,11 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
|
||||
#ifdef BLKSSZGET
|
||||
case BLKSSZGET:
|
||||
ntfs_log_debug("BLKSSZGET detected.\n");
|
||||
return ntfs_win32_blksszget(dev, (int *)argp);
|
||||
if (fd && !fd->ntdll) {
|
||||
*(int*)argp = fd->geo_sector_size;
|
||||
return (0);
|
||||
} else
|
||||
return ntfs_win32_blksszget(dev, (int *)argp);
|
||||
#endif
|
||||
#ifdef BLKBSZSET
|
||||
case BLKBSZSET:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* xattrs.c : common functions to deal with system extended attributes
|
||||
*
|
||||
* Copyright (c) 2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2010-2014 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
|
||||
@@ -23,8 +23,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes support required */
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
@@ -55,6 +53,7 @@
|
||||
#include "efs.h"
|
||||
#include "reparse.h"
|
||||
#include "object_id.h"
|
||||
#include "ea.h"
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
#include "xattrs.h"
|
||||
@@ -82,10 +81,6 @@ struct LE_POSIX_ACL {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
static const char nf_ns_user_prefix[] = "user.";
|
||||
static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
|
||||
|
||||
static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
|
||||
static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
|
||||
static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be";
|
||||
@@ -97,6 +92,7 @@ static const char nf_ns_xattr_times[] = "system.ntfs_times";
|
||||
static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be";
|
||||
static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime";
|
||||
static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be";
|
||||
static const char nf_ns_xattr_ea[] = "system.ntfs_ea";
|
||||
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
|
||||
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
|
||||
|
||||
@@ -119,6 +115,7 @@ static struct XATTRNAME nf_ns_xattr_names[] = {
|
||||
{ XATTR_NTFS_TIMES_BE, nf_ns_xattr_times_be },
|
||||
{ XATTR_NTFS_CRTIME, nf_ns_xattr_crtime },
|
||||
{ XATTR_NTFS_CRTIME_BE, nf_ns_xattr_crtime_be },
|
||||
{ XATTR_NTFS_EA, nf_ns_xattr_ea },
|
||||
{ XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
|
||||
{ XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
|
||||
{ XATTR_UNMAPPED, (char*)NULL } /* terminator */
|
||||
@@ -473,7 +470,6 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping)
|
||||
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
|
||||
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
@@ -589,6 +585,9 @@ int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
if ((res >= (int)sizeof(u64)) && value)
|
||||
fix_big_endian(value,sizeof(u64));
|
||||
break;
|
||||
case XATTR_NTFS_EA :
|
||||
res = ntfs_get_ntfs_ea(ni, value, size);
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
@@ -712,6 +711,9 @@ int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx,
|
||||
} else
|
||||
res = ntfs_inode_set_times(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_EA :
|
||||
res = ntfs_set_ntfs_ea(ni, value, size, flags);
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
@@ -780,6 +782,9 @@ int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_NTFS_EA :
|
||||
res = ntfs_remove_ntfs_ea(ni);
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
@@ -787,5 +792,3 @@ int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
@@ -19,8 +19,27 @@
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_XATTR_H_
|
||||
#define _NTFS_XATTR_H_
|
||||
#ifndef _NTFS_XATTRS_H_
|
||||
#define _NTFS_XATTRS_H_
|
||||
|
||||
/*
|
||||
* Flags that modify setxattr() semantics. These flags are also used by a
|
||||
* number of libntfs-3g functions, such as ntfs_set_ntfs_acl(), which were
|
||||
* originally tied to extended attributes support but now can be used by
|
||||
* applications even if the platform does not support extended attributes.
|
||||
*
|
||||
* Careful: applications including this header should define HAVE_SETXATTR or
|
||||
* HAVE_SYS_XATTR_H if the platform supports extended attributes. Otherwise the
|
||||
* defined flags values may be incorrect (they will be correct for Linux but not
|
||||
* necessarily for other platforms).
|
||||
*/
|
||||
#if defined(HAVE_SETXATTR) || defined(HAVE_SYS_XATTR_H)
|
||||
#include <sys/xattr.h>
|
||||
#else
|
||||
#include "compat.h" /* may be needed for ENODATA definition */
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_REPLACE 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Identification of data mapped to the system name space
|
||||
@@ -39,6 +58,7 @@ enum SYSTEMXATTRS {
|
||||
XATTR_NTFS_TIMES_BE,
|
||||
XATTR_NTFS_CRTIME,
|
||||
XATTR_NTFS_CRTIME_BE,
|
||||
XATTR_NTFS_EA,
|
||||
XATTR_POSIX_ACC,
|
||||
XATTR_POSIX_DEF
|
||||
} ;
|
||||
@@ -60,6 +80,8 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
|
||||
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
|
||||
ntfs_volume *vol);
|
||||
|
||||
struct SECURITY_CONTEXT;
|
||||
|
||||
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
@@ -72,4 +94,4 @@ int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#endif /* _NTFS_XATTR_H_ */
|
||||
#endif /* _NTFS_XATTRS_H_ */
|
||||
|
||||
Reference in New Issue
Block a user