1717
1818#include <config.h>
1919
20+ #include <dirent.h>
2021#include <endian.h>
2122#include <errno.h>
2223#include <fcntl.h>
24+ #include <glib/gstdio.h>
2325#include <inttypes.h>
2426#include <libdevmapper.h>
2527#include <linux/fs.h>
3941#include "gpt.h"
4042#include "ldm.h"
4143
44+ #ifndef G_DEFINE_AUTOPTR_CLEANUP_FUNC_FILE_CLOSER
45+ #define G_DEFINE_AUTOPTR_CLEANUP_FUNC_FILE_CLOSER
46+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE , fclose )
47+ #endif
48+ #ifndef G_DEFINE_AUTOPTR_CLEANUP_FUNC_DIR_CLOSER
49+ #define G_DEFINE_AUTOPTR_CLEANUP_FUNC_DIR_CLOSER
50+ G_DEFINE_AUTOPTR_CLEANUP_FUNC (DIR , closedir )
51+ #endif
52+
4253#define DM_UUID_PREFIX "LDM-"
4354
4455#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-" \
@@ -2729,6 +2740,113 @@ _dm_remove(const gchar * const name, uint32_t udev_cookie, GError ** const err)
27292740 return r ;
27302741}
27312742
2743+ static int _find_partition (GString * target_params ,
2744+ const gchar * dev_name , guint64 abs_part_start , guint64 part_size )
2745+ {
2746+ g_autofree gchar * base_name = g_path_get_basename (dev_name );
2747+ if (!base_name || strlen (base_name ) == 0 )
2748+ return -1 ;
2749+
2750+ g_autofree gchar * sysfs_path = g_strdup_printf ("/sys/block/%s" , base_name );
2751+ if (!sysfs_path )
2752+ return -1 ;
2753+
2754+ g_autoptr (DIR ) dir = opendir (sysfs_path );
2755+ if (!dir ) {
2756+ return -1 ;
2757+ }
2758+
2759+ struct dirent * entry ;
2760+ int found = 0 ;
2761+ while ((entry = readdir (dir )) != NULL && !found ) {
2762+ if (strcmp (entry -> d_name , "." ) == 0 || strcmp (entry -> d_name , ".." ) == 0 ) {
2763+ continue ;
2764+ }
2765+
2766+ g_autofree gchar * partition_dir_path = g_build_filename (sysfs_path , entry -> d_name , NULL );
2767+ if (!partition_dir_path )
2768+ continue ;
2769+
2770+ g_autofree gchar * partition_file_path = g_build_filename (partition_dir_path , "partition" , NULL );
2771+ g_autofree gchar * start_file_path = g_build_filename (partition_dir_path , "start" , NULL );
2772+ g_autofree gchar * size_file_path = g_build_filename (partition_dir_path , "size" , NULL );
2773+
2774+ if (!partition_file_path || !start_file_path || !size_file_path )
2775+ continue ;
2776+
2777+ // Check if the 'partition' file exists within this subdirectory
2778+ // This is a filter against other subdirectories that do not
2779+ // refer to partitions
2780+ if (g_access (partition_file_path , F_OK ) == 0 &&
2781+ g_access (start_file_path , F_OK ) == 0 &&
2782+ g_access (size_file_path , F_OK ) == 0 ) {
2783+
2784+ g_autoptr (FILE ) fstart = fopen (start_file_path , "r" );
2785+ if (!fstart )
2786+ continue ;
2787+
2788+ guint64 curr_part_start = 0 ;
2789+ if (fscanf (fstart , "%" PRIu64 , & curr_part_start ) == 1 ) {
2790+ g_autoptr (FILE ) fsize = fopen (size_file_path , "r" );
2791+ if (!fsize )
2792+ continue ;
2793+
2794+ guint64 curr_part_size = 0 ;
2795+ if (fscanf (fsize , "%" PRIu64 , & curr_part_size ) == 1 ) {
2796+ guint64 curr_part_end = curr_part_start + curr_part_size ;
2797+ guint64 target_part_end = abs_part_start + part_size ;
2798+
2799+ if (abs_part_start >= curr_part_start &&
2800+ target_part_end <= curr_part_end )
2801+ {
2802+ g_autofree gchar * dev_dir = g_path_get_dirname (dev_name );
2803+ if (!dev_dir )
2804+ return -1 ;
2805+
2806+ g_autofree gchar * full_part_path = g_build_filename (dev_dir , entry -> d_name , NULL );
2807+ if (!full_part_path )
2808+ return -1 ;
2809+
2810+ g_string_printf (target_params , "%s %" PRIu64 ,
2811+ full_part_path ,
2812+ abs_part_start - curr_part_start );
2813+ found = 1 ;
2814+ }
2815+ }
2816+ }
2817+ }
2818+ }
2819+
2820+ return found ? 0 : -1 ;
2821+ }
2822+
2823+ static void _refine_partition (GString * target_params ,
2824+ const LDMDiskPrivate * const disk , guint64 part_start , guint64 part_size )
2825+ {
2826+ // The goal here is to try to use partition's block device instead
2827+ // of whole disk's device. The problem of using the whole disk is this:
2828+ // If LDM disk has at least one partition mounted directly, then it won't
2829+ // be possible to create *any* LDM devmapper device using that disk.
2830+ //
2831+ // Mounting LDM partition directly may make sense for cases like Linux
2832+ // system booting from LDM. The approach is the following:
2833+ // 1. First, you need to split GPT/MBR's LDM protective partition into a few
2834+ // separate protective partitions, so that your target LDM partition is
2835+ // exactly matched by one protective partition.
2836+ // 2. Then you'll be able to mount it as usual, boot from it and so on.
2837+ // Windows actually does this for its C:\ partition is the respective
2838+ // disk is converted to LDM.
2839+
2840+ if (_find_partition (target_params , disk -> device ,
2841+ disk -> data_start + part_start , part_size ) == 0 ) {
2842+ return ;
2843+ }
2844+
2845+ // fallback
2846+ g_string_printf (target_params , "%s %" PRIu64 ,
2847+ disk -> device , disk -> data_start + part_start );
2848+ }
2849+
27322850static GString *
27332851_dm_create_part (const LDMPartitionPrivate * const part , uint32_t cookie ,
27342852 GError * * const err )
@@ -2747,8 +2865,7 @@ _dm_create_part(const LDMPartitionPrivate * const part, uint32_t cookie,
27472865 target .size = part -> size ;
27482866 target .type = "linear" ;
27492867 target .params = g_string_new ("" );
2750- g_string_printf (target .params , "%s %" PRIu64 ,
2751- disk -> device , disk -> data_start + part -> start );
2868+ _refine_partition (target .params , disk , part -> start , part -> size );
27522869
27532870 GString * name = _dm_part_name (part );
27542871 GString * uuid = _dm_part_uuid (part );
@@ -2817,9 +2934,8 @@ _dm_create_spanned(const LDMVolumePrivate * const vol, GError ** const err)
28172934 target -> size = part -> size ;
28182935 target -> type = "linear" ;
28192936 target -> params = g_string_new ("" );
2820- g_string_append_printf (target -> params , "%s %" PRIu64 ,
2821- disk -> device ,
2822- disk -> data_start + part -> start );
2937+ _refine_partition (target -> params , disk , part -> start , part -> size );
2938+
28232939 pos += part -> size ;
28242940 }
28252941
@@ -2878,9 +2994,7 @@ _dm_create_striped(const LDMVolumePrivate * const vol, GError ** const err)
28782994 goto out ;
28792995 }
28802996
2881- g_string_append_printf (target .params , " %s %" PRIu64 ,
2882- disk -> device ,
2883- disk -> data_start + part -> start );
2997+ _refine_partition (target .params , disk , part -> start , part -> size );
28842998 }
28852999
28863000 uint32_t cookie ;
0 commit comments