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)
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"
48 static Option o_ignore_exec
;
50 /* Static prototypes */
51 static void examine_dir(const guchar
*path
, DirItem
*item
);
54 /****************************************************************
55 * EXTERNAL INTERFACE *
56 ****************************************************************/
58 void diritem_init(void)
60 option_add_int(&o_ignore_exec
, "display_ignore_exec", FALSE
);
65 /* Bring this item's structure uptodate.
66 * 'parent' is optional; it saves one stat() for directories.
68 void diritem_restat(const guchar
*path
, DirItem
*item
, struct stat
*parent
)
74 g_object_unref(item
->image
);
78 item
->mime_type
= NULL
;
80 if (mc_lstat(path
, &info
) == -1)
82 item
->lstat_errno
= errno
;
83 item
->base_type
= TYPE_ERROR
;
86 item
->mtime
= item
->ctime
= item
->atime
= 0;
87 item
->uid
= (uid_t
) -1;
88 item
->gid
= (gid_t
) -1;
92 item
->lstat_errno
= 0;
93 item
->size
= info
.st_size
;
94 item
->mode
= info
.st_mode
;
95 item
->atime
= info
.st_atime
;
96 item
->ctime
= info
.st_ctime
;
97 item
->mtime
= info
.st_mtime
;
98 item
->uid
= info
.st_uid
;
99 item
->gid
= info
.st_gid
;
101 if (S_ISLNK(info
.st_mode
))
103 if (mc_stat(path
, &info
))
104 item
->base_type
= TYPE_ERROR
;
107 mode_to_base_type(info
.st_mode
);
109 item
->flags
|= ITEM_FLAG_SYMLINK
;
113 item
->base_type
= mode_to_base_type(info
.st_mode
);
115 if (item
->base_type
== TYPE_DIRECTORY
)
117 if (mount_is_mounted(path
, &info
, parent
))
118 item
->flags
|= ITEM_FLAG_MOUNT_POINT
120 else if (g_hash_table_lookup(fstab_mounts
,
122 item
->flags
|= ITEM_FLAG_MOUNT_POINT
;
127 if (item
->base_type
== TYPE_DIRECTORY
)
128 examine_dir(path
, item
);
129 else if (item
->base_type
== TYPE_FILE
)
131 /* Type determined from path before checking for executables
132 * because some mounts show everything as executable and we
133 * still want to use the file name to set the mime type.
135 if (item
->flags
& ITEM_FLAG_SYMLINK
)
138 link_path
= readlink_dup(path
);
139 item
->mime_type
= type_from_path(link_path
145 item
->mime_type
= type_from_path(path
);
147 /* Note: for symlinks we need the mode of the target */
148 if (info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))
150 /* Note that the flag is set for ALL executable
151 * files, but the mime_type is only special_exec
152 * if the file doesn't have a known extension when
153 * that option is in force.
155 item
->flags
|= ITEM_FLAG_EXEC_FILE
;
157 if (!o_ignore_exec
.int_value
)
158 item
->mime_type
= special_exec
;
161 if (!item
->mime_type
)
162 item
->mime_type
= item
->flags
& ITEM_FLAG_EXEC_FILE
166 check_globicon(path
, item
);
169 check_globicon(path
, item
);
172 if (!item
->mime_type
)
173 item
->mime_type
= mime_type_from_base_type(item
->base_type
);
177 if (item
->base_type
== TYPE_ERROR
)
179 item
->image
= im_error
;
180 g_object_ref(im_error
);
183 item
->image
= type_to_icon(item
->mime_type
);
187 DirItem
*diritem_new(const guchar
*leafname
)
191 gboolean all_alpha
= TRUE
;
193 item
= g_new(DirItem
, 1);
194 item
->leafname
= g_strdup(leafname
);
195 item
->may_delete
= FALSE
;
197 item
->base_type
= TYPE_UNKNOWN
;
199 item
->mime_type
= NULL
;
201 for (i
= leafname
; *i
; i
++)
211 item
->leafname_collate
= item
->leafname
;
215 gboolean need_digit_spacer
= FALSE
;
216 gboolean may_need_digit_spacer
= FALSE
;
218 item
->leafname_collate
= g_malloc(strlen(item
->leafname
) + 1);
219 o
= item
->leafname_collate
;
221 for (i
= leafname
; *i
; i
++)
225 if (need_digit_spacer
)
227 need_digit_spacer
= FALSE
;
230 may_need_digit_spacer
= TRUE
;
233 else if (isalpha(*i
))
235 need_digit_spacer
= FALSE
;
236 may_need_digit_spacer
= FALSE
;
239 else if (may_need_digit_spacer
)
241 /* We had a digit more recently than
242 * an alpha. If this thing following this
243 * punctuation is another digit, add a spacer.
245 need_digit_spacer
= TRUE
;
254 void diritem_free(DirItem
*item
)
256 g_return_if_fail(item
!= NULL
);
259 g_object_unref(item
->image
);
261 if (item
->leafname_collate
!= item
->leafname
)
262 g_free(item
->leafname_collate
);
263 g_free(item
->leafname
);
264 item
->leafname
= NULL
;
269 /****************************************************************
270 * INTERNAL FUNCTIONS *
271 ****************************************************************/
273 /* Fill in more details of the DirItem for a directory item.
274 * - Looks for an image (but maybe still NULL on error)
275 * - Updates ITEM_FLAG_APPDIR
277 static void examine_dir(const guchar
*path
, DirItem
*item
)
279 uid_t uid
= item
->uid
;
281 static GString
*tmp
= NULL
;
284 tmp
= g_string_new(NULL
);
286 check_globicon(path
, item
);
288 if (item
->flags
& ITEM_FLAG_MOUNT_POINT
)
289 return; /* Try to avoid automounter problems */
293 * - If it contains a .DirIcon then that's the icon
294 * - If it contains an AppRun then it's an application
295 * - If it contains an AppRun but no .DirIcon then try to
296 * use AppIcon.xpm as the icon.
298 * .DirIcon and AppRun must have the same owner as the
299 * directory itself, to prevent abuse of /tmp, etc.
300 * For symlinks, we want the symlink's owner.
303 g_string_sprintf(tmp
, "%s/.DirIcon", path
);
306 goto no_diricon
; /* Already got an icon */
308 if (mc_lstat(tmp
->str
, &info
) != 0 || info
.st_uid
!= uid
)
309 goto no_diricon
; /* Missing, or wrong owner */
311 if (S_ISLNK(info
.st_mode
) && mc_stat(tmp
->str
, &info
) != 0)
312 goto no_diricon
; /* Bad symlink */
314 if (info
.st_size
> MAX_ICON_SIZE
|| !S_ISREG(info
.st_mode
))
315 goto no_diricon
; /* Too big, or non-regular file */
317 /* Try to load image; may still get NULL... */
318 item
->image
= g_fscache_lookup(pixmap_cache
, tmp
->str
);
322 /* Try to find AppRun... */
323 g_string_truncate(tmp
, tmp
->len
- 8);
324 g_string_append(tmp
, "AppRun");
326 if (mc_lstat(tmp
->str
, &info
) != 0 || info
.st_uid
!= uid
)
327 goto out
; /* Missing, or wrong owner */
329 if (!(info
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
)))
330 goto out
; /* Not executable */
332 item
->flags
|= ITEM_FLAG_APPDIR
;
334 /* Try to load AppIcon.xpm... */
337 goto out
; /* Already got an icon */
339 g_string_truncate(tmp
, tmp
->len
- 3);
340 g_string_append(tmp
, "Icon.xpm");
342 /* Note: since AppRun is valid we don't need to check AppIcon.xpm
346 if (mc_stat(tmp
->str
, &info
) != 0)
347 goto out
; /* Missing, or broken symlink */
349 if (info
.st_size
> MAX_ICON_SIZE
|| !S_ISREG(info
.st_mode
))
350 goto out
; /* Too big, or non-regular file */
352 /* Try to load image; may still get NULL... */
353 item
->image
= g_fscache_lookup(pixmap_cache
, tmp
->str
);
357 if ((item
->flags
& ITEM_FLAG_APPDIR
) && !item
->image
)
359 /* This is an application without an icon */
360 item
->image
= im_appdir
;
361 g_object_ref(item
->image
);