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 c63899775d242f3cd5aae4134537ca0413f05aa0
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
AuthorDate: Fri Jul 5 11:40:20 2024 +0100
mv metadata properly for custom xy,wh .. or others in future
---
TODO.md | 26 +----
src/backends/default/fs.c | 16 +--
src/backends/default/meta.c | 236 ++++++++++++++++++++++++++++++++++++++++----
src/backends/default/meta.h | 8 ++
src/backends/default/mv.c | 35 +++----
src/efm/efm_dnd.c | 27 ++++-
src/shared/sha.c | 3 -
src/shared/util.c | 46 +++++++++
src/shared/util.h | 10 +-
9 files changed, 332 insertions(+), 75 deletions(-)
diff --git a/TODO.md b/TODO.md
index 7d4da44..b790e72 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,33 +2,9 @@
# NOTES
-Solve Meta clash problem:
-
-* On load of meta file
- * Lock meta
- * Store stat info
- * Load fields
- * Unlock meta
-* Add changed flags to each meta key that was changed in memory
-* On write of meta
- * Lock meta file
- * If a meta file exists + stat info differs
- * Load meta file fields again but keey changed flag fields as is
- * Write out all meta file
- * Unlock meta file
-* On mv or cp of meta
- * Lock src meta
- * Lock dst meta
- * Read src meta
- * Read dst meta
- * Merge in only xy meta field into src meta if it exists
- * Write src meta to dst meta (now merged)
- * Delete src meta
- * Unlock src meta
- * Unlock dst meta
-
## Now
+* Handle open command crashing (stiore null exe and don't send cmds when null)
* View
* Vertical icon view
* Free x/y cleanup/grid align
diff --git a/src/backends/default/fs.c b/src/backends/default/fs.c
index 2fe1148..e352ae1 100644
--- a/src/backends/default/fs.c
+++ b/src/backends/default/fs.c
@@ -1,5 +1,5 @@
// for copy_file_range()
-#define _GNU_SOURCE
+#include "efm_config.h"
#define _FILE_OFFSET_BITS 64
#include <Eina.h>
@@ -408,13 +408,13 @@ err_unlink:
// 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)
-# 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)
+# 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)
+# 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)
@@ -459,4 +459,4 @@ done:
return res;
}
-// add fs_cp() fs_rm() fs_trash() fs_rename()
\ No newline at end of file
+// add fs_cp() fs_rm() fs_trash() fs_rename()
diff --git a/src/backends/default/meta.c b/src/backends/default/meta.c
index de92471..ad1b553 100644
--- a/src/backends/default/meta.c
+++ b/src/backends/default/meta.c
@@ -5,6 +5,7 @@
#include <Ecore_File.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include "eina_list.h"
#include "sha.h"
#include "meta.h"
#include "util.h"
@@ -32,12 +33,13 @@
#define META_WRITE_TIMEOUT 0.2
-typedef struct _Meta_File
+struct _Meta_File
{
- const char *path; // path of original file this metadata is for
- Eina_List *list; // for a small mount of meta - list of Meta
- Eina_Bool changed : 1; // has changes to write out
-} Meta_File;
+ const char *path; // path of original file this metadata is for
+ Eina_List *list; // for a small mount of meta - list of Meta
+ Eina_Bool changed : 1; // has changes to write out
+ Util_Modtime modtime; // time file modified when loaded - if it existed
+};
typedef struct _Meta
{
@@ -109,13 +111,50 @@ _meta_file_free(Meta_File *mf)
free(mf);
}
+static Eina_Bool
+_cb_meta_desktop_x_foreach_merge(const Eina_Hash *hash EINA_UNUSED,
+ const void *key, void *data, void *fdata)
+{
+ Meta_File *mf = fdata;
+ Meta *m;
+ Eina_List *l;
+ const char *meta = key;
+
+ EINA_LIST_FOREACH(mf->list, l, m)
+ {
+ if (!strcmp(m->meta, meta))
+ {
+ if (m->changed) // our in-memory key has changed - keep it
+ return EINA_TRUE;
+ else
+ { // key exists - replace with new one
+ eina_stringshare_replace(&(m->data), data);
+ return EINA_TRUE;
+ }
+ }
+ }
+ // it's a new key - add it
+ m = calloc(1, sizeof(Meta));
+ if (m)
+ {
+ m->meta = eina_stringshare_add(key /* + 6*/);
+ m->data = ""
+ mf->list = eina_list_append(mf->list, m);
+ }
+ // yes - we don't delete keys that were removed... we're handling the x,y
+ // meta problem with this so it's ok.
+ return EINA_TRUE;
+}
+
static void
_meta_file_write(Meta_File *mf)
{ // write out all in memory metadata to target meta file
- Eina_List *l;
- Meta *m;
- FILE *f;
- char *meta_path = NULL, *dir = NULL;
+ Util_Modtime mt, mt2;
+ Eina_List *l;
+ Meta *m;
+ FILE *f = NULL;
+ char *meta_path = NULL, *meta_path_tmp = NULL, *dir = NULL;
+ int tmpfd;
if (!mf->changed) return;
mf->changed = EINA_FALSE;
@@ -130,21 +169,60 @@ _meta_file_write(Meta_File *mf)
if (mf->list)
{
- // XXX: should gain a lock!
- // XXX: should write to tmp then rename atomically
- f = fopen(meta_path, "w");
+merge_again:
+ // get the mod time of the target file
+ mt = util_file_modtime_get(meta_path);
+ // has the target file changed since we may have read from it?
+ if (((util_modtime_valid(mt))
+ && (util_modtime_valid(mf->modtime))
+ && (util_modtime_cmp(mt, mf->modtime) >= 0)) || (!util_modtime_valid(mf->modtime)))
+ { // file we are about to write is newer than original. we need to
+ // merge these files - keep changed keys but re-load rest. if we've
+ // picked up keys from a file + personal overlay file then we
+ // only care about the changes in the overlay. we are doing this
+ // specifically to handle x,y coords on dnd that may be written
+ // to a dest meta file before the src meta file is cp/mv'd over
+ // and thus this x,y has to be merged or tyhe x,y may be written
+ // after the src meta has mv/cp'd over
+ Efreet_Ini *ini = efreet_ini_new(meta_path);
+ if (ini)
+ {
+ if ((ini->data) && (efreet_ini_section_set(ini, "Efm Meta")))
+ eina_hash_foreach(ini->section, _cb_meta_desktop_x_foreach_merge, mf);
+ efreet_ini_free(ini);
+ }
+ }
+ meta_path_tmp = malloc(strlen(meta_path) + 7 + 1);
+ // XXX: malloc fails?
+ strcpy(meta_path_tmp, meta_path);
+ strcat(meta_path_tmp, ".XXXXXX");
+ tmpfd = mkstemp(meta_path_tmp);
+ if (tmpfd >= 0) f = fdopen(tmpfd, "w");
if (!f)
{ // can't write to dir - write to personal meta instead
+ if (tmpfd >= 0) close(tmpfd);
free(meta_path);
+ meta_path = NULL;
+ free(meta_path_tmp);
+ meta_path_tmp = NULL;
meta_path = _meta_personal_overlay_file_get(mf);
- if (!meta_path) return;
+ if (!meta_path) goto err;
dir = ecore_file_dir_get(meta_path);
- if (!dir) return;
+ if (!dir) goto err;
if (!ecore_file_is_dir(dir)) ecore_file_mkpath(dir);
free(dir);
dir = NULL;
- f = fopen(meta_path, "w");
- if (!f) goto err;
+ meta_path_tmp = malloc(strlen(meta_path) + 7 + 1);
+ // XXX: malloc fails?
+ strcpy(meta_path_tmp, meta_path);
+ strcat(meta_path_tmp, ".XXXXXX");
+ tmpfd = mkstemp(meta_path_tmp);
+ if (tmpfd >= 0) f = fdopen(tmpfd, "w");
+ if (!f)
+ {
+ if (tmpfd >= 0) close(tmpfd);
+ goto err;
+ }
}
fprintf(f, "[Efm Meta]\n");
EINA_LIST_FOREACH(mf->list, l, m)
@@ -153,10 +231,23 @@ _meta_file_write(Meta_File *mf)
m->changed = EINA_FALSE;
}
fclose(f);
+ mt2 = util_file_modtime_get(meta_path);
+ if (((util_modtime_valid(mt2)) && (util_modtime_valid(mt))
+ && (util_modtime_cmp(mt2, mt) != 0))
+ || ((util_modtime_valid(mt2)) && (!util_modtime_valid(mt))))
+ { // this is unusual - someone snuck in a write between now and our
+ // previous modtime check. try merge in again...
+ unlink(meta_path_tmp);
+ free(meta_path_tmp);
+ meta_path_tmp = NULL;
+ goto merge_again;
+ }
+ rename(meta_path_tmp, meta_path);
}
else // no meta keys - delete it
ecore_file_unlink(meta_path);
err:
+ free(meta_path_tmp);
free(meta_path);
free(dir);
}
@@ -248,9 +339,10 @@ done:
static Meta_File *
_meta_file_find(const char *path)
{
- Meta_File *mf;
- Efreet_Ini *ini;
- char *meta_path;
+ Util_Modtime mt;
+ Meta_File *mf;
+ Efreet_Ini *ini;
+ char *meta_path;
// find existing in memory meta file data and return that
mf = eina_hash_find(_meta_hash, path);
@@ -273,6 +365,7 @@ _meta_file_find(const char *path)
eina_hash_foreach(ini->section, _cb_meta_desktop_x_foreach, mf);
efreet_ini_free(ini);
}
+ mf->modtime = util_file_modtime_get(meta_path);
free(meta_path);
// load overlayed user metdata and modify meta file content based on it
@@ -287,6 +380,13 @@ _meta_file_find(const char *path)
mf);
efreet_ini_free(ini);
}
+ mt = util_file_modtime_get(meta_path);
+ // base modtime not valid use overlay anyway
+ if (!util_modtime_valid(mf->modtime)) mf->modtime = mt;
+ // base modtime is valid, so if overlay modtime is valid and newere, use it
+ else if (util_modtime_valid(mt)
+ && (util_modtime_cmp(mt, mf->modtime) >= 0))
+ mf->modtime = mt;
free(meta_path);
}
// add to our hash db of meta files
@@ -448,3 +548,101 @@ err:
free(dir);
return ret;
}
+
+Meta_File *
+meta_file_load(const char *path)
+{
+ return _meta_file_find(path);
+}
+
+void
+meta_file_free(Meta_File *mf)
+{
+ if (mf->changed)
+ _meta_writes = eina_list_remove(_meta_writes, mf);
+ eina_hash_del(_meta_hash, mf->path, mf);
+}
+
+Meta_File *
+meta_file_copy(Meta_File *mf, const char *path)
+{
+ Meta_File *mf2;
+ Eina_List *l, *l2;
+ Meta *m, *m2;
+
+ mf2 = eina_hash_find(_meta_hash, path);
+ if (mf2)
+ {
+ EINA_LIST_FOREACH(mf->list, l, m)
+ {
+ EINA_LIST_FOREACH(mf2->list, l2, m2)
+ {
+ if (!strcmp(m->meta, m2->meta))
+ {
+ if ((m->changed) && (!m2->changed))
+ {
+ if (m2->data) eina_stringshare_del(m2->data);
+ m2->data = ""
+ if (m->data) m2->data = ""
+ }
+ }
+ }
+ if (!l2) // key in mf doesnt exist in mf2
+ {
+ m2 = calloc(1, sizeof(Meta));
+ if (m2)
+ {
+ m2->meta = eina_stringshare_add(m->meta);
+ if (m->data) m2->data = ""
+ m2->changed = m->changed;
+ mf2->list = eina_list_append(mf2->list, m2);
+ }
+ }
+ }
+ }
+ else
+ {
+ mf2 = calloc(1, sizeof(Meta_File));
+ if (!mf2) return NULL;
+ mf2->modtime = util_file_modtime_get(NULL); // invalid time for NULL
+ mf2->path = eina_stringshare_add(path);
+ eina_hash_add(_meta_hash, mf2->path, mf2);
+ EINA_LIST_FOREACH(mf->list, l, m)
+ {
+ m2 = calloc(1, sizeof(Meta));
+ if (m2)
+ {
+ m2->meta = eina_stringshare_add(m->meta);
+ if (m->data) m2->data = ""
+ m2->changed = m->changed;
+ mf2->list = eina_list_append(mf2->list, m2);
+ }
+ }
+ }
+ _meta_file_write_queue(mf2); // queue writes for later
+ return mf2;
+}
+
+void
+meta_file_del(Meta_File *mf)
+{
+ char *meta_file;
+
+ if ((meta_file = meta_path_find(mf->path, "meta.efm")))
+ {
+ unlink(meta_file);
+ free(meta_file);
+ }
+ if ((meta_file = meta_path_user_find(mf->path, "meta.efm")))
+ {
+ unlink(meta_file);
+ free(meta_file);
+ }
+}
+
+void
+meta_file_save(Meta_File *mf)
+{
+ _meta_writes = eina_list_remove(_meta_writes, mf);
+ _meta_file_write(mf);
+}
\ No newline at end of file
diff --git a/src/backends/default/meta.h b/src/backends/default/meta.h
index 87dd91a..8f8a979 100644
--- a/src/backends/default/meta.h
+++ b/src/backends/default/meta.h
@@ -2,6 +2,8 @@
#define META_H
#include <Eina.h>
+typedef struct _Meta_File Meta_File;
+
void meta_init(const char *config_dir);
void meta_shutdown(void);
@@ -13,4 +15,10 @@ char *meta_path_user_find(const char *path, const char *extn);
Eina_Bool meta_path_prepare(const char *path);
Eina_Bool meta_path_can_write(const char *path);
+Meta_File *meta_file_load(const char *path);
+void meta_file_free(Meta_File *mf);
+Meta_File *meta_file_copy(Meta_File *mf, const char *path);
+void meta_file_del(Meta_File *mf);
+void meta_file_save(Meta_File *mf);
+
#endif
\ No newline at end of file
diff --git a/src/backends/default/mv.c b/src/backends/default/mv.c
index d655bc9..d2022a0 100644
--- a/src/backends/default/mv.c
+++ b/src/backends/default/mv.c
@@ -196,25 +196,26 @@ main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
{ // it worked so deal with meta/thumbs
char *src_meta, *dst_meta;
- // metadata file for the base target file
- if (src_can_write) src_meta = meta_path_find(src, "meta.efm");
- else src_meta = meta_path_user_find(src, "meta.efm");
- if (dst_can_write) dst_meta = meta_path_find(dst, "meta.efm");
- else dst_meta = meta_path_user_find(dst, "meta.efm");
- if ((src_meta) && (dst_meta) && (meta_path_prepare(dst)))
+ // XXX: use meta api to:
+ // 1. meta_load src (new api that takes path + ret handle)
+ // 2. meta_dup src to dst (new api with new path dst path, ret dst hnd)
+ // 3. meta_save the duplicated meta (bew api)
+ // 4. meta_del the src meta (new api)
+ // 5. meta_free src + dst handles (new api)
+ Meta_File *mfsrc, *mfdst;
+
+ mfsrc = meta_file_load(src);
+ if (mfsrc)
{
- status_count(1, src_meta);
- fs_mv(src_meta, dst_meta, EINA_FALSE);
- // XXX: how do we force a re-read of the meta file? also how to
- // merge? e.g. we dnd an icon into a dir - we may or may not at that
- // point write x,y to the meta file - but we have other fields we
- // will want to merge in ... so we don't want to mv here - we want
- // to merge sensibly... so ugh... bug already here ... we want
- // to also trigger an update of meta data for any efm backends
- // telling the front-ends...
+ mfdst = meta_file_copy(mfsrc, dst);
+ if (mfdst)
+ {
+ meta_file_save(mfdst);
+ meta_file_del(mfsrc);
+ meta_file_free(mfsrc);
+ meta_file_free(mfdst);
+ }
}
- free(src_meta);
- free(dst_meta);
// thumbnail file for the base target file
if (src_can_write) src_meta = meta_path_find(src, "thumb.efm");
diff --git a/src/efm/efm_dnd.c b/src/efm/efm_dnd.c
index d476573..f67a6e9 100644
--- a/src/efm/efm_dnd.c
+++ b/src/efm/efm_dnd.c
@@ -214,13 +214,14 @@ _cb_drop(void *data, Evas_Object *o EINA_UNUSED, Elm_Selection_Data *ev)
printf("XXX: DROP FILE: [%s]\n", esc);
if (sd->config.view_mode == EFM_VIEW_MODE_ICONS_CUSTOM)
{
+ Eina_Bool found = EINA_FALSE;
+ char str[128];
+
dropicons = _icons_path_find(esc);
EINA_LIST_FREE(dropicons, icon)
{
if (icon->selected)
{
- char str[128];
-
if (icon->sd == sd)
{
icon->geom.x += delta_x;
@@ -240,8 +241,30 @@ _cb_drop(void *data, Evas_Object *o EINA_UNUSED, Elm_Selection_Data *ev)
(int)(icon->geom.y / _scale_get(icon->sd)));
cmd_strbuf_append(buf, "xy", str);
cmd_strbuf_exe_consume(buf, icon->sd->exe_open);
+ found = EINA_TRUE;
}
}
+ if (!found)
+ {
+ Eina_Strbuf *buf2 = eina_strbuf_new();
+
+ if (buf2)
+ {
+ printf("XXX: -> DROPEXTICON: [%s] %i %i\n",
+ esc, sd->dnd_x, sd->dnd_y);
+ buf = cmd_strbuf_new("meta-set");
+
+ eina_strbuf_append(buf2, sd->config.path);
+ eina_strbuf_append(buf2, ecore_file_file_get(esc));
+ cmd_strbuf_append(buf, "path", eina_strbuf_string_get(buf2));
+ snprintf(str, sizeof(str), "%i,%i",
+ (int)(sd->dnd_x / _scale_get(sd)),
+ (int)(sd->dnd_y / _scale_get(sd)));
+ cmd_strbuf_append(buf, "xy", str);
+ cmd_strbuf_exe_consume(buf, sd->exe_open);
+ eina_strbuf_free(buf2);
+ }
+ }
}
free(esc);
}
diff --git a/src/shared/sha.c b/src/shared/sha.c
index a2a6492..3ca5b12 100644
--- a/src/shared/sha.c
+++ b/src/shared/sha.c
@@ -13,14 +13,11 @@ sha1_stat(const struct stat *st, unsigned char dst[20])
#ifdef STAT_NSEC
# ifdef st_mtime
# 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_MTIME(st) (unsigned long long)((st)->st_mtimensec)
-# define STAT_NSEC_CTIME(st) (unsigned long long)((st)->st_ctimensec)
# endif
#else
# define STAT_NSEC_MTIME(st) (unsigned long long)(0)
-# define STAT_NSEC_CTIME(st) (unsigned long long)(0)
#endif
snprintf(buf, sizeof(buf), "%llu %llu %llu",
diff --git a/src/shared/util.c b/src/shared/util.c
index 8460430..f9871ae 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1,4 +1,5 @@
#include "util.h"
+#include "efm_config.h"
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
@@ -24,4 +25,49 @@ util_file_mode_parent_copy(const char *file, Eina_Bool is_dir)
}
err:
free(dir_parent);
+}
+
+Util_Modtime
+util_file_modtime_get(const char *file)
+{
+ struct stat st;
+ Util_Modtime mt = { ~(0ull), ~(0ull) }; // default - ivalid all bits 1
+
+ if (!file) return mt;
+ if (stat(file, &st) == 0)
+ {
+ mt.sec = st.st_mtime;
+#ifdef STAT_NSEC
+# ifdef st_mtime
+# define STAT_NSEC_MTIME(st) (unsigned long long)((st).st_mtim.tv_nsec)
+# else
+# define STAT_NSEC_MTIME(st) (unsigned long long)((st).st_mtimensec)
+# endif
+#else
+# define STAT_NSEC_MTIME(st) (unsigned long long)(0)
+#endif
+ mt.nsec = STAT_NSEC_MTIME(st);
+ }
+ return mt;
+}
+
+int
+util_modtime_cmp(Util_Modtime t1, Util_Modtime t2)
+{
+ if (t1.sec > t2.sec) return 1; // t1 > t2
+ else if (t1.sec < t2.sec) return -1; // t1 < t2
+ // seconds equal - check nsec
+ if (t1.nsec > t2.nsec) return 1; // t1 > t2
+ else if (t1.nsec < t2.nsec) return -1; // t1 < t2
+ // they are both equal
+ return 0; // t1 == t2
+}
+
+Eina_Bool
+util_modtime_valid(Util_Modtime t)
+{
+ const Util_Modtime mt = { ~(0ull), ~(0ull) }; // default - ivalid all bits 1
+
+ if ((t.sec == mt.sec) && (t.nsec == mt.nsec)) return EINA_FALSE;
+ return EINA_TRUE;
}
\ No newline at end of file
diff --git a/src/shared/util.h b/src/shared/util.h
index 4a7abdf..38f4ec8 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -3,6 +3,14 @@
#include <Eina.h>
-void util_file_mode_parent_copy(const char *file, Eina_Bool is_dir);
+typedef struct
+{
+ unsigned long long sec, nsec;
+} Util_Modtime;
+
+void util_file_mode_parent_copy(const char *file, Eina_Bool is_dir);
+Util_Modtime util_file_modtime_get(const char *file);
+int util_modtime_cmp(Util_Modtime t1, Util_Modtime t2);
+Eina_Bool util_modtime_valid(Util_Modtime t);
#endif
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.