bundle_util_file_write() has now 'flags' parameter.
authorshort <>
Sun, 26 Jun 2005 06:21:17 +0000 (06:21 +0000)
committershort <>
Sun, 26 Jun 2005 06:21:17 +0000 (06:21 +0000)
bundle_util_file_write(): +BUNDLE_UTIL_MKDIRS_MASK
 - Create all intermediate directories to the: pathname
bundle_util_file_write(): +BUNDLE_UTIL_TEMPORARY_MASK
 - Cleanup all the files+intermediate directories at g_atexit() time.

src/bundle-util.c
src/bundle-util.h

index 30e1b77..9200493 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <time.h>
 #include <stdio.h>
+#include <glib/gstrfuncs.h>
 
 #include "bundle-util.h"       /* self */
 #include "bundle.h"
@@ -124,23 +125,132 @@ gboolean bundle_util_file_remove(const gchar *pathname,const gchar *basename)
        return TRUE;
 }
 
-gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode,gboolean pathname_backup)
+struct dir_stack {
+       struct dir_stack *next;
+       gchar *dirname; /* in fact 'pathname' */
+       };
+
+/* Always creates up to 'dirname(pathname)', never 'pathname' itself! */
+static struct dir_stack *pathname_mkdirs(const gchar *pathname,mode_t mode)
+{
+gchar *dirname;
+struct dir_stack *r;
+
+       g_return_val_if_fail(pathname!=NULL,NULL);
+
+       dirname=g_path_get_dirname(pathname);
+       if (!strcmp(dirname,pathname)) {
+               g_free(dirname);
+               dirname=NULL;
+               }
+       if (!dirname)
+               return NULL;
+       r=pathname_mkdirs(dirname,mode);
+       if (mkdir(dirname,mode))
+               g_free(dirname);
+       else {
+struct dir_stack *dir_stack;
+
+               udpgate_new(dir_stack);
+               dir_stack->dirname=dirname;
+               dir_stack->next=r;
+               r=dir_stack;
+               }
+       return r;
+}
+
+static struct dir_stack *bundle_util_file_write_atexit_dir_stack_head;
+struct file_stack {
+       struct file_stack *next;
+       gchar *pathname;
+       gchar *basename;
+       };
+static struct file_stack *bundle_util_file_write_atexit_file_stack_head;
+
+static void bundle_util_file_write_atexit(void)
+{
+struct file_stack *file_stack;
+struct dir_stack *dir_stack;
+
+       /* Always remove files first before their directories! */
+       while ((file_stack=bundle_util_file_write_atexit_file_stack_head)) {
+               /* Errors already reported: */
+               bundle_util_file_remove(file_stack->pathname,file_stack->basename);
+               g_free(file_stack->pathname);
+               g_free(file_stack->basename);
+               bundle_util_file_write_atexit_file_stack_head=file_stack->next;
+               g_free(file_stack);
+               }
+
+       while ((dir_stack=bundle_util_file_write_atexit_dir_stack_head)) {
+               if (rmdir(dir_stack->dirname))
+                       g_warning(_("Error cleaning up created temporary directory: %s"),dir_stack->dirname);
+               g_free(dir_stack->dirname);
+               bundle_util_file_write_atexit_dir_stack_head=dir_stack->next;
+               g_free(dir_stack);
+               }
+}
+
+gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode,
+               enum bundle_util_flags flags)
 {
 const guint8 *data;
 guint32 data_length;
 int fd;
+struct dir_stack *mkdirs=NULL;
+static gboolean atexited=FALSE;
 
        g_return_val_if_fail(pathname!=NULL,FALSE);
        g_return_val_if_fail(basename!=NULL,FALSE);
+       g_return_val_if_fail(flags&(BUNDLE_UTIL_BACKUP_MASK|BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK),FALSE);
+       /* Currently just unsupported: */
+       g_return_val_if_fail((flags&(BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK))!=BUNDLE_UTIL_MKDIRS_MASK,FALSE);
 
        if (!(data=bundle_util_file_retrieve(&data_length,basename)))
                return FALSE;
 
-       if (pathname_backup && !bundle_util_file_backup_conditional(pathname,basename))
+       if ((flags&BUNDLE_UTIL_BACKUP_MASK) && !bundle_util_file_backup_conditional(pathname,basename))
                return FALSE;
+       
+       if (flags&BUNDLE_UTIL_MKDIRS_MASK) {
+mode_t dir_mode=pathname_mode;
+
+               dir_mode|=(pathname_mode&0444)>>2;      /* mode|=('r'->'x') */
+               mkdirs=pathname_mkdirs(pathname,dir_mode);
+               }
+
+       if (!atexited) {
+               atexited=TRUE;
+               g_atexit(bundle_util_file_write_atexit);
+               }
+
+       if (flags&BUNDLE_UTIL_TEMPORARY_MASK) {
+struct dir_stack **mkdirs_tail_pointer;
+struct file_stack *file_stack;
+
+               /* Stack current 'mkdirs' in front of the current: bundle_util_file_write_atexit_dir_stack_head
+                * to remove them in the reverse order than created.
+                * Removal ordering of the current 'mkdirs' stack is preserved
+                * as it is already reversed.
+                */
+               for (mkdirs_tail_pointer=&mkdirs;*mkdirs_tail_pointer;mkdirs_tail_pointer=&(*mkdirs_tail_pointer)->next);
+               *mkdirs_tail_pointer=bundle_util_file_write_atexit_dir_stack_head;
+               bundle_util_file_write_atexit_dir_stack_head=mkdirs;
+               mkdirs=NULL;
+
+               /* Register also the file itself. */
+               udpgate_new(file_stack);
+               file_stack->pathname=g_strdup(pathname);
+               file_stack->basename=g_strdup(basename);
+               file_stack->next=bundle_util_file_write_atexit_file_stack_head;
+               bundle_util_file_write_atexit_file_stack_head=file_stack;
+               }
+       /* Currently just unsupported: */
+       g_assert(!mkdirs);
 
        if (-1==(fd=open(pathname,O_WRONLY|O_CREAT|O_TRUNC,pathname_mode))) {
-               g_warning(_("Error opening the file \"%s\" for rewrite: %m"),pathname);
+               if (errno!=EPERM)
+                       g_warning(_("Error opening the file \"%s\" for rewrite: %m"),pathname);
                return FALSE;
                }
        if ((int)data_length!=write(fd,data,data_length)) {
index cb58855..381e0a8 100644 (file)
 
 G_BEGIN_DECLS
 
+enum bundle_util_flags {
+       BUNDLE_UTIL_BACKUP_BIT,
+#define BUNDLE_UTIL_BACKUP_MASK    (1<<BUNDLE_UTIL_BACKUP_BIT)
+       BUNDLE_UTIL_MKDIRS_BIT,
+#define BUNDLE_UTIL_MKDIRS_MASK    (1<<BUNDLE_UTIL_MKDIRS_BIT)
+       BUNDLE_UTIL_TEMPORARY_BIT,
+#define BUNDLE_UTIL_TEMPORARY_MASK (1<<BUNDLE_UTIL_TEMPORARY_BIT)
+       };
+
 gboolean bundle_util_file_remove(const gchar *pathname,const gchar *basename);
-gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode,gboolean pathname_backup);
+gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode,
+               enum bundle_util_flags flags);
 
 G_END_DECLS