Implemented an extended attribute to get/set EAs
The new extended attribute "system.ntfs_ea" can now be used to get or set the set of EAs of a file or directory.edge.strict_endians
parent
f3c4c6c604
commit
ae459dd7b3
|
@ -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,6 +39,7 @@ enum SYSTEMXATTRS {
|
|||
XATTR_NTFS_TIMES_BE,
|
||||
XATTR_NTFS_CRTIME,
|
||||
XATTR_NTFS_CRTIME_BE,
|
||||
XATTR_NTFS_EA,
|
||||
XATTR_POSIX_ACC,
|
||||
XATTR_POSIX_DEF
|
||||
} ;
|
||||
|
|
|
@ -27,6 +27,7 @@ libntfs_3g_la_SOURCES = \
|
|||
debug.c \
|
||||
device.c \
|
||||
dir.c \
|
||||
ea.c \
|
||||
efs.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
/**
|
||||
* 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_SETXATTR /* extended attributes support required */
|
||||
|
||||
#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
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.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"
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2008-2013 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
|
||||
|
@ -1117,7 +1117,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,
|
||||
|
|
|
@ -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
|
||||
|
@ -55,6 +55,7 @@
|
|||
#include "efs.h"
|
||||
#include "reparse.h"
|
||||
#include "object_id.h"
|
||||
#include "ea.h"
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
#include "xattrs.h"
|
||||
|
@ -97,6 +98,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 +121,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 +476,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 +591,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 +717,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 +788,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;
|
||||
|
|
|
@ -1979,9 +1979,12 @@ static void ntfs_dump_attr_ea_information(ATTR_RECORD *attr)
|
|||
*/
|
||||
static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol)
|
||||
{
|
||||
EA_ATTR *ea;
|
||||
const EA_ATTR *ea;
|
||||
const u8 *pvalue;
|
||||
u8 *buf = NULL;
|
||||
le32 *pval;
|
||||
const le32 *pval;
|
||||
int offset;
|
||||
int cnt;
|
||||
s64 data_size;
|
||||
|
||||
if (attr->non_resident) {
|
||||
|
@ -2019,6 +2022,7 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol)
|
|||
return;
|
||||
ea = (EA_ATTR*)((u8*)attr + le16_to_cpu(attr->value_offset));
|
||||
}
|
||||
offset = 0;
|
||||
while (1) {
|
||||
printf("\n\tEA flags:\t\t ");
|
||||
if (ea->flags) {
|
||||
|
@ -2035,21 +2039,36 @@ static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol)
|
|||
printf("\tValue length:\t %d (0x%x)\n",
|
||||
(unsigned)le16_to_cpu(ea->value_length),
|
||||
(unsigned)le16_to_cpu(ea->value_length));
|
||||
/* Name expected to be null terminated ? */
|
||||
printf("\tName:\t\t '%s'\n", ea->name);
|
||||
printf("\tValue:\t\t ");
|
||||
if (ea->name_length == 11 &&
|
||||
!strncmp((const char*)"SETFILEBITS",
|
||||
(const char*)ea->name, 11)) {
|
||||
pval = (le32*)(ea->value + ea->name_length + 1);
|
||||
pval = (const le32*)(ea->value + ea->name_length + 1);
|
||||
printf("0%lo\n", (unsigned long)le32_to_cpu(*pval));
|
||||
} else {
|
||||
/* No alignment for value */
|
||||
pvalue = ea->value + ea->name_length + 1;
|
||||
/* Hex show a maximum of 32 bytes */
|
||||
cnt = le16_to_cpu(ea->value_length);
|
||||
printf(cnt ? "0x" : "(NONE)");
|
||||
if (cnt > 32)
|
||||
cnt = 32;
|
||||
while (cnt-- > 0)
|
||||
printf("%02x",*pvalue++);
|
||||
if (le16_to_cpu(ea->value_length) > 32)
|
||||
printf("...\n");
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
if (ea->next_entry_offset) {
|
||||
offset += le32_to_cpu(ea->next_entry_offset);
|
||||
ea = (const EA_ATTR*)((const u8*)ea
|
||||
+ le32_to_cpu(ea->next_entry_offset));
|
||||
} else
|
||||
printf("'%s'\n", ea->value + ea->name_length + 1);
|
||||
if (ea->next_entry_offset)
|
||||
ea = (EA_ATTR*)((u8*)ea +
|
||||
le32_to_cpu(ea->next_entry_offset));
|
||||
else
|
||||
break;
|
||||
if ((u8*)ea - buf >= data_size)
|
||||
if (offset >= data_size)
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
|
|
Loading…
Reference in New Issue