diff --git a/libfsxfs/fsxfs_superblock.h b/libfsxfs/fsxfs_superblock.h index 8c8feb9..5d67adf 100644 --- a/libfsxfs/fsxfs_superblock.h +++ b/libfsxfs/fsxfs_superblock.h @@ -497,6 +497,26 @@ struct fsxfs_superblock_v5 * Consists of 4 bytes */ uint8_t secondary_feature_flags_copy[ 4 ]; + + /* Compatible feature flags (v5 only) + * Consists of 4 bytes + */ + uint8_t features_compat[ 4 ]; + + /* Read-only compatible feature flags (v5 only) + * Consists of 4 bytes + */ + uint8_t features_ro_compat[ 4 ]; + + /* Incompatible feature flags (v5 only) + * Consists of 4 bytes + */ + uint8_t features_incompat[ 4 ]; + + /* Log incompatible feature flags (v5 only) + * Consists of 4 bytes + */ + uint8_t features_log_incompat[ 4 ]; }; #if defined( __cplusplus ) diff --git a/libfsxfs/libfsxfs_definitions.h.in b/libfsxfs/libfsxfs_definitions.h.in index 8d10cf8..521ad4c 100644 --- a/libfsxfs/libfsxfs_definitions.h.in +++ b/libfsxfs/libfsxfs_definitions.h.in @@ -98,6 +98,13 @@ enum LIBFSXFS_SECONDARY_FEATURE_FLAGS LIBFSXFS_SECONDARY_FEATURE_FLAG_FILE_TYPE = 0x00000200UL }; +/* The incompatible feature flags (v5 only) + */ +enum LIBFSXFS_INCOMPAT_FEATURE_FLAGS +{ + LIBFSXFS_INCOMPAT_FEATURE_FLAG_BIGTIME = 0x00000008UL +}; + /* The fork types */ enum LIBFSXFS_FORK_TYPES diff --git a/libfsxfs/libfsxfs_inode.c b/libfsxfs/libfsxfs_inode.c index bcec949..c65f84d 100644 --- a/libfsxfs/libfsxfs_inode.c +++ b/libfsxfs/libfsxfs_inode.c @@ -218,11 +218,38 @@ int libfsxfs_inode_free( return( result ); } +/* Converts bigtime ondisk timestamp to Unix nanoseconds + * Returns the Unix timestamp in nanoseconds + */ +static int64_t libfsxfs_inode_bigtime_to_unix( + uint64_t ondisk_nanoseconds ) +{ + #define FSXFS_BIGTIME_EPOCH_OFFSET -2147483648LL + #define NSEC_PER_SEC 1000000000ULL + + uint64_t seconds; + uint32_t nanoseconds; + int64_t unix_seconds; + int64_t unix_nanoseconds; + + seconds = ondisk_nanoseconds / NSEC_PER_SEC; + nanoseconds = ondisk_nanoseconds % NSEC_PER_SEC; + + unix_seconds = (int64_t) seconds + FSXFS_BIGTIME_EPOCH_OFFSET; + unix_nanoseconds = unix_seconds * (int64_t) NSEC_PER_SEC + nanoseconds; + + return( unix_nanoseconds ); + + #undef FSXFS_BIGTIME_EPOCH_OFFSET + #undef NSEC_PER_SEC +} + /* Reads the inode data * Returns 1 if successful or -1 on error */ int libfsxfs_inode_read_data( libfsxfs_inode_t *inode, + libfsxfs_io_handle_t *io_handle, const uint8_t *data, size_t data_size, libcerror_error_t **error ) @@ -230,11 +257,11 @@ int libfsxfs_inode_read_data( static char *function = "libfsxfs_inode_read_data"; size_t data_fork_size = 0; size_t inode_data_size = 0; + uint64_t value_64bit = 0; uint32_t value_32bit = 0; uint8_t format_version = 0; #if defined( HAVE_DEBUG_OUTPUT ) - uint64_t value_64bit = 0; uint16_t value_16bit = 0; #endif @@ -348,59 +375,95 @@ int libfsxfs_inode_read_data( ( (fsxfs_inode_v2_t *) data )->number_of_links, inode->number_of_links ); } - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->access_time, - value_32bit ); - - inode->access_time = (int32_t) value_32bit * (int64_t) 1000000000; - - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->access_time_nano_seconds, - value_32bit ); - - if( inode->access_time > 0 ) + if( ( io_handle->features_incompat & LIBFSXFS_INCOMPAT_FEATURE_FLAG_BIGTIME ) != 0 ) { - inode->access_time += value_32bit; + byte_stream_copy_to_uint64_big_endian( + ( (fsxfs_inode_v1_t *) data )->access_time, + value_64bit ); + + inode->access_time = libfsxfs_inode_bigtime_to_unix( + value_64bit ); } else { - inode->access_time -= value_32bit; - } - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->modification_time, - value_32bit ); + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->access_time, + value_32bit ); - inode->modification_time = (int32_t) value_32bit * (int64_t) 1000000000; + inode->access_time = (int32_t) value_32bit * (int64_t) 1000000000; - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->modification_time_nano_seconds, - value_32bit ); + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->access_time_nano_seconds, + value_32bit ); - if( inode->modification_time > 0 ) + if( inode->access_time > 0 ) + { + inode->access_time += value_32bit; + } + else + { + inode->access_time -= value_32bit; + } + } + if( ( io_handle->features_incompat & LIBFSXFS_INCOMPAT_FEATURE_FLAG_BIGTIME ) != 0 ) { - inode->modification_time += value_32bit; + byte_stream_copy_to_uint64_big_endian( + ( (fsxfs_inode_v1_t *) data )->modification_time, + value_64bit ); + + inode->modification_time = libfsxfs_inode_bigtime_to_unix( + value_64bit ); } else { - inode->modification_time -= value_32bit; - } - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->inode_change_time, - value_32bit ); + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->modification_time, + value_32bit ); - inode->inode_change_time = (int32_t) value_32bit * (int64_t) 1000000000; + inode->modification_time = (int32_t) value_32bit * (int64_t) 1000000000; - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v1_t *) data )->inode_change_time_nano_seconds, - value_32bit ); + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->modification_time_nano_seconds, + value_32bit ); - if( inode->inode_change_time > 0 ) + if( inode->modification_time > 0 ) + { + inode->modification_time += value_32bit; + } + else + { + inode->modification_time -= value_32bit; + } + } + if( ( io_handle->features_incompat & LIBFSXFS_INCOMPAT_FEATURE_FLAG_BIGTIME ) != 0 ) { - inode->inode_change_time += value_32bit; + byte_stream_copy_to_uint64_big_endian( + ( (fsxfs_inode_v1_t *) data )->inode_change_time, + value_64bit ); + + inode->inode_change_time = libfsxfs_inode_bigtime_to_unix( + value_64bit ); } else { - inode->inode_change_time -= value_32bit; + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->inode_change_time, + value_32bit ); + + inode->inode_change_time = (int32_t) value_32bit * (int64_t) 1000000000; + + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v1_t *) data )->inode_change_time_nano_seconds, + value_32bit ); + + if( inode->inode_change_time > 0 ) + { + inode->inode_change_time += value_32bit; + } + else + { + inode->inode_change_time -= value_32bit; + } } byte_stream_copy_to_uint64_big_endian( ( (fsxfs_inode_v1_t *) data )->data_size, @@ -690,23 +753,35 @@ int libfsxfs_inode_read_data( } if( format_version == 3 ) { - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v3_t *) data )->creation_time, - value_32bit ); - - inode->creation_time = (int32_t) value_32bit * (int64_t) 1000000000; - - byte_stream_copy_to_uint32_big_endian( - ( (fsxfs_inode_v3_t *) data )->creation_time_nano_seconds, - value_32bit ); - - if( inode->creation_time > 0 ) + if( ( io_handle->features_incompat & LIBFSXFS_INCOMPAT_FEATURE_FLAG_BIGTIME ) != 0 ) { - inode->creation_time += value_32bit; + byte_stream_copy_to_uint64_big_endian( + ( (fsxfs_inode_v3_t *) data )->creation_time, + value_64bit ); + + inode->creation_time = libfsxfs_inode_bigtime_to_unix( + value_64bit ); } else { - inode->creation_time -= value_32bit; + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v3_t *) data )->creation_time, + value_32bit ); + + inode->creation_time = (int32_t) value_32bit * (int64_t) 1000000000; + + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_inode_v3_t *) data )->creation_time_nano_seconds, + value_32bit ); + + if( inode->creation_time > 0 ) + { + inode->creation_time += value_32bit; + } + else + { + inode->creation_time -= value_32bit; + } } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) @@ -931,6 +1006,7 @@ int libfsxfs_inode_read_file_io_handle( } if( libfsxfs_inode_read_data( inode, + io_handle, inode->data, inode->data_size, error ) != 1 ) diff --git a/libfsxfs/libfsxfs_inode.h b/libfsxfs/libfsxfs_inode.h index 7a1799b..9d30bf9 100644 --- a/libfsxfs/libfsxfs_inode.h +++ b/libfsxfs/libfsxfs_inode.h @@ -151,6 +151,7 @@ int libfsxfs_inode_free( int libfsxfs_inode_read_data( libfsxfs_inode_t *inode, + libfsxfs_io_handle_t *io_handle, const uint8_t *data, size_t data_size, libcerror_error_t **error ); diff --git a/libfsxfs/libfsxfs_io_handle.h b/libfsxfs/libfsxfs_io_handle.h index 4ff33b9..b85d1b4 100644 --- a/libfsxfs/libfsxfs_io_handle.h +++ b/libfsxfs/libfsxfs_io_handle.h @@ -44,6 +44,10 @@ struct libfsxfs_io_handle */ uint32_t secondary_feature_flags; + /* Incompatible feature flags (v5 only) + */ + uint32_t features_incompat; + /* The block size */ uint32_t block_size; diff --git a/libfsxfs/libfsxfs_superblock.c b/libfsxfs/libfsxfs_superblock.c index 385796b..82cb494 100644 --- a/libfsxfs/libfsxfs_superblock.c +++ b/libfsxfs/libfsxfs_superblock.c @@ -281,6 +281,12 @@ int libfsxfs_superblock_read_data( ( (fsxfs_superblock_t *) data )->secondary_feature_flags, superblock->secondary_feature_flags ); + if( superblock->format_version == 5 ) + { + byte_stream_copy_to_uint32_big_endian( + ( (fsxfs_superblock_v5_t *) data )->features_incompat, + superblock->features_incompat ); + } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { diff --git a/libfsxfs/libfsxfs_superblock.h b/libfsxfs/libfsxfs_superblock.h index 8bd9547..db180aa 100644 --- a/libfsxfs/libfsxfs_superblock.h +++ b/libfsxfs/libfsxfs_superblock.h @@ -90,6 +90,10 @@ struct libfsxfs_superblock */ uint32_t secondary_feature_flags; + /* Incompatible feature flags (v5 only) + */ + uint32_t features_incompat; + /* Number of bits used for the relative block number */ uint8_t number_of_relative_block_number_bits; diff --git a/libfsxfs/libfsxfs_volume.c b/libfsxfs/libfsxfs_volume.c index 5356192..7847a3c 100644 --- a/libfsxfs/libfsxfs_volume.c +++ b/libfsxfs/libfsxfs_volume.c @@ -1056,6 +1056,7 @@ int libfsxfs_internal_volume_open_read( internal_volume->superblock = superblock; internal_volume->io_handle->format_version = superblock->format_version; internal_volume->io_handle->secondary_feature_flags = superblock->secondary_feature_flags; + internal_volume->io_handle->features_incompat = superblock->features_incompat; internal_volume->io_handle->block_size = superblock->block_size; internal_volume->io_handle->allocation_group_size = superblock->allocation_group_size; internal_volume->io_handle->inode_size = superblock->inode_size;