[DROID] Read /proc/mounts in one go to avoid race.
authorTrent Nelson <trent.a.b.nelson@gmail.com>
Wed, 19 Feb 2014 23:06:57 +0000 (16:06 -0700)
committerTrent Nelson <trent.a.b.nelson@gmail.com>
Tue, 25 Feb 2014 00:25:28 +0000 (17:25 -0700)
/proc/mounts is only guaranteed atomic for the current read operation.

xbmc/storage/android/AndroidStorageProvider.cpp

index 29b1f2e..19e94dc 100644 (file)
@@ -27,6 +27,9 @@
 #include "utils/RegExp.h"
 #include "utils/StringUtils.h"
 #include "utils/URIUtils.h"
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
 
 CAndroidStorageProvider::CAndroidStorageProvider()
 {
@@ -95,16 +98,59 @@ void CAndroidStorageProvider::GetLocalDrives(VECSOURCES &localDrives)
 void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES &removableDrives)
 {
   // mounted usb disks
+  char*                   buf     = NULL;
+  FILE*                   pipe;
   std::vector<CStdString> result;
-  CRegExp reMount;
+  CRegExp                 reMount;
   reMount.RegComp("^(.+?)\\s+(.+?)\\s+(.+?)\\s");
-  char line[1024];
 
-  FILE* pipe = fopen("/proc/mounts", "r");
+  /* /proc/mounts is only guaranteed atomic for the current read
+   * operation, so we need to read it all at once.
+   */
+  if ((pipe = fopen("/proc/mounts", "r")))
+  {
+    char*   new_buf;
+    size_t  buf_len = 4096;
+
+    while ((new_buf = (char*)realloc(buf, buf_len * sizeof(char))))
+    {
+      size_t nread;
 
-  if (pipe)
+      buf   = new_buf;
+      nread = fread(buf, sizeof(char), buf_len, pipe);
+
+      if (nread == buf_len)
+      {
+        rewind(pipe);
+        buf_len *= 2;
+      }
+      else
+      {
+        buf[nread] = '\0';
+        if (!feof(pipe))
+          new_buf = NULL;
+        break;
+      }
+    }
+
+    if (!new_buf)
+    {
+      free(buf);
+      buf = NULL;
+    }
+    fclose(pipe);
+  }
+  else
+    CLog::Log(LOGERROR, "Cannot read mount points");
+
+  if (buf)
   {
-    while (fgets(line, sizeof(line) - 1, pipe))
+    char* line;
+    char* saveptr = NULL;
+
+    line = strtok_r(buf, "\n", &saveptr);
+
+    while (line)
     {
       if (reMount.RegFind(line) != -1)
       {
@@ -132,10 +178,10 @@ void CAndroidStorageProvider::GetRemovableDrives(VECSOURCES &removableDrives)
         if(accepted)
           result.push_back(mount);
       }
+      line = strtok_r(NULL, "\n", &saveptr);
     }
-    fclose(pipe);
-  } else
-    CLog::Log(LOGERROR, "Cannot read mount points");
+    free(buf);
+  }
 
   for (unsigned int i = 0; i < result.size(); i++)
   {