4 * Copyright (C) 2005, 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)
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
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)
40 #include "gui_support.h"
43 #include "usericons.h"
49 #define RECENT_DELAY (5 * 60) /* Time in seconds to consider a file recent */
50 #define ABOUT_NOW(time) (diritem_recent_time - time < RECENT_DELAY)
51 /* If you want to make use of the RECENT flag, make sure this is set to
52 * the current time before calling diritem_restat().
54 time_t diritem_recent_time
;
56 /* Static prototypes */
57 static void examine_dir(const guchar
*path
, DirItem
*item
,
58 struct stat
*link_target
);
60 /****************************************************************
61 * EXTERNAL INTERFACE *
62 ****************************************************************/
64 void diritem_init(void)
69 /* Bring this item's structure uptodate.
70 * 'parent' is optional; it saves one stat() for directories.
72 void diritem_restat(const guchar
*path
, DirItem
*item
, struct stat
*parent
)
78 g_object_unref(item
->_image
);
82 item
->mime_type
= NULL
;
84 if (mc_lstat(path
, &info
) == -1)
86 item
->lstat_errno
= errno
;
87 item
->base_type
= TYPE_ERROR
;
90 item
->mtime
= item
->ctime
= item
->atime
= 0;
91 item
->uid
= (uid_t
) -1;
92 item
->gid
= (gid_t
) -1;
98 item
->lstat_errno
= 0;
99 item
->size
= info
.st_size
;
100 item
->mode
= info
.st_mode
;
101 item
->atime
= info
.st_atime
;
102 item
->ctime
= info
.st_ctime
;
103 item
->mtime
= info
.st_mtime
;
104 item
->uid
= info
.st_uid
;
105 item
->gid
= info
.st_gid
;
106 if (ABOUT_NOW(item
->mtime
) || ABOUT_NOW(item
->ctime
))
107 item
->flags
|= ITEM_FLAG_RECENT
;
109 if (xattr_have(path
))
110 item
->flags
|= ITEM_FLAG_HAS_XATTR
;
112 if (S_ISLNK(info
.st_mode
))
114 if (mc_stat(path
, &info
))
115 item
->base_type
= TYPE_ERROR
;
118 mode_to_base_type(info
.st_mode
);
120 item
->flags
|= ITEM_FLAG_SYMLINK
;
122 target_path
= readlink_dup(path
);
126 item
->base_type
= mode_to_base_type(info
.st_mode
);
127 target_path
= (guchar
*) path
;
130 if (item
->base_type
== TYPE_DIRECTORY
)
132 if (mount_is_mounted(target_path
, &info
,
133 target_path
== path
? parent
: NULL
))
134 item
->flags
|= ITEM_FLAG_MOUNT_POINT
136 else if (g_hash_table_lookup(fstab_mounts
,
138 item
->flags
|= ITEM_FLAG_MOUNT_POINT
;
141 if (path
!= target_path
)
145 if (item
->base_type
== TYPE_DIRECTORY
)
147 /* KRJW: info.st_uid will be the uid of the dir, regardless
148 * of whether `path' is a dir or a symlink to one. Note that
149 * if path is a symlink to a dir, item->uid will be the uid
150 * of the *symlink*, but we really want the uid of the dir
151 * to which the symlink points.
153 examine_dir(path
, item
, &info
);
155 else if (item
->base_type
== TYPE_FILE
)
158 item
->mime_type
= text_plain
;
159 else if (item
->flags
& ITEM_FLAG_SYMLINK
)
162 link_path
= pathdup(path
);
163 item
->mime_type
= type_from_path(link_path
169 item
->mime_type
= type_from_path(path
);
171 /* Note: for symlinks we need the mode of the target */
172 if (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
174 /* Note that the flag is set for ALL executable
175 * files, but the mime_type must also be executable
176 * for clicking on the file to run it.
178 item
->flags
|= ITEM_FLAG_EXEC_FILE
;
180 if (item
->mime_type
== NULL
||
181 item
->mime_type
== application_octet_stream
)
183 item
->mime_type
= application_executable
;
185 else if (item
->mime_type
== text_plain
&&
186 !strchr(item
->leafname
, '.'))
188 item
->mime_type
= application_x_shellscript
;
191 else if (item
->mime_type
== application_x_desktop
)
193 item
->flags
|= ITEM_FLAG_EXEC_FILE
;
196 if (!item
->mime_type
)
197 item
->mime_type
= text_plain
;
199 check_globicon(path
, item
);
201 if (item
->mime_type
== application_x_desktop
&& item
->_image
== NULL
)
203 item
->_image
= g_fscache_lookup(desktop_icon_cache
, path
);
207 check_globicon(path
, item
);
209 if (!item
->mime_type
)
210 item
->mime_type
= mime_type_from_base_type(item
->base_type
);
213 DirItem
*diritem_new(const guchar
*leafname
)
217 item
= g_new(DirItem
, 1);
218 item
->leafname
= g_strdup(leafname
);
219 item
->may_delete
= FALSE
;
221 item
->base_type
= TYPE_UNKNOWN
;
222 item
->flags
= ITEM_FLAG_NEED_RESCAN_QUEUE
;
223 item
->mime_type
= NULL
;
224 item
->leafname_collate
= collate_key_new(leafname
);
229 void diritem_free(DirItem
*item
)
231 g_return_if_fail(item
!= NULL
);
234 g_object_unref(item
->_image
);
236 collate_key_free(item
->leafname_collate
);
237 g_free(item
->leafname
);
241 /* For use by di_image() only. Sets item->_image. */
242 void _diritem_get_image(DirItem
*item
)
244 g_return_if_fail(item
->_image
== NULL
);
246 if (item
->base_type
== TYPE_ERROR
)
248 item
->_image
= im_error
;
249 g_object_ref(im_error
);
252 item
->_image
= type_to_icon(item
->mime_type
);
255 /****************************************************************
256 * INTERNAL FUNCTIONS *
257 ****************************************************************/
259 /* Fill in more details of the DirItem for a directory item.
260 * - Looks for an image (but maybe still NULL on error)
261 * - Updates ITEM_FLAG_APPDIR
263 * link_target contains stat info for the link target for symlinks (or for the
264 * item itself if not a link).
266 static void examine_dir(const guchar
*path
, DirItem
*item
,
267 struct stat
*link_target
)
270 static GString
*tmp
= NULL
;
271 uid_t uid
= link_target
->st_uid
;
274 tmp
= g_string_new(NULL
);
276 check_globicon(path
, item
);
278 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
280 item
->mime_type
= inode_mountpoint
;
281 return; /* Try to avoid automounter problems */
284 if (link_target
->st_mode
& S_IWOTH
)
285 return; /* Don't trust world-writable dirs */
289 * - If it contains a .DirIcon then that's the icon
290 * - If it contains an AppRun then it's an application
291 * - If it contains an AppRun but no .DirIcon then try to
292 * use AppIcon.xpm as the icon.
294 * .DirIcon and AppRun must have the same owner as the
295 * directory itself, to prevent abuse of /tmp, etc.
296 * For symlinks, we want the symlink's owner.
299 g_string_printf(tmp
, "%s/.DirIcon", path
);
302 goto no_diricon
; /* Already got an icon */
304 if (mc_lstat(tmp
->str
, &info
) != 0 || info
.st_uid
!= uid
)
305 goto no_diricon
; /* Missing, or wrong owner */
307 if (S_ISLNK(info
.st_mode
) && mc_stat(tmp
->str
, &info
) != 0)
308 goto no_diricon
; /* Bad symlink */
310 if (info
.st_size
> MAX_ICON_SIZE
|| !S_ISREG(info
.st_mode
))
311 goto no_diricon
; /* Too big, or non-regular file */
313 /* Try to load image; may still get NULL... */
314 item
->_image
= g_fscache_lookup(pixmap_cache
, tmp
->str
);
318 /* Try to find AppRun... */
319 g_string_truncate(tmp
, tmp
->len
- 8);
320 g_string_append(tmp
, "AppRun");
322 if (mc_lstat(tmp
->str
, &info
) != 0 || info
.st_uid
!= uid
)
323 goto out
; /* Missing, or wrong owner */
325 if (!(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
326 goto out
; /* Not executable */
328 item
->flags
|= ITEM_FLAG_APPDIR
;
330 /* Try to load AppIcon.xpm... */
333 goto out
; /* Already got an icon */
335 g_string_truncate(tmp
, tmp
->len
- 3);
336 g_string_append(tmp
, "Icon.xpm");
338 /* Note: since AppRun is valid we don't need to check AppIcon.xpm
342 if (mc_stat(tmp
->str
, &info
) != 0)
343 goto out
; /* Missing, or broken symlink */
345 if (info
.st_size
> MAX_ICON_SIZE
|| !S_ISREG(info
.st_mode
))
346 goto out
; /* Too big, or non-regular file */
348 /* Try to load image; may still get NULL... */
349 item
->_image
= g_fscache_lookup(pixmap_cache
, tmp
->str
);
353 if ((item
->flags
& ITEM_FLAG_APPDIR
) && !item
->_image
)
355 /* This is an application without an icon */
356 item
->_image
= im_appdir
;
357 g_object_ref(item
->_image
);