@@ -2729,6 +2729,121 @@ _dm_remove(const gchar * const name, uint32_t udev_cookie, GError ** const err)
27292729 return r ;
27302730}
27312731
2732+ static int _find_partition (GString * target_params ,
2733+ const gchar * dev_name , guint64 abs_part_start , guint64 part_size )
2734+ {
2735+ char * dev_name_copy = strdup (dev_name ); // basename might modify its arg
2736+ if (!dev_name_copy ) {
2737+ return -1 ;
2738+ }
2739+ char * base_name = basename (dev_name_copy );
2740+ if (!base_name || strlen (base_name ) == 0 ) {
2741+ free (dev_name_copy );
2742+ return -1 ;
2743+ }
2744+
2745+ char sysfs_path [PATH_MAX ];
2746+ snprintf (sysfs_path , sizeof (sysfs_path ), "/sys/block/%s" , base_name );
2747+
2748+ DIR * dir = opendir (sysfs_path );
2749+ if (!dir ) {
2750+ free (dev_name_copy );
2751+ return -1 ;
2752+ }
2753+
2754+ struct dirent * entry ;
2755+ int found = 0 ;
2756+ while ((entry = readdir (dir )) != NULL && !found ) {
2757+ if (strcmp (entry -> d_name , "." ) == 0 || strcmp (entry -> d_name , ".." ) == 0 ) {
2758+ continue ;
2759+ }
2760+
2761+ char partition_file_path [PATH_MAX ];
2762+ if (snprintf (partition_file_path , sizeof (partition_file_path ),
2763+ "%s/%s/partition" , sysfs_path , entry -> d_name ) < 0 )
2764+ continue ;
2765+
2766+ char start_file_path [PATH_MAX ];
2767+ if (snprintf (start_file_path , sizeof (start_file_path ), "%s/%s/start" ,
2768+ sysfs_path , entry -> d_name ) < 0 )
2769+ continue ;
2770+
2771+ char size_file_path [PATH_MAX ];
2772+ if (snprintf (size_file_path , sizeof (size_file_path ), "%s/%s/size" ,
2773+ sysfs_path , entry -> d_name ) < 0 )
2774+ continue ;
2775+
2776+ // Check if the 'partition' file exists within this subdirectory
2777+ // This is a filter against other subdirectories that do not
2778+ // refer to partitions
2779+ if (access (partition_file_path , F_OK ) == 0 &&
2780+ access (start_file_path , F_OK ) == 0 &&
2781+ access (size_file_path , F_OK ) == 0 ) {
2782+
2783+ FILE * fstart = fopen (start_file_path , "r" );
2784+ if (fstart ) {
2785+ guint64 curr_part_start = 0 ;
2786+ if (fscanf (fstart , "%" PRIu64 , & curr_part_start ) == 1 ) {
2787+ FILE * fsize = fopen (size_file_path , "r" );
2788+ if (fsize ) {
2789+ guint64 curr_part_size = 0 ;
2790+ if (fscanf (fsize , "%" PRIu64 , & curr_part_size ) == 1 ) {
2791+ if (abs_part_start >= curr_part_start &&
2792+ abs_part_start + part_size <=
2793+ curr_part_start + curr_part_size )
2794+ {
2795+ char * dir_name = strdup (dev_name );
2796+ int last_slash = strlen (dev_name ) - strlen (base_name );
2797+ dir_name [last_slash ] = '\0' ;
2798+
2799+ g_string_printf (target_params , "%s%s %" PRIu64 ,
2800+ dir_name , entry -> d_name ,
2801+ abs_part_start - curr_part_start );
2802+ found = 1 ;
2803+ free (dir_name );
2804+ }
2805+ }
2806+ fclose (fsize );
2807+ }
2808+ }
2809+ fclose (fstart );
2810+ }
2811+ }
2812+ }
2813+
2814+ closedir (dir );
2815+ free (dev_name_copy );
2816+
2817+ return found ? 0 : -1 ;
2818+ }
2819+
2820+ static void _refine_partition (GString * target_params ,
2821+ const LDMDiskPrivate * const disk , guint64 part_start , guint64 part_size )
2822+ {
2823+ // The goal here is to try to use partition's block device instead
2824+ // of whole disk's device. The problem of using the whole disk is this:
2825+ // If LDM disk has at least one partition mounted directly, then it won't
2826+ // be possible to create *any* LDM devmapper device using that disk.
2827+ //
2828+ // Mounting LDM partition directly may make sense for cases like Linux
2829+ // system booting from LDM. The approach is the following:
2830+ // 1. First, you need to split GPT/MBR's LDM protective partition into a few
2831+ // separate protective partitions, so that your target LDM partition is
2832+ // exactly matched by one protective partition.
2833+ // 2. Then you'll be able to mount it as usual, boot from it and so on.
2834+ // Windows actually does this for its C:\ partition is the respective
2835+ // disk is converted to LDM.
2836+
2837+ if (_find_partition (target_params , disk -> device ,
2838+ disk -> data_start + part_start , part_size ) == 0 ) {
2839+ return ;
2840+ }
2841+
2842+ // fallback
2843+ g_string_printf (target_params , "%s %" PRIu64 ,
2844+ disk -> device , disk -> data_start + part_start );
2845+ }
2846+
27322847static GString *
27332848_dm_create_part (const LDMPartitionPrivate * const part , uint32_t cookie ,
27342849 GError * * const err )
@@ -2747,8 +2862,7 @@ _dm_create_part(const LDMPartitionPrivate * const part, uint32_t cookie,
27472862 target .size = part -> size ;
27482863 target .type = "linear" ;
27492864 target .params = g_string_new ("" );
2750- g_string_printf (target .params , "%s %" PRIu64 ,
2751- disk -> device , disk -> data_start + part -> start );
2865+ _refine_partition (target .params , disk , part -> start , part -> size );
27522866
27532867 GString * name = _dm_part_name (part );
27542868 GString * uuid = _dm_part_uuid (part );
@@ -2817,9 +2931,8 @@ _dm_create_spanned(const LDMVolumePrivate * const vol, GError ** const err)
28172931 target -> size = part -> size ;
28182932 target -> type = "linear" ;
28192933 target -> params = g_string_new ("" );
2820- g_string_append_printf (target -> params , "%s %" PRIu64 ,
2821- disk -> device ,
2822- disk -> data_start + part -> start );
2934+ _refine_partition (target -> params , disk , part -> start , part -> size );
2935+
28232936 pos += part -> size ;
28242937 }
28252938
@@ -2878,9 +2991,7 @@ _dm_create_striped(const LDMVolumePrivate * const vol, GError ** const err)
28782991 goto out ;
28792992 }
28802993
2881- g_string_append_printf (target .params , " %s %" PRIu64 ,
2882- disk -> device ,
2883- disk -> data_start + part -> start );
2994+ _refine_partition (target .params , disk , part -> start , part -> size );
28842995 }
28852996
28862997 uint32_t cookie ;
0 commit comments