@@ -64,10 +64,11 @@ sanitize_label_string (WCHAR *s)
64
64
/* Linux does not skip leading spaces. */
65
65
return sanitize_string (s, L' \0 ' , L' ' , L' _' , [] (WCHAR c) -> bool
66
66
{
67
- /* Labels may contain characters not allowed in filenames.
68
- Linux replaces spaces with \x20 which is not an option here. */
69
- return !((0 <= c && c <= L' ' ) || c == L' :' || c == L' /' || c == L' \\ '
70
- || c == L' "' );
67
+ /* Labels may contain characters not allowed in filenames. Also
68
+ replace '#' to avoid that duplicate markers introduce new
69
+ duplicates. Linux replaces spaces with \x20 which is not an
70
+ option here. */
71
+ return !(c == L' /' || c == L' \\ ' || c == L' #' );
71
72
}
72
73
);
73
74
}
@@ -304,8 +305,7 @@ partition_to_label_or_uuid(bool uuid, const UNICODE_STRING *drive_uname,
304
305
const NTFS_VOLUME_DATA_BUFFER *nvdb =
305
306
reinterpret_cast <const NTFS_VOLUME_DATA_BUFFER *>(ioctl_buf);
306
307
if (uuid && DeviceIoControl (volhdl, FSCTL_GET_NTFS_VOLUME_DATA, nullptr , 0 ,
307
- ioctl_buf, NT_MAX_PATH, &bytes_read, nullptr )
308
- && nvdb->VolumeSerialNumber .QuadPart )
308
+ ioctl_buf, NT_MAX_PATH, &bytes_read, nullptr ))
309
309
{
310
310
/* Print without any separator as on Linux. */
311
311
__small_sprintf (name, " %016X" , nvdb->VolumeSerialNumber .QuadPart );
@@ -327,13 +327,9 @@ partition_to_label_or_uuid(bool uuid, const UNICODE_STRING *drive_uname,
327
327
FILE_FS_VOLUME_INFORMATION *ffvi =
328
328
reinterpret_cast <FILE_FS_VOLUME_INFORMATION *>(ioctl_buf);
329
329
if (uuid)
330
- {
331
- if (!ffvi->VolumeSerialNumber )
332
- return false ;
333
- /* Print with separator as on Linux. */
334
- __small_sprintf (name, " %04x-%04x" , ffvi->VolumeSerialNumber >> 16 ,
335
- ffvi->VolumeSerialNumber & 0xffff );
336
- }
330
+ /* Print with separator as on Linux. */
331
+ __small_sprintf (name, " %04x-%04x" , ffvi->VolumeSerialNumber >> 16 ,
332
+ ffvi->VolumeSerialNumber & 0xffff );
337
333
else
338
334
{
339
335
/* Label is not null terminated. */
@@ -361,6 +357,20 @@ by_id_compare_name (const void *a, const void *b)
361
357
return strcmp (ap->name , bp->name );
362
358
}
363
359
360
+ static int
361
+ by_id_compare_name_drive_part (const void *a, const void *b)
362
+ {
363
+ const by_id_entry *ap = reinterpret_cast <const by_id_entry *>(a);
364
+ const by_id_entry *bp = reinterpret_cast <const by_id_entry *>(b);
365
+ int cmp = strcmp (ap->name , bp->name );
366
+ if (cmp)
367
+ return cmp;
368
+ cmp = ap->drive - bp->drive ;
369
+ if (cmp)
370
+ return cmp;
371
+ return ap->part - bp->part ;
372
+ }
373
+
364
374
static by_id_entry *
365
375
by_id_realloc (by_id_entry *p, size_t n)
366
376
{
@@ -610,21 +620,23 @@ get_by_id_table (by_id_entry * &table, fhandler_dev_disk::dev_disk_location loc)
610
620
if (!table)
611
621
return (errno_set ? -1 : 0 );
612
622
613
- /* Sort by name and remove duplicates. */
614
- qsort (table, table_size, sizeof (*table), by_id_compare_name);
623
+ /* Sort by {name, drive, part} to ensure stable sort order. */
624
+ qsort (table, table_size, sizeof (*table), by_id_compare_name_drive_part);
625
+ /* Mark duplicate names. */
615
626
for (unsigned i = 0 ; i < table_size; i++)
616
627
{
617
628
unsigned j = i + 1 ;
618
629
while (j < table_size && !strcmp (table[i].name , table[j].name ))
619
630
j++;
620
631
if (j == i + 1 )
621
632
continue ;
622
- /* Duplicate(s) found, remove all entries with this name. */
623
- debug_printf (" removing duplicates %d-%d: '%s'" , i, j - 1 , table[i].name );
624
- if (j < table_size)
625
- memmove (table + i, table + j, (table_size - j) * sizeof (*table));
626
- table_size -= j - i;
627
- i--;
633
+ /* Duplicate(s) found, append "#N" to all entries. This never
634
+ introduces new duplicates because '#' never occurs in the
635
+ original names. */
636
+ debug_printf (" mark duplicates %u-%u of '%s'" , i, j - 1 , table[i].name );
637
+ size_t len = strlen (table[i].name );
638
+ for (unsigned k = i; k < j; k++)
639
+ __small_sprintf (table[k].name + len, " #%u" , k - i);
628
640
}
629
641
630
642
debug_printf (" table_size: %d" , table_size);
0 commit comments