#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include /* 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; }