/* * Given a null-terminated pathname pattern @pat that has been read from line * @line_no of the file @path, validate and canonicalize the pattern. * * On success, returns 0. * On failure, returns WIMLIB_ERR_INVALID_CAPTURE_CONFIG. * In either case, @pat may have been modified in-place (and possibly * shortened). */ int mangle_pat(tchar *pat, const tchar *path, unsigned long line_no) { if (!is_any_path_separator(pat[0]) && pat[0] != T('\0') && pat[1] == T(':')) { /* Pattern begins with drive letter. */ if (!is_any_path_separator(pat[2])) { /* Something like c:file, which is actually a path * relative to the current working directory on the c: * drive. We require paths with drive letters to be * absolute. */ ERROR("%"TS":%lu: Invalid pattern \"%"TS"\":\n" " Patterns including drive letters must be absolute!\n" " Maybe try \"%"TC":%"TC"%"TS"\"?\n", path, line_no, pat, pat[0], OS_PREFERRED_PATH_SEPARATOR, &pat[2]); return WIMLIB_ERR_INVALID_CAPTURE_CONFIG; } WARNING("%"TS":%lu: Pattern \"%"TS"\" starts with a drive " "letter, which is being removed.", path, line_no, pat); /* Strip the drive letter. */ tmemmove(pat, pat + 2, tstrlen(pat + 2) + 1); } /* Collapse consecutive path separators, and translate both / and \ into * / (UNIX) or \ (Windows). * * Note: we expect that this function produces patterns that can be used * for both filesystem paths and WIM paths, so the desired path * separators must be the same. */ BUILD_BUG_ON(OS_PREFERRED_PATH_SEPARATOR != WIM_PATH_SEPARATOR); do_canonicalize_path(pat, pat); /* Relative patterns can only match file names, so they must be * single-component only. */ if (pat[0] != OS_PREFERRED_PATH_SEPARATOR && tstrchr(pat, OS_PREFERRED_PATH_SEPARATOR)) { ERROR("%"TS":%lu: Invalid pattern \"%"TS"\":\n" " Relative patterns can only include one path component!\n" " Maybe try \"%"TC"%"TS"\"?", path, line_no, pat, OS_PREFERRED_PATH_SEPARATOR, pat); return WIMLIB_ERR_INVALID_CAPTURE_CONFIG; } return 0; }
/* * canonicalize_wim_path() - Given a user-provided path to a file within a WIM * image, translate it into a "canonical" path. * * - Translate both types of slash into a consistent type (WIM_PATH_SEPARATOR). * - Collapse path separators. * - Add leading slash if missing. * - Strip trailing slashes. * * Examples (with WIM_PATH_SEPARATOR == '/'): * * => / [ either NULL or empty string ] * / => / * \ => / * hello => /hello * \hello => /hello * \hello => /hello * /hello/ => /hello * \hello/ => /hello * /hello//1 => /hello/1 * \\hello\\1\\ => /hello/1 */ tchar * canonicalize_wim_path(const tchar *wim_path) { const tchar *in; tchar *out; tchar *result; in = wim_path; if (!in) in = T(""); result = MALLOC((1 + tstrlen(in) + 1) * sizeof(result[0])); if (!result) return NULL; out = result; /* Add leading slash if missing */ if (!is_any_path_separator(*in)) *out++ = WIM_PATH_SEPARATOR; do_canonicalize_path(in, out); return result; }
/* Collapse and translate path separators, and strip trailing slashes. Doesn't * add or delete a leading slash. * * @in may alias @out. */ void do_canonicalize_path(const tchar *in, tchar *out) { tchar *orig_out = out; while (*in) { if (is_any_path_separator(*in)) { /* Collapse multiple path separators into one */ *out++ = WIM_PATH_SEPARATOR; do { in++; } while (is_any_path_separator(*in)); } else { /* Copy non-path-separator character */ *out++ = *in++; } } /* Remove trailing slash if existent */ if (out - orig_out > 1 && *(out - 1) == WIM_PATH_SEPARATOR) --out; *out = T('\0'); }