Whamcloud - gitweb
LU-12352 libcfs: crashes with certain cpu part numbers
[fs/lustre-release.git] / libcfs / libcfs / util / string.c
index 9078500..2c1a24c 100644 (file)
@@ -23,7 +23,7 @@
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, 2014, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
+#include <unistd.h>
 #include <libcfs/util/string.h>
 
-/*
- * According manual of strlcpy() and strlcat() the functions should return
- * the total length of the string they tried to create. For strlcpy() that
- * means the length of src. For strlcat() that means the initial length of
- * dst plus the length of src. So, the function strnlen() cannot be used
- * otherwise the return value will be wrong.
- */
-#ifndef HAVE_STRLCPY /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcpy(char *dst, const char *src, size_t size)
-{
-       size_t ret = strlen(src);
-
-       if (size) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-               memcpy(dst, src, len);
-               dst[len] = '\0';
-       }
-       return ret;
-}
-#endif
-
-#ifndef HAVE_STRLCAT /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcat(char *dst, const char *src, size_t size)
-{
-       size_t dsize = strlen(dst);
-       size_t len = strlen(src);
-       size_t ret = dsize + len;
-
-       dst  += dsize;
-       size -= dsize;
-       if (len >= size)
-               len = size-1;
-       memcpy(dst, src, len);
-       dst[len] = '\0';
-       return ret;
-}
-#endif
-
 /**
  * Extracts tokens from strings.
  *
@@ -480,3 +444,83 @@ cfs_expr_list_free_list(struct list_head *list)
                cfs_expr_list_free(el);
        }
 }
+
+/**
+ * cfs_abs_path() - Get the absolute path of a relative path
+ * @request_path:      The relative path to be resolved
+ * @resolved_path:     Set to the resolved absolute path
+ *
+ * Returns the canonicalized absolute pathname.  This function is a wrapper to
+ * realpath, but will work even if the target file does not exist.  All
+ * directories in the path must exist.
+ *
+ * Return: On success, 0 is returned and resolved_path points to an allocated
+ * string containing the absolute pathname.  On error, errno is set
+ * appropriately, -errno is returned, and resolved_path points to NULL.
+ */
+int cfs_abs_path(const char *request_path, char **resolved_path)
+{
+       char  buf[PATH_MAX + 1] = "";
+       char *path;
+       char *ptr;
+       int len;
+       int rc = 0;
+       const char *fmt;
+
+       path = malloc(sizeof(buf));
+       if (path == NULL)
+               return -ENOMEM;
+
+       if (request_path[0] != '/') {
+               if (getcwd(path, sizeof(buf) - 1) == NULL) {
+                       rc = -errno;
+                       goto out;
+               }
+               len = snprintf(buf, sizeof(buf), "%s/%s", path, request_path);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       } else {
+               /* skip duplicate leading '/' */
+               len = snprintf(buf, sizeof(buf), "%s",
+                              request_path + strspn(request_path, "/") - 1);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       }
+
+       /* if filename not in root directory, call realpath for parent path */
+       ptr = strrchr(buf, '/');
+       if (ptr != buf) {
+               *ptr = '\0';
+               if (path != realpath(buf, path)) {
+                       rc = -errno;
+                       goto out;
+               }
+               /* add the filename back */
+               len = strlen(path);
+               fmt = (path[len - 1] == '/') ? "%s" : "/%s";
+               len = snprintf(path + len, sizeof(buf) - len, fmt, ptr + 1);
+               if (len >= sizeof(buf) - len) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       } else {
+               len = snprintf(path, sizeof(buf), "%s", buf);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       }
+
+out:
+       if (rc == 0) {
+               *resolved_path = path;
+       } else {
+               *resolved_path = NULL;
+               free(path);
+       }
+       return rc;
+}