From 323fedecd73055f3af5395559af132d30b0dbcaf Mon Sep 17 00:00:00 2001 From: Slava Zanko Date: Tue, 20 Sep 2011 12:40:14 +0300 Subject: [PATCH] Added implementation for files space preallocation Signed-off-by: Slava Zanko --- lib/vfs/vfs.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/vfs/vfs.h | 2 ++ src/filemanager/file.c | 21 +++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/lib/vfs/vfs.c b/lib/vfs/vfs.c index 14a50b75d..39025926a 100644 --- a/lib/vfs/vfs.c +++ b/lib/vfs/vfs.c @@ -594,3 +594,42 @@ vfs_change_encoding (vfs_path_t * vpath, const char *encoding) } /* --------------------------------------------------------------------------------------------- */ + +/** + * Preallocate space for file in new place for ensure that file + * will be fully copied with less fragmentation. + * + * @param dest_desc mc VFS file handler + * @param src_fsize source file size + * @param dest_fsize destination file size (if destination exists, otherwise should be 0) + * + * @return 0 if success and non-zero otherwise. + * Note: function doesn't touch errno global variable. + */ +int +vfs_preallocate (int dest_vfs_fd, off_t src_fsize, off_t dest_fsize) +{ +#ifndef HAVE_POSIX_FALLOCATE + (void) dest_desc; + (void) src_fsize; + (void) dest_fsize; + return 0; + +#else /* HAVE_POSIX_FALLOCATE */ + int *dest_fd; + struct vfs_class *dest_class; + + dest_class = vfs_class_find_by_handle (dest_vfs_fd); + if ((dest_class->flags & VFSF_LOCAL) == 0) + return 0; + + dest_fd = (int *) vfs_class_data_find_by_handle (dest_vfs_fd); + if (dest_fd == NULL) + return 0; + + return posix_fallocate (*dest_fd, dest_fsize, src_fsize - dest_fsize); + +#endif /* HAVE_POSIX_FALLOCATE */ +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index 5319711f9..e4892b39d 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -268,6 +268,8 @@ char *_vfs_get_cwd (void); vfs_path_t *vfs_change_encoding (vfs_path_t * vpath, const char *encoding); +int vfs_preallocate (int dest_desc, off_t src_fsize, off_t dest_fsize); + /** * Interface functions described in interface.c */ diff --git a/src/filemanager/file.c b/src/filemanager/file.c index c42970d33..dc21ae857 100644 --- a/src/filemanager/file.c +++ b/src/filemanager/file.c @@ -1504,6 +1504,27 @@ copy_file_file (FileOpTotalContext * tctx, FileOpContext * ctx, ctx->skip_all = TRUE; goto ret; } + while (TRUE) + { + errno = vfs_preallocate (dest_desc, file_size, (ctx->do_append != 0) ? sb.st_size : 0); + if (errno == 0) + break; + + if (!ctx->skip_all) + { + return_status = + file_error (_("Cannot preallocate space for target file \"%s\"\n%s"), dst_path); + if (return_status == FILE_RETRY) + continue; + if (return_status == FILE_SKIPALL) + ctx->skip_all = TRUE; + } + mc_close (dest_desc); + dest_desc = -1; + mc_unlink (dst_path); + dst_status = DEST_NONE; + goto ret; + } ctx->eta_secs = 0.0; ctx->bps = 0;