cleaner code - move file cp to own func etc.
This commit is contained in:
parent
f603296834
commit
3519ab0f91
|
@ -15,22 +15,30 @@
|
|||
#include "status.h"
|
||||
#include "fs.h"
|
||||
|
||||
// generic error handler. special case handling all errnos for everything is
|
||||
// pretty insane - so handle non-errors in switches and otherwise pass to
|
||||
// this tio handle the reast in a generic way.
|
||||
static void
|
||||
_error_handle(const char *src, const char *dst, const char *op, int errno_in)
|
||||
static Eina_Strbuf *
|
||||
error_strbuf_new(const char *op)
|
||||
{
|
||||
Eina_Strbuf *buf = eina_strbuf_new();
|
||||
|
||||
if (!buf) abort();
|
||||
eina_strbuf_append(buf, op);
|
||||
eina_strbuf_append(buf, ": ");
|
||||
#define HNDL(_err, _str) \
|
||||
_err: \
|
||||
eina_strbuf_append(buf, _str); \
|
||||
status_error(src, dst, eina_strbuf_string_get(buf)); \
|
||||
break
|
||||
return buf;
|
||||
}
|
||||
|
||||
// generic error handler. special case handling all errnos for everything is
|
||||
// pretty insane - so handle non-errors in switches and otherwise pass to
|
||||
// this tio handle the reast in a generic way.
|
||||
static void
|
||||
_error_handle(const char *src, const char *dst, const char *op, int errno_in)
|
||||
{
|
||||
Eina_Strbuf *buf = error_strbuf_new(op);
|
||||
|
||||
#define HNDL(_err, _str) \
|
||||
_err: \
|
||||
eina_strbuf_append(buf, _str); \
|
||||
status_error(src, dst, eina_strbuf_string_get(buf)); \
|
||||
break
|
||||
switch (errno_in)
|
||||
{
|
||||
HNDL(case EACCES, "Access denied");
|
||||
|
@ -61,6 +69,120 @@ _error_handle(const char *src, const char *dst, const char *op, int errno_in)
|
|||
eina_strbuf_free(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
error_ok_pos(const char *src, const char *op, const char *str)
|
||||
{
|
||||
Eina_Strbuf *buf = error_strbuf_new(op);
|
||||
|
||||
eina_strbuf_append(buf, str);
|
||||
status_pos(1, eina_strbuf_string_get(buf));
|
||||
eina_strbuf_free(buf);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
fs_cp_file(const char *src, const char *dst, const char *op, struct stat src_st)
|
||||
{
|
||||
// copy a normal file from src to dst - use optimized copy range if possible
|
||||
// and fall abck to read + write into userspace buffer otherwise. use the
|
||||
// struct stat mode passed in for created file. return true if fully
|
||||
// successful or false otherwise
|
||||
int fd_in, fd_ou;
|
||||
void *old_copy_buf = NULL;
|
||||
Eina_Bool res = EINA_TRUE;
|
||||
|
||||
fd_in = open(src, O_RDONLY);
|
||||
fd_ou = open(dst, O_WRONLY | O_CREAT, src_st.st_mode);
|
||||
if ((fd_in >= 0) && (fd_ou >= 0))
|
||||
{
|
||||
ssize_t size = 1 * 1024 * 1024; // 1mb default for copy range
|
||||
ssize_t ret, ret2;
|
||||
off_t off_in = 0, off_ou = 0;
|
||||
Eina_Bool old_copy = EINA_FALSE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (old_copy)
|
||||
{
|
||||
if (!old_copy_buf)
|
||||
{
|
||||
size = 256 * 1024; // drop to 256k buffer for r+w
|
||||
old_copy_buf = malloc(size);
|
||||
if (!old_copy_buf)
|
||||
{
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
again_read:
|
||||
ret = read(fd_in, old_copy_buf, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
goto again_read;
|
||||
default:
|
||||
_error_handle(src, NULL, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
off_in += ret;
|
||||
again_write:
|
||||
ret2 = write(fd_ou, old_copy_buf, ret);
|
||||
if (ret2 < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
goto again_write;
|
||||
default:
|
||||
_error_handle(NULL, dst, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else if (ret2 == ret)
|
||||
{
|
||||
off_ou += ret;
|
||||
if (ret < size) break; // end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = copy_file_range(fd_in, &off_in, fd_ou, &off_ou, size, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EOPNOTSUPP:
|
||||
case EXDEV:
|
||||
// fall back to old read+write copy into userspace buf
|
||||
old_copy = EINA_TRUE;
|
||||
break;
|
||||
default:
|
||||
_error_handle(src, dst, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else if (ret < size) break; // end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
else res = EINA_FALSE;
|
||||
err:
|
||||
if (old_copy_buf) free(old_copy_buf);
|
||||
if (fd_in >= 0) close(fd_in);
|
||||
if (fd_ou >= 0) close(fd_ou);
|
||||
return res;
|
||||
}
|
||||
|
||||
// this scans a tree to build a potential operation progress count. it may
|
||||
// not be 100% right as the fs can change while the scan happens and after
|
||||
// so any move that devolves into a cp + rm isn't going to be atomic and
|
||||
|
@ -94,10 +216,7 @@ fs_scan(const char *src)
|
|||
{
|
||||
EINA_ITERATOR_FOREACH(it, s)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
if (!fs_scan(s)) res = EINA_FALSE;
|
||||
}
|
||||
if ((res) && (!fs_scan(s))) res = EINA_FALSE;
|
||||
eina_stringshare_del(s);
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
|
@ -125,9 +244,8 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
mode_t old_umask;
|
||||
struct timeval times[2];
|
||||
const char *op = "";
|
||||
Eina_Strbuf *sbuf = NULL;
|
||||
|
||||
if (strlen(src) < 1) return EINA_FALSE;
|
||||
if ((!src) || (!dst) || (strlen(src) < 1)) return EINA_FALSE;
|
||||
|
||||
// first count how much work needs doing
|
||||
if (!fs_scan(src)) return EINA_FALSE;
|
||||
|
@ -142,11 +260,7 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
switch (errno)
|
||||
{
|
||||
case ENOENT: // ignore this error - file removed during scan ?
|
||||
eina_strbuf_reset(sbuf);
|
||||
eina_strbuf_append(sbuf, op);
|
||||
eina_strbuf_append(sbuf, ": ");
|
||||
eina_strbuf_append(sbuf, "File vanished");
|
||||
status_pos(1, eina_strbuf_string_get(sbuf));
|
||||
error_ok_pos(src, op, "File vanished");
|
||||
goto err;
|
||||
default:
|
||||
_error_handle(src, dst, op, errno);
|
||||
|
@ -154,7 +268,6 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
goto err;
|
||||
}
|
||||
}
|
||||
sbuf = eina_strbuf_new();
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{ // it's a dir - scan this recursively
|
||||
if (cp)
|
||||
|
@ -165,7 +278,7 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
{
|
||||
case EEXIST: // ignore - mv would mv over this anyway
|
||||
break;
|
||||
default: // WAT
|
||||
default:
|
||||
_error_handle(NULL, dst, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
|
@ -175,15 +288,18 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
it = eina_file_ls(src);
|
||||
if (it)
|
||||
{
|
||||
Eina_Strbuf *buf = eina_strbuf_new();
|
||||
|
||||
if (!buf) abort();
|
||||
EINA_ITERATOR_FOREACH(it, s)
|
||||
{
|
||||
Eina_Strbuf *buf = eina_strbuf_new();
|
||||
const char *fs = ecore_file_file_get(s);
|
||||
|
||||
if (buf)
|
||||
{
|
||||
if ((res) && (fs))
|
||||
{
|
||||
eina_strbuf_reset(buf);
|
||||
eina_strbuf_append(buf, dst);
|
||||
eina_strbuf_append(buf, "/");
|
||||
eina_strbuf_append(buf, fs);
|
||||
|
@ -191,11 +307,11 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
report_err, cp, rm))
|
||||
res = EINA_FALSE;
|
||||
}
|
||||
eina_strbuf_free(buf);
|
||||
}
|
||||
eina_stringshare_del(s);
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
eina_strbuf_free(buf);
|
||||
}
|
||||
}
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
|
@ -210,11 +326,7 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
{
|
||||
if (symlink(link, dst) < 0)
|
||||
{ // soft error? e.g. mv on FAT fs? report but move on
|
||||
eina_strbuf_reset(sbuf);
|
||||
eina_strbuf_append(sbuf, op);
|
||||
eina_strbuf_append(sbuf, ": ");
|
||||
eina_strbuf_append(sbuf, "Error creating symlink");
|
||||
status_pos(1, eina_strbuf_string_get(sbuf));
|
||||
error_ok_pos(dst, op, "Error creating symlink");
|
||||
}
|
||||
}
|
||||
else if (lnsz < 0)
|
||||
|
@ -222,24 +334,16 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
switch (errno)
|
||||
{
|
||||
case ENOENT: // ignore this error - file removed during scan ?
|
||||
eina_strbuf_reset(sbuf);
|
||||
eina_strbuf_append(sbuf, op);
|
||||
eina_strbuf_append(sbuf, ": ");
|
||||
eina_strbuf_append(sbuf, "File vanished");
|
||||
status_pos(1, eina_strbuf_string_get(sbuf));
|
||||
error_ok_pos(src, op, "File vanished");
|
||||
break;
|
||||
default:
|
||||
_error_handle(src, dst, op, errno);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
else // 0 sized symlink ... WAT?
|
||||
{
|
||||
eina_strbuf_reset(sbuf);
|
||||
eina_strbuf_append(sbuf, op);
|
||||
eina_strbuf_append(sbuf, ": ");
|
||||
eina_strbuf_append(sbuf, "Zero sized symlink");
|
||||
status_error(src, NULL, eina_strbuf_string_get(sbuf));
|
||||
else
|
||||
{ // 0 sized symlink ... WAT?
|
||||
error_ok_pos(src, op, "Zero sized symlink");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,8 +359,7 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
else if (S_ISSOCK(st.st_mode))
|
||||
{
|
||||
if (cp)
|
||||
{
|
||||
// we can't just make sockets - so ignore but document here
|
||||
{ // we can't just make sockets - so ignore but document here
|
||||
}
|
||||
}
|
||||
else if ((S_ISCHR(st.st_mode)) || (S_ISBLK(st.st_mode)))
|
||||
|
@ -272,99 +375,7 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err, Eina_Bool cp,
|
|||
{
|
||||
if (cp)
|
||||
{
|
||||
int fd_in, fd_ou;
|
||||
void *old_copy_buf = NULL;
|
||||
|
||||
fd_in = open(src, O_RDONLY);
|
||||
fd_ou = open(dst, O_WRONLY | O_CREAT, st.st_mode);
|
||||
if ((fd_in >= 0) && (fd_ou >= 0))
|
||||
{
|
||||
ssize_t size = 1 * 1024 * 1024; // 1mb default
|
||||
ssize_t ret, ret2;
|
||||
off_t off_in = 0, off_ou = 0;
|
||||
Eina_Bool old_copy = EINA_FALSE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (old_copy)
|
||||
{
|
||||
if (!old_copy_buf)
|
||||
{
|
||||
size = 256 * 1024; // drop to 256k buffer
|
||||
old_copy_buf = malloc(size);
|
||||
if (!old_copy_buf)
|
||||
{
|
||||
res = EINA_FALSE;
|
||||
goto err_copy;
|
||||
}
|
||||
}
|
||||
again_read:
|
||||
ret = read(fd_in, old_copy_buf, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
goto again_read;
|
||||
default:
|
||||
_error_handle(src, NULL, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err_copy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
off_in += ret;
|
||||
again_write:
|
||||
ret2 = write(fd_ou, old_copy_buf, ret);
|
||||
if (ret2 < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
case EINTR:
|
||||
goto again_write;
|
||||
default:
|
||||
_error_handle(NULL, dst, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err_copy;
|
||||
}
|
||||
}
|
||||
else if (ret2 == ret)
|
||||
{
|
||||
off_ou += ret;
|
||||
if (ret < size) break; // end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = copy_file_range(fd_in, &off_in, fd_ou, &off_ou,
|
||||
size, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EOPNOTSUPP:
|
||||
case EXDEV:
|
||||
old_copy = EINA_TRUE;
|
||||
break;
|
||||
case EBADF:
|
||||
default: // WAT
|
||||
_error_handle(src, dst, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err_copy;
|
||||
}
|
||||
}
|
||||
else if (ret < size) break; // end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
err_copy:
|
||||
if (old_copy_buf) free(old_copy_buf);
|
||||
if (fd_in >= 0) close(fd_in);
|
||||
if (fd_ou >= 0) close(fd_ou);
|
||||
res = fs_cp_file(src, dst, op, st);
|
||||
}
|
||||
}
|
||||
if ((rm) && (res))
|
||||
|
@ -380,9 +391,12 @@ err_copy:
|
|||
default:
|
||||
_error_handle(src, NULL, op, errno);
|
||||
res = EINA_FALSE;
|
||||
goto err;
|
||||
goto err_unlink;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlink(src) != 0)
|
||||
{
|
||||
switch (errno)
|
||||
|
@ -399,6 +413,7 @@ err_copy:
|
|||
}
|
||||
err_unlink:
|
||||
chown(dst, st.st_uid, st.st_gid); // ignore err
|
||||
// duplicate mtime+atime from src down to msic/nsec if possible
|
||||
#ifdef STAT_NSEC
|
||||
#ifdef st_mtime
|
||||
#define STAT_NSEC_ATIME(st) (unsigned long long)((st)->st_atim.tv_nsec)
|
||||
|
@ -421,7 +436,6 @@ err_unlink:
|
|||
utimes(dst, times); // ingore err
|
||||
err:
|
||||
umask(old_umask);
|
||||
if (sbuf) eina_strbuf_free(sbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue