[kdbus] Enable 'initial_read()' - is no longer needed
[platform/upstream/glib.git] / gio / glocalfileinfo.c
index 407067a..7c46837 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Alexander Larsson <alexl@redhat.com>
  */
 
 #include "config.h"
 
+#include <glib.h>
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 #include <fcntl.h>
 #include <errno.h>
-#ifdef HAVE_GRP_H
+#ifdef G_OS_UNIX
 #include <grp.h>
-#endif
-#ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
 #ifdef HAVE_SELINUX
 #include <gfileinfo-priv.h>
 #include <gvfs.h>
 
-#include "glibintl.h"
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#include "glib-unix.h"
+#include "glib-private.h"
+#endif
+
+#include "thumbnail-verify.h"
 
 #ifdef G_OS_WIN32
 #include <windows.h>
@@ -91,6 +92,7 @@
 #include "gioerror.h"
 #include "gthemedicon.h"
 #include "gcontenttypeprivate.h"
+#include "glibintl.h"
 
 
 struct ThumbMD5Context {
@@ -660,6 +662,7 @@ get_xattrs_from_fd (int                    fd,
                g_free (escaped_attr);
              
              get_one_xattr_from_fd (fd, info, gio_attr, attr);
+             g_free (gio_attr);
            }
          
          len = strlen (attr) + 1;
@@ -1094,6 +1097,7 @@ lookup_uid_data (uid_t uid)
       if (pwbufp->pw_name != NULL && pwbufp->pw_name[0] != 0)
        data->user_name = convert_pwd_string_to_utf8 (pwbufp->pw_name);
 
+#ifndef __BIONIC__
       gecos = pwbufp->pw_gecos;
 
       if (gecos)
@@ -1103,6 +1107,7 @@ lookup_uid_data (uid_t uid)
            *comma = 0;
          data->real_name = convert_pwd_string_to_utf8 (gecos);
        }
+#endif
     }
 
   /* Default fallbacks */
@@ -1247,17 +1252,17 @@ get_content_type (const char          *basename,
            sniff_length = 4096;
 
 #ifdef O_NOATIME         
-          fd = open (path, O_RDONLY | O_NOATIME);
+          fd = g_open (path, O_RDONLY | O_NOATIME, 0);
           if (fd < 0 && errno == EPERM)
 #endif
-           fd = open (path, O_RDONLY);
+           fd = g_open (path, O_RDONLY, 0);
 
          if (fd != -1)
            {
              ssize_t res;
              
              res = read (fd, sniff_buffer, sniff_length);
-             close (fd);
+             (void) g_close (fd, NULL);
              if (res >= 0)
                {
                  g_free (content_type);
@@ -1272,9 +1277,11 @@ get_content_type (const char          *basename,
   
 }
 
+/* @stat_buf is the pre-calculated result of stat(path), or %NULL if that failed. */
 static void
-get_thumbnail_attributes (const char *path,
-                          GFileInfo  *info)
+get_thumbnail_attributes (const char     *path,
+                          GFileInfo      *info,
+                          const GLocalFileStat *stat_buf)
 {
   GChecksum *checksum;
   char *uri;
@@ -1285,32 +1292,53 @@ get_thumbnail_attributes (const char *path,
 
   checksum = g_checksum_new (G_CHECKSUM_MD5);
   g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
-  
-  g_free (uri);
 
   basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
   g_checksum_free (checksum);
 
   filename = g_build_filename (g_get_user_cache_dir (),
-                               "thumbnails", "normal", basename,
+                               "thumbnails", "large", basename,
                                NULL);
 
   if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
-    _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename);
+    {
+      _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename);
+      _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID,
+                                                thumbnail_verify (filename, uri, stat_buf));
+    }
   else
     {
       g_free (filename);
       filename = g_build_filename (g_get_user_cache_dir (),
-                                   "thumbnails", "fail",
-                                   "gnome-thumbnail-factory",
-                                   basename,
+                                   "thumbnails", "normal", basename,
                                    NULL);
 
       if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
-       _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED, TRUE);
+        {
+          _g_file_info_set_attribute_byte_string_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH, filename);
+          _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID,
+                                                    thumbnail_verify (filename, uri, stat_buf));
+        }
+      else
+        {
+          g_free (filename);
+          filename = g_build_filename (g_get_user_cache_dir (),
+                                       "thumbnails", "fail",
+                                       "gnome-thumbnail-factory",
+                                       basename,
+                                       NULL);
+
+          if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+            {
+              _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED, TRUE);
+              _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID,
+                                                        thumbnail_verify (filename, uri, stat_buf));
+            }
+        }
     }
   g_free (basename);
   g_free (filename);
