usbloadergx/libcustomntfs/efs.c
dimok321 0f17471b27 *Removed ntfs/fat source and added them as custom libs (makes them easier to update later)
*Added sources of the custom libs to the branches
*Fixed crash when switching from list layout to grid/carousel layout
*Removed 1:1 copy option because its meaningless and almost the same as installing all partitions
*Fixed install partition selection. This option needs a reset. Go to settings and reselect your option for this.
*Fixed schinese and tchinese language modes (filename bugs. has to be schinese.lang and tchinese.lang like on SVN)
*Fixed bug in sound buffer circle
*Fixed incorrect behaviour of x-flip when selecting system like (thx Cyan for the patch)
*Accept ios revision 65535 for Waninkokos IOSes (thx to PPSainity for pointing it out)
*Merged the new theming style branch into trunk. Just as a reminder: ALL old themes will not work until the themers did port it to the new style!
*Removed old theme style completely

Theme example:
The example file of the theme is the Default.them file. It can be found in the SVN trunk.

Change in loading of themes:
When selecting a theme now a list of all .them files in a folder is displayed. The image folder of that theme has to be in the same folder as the .them file. The image path is defined in the head of the .them file in the line with "Image-Folder: Example\n".
2010-12-26 17:02:14 +00:00

440 lines
11 KiB
C

