From 8bf7fe16ad44a232a015fcb807cec377d71341fa Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Thu, 13 Apr 2000 10:44:52 +0000 Subject: [PATCH] r238: It is now possible to copy files (and dirs) using VFS! --- ROX-Filer/src/action.c | 35 +++++++++--------- ROX-Filer/src/my_vfs.h | 10 ++++++ ROX-Filer/src/support.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ ROX-Filer/src/support.h | 1 + 4 files changed, 122 insertions(+), 18 deletions(-) diff --git a/ROX-Filer/src/action.c b/ROX-Filer/src/action.c index 7061f08d..8dca3d06 100644 --- a/ROX-Filer/src/action.c +++ b/ROX-Filer/src/action.c @@ -654,7 +654,7 @@ static void for_dir_contents(ForDirCB *cb, char *src_dir, char *dest_path) struct dirent *ent; GSList *list = NULL, *next; - d = opendir(src_dir); + d = mc_opendir(src_dir); if (!d) { g_string_sprintf(message, "!ERROR reading '%s': %s\n", @@ -665,7 +665,7 @@ static void for_dir_contents(ForDirCB *cb, char *src_dir, char *dest_path) send_dir(src_dir); - while ((ent = readdir(d))) + while ((ent = mc_readdir(d))) { if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) @@ -673,7 +673,7 @@ static void for_dir_contents(ForDirCB *cb, char *src_dir, char *dest_path) list = g_slist_append(list, g_strdup(make_path(src_dir, ent->d_name)->str)); } - closedir(d); + mc_closedir(d); if (!list) return; @@ -1076,7 +1076,7 @@ static gboolean do_usage(char *src_path, char *dest_path) check_flags(); - if (lstat(src_path, &info)) + if (mc_lstat(src_path, &info)) { g_string_sprintf(message, "'%s:\n", src_path); send(); @@ -1110,7 +1110,7 @@ static gboolean do_delete(char *src_path, char *dest_path) check_flags(); - if (lstat(src_path, &info)) + if (mc_lstat(src_path, &info)) { send_error(); return FALSE; @@ -1198,7 +1198,7 @@ static gboolean do_find(char *path, char *dummy) return FALSE; } - if (lstat(path, &info.stats)) + if (mc_lstat(path, &info.stats)) { send_error(); g_string_sprintf(message, "'(while checking '%s')\n", path); @@ -1236,7 +1236,7 @@ static gboolean do_chmod(char *path, char *dummy) check_flags(); - if (lstat(path, &info)) + if (mc_lstat(path, &info)) { send_error(); return FALSE; @@ -1280,7 +1280,7 @@ static gboolean do_chmod(char *path, char *dummy) return FALSE; } - if (lstat(path, &info)) + if (mc_lstat(path, &info)) { send_error(); return FALSE; @@ -1341,13 +1341,13 @@ static gboolean do_copy2(char *path, char *dest) dest_path = make_dest_path(path, dest); - if (lstat(path, &info)) + if (mc_lstat(path, &info)) { send_error(); return FALSE; } - if (lstat(dest_path, &dest_info) == 0) + if (mc_lstat(dest_path, &dest_info) == 0) { int err; gboolean merge; @@ -1406,7 +1406,7 @@ static gboolean do_copy2(char *path, char *dest) safe_path = g_strdup(path); safe_dest = g_strdup(dest_path); - exists = !lstat(dest_path, &dest_info); + exists = !mc_lstat(dest_path, &dest_info); if (exists && !S_ISDIR(dest_info.st_mode)) { @@ -1460,14 +1460,13 @@ static gboolean do_copy2(char *path, char *dest) } else { - char *argv[] = {"cp", "-pRf", NULL, NULL, NULL}; + guchar *error; - argv[2] = path; - argv[3] = dest_path; + error = copy_file(path, dest_path); - if (fork_exec_wait(argv)) + if (error) { - g_string_sprintf(message, "!ERROR: Copy failed\n"); + g_string_sprintf(message, "!ERROR: %s\n", error); send(); retval = FALSE; } @@ -1521,7 +1520,7 @@ static gboolean do_move(char *path, char *dest) dest_path = make_path(dest, leaf)->str; - is_dir = lstat(path, &info2) == 0 && S_ISDIR(info2.st_mode); + is_dir = mc_lstat(path, &info2) == 0 && S_ISDIR(info2.st_mode); if (access(dest_path, F_OK) == 0) { @@ -1533,7 +1532,7 @@ static gboolean do_move(char *path, char *dest) if (!reply(from_parent, TRUE)) return FALSE; - if (lstat(dest_path, &info)) + if (mc_lstat(dest_path, &info)) { send_error(); return FALSE; diff --git a/ROX-Filer/src/my_vfs.h b/ROX-Filer/src/my_vfs.h index 2d2ac190..4d066297 100644 --- a/ROX-Filer/src/my_vfs.h +++ b/ROX-Filer/src/my_vfs.h @@ -29,6 +29,11 @@ int mc_closedir (DIR *dir); int mc_telldir (DIR *dir); void mc_seekdir (DIR *dir, int offset); +int mc_open (const char *filename, int flags, ...); +int mc_close (int handle); +int mc_read (int handle, char *buffer, int count); +int mc_write (int hanlde, char *buffer, int count); + int mc_stat (char *path, struct stat *buf); int mc_lstat (char *path, struct stat *buf); int mc_fstat (int fd, struct stat *buf); @@ -38,6 +43,11 @@ int mc_fstat (int fd, struct stat *buf); /* We don't have VFS installed. Just use the normal functions instead. */ +# define mc_open open +# define mc_close close +# define mc_read read +# define mc_write write + # define mc_stat(x, y) stat(x, y) # define mc_lstat(x, y) lstat(x, y) # define mc_fstat(x, y) fstat(x, y) diff --git a/ROX-Filer/src/support.c b/ROX-Filer/src/support.c index 803e0291..244b5429 100644 --- a/ROX-Filer/src/support.c +++ b/ROX-Filer/src/support.c @@ -41,6 +41,7 @@ #include "main.h" #include "support.h" +#include "my_vfs.h" static GHashTable *uid_hash = NULL; /* UID -> User name */ static GHashTable *gid_hash = NULL; /* GID -> Group name */ @@ -417,3 +418,96 @@ char *pretty_time(time_t *time) return time_buf; } + +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0x0 +#endif + +/* Copy data from 'read_fd' FD to 'write_fd' FD until EOF or error. + * Returns 0 on success, -1 on error (and sets errno). + */ +static int copy_fd(int read_fd, int write_fd) +{ + char buffer[4096]; + int got; + + while ((got = mc_read(read_fd, buffer, sizeof(buffer))) > 0) + { + int sent = 0; + + while (sent < got) + { + int c; + + c = mc_write(write_fd, buffer + sent, got - sent); + if (c < 0) + return -1; + sent += c; + } + } + + return got; +} + +/* 'from' and 'to' are complete pathnames of files (not dirs or symlinks). + * This spawns 'cp' to do the copy if lstat() succeeds, otherwise we + * do the copy manually using vfs. + * + * Returns an error string, or NULL on success. + */ +guchar *copy_file(guchar *from, guchar *to) +{ + char *argv[] = {"cp", "-pRf", NULL, NULL, NULL}; + +#ifdef HAVE_LIBVFS + struct stat info; + + if (lstat(from, &info)) + { + int read_fd = -1; + int write_fd = -1; + int error = 0; + + if (mc_lstat(from, &info)) + return g_strerror(errno); + + /* Regular lstat() can't find it, but mc_lstat() can, + * so try reading it with VFS. + */ + + if (!S_ISREG(info.st_mode)) + goto err; + + read_fd = mc_open(from, O_RDONLY); + if (read_fd == -1) + goto err; + write_fd = mc_open(to, + O_NOFOLLOW | O_WRONLY | O_CREAT | O_TRUNC, + info.st_mode & 0777); + if (write_fd == -1) + goto err; + + if (copy_fd(read_fd, write_fd)) + goto err; + + /* (yes, the single | is right) */ + if (mc_close(read_fd) | mc_close(write_fd)) + return g_strerror(errno); + return NULL; +err: + error = errno; + if (read_fd != -1) + mc_close(read_fd); + if (write_fd != -1) + mc_close(write_fd); + return error ? g_strerror(error) : "Copy error"; + } +#endif + + argv[2] = from; + argv[3] = to; + + if (fork_exec_wait(argv)) + return "Copy failed"; + return NULL; +} diff --git a/ROX-Filer/src/support.h b/ROX-Filer/src/support.h index 478c08a8..01853822 100644 --- a/ROX-Filer/src/support.h +++ b/ROX-Filer/src/support.h @@ -31,5 +31,6 @@ char *get_local_path(char *uri); void close_on_exec(int fd, gboolean close); void set_blocking(int fd, gboolean blocking); char *pretty_time(time_t *time); +guchar *copy_file(guchar *from, guchar *to); #endif /* _SUPPORT_H */ -- 2.11.4.GIT