char *dir_canonical_vpath(pool *p, const char *path) { char buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char work[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; if (p == NULL || path == NULL) { errno = EINVAL; return NULL; } if (*path == '~') { if (pr_fs_interpolate(path, work, sizeof(work)-1) != 1) { if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) { return NULL; } } } else { if (pr_fs_dircat(work, sizeof(work), pr_fs_getvwd(), path) < 0) { return NULL; } } pr_fs_clean_path(work, buf, sizeof(buf)-1); return pstrdup(p, buf); }
/* dir_best_path() creates the "most" fully canonicalized path possible * (i.e. if path components at the end don't exist, they are ignored). */ char *dir_best_path(pool *p, const char *path) { char workpath[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char realpath_buf[PR_TUNABLE_PATH_MAX + 1] = {'\0'}; char *target = NULL, *ntarget; int fini = 0; if (*path == '~') { if (pr_fs_interpolate(path, workpath, sizeof(workpath)-1) != 1) { if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) return NULL; } } else { if (pr_fs_dircat(workpath, sizeof(workpath), pr_fs_getcwd(), path) < 0) return NULL; } pr_fs_clean_path(pstrdup(p, workpath), workpath, sizeof(workpath)-1); while (!fini && *workpath) { if (pr_fs_resolve_path(workpath, realpath_buf, sizeof(realpath_buf)-1, 0) != -1) break; ntarget = strrchr(workpath, '/'); if (ntarget) { if (target) { if (pr_fs_dircat(workpath, sizeof(workpath), workpath, target) < 0) return NULL; } target = ntarget; *target++ = '\0'; } else fini++; } if (!fini && *workpath) { if (target) { if (pr_fs_dircat(workpath, sizeof(workpath), realpath_buf, target) < 0) return NULL; } else sstrncpy(workpath, realpath_buf, sizeof(workpath)); } else { if (pr_fs_dircat(workpath, sizeof(workpath), "/", target) < 0) return NULL; } return pstrdup(p, workpath); }
END_TEST START_TEST (fs_dircat_test) { char buf[PR_TUNABLE_PATH_MAX+1], *a, *b, *ok; int res; res = pr_fs_dircat(NULL, 0, NULL, NULL); fail_unless(res == -1, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL for null arguments"); res = pr_fs_dircat(buf, 0, "foo", "bar"); fail_unless(res == -1, "Failed to handle zero-length buffer"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL for zero-length buffer"); res = pr_fs_dircat(buf, -1, "foo", "bar"); fail_unless(res == -1, "Failed to handle negative-length buffer"); fail_unless(errno == EINVAL, "Failed to set errno to EINVAL for negative-length buffer"); a = pcalloc(p, PR_TUNABLE_PATH_MAX); memset(a, 'A', PR_TUNABLE_PATH_MAX-1); b = "foo"; res = pr_fs_dircat(buf, sizeof(buf)-1, a, b); fail_unless(res == -1, "Failed to handle too-long paths"); fail_unless(errno == ENAMETOOLONG, "Failed to set errno to ENAMETOOLONG for too-long paths"); a = "foo"; b = "/bar"; ok = b; res = pr_fs_dircat(buf, sizeof(buf)-1, a, b); fail_unless(res == 0, "Failed to concatenate abs-path path second dir"); fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'", ok, buf); a = "foo"; b = "bar"; ok = "foo/bar"; res = pr_fs_dircat(buf, sizeof(buf)-1, a, b); fail_unless(res == 0, "Failed to concatenate two normal paths"); fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'", ok, buf); a = "foo/"; b = "bar"; ok = "foo/bar"; res = pr_fs_dircat(buf, sizeof(buf)-1, a, b); fail_unless(res == 0, "Failed to concatenate first dir with trailing slash"); fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'", ok, buf); a = ""; b = ""; ok = "/"; res = pr_fs_dircat(buf, sizeof(buf)-1, a, b); fail_unless(res == 0, "Failed to concatenate two empty paths"); fail_unless(strcmp(buf, ok) == 0, "Expected concatenated dir '%s', got '%s'", ok, buf); }