mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-16 00:15:08 +01:00
f6c9003574
*modified libcustomfat and ntfs fragment fetch function to support >512 bytes per sector *Added new ehcmodule (thanks rodries) *Added real support of using both ports simultaniously without shutting down the other (thanks rodries for the ehcmodule works on this). There is no longer the limitation that the settings have to be on SD card for this. (ONLY HERMES CIOS) *Moved a few settings to Feature Settings and added a new Hard Drive Settings *Changed Wiinnertag path to only point to the path and not to the file. You must correct the path manually in custom path settings or reset you configs for this change or Winnertag won't work!! *Removed a few compile warnings for devkitPPC R23
370 lines
9.8 KiB
C
370 lines
9.8 KiB
C
/**
|
|
* attrib.c - Attribute handling code. Originated from the Linux-NTFS project.
|
|
*
|
|
* Copyright (c) 2000-2005 Anton Altaparmakov
|
|
* Copyright (c) 2002-2005 Richard Russon
|
|
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
|
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
|
* Copyright (c) 2007-2009 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_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#include "compat.h"
|
|
#include "attrib.h"
|
|
#include "attrlist.h"
|
|
#include "device.h"
|
|
#include "mft.h"
|
|
#include "debug.h"
|
|
#include "mst.h"
|
|
#include "volume.h"
|
|
#include "types.h"
|
|
#include "layout.h"
|
|
#include "inode.h"
|
|
#include "runlist.h"
|
|
#include "lcnalloc.h"
|
|
#include "dir.h"
|
|
#include "compress.h"
|
|
#include "bitmap.h"
|
|
#include "logging.h"
|
|
#include "misc.h"
|
|
#include "efs.h"
|
|
#include "ntfs.h"
|
|
#include "ntfsfile_frag.h"
|
|
|
|
static u8 size_to_shift(u32 size)
|
|
{
|
|
u8 ret = 0;
|
|
while (size)
|
|
{
|
|
ret++;
|
|
size >>= 1;
|
|
}
|
|
return ret - 1;
|
|
}
|
|
|
|
/**
|
|
* ntfs_attr_pread_i - see description at ntfs_attr_pread()
|
|
*/
|
|
static s64 ntfs_attr_getfragments_i(ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
|
_ntfs_frag_append_t append_fragment, void *callback_data)
|
|
{
|
|
u64 b = offset;
|
|
s64 br, to_read, ofs, total, total2, max_read, max_init;
|
|
ntfs_volume *vol;
|
|
runlist_element *rl;
|
|
//u16 efs_padding_length;
|
|
|
|
/* Sanity checking arguments is done in ntfs_attr_pread(). */
|
|
|
|
if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident(na))
|
|
{
|
|
//return -1; // no compressed files
|
|
return -31;
|
|
/*
|
|
if ((na->data_flags & ATTR_COMPRESSION_MASK)
|
|
== ATTR_IS_COMPRESSED)
|
|
return ntfs_compressed_attr_pread(na, pos, count, b);
|
|
else {
|
|
// compression mode not supported
|
|
errno = EOPNOTSUPP;
|
|
return -1;
|
|
}
|
|
*/
|
|
}
|
|
/*
|
|
* Encrypted non-resident attributes are not supported. We return
|
|
* access denied, which is what Windows NT4 does, too.
|
|
* However, allow if mounted with efs_raw option
|
|
*/
|
|
vol = na->ni->vol;
|
|
if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) {
|
|
errno = EACCES;
|
|
//return -1;
|
|
return -32;
|
|
}
|
|
|
|
if (!count)
|
|
return 0;
|
|
/*
|
|
* Truncate reads beyond end of attribute,
|
|
* but round to next 512 byte boundary for encrypted
|
|
* attributes with efs_raw mount option
|
|
*/
|
|
max_read = na->data_size;
|
|
max_init = na->initialized_size;
|
|
if (na->ni->vol->efs_raw
|
|
&& (na->data_flags & ATTR_IS_ENCRYPTED)
|
|
&& NAttrNonResident(na)) {
|
|
if (na->data_size != na->initialized_size) {
|
|
ntfs_log_error("uninitialized encrypted file not supported\n");
|
|
errno = EINVAL;
|
|
//return -1;
|
|
return -33;
|
|
}
|
|
max_init = max_read = ((na->data_size + 511) & ~511) + 2;
|
|
}
|
|
if (pos + count > max_read) {
|
|
if (pos >= max_read)
|
|
return 0;
|
|
count = max_read - pos;
|
|
}
|
|
/* If it is a resident attribute, get the value from the mft record. */
|
|
if (!NAttrNonResident(na))
|
|
{
|
|
return -34; // No resident files
|
|
/*
|
|
ntfs_attr_search_ctx *ctx;
|
|
char *val;
|
|
|
|
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
|
if (!ctx)
|
|
return -1;
|
|
if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
|
|
0, NULL, 0, ctx)) {
|
|
res_err_out:
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
return -1;
|
|
}
|
|
val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
|
|
if (val < (char*)ctx->attr || val +
|
|
le32_to_cpu(ctx->attr->value_length) >
|
|
(char*)ctx->mrec + vol->mft_record_size) {
|
|
errno = EIO;
|
|
ntfs_log_perror("%s: Sanity check failed", __FUNCTION__);
|
|
goto res_err_out;
|
|
}
|
|
memcpy(b, val + pos, count);
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
return count;
|
|
*/
|
|
}
|
|
total = total2 = 0;
|
|
/* Zero out reads beyond initialized size. */
|
|
if (pos + count > max_init) {
|
|
if (pos >= max_init) {
|
|
//memset(b, 0, count);
|
|
return count;
|
|
}
|
|
total2 = pos + count - max_init;
|
|
count -= total2;
|
|
//memset((u8*)b + count, 0, total2);
|
|
}
|
|
/*
|
|
* for encrypted non-resident attributes with efs_raw set
|
|
* the last two bytes aren't read from disk but contain
|
|
* the number of padding bytes so original size can be
|
|
* restored
|
|
*/
|
|
if (na->ni->vol->efs_raw &&
|
|
(na->data_flags & ATTR_IS_ENCRYPTED) &&
|
|
((pos + count) > max_init-2))
|
|
{
|
|
return -35; //No encrypted files
|
|
/*
|
|
efs_padding_length = 511 - ((na->data_size - 1) & 511);
|
|
if (pos+count == max_init) {
|
|
if (count == 1) {
|
|
*((u8*)b+count-1) = (u8)(efs_padding_length >> 8);
|
|
count--;
|
|
total2++;
|
|
} else {
|
|
*(u16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length);
|
|
count -= 2;
|
|
total2 +=2;
|
|
}
|
|
} else {
|
|
*((u8*)b+count-1) = (u8)(efs_padding_length & 0xff);
|
|
count--;
|
|
total2++;
|
|
}
|
|
*/
|
|
}
|
|
|
|
/* Find the runlist element containing the vcn. */
|
|
rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
|
|
if (!rl) {
|
|
/*
|
|
* If the vcn is not present it is an out of bounds read.
|
|
* However, we already truncated the read to the data_size,
|
|
* so getting this here is an error.
|
|
*/
|
|
if (errno == ENOENT) {
|
|
errno = EIO;
|
|
ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__);
|
|
}
|
|
//return -1;
|
|
return -36;
|
|
}
|
|
/*
|
|
* Gather the requested data into the linear destination buffer. Note,
|
|
* a partial final vcn is taken care of by the @count capping of read
|
|
* length.
|
|
*/
|
|
ofs = pos - (rl->vcn << vol->cluster_size_bits);
|
|
for (; count; rl++, ofs = 0) {
|
|
if (rl->lcn == LCN_RL_NOT_MAPPED) {
|
|
rl = ntfs_attr_find_vcn(na, rl->vcn);
|
|
if (!rl) {
|
|
if (errno == ENOENT) {
|
|
errno = EIO;
|
|
ntfs_log_perror("%s: Failed to find VCN #2",
|
|
__FUNCTION__);
|
|
}
|
|
goto rl_err_out;
|
|
}
|
|
/* Needed for case when runs merged. */
|
|
ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
|
|
}
|
|
if (!rl->length) {
|
|
errno = EIO;
|
|
ntfs_log_perror("%s: Zero run length", __FUNCTION__);
|
|
goto rl_err_out;
|
|
}
|
|
if (rl->lcn < (LCN)0) {
|
|
if (rl->lcn != (LCN)LCN_HOLE) {
|
|
ntfs_log_perror("%s: Bad run (%lld)",
|
|
__FUNCTION__,
|
|
(long long)rl->lcn);
|
|
goto rl_err_out;
|
|
}
|
|
/* It is a hole, just zero the matching @b range. */
|
|
to_read = min(count, (rl->length <<
|
|
vol->cluster_size_bits) - ofs);
|
|
//memset(b, 0, to_read);
|
|
/* Update progress counters. */
|
|
total += to_read;
|
|
count -= to_read;
|
|
b = b + to_read;
|
|
continue;
|
|
}
|
|
/* It is a real lcn, read it into @dst. */
|
|
to_read = min(count, (rl->length << vol->cluster_size_bits) -
|
|
ofs);
|
|
retry:
|
|
ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs"
|
|
" %lld.\n", (long long)to_read, (long long)rl->vcn,
|
|
(long long )rl->lcn, (long long)ofs);
|
|
/*
|
|
br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) +
|
|
ofs, to_read, b);
|
|
*/
|
|
br = to_read;
|
|
// convert to sectors unit
|
|
u32 shift = size_to_shift(na->ni->vol->sector_size);
|
|
u32 off_sec = b >> shift;
|
|
u32 sector = ((rl->lcn << vol->cluster_size_bits) + ofs) >> shift;
|
|
u32 count_sec = to_read >> shift;
|
|
int ret;
|
|
ret = append_fragment(callback_data, off_sec, sector, count_sec);
|
|
if (ret) {
|
|
if (ret < 0) return ret;
|
|
return -50;
|
|
}
|
|
/* If everything ok, update progress counters and continue. */
|
|
if (br > 0) {
|
|
total += br;
|
|
count -= br;
|
|
b = b + br;
|
|
}
|
|
if (br == to_read)
|
|
continue;
|
|
/* If the syscall was interrupted, try again. */
|
|
if (br == (s64)-1 && errno == EINTR)
|
|
goto retry;
|
|
if (total)
|
|
return total;
|
|
if (!br)
|
|
errno = EIO;
|
|
ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__);
|
|
//return -1;
|
|
return -38;
|
|
}
|
|
/* Finally, return the number of bytes read. */
|
|
return total + total2;
|
|
rl_err_out:
|
|
if (total)
|
|
return total;
|
|
errno = EIO;
|
|
//return -1;
|
|
return -39;
|
|
}
|
|
|
|
|
|
/**
|
|
* ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
|
|
* @na: ntfs attribute to read from
|
|
* @pos: byte position in the attribute to begin reading from
|
|
* @count: number of bytes to read
|
|
* @b: output data buffer
|
|
*
|
|
* This function will read @count bytes starting at offset @pos from the ntfs
|
|
* attribute @na into the data buffer @b.
|
|
*
|
|
* On success, return the number of successfully read bytes. If this number is
|
|
* lower than @count this means that the read reached end of file or that an
|
|
* error was encountered during the read so that the read is partial. 0 means
|
|
* end of file or nothing was read (also return 0 when @count is 0).
|
|
*
|
|
* On error and nothing has been read, return -1 with errno set appropriately
|
|
* to the return code of ntfs_pread(), or to EINVAL in case of invalid
|
|
* arguments.
|
|
*/
|
|
s64 ntfs_attr_getfragments(ntfs_attr *na, const s64 pos, s64 count, u64 offset,
|
|
_ntfs_frag_append_t append_fragment, void *callback_data)
|
|
{
|
|
s64 ret;
|
|
|
|
if (!na || !na->ni || !na->ni->vol || !callback_data || pos < 0 || count < 0) {
|
|
errno = EINVAL;
|
|
ntfs_log_perror("%s: na=%p b=%p pos=%lld count=%lld",
|
|
__FUNCTION__, na, callback_data, (long long)pos,
|
|
(long long)count);
|
|
//return -1;
|
|
return -21;
|
|
}
|
|
|
|
/*
|
|
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);
|
|
*/
|
|
|
|
ret = ntfs_attr_getfragments_i(na, pos, count, offset,
|
|
append_fragment, callback_data);
|
|
|
|
//ntfs_log_leave("\n");
|
|
return ret;
|
|
}
|
|
|