char *str_dup(char *s) { char *ret = NULL; uint32 len = 0; /* buffer */ len = str_len(s) + 1; /* for '\0' */ ret = __builtin_alloca(len); /* copy */ str_move(ret, s, len); return ret; }
void custom_canonicalize_pathname (char *path, CANON_PATH_FLAGS flags) { char *p, *s; char *lpath = path; /* path without leading UNC part */ const size_t url_delim_len = strlen (VFS_PATH_URL_DELIMITER); /* Detect and preserve UNC paths: //server/... */ if ((flags & CANON_PATH_GUARDUNC) != 0 && IS_PATH_SEP (path[0]) && IS_PATH_SEP (path[1])) { p = path + 2; while (p[0] != '\0' && !IS_PATH_SEP (p[0])) p++; if (IS_PATH_SEP (p[0]) && p > path + 2) lpath = p; } if (!lpath[0] || !lpath[1]) return; if (flags & CANON_PATH_JOINSLASHES) { /* Collapse multiple slashes */ p = lpath; while (*p) { if (IS_PATH_SEP (p[0]) && IS_PATH_SEP (p[1]) && (p == lpath || *(p - 1) != ':')) { s = p + 1; while (IS_PATH_SEP (*(++s))) ; str_move (p + 1, s); } p++; } } if (flags & CANON_PATH_JOINSLASHES) { /* Collapse "/./" -> "/" */ p = lpath; while (*p) { if (IS_PATH_SEP (p[0]) && p[1] == '.' && IS_PATH_SEP (p[2])) str_move (p, p + 2); else p++; } } if (flags & CANON_PATH_REMSLASHDOTS) { size_t len; /* Remove trailing slashes */ p = lpath + strlen (lpath) - 1; while (p > lpath && IS_PATH_SEP (*p)) { if (p >= lpath + url_delim_len - 1 && strncmp (p - url_delim_len + 1, VFS_PATH_URL_DELIMITER, url_delim_len) == 0) break; *p-- = 0; } /* Remove leading "./" */ if (lpath[0] == '.' && IS_PATH_SEP (lpath[1])) { if (lpath[2] == 0) { lpath[1] = 0; return; } else { str_move (lpath, lpath + 2); } } /* Remove trailing "/" or "/." */ len = strlen (lpath); if (len < 2) return; if (IS_PATH_SEP (lpath[len - 1]) && (len < url_delim_len || strncmp (lpath + len - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) != 0)) { lpath[len - 1] = '\0'; } else { if (lpath[len - 1] == '.' && IS_PATH_SEP (lpath[len - 2])) { if (len == 2) { lpath[1] = '\0'; return; } else { lpath[len - 2] = '\0'; } } } } if (flags & CANON_PATH_REMDOUBLEDOTS) { #ifdef HAVE_CHARSET const size_t enc_prefix_len = strlen (VFS_ENCODING_PREFIX); #endif /* HAVE_CHARSET */ /* Collapse "/.." with the previous part of path */ p = lpath; while (p[0] && p[1] && p[2]) { if (!IS_PATH_SEP (p[0]) || p[1] != '.' || p[2] != '.' || (!IS_PATH_SEP (p[3]) && p[3] != '\0')) { p++; continue; } /* search for the previous token */ s = p - 1; if (s >= lpath + url_delim_len - 2 && strncmp (s - url_delim_len + 2, VFS_PATH_URL_DELIMITER, url_delim_len) == 0) { s -= (url_delim_len - 2); while (s >= lpath && !IS_PATH_SEP (*s--)) ; } while (s >= lpath) { if (s - url_delim_len > lpath && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0) { char *vfs_prefix = s - url_delim_len; struct vfs_class *vclass; while (vfs_prefix > lpath && !IS_PATH_SEP (*--vfs_prefix)) ; if (IS_PATH_SEP (*vfs_prefix)) vfs_prefix++; *(s - url_delim_len) = '\0'; vclass = vfs_prefix_to_class (vfs_prefix); *(s - url_delim_len) = *VFS_PATH_URL_DELIMITER; if (vclass != NULL) { struct vfs_s_subclass *sub = (struct vfs_s_subclass *) vclass->data; if (sub != NULL && sub->flags & VFS_S_REMOTE) { s = vfs_prefix; continue; } } } if (IS_PATH_SEP (*s)) break; s--; } s++; /* If the previous token is "..", we cannot collapse it */ if (s[0] == '.' && s[1] == '.' && s + 2 == p) { p += 3; continue; } if (p[3] != 0) { if (s == lpath && IS_PATH_SEP (*s)) { /* "/../foo" -> "/foo" */ str_move (s + 1, p + 4); } else { /* "token/../foo" -> "foo" */ #ifdef HAVE_CHARSET if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0) && (is_supported_encoding (s + enc_prefix_len))) /* special case: remove encoding */ str_move (s, p + 1); else #endif /* HAVE_CHARSET */ str_move (s, p + 4); } p = (s > lpath) ? s - 1 : s; continue; } /* trailing ".." */ if (s == lpath) { /* "token/.." -> "." */ if (!IS_PATH_SEP (lpath[0])) lpath[0] = '.'; lpath[1] = '\0'; } else { /* "foo/token/.." -> "foo" */ if (s == lpath + 1) s[0] = '\0'; #ifdef HAVE_CHARSET else if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0) && (is_supported_encoding (s + enc_prefix_len))) { /* special case: remove encoding */ s[0] = '.'; s[1] = '.'; s[2] = '\0'; /* search for the previous token */ /* IS_PATH_SEP (s[-1]) */ p = s - 1; while (p >= lpath && !IS_PATH_SEP (*p)) p--; if (p >= lpath) continue; } #endif /* HAVE_CHARSET */ else { if (s >= lpath + url_delim_len && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0) *s = '\0'; else s[-1] = '\0'; } } break; } } }