r1322: Converted MaskedPixmap to GObject.
[rox-filer.git] / ROX-Filer / src / diritem.c
blobcf442116eead15c11901584afaf603202f502324
1 /*
2 * $Id$
4 * Copyright (C) 2002, the ROX-Filer team.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* diritem.c - get details about files */
23 /* Don't load icons larger than 400K (this is rather excessive, basically
24 * we just want to stop people crashing the filer with huge icons).
26 #define MAX_ICON_SIZE (400 * 1024)
28 #include "config.h"
30 #include <gtk/gtk.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <string.h>
35 #include "global.h"
37 #include "diritem.h"
38 #include "support.h"
39 #include "gui_support.h"
40 #include "mount.h"
41 #include "type.h"
42 #include "usericons.h"
43 #include "options.h"
44 #include "fscache.h"
45 #include "pixmaps.h"
47 static Option o_ignore_exec;
49 /* Static prototypes */
50 static void examine_dir(const guchar *path, DirItem *item);
53 /****************************************************************
54 * EXTERNAL INTERFACE *
55 ****************************************************************/
57 void diritem_init(void)
59 option_add_int(&o_ignore_exec, "display_ignore_exec", FALSE);
61 read_globicons();
64 /* Bring this item's structure uptodate */
65 void diritem_restat(const guchar *path, DirItem *item)
67 struct stat info;
69 if (item->image)
71 g_object_unref(item->image);
72 item->image = NULL;
74 item->flags = 0;
75 item->mime_type = NULL;
77 if (mc_lstat(path, &info) == -1)
79 item->lstat_errno = errno;
80 item->base_type = TYPE_ERROR;
81 item->size = 0;
82 item->mode = 0;
83 item->mtime = item->ctime = item->atime = 0;
84 item->uid = (uid_t) -1;
85 item->gid = (gid_t) -1;
87 else
89 item->lstat_errno = 0;
90 item->size = info.st_size;
91 item->mode = info.st_mode;
92 item->atime = info.st_atime;
93 item->ctime = info.st_ctime;
94 item->mtime = info.st_mtime;
95 item->uid = info.st_uid;
96 item->gid = info.st_gid;
98 if (S_ISLNK(info.st_mode))
100 if (mc_stat(path, &info))
101 item->base_type = TYPE_ERROR;
102 else
103 item->base_type =
104 mode_to_base_type(info.st_mode);
106 item->flags |= ITEM_FLAG_SYMLINK;
108 else
110 item->base_type = mode_to_base_type(info.st_mode);
112 if (item->base_type == TYPE_DIRECTORY)
114 if (mount_is_mounted(path))
115 item->flags |= ITEM_FLAG_MOUNT_POINT
116 | ITEM_FLAG_MOUNTED;
117 else if (g_hash_table_lookup(fstab_mounts,
118 path))
119 item->flags |= ITEM_FLAG_MOUNT_POINT;
124 if (item->base_type == TYPE_DIRECTORY)
125 examine_dir(path, item);
126 else if (item->base_type == TYPE_FILE)
128 /* Type determined from path before checking for executables
129 * because some mounts show everything as executable and we
130 * still want to use the file name to set the mime type.
132 if (item->flags & ITEM_FLAG_SYMLINK)
134 guchar *link_path;
135 link_path = readlink_dup(path);
136 item->mime_type = type_from_path(link_path
137 ? link_path
138 : path);
139 g_free(link_path);
141 else
142 item->mime_type = type_from_path(path);
144 /* Note: for symlinks we need the mode of the target */
145 if (info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
147 /* Note that the flag is set for ALL executable
148 * files, but the mime_type is only special_exec
149 * if the file doesn't have a known extension when
150 * that option is in force.
152 item->flags |= ITEM_FLAG_EXEC_FILE;
154 if (!o_ignore_exec.int_value)
155 item->mime_type = special_exec;
158 if (!item->mime_type)
159 item->mime_type = item->flags & ITEM_FLAG_EXEC_FILE
160 ? special_exec
161 : text_plain;
163 check_globicon(path, item);
165 else
166 check_globicon(path, item);
169 if (!item->mime_type)
170 item->mime_type = mime_type_from_base_type(item->base_type);
172 if (!item->image)
174 if (item->base_type == TYPE_ERROR)
176 item->image = im_error;
177 g_object_ref(im_error);
179 else
180 item->image = type_to_icon(item->mime_type);
184 DirItem *diritem_new(const guchar *leafname)
186 DirItem *item;
188 item = g_new(DirItem, 1);
189 item->leafname = g_strdup(leafname);
190 item->may_delete = FALSE;
191 item->image = NULL;
192 item->base_type = TYPE_UNKNOWN;
193 item->flags = 0;
194 item->mime_type = NULL;
196 return item;
199 void diritem_free(DirItem *item)
201 g_return_if_fail(item != NULL);
203 if (item->image)
204 g_object_unref(item->image);
205 item->image = NULL;
206 g_free(item->leafname);
207 item->leafname = NULL;
208 g_free(item);
212 /****************************************************************
213 * INTERNAL FUNCTIONS *
214 ****************************************************************/
216 /* Fill in more details of the DirItem for a directory item.
217 * - Looks for an image (but maybe still NULL on error)
218 * - Updates ITEM_FLAG_APPDIR
220 static void examine_dir(const guchar *path, DirItem *item)
222 uid_t uid = item->uid;
223 struct stat info;
224 static GString *tmp = NULL;
226 if (!tmp)
227 tmp = g_string_new(NULL);
229 check_globicon(path, item);
231 if (item->flags & ITEM_FLAG_MOUNT_POINT)
232 return; /* Try to avoid automounter problems */
234 /* Finding the icon:
236 * - If it contains a .DirIcon then that's the icon
237 * - If it contains an AppRun then it's an application
238 * - If it contains an AppRun but no .DirIcon then try to
239 * use AppIcon.xpm as the icon.
241 * .DirIcon and AppRun must have the same owner as the
242 * directory itself, to prevent abuse of /tmp, etc.
243 * For symlinks, we want the symlink's owner.
246 g_string_sprintf(tmp, "%s/.DirIcon", path);
248 if (item->image)
249 goto no_diricon; /* Already got an icon */
251 if (mc_lstat(tmp->str, &info) != 0 || info.st_uid != uid)
252 goto no_diricon; /* Missing, or wrong owner */
254 if (S_ISLNK(info.st_mode) && mc_stat(tmp->str, &info) != 0)
255 goto no_diricon; /* Bad symlink */
257 if (info.st_size > MAX_ICON_SIZE || !S_ISREG(info.st_mode))
258 goto no_diricon; /* Too big, or non-regular file */
260 /* Try to load image; may still get NULL... */
261 item->image = g_fscache_lookup(pixmap_cache, tmp->str);
263 no_diricon:
265 /* Try to find AppRun... */
266 g_string_truncate(tmp, tmp->len - 8);
267 g_string_append(tmp, "AppRun");
269 if (mc_lstat(tmp->str, &info) != 0 || info.st_uid != uid)
270 goto out; /* Missing, or wrong owner */
272 if (!(info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
273 goto out; /* Not executable */
275 item->flags |= ITEM_FLAG_APPDIR;
277 /* Try to load AppIcon.xpm... */
279 if (item->image)
280 goto out; /* Already got an icon */
282 g_string_truncate(tmp, tmp->len - 3);
283 g_string_append(tmp, "Icon.xpm");
285 /* Note: since AppRun is valid we don't need to check AppIcon.xpm
286 * so carefully.
289 if (mc_stat(tmp->str, &info) != 0)
290 goto out; /* Missing, or broken symlink */
292 if (info.st_size > MAX_ICON_SIZE || !S_ISREG(info.st_mode))
293 goto out; /* Too big, or non-regular file */
295 /* Try to load image; may still get NULL... */
296 item->image = g_fscache_lookup(pixmap_cache, tmp->str);
298 out:
300 if ((item->flags & ITEM_FLAG_APPDIR) && !item->image)
302 /* This is an application without an icon */
303 item->image = im_appdir;
304 g_object_ref(item->image);