diff options
Diffstat (limited to 'src/lib/efreet_trash.c')
-rw-r--r-- | src/lib/efreet_trash.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/lib/efreet_trash.c b/src/lib/efreet_trash.c new file mode 100644 index 0000000..27cc2b1 --- /dev/null +++ b/src/lib/efreet_trash.c @@ -0,0 +1,288 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/stat.h> +#include <unistd.h> +#include <libgen.h> +#include <errno.h> + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_trash_log_dom +static int _efreet_trash_log_dom = -1; + +#include "Efreet.h" +#include "Efreet_Trash.h" +#include "efreet_private.h" + +static unsigned int _efreet_trash_init_count = 0; +static const char *efreet_trash_dir = NULL; + +#ifdef _WIN32 +# define getuid() GetCurrentProcessId() +#endif + +EAPI int +efreet_trash_init(void) +{ + if (++_efreet_trash_init_count != 1) + return _efreet_trash_init_count; + + if (!eina_init()) + return --_efreet_trash_init_count; + + _efreet_trash_log_dom = eina_log_domain_register + ("efreet_trash", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_trash_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_trash"); + eina_shutdown(); + return --_efreet_trash_init_count; + } + return _efreet_trash_init_count; +} + +EAPI int +efreet_trash_shutdown(void) +{ + if (--_efreet_trash_init_count != 0) + return _efreet_trash_init_count; + + IF_RELEASE(efreet_trash_dir); + eina_log_domain_unregister(_efreet_trash_log_dom); + _efreet_trash_log_dom = -1; + eina_shutdown(); + + return _efreet_trash_init_count; +} + +EAPI const char* +efreet_trash_dir_get(const char *file) +{ + char buf[PATH_MAX]; + struct stat s_dest; + struct stat s_src; + const char *trash_dir = NULL; + + if (file) + { + if (stat(efreet_data_home_get(), &s_dest) != 0) + return NULL; + + if (stat(file, &s_src) != 0) + return NULL; + } + + if (!file || s_src.st_dev == s_dest.st_dev) + { + if (efreet_trash_dir && ecore_file_exists(efreet_trash_dir)) + { + eina_stringshare_ref(efreet_trash_dir); + return efreet_trash_dir; + } + + snprintf(buf, sizeof(buf), "%s/Trash", efreet_data_home_get()); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + IF_RELEASE(efreet_trash_dir); + efreet_trash_dir = eina_stringshare_add(buf); + trash_dir = eina_stringshare_ref(efreet_trash_dir); + } + else + { + char *dir; + char path[PATH_MAX]; + + strncpy(buf, file, PATH_MAX); + buf[PATH_MAX - 1] = 0; + path[0] = 0; + + while (strlen(buf) > 1) + { + strncpy(path, buf, PATH_MAX); + dir = dirname(buf); + + if (stat(dir, &s_dest) == 0) + { + if (s_src.st_dev == s_dest.st_dev){ + + strncpy(buf, dir, PATH_MAX); + continue; + } + else + { + /* other device */ + break; + } + } + path[0] = 0; + break; + } + + if (path[0]) + { + snprintf(buf, sizeof(buf), "%s/.Trash-%d", path, getuid()); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + trash_dir = eina_stringshare_add(buf); + } + } + if (trash_dir) + { + snprintf(buf, sizeof(buf), "%s/files", trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + { + eina_stringshare_del(trash_dir); + return NULL; + } + + snprintf(buf, sizeof(buf), "%s/info", trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + { + eina_stringshare_del(trash_dir); + return NULL; + } + } + + return trash_dir; +} + +EAPI int +efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete) +{ + char dest[PATH_MAX]; + char times[64]; + const char *fname; + const char *escaped; + const char *trash_dir; + int i = 1; + time_t now; + FILE *f; + + EINA_SAFETY_ON_NULL_RETURN_VAL(uri, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, 0); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ecore_file_can_write(uri->path), 0); + + fname = ecore_file_file_get(uri->path); + + trash_dir = efreet_trash_dir_get(uri->path); + if (!trash_dir) + { + ERR("EFREET TRASH ERROR: No trash directory."); + return 0; + } + snprintf(dest, sizeof(dest), "%s/files/%s", trash_dir, fname); + + /* search for a free filename */ + while (ecore_file_exists(dest) && (i < 100)) + snprintf(dest, sizeof(dest), "%s/files/%s$%d", + trash_dir, fname, i++); + + fname = ecore_file_file_get(dest); + + /* move file to trash dir */ + if (rename(uri->path, dest)) + { + if (errno == EXDEV) + { + if (!force_delete) + { + eina_stringshare_del(trash_dir); + return -1; + } + + if (!ecore_file_recursive_rm(uri->path)) + { + ERR("EFREET TRASH ERROR: Can't delete file."); + eina_stringshare_del(trash_dir); + return 0; + } + } + else + { + ERR("EFREET TRASH ERROR: Can't move file to trash."); + eina_stringshare_del(trash_dir); + return 0; + } + } + + /* create info file */ + snprintf(dest, sizeof(dest), "%s/info/%s.trashinfo", trash_dir, fname); + + if ((f = fopen(dest, "w"))) + { + fputs("[Trash Info]\n", f); + + fputs("Path=", f); + escaped = efreet_uri_encode(uri); + fputs(escaped + 7, f); // +7 == don't write 'file://' + IF_RELEASE(escaped); + + time(&now); + strftime(times, sizeof(times), "%Y-%m-%dT%H:%M:%S", localtime(&now)); + fputs("\nDeletionDate=", f); + fputs(times, f); + fputs("\n", f); + fclose(f); + } + else + { + ERR("EFREET TRASH ERROR: Can't create trash info file."); + return 0; + } + + return 1; +} + +EAPI int +efreet_trash_is_empty(void) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + + /* TODO Check also trash in other filesystems */ + return ecore_file_dir_is_empty(buf); +} + +EAPI int +efreet_trash_empty_trash(void) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/info", efreet_trash_dir_get(NULL)); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + /* TODO Empty also trash in other filesystems */ + return 1; +} + +EAPI Eina_List* +efreet_trash_ls(void) +{ + char *infofile; + char buf[PATH_MAX]; + Eina_List *files, *l; + + // NOTE THIS FUNCTION NOW IS NOT COMPLETE AS I DON'T NEED IT + // TODO read the name from the infofile instead of the filename + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + files = ecore_file_ls(buf); + + if (eina_log_domain_level_check(_efreet_trash_log_dom, EINA_LOG_LEVEL_INFO)) + EINA_LIST_FOREACH(files, l, infofile) + INF("FILE: %s\n", infofile); + + return files; +} + |