Skip to content

Commit

Permalink
In order to reset timers during a potentially long-running copy proce…
Browse files Browse the repository at this point in the history
…ss, we

expand the file-copying function with an optional progress callback.  The
mod_copy module, then, can make use of this callback for determining when
to reset timers (Bug#4236).
  • Loading branch information
Castaglia committed Aug 4, 2016
1 parent 1ba1632 commit 94ef4e6
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
62 changes: 56 additions & 6 deletions contrib/mod_copy.c
Expand Up @@ -42,6 +42,15 @@ static int copy_engine = TRUE;
static unsigned long copy_opts = 0UL;
#define COPY_OPT_DELETE_ON_FAILURE 0x0001

static size_t copy_iter_count = 0;

/* We will reset timers in the progress callback every Nth iteration of the
* callback when copying a file.
*/
#ifndef COPY_PROGRESS_NTH_ITER
# define COPY_PROGRESS_NTH_ITER 50000
#endif

static const char *trace_channel = "copy";

static int copy_sess_init(void);
Expand Down Expand Up @@ -157,6 +166,41 @@ static int create_path(pool *p, const char *path) {
return 0;
}

static void copy_reset_progress(void) {
copy_iter_count = 0;
}

static void copy_progress_cb(void) {
int res;

copy_iter_count++;
if ((copy_iter_count % COPY_PROGRESS_NTH_ITER) != 0) {
return;
}

/* Reset some of the Timeouts which might interfere, i.e. TimeoutIdle and
* TimeoutNoDataTransfer.
*/

res = pr_timer_reset(PR_TIMER_IDLE, ANY_MODULE);
if (res < 0) {
pr_trace_msg(trace_channel, 14, "error resetting TimeoutIdle timer: %s",
strerror(errno));
}

res = pr_timer_reset(PR_TIMER_NOXFER, ANY_MODULE);
if (res < 0) {
pr_trace_msg(trace_channel, 14,
"error resetting TimeoutNoTransfer timer: %s", strerror(errno));
}

res = pr_timer_reset(PR_TIMER_STALLED, ANY_MODULE);
if (res < 0) {
pr_trace_msg(trace_channel, 14,
"error resetting TimeoutStalled timer: %s", strerror(errno));
}
}

static int copy_symlink(pool *p, const char *src_path, const char *dst_path) {
char *link_path = pcalloc(p, PR_TUNABLE_BUFFER_SIZE);
int len;
Expand Down Expand Up @@ -269,7 +313,8 @@ static int copy_dir(pool *p, const char *src_dir, const char *dst_dir) {
break;

} else {
if (pr_fs_copy_file(src_path, dst_path) < 0) {
copy_reset_progress();
if (pr_fs_copy_file2(src_path, dst_path, copy_progress_cb) < 0) {
int xerrno = errno;

pr_log_debug(DEBUG7, MOD_COPY_VERSION
Expand Down Expand Up @@ -393,7 +438,8 @@ static int copy_paths(pool *p, const char *from, const char *to) {
}
}

res = pr_fs_copy_file(from, to);
copy_reset_progress();
res = pr_fs_copy_file2(from, to, copy_progress_cb);
if (res < 0) {
int xerrno = errno;

Expand Down Expand Up @@ -459,6 +505,7 @@ static int copy_paths(pool *p, const char *from, const char *to) {
*allow_overwrite == FALSE) {
pr_log_debug(DEBUG6, MOD_COPY_VERSION
": AllowOverwrite permission denied for '%s'", to);

errno = EACCES;
return -1;
}
Expand All @@ -478,6 +525,7 @@ static int copy_paths(pool *p, const char *from, const char *to) {
} else {
pr_log_debug(DEBUG7, MOD_COPY_VERSION
": unsupported file type for '%s'", from);

errno = EINVAL;
return -1;
}
Expand Down Expand Up @@ -825,7 +873,7 @@ MODRET copy_cpto(cmd_rec *cmd) {

if (copy_paths(cmd->tmp_pool, from, to) < 0) {
int xerrno = errno;
const char *resp_code = R_550;
const char *err_code = R_550;

pr_log_debug(DEBUG7, MOD_COPY_VERSION
": error copying '%s' to '%s': %s", from, to, strerror(xerrno));
Expand All @@ -845,15 +893,15 @@ MODRET copy_cpto(cmd_rec *cmd) {
#if defined(ENOSPC)
case ENOSPC:
#endif /* ENOSPC */
resp_code = R_552;
err_code = R_552;
break;

default:
resp_code = R_550;
err_code = R_550;
break;
}

pr_response_add_err(resp_code, "%s: %s", (char *) cmd->argv[1],
pr_response_add_err(err_code, "%s: %s", (char *) cmd->argv[1],
strerror(xerrno));

if (copy_opts & COPY_OPT_DELETE_ON_FAILURE) {
Expand Down Expand Up @@ -900,6 +948,7 @@ MODRET copy_post_pass(cmd_rec *cmd) {
config_rec *c;

if (copy_engine == FALSE) {
pr_event_unregister(&copy_module, NULL, NULL);
return PR_DECLINED(cmd);
}

Expand All @@ -912,6 +961,7 @@ MODRET copy_post_pass(cmd_rec *cmd) {
}

if (copy_engine == FALSE) {
pr_event_unregister(&copy_module, NULL, NULL);
return PR_DECLINED(cmd);
}

Expand Down
10 changes: 9 additions & 1 deletion include/fsio.h
Expand Up @@ -350,7 +350,15 @@ void pr_fs_statcache_reset(void);
int pr_fs_statcache_set_policy(unsigned int size, unsigned int max_age,
unsigned int flags);

int pr_fs_copy_file(const char *, const char *);
/* Copy a file from the given source path to the destination path. */
int pr_fs_copy_file(const char *src, const char *dst);

/* Similar to pr_fs_copy_file(), with the addition of an optional progress
* callback, invoked during the potentially long-running copy process.
*/
int pr_fs_copy_file2(const char *src, const char *dst,
void (*progress_cb)(void));

int pr_fs_setcwd(const char *);
const char *pr_fs_getcwd(void);
const char *pr_fs_getvwd(void);
Expand Down
11 changes: 10 additions & 1 deletion src/fsio.c
Expand Up @@ -1743,7 +1743,8 @@ void pr_fs_clear_cache(void) {

/* FS functions proper */

int pr_fs_copy_file(const char *src, const char *dst) {
int pr_fs_copy_file2(const char *src, const char *dst,
void (*progress_cb)(void)) {
pr_fh_t *src_fh, *dst_fh;
struct stat src_st, dst_st;
char *buf;
Expand Down Expand Up @@ -1936,6 +1937,10 @@ int pr_fs_copy_file(const char *src, const char *dst) {
return -1;
}

if (progress_cb != NULL) {
(progress_cb)();
}

if ((size_t) res == datalen) {
break;
}
Expand Down Expand Up @@ -2091,6 +2096,10 @@ int pr_fs_copy_file(const char *src, const char *dst) {
return res;
}

int pr_fs_copy_file(const char *src, const char *dst) {
return pr_fs_copy_file2(src, dst, NULL);
}

pr_fs_t *pr_register_fs(pool *p, const char *name, const char *path) {
pr_fs_t *fs = NULL;
int xerrno = 0;
Expand Down

0 comments on commit 94ef4e6

Please sign in to comment.