This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository efm2.
View the commit online.
commit f918c86d251299bb837cd6e0e7d4b053bb62e3e3
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
AuthorDate: Tue Apr 23 19:44:43 2024 +0100
more work on mv impl
---
src/backends/default/mv.c | 393 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 380 insertions(+), 13 deletions(-)
diff --git a/src/backends/default/mv.c b/src/backends/default/mv.c
index e39bf1c..430576d 100644
--- a/src/backends/default/mv.c
+++ b/src/backends/default/mv.c
@@ -1,3 +1,8 @@
+// for copy_file_range()
+#include <asm-generic/errno-base.h>
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
#include <Eina.h>
#include <Ecore.h>
#include <Ecore_File.h>
@@ -11,6 +16,7 @@
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
+#include <fcntl.h>
#include "eina_strbuf.h"
#include "eina_thread.h"
@@ -27,11 +33,12 @@ static const char *config_dir = NULL;
static Eina_Bool
fs_scan(const char *src)
{
+ Eina_Bool res = EINA_TRUE;
Eina_Iterator *it;
- const char *s;
+ const char *s;
+ struct stat st;
if (strlen(src) < 1) return EINA_FALSE;
- struct stat st;
if (lstat(src, &st) != 0)
{
@@ -79,8 +86,13 @@ fs_scan(const char *src)
{
EINA_ITERATOR_FOREACH(it, s)
{
- if (!fs_scan(s)) return EINA_FALSE;
+ if (res)
+ {
+ if (!fs_scan(s)) res = EINA_FALSE;
+ }
+ eina_stringshare_del(s);
}
+ eina_iterator_free(it);
}
}
else
@@ -92,16 +104,15 @@ fs_scan(const char *src)
if (st.st_size > 0)
status_count(st.st_size, ecore_file_file_get(src));
}
- return EINA_TRUE;
+ return res;
}
static Eina_Bool
fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err)
-{
- Eina_Bool res = EINA_TRUE;
-
- if (!fs_scan(src)) return EINA_FALSE;
-
+{ // cp_rm /path/to/src/filename /path/to/dst/filename
+ // XXX: ecore_file_mv() ? <- look at it
+ // XXX: utime()/utimes() -> utimensat()
+ //
// if src is dir
// fs_mkdir(dst)
// for all files in src
@@ -136,17 +147,370 @@ fs_cp_rm(const char *src, const char *dst, Eina_Bool report_err)
// fs_chmod(src_meta, dst_meta)
// fs_chown(src_meta, dst_meta)
// fs_rm(src_meta)
+ Eina_Bool res = EINA_TRUE;
+ Eina_Iterator *it;
+ const char *s;
+ struct stat st;
+ mode_t old_umask;
+ struct timeval times[2];
+
+ if (strlen(src) < 1) return EINA_FALSE;
+
+ // first count how much work needs doing
+ if (!fs_scan(src)) return EINA_FALSE;
+
+ fprintf(stderr, "cp_rm [%s] -> [%s]\n", src, dst);
+ fflush(stderr);
+ if (lstat(src, &st) != 0)
+ {
+ switch (errno)
+ {
+ case ENOENT: // ignore this error - file removed during scan ?
+ status_pos(1, "Move - File vanished");
+ break;
+ case EACCES:
+ status_error(src, dst, "Move - Permission denied for source");
+ return EINA_FALSE;
+ case EFAULT:
+ status_error(src, dst, "Move - Memory Fault");
+ return EINA_FALSE;
+ case ELOOP:
+ status_error(src, dst, "Move - Too many symlinks");
+ return EINA_FALSE;
+ case ENAMETOOLONG:
+ status_error(src, dst, "Move - Name too long");
+ return EINA_FALSE;
+ case ENOMEM:
+ status_error(src, dst, "Move - Out of memory");
+ return EINA_FALSE;
+ case ENOTDIR:
+ status_error(src, dst, "Move - Source path component is not a directory");
+ return EINA_FALSE;
+ case EOVERFLOW:
+ status_error(src, dst, "Move - Overflow");
+ return EINA_FALSE;
+ default: // WAT?
+ return EINA_FALSE;
+ }
+ }
+ old_umask = umask(0);
+ if (S_ISDIR(st.st_mode))
+ { // it's a dir - scan this recursively
+ if (mkdir(dst, st.st_mode) != 0)
+ {
+ switch (errno)
+ {
+ case EEXIST: // ignore - mv would mv over this anyway
+ break;
+ case EACCES:
+ res = EINA_FALSE;
+ goto err;
+ case EDQUOT:
+ res = EINA_FALSE;
+ goto err;
+ case EFAULT:
+ res = EINA_FALSE;
+ goto err;
+ case EINVAL:
+ res = EINA_FALSE;
+ goto err;
+ case ELOOP:
+ res = EINA_FALSE;
+ goto err;
+ case EMLINK:
+ res = EINA_FALSE;
+ goto err;
+ case ENAMETOOLONG:
+ res = EINA_FALSE;
+ goto err;
+ case ENOENT:
+ res = EINA_FALSE;
+ goto err;
+ case ENOMEM:
+ res = EINA_FALSE;
+ goto err;
+ case ENOSPC:
+ res = EINA_FALSE;
+ goto err;
+ case ENOTDIR:
+ res = EINA_FALSE;
+ goto err;
+ case EPERM:
+ res = EINA_FALSE;
+ goto err;
+ case EROFS:
+ res = EINA_FALSE;
+ goto err;
+ default: // WAT
+ res = EINA_FALSE;
+ goto err;
+ }
+ }
+ it = eina_file_ls(src);
+ if (it)
+ {
+ 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_append(buf, dst);
+ eina_strbuf_append(buf, "/");
+ eina_strbuf_append(buf, fs);
+ if (!fs_cp_rm(s, eina_strbuf_string_get(buf), report_err))
+ res = EINA_FALSE;
+ }
+ eina_strbuf_free(buf);
+ }
+ eina_stringshare_del(s);
+ }
+ eina_iterator_free(it);
+ }
+ // if (res) rmdir(src);
+ }
+ else if (S_ISLNK(st.st_mode))
+ {
+ char link[PATH_MAX];
+ ssize_t lnsz;
+
+ lnsz = readlink(src, link, sizeof(link));
+ if ((lnsz > 0) && (lnsz < (ssize_t)sizeof(link)))
+ {
+ if (symlink(link, dst) < 0)
+ { // XXX: soft error? e.g. mv on FAT fs?
+ }
+ }
+ else if (lnsz < 0)
+ { // XXX: handle read link err
+ }
+ }
+ else if (S_ISFIFO(st.st_mode))
+ {
+ if (mkfifo(dst, st.st_mode) < 0)
+ { // XXX: soft error? ignore?
+ }
+ }
+ else if (S_ISSOCK(st.st_mode))
+ {
+ // we can't just make sockets - so ignore but have this here to document
+ }
+ else if ((S_ISCHR(st.st_mode)) || (S_ISBLK(st.st_mode)))
+ {
+ if (mknod(dst, st.st_mode, st.st_dev) < 0)
+ { // XXX: soft error? ignore?
+ }
+ }
+ else
+ {
+ 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;
+ case EBADF:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EFAULT:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EINVAL:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EIO:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EISDIR:
+ res = EINA_FALSE;
+ goto err_copy;
+ default: // WAT
+ 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;
+ case EBADF:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EDQUOT:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EFAULT:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EFBIG:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EINVAL:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EIO:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case ENOSPC:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EPERM:
+ res = EINA_FALSE;
+ goto err_copy;
+ break;
+ case EDESTADDRREQ: // WAT
+ case EPIPE: // WAT
+ default: // WAT
+ 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:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EFBIG:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EINVAL:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EIO:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EISDIR:
+ res = EINA_FALSE;
+ goto err_copy;
+ case ENOMEM:
+ res = EINA_FALSE;
+ goto err_copy;
+ case ENOSPC:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EOVERFLOW:
+ res = EINA_FALSE;
+ goto err_copy;
+ case EPERM:
+ res = EINA_FALSE;
+ goto err_copy;
+ case ETXTBSY:
+ res = EINA_FALSE;
+ goto err_copy;
+ default: // WAT
+ 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);
+ // if (res) unlink(src);
+ }
+ chown(dst, st.st_uid, st.st_gid);
+#ifdef STAT_NSEC
+#ifdef st_mtime
+#define STAT_NSEC_ATIME(st) (unsigned long long)((st)->st_atim.tv_nsec)
+#define STAT_NSEC_MTIME(st) (unsigned long long)((st)->st_mtim.tv_nsec)
+#define STAT_NSEC_CTIME(st) (unsigned long long)((st)->st_ctim.tv_nsec)
+#else
+#define STAT_NSEC_ATIME(st) (unsigned long long)((st)->st_atimensec)
+#define STAT_NSEC_MTIME(st) (unsigned long long)((st)->st_mtimensec)
+#define STAT_NSEC_CTIME(st) (unsigned long long)((st)->st_ctimensec)
+#endif
+#else
+#define STAT_NSEC_ATIME(st) (unsigned long long)(0)
+#define STAT_NSEC_MTIME(st) (unsigned long long)(0)
+#define STAT_NSEC_CTIME(st) (unsigned long long)(0)
+#endif
+ times[0].tv_sec = st.st_atime;
+ times[0].tv_usec = STAT_NSEC_ATIME(st) * 1000;
+ times[1].tv_sec = st.st_mtime;
+ times[1].tv_usec = STAT_NSEC_MTIME(st) * 1000;
+ utimes(dst, times);
+err:
+ umask(old_umask);
+ if (!res)
+ {
+ fprintf(stderr, "MV: ERROR!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ fflush(stderr);
+ }
return res;
}
static Eina_Bool
fs_mv(const char *src, const char *dst, Eina_Bool report_err)
-{
+{ // mv /path/to/src/filename /path/to/dst/filename
Eina_Bool res = EINA_TRUE;
int ret;
- // XXX: ecore_file_mv() ? <- look at it
- // XXX: utime()/utimes() -> utimensat()
status_op("mv");
status_count(1, src);
ret = rename(src, dst);
@@ -218,7 +582,7 @@ fs_mv(const char *src, const char *dst, Eina_Bool report_err)
res = EINA_FALSE;
break;
case EXDEV: // revert to cp + rm
- // XXX: handle fallback to cp + rm
+ return fs_cp_rm(src, dst, report_err);
break;
default: // WAT???
res = EINA_FALSE;
@@ -243,6 +607,9 @@ main(int argc, char **argv)
ecore_init();
efreet_init();
+ fprintf(stderr, "MV: [%s] -> [%s]\n", src, dst);
+ fflush(stderr);
+
config_dir = getenv("E_HOME_DIR");
home_dir = getenv("HOME");
if (!home_dir) return 77; // no $HOME? definitely an error!
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.