Index: trunk/src/VBox/Runtime/r3/linux/sysfs.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/linux/sysfs.cpp	(revision 15509)
+++ trunk/src/VBox/Runtime/r3/linux/sysfs.cpp	(revision 15644)
@@ -34,4 +34,10 @@
 *******************************************************************************/
 #define LOG_GROUP RTLOGGROUP_SYSTEM
+#include <iprt/linux/sysfs.h>
+#include <iprt/assert.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
 #include <unistd.h>
 #include <stdio.h>
@@ -41,9 +47,4 @@
 #include <errno.h>
 
-#include <iprt/linux/sysfs.h>
-#include <iprt/assert.h>
-#include <iprt/param.h>
-#include <iprt/string.h>
-
 
 /**
@@ -51,46 +52,41 @@
  * prepending "/sys/" if the path is relative.
  *
- * @returns The number of characters written, or -1 and errno on failure.
+ * @returns The number of characters returned, or -1 and errno set to ERANGE on
+ *        failure.
+ *
  * @param   pszBuf     Where to write the path.  Must be at least
  *                     sizeof("/sys/") characters long
- * @param   cchBuf     The size of the buffer pointed to by @a pszBuf
+ * @param   cchBuf     The size of the buffer pointed to by @a pszBuf.
  * @param   pszFormat  The name format, either absolute or relative to "/sys/".
  * @param   va         The format args.
  */
-static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf,
-                                         const char *pszFormat, va_list va)
-{
+static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
+{
+    static const char s_szPrefix[] = "/sys/";
+    AssertReturnStmt(cchBuf > sizeof(s_szPrefix), errno = ERANGE, -1);
+
+    size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va);
+    if (*pszBuf != '/')
+    {
+        AssertReturnStmt(cchBuf >= cch + sizeof(s_szPrefix), errno = ERANGE, -1);
+        memmove(pszBuf + sizeof(s_szPrefix) - 1, pszBuf, cch + 1);
+        memcpy(pszBuf, s_szPrefix, sizeof(s_szPrefix) - 1);
+        cch += sizeof(s_szPrefix) - 1;
+    }
+    return cch;
+}
+
+
+RTDECL(bool) RTLinuxSysFsExistsV(const char *pszFormat, va_list va)
+{
+    int iSavedErrno = errno;
+
+    /*
+     * Construct the filename and call stat.
+     */
+    bool fRet = false;
     char szFilename[RTPATH_MAX];
-    const char szPrefix[] = "/sys/";
-    if (cchBuf < sizeof(szPrefix))
-        AssertFailedReturnStmt(errno = EINVAL, -1);
-    size_t cch = RTStrPrintfV(szFilename, sizeof(szFilename), pszFormat, va);
-    if (szFilename[0] == '/')
-        *pszBuf = '\0';
-    else
-        strcpy(pszBuf, szPrefix);
-    strncat(pszBuf, szFilename, cchBuf);
-    return strlen(pszBuf);
-}
-
-/**
- * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
- *
- * @returns true / false, errno is preserved.
- * @param   pszFormat   The name format, either absolute or relative to "/sys/".
- * @param   va          The format args.
- */
-bool RTLinuxSysFsExistsV(const char *pszFormat, va_list va)
-{
-    int iSavedErrno = errno;
-
-    /*
-     * Construct the filename and call stat.
-     */
-    char szFilename[RTPATH_MAX];
-    bool fRet = false;
-    ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename),
-                                           pszFormat, va);
-    if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename))
+    ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
+    if (rc != -1)
     {
         struct stat st;
@@ -102,12 +98,6 @@
 }
 