/**
* efs.c - Limited processing of encrypted files
*
* This module is part of ntfs-3g library
*
* Copyright (c) 2009 Martin Bene
* Copyright (c) 2009-2010 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_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#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
#include "types.h"
#include "debug.h"
#include "attrib.h"
#include "inode.h"
#include "dir.h"
#include "efs.h"
#include "index.h"
#include "logging.h"
#include "misc.h"
#include "efs.h"
#ifdef HAVE_SETXATTR /* extended attributes interface required */
static ntfschar logged_utility_stream_name[] = {
const_cpu_to_le16('$'),
const_cpu_to_le16('E'),
const_cpu_to_le16('F'),
const_cpu_to_le16('S'),
const_cpu_to_le16(0)
} ;
/*
* Get the ntfs EFS info into an extended attribute
*/
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
{
EFS_ATTR_HEADER *efs_info;
s64 attr_size = 0;
if (ni) {
if (ni->flags & FILE_ATTR_ENCRYPTED) {
efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
&attr_size);
if (efs_info
&& (le32_to_cpu(efs_info->length) == attr_size)) {
if (attr_size <= (s64)size) {
if (value)
memcpy(value,efs_info,attr_size);
else {
errno = EFAULT;
attr_size = 0;
}
} else
if (size) {
errno = ERANGE;
attr_size = 0;
}
free (efs_info);
} else {
if (efs_info) {
free(efs_info);
ntfs_log_error("Bad efs_info for inode %lld\n",
(long long)ni->mft_no);
} else {
ntfs_log_error("Could not get efsinfo"
" for inode %lld\n",
(long long)ni->mft_no);
}
errno = EIO;
attr_size = 0;
}
} else {
errno = ENODATA;
ntfs_log_trace("Inode %lld is not encrypted\n",
(long long)ni->mft_no);
}
}
return (attr_size ? (int)attr_size : -errno);
}
/*
* Fix all encrypted AT_DATA attributes of an inode
*
* The fix may require making an attribute non resident, which
* requires more space in the MFT record, and may cause some
* attribute to be expelled and the full record to be reorganized.
* When this happens, the search for data attributes has to be
* reinitialized.
*
* Returns zero if successful.
* -1 if there is a problem.
*/
static int fixup_loop(ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
ntfs_attr *na;
ATTR_RECORD *a;
BOOL restart;
BOOL first;
int cnt;
int maxcnt;
int res = 0;
maxcnt = 0;
do {
restart = FALSE;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
ntfs_log_error("Failed to get ctx for efs\n");
res = -1;
}
cnt = 0;
while (!restart && !res
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
cnt++;
a = ctx->attr;
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
a->name_length);
if (!na) {
ntfs_log_error("can't open DATA Attribute\n");
res = -1;
}
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
if (!NAttrNonResident(na)
&& ntfs_attr_make_non_resident(na, ctx)) {
/*
* ntfs_attr_make_non_resident fails if there
* is not enough space in the MFT record.
* When this happens, force making non-resident
* so that some other attribute is expelled.
*/
if (ntfs_attr_force_non_resident(na)) {
res = -1;
} else {
/* make sure there is some progress */
if (cnt <= maxcnt) {
errno = EIO;
ntfs_log_error("Multiple failure"
" making non resident\n");
res = -1;
} else {
ntfs_attr_put_search_ctx(ctx);
ctx = (ntfs_attr_search_ctx*)NULL;
restart = TRUE;
maxcnt = cnt;
}
}
}
if (!restart && !res
&& ntfs_efs_fixup_attribute(ctx, na)) {
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
res = -1;
}
}
if (na)
ntfs_attr_close(na);
}
first = FALSE;
} while (restart && !res);
if (ctx)
ntfs_attr_put_search_ctx(ctx);
return (res);
}
/*
* Set the efs data from an extended attribute
* Warning : the new data is not checked
* Returns 0, or -1 if there is a problem
*/
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
int flags)
{
int res;
int written;
ntfs_attr *na;
const EFS_ATTR_HEADER *info_header;
res = 0;
if (ni && value && size) {
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
if (ni->flags & FILE_ATTR_ENCRYPTED) {
ntfs_log_trace("Inode %lld already encrypted\n",
(long long)ni->mft_no);
errno = EEXIST;
} else {
/*
* Possible problem : if encrypted file was
* restored in a compressed directory, it was
* restored as compressed.
* TODO : decompress first.
*/
ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
(long long)ni->mft_no);
errno = EIO;
}
return -1;
}
info_header = (const EFS_ATTR_HEADER*)value;
/* make sure we get a likely efsinfo */
if (le32_to_cpu(info_header->length) != size) {
errno = EINVAL;
return (-1);
}
if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
(ntfschar*)NULL,0)) {
if (!(flags & XATTR_REPLACE)) {
/*
* no logged_utility_stream attribute : add one,
* apparently, this does not feed the new value in
*/
res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
logged_utility_stream_name,4,
(u8*)NULL,(s64)size);
} else {
errno = ENODATA;
res = -1;
}
} else {
errno = EEXIST;
res = -1;
}
if (!res) {
/*
* open and update the existing efs data
*/
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
logged_utility_stream_name, 4);
if (na) {
/* resize attribute */
res = ntfs_attr_truncate(na, (s64)size);
/* overwrite value if any */
if (!res && value) {
written = (int)ntfs_attr_pwrite(na,
(s64)0, (s64)size, value);
if (written != (s64)size) {
ntfs_log_error("Failed to "
"update efs data\n");
errno = EIO;
res = -1;
}
}
ntfs_attr_close(na);
} else
res = -1;
}
if (!res) {
/* Don't handle AT_DATA Attribute(s) if inode is a directory */
if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
/* iterate over AT_DATA attributes */
/* set encrypted flag, truncate attribute to match padding bytes */
if (fixup_loop(ni))
return -1;
}
ni->flags |= FILE_ATTR_ENCRYPTED;
NInoSetDirty(ni);
NInoFileNameSetDirty(ni);
}
} else {
errno = EINVAL;
res = -1;
}
return (res ? -1 : 0);
}
/*
* Fixup raw encrypted AT_DATA Attribute
* read padding length from last two bytes
* truncate attribute, make non-resident,
* set data size to match padding length
* set ATTR_IS_ENCRYPTED flag on attribute
*
* Return 0 if successful
* -1 if failed (errno tells why)
*/
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
{
u64 newsize;
u64 oldsize;
le16 appended_bytes;
u16 padding_length;
ntfs_inode *ni;
BOOL close_ctx = FALSE;
if (!na) {
ntfs_log_error("no na specified for efs_fixup_attribute\n");
goto err_out;
}
if (!ctx) {
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
if (!ctx) {
ntfs_log_error("Failed to get ctx for efs\n");
goto err_out;
}
close_ctx = TRUE;
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
goto err_out;
}
} else {
if (!NAttrNonResident(na)) {
ntfs_log_error("Cannot make non resident"
" when a context has been allocated\n");
goto err_out;
}
}
/* no extra bytes are added to void attributes */
oldsize = na->data_size;
if (oldsize) {
/* make sure size is valid for a raw encrypted stream */
if ((oldsize & 511) != 2) {
ntfs_log_error("Bad raw encrypted stream\n");
goto err_out;
}
/* read padding length from last two bytes of attribute */
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
ntfs_log_error("Error reading padding length\n");
goto err_out;
}
padding_length = le16_to_cpu(appended_bytes);
if (padding_length > 511 || padding_length > na->data_size-2) {
errno = EINVAL;
ntfs_log_error("invalid padding length %d for data_size %lld\n",
padding_length, (long long)oldsize);
goto err_out;
}
newsize = oldsize - padding_length - 2;
/*
* truncate attribute to possibly free clusters allocated
* for the last two bytes, but do not truncate to new size
* to avoid losing useful data
*/
if (ntfs_attr_truncate(na, oldsize - 2)) {
ntfs_log_error("Error truncating attribute\n");
goto err_out;
}
} else
newsize = 0;
/*
* Encrypted AT_DATA Attributes MUST be non-resident
* This has to be done after the attribute is resized, as
* resizing down to zero may cause the attribute to be made
* resident.
*/
if (!NAttrNonResident(na)
&& ntfs_attr_make_non_resident(na, ctx)) {
if (!close_ctx
|| ntfs_attr_force_non_resident(na)) {
ntfs_log_error("Error making DATA attribute non-resident\n");
goto err_out;
} else {
/*
* must reinitialize context after forcing
* non-resident. We need a context for updating
* the state, and at this point, we are sure
* the context is not used elsewhere.
*/
ntfs_attr_reinit_search_ctx(ctx);
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
goto err_out;
}
}
}
ni = na->ni;
if (!na->name_len) {
ni->data_size = newsize;
ni->allocated_size = na->allocated_size;
}
NInoSetDirty(ni);
NInoFileNameSetDirty(ni);
ctx->attr->data_size = cpu_to_le64(newsize);
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
ctx->attr->initialized_size = ctx->attr->data_size;
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
if (close_ctx)
ntfs_attr_put_search_ctx(ctx);
return (0);
err_out:
if (close_ctx && ctx)
ntfs_attr_put_search_ctx(ctx);
return (-1);
}
#endif /* HAVE_SETXATTR */