EFL 1.7 svn doobies
[profile/ivi/efreet.git] / src / lib / efreet_trash.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <libgen.h>
8 #include <errno.h>
9
10 #include <Ecore_File.h>
11
12 /* define macros and variable for using the eina logging system  */
13 #define EFREET_MODULE_LOG_DOM _efreet_trash_log_dom
14 static int _efreet_trash_log_dom = -1;
15
16 #include "Efreet.h"
17 #include "Efreet_Trash.h"
18 #include "efreet_private.h"
19
20 static unsigned int _efreet_trash_init_count = 0;
21 static const char *efreet_trash_dir = NULL;
22
23 #ifdef _WIN32
24 # define getuid() GetCurrentProcessId()
25 #endif
26
27 EAPI int
28 efreet_trash_init(void)
29 {
30     if (++_efreet_trash_init_count != 1)
31         return _efreet_trash_init_count;
32
33     if (!eina_init())
34         return --_efreet_trash_init_count;
35
36     _efreet_trash_log_dom = eina_log_domain_register
37       ("efreet_trash", EFREET_DEFAULT_LOG_COLOR);
38     if (_efreet_trash_log_dom < 0)
39     {
40         EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_trash");
41         eina_shutdown();
42         return --_efreet_trash_init_count;
43     }
44     return _efreet_trash_init_count;
45 }
46
47 EAPI int
48 efreet_trash_shutdown(void)
49 {
50     if (--_efreet_trash_init_count != 0)
51         return _efreet_trash_init_count;
52
53     IF_RELEASE(efreet_trash_dir);
54     eina_log_domain_unregister(_efreet_trash_log_dom);
55     _efreet_trash_log_dom = -1;
56     eina_shutdown();
57
58     return _efreet_trash_init_count;
59 }
60
61 EAPI const char*
62 efreet_trash_dir_get(const char *file)
63 {
64     char buf[PATH_MAX];
65     struct stat s_dest;
66     struct stat s_src;
67     const char *trash_dir = NULL;
68
69     if (file)
70     {
71         if (stat(efreet_data_home_get(), &s_dest) != 0)
72             return NULL;
73
74         if (stat(file, &s_src) != 0)
75             return NULL;
76     }
77
78     if (!file || s_src.st_dev == s_dest.st_dev)
79     {
80         if (efreet_trash_dir && ecore_file_exists(efreet_trash_dir))
81         {
82             eina_stringshare_ref(efreet_trash_dir);
83             return efreet_trash_dir;
84         }
85
86         snprintf(buf, sizeof(buf), "%s/Trash", efreet_data_home_get());
87         if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf))
88             return NULL;
89
90         IF_RELEASE(efreet_trash_dir);
91         efreet_trash_dir = eina_stringshare_add(buf);
92         trash_dir = eina_stringshare_ref(efreet_trash_dir);
93     }
94     else
95     {
96         char *dir;
97         char path[PATH_MAX];
98
99         strncpy(buf, file, PATH_MAX);
100         buf[PATH_MAX - 1] = 0;
101         path[0] = 0;
102
103         while (strlen(buf) > 1)
104         {
105             strncpy(path, buf, PATH_MAX);
106             dir = dirname(buf);
107
108             if (stat(dir, &s_dest) == 0)
109             {
110                 if (s_src.st_dev == s_dest.st_dev){
111
112                     strncpy(buf, dir, PATH_MAX);
113                     continue;
114                 }
115                 else
116                 {
117                     /* other device */
118                     break;
119                 }
120             }
121             path[0] = 0;
122             break;
123         }
124
125         if (path[0])
126         {
127             snprintf(buf, sizeof(buf), "%s/.Trash-%d", path, getuid());
128             if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf))
129                 return NULL;
130
131             trash_dir = eina_stringshare_add(buf);
132         }
133     }
134     if (trash_dir)
135     {
136         snprintf(buf, sizeof(buf), "%s/files", trash_dir);
137         if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf))
138         {
139             eina_stringshare_del(trash_dir);
140             return NULL;
141         }
142
143         snprintf(buf, sizeof(buf), "%s/info", trash_dir);
144         if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf))
145         {
146             eina_stringshare_del(trash_dir);
147             return NULL;
148         }
149     }
150
151     return trash_dir;
152 }
153
154 EAPI int
155 efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete)
156 {
157     char dest[PATH_MAX];
158     char times[64];
159     const char *fname;
160     const char *escaped;
161     const char *trash_dir;
162     int i = 1;
163     time_t now;
164     FILE *f;
165
166     EINA_SAFETY_ON_NULL_RETURN_VAL(uri, 0);
167     EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, 0);
168     EINA_SAFETY_ON_FALSE_RETURN_VAL(ecore_file_can_write(uri->path), 0);
169
170     fname = ecore_file_file_get(uri->path);
171
172     trash_dir = efreet_trash_dir_get(uri->path);
173     if (!trash_dir)
174     {
175         ERR("EFREET TRASH ERROR: No trash directory.");
176         return 0;
177     }
178     snprintf(dest, sizeof(dest), "%s/files/%s", trash_dir, fname);
179
180     /* search for a free filename */
181     while (ecore_file_exists(dest) && (i < 100))
182         snprintf(dest, sizeof(dest), "%s/files/%s$%d",
183                     trash_dir, fname, i++);
184
185     fname = ecore_file_file_get(dest);
186
187     /* move file to trash dir */
188     if (rename(uri->path, dest))
189     {
190         if (errno == EXDEV)
191         {
192             if (!force_delete)
193             {
194                 eina_stringshare_del(trash_dir);
195                 return -1;
196             }
197
198             if (!ecore_file_recursive_rm(uri->path))
199             {
200                 ERR("EFREET TRASH ERROR: Can't delete file.");
201                 eina_stringshare_del(trash_dir);
202                 return 0;
203             }
204         }
205         else
206         {
207             ERR("EFREET TRASH ERROR: Can't move file to trash.");
208             eina_stringshare_del(trash_dir);
209             return 0;
210         }
211     }
212
213     /* create info file */
214     snprintf(dest, sizeof(dest), "%s/info/%s.trashinfo", trash_dir, fname);
215
216     if ((f = fopen(dest, "w")))
217     {
218         fputs("[Trash Info]\n", f);
219
220         fputs("Path=", f);
221         escaped = efreet_uri_encode(uri);
222         fputs(escaped + 7, f); // +7 == don't write 'file://'
223         IF_RELEASE(escaped);
224
225         time(&now);
226         strftime(times, sizeof(times), "%Y-%m-%dT%H:%M:%S", localtime(&now));
227         fputs("\nDeletionDate=", f);
228         fputs(times, f);
229         fputs("\n", f);
230         fclose(f);
231     }
232     else
233     {
234         ERR("EFREET TRASH ERROR: Can't create trash info file.");
235         return 0;
236     }
237
238     return 1;
239 }
240
241 EAPI int
242 efreet_trash_is_empty(void)
243 {
244     char buf[PATH_MAX];
245
246     snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL));
247
248     /* TODO Check also trash in other filesystems */
249     return ecore_file_dir_is_empty(buf);
250 }
251
252 EAPI int
253 efreet_trash_empty_trash(void)
254 {
255     char buf[PATH_MAX];
256
257     snprintf(buf, sizeof(buf), "%s/info", efreet_trash_dir_get(NULL));
258     if (!ecore_file_recursive_rm(buf)) return 0;
259     ecore_file_mkdir(buf);
260
261     snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL));
262     if (!ecore_file_recursive_rm(buf)) return 0;
263     ecore_file_mkdir(buf);
264
265     /* TODO Empty also trash in other filesystems */
266     return 1;
267 }
268
269 EAPI Eina_List*
270 efreet_trash_ls(void)
271 {
272     char *infofile;
273     char buf[PATH_MAX];
274     Eina_List *files, *l;
275
276     // NOTE THIS FUNCTION NOW IS NOT COMPLETE AS I DON'T NEED IT
277     // TODO read the name from the infofile instead of the filename
278
279     snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL));
280     files = ecore_file_ls(buf);
281
282     if (eina_log_domain_level_check(_efreet_trash_log_dom, EINA_LOG_LEVEL_INFO))
283         EINA_LIST_FOREACH(files, l, infofile)
284             INF("FILE: %s\n", infofile);
285
286     return files;
287 }
288