/* Copies file/directory overwriting destination files if requested. Returns * non-zero on error, otherwise zero is returned. */ static int op_cp(void *data, const char src[], const char dst[], int overwrite) { #ifndef _WIN32 char *escaped_src, *escaped_dst; char cmd[6 + PATH_MAX*2 + 1]; int result; escaped_src = escape_filename(src, 0); escaped_dst = escape_filename(dst, 0); if(escaped_src == NULL || escaped_dst == NULL) { free(escaped_dst); free(escaped_src); return -1; } snprintf(cmd, sizeof(cmd), "cp %s -R " PRESERVE_FLAGS " %s %s", overwrite ? "" : NO_CLOBBER, escaped_src, escaped_dst); LOG_INFO_MSG("Running cp command: \"%s\"", cmd); result = background_and_wait_for_errors(cmd); free(escaped_dst); free(escaped_src); return result; #else int ret; if(is_dir(src)) { char cmd[6 + PATH_MAX*2 + 1]; snprintf(cmd, sizeof(cmd), "xcopy \"%s\" \"%s\" ", src, dst); to_back_slash(cmd); if(is_vista_and_above()) strcat(cmd, "/B "); if(overwrite) { strcat(cmd, "/Y "); } strcat(cmd, "/E /I /H /R > NUL"); ret = system(cmd); } else { ret = (CopyFileA(src, dst, 0) == 0); } return ret; #endif }
/* Moves file/directory overwriting destination files if requested. Returns * non-zero on error, otherwise zero is returned. */ static int op_mv(void *data, const char src[], const char dst[], int overwrite) { #ifndef _WIN32 struct stat st; char *escaped_src, *escaped_dst; char cmd[6 + PATH_MAX*2 + 1]; int result; if(lstat(dst, &st) == 0) return -1; escaped_src = escape_filename(src, 0); escaped_dst = escape_filename(dst, 0); if(escaped_src == NULL || escaped_dst == NULL) { free(escaped_dst); free(escaped_src); return -1; } snprintf(cmd, sizeof(cmd), "mv %s %s %s", overwrite ? "" : NO_CLOBBER, escaped_src, escaped_dst); free(escaped_dst); free(escaped_src); LOG_INFO_MSG("Running mv command: \"%s\"", cmd); if((result = background_and_wait_for_errors(cmd)) != 0) return result; if(path_starts_with(dst, cfg.trash_dir)) add_to_trash(src, strrchr(dst, '/') + 1); else if(path_starts_with(src, cfg.trash_dir)) remove_from_trash(strrchr(src, '/') + 1); return 0; #else BOOL ret = MoveFile(src, dst); if(!ret && GetLastError() == 5) { int r = op_cp(data, src, dst, overwrite); if(r != 0) return r; return op_removesl(data, src, NULL); } return ret == 0; #endif }
char * expand_envvars(const char str[], int escape_vals) { char *result = NULL; size_t len = 0; int prev_slash = 0; while(*str != '\0') { if(!prev_slash && *str == '$' && isalpha(str[1])) { char var_name[NAME_MAX]; const char *p = str + 1; char *q = var_name; const char *var_value; while((isalnum(*p) || *p == '_') && q - var_name < sizeof(var_name) - 1) *q++ = *p++; *q = '\0'; var_value = env_get(var_name); if(var_value != NULL) { char *escaped_var_value = NULL; if(escape_vals) { escaped_var_value = escape_filename(var_value, 1); var_value = escaped_var_value; } result = extend_string(result, var_value, &len); free(escaped_var_value); str = p; } else { str++; } } else { prev_slash = (*str == '\\') ? !prev_slash : 0; if(!prev_slash || escape_vals) { const char single_char[] = { *str, '\0' }; result = extend_string(result, single_char, &len); } str++; } } if(result == NULL) result = strdup(""); return result; }
static int op_symlink(void *data, const char *src, const char *dst) { char *escaped_src, *escaped_dst; char cmd[6 + PATH_MAX*2 + 1]; int result; #ifdef _WIN32 char buf[PATH_MAX + 2]; #endif escaped_src = escape_filename(src, 0); escaped_dst = escape_filename(dst, 0); if(escaped_src == NULL || escaped_dst == NULL) { free(escaped_dst); free(escaped_src); return -1; } #ifndef _WIN32 snprintf(cmd, sizeof(cmd), "ln -s %s %s", escaped_src, escaped_dst); LOG_INFO_MSG("Running ln command: \"%s\"", cmd); result = background_and_wait_for_errors(cmd); #else if(GetModuleFileNameA(NULL, buf, ARRAY_LEN(buf)) == 0) { free(escaped_dst); free(escaped_src); return -1; } *strrchr(buf, '\\') = '\0'; snprintf(cmd, sizeof(cmd), "%s\\win_helper -s %s %s", buf, escaped_src, escaped_dst); result = system(cmd); #endif free(escaped_dst); free(escaped_src); return result; }
static int op_chmodr(void *data, const char *src, const char *dst) { char cmd[128 + PATH_MAX]; char *escaped; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "chmod -R %s %s", (char *)data, escaped); free(escaped); start_background_job(cmd, 0); return 0; }
static int op_removesl(void *data, const char *src, const char *dst) { #ifndef _WIN32 char *escaped; char cmd[16 + PATH_MAX]; int result; escaped = escape_filename(src, 0); if(escaped == NULL) return -1; snprintf(cmd, sizeof(cmd), "rm -rf %s", escaped); LOG_INFO_MSG("Running rm command: \"%s\"", cmd); result = background_and_wait_for_errors(cmd); free(escaped); return result; #else if(is_dir(src)) { char buf[PATH_MAX]; int err; int i; snprintf(buf, sizeof(buf), "%s%c", src, '\0'); for(i = 0; buf[i] != '\0'; i++) if(buf[i] == '/') buf[i] = '\\'; SHFILEOPSTRUCTA fo = { .hwnd = NULL, .wFunc = FO_DELETE, .pFrom = buf, .pTo = NULL, .fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI, }; err = SHFileOperation(&fo); log_msg("Error: %d", err); return err; } else { int ok; DWORD attributes = GetFileAttributesA(src); if(attributes & FILE_ATTRIBUTE_READONLY) SetFileAttributesA(src, attributes & ~FILE_ATTRIBUTE_READONLY); ok = DeleteFile(src); if(!ok) LOG_WERROR(GetLastError()); return !ok; } #endif }
static int op_chmod(void *data, const char *src, const char *dst) { char cmd[128 + PATH_MAX]; char *escaped; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "chmod %s %s", (char *)data, escaped); free(escaped); LOG_INFO_MSG("Running chmod command: \"%s\"", cmd); return background_and_wait_for_errors(cmd); }
static int op_rmdir(void *data, const char *src, const char *dst) { #ifndef _WIN32 char cmd[128 + PATH_MAX]; char *escaped; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "rmdir %s", escaped); free(escaped); LOG_INFO_MSG("Running rmdir command: \"%s\"", cmd); return background_and_wait_for_errors(cmd); #else return RemoveDirectory(src) == 0; #endif }
static int op_mkdir(void *data, const char *src, const char *dst) { #ifndef _WIN32 char cmd[128 + PATH_MAX]; char *escaped; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "mkdir %s %s", (data == NULL) ? "" : "-p", escaped); free(escaped); LOG_INFO_MSG("Running mkdir command: \"%s\"", cmd); return background_and_wait_for_errors(cmd); #else if(data == NULL) { return CreateDirectory(src, NULL) == 0; } else { char *p; char t; p = strchr(src + 2, '/'); do { t = *p; *p = '\0'; if(!is_dir(src)) { if(!CreateDirectory(src, NULL)) { *p = t; return -1; } } *p = t; if((p = strchr(p + 1, '/')) == NULL) p = (char *)src + strlen(src); } while(t != '\0'); return 0; } #endif }
static void complete_with_shared(const char *server, const char *file) { NET_API_STATUS res; size_t len = strlen(file); do { PSHARE_INFO_502 buf_ptr; DWORD er = 0, tr = 0, resume = 0; wchar_t *wserver = to_wide(server + 2); if(wserver == NULL) { show_error_msg("Memory Error", "Unable to allocate enough memory"); return; } res = NetShareEnum(wserver, 502, (LPBYTE *)&buf_ptr, -1, &er, &tr, &resume); free(wserver); if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA) { PSHARE_INFO_502 p; DWORD i; p = buf_ptr; for(i = 1; i <= er; i++) { char buf[512]; WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)p->shi502_netname, -1, buf, sizeof(buf), NULL, NULL); strcat(buf, "/"); if(strnoscmp(buf, file, len) == 0) { char *const escaped = escape_filename(buf, 1); vle_compl_add_match(escaped); free(escaped); } p++; } NetApiBufferFree(buf_ptr); } } while(res == ERROR_MORE_DATA); }
static int op_chgrp(void *data, const char *src, const char *dst) { #ifndef _WIN32 char cmd[10 + 32 + PATH_MAX]; char *escaped; gid_t gid = (gid_t)(long)data; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "chown -fR :%u %s", gid, escaped); free(escaped); LOG_INFO_MSG("Running chgrp command: \"%s\"", cmd); return background_and_wait_for_errors(cmd); #else return -1; #endif }
void fuse_unmount_all(void) { fuse_mount_t *runner; if(fuse_mounts == NULL) { return; } if(vifm_chdir("/") != 0) { return; } runner = fuse_mounts; while(runner != NULL) { char buf[14 + PATH_MAX + 1]; char *escaped_filename; escaped_filename = escape_filename(runner->mount_point, 0); snprintf(buf, sizeof(buf), "%s %s", curr_stats.fuse_umount_cmd, escaped_filename); free(escaped_filename); (void)vifm_system(buf); if(path_exists(runner->mount_point, DEREF)) { rmdir(runner->mount_point); } runner = runner->next; } leave_invalid_dir(&lwin); leave_invalid_dir(&rwin); }
static int op_mkfile(void *data, const char *src, const char *dst) { #ifndef _WIN32 char cmd[128 + PATH_MAX]; char *escaped; escaped = escape_filename(src, 0); snprintf(cmd, sizeof(cmd), "touch %s", escaped); free(escaped); LOG_INFO_MSG("Running touch command: \"%s\"", cmd); return background_and_wait_for_errors(cmd); #else HANDLE hfile; hfile = CreateFileA(src, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if(hfile == INVALID_HANDLE_VALUE) return -1; CloseHandle(hfile); return 0; #endif }
/* Returns a pointer to newly allocated memory, which should be released by the * caller. */ static char * get_viewer_command(const char viewer[]) { char *result; if(strchr(viewer, '%') == NULL) { char *escaped; FileView *view = curr_stats.preview_hint; if(view == NULL) { view = curr_view; } escaped = escape_filename(get_current_file_name(view), 0); result = format_str("%s %s", viewer, escaped); free(escaped); } else { result = expand_macros(viewer, NULL, NULL, 1); } return result; }
/* Appends the path to the expanded string with either proper escaping or * quoting. Returns NULL on not enough memory error. */ static char * append_path_to_expanded(char expanded[], int quotes, const char path[]) { if(quotes) { const char *const dquoted = enclose_in_dquotes(path); expanded = append_to_expanded(expanded, dquoted); } else { char *const escaped = escape_filename(path, 0); if(escaped == NULL) { show_error_msg("Memory Error", "Unable to allocate enough memory"); free(expanded); return NULL; } expanded = append_to_expanded(expanded, escaped); free(escaped); } return expanded; }
int fuse_try_unmount(FileView *view) { char buf[14 + PATH_MAX + 1]; fuse_mount_t *runner, *trailer; int status; fuse_mount_t *sniffer; char *escaped_mount_point; runner = fuse_mounts; trailer = NULL; while(runner) { if(paths_are_equal(runner->mount_point, view->curr_dir)) { break; } trailer = runner; runner = runner->next; } if(runner == NULL) { return 0; } /* we are exiting a top level dir */ escaped_mount_point = escape_filename(runner->mount_point, 0); snprintf(buf, sizeof(buf), "%s %s 2> /dev/null", curr_stats.fuse_umount_cmd, escaped_mount_point); LOG_INFO_MSG("FUSE unmount command: `%s`", buf); free(escaped_mount_point); /* Have to chdir to parent temporarily, so that this DIR can be unmounted. */ if(vifm_chdir(cfg.fuse_home) != 0) { show_error_msg("FUSE UMOUNT ERROR", "Can't chdir to FUSE home"); return -1; } status_bar_message("FUSE unmounting selected file, please stand by.."); status = background_and_wait_for_status(buf, 0, NULL); clean_status_bar(); /* check child status */ if(!WIFEXITED(status) || WEXITSTATUS(status)) { werase(status_bar); show_error_msgf("FUSE UMOUNT ERROR", "Can't unmount %s. It may be busy.", runner->source_file_name); (void)vifm_chdir(flist_get_dir(view)); return -1; } /* remove the directory we created for the mount */ if(path_exists(runner->mount_point, DEREF)) rmdir(runner->mount_point); /* remove mount point from fuse_mount_t */ sniffer = runner->next; if(trailer) trailer->next = sniffer ? sniffer : NULL; else fuse_mounts = sniffer; updir_from_mount(view, runner); free(runner); return 1; }
/* Builds the mount command based on the file type program. * Accepted formats are: * FUSE_MOUNT|some_mount_command %SOURCE_FILE %DESTINATION_DIR [%FOREGROUND] * and * FUSE_MOUNT2|some_mount_command %PARAM %DESTINATION_DIR [%FOREGROUND] * %CLEAR is an obsolete name of %FOREGROUND. * Always sets value of *foreground. */ TSTATIC void format_mount_command(const char mount_point[], const char file_name[], const char param[], const char format[], size_t buf_size, char buf[], int *foreground) { char *buf_pos; const char *prog_pos; char *escaped_path; char *escaped_mount_point; *foreground = 0; escaped_path = escape_filename(file_name, 0); escaped_mount_point = escape_filename(mount_point, 0); buf_pos = buf; buf_pos[0] = '\0'; prog_pos = after_first(format, '|'); while(*prog_pos != '\0') { if(*prog_pos == '%') { char cmd_buf[96]; char *cmd_pos; cmd_pos = cmd_buf; while(*prog_pos != '\0' && *prog_pos != ' ') { *cmd_pos = *prog_pos; if(cmd_pos - cmd_buf < sizeof(cmd_buf)) cmd_pos++; prog_pos++; } *cmd_pos = '\0'; if(!strcmp(cmd_buf, "%SOURCE_FILE")) { copy_str(buf_pos, buf_size - (buf_pos - buf), escaped_path); buf_pos += strlen(buf_pos); } else if(!strcmp(cmd_buf, "%PARAM")) { copy_str(buf_pos, buf_size - (buf_pos - buf), param); buf_pos += strlen(buf_pos); } else if(!strcmp(cmd_buf, "%DESTINATION_DIR")) { copy_str(buf_pos, buf_size - (buf_pos - buf), escaped_mount_point); buf_pos += strlen(buf_pos); } else if(!strcmp(cmd_buf, "%FOREGROUND") || !strcmp(cmd_buf, "%CLEAR")) { *foreground = 1; } } else { *buf_pos = *prog_pos; if(buf_pos - buf < buf_size - 1) buf_pos++; prog_pos++; } } *buf_pos = '\0'; free(escaped_mount_point); free(escaped_path); }
/* mount_point should be an array of at least PATH_MAX characters * Returns non-zero on error. */ static int fuse_mount(FileView *view, char file_full_path[], const char param[], const char program[], char mount_point[]) { /* TODO: refactor this function fuse_mount(). */ int mount_point_id; char buf[2*PATH_MAX]; char *escaped_filename; int foreground; char errors_file[PATH_MAX]; int status; int cancelled; escaped_filename = escape_filename(get_current_file_name(view), 0); mount_point_id = get_last_mount_point_id(fuse_mounts); do { snprintf(mount_point, PATH_MAX, "%s/%03d_%s", cfg.fuse_home, ++mount_point_id, get_current_file_name(view)); } while(path_exists(mount_point, DEREF)); if(os_mkdir(mount_point, S_IRWXU) != 0) { free(escaped_filename); show_error_msg("Unable to create FUSE mount directory", mount_point); return -1; } free(escaped_filename); /* Just before running the mount, I need to chdir out temporarily from any FUSE mounted paths, Otherwise the fuse-zip command fails with "fusermount: failed to open current directory: permission denied" (this happens when mounting JARs from mounted JARs) */ if(vifm_chdir(cfg.fuse_home) != 0) { show_error_msg("FUSE MOUNT ERROR", "Can't chdir() to FUSE home"); return -1; } format_mount_command(mount_point, file_full_path, param, program, sizeof(buf), buf, &foreground); status_bar_message("FUSE mounting selected file, please stand by.."); if(foreground) { def_prog_mode(); endwin(); } generate_tmp_file_name("vifm.errors", errors_file, sizeof(errors_file)); strcat(buf, " 2> "); strcat(buf, errors_file); LOG_INFO_MSG("FUSE mount command: `%s`", buf); status = background_and_wait_for_status(buf, !foreground, &cancelled); clean_status_bar(); /* Check child process exit status. */ if(!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) { FILE *ef; if(!WIFEXITED(status)) { LOG_ERROR_MSG("FUSE mounter didn't exit!"); } else { LOG_ERROR_MSG("FUSE mount command exit status: %d", WEXITSTATUS(status)); } ef = os_fopen(errors_file, "r"); if(ef == NULL) { LOG_SERROR_MSG(errno, "Failed to open temporary stderr file: %s", errors_file); } show_errors_from_file(ef, "FUSE mounter error"); werase(status_bar); if(cancelled) { status_bar_message("FUSE mount cancelled"); curr_stats.save_msg = 1; } else { show_error_msg("FUSE MOUNT ERROR", file_full_path); } if(unlink(errors_file) != 0) { LOG_SERROR_MSG(errno, "Error file deletion failure: %d", errors_file); } /* Remove the directory we created for the mount. */ (void)rmdir(mount_point); (void)vifm_chdir(flist_get_dir(view)); return -1; } unlink(errors_file); status_bar_message("FUSE mount success"); register_mount(&fuse_mounts, file_full_path, mount_point, mount_point_id); return 0; }
/* * mount_point should be an array of at least PATH_MAX characters * Returns non-zero on error. */ static int fuse_mount(FileView *view, char *file_full_path, const char *param, const char *program, char *mount_point) { /* TODO: refactor this function fuse_mount() */ fuse_mount_t *runner = NULL; int mount_point_id = 0; fuse_mount_t *fuse_item = NULL; char buf[2*PATH_MAX]; char *escaped_filename; int clear_before_mount = 0; char errors_file[PATH_MAX]; int status; escaped_filename = escape_filename(get_current_file_name(view), 0); /* get mount_point_id + mount_point and set runner pointing to the list's * tail */ if(fuse_mounts != NULL) { runner = fuse_mounts; while(runner->next != NULL) runner = runner->next; mount_point_id = runner->mount_point_id; } do { snprintf(mount_point, PATH_MAX, "%s/%03d_%s", cfg.fuse_home, ++mount_point_id, get_current_file_name(view)); } while(path_exists(mount_point)); if(make_dir(mount_point, S_IRWXU) != 0) { free(escaped_filename); show_error_msg("Unable to create FUSE mount directory", mount_point); return -1; } free(escaped_filename); /* Just before running the mount, I need to chdir out temporarily from any FUSE mounted paths, Otherwise the fuse-zip command fails with "fusermount: failed to open current directory: permission denied" (this happens when mounting JARs from mounted JARs) */ if(vifm_chdir(cfg.fuse_home) != 0) { show_error_msg("FUSE MOUNT ERROR", "Can't chdir() to FUSE home"); return -1; } clear_before_mount = format_mount_command(mount_point, file_full_path, param, program, sizeof(buf), buf); status_bar_message("FUSE mounting selected file, please stand by.."); if(clear_before_mount) { def_prog_mode(); endwin(); } generate_tmp_file_name("vifm.errors", errors_file, sizeof(errors_file)); strcat(buf, " 2> "); strcat(buf, errors_file); LOG_INFO_MSG("FUSE mount command: `%s`", buf); status = background_and_wait_for_status(buf); clean_status_bar(); /* check child status */ if(!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) { FILE *ef = fopen(errors_file, "r"); print_errors(ef); unlink(errors_file); werase(status_bar); /* remove the directory we created for the mount */ if(path_exists(mount_point)) rmdir(mount_point); show_error_msg("FUSE MOUNT ERROR", file_full_path); (void)vifm_chdir(view->curr_dir); return -1; } unlink(errors_file); status_bar_message("FUSE mount success"); fuse_item = malloc(sizeof(*fuse_item)); copy_str(fuse_item->source_file_name, sizeof(fuse_item->source_file_name), file_full_path); strcpy(fuse_item->source_file_dir, view->curr_dir); canonicalize_path(mount_point, fuse_item->mount_point, sizeof(fuse_item->mount_point)); fuse_item->mount_point_id = mount_point_id; fuse_item->next = NULL; if(fuse_mounts == NULL) fuse_mounts = fuse_item; else runner->next = fuse_item; return 0; }
List *list_available_extensions_in_archive_dir(Platform platform) { List *result = NIL; DIR *dir; struct dirent *de; char *pf_name = escape_filename(platform->os_name); char *pf_version = escape_filename(platform->os_version); char *pf_arch = escape_filename(platform->arch); dir = AllocateDir(pginstall_archive_dir); while ((de = ReadDir(dir, pginstall_archive_dir)) != NULL) { pginstall_extension *ext; char *extname = NULL; char *pgversion = NULL; char *os = NULL ; char *version = NULL; char *arch = NULL; char *ptr = NULL; /* must be a .tar.gz file ... */ if (!is_extension_archive_filename(de->d_name)) continue; /* extract extension name from filename */ extname = pstrdup(de->d_name); if ((ptr = strstr(extname, "--")) != NULL) { *ptr = '\0'; pgversion = ptr+2; } /* parse and check pgversion */ if (pgversion && (ptr = strstr(pgversion, "--")) != NULL) { *ptr = '\0'; os = ptr+2; if (strcmp(pgversion, PG_VERSION) != 0) continue; } /* parse and check os name */ if (os && (ptr = strstr(os, "--")) != NULL) { *ptr = '\0'; version = ptr+2; if (strcmp(os, pf_name) != 0) continue; } /* parse and check os version */ if (version && (ptr = strstr(version, "--")) != NULL) { *ptr = '\0'; arch = ptr+2; if (strcmp(version, pf_version) != 0) continue; } /* parse and check arc */ if (arch && (ptr = strstr(arch, ".")) != NULL) { *ptr = '\0'; if (strcmp(arch, pf_arch) != 0) continue; } ext = (pginstall_extension *)palloc(sizeof(pginstall_extension)); ext->id = -1; ext->shortname = pstrdup(extname); ext->fullname = NULL; ext->uri = pstrdup(de->d_name); ext->description = NULL; result = lappend(result, ext); } FreeDir(dir); return result; }
/* * At CREATE EXTENSION time we check if the extension is already available, * which is driven by the presence of its control file on disk. * * If the extension is not already available, we ask the repository server for * it, and unpack received binary archive to the right place. * * TODO: actually talk to the repository server. Current prototype version * directly uses the local archive cache. */ void download_and_unpack_archive(const char *extname) { PlatformData platform; char *control_filename = get_extension_control_filename(extname); char *archive_filename; /* * No cache, download again each time asked: any existing control file for * the extension could be one we left behind from a previous version of the * extension's archive. * * This also means that if an extension is already provided by the * operating system, by installing pginstall you give preference to * pginstall builds. */ current_platform(&platform); archive_filename = psprintf("%s/%s--%s--%s--%s--%s.tar.gz", pginstall_archive_dir, extname, PG_VERSION, escape_filename(platform.os_name), escape_filename(platform.os_version), escape_filename(platform.arch)); /* * The local repository might be added to directly by the pginstall build * client, and pginstall.serve_from_archive_dir allows to setup the * pginstall.archive_dir as a local authoritative source. * * Given that, we only download an archive file when * * 1. we have a pginstall.repository * 2. pginstall.serve_from_archive_dir is false * 3. pginstall.serve_from_archive_dir is true but we don't have the * needed file locally */ if (pginstall_repository != NULL && strcmp(pginstall_repository, "") != 0) { if (pginstall_serve_from_archive_dir && access(archive_filename, R_OK) == 0) { /* no download here. */ (void)0; } else { download_archive(archive_filename, extname, &platform); } } /* * Even if we didn't find any extension's archive file for our platform on * the repository server, it could be that the extension is available * locally either through the OS packages or maybe a local developer setup * (make install). * * In case when when extension control file still doesn't exists after * we've been communicating with the repository server, PostgreSQL will * issue its usual error message about a missing control file. */ if (access(archive_filename, R_OK) == 0) { extract(extname, archive_filename); /* now rewrite the control file to "relocate" the extension */ rewrite_control_file(extname, control_filename); } return; }
/* * Restore files */ bool restore_cmd(UAContext *ua, const char *cmd) { RESTORE_CTX rx; /* restore context */ POOL_MEM buf; JOBRES *job; int i; JCR *jcr = ua->jcr; char *escaped_bsr_name = NULL; char *escaped_where_name = NULL; char *strip_prefix, *add_prefix, *add_suffix, *regexp; strip_prefix = add_prefix = add_suffix = regexp = NULL; memset(&rx, 0, sizeof(rx)); rx.path = get_pool_memory(PM_FNAME); rx.fname = get_pool_memory(PM_FNAME); rx.JobIds = get_pool_memory(PM_FNAME); rx.JobIds[0] = 0; rx.BaseJobIds = get_pool_memory(PM_FNAME); rx.query = get_pool_memory(PM_FNAME); rx.bsr = new_bsr(); i = find_arg_with_value(ua, "comment"); if (i >= 0) { rx.comment = ua->argv[i]; if (!is_comment_legal(ua, rx.comment)) { goto bail_out; } } i = find_arg_with_value(ua, "backupformat"); if (i >= 0) { rx.backup_format = ua->argv[i]; } i = find_arg_with_value(ua, "where"); if (i >= 0) { rx.where = ua->argv[i]; } i = find_arg_with_value(ua, "replace"); if (i >= 0) { rx.replace = ua->argv[i]; } i = find_arg_with_value(ua, "pluginoptions"); if (i >= 0) { rx.plugin_options = ua->argv[i]; } i = find_arg_with_value(ua, "strip_prefix"); if (i >= 0) { strip_prefix = ua->argv[i]; } i = find_arg_with_value(ua, "add_prefix"); if (i >= 0) { add_prefix = ua->argv[i]; } i = find_arg_with_value(ua, "add_suffix"); if (i >= 0) { add_suffix = ua->argv[i]; } i = find_arg_with_value(ua, "regexwhere"); if (i >= 0) { rx.RegexWhere = ua->argv[i]; } if (strip_prefix || add_suffix || add_prefix) { int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); regexp = (char *)bmalloc(len * sizeof(char)); bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); rx.RegexWhere = regexp; } /* TODO: add acl for regexwhere ? */ if (rx.RegexWhere) { if (!acl_access_ok(ua, Where_ACL, rx.RegexWhere, true)) { ua->error_msg(_("\"RegexWhere\" specification not authorized.\n")); goto bail_out; } } if (rx.where) { if (!acl_access_ok(ua, Where_ACL, rx.where, true)) { ua->error_msg(_("\"where\" specification not authorized.\n")); goto bail_out; } } if (!open_client_db(ua, true)) { goto bail_out; } /* Ensure there is at least one Restore Job */ LockRes(); foreach_res(job, R_JOB) { if (job->JobType == JT_RESTORE) { if (!rx.restore_job) { rx.restore_job = job; } rx.restore_jobs++; } } UnlockRes(); if (!rx.restore_jobs) { ua->error_msg(_( "No Restore Job Resource found in bareos-dir.conf.\n" "You must create at least one before running this command.\n")); goto bail_out; } /* * Request user to select JobIds or files by various different methods * last 20 jobs, where File saved, most recent backup, ... * In the end, a list of files are pumped into * add_findex() */ switch (user_select_jobids_or_files(ua, &rx)) { case 0: /* error */ goto bail_out; case 1: /* selected by jobid */ get_and_display_basejobs(ua, &rx); if (!build_directory_tree(ua, &rx)) { ua->send_msg(_("Restore not done.\n")); goto bail_out; } break; case 2: /* selected by filename, no tree needed */ break; } if (rx.bsr->JobId) { char ed1[50]; if (!complete_bsr(ua, rx.bsr)) { /* find Vol, SessId, SessTime from JobIds */ ua->error_msg(_("Unable to construct a valid BSR. Cannot continue.\n")); goto bail_out; } if (!(rx.selected_files = write_bsr_file(ua, rx))) { ua->warning_msg(_("No files selected to be restored.\n")); goto bail_out; } display_bsr_info(ua, rx); /* display vols needed, etc */ if (rx.selected_files==1) { ua->info_msg(_("\n1 file selected to be restored.\n\n")); } else { ua->info_msg(_("\n%s files selected to be restored.\n\n"), edit_uint64_with_commas(rx.selected_files, ed1)); } } else { ua->warning_msg(_("No files selected to be restored.\n")); goto bail_out; } if (rx.restore_jobs == 1) { job = rx.restore_job; } else { job = get_restore_job(ua); } if (!job) { goto bail_out; } if (!get_client_name(ua, &rx)) { goto bail_out; } if (!rx.ClientName) { ua->error_msg(_("No Client resource found!\n")); goto bail_out; } if (!get_restore_client_name(ua, rx)) { goto bail_out; } escaped_bsr_name = escape_filename(jcr->RestoreBootstrap); Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" " bootstrap=\"%s\" files=%u catalog=\"%s\"", job->name(), rx.ClientName, rx.RestoreClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, rx.selected_files, ua->catalog->name()); /* * Build run command */ if (rx.backup_format) { Mmsg(buf, " backupformat=%s", rx.backup_format); pm_strcat(ua->cmd, buf); } pm_strcpy(buf, ""); if (rx.RegexWhere) { escaped_where_name = escape_filename(rx.RegexWhere); Mmsg(buf, " regexwhere=\"%s\"", escaped_where_name ? escaped_where_name : rx.RegexWhere); } else if (rx.where) { escaped_where_name = escape_filename(rx.where); Mmsg(buf," where=\"%s\"", escaped_where_name ? escaped_where_name : rx.where); } pm_strcat(ua->cmd, buf); if (rx.replace) { Mmsg(buf, " replace=%s", rx.replace); pm_strcat(ua->cmd, buf); } if (rx.plugin_options) { Mmsg(buf, " pluginoptions=%s", rx.plugin_options); pm_strcat(ua->cmd, buf); } if (rx.comment) { Mmsg(buf, " comment=\"%s\"", rx.comment); pm_strcat(ua->cmd, buf); } if (escaped_bsr_name != NULL) { bfree(escaped_bsr_name); } if (escaped_where_name != NULL) { bfree(escaped_where_name); } if (regexp) { bfree(regexp); } if (find_arg(ua, NT_("yes")) > 0) { pm_strcat(ua->cmd, " yes"); /* pass it on to the run command */ } Dmsg1(200, "Submitting: %s\n", ua->cmd); /* * Transfer jobids to jcr to for picking up restore objects */ jcr->JobIds = rx.JobIds; rx.JobIds = NULL; parse_ua_args(ua); run_cmd(ua, ua->cmd); free_rx(&rx); garbage_collect_memory(); /* release unused memory */ return true; bail_out: if (escaped_bsr_name != NULL) { bfree(escaped_bsr_name); } if (escaped_where_name != NULL) { bfree(escaped_where_name); } if (regexp) { bfree(regexp); } free_rx(&rx); garbage_collect_memory(); /* release unused memory */ return false; }
/* * Complete the word at or before point, * 'what_to_do' says what to do with the completion. * \t means do standard completion. * `?' means list the possible completions. * `*' means insert all of the possible completions. * `!' means to do standard completion, and list all possible completions if * there is more than one. * * Note: '*' support is not implemented * '!' could never be invoked */ int fn_complete(EditLine *el, char *(*complet_func)(const char *, int), char **(*attempted_completion_function)(const char *, int, int), const wchar_t *word_break, const wchar_t *special_prefixes, const char *(*app_func)(const char *), size_t query_items, int *completion_type, int *over, int *point, int *end) { const LineInfoW *li; wchar_t *temp; char **matches; size_t len; int what_to_do = '\t'; int retval = CC_NORM; if (el->el_state.lastcmd == el->el_state.thiscmd) what_to_do = '?'; /* readline's rl_complete() has to be told what we did... */ if (completion_type != NULL) *completion_type = what_to_do; if (!complet_func) complet_func = fn_filename_completion_function; if (!app_func) app_func = append_char_function; li = el_wline(el); temp = find_word_to_complete(li->cursor, li->buffer, word_break, special_prefixes, &len); if (temp == NULL) goto out; /* these can be used by function called in completion_matches() */ /* or (*attempted_completion_function)() */ if (point != NULL) *point = (int)(li->cursor - li->buffer); if (end != NULL) *end = (int)(li->lastchar - li->buffer); if (attempted_completion_function) { int cur_off = (int)(li->cursor - li->buffer); matches = (*attempted_completion_function)( ct_encode_string(temp, &el->el_scratch), cur_off - (int)len, cur_off); } else matches = NULL; if (!attempted_completion_function || (over != NULL && !*over && !matches)) matches = completion_matches( ct_encode_string(temp, &el->el_scratch), complet_func); if (over != NULL) *over = 0; if (matches) { int i; size_t matches_num, maxlen, match_len, match_display=1; int single_match = matches[2] == NULL && (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0); retval = CC_REFRESH; if (matches[0][0] != '\0') { el_deletestr(el, (int) len); if (single_match) { /* * We found exact match. Add a space after * it, unless we do filename completion and the * object is a directory. Also do necessary escape quoting */ char *escaped_completion = escape_filename(el, matches[0]); if (escaped_completion == NULL) goto out; el_winsertstr(el, ct_decode_string(escaped_completion, &el->el_scratch)); el_winsertstr(el, ct_decode_string((*app_func)(escaped_completion), &el->el_scratch)); free(escaped_completion); } else { /* * Only replace the completed string with common part of * possible matches if there is possible completion. */ el_winsertstr(el, ct_decode_string(matches[0], &el->el_scratch)); } } if (!single_match && (what_to_do == '!' || what_to_do == '?')) { /* * More than one match and requested to list possible * matches. */ for(i = 1, maxlen = 0; matches[i]; i++) { match_len = strlen(matches[i]); if (match_len > maxlen) maxlen = match_len; } /* matches[1] through matches[i-1] are available */ matches_num = (size_t)(i - 1); /* newline to get on next line from command line */ (void)fprintf(el->el_outfile, "\n"); /* * If there are too many items, ask user for display * confirmation. */ if (matches_num > query_items) { (void)fprintf(el->el_outfile, "Display all %zu possibilities? (y or n) ", matches_num); (void)fflush(el->el_outfile); if (getc(stdin) != 'y') match_display = 0; (void)fprintf(el->el_outfile, "\n"); } if (match_display) { /* * Interface of this function requires the * strings be matches[1..num-1] for compat. * We have matches_num strings not counting * the prefix in matches[0], so we need to * add 1 to matches_num for the call. */ fn_display_match_list(el, matches, matches_num+1, maxlen, app_func); } retval = CC_REDISPLAY; } else if (matches[0][0]) { /* * There was some common match, but the name was * not complete enough. Next tab will print possible * completions. */ el_beep(el); } else { /* lcd is not a valid object - further specification */ /* is needed */ el_beep(el); retval = CC_NORM; } /* free elements of array and the array itself */ for (i = 0; matches[i]; i++) el_free(matches[i]); el_free(matches); matches = NULL; } out: el_free(temp); return retval; }