📄 path.c
字号:
svn_path_compare_paths(const char *path1, const char *path2){ apr_size_t path1_len = strlen(path1); apr_size_t path2_len = strlen(path2); apr_size_t min_len = ((path1_len < path2_len) ? path1_len : path2_len); apr_size_t i = 0; assert(is_canonical(path1, path1_len)); assert(is_canonical(path2, path2_len)); /* Skip past common prefix. */ while (i < min_len && path1[i] == path2[i]) ++i; /* Are the paths exactly the same? */ if ((path1_len == path2_len) && (i >= min_len)) return 0; /* Children of paths are greater than their parents, but less than greater siblings of their parents. */ if ((path1[i] == '/') && (path2[i] == 0)) return 1; if ((path2[i] == '/') && (path1[i] == 0)) return -1; if (path1[i] == '/') return -1; if (path2[i] == '/') return 1; /* Common prefix was skipped above, next character is compared to determine order. We need to use an unsigned comparison, though, so a "next character" of NULL (0x00) sorts numerically smallest. */ return (unsigned char)(path1[i]) < (unsigned char)(path2[i]) ? -1 : 1;}/* Return the string length of the longest common ancestor of PATH1 and PATH2. * * This function handles everything except the URL-handling logic * of svn_path_get_longest_ancestor, and assumes that PATH1 and * PATH2 are *not* URLs. * * If the two paths do not share a common ancestor, return 0. * * New strings are allocated in POOL. */static apr_size_tget_path_ancestor_length(const char *path1, const char *path2, apr_pool_t *pool){ apr_size_t path1_len, path2_len; apr_size_t i = 0; apr_size_t last_dirsep = 0; path1_len = strlen(path1); path2_len = strlen(path2); if (SVN_PATH_IS_EMPTY(path1) || SVN_PATH_IS_EMPTY(path2)) return 0; while (path1[i] == path2[i]) { /* Keep track of the last directory separator we hit. */ if (path1[i] == '/') last_dirsep = i; i++; /* If we get to the end of either path, break out. */ if ((i == path1_len) || (i == path2_len)) break; } /* last_dirsep is now the offset of the last directory separator we crossed before reaching a non-matching byte. i is the offset of that non-matching byte. */ if (((i == path1_len) && (path2[i] == '/')) || ((i == path2_len) && (path1[i] == '/')) || ((i == path1_len) && (i == path2_len))) return i; else return last_dirsep;}char *svn_path_get_longest_ancestor(const char *path1, const char *path2, apr_pool_t *pool){ svn_boolean_t path1_is_url, path2_is_url; path1_is_url = svn_path_is_url(path1); path2_is_url = svn_path_is_url(path2); if (path1_is_url && path2_is_url) { apr_size_t path_ancestor_len; apr_size_t i = 0; /* Find ':' */ while (1) { /* No shared protocol => no common prefix */ if (path1[i] != path2[i]) return apr_pmemdup(pool, SVN_EMPTY_PATH, sizeof(SVN_EMPTY_PATH)); if (path1[i] == ':') break; /* They're both URLs, so EOS can't come before ':' */ assert((path1[i] != '\0') && (path2[i] != '\0')); i++; } i += 3; /* Advance past '://' */ path_ancestor_len = get_path_ancestor_length(path1 + i, path2 + i, pool); if (path_ancestor_len == 0) return apr_pmemdup(pool, SVN_EMPTY_PATH, sizeof(SVN_EMPTY_PATH)); else return apr_pstrndup(pool, path1, path_ancestor_len + i); } else if ((! path1_is_url) && (! path2_is_url)) { return apr_pstrndup(pool, path1, get_path_ancestor_length(path1, path2, pool)); } else { /* A URL and a non-URL => no common prefix */ return apr_pmemdup(pool, SVN_EMPTY_PATH, sizeof(SVN_EMPTY_PATH)); }}const char *svn_path_is_child(const char *path1, const char *path2, apr_pool_t *pool){ apr_size_t i; /* assert (is_canonical (path1, strlen (path1))); ### Expensive strlen */ /* assert (is_canonical (path2, strlen (path2))); ### Expensive strlen */ /* Allow "" and "foo" to be parent/child */ if (SVN_PATH_IS_EMPTY(path1)) /* "" is the parent */ { if (SVN_PATH_IS_EMPTY(path2) /* "" not a child */ || path2[0] == '/') /* "/foo" not a child */ return NULL; else return apr_pstrdup(pool, path2); /* everything else is child */ } /* Reach the end of at least one of the paths. How should we handle things like path1:"foo///bar" and path2:"foo/bar/baz"? It doesn't appear to arise in the current Subversion code, it's not clear to me if they should be parent/child or not. */ for (i = 0; path1[i] && path2[i]; i++) if (path1[i] != path2[i]) return NULL; /* There are two cases that are parent/child ... path1[i] == '\0' .../foo path2[i] == '/' or / path1[i] == '\0' /foo path2[i] != '/' */ if (path1[i] == '\0' && path2[i]) { if (path2[i] == '/') return apr_pstrdup(pool, path2 + i + 1); else if (i == 1 && path1[0] == '/') return apr_pstrdup(pool, path2 + 1); } /* Otherwise, path2 isn't a child. */ return NULL;}svn_boolean_tsvn_path_is_ancestor(const char *path1, const char *path2){ apr_size_t path1_len = strlen(path1); /* If path1 is empty and path2 is not absoulte, then path1 is an ancestor. */ if (SVN_PATH_IS_EMPTY(path1)) return *path2 != '/'; /* If path1 is a prefix of path2, then: - If path1 ends in a path separator, - If the paths are of the same length OR - path2 starts a new path component after the common prefix, then path1 is an ancestor. */ if (strncmp(path1, path2, path1_len) == 0) return path1[path1_len - 1] == '/' || (path2[path1_len] == '/' || path2[path1_len] == '\0'); return FALSE;}apr_array_header_t *svn_path_decompose(const char *path, apr_pool_t *pool){ apr_size_t i, oldi; apr_array_header_t *components = apr_array_make(pool, 1, sizeof(const char *)); /* assert (is_canonical (path, strlen (path))); ### Expensive strlen */ if (SVN_PATH_IS_EMPTY(path)) return components; /* ### Should we return a "" component? */ /* If PATH is absolute, store the '/' as the first component. */ i = oldi = 0; if (path[i] == '/') { char dirsep = '/'; *((const char **) apr_array_push(components)) = apr_pstrmemdup(pool, &dirsep, sizeof(dirsep)); i++; oldi++; if (path[i] == '\0') /* path is a single '/' */ return components; } do { if ((path[i] == '/') || (path[i] == '\0')) { if (SVN_PATH_IS_PLATFORM_EMPTY(path + oldi, i - oldi)) *((const char **) apr_array_push(components)) = SVN_EMPTY_PATH; else *((const char **) apr_array_push(components)) = apr_pstrmemdup(pool, path + oldi, i - oldi); i++; oldi = i; /* skipping past the dirsep */ continue; } i++; } while (path[i-1]); return components;}svn_boolean_tsvn_path_is_single_path_component(const char *name){ /* assert (is_canonical (name, strlen (name))); ### Expensive strlen */ /* Can't be empty or `..' */ if (SVN_PATH_IS_EMPTY(name) || (name[0] == '.' && name[1] == '.' && name[2] == '\0')) return FALSE; /* Slashes are bad, m'kay... */ if (strchr(name, '/') != NULL) return FALSE; /* It is valid. */ return TRUE;}svn_boolean_tsvn_path_is_backpath_present(const char *path){ int len = strlen(path); if (! strcmp(path, "..")) return TRUE; if (! strncmp(path, "../", 3)) return TRUE; if (strstr(path, "/../") != NULL) return TRUE; if (len >= 3 && (! strncmp(path + len - 3, "/..", 3))) return TRUE; return FALSE;}/*** URI Stuff ***//* Examine PATH as a potential URI, and return a substring of PATH that immediately follows the (scheme):// portion of the URI, or NULL if PATH doesn't appear to be a valid URI. The returned value is not alloced -- it shares memory with PATH. */static const char *skip_uri_scheme(const char *path){ apr_size_t j; for (j = 0; path[j]; ++j) if (path[j] == ':' || path[j] == '/') break; if (j > 0 && path[j] == ':' && path[j+1] == '/' && path[j+2] == '/') return path + j + 3; return NULL;}svn_boolean_t svn_path_is_url(const char *path){ /* ### This function is reaaaaaaaaaaaaaally stupid right now. We're just going to look for: (scheme)://(optional_stuff) Where (scheme) has no ':' or '/' characters. Someday it might be nice to have an actual URI parser here. */ return skip_uri_scheme(path) ? TRUE : FALSE;}/* Here is the BNF for path components in a URI. "pchar" is a character in a path component. pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | "," unreserved = alphanum | mark mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" Note that "escaped" doesn't really apply to what users can put in their paths, so that really means the set of characters is: alphanum | mark | ":" | "@" | "&" | "=" | "+" | "$" | "," */static const char uri_char_validity[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 64 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};svn_boolean_t svn_path_is_uri_safe(const char *path){ apr_size_t i; /* Skip the URI scheme. */ path = skip_uri_scheme(path); /* No scheme? Get outta here. */ if (! path) return FALSE; /* Skip to the first slash that's after the URI scheme. */ path = strchr(path, '/'); /* If there's no first slash, then there's only a host portion; therefore there couldn't be any uri-unsafe characters after the host... so return true. */ if (path == NULL) return TRUE; for (i = 0; path[i]; i++) { /* Allow '%XX' (where each X is a hex digit) */ if (path[i] == '%') { if (apr_isxdigit(path[i + 1]) && apr_isxdigit(path[i + 2])) { i += 2; continue; } return FALSE; } else if (! uri_char_validity[((unsigned char)path[i])]) { return FALSE; } } return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -