static bool is_valid_path(char const* path) { if (is_unc_path(path)) { if (path[2] != '\0' && !isalnum(path[2])) { return false; } } else { char const* colon_pos = strchr(path, ':'); if (colon_pos != NULL) { if (colon_pos != path + 1 || !isalpha(path[0])) { return false; } path += 2; } } return strpbrk(path, "<>:\"|?*") == NULL; }
char* tr_sys_path_dirname(char const* path, tr_error** error) { if (path == NULL || path[0] == '\0') { return tr_strdup("."); } if (!is_valid_path(path)) { set_system_error(error, ERROR_PATH_NOT_FOUND); return NULL; } bool const is_unc = is_unc_path(path); if (is_unc && path[2] == '\0') { return tr_strdup(path); } char const* end = path + strlen(path); while (end > path && is_slash(*(end - 1))) { --end; } if (end == path) { return tr_strdup("/"); } char const* name = end; while (name > path && *(name - 1) != ':' && !is_slash(*(name - 1))) { --name; } while (name > path && is_slash(*(name - 1))) { --name; } if (name == path) { return tr_strdup(is_unc ? "\\\\" : "."); } if (name > path && *(name - 1) == ':' && *name != '\0' && !is_slash(*name)) { return tr_strdup_printf("%c:.", path[0]); } return tr_strndup(path, name - path); }
int is_path_well_formed(const char *path) { #ifndef _WIN32 return strchr(path, '/') != NULL; #else return is_unc_path(path) || (strlen(path) >= 2 && path[1] == ':' && drive_exists(path[0])); #endif }
static wchar_t* path_to_native_path_ex(char const* path, int extra_chars_after, int* real_result_size) { /* Extending maximum path length limit up to ~32K. See "Naming Files, Paths, and Namespaces" (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx) for more info */ wchar_t const local_prefix[] = { '\\', '\\', '?', '\\' }; wchar_t const unc_prefix[] = { '\\', '\\', '?', '\\', 'U', 'N', 'C', '\\' }; bool const is_relative = tr_sys_path_is_relative(path); bool const is_unc = is_unc_path(path); /* `-2` for UNC since we overwrite existing prefix slashes */ int const extra_chars_before = is_relative ? 0 : (is_unc ? TR_N_ELEMENTS(unc_prefix) - 2 : TR_N_ELEMENTS(local_prefix)); /* TODO (?): TR_ASSERT(!is_relative); */ wchar_t* const wide_path = tr_win32_utf8_to_native_ex(path, -1, extra_chars_before, extra_chars_after, real_result_size); if (wide_path == NULL) { return NULL; } /* Relative paths cannot be used with "\\?\" prefixes. This also means that relative paths are limited to ~260 chars... but we should rarely work with relative paths in the first place */ if (!is_relative) { if (is_unc) { /* UNC path: "\\server\share" -> "\\?\UNC\server\share" */ memcpy(wide_path, unc_prefix, sizeof(unc_prefix)); } else { /* Local path: "C:" -> "\\?\C:" */ memcpy(wide_path, local_prefix, sizeof(local_prefix)); } } /* Automatic '/' to '\' conversion is disabled for "\\?\"-prefixed paths */ wchar_t* p = wide_path + extra_chars_before; while ((p = wcschr(p, L'/')) != NULL) { *p++ = L'\\'; } if (real_result_size != NULL) { *real_result_size += extra_chars_before; } return wide_path; }
/* Implementation of :u filename modifier. */ static int apply_u_mod(const char *path, char *buf, size_t buf_len) { if(!is_unc_path(path)) { DWORD size = buf_len - 2; snprintf(buf, buf_len, "//"); GetComputerNameA(buf + 2, &size); return 0; } snprintf(buf, buf_len, "%s", path); break_at(buf + 2, '/'); return 0; }
int is_unc_root(const char *path) { #ifdef _WIN32 if(is_unc_path(path) && path[2] != '\0') { char *p = strchr(path + 2, '/'); if(p == NULL || p[1] == '\0') return 1; } return 0; #else return 0; #endif }
bool tr_sys_path_is_relative (const char * path) { assert (path != NULL); /* UNC path: `\\...`. */ if (is_unc_path (path)) return false; /* Local path: `X:` or `X:\...`. */ if (isalpha (path[0]) && path[1] == ':' && (path[2] == '\0' || is_slash (path[2]))) return false; return true; }
static int open_file(FILE **f) { if(f!=0 && ((*f)==0)){ WCHAR tmp[SR_MAX_PATH]; if(is_unc_path(fname)) _snwprintf(tmp,sizeof(tmp)/sizeof(WCHAR),L"\\\\?\\UNC%s",fname+1); else _snwprintf(tmp,sizeof(tmp)/sizeof(WCHAR),L"\\\\?\\%s",fname); tmp[sizeof(tmp)/sizeof(WCHAR)-1]=0; *f=_wfopen(tmp,L"rb"); if(*f!=0) _fseeki64(*f,last_offset,SEEK_SET); } return f!=0 ? TRUE:FALSE; }
bool tr_sys_path_is_relative(char const* path) { TR_ASSERT(path != NULL); /* UNC path: `\\...`. */ if (is_unc_path(path)) { return false; } /* Local path: `X:` or `X:\...`. */ if (isalpha(path[0]) && path[1] == ':' && (path[2] == '\0' || is_slash(path[2]))) { return false; } return true; }
/* Runs command in a background and redirects its stdout and stderr streams to * file streams which are set. Returns (pid_t)0 or (pid_t)-1 on error. */ static pid_t background_and_capture_internal(char cmd[], int user_sh, FILE **out, FILE **err, int out_pipe[2], int err_pipe[2]) { wchar_t *args[4]; char cwd[PATH_MAX]; int code; wchar_t *final_wide_cmd; wchar_t *wide_sh = NULL; if(_dup2(out_pipe[1], _fileno(stdout)) != 0) return (pid_t)-1; if(_dup2(err_pipe[1], _fileno(stderr)) != 0) return (pid_t)-1; cwd[0] = '\0'; if(get_cwd(cwd, sizeof(cwd)) != NULL) { if(is_unc_path(cwd)) { (void)chdir(get_tmpdir()); } } final_wide_cmd = to_wide(cmd); wide_sh = to_wide(user_sh ? cfg.shell : "cmd"); if(!user_sh || curr_stats.shell_type == ST_CMD) { args[0] = wide_sh; args[1] = L"/C"; args[2] = final_wide_cmd; args[3] = NULL; } else { args[0] = wide_sh; args[1] = L"-c"; args[2] = final_wide_cmd; args[3] = NULL; } code = _wspawnvp(P_NOWAIT, args[0], (const wchar_t **)args); free(wide_sh); free(final_wide_cmd); if(is_unc_path(cwd)) { (void)chdir(cwd); } if(code == 0) { return (pid_t)-1; } if((*out = _fdopen(out_pipe[0], "r")) == NULL) return (pid_t)-1; if((*err = _fdopen(err_pipe[0], "r")) == NULL) { fclose(*out); return (pid_t)-1; } return 0; }
/* * type: CT_* */ void filename_completion(const char *str, CompletionType type) { /* TODO refactor filename_completion(...) function */ DIR * dir; char * dirname; char * filename; char * temp; if(str[0] == '~' && strchr(str, '/') == NULL) { char *const tilde_expanded = expand_tilde(str); vle_compl_add_path_match(tilde_expanded); free(tilde_expanded); return; } dirname = expand_tilde(str); filename = strdup(dirname); temp = cmds_expand_envvars(dirname); free(dirname); dirname = temp; temp = strrchr(dirname, '/'); if(temp != NULL && type != CT_FILE && type != CT_FILE_WOE) { strcpy(filename, ++temp); *temp = '\0'; } else { dirname = realloc(dirname, 2); strcpy(dirname, "."); } #ifdef _WIN32 if(is_unc_root(dirname) || (stroscmp(dirname, ".") == 0 && is_unc_root(curr_view->curr_dir)) || (stroscmp(dirname, "/") == 0 && is_unc_path(curr_view->curr_dir))) { char buf[PATH_MAX]; if(!is_unc_root(dirname)) snprintf(buf, strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 1, "%s", curr_view->curr_dir); else snprintf(buf, sizeof(buf), "%s", dirname); complete_with_shared(buf, filename); free(filename); free(dirname); return; } if(is_unc_path(curr_view->curr_dir)) { char buf[PATH_MAX]; if(is_path_absolute(dirname) && !is_unc_root(curr_view->curr_dir)) snprintf(buf, strchr(curr_view->curr_dir + 2, '/') - curr_view->curr_dir + 2, "%s", curr_view->curr_dir); else snprintf(buf, sizeof(buf), "%s", curr_view->curr_dir); strcat(buf, dirname); chosp(buf); (void)replace_string(&dirname, buf); } #endif dir = opendir(dirname); if(dir == NULL || vifm_chdir(dirname) != 0) { vle_compl_add_path_match(filename); } else { filename_completion_internal(dir, dirname, filename, type); (void)vifm_chdir(curr_view->curr_dir); } free(filename); free(dirname); if(dir != NULL) { closedir(dir); } }