*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
*
* GPL HEADER END
*/
* 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.
*
numexprs++;
if (numexprs > 1)
- i += snprintf(buffer + i, count - i, "[");
+ i += scnprintf(buffer + i, count - i, "[");
list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
if (j++ != 0)
- i += snprintf(buffer + i, count - i, ",");
+ i += scnprintf(buffer + i, count - i, ",");
i += cfs_range_expr_print(buffer + i, count - i, expr,
numexprs > 1);
}
if (numexprs > 1)
- i += snprintf(buffer + i, count - i, "]");
+ i += scnprintf(buffer + i, count - i, "]");
return i;
}
}
/**
+ * Convert express list (\a expr_list) to an array of all matched values
+ *
+ * \retval N N is total number of all matched values
+ * \retval 0 if expression list is empty
+ * \retval < 0 for failure
+ */
+int
+cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp)
+{
+ struct cfs_range_expr *expr;
+ __u32 *val;
+ int count = 0;
+ int i;
+
+ list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+ for (i = expr->re_lo; i <= expr->re_hi; i++) {
+ if (((i - expr->re_lo) % expr->re_stride) == 0)
+ count++;
+ }
+ }
+
+ if (count == 0) /* empty expression list */
+ return 0;
+
+ if (count > max)
+ return -EINVAL;
+
+ val = calloc(sizeof(val[0]), count);
+ if (val == NULL)
+ return -ENOMEM;
+
+ count = 0;
+ list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+ for (i = expr->re_lo; i <= expr->re_hi; i++) {
+ if (((i - expr->re_lo) % expr->re_stride) == 0)
+ val[count++] = i;
+ }
+ }
+
+ *valpp = val;
+ return count;
+}
+
+void
+cfs_expr_list_values_free(__u32 *values, int num)
+{
+ /* This array is allocated by LIBCFS_ALLOC(), so it shouldn't be freed
+ * by OBD_FREE() if it's called by module other than libcfs & LNet,
+ * otherwise we will see fake memory leak */
+ free(values);
+}
+
+/**
* Frees cfs_range_expr structures of \a expr_list.
*
* \retval none
*/
-static void
+void
cfs_expr_list_free(struct cfs_expr_list *expr_list)
{
while (!list_empty(&expr_list->el_exprs)) {
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;
+}