357 lines
9.3 KiB
C
357 lines
9.3 KiB
C
/* $Id$ */
|
|
/* Copyright (c) 2012-2015 Pierre Pronchery <khorben@defora.org> */
|
|
/* This file is part of DeforaOS Desktop Browser */
|
|
/* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the authors nor the names of the contributors may be
|
|
* used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
|
|
|
|
|
|
|
#if defined(__sun)
|
|
# include <fcntl.h>
|
|
# include <unistd.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <libgen.h>
|
|
#include "../include/Browser/vfs.h"
|
|
|
|
|
|
/* public */
|
|
/* functions */
|
|
/* accessors */
|
|
/* browser_vfs_is_mountpoint */
|
|
int browser_vfs_is_mountpoint(struct stat * lst, dev_t parent)
|
|
{
|
|
return (lst->st_dev != parent) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/* useful */
|
|
/* browser_vfs_lstat */
|
|
int browser_vfs_lstat(char const * filename, struct stat * st)
|
|
{
|
|
return lstat(filename, st);
|
|
}
|
|
|
|
|
|
/* browser_vfs_closedir */
|
|
int browser_vfs_closedir(DIR * dir)
|
|
{
|
|
return closedir(dir);
|
|
}
|
|
|
|
|
|
/* browser_vfs_mime_icon */
|
|
static GdkPixbuf * _mime_icon_emblem(GdkPixbuf * pixbuf, int size,
|
|
char const * emblem);
|
|
static GdkPixbuf * _mime_icon_folder(Mime * mime, char const * filename,
|
|
struct stat * lst, struct stat * st, int size);
|
|
static gboolean _mime_icon_folder_in_home(struct stat * pst);
|
|
static gboolean _mime_icon_folder_is_home(struct stat * st);
|
|
|
|
GdkPixbuf * browser_vfs_mime_icon(Mime * mime, char const * filename,
|
|
char const * type, struct stat * lst, struct stat * st,
|
|
int size)
|
|
{
|
|
GdkPixbuf * ret = NULL;
|
|
mode_t mode = (lst != NULL) ? lst->st_mode : 0;
|
|
struct stat s;
|
|
char const * emblem;
|
|
|
|
if(filename == NULL)
|
|
return NULL;
|
|
if(type == NULL)
|
|
type = browser_vfs_mime_type(mime, filename,
|
|
S_ISLNK(mode) ? 0 : mode);
|
|
if(st == NULL && browser_vfs_stat(filename, &s) == 0)
|
|
st = &s;
|
|
if(S_ISDIR(mode) || (st != NULL && S_ISDIR(st->st_mode)))
|
|
ret = _mime_icon_folder(mime, filename, lst, st, size);
|
|
else if(S_ISLNK(mode) && (st != NULL && S_ISDIR(st->st_mode)))
|
|
ret = _mime_icon_folder(mime, filename, lst, st, size);
|
|
else
|
|
mime_icons(mime, type, size, &ret, -1);
|
|
if(ret == NULL || lst == NULL)
|
|
return ret;
|
|
/* determine the emblem */
|
|
if(S_ISCHR(lst->st_mode) || S_ISBLK(lst->st_mode))
|
|
emblem = "emblem-system";
|
|
else if(S_ISLNK(lst->st_mode))
|
|
emblem = "emblem-symbolic-link";
|
|
else if((lst->st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0)
|
|
emblem = "emblem-unreadable";
|
|
else if((lst->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0)
|
|
emblem = "emblem-readonly";
|
|
else
|
|
emblem = NULL;
|
|
/* apply the emblem if relevant */
|
|
if(emblem != NULL)
|
|
ret = _mime_icon_emblem(ret, size, emblem);
|
|
return ret;
|
|
}
|
|
|
|
static GdkPixbuf * _mime_icon_emblem(GdkPixbuf * pixbuf, int size,
|
|
char const * emblem)
|
|
{
|
|
int esize;
|
|
GdkPixbuf * epixbuf;
|
|
GtkIconTheme * icontheme;
|
|
#if GTK_CHECK_VERSION(2, 14, 0)
|
|
const unsigned int flags = GTK_ICON_LOOKUP_USE_BUILTIN
|
|
| GTK_ICON_LOOKUP_FORCE_SIZE;
|
|
#else
|
|
const unsigned int flags = GTK_ICON_LOOKUP_USE_BUILTIN;
|
|
#endif
|
|
|
|
/* work on a copy */
|
|
epixbuf = gdk_pixbuf_copy(pixbuf);
|
|
g_object_unref(pixbuf);
|
|
pixbuf = epixbuf;
|
|
/* determine the size of the emblem */
|
|
if(size >= 96)
|
|
esize = 32;
|
|
else if(size >= 48)
|
|
esize = 24;
|
|
else
|
|
esize = 12;
|
|
/* obtain the emblem's icon */
|
|
icontheme = gtk_icon_theme_get_default();
|
|
if((epixbuf = gtk_icon_theme_load_icon(icontheme, emblem, esize, flags,
|
|
NULL)) == NULL)
|
|
return pixbuf;
|
|
/* blit the emblem */
|
|
#if 0 /* XXX does not show anything (bottom right) */
|
|
gdk_pixbuf_composite(epixbuf, pixbuf, size - esize, size - esize,
|
|
esize, esize, 0, 0, 1.0, 1.0, GDK_INTERP_NEAREST,
|
|
255);
|
|
#else /* blitting at the top left instead */
|
|
gdk_pixbuf_composite(epixbuf, pixbuf, 0, 0, esize, esize, 0, 0,
|
|
1.0, 1.0, GDK_INTERP_NEAREST, 255);
|
|
#endif
|
|
g_object_unref(epixbuf);
|
|
return pixbuf;
|
|
}
|
|
|
|
static GdkPixbuf * _mime_icon_folder(Mime * mime, char const * filename,
|
|
struct stat * lst, struct stat * st, int size)
|
|
{
|
|
GdkPixbuf * ret = NULL;
|
|
char const * icon = NULL;
|
|
struct stat ls;
|
|
struct stat ps;
|
|
char * p;
|
|
size_t i;
|
|
struct
|
|
{
|
|
char const * name;
|
|
char const * icon;
|
|
} name_icon[] =
|
|
{
|
|
{ "DCIM", "folder-pictures" },
|
|
{ "Desktop", "user-desktop" },
|
|
{ "Documents", "folder-documents" },
|
|
{ "Download", "folder-download" },
|
|
{ "Downloads", "folder-download" },
|
|
{ "Music", "folder-music" },
|
|
{ "Pictures", "folder-pictures" },
|
|
{ "public_html","folder-publicshare" },
|
|
{ "Templates", "folder-templates" },
|
|
{ "Video", "folder-videos" },
|
|
{ "Videos", "folder-videos" },
|
|
};
|
|
GtkIconTheme * icontheme;
|
|
const unsigned int flags = GTK_ICON_LOOKUP_FORCE_SIZE;
|
|
|
|
if(lst == NULL && browser_vfs_lstat(filename, &ls) == 0)
|
|
lst = &ls;
|
|
/* check if the folder is special */
|
|
if((p = strdup(filename)) != NULL
|
|
&& (lst == NULL || !S_ISLNK(lst->st_mode))
|
|
&& st != NULL
|
|
&& browser_vfs_lstat(dirname(p), &ps) == 0)
|
|
{
|
|
if(st->st_dev != ps.st_dev || st->st_ino == ps.st_ino)
|
|
icon = "mount-point";
|
|
else if(_mime_icon_folder_is_home(st))
|
|
icon = "folder_home";
|
|
else if(_mime_icon_folder_in_home(&ps))
|
|
/* check if the folder is special */
|
|
for(i = 0; i < sizeof(name_icon) / sizeof(*name_icon);
|
|
i++)
|
|
if(strcasecmp(basename(p), name_icon[i].name)
|
|
== 0)
|
|
{
|
|
icon = name_icon[i].icon;
|
|
break;
|
|
}
|
|
}
|
|
free(p);
|
|
if(icon != NULL)
|
|
{
|
|
icontheme = gtk_icon_theme_get_default();
|
|
ret = gtk_icon_theme_load_icon(icontheme, icon, size, flags,
|
|
NULL);
|
|
}
|
|
/* generic fallback */
|
|
if(ret == NULL)
|
|
mime_icons(mime, "inode/directory", size, &ret, -1);
|
|
return ret;
|
|
}
|
|
|
|
static gboolean _mime_icon_folder_in_home(struct stat * pst)
|
|
{
|
|
static char const * homedir = NULL;
|
|
static struct stat hst;
|
|
|
|
if(homedir == NULL)
|
|
{
|
|
if((homedir = getenv("HOME")) == NULL
|
|
&& (homedir = g_get_home_dir()) == NULL)
|
|
return FALSE;
|
|
if(browser_vfs_stat(homedir, &hst) != 0)
|
|
{
|
|
homedir = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
return (hst.st_dev == pst->st_dev && hst.st_ino == pst->st_ino)
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
static gboolean _mime_icon_folder_is_home(struct stat * st)
|
|
{
|
|
/* FIXME code duplicated from _mime_icon_folder_in_home() */
|
|
static char const * homedir = NULL;
|
|
static struct stat hst;
|
|
|
|
if(homedir == NULL)
|
|
{
|
|
if((homedir = getenv("HOME")) == NULL
|
|
&& (homedir = g_get_home_dir()) == NULL)
|
|
return FALSE;
|
|
if(browser_vfs_stat(homedir, &hst) != 0)
|
|
{
|
|
homedir = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
return (hst.st_dev == st->st_dev && hst.st_ino == st->st_ino)
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
/* browser_vfs_mime_type */
|
|
char const * browser_vfs_mime_type(Mime * mime, char const * filename,
|
|
mode_t mode)
|
|
{
|
|
char const * ret = NULL;
|
|
struct stat st;
|
|
struct stat pst;
|
|
char * p = NULL;
|
|
|
|
if(mode == 0 && filename != NULL
|
|
&& browser_vfs_lstat(filename, &st) == 0)
|
|
mode = st.st_mode;
|
|
if(S_ISDIR(mode))
|
|
{
|
|
/* look for mountpoints */
|
|
if(filename != NULL && (p = strdup(filename)) != NULL
|
|
&& browser_vfs_lstat(filename, &st) == 0
|
|
&& browser_vfs_lstat(dirname(p), &pst) == 0
|
|
&& (st.st_dev != pst.st_dev
|
|
|| st.st_ino == pst.st_ino))
|
|
ret = "inode/mountpoint";
|
|
else
|
|
ret = "inode/directory";
|
|
free(p);
|
|
return ret;
|
|
}
|
|
else if(S_ISBLK(mode))
|
|
return "inode/blockdevice";
|
|
else if(S_ISCHR(mode))
|
|
return "inode/chardevice";
|
|
else if(S_ISFIFO(mode))
|
|
return "inode/fifo";
|
|
else if(S_ISLNK(mode))
|
|
return "inode/symlink";
|
|
#ifdef S_ISSOCK
|
|
else if(S_ISSOCK(mode))
|
|
return "inode/socket";
|
|
#endif
|
|
if(mime != NULL && filename != NULL)
|
|
ret = mime_type(mime, filename);
|
|
if(ret == NULL && (mode & S_IXUSR) != 0)
|
|
ret = "application/x-executable";
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* browser_vfs_opendir */
|
|
DIR * browser_vfs_opendir(char const * filename, struct stat * st)
|
|
{
|
|
DIR * dir;
|
|
int fd;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s(\"%s\", %p)\n", __func__, filename, st);
|
|
#endif
|
|
if(st == NULL)
|
|
return opendir(filename);
|
|
#if defined(__sun)
|
|
if((fd = open(filename, O_RDONLY)) < 0
|
|
|| (dir = fdopendir(fd)) == NULL)
|
|
{
|
|
if(fd >= 0)
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
#else
|
|
if((dir = opendir(filename)) == NULL)
|
|
return NULL;
|
|
fd = dirfd(dir);
|
|
#endif
|
|
if(fstat(fd, st) != 0)
|
|
{
|
|
browser_vfs_closedir(dir);
|
|
return NULL;
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
|
|
/* browser_vfs_readdir */
|
|
struct dirent * browser_vfs_readdir(DIR * dir)
|
|
{
|
|
return readdir(dir);
|
|
}
|
|
|
|
|
|
/* browser_vfs_stat */
|
|
int browser_vfs_stat(char const * filename, struct stat * st)
|
|
{
|
|
return stat(filename, st);
|
|
}
|