1 /* $Id$ */
2 /* Copyright (c) 2012-2015 Pierre Pronchery <khorben@defora.org> */
3 /* This file is part of DeforaOS Desktop Browser */
4 /* Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the authors nor the names of the contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29
30
31
32 #if defined(__sun)
33 # include <fcntl.h>
34 # include <unistd.h>
35 #endif
36 #include <stdlib.h>
37 #include <string.h>
38 #include <libgen.h>
39 #include "../include/Browser/vfs.h"
40
41
42 /* public */
43 /* functions */
44 /* accessors */
45 /* browser_vfs_is_mountpoint */
browser_vfs_is_mountpoint(struct stat * lst,dev_t parent)46 int browser_vfs_is_mountpoint(struct stat * lst, dev_t parent)
47 {
48 return (lst->st_dev != parent) ? 1 : 0;
49 }
50
51
52 /* useful */
53 /* browser_vfs_lstat */
browser_vfs_lstat(char const * filename,struct stat * st)54 int browser_vfs_lstat(char const * filename, struct stat * st)
55 {
56 return lstat(filename, st);
57 }
58
59
60 /* browser_vfs_closedir */
browser_vfs_closedir(DIR * dir)61 int browser_vfs_closedir(DIR * dir)
62 {
63 return closedir(dir);
64 }
65
66
67 /* browser_vfs_mime_icon */
68 static GdkPixbuf * _mime_icon_emblem(GdkPixbuf * pixbuf, int size,
69 char const * emblem);
70 static GdkPixbuf * _mime_icon_folder(Mime * mime, char const * filename,
71 struct stat * lst, struct stat * st, int size);
72 static gboolean _mime_icon_folder_in_home(struct stat * pst);
73 static gboolean _mime_icon_folder_is_home(struct stat * st);
74
browser_vfs_mime_icon(Mime * mime,char const * filename,char const * type,struct stat * lst,struct stat * st,int size)75 GdkPixbuf * browser_vfs_mime_icon(Mime * mime, char const * filename,
76 char const * type, struct stat * lst, struct stat * st,
77 int size)
78 {
79 GdkPixbuf * ret = NULL;
80 mode_t mode = (lst != NULL) ? lst->st_mode : 0;
81 struct stat s;
82 char const * emblem;
83
84 if(filename == NULL)
85 return NULL;
86 if(type == NULL)
87 type = browser_vfs_mime_type(mime, filename,
88 S_ISLNK(mode) ? 0 : mode);
89 if(st == NULL && browser_vfs_stat(filename, &s) == 0)
90 st = &s;
91 if(S_ISDIR(mode) || (st != NULL && S_ISDIR(st->st_mode)))
92 ret = _mime_icon_folder(mime, filename, lst, st, size);
93 else if(S_ISLNK(mode) && (st != NULL && S_ISDIR(st->st_mode)))
94 ret = _mime_icon_folder(mime, filename, lst, st, size);
95 else
96 mime_icons(mime, type, size, &ret, -1);
97 if(ret == NULL || lst == NULL)
98 return ret;
99 /* determine the emblem */
100 if(S_ISCHR(lst->st_mode) || S_ISBLK(lst->st_mode))
101 emblem = "emblem-system";
102 else if(S_ISLNK(lst->st_mode))
103 emblem = "emblem-symbolic-link";
104 else if((lst->st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0)
105 emblem = "emblem-unreadable";
106 else if((lst->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0)
107 emblem = "emblem-readonly";
108 else
109 emblem = NULL;
110 /* apply the emblem if relevant */
111 if(emblem != NULL)
112 ret = _mime_icon_emblem(ret, size, emblem);
113 return ret;
114 }
115
_mime_icon_emblem(GdkPixbuf * pixbuf,int size,char const * emblem)116 static GdkPixbuf * _mime_icon_emblem(GdkPixbuf * pixbuf, int size,
117 char const * emblem)
118 {
119 int esize;
120 GdkPixbuf * epixbuf;
121 GtkIconTheme * icontheme;
122 #if GTK_CHECK_VERSION(2, 14, 0)
123 const unsigned int flags = GTK_ICON_LOOKUP_USE_BUILTIN
124 | GTK_ICON_LOOKUP_FORCE_SIZE;
125 #else
126 const unsigned int flags = GTK_ICON_LOOKUP_USE_BUILTIN;
127 #endif
128
129 /* work on a copy */
130 epixbuf = gdk_pixbuf_copy(pixbuf);
131 g_object_unref(pixbuf);
132 pixbuf = epixbuf;
133 /* determine the size of the emblem */
134 if(size >= 96)
135 esize = 32;
136 else if(size >= 48)
137 esize = 24;
138 else
139 esize = 12;
140 /* obtain the emblem's icon */
141 icontheme = gtk_icon_theme_get_default();
142 if((epixbuf = gtk_icon_theme_load_icon(icontheme, emblem, esize, flags,
143 NULL)) == NULL)
144 return pixbuf;
145 /* blit the emblem */
146 #if 0 /* XXX does not show anything (bottom right) */
147 gdk_pixbuf_composite(epixbuf, pixbuf, size - esize, size - esize,
148 esize, esize, 0, 0, 1.0, 1.0, GDK_INTERP_NEAREST,
149 255);
150 #else /* blitting at the top left instead */
151 gdk_pixbuf_composite(epixbuf, pixbuf, 0, 0, esize, esize, 0, 0,
152 1.0, 1.0, GDK_INTERP_NEAREST, 255);
153 #endif
154 g_object_unref(epixbuf);
155 return pixbuf;
156 }
157
_mime_icon_folder(Mime * mime,char const * filename,struct stat * lst,struct stat * st,int size)158 static GdkPixbuf * _mime_icon_folder(Mime * mime, char const * filename,
159 struct stat * lst, struct stat * st, int size)
160 {
161 GdkPixbuf * ret = NULL;
162 char const * icon = NULL;
163 struct stat ls;
164 struct stat ps;
165 char * p;
166 size_t i;
167 struct
168 {
169 char const * name;
170 char const * icon;
171 } name_icon[] =
172 {
173 { "DCIM", "folder-pictures" },
174 { "Desktop", "user-desktop" },
175 { "Documents", "folder-documents" },
176 { "Download", "folder-download" },
177 { "Downloads", "folder-download" },
178 { "Music", "folder-music" },
179 { "Pictures", "folder-pictures" },
180 { "public_html","folder-publicshare" },
181 { "Templates", "folder-templates" },
182 { "Video", "folder-videos" },
183 { "Videos", "folder-videos" },
184 };
185 GtkIconTheme * icontheme;
186 const unsigned int flags = GTK_ICON_LOOKUP_FORCE_SIZE;
187
188 if(lst == NULL && browser_vfs_lstat(filename, &ls) == 0)
189 lst = &ls;
190 /* check if the folder is special */
191 if((p = strdup(filename)) != NULL
192 && (lst == NULL || !S_ISLNK(lst->st_mode))
193 && st != NULL
194 && browser_vfs_lstat(dirname(p), &ps) == 0)
195 {
196 if(st->st_dev != ps.st_dev || st->st_ino == ps.st_ino)
197 icon = "mount-point";
198 else if(_mime_icon_folder_is_home(st))
199 icon = "folder_home";
200 else if(_mime_icon_folder_in_home(&ps))
201 /* check if the folder is special */
202 for(i = 0; i < sizeof(name_icon) / sizeof(*name_icon);
203 i++)
204 if(strcasecmp(basename(p), name_icon[i].name)
205 == 0)
206 {
207 icon = name_icon[i].icon;
208 break;
209 }
210 }
211 free(p);
212 if(icon != NULL)
213 {
214 icontheme = gtk_icon_theme_get_default();
215 ret = gtk_icon_theme_load_icon(icontheme, icon, size, flags,
216 NULL);
217 }
218 /* generic fallback */
219 if(ret == NULL)
220 mime_icons(mime, "inode/directory", size, &ret, -1);
221 return ret;
222 }
223
_mime_icon_folder_in_home(struct stat * pst)224 static gboolean _mime_icon_folder_in_home(struct stat * pst)
225 {
226 static char const * homedir = NULL;
227 static struct stat hst;
228
229 if(homedir == NULL)
230 {
231 if((homedir = getenv("HOME")) == NULL
232 && (homedir = g_get_home_dir()) == NULL)
233 return FALSE;
234 if(browser_vfs_stat(homedir, &hst) != 0)
235 {
236 homedir = NULL;
237 return FALSE;
238 }
239 }
240 return (hst.st_dev == pst->st_dev && hst.st_ino == pst->st_ino)
241 ? TRUE : FALSE;
242 }
243
_mime_icon_folder_is_home(struct stat * st)244 static gboolean _mime_icon_folder_is_home(struct stat * st)
245 {
246 /* FIXME code duplicated from _mime_icon_folder_in_home() */
247 static char const * homedir = NULL;
248 static struct stat hst;
249
250 if(homedir == NULL)
251 {
252 if((homedir = getenv("HOME")) == NULL
253 && (homedir = g_get_home_dir()) == NULL)
254 return FALSE;
255 if(browser_vfs_stat(homedir, &hst) != 0)
256 {
257 homedir = NULL;
258 return FALSE;
259 }
260 }
261 return (hst.st_dev == st->st_dev && hst.st_ino == st->st_ino)
262 ? TRUE : FALSE;
263 }
264
265
266 /* browser_vfs_mime_type */
browser_vfs_mime_type(Mime * mime,char const * filename,mode_t mode)267 char const * browser_vfs_mime_type(Mime * mime, char const * filename,
268 mode_t mode)
269 {
270 char const * ret = NULL;
271 struct stat st;
272 struct stat pst;
273 char * p = NULL;
274
275 if(mode == 0 && filename != NULL
276 && browser_vfs_lstat(filename, &st) == 0)
277 mode = st.st_mode;
278 if(S_ISDIR(mode))
279 {
280 /* look for mountpoints */
281 if(filename != NULL && (p = strdup(filename)) != NULL
282 && browser_vfs_lstat(filename, &st) == 0
283 && browser_vfs_lstat(dirname(p), &pst) == 0
284 && (st.st_dev != pst.st_dev
285 || st.st_ino == pst.st_ino))
286 ret = "inode/mountpoint";
287 else
288 ret = "inode/directory";
289 free(p);
290 return ret;
291 }
292 else if(S_ISBLK(mode))
293 return "inode/blockdevice";
294 else if(S_ISCHR(mode))
295 return "inode/chardevice";
296 else if(S_ISFIFO(mode))
297 return "inode/fifo";
298 else if(S_ISLNK(mode))
299 return "inode/symlink";
300 #ifdef S_ISSOCK
301 else if(S_ISSOCK(mode))
302 return "inode/socket";
303 #endif
304 if(mime != NULL && filename != NULL)
305 ret = mime_type(mime, filename);
306 if(ret == NULL && (mode & S_IXUSR) != 0)
307 ret = "application/x-executable";
308 return ret;
309 }
310
311
312 /* browser_vfs_opendir */
browser_vfs_opendir(char const * filename,struct stat * st)313 DIR * browser_vfs_opendir(char const * filename, struct stat * st)
314 {
315 DIR * dir;
316 int fd;
317
318 #ifdef DEBUG
319 fprintf(stderr, "DEBUG: %s(\"%s\", %p)\n", __func__, filename, st);
320 #endif
321 if(st == NULL)
322 return opendir(filename);
323 #if defined(__sun)
324 if((fd = open(filename, O_RDONLY)) < 0
325 || (dir = fdopendir(fd)) == NULL)
326 {
327 if(fd >= 0)
328 close(fd);
329 return NULL;
330 }
331 #else
332 if((dir = opendir(filename)) == NULL)
333 return NULL;
334 fd = dirfd(dir);
335 #endif
336 if(fstat(fd, st) != 0)
337 {
338 browser_vfs_closedir(dir);
339 return NULL;
340 }
341 return dir;
342 }
343
344
345 /* browser_vfs_readdir */
browser_vfs_readdir(DIR * dir)346 struct dirent * browser_vfs_readdir(DIR * dir)
347 {
348 return readdir(dir);
349 }
350
351
352 /* browser_vfs_stat */
browser_vfs_stat(char const * filename,struct stat * st)353 int browser_vfs_stat(char const * filename, struct stat * st)
354 {
355 return stat(filename, st);
356 }
357