+  g_free (uri);
 }
 
 #ifdef G_OS_WIN32
@@ -1405,6 +1433,109 @@ win32_get_file_user_info (const gchar  *filename,
 }
 #endif /* G_OS_WIN32 */
 
+#ifndef G_OS_WIN32
+/* support for '.hidden' files */
+G_LOCK_DEFINE_STATIC (hidden_cache);
+static GHashTable *hidden_cache;
+
+static gboolean
+remove_from_hidden_cache (gpointer user_data)
+{
+  G_LOCK (hidden_cache);
+  g_hash_table_remove (hidden_cache, user_data);
+  G_UNLOCK (hidden_cache);
+
+  return FALSE;
+}
+
+static GHashTable *
+read_hidden_file (const gchar *dirname)
+{
+  gchar *contents = NULL;
+  gchar *filename;
+
+  filename = g_build_path ("/", dirname, ".hidden", NULL);
+  (void) g_file_get_contents (filename, &contents, NULL, NULL);
+  g_free (filename);
+
+  if (contents != NULL)
+    {
+      GHashTable *table;
+      gchar **lines;
+      gint i;
+
+      table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+      lines = g_strsplit (contents, "\n", 0);
+      g_free (contents);
+
+      for (i = 0; lines[i]; i++)
+        /* hash table takes the individual strings... */
+        g_hash_table_add (table, lines[i]);
+
+      /* ... so we only free the container. */
+      g_free (lines);
+
+      return table;
+    }
+  else
+    return NULL;
+}
+
+static void
+maybe_unref_hash_table (gpointer data)
+{
+  if (data != NULL)
+    g_hash_table_unref (data);
+}
+
+static gboolean
+file_is_hidden (const gchar *path,
+                const gchar *basename)
+{
+  gboolean result;
+  gchar *dirname;
+  gpointer table;
+
+  dirname = g_path_get_dirname (path);
+
+  G_LOCK (hidden_cache);
+
+  if G_UNLIKELY (hidden_cache == NULL)
+    hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                          g_free, maybe_unref_hash_table);
+
+  if (!g_hash_table_lookup_extended (hidden_cache, dirname,
+                                     NULL, &table))
+    {
+      gchar *mydirname;
+      GSource *remove_from_cache_source;
+
+      g_hash_table_insert (hidden_cache,
+                           mydirname = g_strdup (dirname),
+                           table = read_hidden_file (dirname));
+
+      remove_from_cache_source = g_timeout_source_new_seconds (5);
+      g_source_set_priority (remove_from_cache_source, G_PRIORITY_DEFAULT);
+      g_source_set_callback (remove_from_cache_source, 
+                             remove_from_hidden_cache, 
+                             mydirname, 
+                             NULL);
+      g_source_attach (remove_from_cache_source, 
+                       GLIB_PRIVATE_CALL (g_get_worker_context) ());
+      g_source_unref (remove_from_cache_source);
+    }
+
+  result = table != NULL && g_hash_table_contains (table, basename);
+
+  G_UNLOCK (hidden_cache);
+
+  g_free (dirname);
+
+  return result;
+}
+#endif /* !G_OS_WIN32 */
+
 void
 _g_local_file_info_get_nostat (GFileInfo              *info,
                                const char             *basename,
@@ -1448,6 +1579,96 @@ _g_local_file_info_get_nostat (GFileInfo              *info,
     }
 }
 