-/**
- * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
- *
- * @returns true / false, errno is preserved.
- * @param   pszFormat   The name format, either absolute or relative to "/sys/".
- * @param   ...         The format args.
- */
-bool RTLinuxSysFsExists(const char *pszFormat, ...)
+
+RTDECL(bool) RTLinuxSysFsExists(const char *pszFormat, ...)
 {
     va_list va;
@@ -119,12 +109,5 @@
 
 
-/**
- * Opens a sysfs file.
- *
- * @returns The file descriptor. -1 and errno on failure.
- * @param   pszFormat   The name format, either absolute or relative to "/sys/".
- * @param   va          The format args.
- */
-int RTLinuxSysFsOpenV(const char *pszFormat, va_list va)
+RTDECL(int) RTLinuxSysFsOpenV(const char *pszFormat, va_list va)
 {
     /*
@@ -132,7 +115,6 @@
      */
     char szFilename[RTPATH_MAX];
-    ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename),
-                                           pszFormat, va);
-    if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename))
+    ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
+    if (rc != -1)
         rc = open(szFilename, O_RDONLY, 0);
     return rc;
@@ -140,12 +122,5 @@
 
 
-/**
- * Opens a sysfs file.
- *
- * @returns The file descriptor. -1 and errno on failure.
- * @param   pszFormat   The name format, either absolute or relative to "/sys/".
- * @param   ...         The format args.
- */
-int RTLinuxSysFsOpen(const char *pszFormat, ...)
+RTDECL(int) RTLinuxSysFsOpen(const char *pszFormat, ...)
 {
     va_list va;
@@ -157,10 +132,5 @@
 
 
-/**
- * Closes a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
- *
- * @param   fd
- */
-void RTLinuxSysFsClose(int fd)
+RTDECL(void) RTLinuxSysFsClose(int fd)
 {
     int iSavedErrno = errno;
@@ -170,13 +140,5 @@
 
 
-/**
- * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
- *
- * @returns The number of bytes read. -1 and errno on failure.
- * @param   fd          The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
- * @param   pszBuf      Where to store the string.
- * @param   cchBuf      The size of the buffer. Must be at least 2 bytes.
- */
-ssize_t RTLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf)
+RTDECL(ssize_t) RTLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf)
 {
     Assert(cchBuf > 1);
@@ -187,13 +149,5 @@
 
 
-/**
- * Reads a number from a sysfs file.
- *
- * @returns 64-bit signed value on success, -1 and errno on failure.
- * @param   uBase       The number base, 0 for autodetect.
- * @param   pszFormat   The filename format, either absolute or relative to "/sys/".
- * @param   va          Format args.
- */
-int64_t RTLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va)
+RTDECL(int64_t) RTLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va)
 {
     int fd = RTLinuxSysFsOpenV(pszFormat, va);
@@ -221,13 +175,5 @@
 
 
-/**
- * Reads a number from a sysfs file.
- *
- * @returns 64-bit signed value on success, -1 and errno on failure.
- * @param   uBase       The number base, 0 for autodetect.
- * @param   pszFormat   The filename format, either absolute or relative to "/sys/".
- * @param   ...         Format args.
- */
-int64_t RTLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...)
+RTDECL(int64_t) RTLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...)
 {
     va_list va;
@@ -239,16 +185,5 @@
 
 
-/**
- * Reads a string from a sysfs file.  If the file contains a newline, we only
- * return the text up until there.
- *
- * @returns number of characters read on success, -1 and errno on failure.
- * @param   pszBuf      Where to store the path element.  Must be at least two
- *                      characters, but a longer buffer would be advisable.
- * @param   cchBuf      The size of the buffer pointed to by @a pszBuf.
- * @param   pszFormat   The filename format, either absolute or relative to "/sys/".
- * @param   va          Format args.
- */
-ssize_t RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
+RTDECL(ssize_t) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
 {
     int fd = RTLinuxSysFsOpenV(pszFormat, va);
@@ -258,25 +193,15 @@
     ssize_t cchRet = RTLinuxSysFsReadStr(fd, pszBuf, cchBuf);
     RTLinuxSysFsClose(fd);
-    char *pchNewLine = NULL;
     if (cchRet > 0)
-        pchNewLine = reinterpret_cast<char *>(memchr(pszBuf, '\n', cchRet));
-    if (pchNewLine != NULL)
-        *pchNewLine = '\0';
+    {
+        char *pchNewLine = (char *)memchr(pszBuf, '\n', cchRet);
+        if (pchNewLine)
+            *pchNewLine = '\0';
+    }
     return cchRet;
 }
 
 
-/**
- * Reads a string from a sysfs file.  If the file contains a newline, we only
- * return the text up until there.
- *
- * @returns number of characters read on success, -1 and errno on failure.
- * @param   pszBuf      Where to store the path element.  Must be at least two
- *                      characters, but a longer buffer would be advisable.
- * @param   cchBuf      The size of the buffer pointed to by @a pszBuf.
- * @param   pszFormat   The filename format, either absolute or relative to "/sys/".
- * @param   ...         Format args.
- */
-ssize_t RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
+RTDECL(ssize_t) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
 {
     va_list va;
@@ -288,48 +213,57 @@
 
 
-/**
- * Reads the last element of the path of the file pointed to by the symbolic
- * link specified.  This is needed at least to get the name of the driver
- * associated with a device, where pszFormat should be the "driver" link in the
- * devices sysfs directory.
- *
- * @returns The number of characters written on success, -1 and errno on failure.
- * @param   pszBuf      Where to store the path element.  Must be at least two
- *                      characters, but a longer buffer would be advisable.
- * @param   cchBuf      The size of the buffer pointed to by @a pszBuf.
- * @param   pszFormat   The filename format, either absolute or relative to "/sys/".
- * @param   ...         Format args.
- */
-int RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
-{
-    if (cchBuf < 2)
-        AssertFailedReturnStmt(errno = EINVAL, -1);
-    va_list va;
-    va_start(va, pszFormat);
-    char szFilename[RTPATH_MAX], szLink[RTPATH_MAX];
+RTDECL(ssize_t) RTLinuxSysFsGetLinkDestV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
+{
+    AssertReturnStmt(cchBuf >= 2, errno = EINVAL, -1);
+
+    /*
+     * Construct the filename and read the link.
+     */
+    char szFilename[RTPATH_MAX];
     int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
-    va_end(va);
-    if (rc == sizeof(szFilename))
-    {
-        rc = -1;
-        errno = EINVAL;  /* Bad format arguements */
-    }
-    if (rc > 0)
-        rc = readlink(szFilename, szLink, sizeof(szLink));
-    if (rc > 0 && static_cast<size_t>(rc) > sizeof(szLink) - 1)
-    {
-        rc = -1;
-        errno = EIO;  /* The path name can't be this big. */
-    }
-    if (rc >= 0)
-    {
-        szLink[rc] = '\0';
-        char *lastPart = strrchr(szLink, '/');
-        Assert(lastPart != NULL);  /* rtLinuxSysFsConstructPath guarantees a path
-                                    * starting with '/'. */
+    if (rc == -1)
+        return -1;
+
+    char szLink[RTPATH_MAX];
+    rc = readlink(szFilename, szLink, sizeof(szLink));
+    if (rc == -1)
+        return -1;
+    if ((size_t)rc > sizeof(szLink) - 1)
+    {
+        errno = ERANGE;
+        return -1;
+    }
+    szLink[rc] = '\0'; /* readlink fun. */
+
+    /*
+     * Extract the file name component and copy it into the return buffer.
+     */
+    size_t cchName;
+    const char *pszName = RTPathFilename(szLink);
+    if (pszName)
+    {
+        cchName = strlen(pszName);
+        if (cchName >= cchBuf)
+        {
+            errno = ERANGE;
+            return -1;
+        }
+        memcpy(pszBuf, pszName, cchName);
+    }
+    else
+    {
         *pszBuf = '\0';
-        strncat(pszBuf, lastPart + 1, cchBuf);
-        rc = strlen(pszBuf);
-    }
+        cchName = 0;
+    }
+    return cchName;
+}
+
+
+RTDECL(ssize_t) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
+{
+    va_list va;
+    va_start(va, pszFormat);
+    int rc = RTLinuxSysFsGetLinkDestV(pszBuf, cchBuf, pszFormat, va);
+    va_end(va);
     return rc;
 }
