File: /home/django/libpff/libcfile/libcfile_file.c
/*
* File functions
*
* Copyright (C) 2008-2024, Joachim Metz <joachim.metz@gmail.com>
*
* Refer to AUTHORS for acknowledgements.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 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 Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <common.h>
#include <memory.h>
#include <narrow_string.h>
#include <system_string.h>
#include <types.h>
#include <wide_string.h>
#if defined( HAVE_SYS_STAT_H )
#include <sys/stat.h>
#endif
#if defined( HAVE_ERRNO_H )
#include <errno.h>
#endif
#if defined( HAVE_FCNTL_H )
#include <fcntl.h>
#endif
#if defined( WINAPI )
#include <io.h>
#endif
#if defined( WINAPI ) && !defined( __CYGWIN__ )
#include <share.h>
#endif
#if defined( HAVE_SYS_IOCTL_H )
#include <sys/ioctl.h>
#endif
#if defined( WINAPI )
#include <winioctl.h>
#elif defined( HAVE_CYGWIN_FS_H )
#include <cygwin/fs.h>
#elif defined( HAVE_LINUX_FS_H )
/* Required for Linux platforms that use a sizeof( u64 )
* in linux/fs.h but have no typedef of it
*/
#if !defined( HAVE_U64 )
typedef size_t u64;
#endif
#include <linux/fs.h>
#else
#if defined( HAVE_SYS_DISK_H )
#include <sys/disk.h>
#endif
#if defined( HAVE_SYS_DISKLABEL_H )
#include <sys/disklabel.h>
#endif
#endif
#if defined( HAVE_UNISTD_H )
#include <unistd.h>
#endif
#if defined( HAVE_GLIB_H )
#include <glib.h>
#include <glib/gstdio.h>
#endif
#include "libcfile_definitions.h"
#include "libcfile_file.h"
#include "libcfile_libcerror.h"
#include "libcfile_libcnotify.h"
#include "libcfile_system_string.h"
#include "libcfile_types.h"
#include "libcfile_winapi.h"
/* Creates a file
* Make sure the value file is referencing, is set to NULL
* Returns 1 if successful or -1 on error
*/
int libcfile_file_initialize(
libcfile_file_t **file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_initialize";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
if( *file != NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
"%s: invalid file value already set.",
function );
return( -1 );
}
internal_file = memory_allocate_structure(
libcfile_internal_file_t );
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
"%s: unable to create file.",
function );
goto on_error;
}
if( memory_set(
internal_file,
0,
sizeof( libcfile_internal_file_t ) ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear file.",
function );
goto on_error;
}
#if defined( WINAPI )
internal_file->handle = INVALID_HANDLE_VALUE;
#else
internal_file->descriptor = -1;
#endif
*file = (libcfile_file_t *) internal_file;
return( 1 );
on_error:
if( internal_file != NULL )
{
memory_free(
internal_file );
}
return( -1 );
}
/* Frees a file
* Returns 1 if successful or -1 on error
*/
int libcfile_file_free(
libcfile_file_t **file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_free";
int result = 1;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
if( *file != NULL )
{
internal_file = (libcfile_internal_file_t *) *file;
#if defined( WINAPI )
if( internal_file->handle != INVALID_HANDLE_VALUE )
#else
if( internal_file->descriptor != -1 )
#endif
{
if( libcfile_file_close(
*file,
error ) != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_CLOSE_FAILED,
"%s: unable to close file.",
function );
result = -1;
}
}
*file = NULL;
memory_free(
internal_file );
}
return( result );
}
/* Opens a file
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open(
libcfile_file_t *file,
const char *filename,
int access_flags,
libcerror_error_t **error )
{
static char *function = "libcfile_file_open";
uint32_t error_code = 0;
if( libcfile_file_open_with_error_code(
file,
filename,
access_flags,
&error_code,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
"%s: unable to open file.",
function );
return( -1 );
}
return( 1 );
}
#if defined( WINAPI )
#if ( WINVER >= 0x0600 ) && ( WINVER < 0x0602 )
#define FileAlignmentInfo 0x11
typedef struct _FILE_ALIGNMENT_INFO FILE_ALIGNMENT_INFO;
struct _FILE_ALIGNMENT_INFO {
ULONG AlignmentRequirement;
};
#endif
/* Opens a file
* This function uses the WINAPI function for Windows XP (0x0501) or later,
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open_with_error_code(
libcfile_file_t *file,
const char *filename,
int access_flags,
uint32_t *error_code,
libcerror_error_t **error )
{
#if ( WINVER >= 0x0600 )
FILE_ALIGNMENT_INFO file_alignment_information;
BOOL result = 0;
#endif
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_open_with_error_code";
DWORD file_io_access_flags = 0;
DWORD file_io_creation_flags = 0;
DWORD file_io_shared_flags = 0;
DWORD flags_and_attributes = 0;
size_t filename_length = 0;
ssize_t read_count = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle != INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
"%s: invalid file - handle value already set.",
function );
return( -1 );
}
if( filename == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid filename.",
function );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 ) )
{
file_io_access_flags = GENERIC_WRITE | GENERIC_READ;
file_io_creation_flags = OPEN_ALWAYS;
file_io_shared_flags = FILE_SHARE_READ;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
{
file_io_access_flags = GENERIC_READ;
file_io_creation_flags = OPEN_EXISTING;
/* FILE_SHARE_WRITE is set to allow reading files that are
* currently being written FILE_SHARE_READ alone does not suffice
*/
file_io_shared_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
{
file_io_access_flags = GENERIC_WRITE;
file_io_creation_flags = OPEN_ALWAYS;
file_io_shared_flags = FILE_SHARE_READ;
}
else
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported access flags: 0x%02x.",
function,
access_flags );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_TRUNCATE ) != 0 ) )
{
file_io_creation_flags = CREATE_ALWAYS;
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
filename_length = narrow_string_length(
filename );
if( filename_length > 4 )
{
if( ( filename[ 0 ] == '\\' )
&& ( filename[ 1 ] == '\\' )
&& ( filename[ 2 ] == '.' )
&& ( filename[ 3 ] == '\\' ) )
{
/* Ignore \\.\F:\ which is an alternative notation for F:
*/
if( ( filename_length < 7 )
|| ( filename[ 5 ] != ':' )
|| ( filename[ 6 ] != '\\' ) )
{
internal_file->is_device_filename = 1;
internal_file->use_asynchronous_io = 1;
}
}
}
flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
if( internal_file->use_asynchronous_io != 0 )
{
flags_and_attributes |= FILE_FLAG_OVERLAPPED;
}
#if ( WINVER <= 0x0500 )
internal_file->handle = libcfile_CreateFileA(
(LPCSTR) filename,
file_io_access_flags,
file_io_shared_flags,
NULL,
file_io_creation_flags,
flags_and_attributes,
NULL );
#else
internal_file->handle = CreateFileA(
(LPCSTR) filename,
file_io_access_flags,
file_io_shared_flags,
NULL,
file_io_creation_flags,
flags_and_attributes,
NULL );
#endif
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
*error_code = (uint32_t) GetLastError();
switch( *error_code )
{
case ERROR_ACCESS_DENIED:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_ACCESS_DENIED,
"%s: access denied to file: %" PRIs_SYSTEM ".",
function,
filename );
break;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_INVALID_RESOURCE,
"%s: no such file: %" PRIs_SYSTEM ".",
function,
filename );
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
*error_code,
"%s: unable to open file: %" PRIs_SYSTEM ".",
function,
filename );
break;
}
return( -1 );
}
if( internal_file->is_device_filename != 0 )
{
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
FSCTL_ALLOW_EXTENDED_DASD_IO,
NULL,
0,
NULL,
0,
error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: FSCTL_ALLOW_EXTENDED_DASD_IO.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
#if ( WINVER >= 0x0600 )
result = GetFileInformationByHandleEx(
internal_file->handle,
FileAlignmentInfo,
(void *) &file_alignment_information,
(DWORD) sizeof( FILE_ALIGNMENT_INFO ) );
if( result == FALSE )
{
*error_code = (uint32_t) GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
*error_code,
"%s: unable to retrieve file alignment information.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else if( file_alignment_information.AlignmentRequirement != 0 )
{
if( libcfile_internal_file_set_block_size(
internal_file,
(size_t) 512,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_SET_FAILED,
"%s: unable to set block size.",
function );
return( -1 );
}
}
#endif /* ( WINVER >= 0x0600 ) */
}
if( libcfile_internal_file_get_size(
internal_file,
&( internal_file->size ),
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve size.",
function );
return( -1 );
}
internal_file->access_flags = access_flags;
internal_file->current_offset = 0;
return( 1 );
}
#elif defined( HAVE_OPEN )
/* Opens a file
* This function uses the POSIX open function or equivalent
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open_with_error_code(
libcfile_file_t *file,
const char *filename,
int access_flags,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_open_with_error_code";
int file_io_flags = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor != -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
"%s: invalid file - descriptor value already set.",
function );
return( -1 );
}
if( filename == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid filename.",
function );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 ) )
{
file_io_flags = O_RDWR | O_CREAT;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
{
file_io_flags = O_RDONLY;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
{
file_io_flags = O_WRONLY | O_CREAT;
}
else
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported access flags: 0x%02x.",
function,
access_flags );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_TRUNCATE ) != 0 ) )
{
file_io_flags |= O_TRUNC;
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
#if defined( O_CLOEXEC )
/* Prevent the file descriptor to remain open across an execve
*/
file_io_flags |= O_CLOEXEC;
#endif
#if defined( HAVE_GLIB_H )
internal_file->descriptor = g_open(
filename,
file_io_flags,
0644 );
#else
internal_file->descriptor = open(
filename,
file_io_flags,
0644 );
#endif
if( internal_file->descriptor == -1 )
{
*error_code = (uint32_t) errno;
switch( *error_code )
{
case EACCES:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_ACCESS_DENIED,
"%s: access denied to file: %" PRIs_SYSTEM ".",
function,
filename );
break;
case ENOENT:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_INVALID_RESOURCE,
"%s: no such file: %" PRIs_SYSTEM ".",
function,
filename );
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
*error_code,
"%s: unable to open file: %" PRIs_SYSTEM ".",
function,
filename );
break;
}
return( -1 );
}
if( libcfile_internal_file_get_size(
internal_file,
&( internal_file->size ),
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve size.",
function );
return( -1 );
}
internal_file->access_flags = access_flags;
internal_file->current_offset = 0;
return( 1 );
}
#else
#error Missing file open function
#endif
#if defined( HAVE_WIDE_CHARACTER_TYPE )
/* Opens a file
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open_wide(
libcfile_file_t *file,
const wchar_t *filename,
int access_flags,
libcerror_error_t **error )
{
static char *function = "libcfile_file_open_wide";
uint32_t error_code = 0;
if( libcfile_file_open_wide_with_error_code(
file,
filename,
access_flags,
&error_code,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
"%s: unable to open file.",
function );
return( -1 );
}
return( 1 );
}
#if defined( WINAPI )
/* Opens a file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open_wide_with_error_code(
libcfile_file_t *file,
const wchar_t *filename,
int access_flags,
uint32_t *error_code,
libcerror_error_t **error )
{
#if ( WINVER >= 0x0600 )
FILE_ALIGNMENT_INFO file_alignment_information;
BOOL result = 0;
#endif
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_open_wide_with_error_code";
DWORD file_io_access_flags = 0;
DWORD file_io_creation_flags = 0;
DWORD file_io_shared_flags = 0;
DWORD flags_and_attributes = 0;
size_t filename_length = 0;
ssize_t read_count = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle != INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
"%s: invalid file - handle value already set.",
function );
return( -1 );
}
if( filename == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid filename.",
function );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 ) )
{
file_io_access_flags = GENERIC_WRITE | GENERIC_READ;
file_io_creation_flags = OPEN_ALWAYS;
file_io_shared_flags = FILE_SHARE_READ;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
{
file_io_access_flags = GENERIC_READ;
file_io_creation_flags = OPEN_EXISTING;
/* FILE_SHARE_WRITE is set to allow reading files that are
* currently being written FILE_SHARE_READ alone does not suffice
*/
file_io_shared_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
{
file_io_access_flags = GENERIC_WRITE;
file_io_creation_flags = OPEN_ALWAYS;
file_io_shared_flags = FILE_SHARE_READ;
}
else
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported access flags: 0x%02x.",
function,
access_flags );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_TRUNCATE ) != 0 ) )
{
file_io_creation_flags = CREATE_ALWAYS;
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
filename_length = wide_string_length(
filename );
if( filename_length > 4 )
{
if( ( filename[ 0 ] == (wchar_t) '\\' )
&& ( filename[ 1 ] == (wchar_t) '\\' )
&& ( filename[ 2 ] == (wchar_t) '.' )
&& ( filename[ 3 ] == (wchar_t) '\\' ) )
{
/* Ignore \\.\F:\ which is an alternative notation for F:
*/
if( ( filename_length < 7 )
|| ( filename[ 5 ] != (wchar_t) ':' )
|| ( filename[ 6 ] != (wchar_t) '\\' ) )
{
internal_file->is_device_filename = 1;
internal_file->use_asynchronous_io = 1;
}
}
}
flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
if( internal_file->use_asynchronous_io != 0 )
{
flags_and_attributes |= FILE_FLAG_OVERLAPPED;
}
#if ( WINVER <= 0x0500 )
internal_file->handle = libcfile_CreateFileW(
(LPCWSTR) filename,
file_io_access_flags,
file_io_shared_flags,
NULL,
file_io_creation_flags,
flags_and_attributes,
NULL );
#else
internal_file->handle = CreateFileW(
(LPCWSTR) filename,
file_io_access_flags,
file_io_shared_flags,
NULL,
file_io_creation_flags,
flags_and_attributes,
NULL );
#endif
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
*error_code = (uint32_t) GetLastError();
switch( *error_code )
{
case ERROR_ACCESS_DENIED:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_ACCESS_DENIED,
"%s: access denied to file: %" PRIs_SYSTEM ".",
function,
filename );
break;
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_INVALID_RESOURCE,
"%s: no such file: %" PRIs_SYSTEM ".",
function,
filename );
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
*error_code,
"%s: unable to open file: %" PRIs_SYSTEM ".",
function,
filename );
break;
}
return( -1 );
}
if( internal_file->is_device_filename != 0 )
{
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
FSCTL_ALLOW_EXTENDED_DASD_IO,
NULL,
0,
NULL,
0,
error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: FSCTL_ALLOW_EXTENDED_DASD_IO.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
#if ( WINVER >= 0x0600 )
result = GetFileInformationByHandleEx(
internal_file->handle,
FileAlignmentInfo,
(void *) &file_alignment_information,
(DWORD) sizeof( FILE_ALIGNMENT_INFO ) );
if( result == FALSE )
{
*error_code = (uint32_t) GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
*error_code,
"%s: unable to retrieve file alignment information.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else if( file_alignment_information.AlignmentRequirement != 0 )
{
if( libcfile_internal_file_set_block_size(
internal_file,
(size_t) 512,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_SET_FAILED,
"%s: unable to set block size.",
function );
return( -1 );
}
}
#endif /* ( WINVER >= 0x0600 ) */
}
if( libcfile_internal_file_get_size(
internal_file,
&( internal_file->size ),
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve size.",
function );
return( -1 );
}
internal_file->access_flags = access_flags;
internal_file->current_offset = 0;
return( 1 );
}
#elif defined( HAVE_OPEN )
/* Opens a file
* This function uses the POSIX open function or equivalent
* Returns 1 if successful or -1 on error
*/
int libcfile_file_open_wide_with_error_code(
libcfile_file_t *file,
const wchar_t *filename,
int access_flags,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_open_wide_with_error_code";
char *narrow_filename = NULL;
size_t filename_size = 0;
size_t narrow_filename_size = 0;
int file_io_flags = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor != -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
"%s: invalid file - descriptor value already set.",
function );
return( -1 );
}
if( filename == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid filename.",
function );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 ) )
{
file_io_flags = O_RDWR | O_CREAT;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_READ ) != 0 )
{
file_io_flags = O_RDONLY;
}
else if( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
{
file_io_flags = O_WRONLY | O_CREAT;
}
else
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported access flags: 0x%02x.",
function,
access_flags );
return( -1 );
}
if( ( ( access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
&& ( ( access_flags & LIBCFILE_ACCESS_FLAG_TRUNCATE ) != 0 ) )
{
file_io_flags |= O_TRUNC;
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
filename_size = 1 + wide_string_length(
filename );
if( libcfile_system_string_size_from_wide_string(
filename,
filename_size,
&narrow_filename_size,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_CONVERSION,
LIBCERROR_CONVERSION_ERROR_GENERIC,
"%s: unable to determine narrow character filename size.",
function );
goto on_error;
}
narrow_filename = narrow_string_allocate(
narrow_filename_size );
if( narrow_filename == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
"%s: unable to create narrow character filename.",
function );
goto on_error;
}
if( libcfile_system_string_copy_from_wide_string(
narrow_filename,
narrow_filename_size,
filename,
filename_size,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_CONVERSION,
LIBCERROR_CONVERSION_ERROR_GENERIC,
"%s: unable to set narrow character filename.",
function );
goto on_error;
}
#if defined( O_CLOEXEC )
/* Prevent the file descriptor to remain open across an execve
*/
file_io_flags |= O_CLOEXEC;
#endif
#if defined( HAVE_GLIB_H )
internal_file->descriptor = g_open(
narrow_filename,
file_io_flags,
0644 );
#else
internal_file->descriptor = open(
narrow_filename,
file_io_flags,
0644 );
#endif
memory_free(
narrow_filename );
narrow_filename = NULL;
if( internal_file->descriptor == -1 )
{
*error_code = (uint32_t) errno;
switch( *error_code )
{
case EACCES:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_ACCESS_DENIED,
"%s: access denied to file: %" PRIs_SYSTEM ".",
function,
filename );
break;
case ENOENT:
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_INVALID_RESOURCE,
"%s: no such file: %" PRIs_SYSTEM ".",
function,
filename );
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_OPEN_FAILED,
*error_code,
"%s: unable to open file: %" PRIs_SYSTEM ".",
function,
filename );
break;
}
goto on_error;
}
if( libcfile_internal_file_get_size(
internal_file,
&( internal_file->size ),
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve size.",
function );
goto on_error;
}
return( 1 );
on_error:
if( narrow_filename != NULL )
{
memory_free(
narrow_filename );
}
return( -1 );
}
#else
#error Missing file open wide function
#endif
#endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
#if defined( WINAPI )
/* Closes the file
* This function uses the WINAPI function for Windows 2000 (0x0500) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 0 if successful or -1 on error
*/
int libcfile_file_close(
libcfile_file_t *file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_close";
DWORD error_code = 0;
BOOL result = FALSE;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle != INVALID_HANDLE_VALUE )
{
#if ( WINVER <= 0x0500 )
result = libcfile_CloseHandle(
internal_file->handle );
#else
result = CloseHandle(
internal_file->handle );
#endif
if( result == 0 )
{
error_code = GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_CLOSE_FAILED,
error_code,
"%s: unable to close file.",
function );
return( -1 );
}
internal_file->handle = INVALID_HANDLE_VALUE;
internal_file->is_device_filename = 0;
internal_file->use_asynchronous_io = 0;
internal_file->access_flags = 0;
internal_file->size = 0;
internal_file->current_offset = 0;
}
if( internal_file->block_data != NULL )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
}
return( 0 );
}
#elif defined( HAVE_CLOSE )
/* Closes the file
* This function uses the POSIX close function or equivalent
* Returns 0 if successful or -1 on error
*/
int libcfile_file_close(
libcfile_file_t *file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_close";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor != -1 )
{
if( close(
internal_file->descriptor ) != 0 )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_CLOSE_FAILED,
errno,
"%s: unable to close file.",
function );
return( -1 );
}
internal_file->descriptor = -1;
internal_file->access_flags = 0;
internal_file->size = 0;
internal_file->current_offset = 0;
}
if( internal_file->block_data != NULL )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
}
return( 0 );
}
#else
#error Missing file close function
#endif
/* Reads a buffer from the file
* Returns the number of bytes read if successful, or -1 on error
*/
ssize_t libcfile_file_read_buffer(
libcfile_file_t *file,
uint8_t *buffer,
size_t size,
libcerror_error_t **error )
{
static char *function = "libcfile_file_read_buffer";
ssize_t read_count = 0;
uint32_t error_code = 0;
read_count = libcfile_file_read_buffer_with_error_code(
file,
buffer,
size,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
"%s: unable to read from file.",
function );
return( -1 );
}
return( read_count );
}
#if defined( WINAPI )
/* Reads a buffer from the file
* This is an internal function to wrap ReadFile in synchronous and asynchronous mode
* the current_offset is only used in asynchronous mode.
* Returns the number of bytes read if successful, or -1 on error
*/
ssize_t libcfile_internal_file_read_buffer_at_offset_with_error_code(
libcfile_internal_file_t *internal_file,
off64_t current_offset,
uint8_t *buffer,
size_t size,
uint32_t *error_code,
libcerror_error_t **error )
{
OVERLAPPED overlapped_data;
static char *function = "libcfile_internal_file_read_buffer_at_offset_with_error_code";
OVERLAPPED *overlapped = NULL;
DWORD read_count = 0;
BOOL io_pending = FALSE;
BOOL result = FALSE;
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
if( current_offset < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
"%s: invalid current offset value out of bounds.",
function );
return( -1 );
}
if( buffer == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid buffer.",
function );
return( -1 );
}
#if ( UINT32_MAX < SSIZE_MAX )
if( size > (size_t) UINT32_MAX )
#else
if( size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
/* For Windows devices we need to use asynchronous IO here
* otherwise the ReadFile function can return ERROR_INVALID_PARAMETER
* if the device is read concurrently and the the block is too large
* to fill. Using smaller block sizes decreases the likelyhood but
* also impacts the performance.
*/
if( internal_file->use_asynchronous_io != 0 )
{
if( memory_set(
&overlapped_data,
0,
sizeof( OVERLAPPED ) ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear overlapped data.",
function );
return( -1 );
}
overlapped = &overlapped_data;
overlapped->Offset = (DWORD) ( 0x0ffffffffUL & current_offset );
overlapped->OffsetHigh = (DWORD) ( current_offset >> 32 );
}
#if ( WINVER <= 0x0500 )
result = libcfile_ReadFile(
internal_file->handle,
buffer,
(DWORD) size,
&read_count,
overlapped );
#else
result = ReadFile(
internal_file->handle,
(VOID *) buffer,
(DWORD) size,
&read_count,
overlapped );
#endif
if( result == 0 )
{
*error_code = (uint32_t) GetLastError();
switch( *error_code )
{
case ERROR_HANDLE_EOF:
break;
case ERROR_IO_PENDING:
io_pending = TRUE;
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file.",
function );
return( -1 );
}
}
if( io_pending == TRUE )
{
#if ( WINVER <= 0x0500 )
result = libcfile_GetOverlappedResult(
internal_file->handle,
overlapped,
&read_count,
TRUE );
#else
result = GetOverlappedResult(
internal_file->handle,
overlapped,
&read_count,
TRUE );
#endif
if( result == 0 )
{
*error_code = (uint32_t) GetLastError();
switch( *error_code )
{
case ERROR_HANDLE_EOF:
break;
default:
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file - overlapped result.",
function );
return( -1 );
}
}
}
return( (ssize_t) read_count );
}
/* Reads a buffer from the file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns the number of bytes read if successful, or -1 on error
*/
ssize_t libcfile_file_read_buffer_with_error_code(
libcfile_file_t *file,
uint8_t *buffer,
size_t size,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_read_buffer_with_error_code";
size_t buffer_offset = 0;
size_t read_size = 0;
size_t read_size_remainder = 0;
ssize_t read_count = 0;
BOOL result = FALSE;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
if( buffer == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid buffer.",
function );
return( -1 );
}
#if ( UINT32_MAX < SSIZE_MAX )
if( size > (size_t) UINT32_MAX )
#else
if( size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
if( internal_file->block_size != 0 )
{
if( internal_file->block_data == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing block data.",
function );
return( -1 );
}
}
if( internal_file->current_offset < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
"%s: invalid file - current offset value out of bounds.",
function );
return( -1 );
}
if( ( size == 0 )
|| ( (size64_t) internal_file->current_offset > internal_file->size ) )
{
return( 0 );
}
if( ( (size64_t) internal_file->current_offset + size ) > internal_file->size )
{
size = (size_t) ( internal_file->size - internal_file->current_offset );
}
if( internal_file->block_size != 0 )
{
/* Read a block of data to align with the next block
*/
if( ( internal_file->block_data_offset > 0 )
&& ( internal_file->block_data_size == 0 ) )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
read_count = libcfile_internal_file_read_buffer_at_offset_with_error_code(
internal_file,
internal_file->current_offset - internal_file->block_data_offset,
internal_file->block_data,
internal_file->block_size,
error_code,
error );
if( read_count != (ssize_t) internal_file->block_size )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
"%s: invalid read count: %" PRIzd " returned.",
function,
read_count );
return( -1 );
}
internal_file->block_data_size = (size_t) read_count;
}
if( ( internal_file->block_data_offset > 0 )
&& ( internal_file->block_data_offset < internal_file->block_data_size ) )
{
read_size = internal_file->block_data_size - internal_file->block_data_offset;
if( read_size > size )
{
read_size = size;
}
if( memory_copy(
buffer,
&( internal_file->block_data[ internal_file->block_data_offset ] ),
read_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_COPY_FAILED,
"%s: unable to copy block data.",
function );
return( -1 );
}
buffer_offset += read_size;
size -= read_size;
internal_file->current_offset += read_size;
internal_file->block_data_offset += read_size;
}
if( size == 0 )
{
return( (ssize_t) buffer_offset );
}
}
read_size = size;
if( internal_file->block_size != 0 )
{
/* Read block aligned
*/
read_size_remainder = read_size % internal_file->block_size;
read_size -= read_size_remainder;
}
if( read_size > 0 )
{
read_count = libcfile_internal_file_read_buffer_at_offset_with_error_code(
internal_file,
internal_file->current_offset,
&( buffer[ buffer_offset ] ),
read_size,
error_code,
error );
if( ( internal_file->block_size == 0 )
&& ( read_count < 0 ) )
{
result = 0;
}
else if( ( internal_file->block_size != 0 )
&& ( read_count != (ssize_t) read_size ) )
{
result = 0;
}
else
{
result = 1;
}
if( result == 0 )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file.",
function );
return( -1 );
}
buffer_offset += (size_t) read_count;
internal_file->current_offset += read_count;
}
/* Read the non-aligned remainder
*/
if( read_size_remainder > 0 )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
read_count = libcfile_internal_file_read_buffer_at_offset_with_error_code(
internal_file,
internal_file->current_offset,
internal_file->block_data,
internal_file->block_size,
error_code,
error );
if( read_count != (ssize_t) internal_file->block_size )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
"%s: invalid read count: %" PRIzd " returned.",
function,
read_count );
return( -1 );
}
internal_file->block_data_offset = 0;
internal_file->block_data_size = (size_t) read_count;
if( memory_copy(
&( buffer[ buffer_offset ] ),
internal_file->block_data,
read_size_remainder ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_COPY_FAILED,
"%s: unable to copy block data.",
function );
return( -1 );
}
buffer_offset += read_size_remainder;
internal_file->current_offset += read_size_remainder;
internal_file->block_data_offset += read_size_remainder;
}
return( (ssize_t) buffer_offset );
}
#elif defined( HAVE_READ )
/* Reads a buffer from the file
* This function uses the POSIX read function or equivalent
* Returns the number of bytes read if successful, or -1 on error
*/
ssize_t libcfile_file_read_buffer_with_error_code(
libcfile_file_t *file,
uint8_t *buffer,
size_t size,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_read_buffer_with_error_code";
size_t buffer_offset = 0;
size_t read_size = 0;
size_t read_size_remainder = 0;
ssize_t read_count = 0;
int result = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
if( buffer == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid buffer.",
function );
return( -1 );
}
if( size > (size_t) SSIZE_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
if( internal_file->block_size != 0 )
{
if( internal_file->block_data == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing block data.",
function );
return( -1 );
}
}
if( internal_file->current_offset < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
"%s: invalid file - current offset value out of bounds.",
function );
return( -1 );
}
if( ( size == 0 )
|| ( (size64_t) internal_file->current_offset > internal_file->size ) )
{
return( 0 );
}
if( ( (size64_t) internal_file->current_offset + size ) > internal_file->size )
{
size = (size_t) ( internal_file->size - internal_file->current_offset );
}
if( internal_file->block_size != 0 )
{
/* Read a block of data to align with the next block
*/
if( ( internal_file->block_data_offset > 0 )
&& ( internal_file->block_data_size == 0 ) )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
read_count = read(
internal_file->descriptor,
internal_file->block_data,
internal_file->block_size );
if( read_count != (ssize_t) internal_file->block_size )
{
*error_code = (uint32_t) errno;
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file.",
function );
return( -1 );
}
internal_file->block_data_size = (size_t) read_count;
}
if( ( internal_file->block_data_offset > 0 )
&& ( internal_file->block_data_offset < internal_file->block_data_size ) )
{
read_size = internal_file->block_data_size - internal_file->block_data_offset;
if( read_size > size )
{
read_size = size;
}
if( memory_copy(
buffer,
&( internal_file->block_data[ internal_file->block_data_offset ] ),
read_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_COPY_FAILED,
"%s: unable to copy block data.",
function );
return( -1 );
}
buffer_offset += read_size;
size -= read_size;
internal_file->block_data_offset += read_size;
internal_file->current_offset += read_size;
}
if( size == 0 )
{
return( (ssize_t) buffer_offset );
}
}
read_size = size;
if( internal_file->block_size != 0 )
{
/* Read block aligned
*/
read_size_remainder = read_size % internal_file->block_size;
read_size -= read_size_remainder;
}
if( read_size > 0 )
{
read_count = read(
internal_file->descriptor,
(void *) &( buffer[ buffer_offset ] ),
read_size );
if( ( internal_file->block_size == 0 )
&& ( read_count < 0 ) )
{
result = 0;
}
else if( ( internal_file->block_size != 0 )
&& ( read_count != (ssize_t) read_size ) )
{
result = 0;
}
else
{
result = 1;
}
if( result == 0 )
{
*error_code = (uint32_t) errno;
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file.",
function );
return( -1 );
}
buffer_offset += (size_t) read_count;
internal_file->current_offset += read_count;
}
/* Read the non-aligned remainder
*/
if( read_size_remainder > 0 )
{
if( memory_set(
internal_file->block_data,
0,
internal_file->block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
read_count = read(
internal_file->descriptor,
internal_file->block_data,
internal_file->block_size );
if( read_count != (ssize_t) internal_file->block_size )
{
*error_code = (uint32_t) errno;
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_READ_FAILED,
*error_code,
"%s: unable to read from file.",
function );
return( -1 );
}
internal_file->block_data_offset = 0;
internal_file->block_data_size = (size_t) read_count;
if( memory_copy(
&( buffer[ buffer_offset ] ),
internal_file->block_data,
read_size_remainder ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_COPY_FAILED,
"%s: unable to copy block data.",
function );
return( -1 );
}
buffer_offset += read_size_remainder;
internal_file->block_data_offset += read_size_remainder;
internal_file->current_offset += read_size_remainder;
}
return( (ssize_t) buffer_offset );
}
#else
#error Missing file read function
#endif
/* Writes a buffer to the file
* Returns the number of bytes written if successful, or -1 on error
*/
ssize_t libcfile_file_write_buffer(
libcfile_file_t *file,
const uint8_t *buffer,
size_t size,
libcerror_error_t **error )
{
static char *function = "libcfile_file_write_buffer";
ssize_t write_count = 0;
uint32_t error_code = 0;
write_count = libcfile_file_write_buffer_with_error_code(
file,
buffer,
size,
&error_code,
error );
if( write_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_WRITE_FAILED,
"%s: unable to write to file.",
function );
return( -1 );
}
return( write_count );
}
#if defined( WINAPI )
/* Writes a buffer to the file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns the number of bytes written if successful, or -1 on error
*/
ssize_t libcfile_file_write_buffer_with_error_code(
libcfile_file_t *file,
const uint8_t *buffer,
size_t size,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_write_buffer_with_error_code";
ssize_t write_count = 0;
BOOL result = FALSE;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
if( buffer == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid buffer.",
function );
return( -1 );
}
#if ( UINT32_MAX < SSIZE_MAX )
if( size > (size_t) UINT32_MAX )
#else
if( size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
#if ( WINVER <= 0x0500 )
result = libcfile_WriteFile(
internal_file->handle,
(VOID *) buffer,
(DWORD) size,
(DWORD *) &write_count,
NULL );
#else
result = WriteFile(
internal_file->handle,
(VOID *) buffer,
(DWORD) size,
(DWORD *) &write_count,
NULL );
#endif
if( result == 0 )
{
*error_code = (uint32_t) GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_WRITE_FAILED,
*error_code,
"%s: unable to write to file.",
function );
return( -1 );
}
if( write_count < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_WRITE_FAILED,
"%s: invalid write count: %" PRIzd " returned.",
function,
write_count );
return( -1 );
}
internal_file->current_offset += write_count;
if( (size64_t) internal_file->current_offset > internal_file->size )
{
internal_file->size = (size64_t) internal_file->current_offset;
}
return( write_count );
}
#elif defined( HAVE_WRITE )
/* Writes a buffer to the file
* This function uses the POSIX write function or equivalent
* Returns the number of bytes written if successful, or -1 on error
*/
ssize_t libcfile_file_write_buffer_with_error_code(
libcfile_file_t *file,
const uint8_t *buffer,
size_t size,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_write_buffer_with_error_code";
ssize_t write_count = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
if( buffer == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid buffer.",
function );
return( -1 );
}
if( size > (size_t) SSIZE_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
write_count = write(
internal_file->descriptor,
(void *) buffer,
size );
if( write_count < 0 )
{
*error_code = (uint32_t) errno;
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_WRITE_FAILED,
*error_code,
"%s: unable to write to file.",
function );
return( -1 );
}
internal_file->current_offset += write_count;
if( (size64_t) internal_file->current_offset > internal_file->size )
{
internal_file->size = (size64_t) internal_file->current_offset;
}
return( write_count );
}
#else
#error Missing file write function
#endif
#if defined( WINAPI )
/* Seeks a certain offset within the file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns the offset if the seek is successful or -1 on error
*/
off64_t libcfile_file_seek_offset(
libcfile_file_t *file,
off64_t offset,
int whence,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_seek_offset";
off64_t offset_remainder = 0;
LARGE_INTEGER large_integer_offset = LIBCFILE_LARGE_INTEGER_ZERO;
DWORD error_code = 0;
DWORD move_method = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
if( offset > (off64_t) INT64_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid offset value exceeds maximum.",
function );
return( -1 );
}
if( ( whence != SEEK_CUR )
&& ( whence != SEEK_END )
&& ( whence != SEEK_SET ) )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported whence.",
function );
return( -1 );
}
if( internal_file->block_size != 0 )
{
if( whence == SEEK_CUR )
{
offset += internal_file->current_offset;
}
else if( whence == SEEK_END )
{
offset += internal_file->size;
}
whence = SEEK_SET;
offset_remainder = offset % internal_file->block_size;
offset -= offset_remainder;
}
if( whence == SEEK_SET )
{
move_method = FILE_BEGIN;
}
else if( whence == SEEK_CUR )
{
move_method = FILE_CURRENT;
}
else if( whence == SEEK_END )
{
move_method = FILE_END;
}
/* SetFilePointerEx cannot be used in combination with FILE_FLAG_OVERLAPPED.
*/
if( internal_file->use_asynchronous_io == 0 )
{
#if defined( __BORLANDC__ ) && __BORLANDC__ <= 0x0520
large_integer_offset.QuadPart = (LONGLONG) offset;
#else
large_integer_offset.LowPart = (DWORD) ( 0x0ffffffffUL & offset );
large_integer_offset.HighPart = (LONG) ( offset >> 32 );
#endif
#if ( WINVER <= 0x0500 )
if( libcfile_SetFilePointerEx(
internal_file->handle,
large_integer_offset,
&large_integer_offset,
move_method ) == 0 )
#else
if( SetFilePointerEx(
internal_file->handle,
large_integer_offset,
&large_integer_offset,
move_method ) == 0 )
#endif
{
error_code = GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
error_code,
"%s: unable to seek offset in file.",
function );
return( -1 );
}
#if defined( __BORLANDC__ ) && __BORLANDC__ <= 0x0520
offset = (off64_t) large_integer_offset.QuadPart;
#else
offset = ( (off64_t) large_integer_offset.HighPart << 32 ) + large_integer_offset.LowPart;
#endif
if( offset < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
"%s: invalid offset: %" PRIi64 " returned.",
function,
offset );
return( -1 );
}
}
internal_file->current_offset = offset;
if( internal_file->block_size != 0 )
{
internal_file->current_offset += offset_remainder;
internal_file->block_data_offset = (size_t) offset_remainder;
internal_file->block_data_size = 0;
}
return( internal_file->current_offset );
}
#elif defined( HAVE_LSEEK )
/* Seeks a certain offset within the file
* This function uses the POSIX lseek function or equivalent
* Returns the offset if the seek is successful or -1 on error
*/
off64_t libcfile_file_seek_offset(
libcfile_file_t *file,
off64_t offset,
int whence,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_seek_offset";
off64_t offset_remainder = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
if( offset > (off64_t) INT64_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid offset value exceeds maximum.",
function );
return( -1 );
}
if( ( whence != SEEK_CUR )
&& ( whence != SEEK_END )
&& ( whence != SEEK_SET ) )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported whence.",
function );
return( -1 );
}
if( internal_file->block_size != 0 )
{
if( whence == SEEK_CUR )
{
offset += internal_file->current_offset;
}
else if( whence == SEEK_END )
{
offset += internal_file->size;
}
whence = SEEK_SET;
offset_remainder = offset % internal_file->block_size;
offset -= offset_remainder;
}
offset = lseek(
internal_file->descriptor,
(off_t) offset,
whence );
if( offset < 0 )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
errno,
"%s: unable to seek offset in file.",
function );
return( -1 );
}
internal_file->current_offset = offset;
if( internal_file->block_size != 0 )
{
internal_file->current_offset += offset_remainder;
internal_file->block_data_offset = (size_t) offset_remainder;
internal_file->block_data_size = 0;
}
return( internal_file->current_offset );
}
#else
#error Missing file lseek function
#endif
#if defined( WINAPI )
/* Resizes the file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 1 if successful or -1 on error
*/
int libcfile_file_resize(
libcfile_file_t *file,
size64_t size,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_resize";
off64_t offset = 0;
LARGE_INTEGER large_integer_offset = LIBCFILE_LARGE_INTEGER_ZERO;
DWORD error_code = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
if( size > (size64_t) INT64_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
#if defined( __BORLANDC__ ) && __BORLANDC__ <= 0x0520
large_integer_offset.QuadPart = (LONGLONG) size;
#else
large_integer_offset.LowPart = (DWORD) ( 0x0ffffffffUL & size );
large_integer_offset.HighPart = (LONG) ( size >> 32 );
#endif
#if ( WINVER <= 0x0500 )
if( libcfile_SetFilePointerEx(
internal_file->handle,
large_integer_offset,
&large_integer_offset,
FILE_BEGIN ) == 0 )
#else
if( SetFilePointerEx(
internal_file->handle,
large_integer_offset,
&large_integer_offset,
FILE_BEGIN ) == 0 )
#endif
{
error_code = GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
error_code,
"%s: unable to seek offset in file.",
function );
return( -1 );
}
#if defined( __BORLANDC__ ) && __BORLANDC__ <= 0x0520
offset = (off64_t) large_integer_offset.QuadPart;
#else
offset = ( (off64_t) large_integer_offset.HighPart << 32 ) + large_integer_offset.LowPart;
#endif
if( offset < 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
"%s: invalid offset: %" PRIi64 " returned.",
function,
offset );
return( -1 );
}
internal_file->current_offset = offset;
#if ( WINVER <= 0x0500 )
if( libcfile_SetEndOfFile(
internal_file->handle ) == 0 )
#else
if( SetEndOfFile(
internal_file->handle ) == 0 )
#endif
{
error_code = GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
error_code,
"%s: unable to resize file.",
function );
return( -1 );
}
return( 1 );
}
#elif defined( HAVE_FTRUNCATE )
/* Resizes the file
* This function uses the POSIX truncate function or equivalent
* Returns 1 if successful or -1 on error
*/
int libcfile_file_resize(
libcfile_file_t *file,
size64_t size,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_resize";
off_t offset = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
#if SIZEOF_OFF_T >= 8
if( size > (size64_t) INT64_MAX )
#else
if( size > (size64_t) INT32_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid size value exceeds maximum.",
function );
return( -1 );
}
if( ftruncate(
internal_file->descriptor,
(off_t) size ) != 0 )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_GENERIC,
errno,
"%s: unable to resize file.",
function );
return( -1 );
}
offset = lseek(
internal_file->descriptor,
0,
SEEK_CUR );
if( offset < 0 )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
errno,
"%s: unable to seek offset in file.",
function );
return( -1 );
}
internal_file->current_offset = (off64_t) offset;
return( 1 );
}
#else
#error Missing file truncate function
#endif
/* Checks if the file is open
* Returns 1 if open, 0 if not or -1 on error
*/
int libcfile_file_is_open(
libcfile_file_t *file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_is_open";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
#if defined( WINAPI )
if( internal_file->handle == INVALID_HANDLE_VALUE )
#else
if( internal_file->descriptor == -1 )
#endif
{
return( 0 );
}
return( 1 );
}
/* Retrieves the current offset in the file
* Returns 1 if successful or -1 on error
*/
int libcfile_file_get_offset(
libcfile_file_t *file,
off64_t *offset,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_get_offset";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
#if defined( WINAPI )
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
#else
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
#endif
if( offset == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid offset.",
function );
return( -1 );
}
*offset = internal_file->current_offset;
return( 1 );
}
#if defined( WINAPI )
#if !defined( IOCTL_DISK_GET_LENGTH_INFO )
#define IOCTL_DISK_GET_LENGTH_INFO \
CTL_CODE( IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS )
typedef struct
{
LARGE_INTEGER Length;
}
GET_LENGTH_INFORMATION;
#endif /* !defined( IOCTL_DISK_GET_LENGTH_INFO ) */
/* Retrieves the size of the file
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 1 if successful or -1 on error
*/
int libcfile_internal_file_get_size(
libcfile_internal_file_t *internal_file,
size64_t *size,
libcerror_error_t **error )
{
DISK_GEOMETRY disk_geometry;
GET_LENGTH_INFORMATION length_information;
static char *function = "libcfile_internal_file_get_size";
LARGE_INTEGER large_integer_size = LIBCFILE_LARGE_INTEGER_ZERO;
size_t read_count = 0;
uint32_t error_code = 0;
int result = 0;
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
if( size == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid size.",
function );
return( -1 );
}
result = libcfile_file_is_device(
(libcfile_file_t *) internal_file,
error );
if( result == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to determine if file is a device.",
function );
return( -1 );
}
else if( result != 0 )
{
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
IOCTL_DISK_GET_LENGTH_INFO,
NULL,
0,
(uint8_t *) &length_information,
sizeof( GET_LENGTH_INFORMATION ),
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: IOCTL_DISK_GET_LENGTH_INFO.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
if( error_code == ERROR_NOT_SUPPORTED )
{
/* A floppy device does not support IOCTL_DISK_GET_LENGTH_INFO
*/
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
(uint8_t *) &disk_geometry,
sizeof( DISK_GEOMETRY ),
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: IOCTL_DISK_GET_DRIVE_GEOMETRY.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else
{
*size = disk_geometry.Cylinders.QuadPart;
*size *= disk_geometry.TracksPerCylinder;
*size *= disk_geometry.SectorsPerTrack;
*size *= disk_geometry.BytesPerSector;
}
}
}
else
{
*size = (size64_t) length_information.Length.HighPart << 32;
*size += (uint32_t) length_information.Length.LowPart;
}
}
else
{
#if ( WINVER <= 0x0500 )
if( libcfile_GetFileSizeEx(
internal_file->handle,
&large_integer_size ) == 0 )
#else
if( GetFileSizeEx(
internal_file->handle,
&large_integer_size ) == 0 )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve file size.",
function );
return( -1 );
}
#if defined( __BORLANDC__ ) && __BORLANDC__ <= 0x520
*size = (size64_t) large_integer_size.QuadPart;
#else
*size = (size64_t) large_integer_size.HighPart << 32;
*size += (uint32_t) large_integer_size.LowPart;
#endif
}
return( 1 );
}
#elif defined( HAVE_FSTAT )
/* Retrieves the size of the file
* This function uses the POSIX fstat function or equivalent
* Returns 1 if successful or -1 on error
*/
int libcfile_internal_file_get_size(
libcfile_internal_file_t *internal_file,
size64_t *size,
libcerror_error_t **error )
{
struct stat file_statistics;
static char *function = "libcfile_internal_file_get_size";
size64_t safe_size = 0;
ssize_t read_count = 0;
off64_t current_offset = 0;
off64_t offset = 0;
#if defined( BLKGETSIZE64 ) || defined( DIOCGMEDIASIZE ) || defined( DIOCGDINFO ) || ( defined( DKIOCGETBLOCKCOUNT ) && defined( DKIOCGETBLOCKSIZE ) )
uint32_t error_code = 0;
#endif
#if !defined( DIOCGMEDIASIZE ) && defined( DIOCGDINFO )
struct disklabel disk_label;
#endif
#if defined( DKIOCGETBLOCKCOUNT ) && defined( DKIOCGETBLOCKSIZE )
uint64_t block_count = 0;
uint32_t bytes_per_sector = 0;
#endif
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
if( size == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid size.",
function );
return( -1 );
}
if( memory_set(
&file_statistics,
0,
sizeof( struct stat ) ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear file statistics.",
function );
return( -1 );
}
if( fstat(
internal_file->descriptor,
&file_statistics ) != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve file statistics.",
function );
return( -1 );
}
if( S_ISBLK( file_statistics.st_mode )
|| S_ISCHR( file_statistics.st_mode ) )
{
#if defined( BLKGETSIZE64 )
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
(uint32_t) BLKGETSIZE64,
NULL,
0,
(uint8_t *) &safe_size,
8,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: BLKGETSIZE64.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
#elif defined( DIOCGMEDIASIZE )
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
(uint32_t) DIOCGMEDIASIZE,
NULL,
0,
(uint8_t *) &safe_size,
8,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: DIOCGMEDIASIZE.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
#elif defined( DIOCGDINFO )
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
(uint32_t) DIOCGDINFO,
NULL,
0,
(uint8_t *) &disk_label,
sizeof( struct disklabel ),
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: DIOCGDINFO.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else
{
safe_size = disk_label.d_secperunit * disk_label.d_secsize;
}
#elif defined( DKIOCGETBLOCKCOUNT ) && defined( DKIOCGETBLOCKSIZE )
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
(uint32_t) DKIOCGETBLOCKSIZE,
NULL,
0,
(uint8_t *) &bytes_per_sector,
4,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: DKIOCGETBLOCKSIZE.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else
{
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
(uint32_t) DKIOCGETBLOCKCOUNT,
NULL,
0,
(uint8_t *) &block_count,
4,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to query device for: DKIOCGETBLOCKCOUNT.",
function );
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
if( ( error != NULL )
&& ( *error != NULL ) )
{
libcnotify_print_error_backtrace(
*error );
}
}
#endif
libcerror_error_free(
error );
}
else
{
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
libcnotify_printf(
"%s: block size: %" PRIu32 " block count: %" PRIu64 " ",
function,
bytes_per_sector,
block_count );
}
#endif
safe_size = (size64_t) ( block_count * bytes_per_sector );
}
}
#endif /* defined( BLKGETSIZE64 ) || defined( DIOCGMEDIASIZE ) || defined( DIOCGDINFO ) || ( defined( DKIOCGETBLOCKCOUNT ) && defined( DKIOCGETBLOCKSIZE ) ) */
if( read_count <= 0 )
{
/* Try to seek the end of the file and determine the size based on the offset
*/
if( libcfile_file_get_offset(
(libcfile_file_t *) internal_file,
¤t_offset,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve current offset.",
function );
return( -1 );
}
offset = libcfile_file_seek_offset(
(libcfile_file_t *) internal_file,
0,
SEEK_END,
error );
if( offset == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
"%s: unable to seek end of file.",
function );
return( -1 );
}
safe_size = (size64_t) offset;
offset = libcfile_file_seek_offset(
(libcfile_file_t *) internal_file,
current_offset,
SEEK_SET,
error );
if( offset == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_SEEK_FAILED,
"%s: unable to seek offset: %" PRIi64 ".",
function,
current_offset );
return( -1 );
}
}
#if defined( HAVE_DEBUG_OUTPUT )
if( libcnotify_verbose != 0 )
{
libcnotify_printf(
"%s: device media size: %" PRIu64 "\n",
function,
safe_size );
}
#endif
}
else
{
safe_size = (size64_t) file_statistics.st_size;
}
*size = safe_size;
return( 1 );
}
#else
#error Missing file get size function
#endif
/* Retrieves the size of the file
* Returns 1 if successful or -1 on error
*/
int libcfile_file_get_size(
libcfile_file_t *file,
size64_t *size,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_get_size";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( size == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid size.",
function );
return( -1 );
}
*size = internal_file->size;
return( 1 );
}
#if defined( WINAPI )
/* Determines if a file is a device
* This function uses the WINAPI function for Windows XP (0x0501) or later
* or tries to dynamically call the function for Windows 2000 (0x0500) or earlier
* Returns 1 if true, 0 if not or -1 on error
*/
int libcfile_file_is_device(
libcfile_file_t *file,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_is_device";
DWORD file_type = 0;
int result = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
/* TODO what about FILE_ATTRIBUTE_DEVICE using GetFileAttributes() */
/* Use the GetFileType function to rule out certain file types
* like pipes, sockets, etc.
*/
#if ( WINVER <= 0x0500 )
file_type = libcfile_GetFileType(
internal_file->handle );
#else
file_type = GetFileType(
internal_file->handle );
#endif
if( file_type == FILE_TYPE_UNKNOWN )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to determine file type.",
function );
return( -1 );
}
else if( file_type == FILE_TYPE_DISK )
{
if( internal_file->is_device_filename )
{
result = 1;
}
}
return( result );
}
#elif defined( HAVE_FSTAT )
/* Determines if a file is a device
* This function uses the POSIX fstat function or equivalent
* Returns 1 if true, 0 if not or -1 on error
*/
int libcfile_file_is_device(
libcfile_file_t *file,
libcerror_error_t **error )
{
struct stat file_statistics;
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_is_device";
int result = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
if( memory_set(
&file_statistics,
0,
sizeof( struct stat ) ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear file statistics.",
function );
return( -1 );
}
if( fstat(
internal_file->descriptor,
&file_statistics ) != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_GET_FAILED,
"%s: unable to retrieve file statistics.",
function );
return( -1 );
}
if( S_ISBLK( file_statistics.st_mode )
|| S_ISCHR( file_statistics.st_mode ) )
{
result = 1;
}
return( result );
}
#else
#error Missing file is device function
#endif
#if defined( HAVE_IOCTL ) || defined( WINAPI )
/* Read data from a device file using IO control
* This function uses the POSIX ioctl function or WINAPI DeviceIoControl
* Returns the number of bytes read if successful or -1 on error
*/
ssize_t libcfile_internal_file_io_control_read_with_error_code(
libcfile_internal_file_t *internal_file,
uint32_t control_code,
uint8_t *control_data,
size_t control_data_size,
uint8_t *data,
size_t data_size,
uint32_t *error_code,
libcerror_error_t **error )
{
static char *function = "libcfile_internal_file_io_control_read_with_error_code";
#if defined( WINAPI )
DWORD response_count = 0;
#endif
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
#if defined( WINAPI )
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
#else
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
#endif
if( control_data == NULL )
{
if( control_data_size != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid control data size value exceeds maximum.",
function );
return( -1 );
}
}
else
{
#if ( UINT32_MAX < SSIZE_MAX )
if( control_data_size > (size_t) UINT32_MAX )
#else
if( control_data_size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid control data size value exceeds maximum.",
function );
return( -1 );
}
}
if( data == NULL )
{
if( data_size != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid data size value exceeds maximum.",
function );
return( -1 );
}
}
else
{
#if ( UINT32_MAX < SSIZE_MAX )
if( data_size > (size_t) UINT32_MAX )
#else
if( data_size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid data size value exceeds maximum.",
function );
return( -1 );
}
}
if( error_code == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid error code.",
function );
return( -1 );
}
#if defined( WINAPI )
if( DeviceIoControl(
internal_file->handle,
(DWORD) control_code,
control_data,
(DWORD) control_data_size,
data,
(DWORD) data_size,
&response_count,
NULL ) == 0 )
{
*error_code = (uint32_t) GetLastError();
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
*error_code,
"%s: unable to IO control device.",
function );
return( -1 );
}
#if ( SSIZE_MAX < UINT32_MAX )
if( response_count > (size_t) SSIZE_MAX )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
"%s: invalid response count value out of bounds.",
function );
return( -1 );
}
#endif
return( (ssize_t) response_count );
#elif defined( HAVE_IOCTL )
if( control_data != NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported control data.",
function );
return( -1 );
}
if( ioctl(
internal_file->descriptor,
(int) control_code,
data ) == -1 )
{
*error_code = (uint32_t) errno;
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
*error_code,
"%s: unable to IO control device.",
function );
return( -1 );
}
return( (size_t) data_size );
#endif
}
#else
#error Missing file IO control with data function
#endif
/* Read data from a device file using IO control
* Returns the number of bytes read if successful or -1 on error
*/
ssize_t libcfile_file_io_control_read(
libcfile_file_t *file,
uint32_t control_code,
uint8_t *control_data,
size_t control_data_size,
uint8_t *data,
size_t data_size,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_io_control_read";
ssize_t read_count = 0;
uint32_t error_code = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
control_code,
control_data,
control_data_size,
data,
data_size,
&error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to to IO control device.",
function );
return( -1 );
}
return( read_count );
}
/* Read data from a device file using IO control
* Returns the number of bytes read if successful or -1 on error
*/
ssize_t libcfile_file_io_control_read_with_error_code(
libcfile_file_t *file,
uint32_t control_code,
uint8_t *control_data,
size_t control_data_size,
uint8_t *data,
size_t data_size,
uint32_t *error_code,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_io_control_read_with_error_code";
ssize_t read_count = 0;
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
read_count = libcfile_internal_file_io_control_read_with_error_code(
internal_file,
control_code,
control_data,
control_data_size,
data,
data_size,
error_code,
error );
if( read_count == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_IOCTL_FAILED,
"%s: unable to to IO control device.",
function );
return( -1 );
}
return( read_count );
}
/* On some versions of Linux the FADVISE definions seem to be missing from fcntl.h
*/
#if defined( HAVE_POSIX_FADVISE ) && !defined( WINAPI )
#if !defined( POSIX_FADV_NORMAL )
#define POSIX_FADV_NORMAL 0
#endif
#if !defined( POSIX_FADV_RANDOM )
#define POSIX_FADV_RANDOM 1
#endif
#if !defined( POSIX_FADV_SEQUENTIAL )
#define POSIX_FADV_SEQUENTIAL 2
#endif
#endif /* #if defined( HAVE_POSIX_FADVISE ) && !defined( WINAPI ) */
/* Sets the expected access behavior so the system can optimize the access
* Returns 1 if successful or -1 on error
*/
int libcfile_file_set_access_behavior(
libcfile_file_t *file,
int access_behavior,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_set_access_behavior";
#if defined( HAVE_POSIX_FADVISE ) && !defined( WINAPI )
int advice = POSIX_FADV_NORMAL;
int result = 0;
#endif
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
#if defined( WINAPI )
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
#else
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
#endif
if( ( access_behavior != LIBCFILE_ACCESS_BEHAVIOR_NORMAL )
&& ( access_behavior != LIBCFILE_ACCESS_BEHAVIOR_RANDOM )
&& ( access_behavior != LIBCFILE_ACCESS_BEHAVIOR_SEQUENTIAL ) )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: unsupported access behavior: %d.",
function,
access_behavior );
return( -1 );
}
#if defined( HAVE_POSIX_FADVISE ) && !defined( WINAPI )
if( access_behavior == LIBCFILE_ACCESS_BEHAVIOR_NORMAL )
{
advice = POSIX_FADV_NORMAL;
}
else if( access_behavior == LIBCFILE_ACCESS_BEHAVIOR_RANDOM )
{
advice = POSIX_FADV_RANDOM;
}
else if( access_behavior == LIBCFILE_ACCESS_BEHAVIOR_SEQUENTIAL )
{
advice = POSIX_FADV_SEQUENTIAL;
}
result = posix_fadvise(
internal_file->descriptor,
0,
0,
advice );
/* Safely ignore if the device does not support fadvise.
* Note that FreeBSD 10.0 had a bug and was returning -1
* and setting errno.
*/
if( ( result != 0 )
&& ( result != ENODEV ) )
{
libcerror_system_set_error(
error,
LIBCERROR_ERROR_DOMAIN_IO,
LIBCERROR_IO_ERROR_GENERIC,
errno,
"%s: unable to advice file descriptor on access behavior.",
function );
return( -1 );
}
#endif /* defined( HAVE_POSIX_FADVISE ) && !defined( WINAPI ) */
return( 1 );
}
/* Sets the block size for the read and seek operations
* A block size of 0 represents no block-based operations
* The total size must be a multitude of block size
* Returns 1 if successful or -1 on error
*/
int libcfile_internal_file_set_block_size(
libcfile_internal_file_t *internal_file,
size_t block_size,
libcerror_error_t **error )
{
static char *function = "libcfile_internal_file_set_block_size";
if( internal_file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
#if defined( WINAPI ) && ( UINT32_MAX < SSIZE_MAX )
if( block_size > (size_t) UINT32_MAX )
#else
if( block_size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid block size value exceeds maximum.",
function );
return( -1 );
}
if( internal_file->block_data != NULL )
{
if( block_size != internal_file->block_size )
{
memory_free(
internal_file->block_data );
internal_file->block_data = NULL;
internal_file->block_data_size = 0;
}
}
if( internal_file->block_data == NULL )
{
if( block_size > 0 )
{
internal_file->block_data = (uint8_t *) memory_allocate(
sizeof( uint8_t ) * block_size );
if( internal_file->block_data == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
"%s: unable to create block data.",
function );
return( -1 );
}
if( memory_set(
internal_file->block_data,
0,
block_size ) == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_MEMORY,
LIBCERROR_MEMORY_ERROR_SET_FAILED,
"%s: unable to clear block data.",
function );
return( -1 );
}
}
internal_file->block_size = block_size;
}
return( 1 );
}
/* Sets the block size for the read and seek operations
* A block size of 0 represents no block-based operations
* The total size must be a multitude of block size
* Returns 1 if successful or -1 on error
*/
int libcfile_file_set_block_size(
libcfile_file_t *file,
size_t block_size,
libcerror_error_t **error )
{
libcfile_internal_file_t *internal_file = NULL;
static char *function = "libcfile_file_set_block_size";
if( file == NULL )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
"%s: invalid file.",
function );
return( -1 );
}
internal_file = (libcfile_internal_file_t *) file;
if( ( internal_file->access_flags & LIBCFILE_ACCESS_FLAG_WRITE ) != 0 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
"%s: setting block size not supported with write access.",
function );
return( -1 );
}
#if defined( WINAPI )
if( internal_file->handle == INVALID_HANDLE_VALUE )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing handle.",
function );
return( -1 );
}
#else
if( internal_file->descriptor == -1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
"%s: invalid file - missing descriptor.",
function );
return( -1 );
}
#endif
#if defined( WINAPI ) && ( UINT32_MAX < SSIZE_MAX )
if( block_size > (size_t) UINT32_MAX )
#else
if( block_size > (size_t) SSIZE_MAX )
#endif
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
"%s: invalid block size value exceeds maximum.",
function );
return( -1 );
}
if( ( block_size != 0 )
&& ( ( internal_file->size % block_size ) != 0 ) )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
"%s: invalid block size value out of bounds.",
function );
return( -1 );
}
if( libcfile_internal_file_set_block_size(
internal_file,
block_size,
error ) != 1 )
{
libcerror_error_set(
error,
LIBCERROR_ERROR_DOMAIN_RUNTIME,
LIBCERROR_RUNTIME_ERROR_SET_FAILED,
"%s: unable to set block size.",
function );
return( -1 );
}
return( 1 );
}