C 替代';realpath';解决问题/&引用;及"/&引用;在一条小路上
C 替代';realpath';解决问题/&引用;及"/&引用;在一条小路上,c,canonicalization,realpath,C,Canonicalization,Realpath,realpath执行我需要的操作,但仅当路径中的文件实际存在时才起作用 我需要一个函数,它可以从字符串(例如。/some//directory/a/b/c//d到some/directory/a/b/d)返回一个规范化路径,而不管目录/文件是否实际存在 本质上相当于windows上的路径规范化 这样的函数已经存在了吗?听起来像是在*nix(例如,Linux)上 问:你的编译器有吗 否则,如果你在C++中编程,你可能会考虑Booo: Python源代码有一个针对多个平台的实现。不幸的是,POSIX
realpath
执行我需要的操作,但仅当路径中的文件实际存在时才起作用
我需要一个函数,它可以从字符串(例如。/some//directory/a/b/c//d
到some/directory/a/b/d
)返回一个规范化路径,而不管目录/文件是否实际存在
本质上相当于windows上的路径规范化
这样的函数已经存在了吗?听起来像是在*nix(例如,Linux)上 问:你的编译器有吗
否则,如果你在C++中编程,你可能会考虑Booo:
Python源代码有一个针对多个平台的实现。不幸的是,POSIX one(在中,对于Python 3,第318行或第308行)是Python中的,但是通用逻辑可以很容易地用C重新实现(函数非常紧凑)。经过多年使用测试 Python解释器和标准库源代码中还有其他平台normpath实现,所以可移植解决方案可以是这些的组合 可能其他用C编写的系统/库也有相同的实现,因为normpath函数在安全性方面至关重要
(使用Python代码的主要优点是能够用C语言并行测试函数,即使是随机输入,而且这种测试对于确保函数的安全性非常重要)我假设您的主机是windows或unix(两者都支持
。
,
和/
分别表示父目录、当前目录和目录分隔符)。并且您的库提供对posix指定函数getcwd()
的访问,该函数检索程序的当前工作目录(即,如果在文件名中没有路径规范的情况下打开输出文件,将写入其中的完整路径)
首先调用getcwd()
以检索工作目录。如果其中的最后一个字符是'/'
,请将该工作目录预先添加到输入字符串中,而不进行修改。否则,请将其和字符'/'
预先添加到字符串中
然后只处理字符串。找到字符串的第一个实例。//“,并删除路径的前一部分和。//“
。例如,如果字符串是”/a/b/c/./foo“
,则结果将是”/a/b/foo“
。重复该操作,直到字符串中没有。//“
的实例
唯一需要注意的是决定如何处理字符串,如“/../”
(从技术上讲,这是一个不存在的路径)。要么将其保留为“/”
(这样您总是可以得到一个可行的路径),要么报告错误
完成后,查找“/。/”
的实例,并将其替换为“/”
。这将把类似“/a/b/c/”
的字符串转换为“/a/b/c/”
,但将只保留类似“/a/b/c./”
(在“/a/b”
中指定名为“c.
的目录)的字符串
以上所有操作都只是处理字符串。除了使用getcwd()
,没有任何依赖于主机环境的操作。因此,无论路径是否实际存在,过程都是相同的
一些建议可能包括使其更好地与windows配合使用,例如将'/'
和'\'
视为等效项,以及处理驱动器说明符,如“A:”
如果您不想调用getcwd()
(例如,如果您的程序不依赖于实际有一个工作目录,或者如果它有一个不存在的目录),那么您需要指定一个启动条件。例如,像“./x/y/z”这样的字符串将在哪里结束
我的建议允许
字符成为文件名(或目录名)的一部分您可能需要也可能不需要。根据需要进行调整。根据您的问题陈述,以下内容完全符合您的要求。大部分代码来自注释链接中提供的路径.c
。添加了删除前面的。/
的修改,以符合您的问题陈述:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void pathCanonicalize (char *path);
int main (int argc, char **argv)
{
if (argc < 2) {
fprintf (stderr, "error: insufficient input, usage: %s <path>\n",
argv[0]);
return 1;
}
char *fullpath = strdup (argv[1]);
if (!fullpath) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
pathCanonicalize (fullpath);
printf ("\n original : %s\n canonical: %s\n\n", argv[1], fullpath);
free (fullpath);
return 0;
}
void pathCanonicalize (char *path)
{
size_t i;
size_t j;
size_t k;
//Move to the beginning of the string
i = 0;
k = 0;
//Replace backslashes with forward slashes
while (path[i] != '\0') {
//Forward slash or backslash separator found?
if (path[i] == '/' || path[i] == '\\') {
path[k++] = '/';
while (path[i] == '/' || path[i] == '\\')
i++;
} else {
path[k++] = path[i++];
}
}
//Properly terminate the string with a NULL character
path[k] = '\0';
//Move back to the beginning of the string
i = 0;
j = 0;
k = 0;
//Parse the entire string
do {
//Forward slash separator found?
if (path[i] == '/' || path[i] == '\0') {
//"." element found?
if ((i - j) == 1 && !strncmp (path + j, ".", 1)) {
//Check whether the pathname is empty?
if (k == 0) {
if (path[i] == '\0') {
path[k++] = '.';
} else if (path[i] == '/' && path[i + 1] == '\0') {
path[k++] = '.';
path[k++] = '/';
}
} else if (k > 1) {
//Remove the final slash if necessary
if (path[i] == '\0')
k--;
}
}
//".." element found?
else if ((i - j) == 2 && !strncmp (path + j, "..", 2)) {
//Check whether the pathname is empty?
if (k == 0) {
path[k++] = '.';
path[k++] = '.';
//Append a slash if necessary
if (path[i] == '/')
path[k++] = '/';
} else if (k > 1) {
//Search the path for the previous slash
for (j = 1; j < k; j++) {
if (path[k - j - 1] == '/')
break;
}
//Slash separator found?
if (j < k) {
if (!strncmp (path + k - j, "..", 2)) {
path[k++] = '.';
path[k++] = '.';
} else {
k = k - j - 1;
}
//Append a slash if necessary
if (k == 0 && path[0] == '/')
path[k++] = '/';
else if (path[i] == '/')
path[k++] = '/';
}
//No slash separator found?
else {
if (k == 3 && !strncmp (path, "..", 2)) {
path[k++] = '.';
path[k++] = '.';
//Append a slash if necessary
if (path[i] == '/')
path[k++] = '/';
} else if (path[i] == '\0') {
k = 0;
path[k++] = '.';
} else if (path[i] == '/' && path[i + 1] == '\0') {
k = 0;
path[k++] = '.';
path[k++] = '/';
} else {
k = 0;
}
}
}
} else {
//Copy directory name
memmove (path + k, path + j, i - j);
//Advance write pointer
k += i - j;
//Append a slash if necessary
if (path[i] == '/')
path[k++] = '/';
}
//Move to the next token
while (path[i] == '/')
i++;
j = i;
}
else if (k == 0) {
while (path[i] == '.' || path[i] == '/') {
j++,i++;
}
}
} while (path[i++] != '\0');
//Properly terminate the string with a NULL character
path[k] = '\0';
}
我不认为有任何标准的库函数可用于此 您可以使用源代码文件
server/util.c
中的函数ap\u getparents()
。我相信它正是您想要的:
(这是假设在您的项目中重新使用Apache许可代码是可以接受的。)另一次尝试。此尝试的怪癖/功能:
- 不规范化为源字符串;写入调用方提供的空间
- 有绝对路径与相对路径的概念(源路径是否以“/”开头?):如果存在足够多的“..”吃掉所有源,则发出“/”表示绝对路径,发出“.”表示相对路径
- 不知道源路径中的元素是否对应于实际的文件系统对象
- 使用C99可变长度数组,并将其返回到调用者提供的空间中,不使用malloc,而是在引擎盖下进行一些拷贝
- 给定这些副本,源和目标可以相同
- 使用strtok_r(3),其关于不返回零长度标记的怪癖似乎与相邻“/”字符的期望行为相匹配
#include <stdlib.h>
#include <string.h>
int
pathcanon(const char *srcpath, char *dstpath, size_t sz)
{
size_t plen = strlen(srcpath) + 1, chk;
char wtmp[plen], *tokv[plen], *s, *tok, *sav;
int i, ti, relpath;
relpath = (*srcpath == '/') ? 0 : 1;
/* make a local copy of srcpath so strtok(3) won't mangle it */
ti = 0;
(void) strcpy(wtmp, srcpath);
tok = strtok_r(wtmp, "/", &sav);
while (tok != NULL) {
if (strcmp(tok, "..") == 0) {
if (ti > 0) {
ti--;
}
} else if (strcmp(tok, ".") != 0) {
tokv[ti++] = tok;
}
tok = strtok_r(NULL, "/", &sav);
}
chk = 0;
s = dstpath;
/*
* Construct canonicalized result, checking for room as we
* go. Running out of space leaves dstpath unusable: written
* to and *not* cleanly NUL-terminated.
*/
for (i = 0; i < ti; i++) {
size_t l = strlen(tokv[i]);
if (i > 0 || !relpath) {
if (++chk >= sz) return -1;
*s++ = '/';
}
chk += l;
if (chk >= sz) return -1;
strcpy(s, tokv[i]);
s += l;
}
if (s == dstpath) {
if (++chk >= sz) return -1;
*s++ = relpath ? '.' : '/';
}
*s = '\0';
return 0;
}
#包括
#包括
int
pathcanon(常量字符*srcpath,字符*dstpath,大小sz)
{
尺寸=strlen(srcpath)+1,chk;
字符wtmp[plen]、*tokv[plen]、*s、*tok、*sav;
int i,ti,relpath;
relpath=(*srcpath=='/')?0:1;
/*制作srcpath的本地副本,这样strtok(3)就不会损坏它*/
ti=0;
(无效)strcpy(wtmp,srcpath);
tok=strtok_r(wtmp,“/”,&sav);
while(tok!=NULL){
如果(strcmp(tok,“…”)==0){
如果(ti>
#ifdef WIN32
#define IS_SLASH(s) ((s == '/') || (s == '\\'))
#else
#define IS_SLASH(s) (s == '/')
#endif
void ap_getparents(char *name)
{
char *next;
int l, w, first_dot;
/* Four paseses, as per RFC 1808 */
/* a) remove ./ path segments */
for (next = name; *next && (*next != '.'); next++) {
}
l = w = first_dot = next - name;
while (name[l] != '\0') {
if (name[l] == '.' && IS_SLASH(name[l + 1])
&& (l == 0 || IS_SLASH(name[l - 1])))
l += 2;
else
name[w++] = name[l++];
}
/* b) remove trailing . path, segment */
if (w == 1 && name[0] == '.')
w--;
else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
w--;
name[w] = '\0';
/* c) remove all xx/../ segments. (including leading ../ and /../) */
l = first_dot;
while (name[l] != '\0') {
if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
&& (l == 0 || IS_SLASH(name[l - 1]))) {
int m = l + 3, n;
l = l - 2;
if (l >= 0) {
while (l >= 0 && !IS_SLASH(name[l]))
l--;
l++;
}
else
l = 0;
n = l;
while ((name[n] = name[m]))
(++n, ++m);
}
else
++l;
}
/* d) remove trailing xx/.. segment. */
if (l == 2 && name[0] == '.' && name[1] == '.')
name[0] = '\0';
else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
&& IS_SLASH(name[l - 3])) {
l = l - 4;
if (l >= 0) {
while (l >= 0 && !IS_SLASH(name[l]))
l--;
l++;
}
else
l = 0;
name[l] = '\0';
}
}
#include <stdlib.h>
#include <string.h>
int
pathcanon(const char *srcpath, char *dstpath, size_t sz)
{
size_t plen = strlen(srcpath) + 1, chk;
char wtmp[plen], *tokv[plen], *s, *tok, *sav;
int i, ti, relpath;
relpath = (*srcpath == '/') ? 0 : 1;
/* make a local copy of srcpath so strtok(3) won't mangle it */
ti = 0;
(void) strcpy(wtmp, srcpath);
tok = strtok_r(wtmp, "/", &sav);
while (tok != NULL) {
if (strcmp(tok, "..") == 0) {
if (ti > 0) {
ti--;
}
} else if (strcmp(tok, ".") != 0) {
tokv[ti++] = tok;
}
tok = strtok_r(NULL, "/", &sav);
}
chk = 0;
s = dstpath;
/*
* Construct canonicalized result, checking for room as we
* go. Running out of space leaves dstpath unusable: written
* to and *not* cleanly NUL-terminated.
*/
for (i = 0; i < ti; i++) {
size_t l = strlen(tokv[i]);
if (i > 0 || !relpath) {
if (++chk >= sz) return -1;
*s++ = '/';
}
chk += l;
if (chk >= sz) return -1;
strcpy(s, tokv[i]);
s += l;
}
if (s == dstpath) {
if (++chk >= sz) return -1;
*s++ = relpath ? '.' : '/';
}
*s = '\0';
return 0;
}