]> Pileus Git - ~andy/gtk/blobdiff - gtk/updateiconcache.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / updateiconcache.c
index 1f748fa6a149eec50feb7652c9a011096e3a151d..effea7c6c605611f497d77b8ec83f515001ab861 100644 (file)
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library 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.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <config.h>
+#include "config.h"
 
 #include <locale.h>
 #include <stdlib.h>
@@ -31,6 +29,7 @@
 #endif
 #include <errno.h>
 #ifdef _MSC_VER
+#include <io.h>
 #include <sys/utime.h>
 #else
 #include <utime.h>
@@ -72,11 +71,11 @@ static gchar *var_name = "-";
 
 #include <ftw.h>
 
-static struct stat cache_stat;
+static GStatBuf cache_stat;
 static gboolean cache_up_to_date;
 
 static int check_dir_mtime (const char        *dir, 
-                            const struct stat *sb,
+                            const GStatBuf    *sb,
                             int                tf)
 {
   if (tf != FTW_NS && sb->st_mtime > cache_stat.st_mtime)
@@ -89,9 +88,9 @@ static int check_dir_mtime (const char        *dir,
   return 0;
 }
 
- gboolean
- is_cache_up_to_date (const gchar *path)
- {
+static gboolean
+is_cache_up_to_date (const gchar *path)
+{
   gchar *cache_path;
   gint retval;
 
@@ -117,7 +116,7 @@ static int check_dir_mtime (const char        *dir,
 gboolean
 is_cache_up_to_date (const gchar *path)
 {
-  struct stat path_stat, cache_stat;
+  GStatBuf path_stat, cache_stat;
   gchar *cache_path;
   int retval; 
   
@@ -488,7 +487,7 @@ maybe_cache_image_data (Image       *image,
          idata2 = g_hash_table_lookup (image_data_hash, path2);
 
          if (idata && idata2 && idata != idata2)
-           g_error (_("different idatas found for symlinked '%s' and '%s'\n"),
+           g_error ("different idatas found for symlinked '%s' and '%s'\n",
                     path, path2);
 
          if (idata && !idata2)
@@ -548,7 +547,7 @@ maybe_cache_icon_data (Image       *image,
          idata2 = g_hash_table_lookup (icon_data_hash, path2);
 
          if (idata && idata2 && idata != idata2)
-           g_error (_("different idatas found for symlinked '%s' and '%s'\n"),
+           g_error ("different idatas found for symlinked '%s' and '%s'\n",
                     path, path2);
 
          if (idata && !idata2)
@@ -575,6 +574,23 @@ maybe_cache_icon_data (Image       *image,
     }
 }
 
+/**
+ * Finds all dir separators and replaces them with '/'.
+ * This makes sure that only /-separated paths are written in cache files,
+ * maintaining compatibility with theme index files that use slashes as
+ * directory separators on all platforms.
+ */
+static void
+replace_backslashes_with_slashes (gchar *path)
+{
+  size_t i;
+  if (path == NULL)
+    return;
+  for (i = 0; path[i]; i++)
+    if (G_IS_DIR_SEPARATOR (path[i]))
+      path[i] = '/';
+}
+
 static GList *
 scan_directory (const gchar *base_path, 
                const gchar *subdir, 
@@ -589,7 +605,7 @@ scan_directory (const gchar *base_path,
   gboolean dir_added = FALSE;
   guint dir_index = 0xffff;
   
-  dir_path = g_build_filename (base_path, subdir, NULL);
+  dir_path = g_build_path ("/", base_path, subdir, NULL);
 
   /* FIXME: Use the gerror */
   dir = g_dir_open (dir_path, 0, NULL);
@@ -608,13 +624,14 @@ scan_directory (const gchar *base_path,
       gchar *basename, *dot;
 
       path = g_build_filename (dir_path, name, NULL);
+
       retval = g_file_test (path, G_FILE_TEST_IS_DIR);
       if (retval)
        {
          gchar *subsubdir;
 
          if (subdir)
-           subsubdir = g_build_filename (subdir, name, NULL);
+           subsubdir = g_build_path ("/", subdir, name, NULL);
          else
            subsubdir = g_strdup (name);
          directories = scan_directory (base_path, subsubdir, files, 
@@ -1094,14 +1111,13 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
       int name_offset;
       int name_size;
       int image_list_offset;
-      int tmp;
       int i, len;
       GList *list;
 
       g_assert (*offset == ftell (cache));
 
       node->offset = *offset;
-         
+
       get_single_node_size (node, &node_size, &image_data_size);
       g_assert (node_size % 4 == 0);
       g_assert (image_data_size % 4 == 0);
@@ -1109,16 +1125,16 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
       next_offset = *offset + node_size + image_data_size;
       /* Chain offset */
       if (node->next != NULL)
-       {
-         if (!write_card32 (cache, next_offset))
-           return FALSE;
-       }
+        {
+          if (!write_card32 (cache, next_offset))
+            return FALSE;
+        }
       else
-       {
-         if (!write_card32 (cache, 0xffffffff))
-           return FALSE;
-       }
-      
+        {
+          if (!write_card32 (cache, 0xffffffff))
+            return FALSE;
+        }
+
       name_size = 0;
       name_offset = find_string (node->name);
       if (name_offset <= 0)
@@ -1128,113 +1144,110 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
           add_string (node->name, name_offset);
         }
       if (!write_card32 (cache, name_offset))
-       return FALSE;
-      
+        return FALSE;
+
       image_list_offset = *offset + 12 + name_size;
       if (!write_card32 (cache, image_list_offset))
-       return FALSE;
-      
+        return FALSE;
+
       /* Icon name */
       if (name_size > 0)
         {
           if (!write_string (cache, node->name))
-           return FALSE;
+            return FALSE;
         }
 
       /* Image list */
       len = g_list_length (node->image_list);
       if (!write_card32 (cache, len))
-       return FALSE;
-      
-      /* Image data goes right after the image list */
-      tmp = image_list_offset + 4 + len * 8;
+        return FALSE;
 
       list = node->image_list;
       data_offset = image_data_offset;
       for (i = 0; i < len; i++)
-       {
-         Image *image = list->data;
-         int image_data_size = get_image_data_size (image);
+        {
+          Image *image = list->data;
+          int image_data_size = get_image_data_size (image);
 
-         /* Directory index */
-         if (!write_card16 (cache, image->dir_index))
-           return FALSE;
-         
-         /* Flags */
-         if (!write_card16 (cache, image->flags))
-           return FALSE;
+          /* Directory index */
+          if (!write_card16 (cache, image->dir_index))
+            return FALSE;
 
-         /* Image data offset */
-         if (image_data_size > 0)
-           {
-             if (!write_card32 (cache, data_offset))
-               return FALSE;
-             data_offset += image_data_size;
-           }
-         else 
-           {
-             if (!write_card32 (cache, 0))
-               return FALSE;
-           }
+          /* Flags */
+          if (!write_card16 (cache, image->flags))
+            return FALSE;
 
-         list = list->next;
-       }
+          /* Image data offset */
+          if (image_data_size > 0)
+            {
+              if (!write_card32 (cache, data_offset))
+                return FALSE;
+              data_offset += image_data_size;
+            }
+          else
+            {
+              if (!write_card32 (cache, 0))
+                return FALSE;
+            }
+
+          list = list->next;
+        }
 
       /* Now write the image data */
       list = node->image_list;
       for (i = 0; i < len; i++, list = list->next)
-       {
-         Image *image = list->data;
-         int pixel_data_size = get_image_pixel_data_size (image);
-         int meta_data_size = get_image_meta_data_size (image);
+        {
+          Image *image = list->data;
+          int pixel_data_size = get_image_pixel_data_size (image);
+          int meta_data_size = get_image_meta_data_size (image);
 
-         if (get_image_data_size (image) == 0)
-           continue;
+          if (get_image_data_size (image) == 0)
+            continue;
 
-         /* Pixel data */
-         if (pixel_data_size > 0) 
-           {
-             image->image_data->offset = image_data_offset + 8;
-             if (!write_card32 (cache, image->image_data->offset))
-               return FALSE;
-           }
-         else
-           {
-             if (!write_card32 (cache, (guint32) image->image_data ? image->image_data->offset : 0))
-               return FALSE;
-           }
+          /* Pixel data */
+          if (pixel_data_size > 0)
+            {
+              image->image_data->offset = image_data_offset + 8;
+              if (!write_card32 (cache, image->image_data->offset))
+                return FALSE;
+            }
+          else
+            {
+              if (!write_card32 (cache, (guint32) (image->image_data ? image->image_data->offset : 0)))
+                return FALSE;
+            }
 
-         if (meta_data_size > 0)
-           {
-             image->icon_data->offset = image_data_offset + pixel_data_size + 8;
-             if (!write_card32 (cache, image->icon_data->offset))
-               return FALSE;
-           }
-         else
-           {
-             if (!write_card32 (cache, image->icon_data ? image->icon_data->offset : 0))
-               return FALSE;
-           }
+          if (meta_data_size > 0)
+            {
+              image->icon_data->offset = image_data_offset + pixel_data_size + 8;
+              if (!write_card32 (cache, image->icon_data->offset))
+                return FALSE;
+            }
+          else
+            {
+              if (!write_card32 (cache, image->icon_data ? image->icon_data->offset : 0))
+                return FALSE;
+            }
 
-         if (pixel_data_size > 0)
-           {
-             if (!write_image_data (cache, image->image_data, image->image_data->offset))
-               return FALSE;
-           }
-         
-         if (meta_data_size > 0)
-           {
+          if (pixel_data_size > 0)
+            {
+              if (!write_image_data (cache, image->image_data, image->image_data->offset))
+                return FALSE;
+            }
+
+          if (meta_data_size > 0)
+            {
               if (!write_icon_data (cache, image->icon_data, image->icon_data->offset))
                 return FALSE;
             }
 
-         image_data_offset += pixel_data_size + meta_data_size + 8;
-       }
-      
+          image_data_offset += pixel_data_size + meta_data_size + 8;
+        }
+
       *offset = next_offset;
       node = node->next;
     }
-  
+
   return TRUE;
 }
 
@@ -1414,15 +1427,41 @@ validate_file (const gchar *file)
 
   if (!_gtk_icon_cache_validate (&info)) 
     {
-      g_mapped_file_free (map);
+      g_mapped_file_unref (map);
       return FALSE;
     }
   
-  g_mapped_file_free (map);
+  g_mapped_file_unref (map);
 
   return TRUE;
 }
 
+/**
+ * safe_fclose:
+ * @f: A FILE* stream, must have underlying fd
+ *
+ * Unix defaults for data preservation after system crash
+ * are unspecified, and many systems will eat your data
+ * in this situation unless you explicitly fsync().
+ *
+ * Returns: %TRUE on success, %FALSE on failure, and will set errno()
+ */
+static gboolean
+safe_fclose (FILE *f)
+{
+  int fd = fileno (f);
+  g_assert (fd >= 0);
+  if (fflush (f) == EOF)
+    return FALSE;
+#ifndef G_OS_WIN32
+  if (fsync (fd) < 0)
+    return FALSE;
+#endif
+  if (fclose (f) == EOF)
+    return FALSE;
+  return TRUE;
+}
+
 static void
 build_cache (const gchar *path)
 {
@@ -1431,18 +1470,33 @@ build_cache (const gchar *path)
   gchar *bak_cache_path = NULL;
 #endif
   GHashTable *files;
-  gboolean retval;
   FILE *cache;
-  struct stat path_stat, cache_stat;
+  GStatBuf path_stat, cache_stat;
   struct utimbuf utime_buf;
   GList *directories = NULL;
   int fd;
+  int retry_count = 0;
+#ifndef G_OS_WIN32
   mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
-  
+#else
+  int mode = _S_IWRITE | _S_IREAD;
+#endif
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+
   tmp_cache_path = g_build_filename (path, "."CACHE_NAME, NULL);
+  cache_path = g_build_filename (path, CACHE_NAME, NULL);
 
-  if ((fd = open (tmp_cache_path, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, mode)) == -1)
+opentmp:
+  if ((fd = g_open (tmp_cache_path, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | _O_BINARY, mode)) == -1)
     {
+      if (force_update && retry_count == 0)
+        {
+          retry_count++;
+          g_remove (tmp_cache_path);
+          goto opentmp;
+        }
       g_printerr (_("Failed to open file %s : %s\n"), tmp_cache_path, g_strerror (errno));
       exit (1);
     }
@@ -1467,34 +1521,35 @@ build_cache (const gchar *path)
       /* Empty table, just close and remove the file */
 
       fclose (cache);
-      close (fd);
       g_unlink (tmp_cache_path);
+      g_unlink (cache_path);
       exit (0);
     }
     
   /* FIXME: Handle failure */
-  retval = write_file (cache, files, directories);
-  fclose (cache);
-  close (fd);
+  if (!write_file (cache, files, directories))
+    {
+      g_unlink (tmp_cache_path);
+      exit (1);
+    }
 
-  g_list_foreach (directories, (GFunc)g_free, NULL);
-  g_list_free (directories);
-  
-  if (!retval)
+  if (!safe_fclose (cache))
     {
+      g_printerr (_("Failed to write cache file: %s\n"), g_strerror (errno));
       g_unlink (tmp_cache_path);
       exit (1);
     }
+  cache = NULL;
+
+  g_list_free_full (directories, g_free);
 
   if (!validate_file (tmp_cache_path))
     {
       g_printerr (_("The generated cache was invalid.\n"));
-      //g_unlink (tmp_cache_path);
+      /*g_unlink (tmp_cache_path);*/
       exit (1);
     }
 
-  cache_path = g_build_filename (path, CACHE_NAME, NULL);
-
 #ifdef G_OS_WIN32
   if (g_file_test (cache_path, G_FILE_TEST_EXISTS))
     {
@@ -1502,9 +1557,11 @@ build_cache (const gchar *path)
       g_unlink (bak_cache_path);
       if (g_rename (cache_path, bak_cache_path) == -1)
        {
+          int errsv = errno;
+
          g_printerr (_("Could not rename %s to %s: %s, removing %s then.\n"),
                      cache_path, bak_cache_path,
-                     g_strerror (errno),
+                     g_strerror (errsv),
                      cache_path);
          g_unlink (cache_path);
          bak_cache_path = NULL;
@@ -1514,16 +1571,22 @@ build_cache (const gchar *path)
 
   if (g_rename (tmp_cache_path, cache_path) == -1)
     {
+      int errsv = errno;
+
       g_printerr (_("Could not rename %s to %s: %s\n"),
                  tmp_cache_path, cache_path,
-                 g_strerror (errno));
+                 g_strerror (errsv));
       g_unlink (tmp_cache_path);
 #ifdef G_OS_WIN32
       if (bak_cache_path != NULL)
        if (g_rename (bak_cache_path, cache_path) == -1)
-         g_printerr (_("Could not rename %s back to %s: %s.\n"),
-                     bak_cache_path, cache_path,
-                     g_strerror (errno));
+          {
+            errsv = errno;
+
+            g_printerr (_("Could not rename %s back to %s: %s.\n"),
+                        bak_cache_path, cache_path,
+                        g_strerror (errsv));
+          }
 #endif
       exit (1);
     }
@@ -1540,8 +1603,12 @@ build_cache (const gchar *path)
 
   utime_buf.actime = path_stat.st_atime;
   utime_buf.modtime = cache_stat.st_mtime;
+#if GLIB_CHECK_VERSION (2, 17, 1)
+  g_utime (path, &utime_buf);
+#else
   utime (path, &utime_buf);
-  
+#endif
+
   if (!quiet)
     g_printerr (_("Cache file created successfully.\n"));
 }
@@ -1630,8 +1697,12 @@ main (int argc, char **argv)
   
   setlocale (LC_ALL, "");
 
+#ifdef ENABLE_NLS
   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+#endif
 
   context = g_option_context_new ("ICONPATH");
   g_option_context_add_main_entries (context, args, GETTEXT_PACKAGE);
@@ -1669,7 +1740,7 @@ main (int argc, char **argv)
     {
       if (path)
        {
-         g_printerr (_("No theme index file."));
+         g_printerr (_("No theme index file.\n"));
        }
       else
        {
@@ -1683,7 +1754,7 @@ main (int argc, char **argv)
   if (!force_update && is_cache_up_to_date (path))
     return 0;
 
-  g_type_init ();
+  replace_backslashes_with_slashes (path);
   build_cache (path);
 
   if (strcmp (var_name, "-") != 0)