Skip to content
73 changes: 70 additions & 3 deletions src/native/libs/System.Native/pal_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
#include "pal_config.h"
#include "pal_mount.h"
#include "pal_utilities.h"
#include "pal_safecrt.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>

// Check if we should use getmntinfo or /proc/mounts
// Check if we should use getfsstat or /proc/mounts
#if HAVE_MNTINFO
#include <sys/mount.h>
#else
Expand All @@ -32,18 +34,83 @@
int32_t SystemNative_GetAllMountPoints(MountPointFound onFound, void* context)
{
#if HAVE_MNTINFO
// getmntinfo returns pointers to OS-internal structs, so we don't need to worry about free'ing the object
// Use getfsstat which is thread-safe (unlike getmntinfo which uses internal static buffers)
#if HAVE_STATFS
struct statfs* mounts = NULL;
#else
struct statvfs* mounts = NULL;
#endif
int count = getmntinfo(&mounts, MNT_WAIT);

int count;
int capacity = 0;
size_t bufferSize = 0;

// Loop to handle the case where mount points are added between calls
while (1)
{
// Get the current number of mount points
count = getfsstat(NULL, 0, MNT_NOWAIT);
if (count < 0)
{
free(mounts);
return -1;
}

// Reallocate buffer if needed - allocate one extra to detect if more mounts were added
if (count >= capacity)
{
free(mounts);
capacity = count + 1;
if (!multiply_s((size_t)capacity, sizeof(*mounts), &bufferSize))
{
errno = ENOMEM;
return -1;
}
if (bufferSize > INT_MAX)
{
errno = ENOMEM;
return -1;
}
#if HAVE_STATFS
mounts = (struct statfs*)malloc(bufferSize);
#else
mounts = (struct statvfs*)malloc(bufferSize);
#endif
if (mounts == NULL)
{
errno = ENOMEM;
return -1;
}
}

// If count is 0, break - post-loop code handles empty case
if (count == 0)
{
break;
}

// Get actual mount point information
count = getfsstat(mounts, (int)bufferSize, MNT_NOWAIT);
if (count < 0)
{
free(mounts);
return -1;
}

// If count is less than capacity, we got all mount points
if (count < capacity)
{
break;
}
// Otherwise, more mounts were added - loop again with larger buffer
}

for (int32_t i = 0; i < count; i++)
{
onFound(context, mounts[i].f_mntonname);
}

free(mounts);
return 0;
}

Expand Down
Loading