/* $Id$ * UDP Gateway single-file bundle utility functions * Copyright (C) 2004 Jan Kratochvil * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; exactly version 2 of June 1991 is required * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "bundle-util.h" /* self */ #include "bundle.h" #include "main.h" static G_CONST_RETURN guint8 *bundle_util_file_retrieve(guint32 *data_length_return,const gchar *basename) { const guint8 *data; g_return_val_if_fail(data_length_return!=NULL,NULL); g_return_val_if_fail(basename!=NULL,NULL); if (optarg_verbose) g_message(_("Retrieving internally stored: %s"),basename); data=g_hash_table_lookup(bundle_hash_new(),basename); g_return_val_if_fail(data!=NULL,NULL); *data_length_return=GUINT32_FROM_BE(*(guint32 *)data); data+=sizeof(*data_length_return); return data; } /* Returns TRUE if it safe to overwrite/unlink the file. */ static gboolean bundle_util_file_backup_conditional(const gchar *pathname,const gchar *basename) { const guint8 *data; guint32 data_length; int fd; guint8 *data_found; int got; char strftime_buffer[LINE_MAX]; const gchar *destination; time_t time_current; g_return_val_if_fail(pathname!=NULL,FALSE); g_return_val_if_fail(basename!=NULL,FALSE); if (!(data=bundle_util_file_retrieve(&data_length,basename))) return FALSE; if (-1==(fd=open(pathname,O_RDONLY))) { if (errno==ENOENT) return TRUE; else { g_warning(_("Error checking file modifications of \"%s\": %m"),pathname); return FALSE; } } /* WARNING: 'data_found' allocated in this block! */ data_found=g_malloc(data_length+1); if (-1==(got=read(fd,data_found,data_length+1))) g_warning(_("Error reading during the check of file modifications of \"%s\": %m"),pathname); if (close(fd)) g_warning(_("Error closing the file \"%s\" during the check of its modifications: %m"),pathname); /* memcmp(3) requires 'data_found'! */ if (got==(int)data_length && !memcmp(data_found,data,data_length)) { g_free(data_found); return TRUE; } g_free(data_found); time_current=time(NULL); /* It is segfault to gmtime(NULL). */ if (!strftime(strftime_buffer,sizeof(strftime_buffer),"GMT%FT%T",gmtime(&time_current))) { g_warning("strftime(3): %m"); /* shouldn't happen */ return FALSE; } destination=udpgate_printf_alloca("%s-%s-%d",pathname,strftime_buffer,(int)getpid()); if (rename(pathname,destination)) { g_warning(_("Error renaming your modified file \"%s\" to the backup \"%s\", giving up: %m"), pathname,destination); return FALSE; } return TRUE; } gboolean bundle_util_file_remove(const gchar *pathname,const gchar *basename) { g_return_val_if_fail(pathname!=NULL,FALSE); g_return_val_if_fail(basename!=NULL,FALSE); if (!bundle_util_file_backup_conditional(pathname,basename)) return FALSE; if (unlink(pathname) && errno!=ENOENT) { g_warning(_("Error removing the file \"%s\": %m"),pathname); return FALSE; } return TRUE; } gboolean bundle_util_file_write(const gchar *pathname,const gchar *basename,mode_t pathname_mode,gboolean pathname_backup) { const guint8 *data; guint32 data_length; int fd; g_return_val_if_fail(pathname!=NULL,FALSE); g_return_val_if_fail(basename!=NULL,FALSE); if (!(data=bundle_util_file_retrieve(&data_length,basename))) return FALSE; if (pathname_backup && !bundle_util_file_backup_conditional(pathname,basename)) return FALSE; if (-1==(fd=open(pathname,O_WRONLY|O_CREAT|O_TRUNC,pathname_mode))) { g_warning(_("Error opening the file \"%s\" for rewrite: %m"),pathname); return FALSE; } if ((int)data_length!=write(fd,data,data_length)) { g_warning(_("Error writing the data of the file \"%s\" being overwritten: %m"),pathname); close(fd); /* errors ignored */ return FALSE; } if (close(fd)) { g_warning(_("Error closing the file \"%s\" after its rewrite: %m"),pathname); return FALSE; } return TRUE; }