+static const char *
+get_icon_name (const char *path,
+               const char *content_type,
+               gboolean    use_symbolic,
+               gboolean   *with_fallbacks_out)
+{
+  const char *name = NULL;
+  gboolean with_fallbacks = TRUE;
+
+  if (strcmp (path, g_get_home_dir ()) == 0)
+    {
+      name = use_symbolic ? "user-home-symbolic" : "user-home";
+      with_fallbacks = FALSE;
+    }
+  else if (strcmp (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
+    {
+      name = use_symbolic ? "user-desktop-symbolic" : "user-desktop";
+      with_fallbacks = FALSE;
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0)
+    {
+      name = use_symbolic ? "folder-documents-symbolic" : "folder-documents";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0)
+    {
+      name = use_symbolic ? "folder-download-symbolic" : "folder-download";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0)
+    {
+      name = use_symbolic ? "folder-music-symbolic" : "folder-music";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0)
+    {
+      name = use_symbolic ? "folder-pictures-symbolic" : "folder-pictures";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0)
+    {
+      name = use_symbolic ? "folder-publicshare-symbolic" : "folder-publicshare";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0)
+    {
+      name = use_symbolic ? "folder-templates-symbolic" : "folder-templates";
+    }
+  else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0)
+    {
+      name = use_symbolic ? "folder-videos-symbolic" : "folder-videos";
+    }
+  else if (g_strcmp0 (content_type, "inode/directory") == 0)
+    {
+      name = use_symbolic ? "folder-symbolic" : "folder";
+    }
+  else
+    {
+      name = NULL;
+    }
+
+  if (with_fallbacks_out != NULL)
+    *with_fallbacks_out = with_fallbacks;
+
+  return name;
+}
+
+static GIcon *
+get_icon (const char *path,
+          const char *content_type,
+          gboolean    use_symbolic)
+{
+  GIcon *icon = NULL;
+  const char *icon_name;
+  gboolean with_fallbacks;
+
+  icon_name = get_icon_name (path, content_type, use_symbolic, &with_fallbacks);
+  if (icon_name != NULL)
+    {
+      if (with_fallbacks)
+        icon = g_themed_icon_new_with_default_fallbacks (icon_name);
+      else
+        icon = g_themed_icon_new (icon_name);
+    }
+  else
+    {
+      if (use_symbolic)
+        icon = g_content_type_get_symbolic_icon (content_type);
+      else
+        icon = g_content_type_get_icon (content_type);
+    }
+
+  return icon;
+}
+
 GFileInfo *
 _g_local_file_info_get (const char             *basename,
                        const char             *path,
@@ -1569,9 +1790,20 @@ _g_local_file_info_get (const char             *basename,
   if (stat_ok)
     set_info_from_stat (info, &statbuf, attribute_matcher);
 
-#ifndef G_OS_WIN32
-  if (basename != NULL && basename[0] == '.')
+#ifdef G_OS_UNIX
+  if (stat_ok && _g_local_file_is_lost_found_dir (path, statbuf.st_dev))
     g_file_info_set_is_hidden (info, TRUE);
+#endif
+
+#ifndef G_OS_WIN32
+  if (_g_file_attribute_matcher_matches_id (attribute_matcher,
+                                           G_FILE_ATTRIBUTE_ID_STANDARD_IS_HIDDEN))
+    {
+      if (basename != NULL &&
+          (basename[0] == '.' ||
+           file_is_hidden (path, basename)))
+        g_file_info_set_is_hidden (info, TRUE);
+    }
 
   if (basename != NULL && basename[strlen (basename) -1] == '~' &&
       (stat_ok && S_ISREG (statbuf.st_mode)))
@@ -1601,7 +1833,9 @@ _g_local_file_info_get (const char             *basename,
   if (_g_file_attribute_matcher_matches_id (attribute_matcher,
                                            G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
       _g_file_attribute_matcher_matches_id (attribute_matcher,
-                                           G_FILE_ATTRIBUTE_ID_STANDARD_ICON))
+                                           G_FILE_ATTRIBUTE_ID_STANDARD_ICON) ||
+      _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                           G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
     {
       char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, FALSE);
 
@@ -1610,47 +1844,28 @@ _g_local_file_info_get (const char             *basename,
          g_file_info_set_content_type (info, content_type);
 
          if (_g_file_attribute_matcher_matches_id (attribute_matcher,
-                                                   G_FILE_ATTRIBUTE_ID_STANDARD_ICON))
+                                                     G_FILE_ATTRIBUTE_ID_STANDARD_ICON)
+               || _g_file_attribute_matcher_matches_id (attribute_matcher,
+                                                        G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
            {
              GIcon *icon;
 
-              if (strcmp (path, g_get_home_dir ()) == 0)
-                icon = g_themed_icon_new ("user-home");
-              else if (strcmp (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
-                icon = g_themed_icon_new ("user-desktop");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-documents");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-download");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-music");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-pictures");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-publicshare");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-templates");
-              else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0)
-                icon = g_themed_icon_new_with_default_fallbacks ("folder-videos");
-              else
+              /* non symbolic icon */
+              icon = get_icon (path, content_type, FALSE);
+              if (icon != NULL)
                 {
-                  icon = g_content_type_get_icon (content_type);
-                  if (G_IS_THEMED_ICON (icon))
-                    {
-                      const char *type_icon = NULL;
-
-                      if (S_ISDIR (statbuf.st_mode)) 
-                        type_icon = "folder";
-                      if (type_icon)
-                        g_themed_icon_append_name (G_THEMED_ICON (icon), type_icon);
-                    }
+                  g_file_info_set_icon (info, icon);
+                  g_object_unref (icon);
                 }
 
+              /* symbolic icon */
+              icon = get_icon (path, content_type, TRUE);
               if (icon != NULL)
                 {
-                  g_file_info_set_icon (info, icon);
+                  g_file_info_set_symbolic_icon (info, icon);
                   g_object_unref (icon);
                 }
+
            }
          
          g_free (content_type);
@@ -1731,7 +1946,12 @@ _g_local_file_info_get (const char             *basename,
 
   if (_g_file_attribute_matcher_matches_id (attribute_matcher,
                                            G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH))
-    get_thumbnail_attributes (path, info);
+    {
+      if (stat_ok)
+          get_thumbnail_attributes (path, info, &statbuf);
+      else
+          get_thumbnail_attributes (path, info, NULL);
+    }
 
   vfs = g_vfs_get_default ();
   class = G_VFS_GET_CLASS (vfs);
@@ -1934,7 +2154,7 @@ set_unix_mode (char                       *filename,
   return TRUE;
 }
 
-#ifdef HAVE_CHOWN
+#ifdef G_OS_UNIX
 static gboolean
 set_unix_uid_gid (char                       *filename,
                  const GFileAttributeValue  *uid_value,
@@ -2218,7 +2438,7 @@ _g_local_file_info_set_attribute (char                 *filename,
   if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
     return set_unix_mode (filename, flags, &value, error);
   
-#ifdef HAVE_CHOWN
+#ifdef G_OS_UNIX
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0)
     return set_unix_uid_gid (filename, &value, NULL, flags, error);
   else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0)
@@ -2295,13 +2515,11 @@ _g_local_file_info_set_attributes  (char                 *filename,
                                    GError              **error)
 {
   GFileAttributeValue *value;
-#ifdef HAVE_CHOWN
+#ifdef G_OS_UNIX
   GFileAttributeValue *uid, *gid;
-#endif
 #ifdef HAVE_UTIMES
   GFileAttributeValue *mtime, *mtime_usec, *atime, *atime_usec;
 #endif
-#if defined (HAVE_CHOWN) || defined (HAVE_UTIMES)
   GFileAttributeStatus status;
 #endif
   gboolean res;
@@ -2331,7 +2549,7 @@ _g_local_file_info_set_attributes  (char                 *filename,
     }
 #endif
 
-#ifdef HAVE_CHOWN
+#ifdef G_OS_UNIX
   /* Group uid and gid setting into one call
    * Change ownership before permissions, since ownership changes can
      change permissions (e.g. setuid)