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.

Reply via email to