diff options
Diffstat (limited to 'gl/mountlist.c')
| -rw-r--r-- | gl/mountlist.c | 629 |
1 files changed, 399 insertions, 230 deletions
diff --git a/gl/mountlist.c b/gl/mountlist.c index 06300d6b..66b3f3d5 100644 --- a/gl/mountlist.c +++ b/gl/mountlist.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* mountlist.c -- return a list of mounted file systems | 1 | /* mountlist.c -- return a list of mounted file systems |
| 2 | 2 | ||
| 3 | Copyright (C) 1991-1992, 1997-2024 Free Software Foundation, Inc. | 3 | Copyright (C) 1991-1992, 1997-2026 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | This program is free software: you can redistribute it and/or modify | 5 | This program is free software: you can redistribute it and/or modify |
| 6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
| @@ -19,20 +19,18 @@ | |||
| 19 | 19 | ||
| 20 | #include "mountlist.h" | 20 | #include "mountlist.h" |
| 21 | 21 | ||
| 22 | #include <errno.h> | ||
| 23 | #include <fcntl.h> | ||
| 22 | #include <limits.h> | 24 | #include <limits.h> |
| 23 | #include <stdio.h> | 25 | #include <stdio.h> |
| 24 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 25 | #include <string.h> | 27 | #include <string.h> |
| 26 | #include <stdint.h> | 28 | #include <stdint.h> |
| 29 | #include <unistd.h> | ||
| 27 | 30 | ||
| 31 | #include "c-ctype.h" | ||
| 28 | #include "xalloc.h" | 32 | #include "xalloc.h" |
| 29 | 33 | ||
| 30 | #include <errno.h> | ||
| 31 | |||
| 32 | #include <fcntl.h> | ||
| 33 | |||
| 34 | #include <unistd.h> | ||
| 35 | |||
| 36 | #if HAVE_SYS_PARAM_H | 34 | #if HAVE_SYS_PARAM_H |
| 37 | # include <sys/param.h> | 35 | # include <sys/param.h> |
| 38 | #endif | 36 | #endif |
| @@ -43,7 +41,7 @@ | |||
| 43 | # include <sys/sysmacros.h> | 41 | # include <sys/sysmacros.h> |
| 44 | #endif | 42 | #endif |
| 45 | 43 | ||
| 46 | #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */ | 44 | #if defined MOUNTED_GETFSSTAT /* (obsolete) Apple Darwin 1.3 */ |
| 47 | # if HAVE_SYS_UCRED_H | 45 | # if HAVE_SYS_UCRED_H |
| 48 | # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS, | 46 | # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS, |
| 49 | NGROUPS is used as an array dimension in ucred.h */ | 47 | NGROUPS is used as an array dimension in ucred.h */ |
| @@ -62,7 +60,7 @@ | |||
| 62 | # endif | 60 | # endif |
| 63 | #endif /* MOUNTED_GETFSSTAT */ | 61 | #endif /* MOUNTED_GETFSSTAT */ |
| 64 | 62 | ||
| 65 | #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android, | 63 | #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, Cygwin, Android, |
| 66 | also (obsolete) 4.3BSD, SunOS */ | 64 | also (obsolete) 4.3BSD, SunOS */ |
| 67 | # include <mntent.h> | 65 | # include <mntent.h> |
| 68 | # include <sys/types.h> | 66 | # include <sys/types.h> |
| @@ -132,6 +130,10 @@ | |||
| 132 | # endif | 130 | # endif |
| 133 | #endif | 131 | #endif |
| 134 | 132 | ||
| 133 | #if defined _WIN32 && !defined __CYGWIN__ | ||
| 134 | # include <windows.h> | ||
| 135 | #endif | ||
| 136 | |||
| 135 | #ifndef HAVE_HASMNTOPT | 137 | #ifndef HAVE_HASMNTOPT |
| 136 | # define hasmntopt(mnt, opt) ((char *) 0) | 138 | # define hasmntopt(mnt, opt) ((char *) 0) |
| 137 | #endif | 139 | #endif |
| @@ -169,23 +171,21 @@ | |||
| 169 | #endif | 171 | #endif |
| 170 | 172 | ||
| 171 | #define ME_DUMMY_0(Fs_name, Fs_type) \ | 173 | #define ME_DUMMY_0(Fs_name, Fs_type) \ |
| 172 | (strcmp (Fs_type, "autofs") == 0 \ | 174 | (streq (Fs_type, "autofs") \ |
| 173 | || strcmp (Fs_type, "proc") == 0 \ | 175 | || streq (Fs_type, "proc") \ |
| 174 | || strcmp (Fs_type, "subfs") == 0 \ | 176 | || streq (Fs_type, "subfs") \ |
| 175 | /* for Linux 2.6/3.x */ \ | 177 | /* for Linux 2.6/3.x */ \ |
| 176 | || strcmp (Fs_type, "debugfs") == 0 \ | 178 | || streq (Fs_type, "debugfs") \ |
| 177 | || strcmp (Fs_type, "devpts") == 0 \ | 179 | || streq (Fs_type, "devpts") \ |
| 178 | || strcmp (Fs_type, "fusectl") == 0 \ | 180 | || streq (Fs_type, "fusectl") \ |
| 179 | || strcmp (Fs_type, "fuse.portal") == 0 \ | 181 | || streq (Fs_type, "fuse.portal") \ |
| 180 | || strcmp (Fs_type, "mqueue") == 0 \ | 182 | || streq (Fs_type, "mqueue") \ |
| 181 | || strcmp (Fs_type, "rpc_pipefs") == 0 \ | 183 | || streq (Fs_type, "rpc_pipefs") \ |
| 182 | || strcmp (Fs_type, "sysfs") == 0 \ | 184 | || streq (Fs_type, "sysfs") \ |
| 183 | /* FreeBSD, Linux 2.4 */ \ | 185 | /* FreeBSD, Linux 2.4 */ \ |
| 184 | || strcmp (Fs_type, "devfs") == 0 \ | 186 | || streq (Fs_type, "devfs") \ |
| 185 | /* for NetBSD 3.0 */ \ | 187 | /* for NetBSD 3.0 */ \ |
| 186 | || strcmp (Fs_type, "kernfs") == 0 \ | 188 | || streq (Fs_type, "kernfs")) |
| 187 | /* for Irix 6.5 */ \ | ||
| 188 | || strcmp (Fs_type, "ignore") == 0) | ||
| 189 | 189 | ||
| 190 | /* Historically, we have marked as "dummy" any file system of type "none", | 190 | /* Historically, we have marked as "dummy" any file system of type "none", |
| 191 | but now that programs like du need to know about bind-mounted directories, | 191 | but now that programs like du need to know about bind-mounted directories, |
| @@ -194,10 +194,10 @@ | |||
| 194 | #ifdef MOUNTED_GETMNTENT1 | 194 | #ifdef MOUNTED_GETMNTENT1 |
| 195 | # define ME_DUMMY(Fs_name, Fs_type, Bind) \ | 195 | # define ME_DUMMY(Fs_name, Fs_type, Bind) \ |
| 196 | (ME_DUMMY_0 (Fs_name, Fs_type) \ | 196 | (ME_DUMMY_0 (Fs_name, Fs_type) \ |
| 197 | || (strcmp (Fs_type, "none") == 0 && !Bind)) | 197 | || (streq (Fs_type, "none") && !Bind)) |
| 198 | #else | 198 | #else |
| 199 | # define ME_DUMMY(Fs_name, Fs_type) \ | 199 | # define ME_DUMMY(Fs_name, Fs_type) \ |
| 200 | (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0) | 200 | (ME_DUMMY_0 (Fs_name, Fs_type) || streq (Fs_type, "none")) |
| 201 | #endif | 201 | #endif |
| 202 | 202 | ||
| 203 | #ifdef __CYGWIN__ | 203 | #ifdef __CYGWIN__ |
| @@ -238,19 +238,19 @@ me_remote (char const *fs_name, _GL_UNUSED char const *fs_type) | |||
| 238 | (strchr (Fs_name, ':') != NULL \ | 238 | (strchr (Fs_name, ':') != NULL \ |
| 239 | || ((Fs_name)[0] == '/' \ | 239 | || ((Fs_name)[0] == '/' \ |
| 240 | && (Fs_name)[1] == '/' \ | 240 | && (Fs_name)[1] == '/' \ |
| 241 | && (strcmp (Fs_type, "smbfs") == 0 \ | 241 | && (streq (Fs_type, "smbfs") \ |
| 242 | || strcmp (Fs_type, "smb3") == 0 \ | 242 | || streq (Fs_type, "smb3") \ |
| 243 | || strcmp (Fs_type, "cifs") == 0)) \ | 243 | || streq (Fs_type, "cifs"))) \ |
| 244 | || strcmp (Fs_type, "acfs") == 0 \ | 244 | || streq (Fs_type, "acfs") \ |
| 245 | || strcmp (Fs_type, "afs") == 0 \ | 245 | || streq (Fs_type, "afs") \ |
| 246 | || strcmp (Fs_type, "coda") == 0 \ | 246 | || streq (Fs_type, "coda") \ |
| 247 | || strcmp (Fs_type, "auristorfs") == 0 \ | 247 | || streq (Fs_type, "auristorfs") \ |
| 248 | || strcmp (Fs_type, "fhgfs") == 0 \ | 248 | || streq (Fs_type, "fhgfs") \ |
| 249 | || strcmp (Fs_type, "gpfs") == 0 \ | 249 | || streq (Fs_type, "gpfs") \ |
| 250 | || strcmp (Fs_type, "ibrix") == 0 \ | 250 | || streq (Fs_type, "ibrix") \ |
| 251 | || strcmp (Fs_type, "ocfs2") == 0 \ | 251 | || streq (Fs_type, "ocfs2") \ |
| 252 | || strcmp (Fs_type, "vxfs") == 0 \ | 252 | || streq (Fs_type, "vxfs") \ |
| 253 | || strcmp ("-hosts", Fs_name) == 0) | 253 | || streq ("-hosts", Fs_name)) |
| 254 | #endif | 254 | #endif |
| 255 | 255 | ||
| 256 | #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */ | 256 | #if MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */ |
| @@ -367,9 +367,7 @@ fsp_to_string (const struct statfs *fsp) | |||
| 367 | static char * | 367 | static char * |
| 368 | fstype_to_string (int t) | 368 | fstype_to_string (int t) |
| 369 | { | 369 | { |
| 370 | struct vfs_ent *e; | 370 | struct vfs_ent *e = getvfsbytype (t); |
| 371 | |||
| 372 | e = getvfsbytype (t); | ||
| 373 | if (!e || !e->vfsent_name) | 371 | if (!e || !e->vfsent_name) |
| 374 | return "none"; | 372 | return "none"; |
| 375 | else | 373 | else |
| @@ -396,15 +394,17 @@ dev_from_mount_options (char const *mount_options) | |||
| 396 | if (devopt) | 394 | if (devopt) |
| 397 | { | 395 | { |
| 398 | char const *optval = devopt + sizeof dev_pattern - 1; | 396 | char const *optval = devopt + sizeof dev_pattern - 1; |
| 399 | char *optvalend; | 397 | if (c_isxdigit (*optval)) |
| 400 | unsigned long int dev; | 398 | { |
| 401 | errno = 0; | 399 | errno = 0; |
| 402 | dev = strtoul (optval, &optvalend, 16); | 400 | char *optvalend; |
| 403 | if (optval != optvalend | 401 | unsigned long int dev = strtoul (optval, &optvalend, 16); |
| 404 | && (*optvalend == '\0' || *optvalend == ',') | 402 | if (optval != optvalend |
| 405 | && ! (dev == ULONG_MAX && errno == ERANGE) | 403 | && (*optvalend == '\0' || *optvalend == ',') |
| 406 | && dev == (dev_t) dev) | 404 | && ! (dev == ULONG_MAX && errno == ERANGE) |
| 407 | return dev; | 405 | && dev == (dev_t) dev) |
| 406 | return dev; | ||
| 407 | } | ||
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | # endif | 410 | # endif |
| @@ -422,9 +422,9 @@ dev_from_mount_options (char const *mount_options) | |||
| 422 | static void | 422 | static void |
| 423 | unescape_tab (char *str) | 423 | unescape_tab (char *str) |
| 424 | { | 424 | { |
| 425 | size_t i, j = 0; | 425 | size_t j = 0; |
| 426 | size_t len = strlen (str) + 1; | 426 | size_t len = strlen (str) + 1; |
| 427 | for (i = 0; i < len; i++) | 427 | for (size_t i = 0; i < len; i++) |
| 428 | { | 428 | { |
| 429 | if (str[i] == '\\' && (i + 4 < len) | 429 | if (str[i] == '\\' && (i + 4 < len) |
| 430 | && str[i + 1] >= '0' && str[i + 1] <= '3' | 430 | && str[i + 1] >= '0' && str[i + 1] <= '3' |
| @@ -452,12 +452,8 @@ terminate_at_blank (char *str) | |||
| 452 | *s = '\0'; | 452 | *s = '\0'; |
| 453 | return s; | 453 | return s; |
| 454 | } | 454 | } |
| 455 | #endif | ||
| 456 | 455 | ||
| 457 | /* Return a list of the currently mounted file systems, or NULL on error. | 456 | #endif |
| 458 | Add each entry to the tail of the list so that they stay in order. | ||
| 459 | If NEED_FS_TYPE is true, ensure that the file system type fields in | ||
| 460 | the returned list are valid. Otherwise, they might not be. */ | ||
| 461 | 457 | ||
| 462 | struct mount_entry * | 458 | struct mount_entry * |
| 463 | read_file_system_list (bool need_fs_type) | 459 | read_file_system_list (bool need_fs_type) |
| @@ -467,18 +463,16 @@ read_file_system_list (bool need_fs_type) | |||
| 467 | struct mount_entry **mtail = &mount_list; | 463 | struct mount_entry **mtail = &mount_list; |
| 468 | (void) need_fs_type; | 464 | (void) need_fs_type; |
| 469 | 465 | ||
| 470 | #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, IRIX, Cygwin, Android, | 466 | #ifdef MOUNTED_GETMNTENT1 /* glibc, HP-UX, Cygwin, Android, |
| 471 | also (obsolete) 4.3BSD, SunOS */ | 467 | also (obsolete) 4.3BSD, SunOS */ |
| 472 | { | 468 | { |
| 473 | FILE *fp; | ||
| 474 | |||
| 475 | # if defined __linux__ || defined __ANDROID__ | 469 | # if defined __linux__ || defined __ANDROID__ |
| 476 | /* Try parsing mountinfo first, as that make device IDs available. | 470 | /* Try parsing mountinfo first, as that make device IDs available. |
| 477 | Note we could use libmount routines to simplify this parsing a little | 471 | Note we could use libmount routines to simplify this parsing a little |
| 478 | (and that code is in previous versions of this function), however | 472 | (and that code is in previous versions of this function), however |
| 479 | libmount depends on libselinux which pulls in many dependencies. */ | 473 | libmount depends on libselinux which pulls in many dependencies. */ |
| 480 | char const *mountinfo = "/proc/self/mountinfo"; | 474 | char const *mountinfo = "/proc/self/mountinfo"; |
| 481 | fp = fopen (mountinfo, "re"); | 475 | FILE *fp = fopen (mountinfo, "re"); |
| 482 | if (fp != NULL) | 476 | if (fp != NULL) |
| 483 | { | 477 | { |
| 484 | char *line = NULL; | 478 | char *line = NULL; |
| @@ -496,61 +490,61 @@ read_file_system_list (bool need_fs_type) | |||
| 496 | &devmaj, &devmin, | 490 | &devmaj, &devmin, |
| 497 | &mntroot_s); | 491 | &mntroot_s); |
| 498 | 492 | ||
| 499 | if (rc != 2 && rc != 3) /* 3 if %n included in count. */ | 493 | if (rc == 2 || rc == 3) /* 3 if %n included in count. */ |
| 500 | continue; | 494 | { |
| 501 | 495 | /* find end of MNTROOT. */ | |
| 502 | /* find end of MNTROOT. */ | 496 | char *mntroot = line + mntroot_s; |
| 503 | char *mntroot = line + mntroot_s; | 497 | char *blank = terminate_at_blank (mntroot); |
| 504 | char *blank = terminate_at_blank (mntroot); | 498 | if (blank) |
| 505 | if (! blank) | 499 | { |
| 506 | continue; | 500 | /* find end of TARGET. */ |
| 507 | 501 | char *target = blank + 1; | |
| 508 | /* find end of TARGET. */ | 502 | blank = terminate_at_blank (target); |
| 509 | char *target = blank + 1; | 503 | if (blank) |
| 510 | blank = terminate_at_blank (target); | 504 | { |
| 511 | if (! blank) | 505 | /* skip optional fields, terminated by " - " */ |
| 512 | continue; | 506 | char *dash = strstr (blank + 1, " - "); |
| 513 | 507 | if (dash) | |
| 514 | /* skip optional fields, terminated by " - " */ | 508 | { |
| 515 | char *dash = strstr (blank + 1, " - "); | 509 | /* advance past the " - " separator. */ |
| 516 | if (! dash) | 510 | char *fstype = dash + 3; |
| 517 | continue; | 511 | blank = terminate_at_blank (fstype); |
| 518 | 512 | if (blank) | |
| 519 | /* advance past the " - " separator. */ | 513 | { |
| 520 | char *fstype = dash + 3; | 514 | /* find end of SOURCE. */ |
| 521 | blank = terminate_at_blank (fstype); | 515 | char *source = blank + 1; |
| 522 | if (! blank) | 516 | if (terminate_at_blank (source)) |
| 523 | continue; | 517 | { |
| 524 | 518 | /* manipulate the sub-strings in place. */ | |
| 525 | /* find end of SOURCE. */ | 519 | unescape_tab (source); |
| 526 | char *source = blank + 1; | 520 | unescape_tab (target); |
| 527 | if (! terminate_at_blank (source)) | 521 | unescape_tab (mntroot); |
| 528 | continue; | 522 | unescape_tab (fstype); |
| 529 | 523 | ||
| 530 | /* manipulate the sub-strings in place. */ | 524 | me = xmalloc (sizeof *me); |
| 531 | unescape_tab (source); | 525 | |
| 532 | unescape_tab (target); | 526 | me->me_devname = xstrdup (source); |
| 533 | unescape_tab (mntroot); | 527 | me->me_mountdir = xstrdup (target); |
| 534 | unescape_tab (fstype); | 528 | me->me_mntroot = xstrdup (mntroot); |
| 535 | 529 | me->me_type = xstrdup (fstype); | |
| 536 | me = xmalloc (sizeof *me); | 530 | me->me_type_malloced = 1; |
| 537 | 531 | me->me_dev = makedev (devmaj, devmin); | |
| 538 | me->me_devname = xstrdup (source); | 532 | /* we pass "false" for the "Bind" option as that's only |
| 539 | me->me_mountdir = xstrdup (target); | 533 | significant when the Fs_type is "none" which will not be |
| 540 | me->me_mntroot = xstrdup (mntroot); | 534 | the case when parsing "/proc/self/mountinfo", and only |
| 541 | me->me_type = xstrdup (fstype); | 535 | applies for static /etc/mtab files. */ |
| 542 | me->me_type_malloced = 1; | 536 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false); |
| 543 | me->me_dev = makedev (devmaj, devmin); | 537 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); |
| 544 | /* we pass "false" for the "Bind" option as that's only | 538 | |
| 545 | significant when the Fs_type is "none" which will not be | 539 | /* Add to the linked list. */ |
| 546 | the case when parsing "/proc/self/mountinfo", and only | 540 | *mtail = me; |
| 547 | applies for static /etc/mtab files. */ | 541 | mtail = &me->me_next; |
| 548 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type, false); | 542 | } |
| 549 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | 543 | } |
| 550 | 544 | } | |
| 551 | /* Add to the linked list. */ | 545 | } |
| 552 | *mtail = me; | 546 | } |
| 553 | mtail = &me->me_next; | 547 | } |
| 554 | } | 548 | } |
| 555 | 549 | ||
| 556 | free (line); | 550 | free (line); |
| @@ -567,16 +561,16 @@ read_file_system_list (bool need_fs_type) | |||
| 567 | goto free_then_fail; | 561 | goto free_then_fail; |
| 568 | } | 562 | } |
| 569 | else /* fallback to /proc/self/mounts (/etc/mtab). */ | 563 | else /* fallback to /proc/self/mounts (/etc/mtab). */ |
| 570 | # endif /* __linux __ || __ANDROID__ */ | 564 | # endif /* __linux__ || __ANDROID__ */ |
| 571 | { | 565 | { |
| 572 | struct mntent *mnt; | ||
| 573 | char const *table = MOUNTED; | 566 | char const *table = MOUNTED; |
| 574 | 567 | ||
| 575 | fp = setmntent (table, "r"); | 568 | FILE *mfp = setmntent (table, "r"); |
| 576 | if (fp == NULL) | 569 | if (mfp == NULL) |
| 577 | return NULL; | 570 | return NULL; |
| 578 | 571 | ||
| 579 | while ((mnt = getmntent (fp))) | 572 | struct mntent *mnt; |
| 573 | while ((mnt = getmntent (mfp))) | ||
| 580 | { | 574 | { |
| 581 | bool bind = hasmntopt (mnt, "bind"); | 575 | bool bind = hasmntopt (mnt, "bind"); |
| 582 | 576 | ||
| @@ -595,7 +589,7 @@ read_file_system_list (bool need_fs_type) | |||
| 595 | mtail = &me->me_next; | 589 | mtail = &me->me_next; |
| 596 | } | 590 | } |
| 597 | 591 | ||
| 598 | if (endmntent (fp) == 0) | 592 | if (endmntent (mfp) == 0) |
| 599 | goto free_then_fail; | 593 | goto free_then_fail; |
| 600 | } | 594 | } |
| 601 | } | 595 | } |
| @@ -604,9 +598,7 @@ read_file_system_list (bool need_fs_type) | |||
| 604 | #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */ | 598 | #ifdef MOUNTED_GETMNTINFO /* Mac OS X, FreeBSD, OpenBSD, also (obsolete) 4.4BSD */ |
| 605 | { | 599 | { |
| 606 | struct statfs *fsp; | 600 | struct statfs *fsp; |
| 607 | int entries; | 601 | int entries = getmntinfo (&fsp, MNT_NOWAIT); |
| 608 | |||
| 609 | entries = getmntinfo (&fsp, MNT_NOWAIT); | ||
| 610 | if (entries < 0) | 602 | if (entries < 0) |
| 611 | return NULL; | 603 | return NULL; |
| 612 | for (; entries-- > 0; fsp++) | 604 | for (; entries-- > 0; fsp++) |
| @@ -633,9 +625,7 @@ read_file_system_list (bool need_fs_type) | |||
| 633 | #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */ | 625 | #ifdef MOUNTED_GETMNTINFO2 /* NetBSD, Minix */ |
| 634 | { | 626 | { |
| 635 | struct statvfs *fsp; | 627 | struct statvfs *fsp; |
| 636 | int entries; | 628 | int entries = getmntinfo (&fsp, MNT_NOWAIT); |
| 637 | |||
| 638 | entries = getmntinfo (&fsp, MNT_NOWAIT); | ||
| 639 | if (entries < 0) | 629 | if (entries < 0) |
| 640 | return NULL; | 630 | return NULL; |
| 641 | for (; entries-- > 0; fsp++) | 631 | for (; entries-- > 0; fsp++) |
| @@ -669,7 +659,6 @@ read_file_system_list (bool need_fs_type) | |||
| 669 | We therefore get the list of subdirectories of /, and the list | 659 | We therefore get the list of subdirectories of /, and the list |
| 670 | of all file systems, and match the two lists. */ | 660 | of all file systems, and match the two lists. */ |
| 671 | 661 | ||
| 672 | DIR *dirp; | ||
| 673 | struct rootdir_entry | 662 | struct rootdir_entry |
| 674 | { | 663 | { |
| 675 | char *name; | 664 | char *name; |
| @@ -677,16 +666,11 @@ read_file_system_list (bool need_fs_type) | |||
| 677 | ino_t ino; | 666 | ino_t ino; |
| 678 | struct rootdir_entry *next; | 667 | struct rootdir_entry *next; |
| 679 | }; | 668 | }; |
| 680 | struct rootdir_entry *rootdir_list; | ||
| 681 | struct rootdir_entry **rootdir_tail; | ||
| 682 | int32 pos; | ||
| 683 | dev_t dev; | ||
| 684 | fs_info fi; | ||
| 685 | 669 | ||
| 686 | /* All volumes are mounted in the rootfs, directly under /. */ | 670 | /* All volumes are mounted in the rootfs, directly under /. */ |
| 687 | rootdir_list = NULL; | 671 | struct rootdir_entry *rootdir_list = NULL; |
| 688 | rootdir_tail = &rootdir_list; | 672 | struct rootdir_entry **rootdir_tail = &rootdir_list; |
| 689 | dirp = opendir ("/"); | 673 | DIR *dirp = opendir ("/"); |
| 690 | if (dirp) | 674 | if (dirp) |
| 691 | { | 675 | { |
| 692 | struct dirent *d; | 676 | struct dirent *d; |
| @@ -696,61 +680,64 @@ read_file_system_list (bool need_fs_type) | |||
| 696 | char *name; | 680 | char *name; |
| 697 | struct stat statbuf; | 681 | struct stat statbuf; |
| 698 | 682 | ||
| 699 | if (strcmp (d->d_name, "..") == 0) | 683 | if (! streq (d->d_name, "..")) |
| 700 | continue; | ||
| 701 | |||
| 702 | if (strcmp (d->d_name, ".") == 0) | ||
| 703 | name = xstrdup ("/"); | ||
| 704 | else | ||
| 705 | { | ||
| 706 | name = xmalloc (1 + strlen (d->d_name) + 1); | ||
| 707 | name[0] = '/'; | ||
| 708 | strcpy (name + 1, d->d_name); | ||
| 709 | } | ||
| 710 | |||
| 711 | if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) | ||
| 712 | { | 684 | { |
| 713 | struct rootdir_entry *re = xmalloc (sizeof *re); | 685 | if (streq (d->d_name, ".")) |
| 714 | re->name = name; | 686 | name = xstrdup ("/"); |
| 715 | re->dev = statbuf.st_dev; | 687 | else |
| 716 | re->ino = statbuf.st_ino; | 688 | { |
| 717 | 689 | name = xmalloc (1 + strlen (d->d_name) + 1); | |
| 718 | /* Add to the linked list. */ | 690 | name[0] = '/'; |
| 719 | *rootdir_tail = re; | 691 | strcpy (name + 1, d->d_name); |
| 720 | rootdir_tail = &re->next; | 692 | } |
| 693 | |||
| 694 | if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) | ||
| 695 | { | ||
| 696 | struct rootdir_entry *re = xmalloc (sizeof *re); | ||
| 697 | re->name = name; | ||
| 698 | re->dev = statbuf.st_dev; | ||
| 699 | re->ino = statbuf.st_ino; | ||
| 700 | |||
| 701 | /* Add to the linked list. */ | ||
| 702 | *rootdir_tail = re; | ||
| 703 | rootdir_tail = &re->next; | ||
| 704 | } | ||
| 705 | else | ||
| 706 | free (name); | ||
| 721 | } | 707 | } |
| 722 | else | ||
| 723 | free (name); | ||
| 724 | } | 708 | } |
| 725 | closedir (dirp); | 709 | closedir (dirp); |
| 726 | } | 710 | } |
| 727 | *rootdir_tail = NULL; | 711 | *rootdir_tail = NULL; |
| 728 | 712 | ||
| 729 | for (pos = 0; (dev = next_dev (&pos)) >= 0; ) | 713 | dev_t dev; |
| 730 | if (fs_stat_dev (dev, &fi) >= 0) | 714 | for (int32 pos = 0; (dev = next_dev (&pos)) >= 0; ) |
| 731 | { | 715 | { |
| 732 | /* Note: fi.dev == dev. */ | 716 | fs_info fi; |
| 733 | struct rootdir_entry *re; | 717 | if (fs_stat_dev (dev, &fi) >= 0) |
| 734 | 718 | { | |
| 735 | for (re = rootdir_list; re; re = re->next) | 719 | /* Note: fi.dev == dev. */ |
| 736 | if (re->dev == fi.dev && re->ino == fi.root) | 720 | struct rootdir_entry *re; |
| 737 | break; | 721 | for (re = rootdir_list; re; re = re->next) |
| 738 | 722 | if (re->dev == fi.dev && re->ino == fi.root) | |
| 739 | me = xmalloc (sizeof *me); | 723 | break; |
| 740 | me->me_devname = xstrdup (fi.device_name[0] != '\0' | 724 | |
| 741 | ? fi.device_name : fi.fsh_name); | 725 | me = xmalloc (sizeof *me); |
| 742 | me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name); | 726 | me->me_devname = xstrdup (fi.device_name[0] != '\0' |
| 743 | me->me_mntroot = NULL; | 727 | ? fi.device_name : fi.fsh_name); |
| 744 | me->me_type = xstrdup (fi.fsh_name); | 728 | me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name); |
| 745 | me->me_type_malloced = 1; | 729 | me->me_mntroot = NULL; |
| 746 | me->me_dev = fi.dev; | 730 | me->me_type = xstrdup (fi.fsh_name); |
| 747 | me->me_dummy = 0; | 731 | me->me_type_malloced = 1; |
| 748 | me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; | 732 | me->me_dev = fi.dev; |
| 749 | 733 | me->me_dummy = 0; | |
| 750 | /* Add to the linked list. */ | 734 | me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; |
| 751 | *mtail = me; | 735 | |
| 752 | mtail = &me->me_next; | 736 | /* Add to the linked list. */ |
| 753 | } | 737 | *mtail = me; |
| 738 | mtail = &me->me_next; | ||
| 739 | } | ||
| 740 | } | ||
| 754 | *mtail = NULL; | 741 | *mtail = NULL; |
| 755 | 742 | ||
| 756 | while (rootdir_list != NULL) | 743 | while (rootdir_list != NULL) |
| @@ -763,19 +750,17 @@ read_file_system_list (bool need_fs_type) | |||
| 763 | } | 750 | } |
| 764 | #endif /* MOUNTED_FS_STAT_DEV */ | 751 | #endif /* MOUNTED_FS_STAT_DEV */ |
| 765 | 752 | ||
| 766 | #if defined MOUNTED_GETFSSTAT /* OSF/1, also (obsolete) Apple Darwin 1.3 */ | 753 | #if defined MOUNTED_GETFSSTAT /* (obsolete) Apple Darwin 1.3 */ |
| 767 | { | 754 | { |
| 768 | int numsys, counter; | ||
| 769 | size_t bufsize; | ||
| 770 | struct statfs *stats; | ||
| 771 | 755 | ||
| 772 | numsys = getfsstat (NULL, 0L, MNT_NOWAIT); | 756 | int numsys = getfsstat (NULL, 0L, MNT_NOWAIT); |
| 773 | if (numsys < 0) | 757 | if (numsys < 0) |
| 774 | return NULL; | 758 | return NULL; |
| 759 | |||
| 760 | struct statfs *stats; | ||
| 775 | if (SIZE_MAX / sizeof *stats <= numsys) | 761 | if (SIZE_MAX / sizeof *stats <= numsys) |
| 776 | xalloc_die (); | 762 | xalloc_die (); |
| 777 | 763 | size_t bufsize = (1 + numsys) * sizeof *stats; | |
| 778 | bufsize = (1 + numsys) * sizeof *stats; | ||
| 779 | stats = xmalloc (bufsize); | 764 | stats = xmalloc (bufsize); |
| 780 | numsys = getfsstat (stats, bufsize, MNT_NOWAIT); | 765 | numsys = getfsstat (stats, bufsize, MNT_NOWAIT); |
| 781 | 766 | ||
| @@ -785,7 +770,7 @@ read_file_system_list (bool need_fs_type) | |||
| 785 | return NULL; | 770 | return NULL; |
| 786 | } | 771 | } |
| 787 | 772 | ||
| 788 | for (counter = 0; counter < numsys; counter++) | 773 | for (int counter = 0; counter < numsys; counter++) |
| 789 | { | 774 | { |
| 790 | me = xmalloc (sizeof *me); | 775 | me = xmalloc (sizeof *me); |
| 791 | me->me_devname = xstrdup (stats[counter].f_mntfromname); | 776 | me->me_devname = xstrdup (stats[counter].f_mntfromname); |
| @@ -808,14 +793,13 @@ read_file_system_list (bool need_fs_type) | |||
| 808 | 793 | ||
| 809 | #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */ | 794 | #if defined MOUNTED_FREAD_FSTYP /* (obsolete) SVR3 */ |
| 810 | { | 795 | { |
| 811 | struct mnttab mnt; | ||
| 812 | char *table = "/etc/mnttab"; | 796 | char *table = "/etc/mnttab"; |
| 813 | FILE *fp; | ||
| 814 | 797 | ||
| 815 | fp = fopen (table, "re"); | 798 | FILE *fp = fopen (table, "re"); |
| 816 | if (fp == NULL) | 799 | if (fp == NULL) |
| 817 | return NULL; | 800 | return NULL; |
| 818 | 801 | ||
| 802 | struct mnttab mnt; | ||
| 819 | while (fread (&mnt, sizeof mnt, 1, fp) > 0) | 803 | while (fread (&mnt, sizeof mnt, 1, fp) > 0) |
| 820 | { | 804 | { |
| 821 | me = xmalloc (sizeof *me); | 805 | me = xmalloc (sizeof *me); |
| @@ -861,20 +845,19 @@ read_file_system_list (bool need_fs_type) | |||
| 861 | 845 | ||
| 862 | #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */ | 846 | #ifdef MOUNTED_GETEXTMNTENT /* Solaris >= 8 */ |
| 863 | { | 847 | { |
| 864 | struct extmnttab mnt; | ||
| 865 | const char *table = MNTTAB; | 848 | const char *table = MNTTAB; |
| 866 | FILE *fp; | ||
| 867 | int ret; | ||
| 868 | 849 | ||
| 869 | /* No locking is needed, because the contents of /etc/mnttab is generated | 850 | /* No locking is needed, because the contents of /etc/mnttab is generated |
| 870 | by the kernel. */ | 851 | by the kernel. */ |
| 871 | 852 | ||
| 872 | errno = 0; | 853 | errno = 0; |
| 873 | fp = fopen (table, "re"); | 854 | FILE *fp = fopen (table, "re"); |
| 855 | int ret; | ||
| 874 | if (fp == NULL) | 856 | if (fp == NULL) |
| 875 | ret = errno; | 857 | ret = errno; |
| 876 | else | 858 | else |
| 877 | { | 859 | { |
| 860 | struct extmnttab mnt; | ||
| 878 | while ((ret = getextmntent (fp, &mnt, 1)) == 0) | 861 | while ((ret = getextmntent (fp, &mnt, 1)) == 0) |
| 879 | { | 862 | { |
| 880 | me = xmalloc (sizeof *me); | 863 | me = xmalloc (sizeof *me); |
| @@ -883,7 +866,9 @@ read_file_system_list (bool need_fs_type) | |||
| 883 | me->me_mntroot = NULL; | 866 | me->me_mntroot = NULL; |
| 884 | me->me_type = xstrdup (mnt.mnt_fstype); | 867 | me->me_type = xstrdup (mnt.mnt_fstype); |
| 885 | me->me_type_malloced = 1; | 868 | me->me_type_malloced = 1; |
| 886 | me->me_dummy = MNT_IGNORE (&mnt) != 0; | 869 | /* The cast from 'struct extmnttab *' to 'struct mnttab *' is OK |
| 870 | because 'struct extmnttab' extends 'struct mnttab'. */ | ||
| 871 | me->me_dummy = MNT_IGNORE ((struct mnttab *) &mnt) != 0; | ||
| 887 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | 872 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); |
| 888 | me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor); | 873 | me->me_dev = makedev (mnt.mnt_major, mnt.mnt_minor); |
| 889 | 874 | ||
| @@ -906,10 +891,7 @@ read_file_system_list (bool need_fs_type) | |||
| 906 | 891 | ||
| 907 | #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */ | 892 | #ifdef MOUNTED_GETMNTENT2 /* Solaris < 8, also (obsolete) SVR4 */ |
| 908 | { | 893 | { |
| 909 | struct mnttab mnt; | ||
| 910 | const char *table = MNTTAB; | 894 | const char *table = MNTTAB; |
| 911 | FILE *fp; | ||
| 912 | int ret; | ||
| 913 | int lockfd = -1; | 895 | int lockfd = -1; |
| 914 | 896 | ||
| 915 | # if defined F_RDLCK && defined F_SETLKW | 897 | # if defined F_RDLCK && defined F_SETLKW |
| @@ -942,11 +924,13 @@ read_file_system_list (bool need_fs_type) | |||
| 942 | # endif | 924 | # endif |
| 943 | 925 | ||
| 944 | errno = 0; | 926 | errno = 0; |
| 945 | fp = fopen (table, "re"); | 927 | FILE *fp = fopen (table, "re"); |
| 928 | int ret; | ||
| 946 | if (fp == NULL) | 929 | if (fp == NULL) |
| 947 | ret = errno; | 930 | ret = errno; |
| 948 | else | 931 | else |
| 949 | { | 932 | { |
| 933 | struct mnttab mnt; | ||
| 950 | while ((ret = getmntent (fp, &mnt)) == 0) | 934 | while ((ret = getmntent (fp, &mnt)) == 0) |
| 951 | { | 935 | { |
| 952 | me = xmalloc (sizeof *me); | 936 | me = xmalloc (sizeof *me); |
| @@ -981,34 +965,24 @@ read_file_system_list (bool need_fs_type) | |||
| 981 | 965 | ||
| 982 | #ifdef MOUNTED_VMOUNT /* AIX */ | 966 | #ifdef MOUNTED_VMOUNT /* AIX */ |
| 983 | { | 967 | { |
| 984 | int bufsize; | ||
| 985 | void *entries; | ||
| 986 | char *thisent; | ||
| 987 | struct vmount *vmp; | ||
| 988 | int n_entries; | ||
| 989 | int i; | ||
| 990 | |||
| 991 | /* Ask how many bytes to allocate for the mounted file system info. */ | 968 | /* Ask how many bytes to allocate for the mounted file system info. */ |
| 992 | entries = &bufsize; | 969 | int bufsize; |
| 993 | if (mntctl (MCTL_QUERY, sizeof bufsize, entries) != 0) | 970 | if (mntctl (MCTL_QUERY, sizeof bufsize, &bufsize) != 0) |
| 994 | return NULL; | 971 | return NULL; |
| 995 | entries = xmalloc (bufsize); | 972 | void *entries = xmalloc (bufsize); |
| 996 | 973 | ||
| 997 | /* Get the list of mounted file systems. */ | 974 | /* Get the list of mounted file systems. */ |
| 998 | n_entries = mntctl (MCTL_QUERY, bufsize, entries); | 975 | int n_entries = mntctl (MCTL_QUERY, bufsize, entries); |
| 999 | if (n_entries < 0) | 976 | if (n_entries < 0) |
| 1000 | { | 977 | { |
| 1001 | free (entries); | 978 | free (entries); |
| 1002 | return NULL; | 979 | return NULL; |
| 1003 | } | 980 | } |
| 1004 | 981 | ||
| 1005 | for (i = 0, thisent = entries; | 982 | char *thisent = entries; |
| 1006 | i < n_entries; | 983 | for (int i = 0; i < n_entries; i++) |
| 1007 | i++, thisent += vmp->vmt_length) | ||
| 1008 | { | 984 | { |
| 1009 | char *options, *ignore; | 985 | struct vmount *vmp = (struct vmount *) thisent; |
| 1010 | |||
| 1011 | vmp = (struct vmount *) thisent; | ||
| 1012 | me = xmalloc (sizeof *me); | 986 | me = xmalloc (sizeof *me); |
| 1013 | if (vmp->vmt_flags & MNT_REMOTE) | 987 | if (vmp->vmt_flags & MNT_REMOTE) |
| 1014 | { | 988 | { |
| @@ -1033,8 +1007,8 @@ read_file_system_list (bool need_fs_type) | |||
| 1033 | me->me_mntroot = NULL; | 1007 | me->me_mntroot = NULL; |
| 1034 | me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); | 1008 | me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); |
| 1035 | me->me_type_malloced = 1; | 1009 | me->me_type_malloced = 1; |
| 1036 | options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; | 1010 | char *options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; |
| 1037 | ignore = strstr (options, "ignore"); | 1011 | char *ignore = strstr (options, "ignore"); |
| 1038 | me->me_dummy = (ignore | 1012 | me->me_dummy = (ignore |
| 1039 | && (ignore == options || ignore[-1] == ',') | 1013 | && (ignore == options || ignore[-1] == ',') |
| 1040 | && (ignore[sizeof "ignore" - 1] == ',' | 1014 | && (ignore[sizeof "ignore" - 1] == ',' |
| @@ -1044,6 +1018,8 @@ read_file_system_list (bool need_fs_type) | |||
| 1044 | /* Add to the linked list. */ | 1018 | /* Add to the linked list. */ |
| 1045 | *mtail = me; | 1019 | *mtail = me; |
| 1046 | mtail = &me->me_next; | 1020 | mtail = &me->me_next; |
| 1021 | |||
| 1022 | thisent += vmp->vmt_length; | ||
| 1047 | } | 1023 | } |
| 1048 | free (entries); | 1024 | free (entries); |
| 1049 | } | 1025 | } |
| @@ -1052,25 +1028,23 @@ read_file_system_list (bool need_fs_type) | |||
| 1052 | #ifdef MOUNTED_INTERIX_STATVFS /* Interix */ | 1028 | #ifdef MOUNTED_INTERIX_STATVFS /* Interix */ |
| 1053 | { | 1029 | { |
| 1054 | DIR *dirp = opendir ("/dev/fs"); | 1030 | DIR *dirp = opendir ("/dev/fs"); |
| 1055 | char node[9 + NAME_MAX]; | ||
| 1056 | |||
| 1057 | if (!dirp) | 1031 | if (!dirp) |
| 1058 | goto free_then_fail; | 1032 | goto free_then_fail; |
| 1059 | 1033 | ||
| 1060 | while (1) | 1034 | while (1) |
| 1061 | { | 1035 | { |
| 1062 | struct statvfs dev; | ||
| 1063 | struct dirent entry; | ||
| 1064 | struct dirent *result; | ||
| 1065 | |||
| 1066 | /* FIXME: readdir_r is planned to be withdrawn from POSIX and | 1036 | /* FIXME: readdir_r is planned to be withdrawn from POSIX and |
| 1067 | marked obsolescent in glibc. Use readdir instead. */ | 1037 | marked obsolescent in glibc. Use readdir instead. */ |
| 1038 | struct dirent entry; | ||
| 1039 | struct dirent *result; | ||
| 1068 | if (readdir_r (dirp, &entry, &result) || result == NULL) | 1040 | if (readdir_r (dirp, &entry, &result) || result == NULL) |
| 1069 | break; | 1041 | break; |
| 1070 | 1042 | ||
| 1043 | char node[9 + NAME_MAX]; | ||
| 1071 | strcpy (node, "/dev/fs/"); | 1044 | strcpy (node, "/dev/fs/"); |
| 1072 | strcat (node, entry.d_name); | 1045 | strcat (node, entry.d_name); |
| 1073 | 1046 | ||
| 1047 | struct statvfs dev; | ||
| 1074 | if (statvfs (node, &dev) == 0) | 1048 | if (statvfs (node, &dev) == 0) |
| 1075 | { | 1049 | { |
| 1076 | me = xmalloc (sizeof *me); | 1050 | me = xmalloc (sizeof *me); |
| @@ -1092,6 +1066,201 @@ read_file_system_list (bool need_fs_type) | |||
| 1092 | } | 1066 | } |
| 1093 | #endif /* MOUNTED_INTERIX_STATVFS */ | 1067 | #endif /* MOUNTED_INTERIX_STATVFS */ |
| 1094 | 1068 | ||
| 1069 | #if defined _WIN32 && !defined __CYGWIN__ /* native Windows */ | ||
| 1070 | /* Don't assume that UNICODE is not defined. */ | ||
| 1071 | # undef GetDriveType | ||
| 1072 | # define GetDriveType GetDriveTypeA | ||
| 1073 | # undef GetVolumeInformation | ||
| 1074 | # define GetVolumeInformation GetVolumeInformationA | ||
| 1075 | { | ||
| 1076 | /* Windows has drive prefixes which are similar to mount points. | ||
| 1077 | GetLogicalDrives returns a bitmask where the i-th bit is set | ||
| 1078 | if ASCII 'A' + i is an available drive. See: | ||
| 1079 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives>. */ | ||
| 1080 | DWORD value = GetLogicalDrives (); | ||
| 1081 | |||
| 1082 | for (unsigned int i = 0; i < 26; ++i) | ||
| 1083 | { | ||
| 1084 | if (value & (1U << i)) | ||
| 1085 | { | ||
| 1086 | char mountdir[4]; | ||
| 1087 | mountdir[0] = 'A' + i; | ||
| 1088 | mountdir[1] = ':'; | ||
| 1089 | mountdir[2] = '\\'; | ||
| 1090 | mountdir[3] = '\0'; | ||
| 1091 | |||
| 1092 | char fs_name[MAX_PATH + 1]; | ||
| 1093 | /* Test whether the drive actually exists, and | ||
| 1094 | get the name of the file system. See: | ||
| 1095 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa>. */ | ||
| 1096 | if (GetVolumeInformation (mountdir, NULL, 0, NULL, NULL, NULL, | ||
| 1097 | fs_name, sizeof fs_name)) | ||
| 1098 | { | ||
| 1099 | me = xmalloc (sizeof *me); | ||
| 1100 | me->me_mountdir = xstrdup (mountdir); | ||
| 1101 | /* Check if drive is remote. See: | ||
| 1102 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea>. */ | ||
| 1103 | me->me_remote = GetDriveType (mountdir) == DRIVE_REMOTE; | ||
| 1104 | /* Here we could use | ||
| 1105 | QueryDosDeviceW -> returns something like '\Device\HarddiskVolume2' | ||
| 1106 | GetVolumeNameForVolumeMountPointW -> return something like '\\?\Volume{...}' | ||
| 1107 | */ | ||
| 1108 | me->me_devname = NULL; | ||
| 1109 | { | ||
| 1110 | /* Find the SUBST or NET USE mapping of the given drive. | ||
| 1111 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-querydosdevicew> | ||
| 1112 | For testing of SUBST: <https://ss64.com/nt/subst.html> | ||
| 1113 | For testing of NET USE: <https://ss64.com/nt/net-use.html> */ | ||
| 1114 | wchar_t drive[3]; | ||
| 1115 | drive[0] = L'A' + i; | ||
| 1116 | drive[1] = L':'; | ||
| 1117 | drive[2] = L'\0'; | ||
| 1118 | wchar_t mapping[MAX_PATH + 1]; | ||
| 1119 | DWORD mapping_len = QueryDosDeviceW (drive, mapping, sizeof (mapping) / sizeof (mapping[0])); | ||
| 1120 | if (mapping_len > 4 && wcsncmp (mapping, L"\\??\\", 4) == 0) | ||
| 1121 | { | ||
| 1122 | /* It's a SUBSTed drive. */ | ||
| 1123 | char subst_dir[MAX_PATH + 1]; | ||
| 1124 | size_t subst_dir_len = wcstombs (subst_dir, mapping + 4, sizeof (subst_dir)); | ||
| 1125 | if (subst_dir_len > 0 && subst_dir_len <= MAX_PATH) | ||
| 1126 | me->me_mntroot = xstrdup (subst_dir); | ||
| 1127 | else | ||
| 1128 | /* mapping is too long or not convertible to the | ||
| 1129 | locale encoding. */ | ||
| 1130 | me->me_mntroot = NULL; | ||
| 1131 | } | ||
| 1132 | else if (mapping_len > 26 | ||
| 1133 | && wcsncmp (mapping, L"\\Device\\LanmanRedirector\\;", 26) == 0) | ||
| 1134 | { | ||
| 1135 | wchar_t *next_backslash = wcschr (mapping + 26, L'\\'); | ||
| 1136 | if (next_backslash != NULL) | ||
| 1137 | { | ||
| 1138 | *--next_backslash = L'\\'; | ||
| 1139 | char share_dir[MAX_PATH + 1]; | ||
| 1140 | size_t share_dir_len = wcstombs (share_dir, next_backslash, sizeof (share_dir)); | ||
| 1141 | if (share_dir_len > 0 && share_dir_len <= MAX_PATH) | ||
| 1142 | me->me_mntroot = xstrdup (share_dir); | ||
| 1143 | else | ||
| 1144 | /* mapping is too long or not convertible to the | ||
| 1145 | locale encoding. */ | ||
| 1146 | me->me_mntroot = NULL; | ||
| 1147 | } | ||
| 1148 | else | ||
| 1149 | /* mapping does not have the expected form. */ | ||
| 1150 | me->me_mntroot = NULL; | ||
| 1151 | } | ||
| 1152 | else | ||
| 1153 | /* It's neither a SUBSTed nor a NET USEd drive. */ | ||
| 1154 | me->me_mntroot = NULL; | ||
| 1155 | } | ||
| 1156 | me->me_dev = (dev_t) -1; | ||
| 1157 | me->me_dummy = 0; | ||
| 1158 | me->me_type = xstrdup (fs_name); | ||
| 1159 | me->me_type_malloced = 1; | ||
| 1160 | |||
| 1161 | /* Add to the linked list. */ | ||
| 1162 | *mtail = me; | ||
| 1163 | mtail = &me->me_next; | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | } | ||
| 1167 | } | ||
| 1168 | { | ||
| 1169 | /* Windows also has true mount points, called "mounted folders". See | ||
| 1170 | <https://learn.microsoft.com/en-us/windows/win32/fileio/volume-mount-points> | ||
| 1171 | For testing: <https://learn.microsoft.com/en-us/windows-server/storage/disk-management/assign-a-mount-point-folder-path-to-a-drive> */ | ||
| 1172 | /* Enumerate the volumes. See | ||
| 1173 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstvolumew> | ||
| 1174 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextvolumew> | ||
| 1175 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findvolumeclose> */ | ||
| 1176 | wchar_t vol_name[MAX_PATH + 1]; | ||
| 1177 | HANDLE h = FindFirstVolumeW (vol_name, sizeof (vol_name) / sizeof (vol_name[0])); | ||
| 1178 | if (h != INVALID_HANDLE_VALUE) | ||
| 1179 | { | ||
| 1180 | do | ||
| 1181 | { | ||
| 1182 | /* Look where the volume vol_name is mounted. | ||
| 1183 | There are two APIs for doing this: | ||
| 1184 | - FindFirstVolumeMountPointW, FindNextVolumeMountPointW, | ||
| 1185 | FindVolumeMountPointClose. This API always fails with | ||
| 1186 | error code ERROR_ACCESS_DENIED. | ||
| 1187 | - GetVolumePathNamesForVolumeNameW. This API works but | ||
| 1188 | may require a significantly larger buffer. | ||
| 1189 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamesforvolumenamew> */ | ||
| 1190 | wchar_t stack_buf[MAX_PATH + 2]; | ||
| 1191 | wchar_t *malloced_buf = NULL; | ||
| 1192 | wchar_t *buf = stack_buf; | ||
| 1193 | DWORD bufsize = sizeof (stack_buf) / sizeof (wchar_t); | ||
| 1194 | BOOL success; | ||
| 1195 | for (;;) | ||
| 1196 | { | ||
| 1197 | success = GetVolumePathNamesForVolumeNameW (vol_name, buf, bufsize, &bufsize); | ||
| 1198 | if (!success && GetLastError () == ERROR_MORE_DATA) | ||
| 1199 | { | ||
| 1200 | free (malloced_buf); | ||
| 1201 | malloced_buf = (wchar_t *) xmalloc (bufsize * sizeof (wchar_t)); | ||
| 1202 | buf = malloced_buf; | ||
| 1203 | } | ||
| 1204 | else | ||
| 1205 | break; | ||
| 1206 | } | ||
| 1207 | if (success) | ||
| 1208 | { | ||
| 1209 | wchar_t *mount_dir = buf; | ||
| 1210 | while (*mount_dir != L'\0') | ||
| 1211 | { | ||
| 1212 | /* Drive mounts are already handled above. */ | ||
| 1213 | if (!(mount_dir[0] >= L'A' && mount_dir[0] <= L'Z' | ||
| 1214 | && mount_dir[1] == L':' && mount_dir[2] == L'\\' | ||
| 1215 | && mount_dir[3] == L'\0')) | ||
| 1216 | { | ||
| 1217 | char mountdir[MAX_PATH + 1]; | ||
| 1218 | size_t mountdir_len = wcstombs (mountdir, mount_dir, sizeof (mountdir)); | ||
| 1219 | if (mountdir_len > 0 && mountdir_len <= MAX_PATH) | ||
| 1220 | { | ||
| 1221 | char fs_name[MAX_PATH + 1]; | ||
| 1222 | /* Get the name of the file system. See: | ||
| 1223 | <https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa>. */ | ||
| 1224 | if (GetVolumeInformation (mountdir, NULL, 0, NULL, NULL, NULL, | ||
| 1225 | fs_name, sizeof fs_name)) | ||
| 1226 | { | ||
| 1227 | me = xmalloc (sizeof *me); | ||
| 1228 | me->me_mountdir = xstrdup (mountdir); | ||
| 1229 | me->me_remote = false; | ||
| 1230 | /* Here we could use vol_name, something like '\\?\Volume{...}'. */ | ||
| 1231 | me->me_devname = NULL; | ||
| 1232 | me->me_mntroot = NULL; | ||
| 1233 | me->me_dev = (dev_t) -1; | ||
| 1234 | me->me_dummy = 0; | ||
| 1235 | me->me_type = xstrdup (fs_name); | ||
| 1236 | me->me_type_malloced = 1; | ||
| 1237 | |||
| 1238 | /* Add to the linked list. */ | ||
| 1239 | *mtail = me; | ||
| 1240 | mtail = &me->me_next; | ||
| 1241 | } | ||
| 1242 | } | ||
| 1243 | else | ||
| 1244 | { | ||
| 1245 | /* mount_dir is too long or not convertible to the | ||
| 1246 | locale encoding. */ | ||
| 1247 | } | ||
| 1248 | } | ||
| 1249 | mount_dir += wcslen (mount_dir) + 1; | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | free (malloced_buf); | ||
| 1253 | } | ||
| 1254 | while (FindNextVolumeW (h, vol_name, sizeof (vol_name) / sizeof (vol_name[0]))); | ||
| 1255 | FindVolumeClose (h); | ||
| 1256 | } | ||
| 1257 | } | ||
| 1258 | #endif | ||
| 1259 | |||
| 1260 | #if MOUNTED_NOT_PORTED | ||
| 1261 | # error "Please port gnulib mountlist.c to your platform!" | ||
| 1262 | #endif | ||
| 1263 | |||
| 1095 | *mtail = NULL; | 1264 | *mtail = NULL; |
| 1096 | return mount_list; | 1265 | return mount_list; |
| 1097 | 1266 | ||
