[Gnucash-changes] Remove the file-path utilities from qofsession.c
and move them into a
Linas Vepstas
linas at cvs.gnucash.org
Sun Jun 13 16:01:32 EDT 2004
Log Message:
-----------
Remove the file-path utilities from qofsession.c and move them into
a temp file 'gnc-filepath-utils.c' which is used by both the
file backend and by the app-file GUI routines. Some of the file-resolution
logic was oved to the file backend.
Modified Files:
--------------
gnucash/src/app-file:
gnc-file.c
gnucash/src/backend/file:
gnc-backend-file.c
gnc-backend-file.h
gnucash/src/engine:
Makefile.am
gw-engine-spec.scm
qofbackend-p.h
qofbackend.c
qofsession-p.h
qofsession.c
qofsession.h
gnucash/src/engine/test:
test-resolve-file-path.c
Revision Data
-------------
Index: gnc-file.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-file/gnc-file.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -Lsrc/app-file/gnc-file.c -Lsrc/app-file/gnc-file.c -u -r1.34 -r1.35
--- src/app-file/gnc-file.c
+++ src/app-file/gnc-file.c
@@ -36,6 +36,7 @@
#include "gnc-file-dialog.h"
#include "gnc-file-history.h"
#include "gnc-file-p.h"
+#include "gnc-filepath-utils.h"
#include "gnc-gui-query.h"
#include "gnc-ui.h"
#include "gnc-ui-util.h"
@@ -43,6 +44,7 @@
#include "qofbook.h"
#include "qofsession.h"
#include "messages.h"
+#include "TransLog.h"
/** GLOBALS *********************************************************/
/* This static indicates the debugging module that this .o belongs to. */
@@ -287,7 +289,9 @@
SCM_BOOL_F));
gnc_close_gui_component_by_session (session);
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
/* start a new book */
qof_session_get_current_session ();
@@ -375,7 +379,9 @@
gw_wcp_assimilate_ptr (current_session,
scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
+ xaccLogDisable();
qof_session_destroy (current_session);
+ xaccLogEnable();
/* load the accounts from the users datafile */
/* but first, check to make sure we've got a session going. */
@@ -462,6 +468,11 @@
{
AccountGroup *new_group;
+ char * logpath = xaccResolveFilePath(newfile);
+ PINFO ("logpath=%s", logpath ? logpath : "(null)");
+ xaccLogSetBaseName (logpath);
+ xaccLogDisable();
+
if (file_percentage_func) {
file_percentage_func(_("Reading file..."), 0.0);
qof_session_load (new_session, file_percentage_func);
@@ -469,6 +480,7 @@
} else {
qof_session_load (new_session, NULL);
}
+ xaccLogEnable();
/* check for i/o error, put up appropriate error dialog */
io_err = qof_session_get_error (new_session);
@@ -490,7 +502,9 @@
/* going down -- abandon ship */
if (uh_oh)
{
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
/* well, no matter what, I think it's a good idea to have a
* topgroup around. For example, early in the gnucash startup
@@ -645,7 +659,9 @@
ok = qof_session_export (new_session, current_session, NULL);
}
gnc_unset_busy_cursor (NULL);
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
gnc_engine_resume_events();
if (!ok)
@@ -801,7 +817,9 @@
if (ERR_BACKEND_NO_ERR != io_err)
{
show_session_error (io_err, newfile);
+ xaccLogDisable();
qof_session_destroy (new_session);
+ xaccLogEnable();
g_free (newfile);
return;
}
@@ -809,7 +827,9 @@
/* if we got to here, then we've successfully gotten a new session */
/* close up the old file session (if any) */
qof_session_swap_data (session, new_session);
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
session = NULL;
/* XXX At this point, we should really mark the data in the new session
@@ -859,7 +879,9 @@
gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
SCM_BOOL_F));
+ xaccLogDisable();
qof_session_destroy (session);
+ xaccLogEnable();
qof_session_get_current_session ();
Index: gnc-backend-file.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/gnc-backend-file.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lsrc/backend/file/gnc-backend-file.h -Lsrc/backend/file/gnc-backend-file.h -u -r1.1 -r1.2
--- src/backend/file/gnc-backend-file.h
+++ src/backend/file/gnc-backend-file.h
@@ -57,4 +57,6 @@
GNC_BOOK_XML2_FILE,
} QofBookFileType;
+QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
+
#endif /* GNC_BACKEND_FILE_H_ */
Index: gnc-backend-file.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/file/gnc-backend-file.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -Lsrc/backend/file/gnc-backend-file.c -Lsrc/backend/file/gnc-backend-file.c -u -r1.39 -r1.40
--- src/backend/file/gnc-backend-file.c
+++ src/backend/file/gnc-backend-file.c
@@ -46,6 +46,7 @@
#include "gnc-date.h"
#include "gnc-trace.h"
#include "gnc-engine-util.h"
+#include "gnc-filepath-utils.h"
#include "io-gncxml.h"
#include "io-gncbin.h"
@@ -63,18 +64,6 @@
static int file_retention_days = 0;
static gboolean file_compression = FALSE;
-static void gnc_file_be_load_from_file(QofBackend *, QofBook *);
-
-static gboolean gnc_file_be_get_file_lock (FileBackend *be);
-static gboolean gnc_file_be_write_to_file(FileBackend *be, QofBook *,
- const gchar *filepath,
- gboolean make_backup);
-static void gnc_file_be_write_accounts_to_file(QofBackend *be,
- QofBook *book);
-static void gnc_file_be_remove_old_files(FileBackend *be);
-
-QofBackend * libgncmod_backend_file_LTX_gnc_backend_new(void);
-
void
gnc_file_be_set_retention_days (int days)
{
@@ -89,6 +78,106 @@
/* ================================================================= */
+static gboolean
+gnc_file_be_get_file_lock (FileBackend *be)
+{
+ struct stat statbuf;
+ char pathbuf[PATH_MAX];
+ char *path = NULL;
+ int rc;
+ QofBackendError be_err;
+
+ rc = stat (be->lockfile, &statbuf);
+ if (!rc)
+ {
+ /* oops .. file is locked by another user .. */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ return FALSE;
+ }
+
+ be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
+ if (be->lockfd < 0)
+ {
+ /* oops .. we can't create the lockfile .. */
+ switch (errno) {
+ case EACCES:
+ case EROFS:
+ case ENOSPC:
+ be_err = ERR_BACKEND_READONLY;
+ break;
+ default:
+ be_err = ERR_BACKEND_LOCKED;
+ break;
+ }
+ qof_backend_set_error ((QofBackend*)be, be_err);
+ return FALSE;
+ }
+
+ /* OK, now work around some NFS atomic lock race condition
+ * mumbo-jumbo. We do this by linking a unique file, and
+ * then examing the link count. At least that's what the
+ * NFS programmers guide suggests.
+ * Note: the "unique filename" must be unique for the
+ * triplet filename-host-process, otherwise accidental
+ * aliases can occur.
+ */
+
+ /* apparently, even this code may not work for some NFS
+ * implementations. In the long run, I am told that
+ * ftp.debian.org
+ * /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
+ * provides a better long-term solution.
+ */
+
+ strcpy (pathbuf, be->lockfile);
+ path = strrchr (pathbuf, '.');
+ sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());
+
+ rc = link (be->lockfile, pathbuf);
+ if (rc)
+ {
+ /* If hard links aren't supported, just allow the lock. */
+ if (errno == EOPNOTSUPP || errno == EPERM)
+ {
+ be->linkfile = NULL;
+ return TRUE;
+ }
+
+ /* Otherwise, something else is wrong. */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ rc = stat (be->lockfile, &statbuf);
+ if (rc)
+ {
+ /* oops .. stat failed! This can't happen! */
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ if (statbuf.st_nlink != 2)
+ {
+ qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
+ unlink (pathbuf);
+ close (be->lockfd);
+ unlink (be->lockfile);
+ return FALSE;
+ }
+
+ be->linkfile = g_strdup (pathbuf);
+
+ return TRUE;
+}
+
+/* ================================================================= */
+
static void
file_session_begin(QofBackend *be_start, QofSession *session,
const char *book_id,
@@ -100,8 +189,14 @@
ENTER (" ");
/* Make sure the directory is there */
- be->dirname = g_strdup (qof_session_get_file_path (session));
+ be->dirname = xaccResolveFilePath(book_id);
+ if (NULL == be->dirname)
+ {
+ qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
+ return;
+ }
be->fullpath = g_strdup (be->dirname);
+ be->be.fullpath = be->fullpath;
p = strrchr (be->dirname, '/');
if (p && p != be->dirname)
{
@@ -180,281 +275,103 @@
g_free(be);
}
-static void
-file_sync_all(QofBackend* be, QofBook *book)
+/* ================================================================= */
+/* Write the financial data in a book to a file, returning FALSE on
+ error and setting the error_result to indicate what went wrong if
+ it's not NULL. This function does not manage file locks in any
+ way.
+
+ If make_backup is true, write out a time-stamped copy of the file
+ into the same directory as the indicated file, with a filename of
+ "file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
+ current year/month/day/hour/minute/second. */
+
+static gboolean
+copy_file(const char *orig, const char *bkup)
{
- FileBackend *fbe = (FileBackend *) be;
- ENTER ("book=%p, primary=%p", book, fbe->primary_book);
+ static int buf_size = 1024;
+ char buf[buf_size];
+ int orig_fd;
+ int bkup_fd;
+ ssize_t count_write;
+ ssize_t count_read;
- /* We make an important assumption here, that we might want to change
- * in the future: when the user says 'save', we really save the one,
- * the only, the current open book, and nothing else. We do this
- * because we assume that any other books that we are dealing with
- * are 'read-only', non-editable, because they are closed books.
- * If we ever want to have more than one book open read-write,
- * this will have to change.
- */
- if (NULL == fbe->primary_book) fbe->primary_book = book;
- if (book != fbe->primary_book) return;
+ orig_fd = open(orig, O_RDONLY);
+ if(orig_fd == -1)
+ {
+ return FALSE;
+ }
+ bkup_fd = creat(bkup, 0600);
+ if(bkup_fd == -1)
+ {
+ close(orig_fd);
+ return FALSE;
+ }
- gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
- gnc_file_be_remove_old_files (fbe);
- LEAVE ("book=%p", book);
-}
+ do
+ {
+ count_read = read(orig_fd, buf, buf_size);
+ if(count_read == -1 && errno != EINTR)
+ {
+ close(orig_fd);
+ close(bkup_fd);
+ return FALSE;
+ }
+
+ if(count_read > 0)
+ {
+ count_write = write(bkup_fd, buf, count_read);
+ if(count_write == -1)
+ {
+ close(orig_fd);
+ close(bkup_fd);
+ return FALSE;
+ }
+ }
+ } while(count_read > 0);
+ close(orig_fd);
+ close(bkup_fd);
+
+ return TRUE;
+}
+
/* ================================================================= */
-/* Routines to deal with the creation of multiple books.
- * The core design assumption here is that the book
- * begin-edit/commit-edit routines are used solely to write out
- * closed accounting periods to files. They're not currently
- * designed to do anything other than this. (Although they could be).
- */
-static char *
-build_period_filepath (FileBackend *fbe, QofBook *book)
+static gboolean
+gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
{
- int len;
- char *str, *p, *q;
-
- len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
- str = g_new (char, len);
- strcpy (str, fbe->fullpath);
+ int err_ret = link(orig, bkup);
+ if(err_ret != 0)
+ {
+ if(errno == EPERM || errno == EOPNOTSUPP)
+ {
+ err_ret = copy_file(orig, bkup);
+ }
- /* XXX it would be nice for the user if we made the book
- * closing date and/or title part of the file-name. */
- p = strrchr (str, '/');
- p++;
- p = stpcpy (p, "book-");
- p = guid_to_string_buff (qof_book_get_guid(book), p);
- p = stpcpy (p, "-");
- q = strrchr (fbe->fullpath, '/');
- q++;
- p = stpcpy (p, q);
- p = stpcpy (p, ".gml");
+ if(!err_ret)
+ {
+ qof_backend_set_error((QofBackend*)be, ERR_FILEIO_BACKUP_ERROR);
+ PWARN ("unable to make file backup from %s to %s: %s",
+ orig, bkup, strerror(errno) ? strerror(errno) : "");
+ return FALSE;
+ }
+ }
- return str;
+ return TRUE;
}
-static void
-file_begin_edit (QofBackend *be, QofInstance *inst)
-{
- if (0) build_period_filepath(0, 0);
-#if BORKEN_FOR_NOW
- FileBackend *fbe = (FileBackend *) be;
- QofBook *book = gp;
- const char * filepath;
+/* ================================================================= */
- QofIdTypeConst typ = QOF_ENTITY(inst)->e_type;
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- filepath = build_period_filepath(fbe, book);
- PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+static gboolean
+is_gzipped_file(const gchar *name)
+{
+ unsigned char buf[2];
+ int fd = open(name, O_RDONLY);
- if (NULL == fbe->primary_book)
+ if(fd == 0)
{
- PERR ("You should have saved the data "
- "at least once before closing the books!\n");
- }
- /* XXX To be anal about it, we should really be checking to see
- * if there already is a file with this book GUID, and disallowing
- * further progress. This is because we are not allowed to
- * modify books that are closed (They should be treated as
- * 'read-only').
- */
-#endif
-}
-
-static void
-file_rollback_edit (QofBackend *be, QofInstance *inst)
-{
-#if BORKEN_FOR_NOW
- QofBook *book = gp;
-
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- PINFO ("book=%p", book);
-#endif
-}
-
-static void
-file_commit_edit (QofBackend *be, QofInstance *inst)
-{
-#if BORKEN_FOR_NOW
- FileBackend *fbe = (FileBackend *) be;
- QofBook *book = gp;
- const char * filepath;
-
- if (strcmp (GNC_ID_PERIOD, typ)) return;
- filepath = build_period_filepath(fbe, book);
- PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
- gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
-
- /* We want to force a save of the current book at this point,
- * because if we don't, and the user forgets to do so, then
- * there'll be the same transactions in the closed book,
- * and also in the current book. */
- gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
-#endif
-}
-
-/* ================================================================= */
-
-QofBackend *
-libgncmod_backend_file_LTX_gnc_backend_new(void)
-{
- FileBackend *fbe;
- QofBackend *be;
-
- fbe = g_new0(FileBackend, 1);
- be = (QofBackend*)fbe;
- qof_backend_init(be);
-
- be->session_begin = file_session_begin;
- be->session_end = file_session_end;
- be->destroy_backend = file_destroy_backend;
-
- be->load = gnc_file_be_load_from_file;
-
- /* The file backend treats accounting periods transactionally. */
- be->begin = file_begin_edit;
- be->commit = file_commit_edit;
- be->rollback = file_rollback_edit;
-
- /* The file backend always loads all data ... */
- be->compile_query = NULL;
- be->free_query = NULL;
- be->run_query = NULL;
- be->price_lookup = NULL;
-
- be->counter = NULL;
-
- /* The file backend will never be multi-user... */
- be->events_pending = NULL;
- be->process_events = NULL;
-
- be->sync = file_sync_all;
- be->export = gnc_file_be_write_accounts_to_file;
-
- fbe->dirname = NULL;
- fbe->fullpath = NULL;
- fbe->lockfile = NULL;
- fbe->linkfile = NULL;
- fbe->lockfd = -1;
-
- fbe->primary_book = NULL;
-
- return be;
-}
-
-/* ================================================================= */
-
-static gboolean
-gnc_file_be_get_file_lock (FileBackend *be)
-{
- struct stat statbuf;
- char pathbuf[PATH_MAX];
- char *path = NULL;
- int rc;
- QofBackendError be_err;
-
- rc = stat (be->lockfile, &statbuf);
- if (!rc)
- {
- /* oops .. file is locked by another user .. */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- return FALSE;
- }
-
- be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
- if (be->lockfd < 0)
- {
- /* oops .. we can't create the lockfile .. */
- switch (errno) {
- case EACCES:
- case EROFS:
- case ENOSPC:
- be_err = ERR_BACKEND_READONLY;
- break;
- default:
- be_err = ERR_BACKEND_LOCKED;
- break;
- }
- qof_backend_set_error ((QofBackend*)be, be_err);
- return FALSE;
- }
-
- /* OK, now work around some NFS atomic lock race condition
- * mumbo-jumbo. We do this by linking a unique file, and
- * then examing the link count. At least that's what the
- * NFS programmers guide suggests.
- * Note: the "unique filename" must be unique for the
- * triplet filename-host-process, otherwise accidental
- * aliases can occur.
- */
-
- /* apparently, even this code may not work for some NFS
- * implementations. In the long run, I am told that
- * ftp.debian.org
- * /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
- * provides a better long-term solution.
- */
-
- strcpy (pathbuf, be->lockfile);
- path = strrchr (pathbuf, '.');
- sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());
-
- rc = link (be->lockfile, pathbuf);
- if (rc)
- {
- /* If hard links aren't supported, just allow the lock. */
- if (errno == EOPNOTSUPP || errno == EPERM)
- {
- be->linkfile = NULL;
- return TRUE;
- }
-
- /* Otherwise, something else is wrong. */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
- }
-
- rc = stat (be->lockfile, &statbuf);
- if (rc)
- {
- /* oops .. stat failed! This can't happen! */
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
- }
-
- if (statbuf.st_nlink != 2)
- {
- qof_backend_set_error ((QofBackend*)be, ERR_BACKEND_LOCKED);
- unlink (pathbuf);
- close (be->lockfd);
- unlink (be->lockfile);
- return FALSE;
- }
-
- be->linkfile = g_strdup (pathbuf);
-
- return TRUE;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static gboolean
-is_gzipped_file(const gchar *name)
-{
- unsigned char buf[2];
- int fd = open(name, O_RDONLY);
-
- if(fd == 0)
- {
- return FALSE;
+ return FALSE;
}
if(read(fd, buf, 2) != 2)
@@ -485,183 +402,179 @@
}
-/* Load financial data from a file into the book, automtically
- detecting the format of the file, if possible. Return FALSE on
- error, and set the error parameter to indicate what went wrong if
- it's not NULL. This function does not manage file locks in any
- way. */
-
-static void
-gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
+static gboolean
+gnc_file_be_backup_file(FileBackend *be)
{
- QofBackendError error = ERR_BACKEND_NO_ERR;
- gboolean rc;
- FileBackend *be = (FileBackend *) bend;
+ gboolean bkup_ret;
+ char *timestamp;
+ char *backup;
+ const char *datafile;
+ struct stat statbuf;
+ int rc;
- be->primary_book = book;
+ datafile = be->fullpath;
+
+ rc = stat (datafile, &statbuf);
+ if (rc)
+ return (errno == ENOENT);
- switch (gnc_file_be_determine_file_type(be->fullpath))
+ if(gnc_file_be_determine_file_type(datafile) == GNC_BOOK_BIN_FILE)
{
- case GNC_BOOK_XML2_FILE:
- rc = qof_session_load_from_xml_file_v2 (be, book);
- if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
- break;
+ /* make a more permament safer backup */
+ const char *back = "-binfmt.bkup";
+ char *bin_bkup = g_new(char, strlen(datafile) + strlen(back) + 1);
+ strcpy(bin_bkup, datafile);
+ strcat(bin_bkup, back);
+ bkup_ret = gnc_int_link_or_make_backup(be, datafile, bin_bkup);
+ g_free(bin_bkup);
+ if(!bkup_ret)
+ {
+ return FALSE;
+ }
+ }
- case GNC_BOOK_XML1_FILE:
- rc = qof_session_load_from_xml_file (book, be->fullpath);
- if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
- break;
+ timestamp = xaccDateUtilGetStampNow ();
+ backup = g_new (char, strlen (datafile) + strlen (timestamp) + 6);
+ strcpy (backup, datafile);
+ strcat (backup, ".");
+ strcat (backup, timestamp);
+ strcat (backup, ".xac");
+ g_free (timestamp);
- case GNC_BOOK_BIN_FILE:
- /* presume it's an old-style binary file */
- qof_session_load_from_binfile(book, be->fullpath);
- error = gnc_get_binfile_io_error();
- break;
+ bkup_ret = gnc_int_link_or_make_backup(be, datafile, backup);
+ g_free(backup);
- default:
- PWARN("File not any known type");
- error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
- break;
- }
-
- if(error != ERR_BACKEND_NO_ERR)
- {
- qof_backend_set_error(bend, error);
- }
-
- /* We just got done loading, it can't possibly be dirty !! */
- qof_book_mark_saved (book);
+ return bkup_ret;
}
-/* ---------------------------------------------------------------------- */
-/* Write the financial data in a book to a file, returning FALSE on
- error and setting the error_result to indicate what went wrong if
- it's not NULL. This function does not manage file locks in any
- way.
-
- If make_backup is true, write out a time-stamped copy of the file
- into the same directory as the indicated file, with a filename of
- "file.YYYYMMDDHHMMSS.xac" where YYYYMMDDHHMMSS is replaced with the
- current year/month/day/hour/minute/second. */
-
+/* ================================================================= */
+
static gboolean
-copy_file(const char *orig, const char *bkup)
+gnc_file_be_write_to_file(FileBackend *fbe,
+ QofBook *book,
+ const gchar *datafile,
+ gboolean make_backup)
{
- static int buf_size = 1024;
- char buf[buf_size];
- int orig_fd;
- int bkup_fd;
- ssize_t count_write;
- ssize_t count_read;
+ QofBackend *be = &fbe->be;
+ char *tmp_name;
+ struct stat statbuf;
+ int rc;
+ QofBackendError be_err;
- orig_fd = open(orig, O_RDONLY);
- if(orig_fd == -1)
- {
- return FALSE;
- }
- bkup_fd = creat(bkup, 0600);
- if(bkup_fd == -1)
+ ENTER (" book=%p file=%s", book, datafile);
+
+ /* If the book is 'clean', recently saved, then don't save again. */
+ /* XXX this is currently broken due to faulty 'Save As' logic. */
+ /* if (FALSE == qof_book_not_saved (book)) return FALSE; */
+
+ tmp_name = g_new(char, strlen(datafile) + 12);
+ strcpy(tmp_name, datafile);
+ strcat(tmp_name, ".tmp-XXXXXX");
+
+ if(!mktemp(tmp_name))
{
- close(orig_fd);
+ qof_backend_set_error(be, ERR_BACKEND_MISC);
return FALSE;
}
-
- do
+
+ if(make_backup)
{
- count_read = read(orig_fd, buf, buf_size);
- if(count_read == -1 && errno != EINTR)
+ if(!gnc_file_be_backup_file(fbe))
{
- close(orig_fd);
- close(bkup_fd);
return FALSE;
}
-
- if(count_read > 0)
+ }
+
+ if(gnc_book_write_to_xml_file_v2(book, tmp_name, file_compression))
+ {
+ /* Record the file's permissions before unlinking it */
+ rc = stat(datafile, &statbuf);
+ if(rc == 0)
{
- count_write = write(bkup_fd, buf, count_read);
- if(count_write == -1)
+ /* Use the permissions from the original data file */
+ if(chmod(tmp_name, statbuf.st_mode) != 0)
{
- close(orig_fd);
- close(bkup_fd);
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to chmod filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+#if VFAT_DOESNT_SUCK /* chmod always fails on vfat fs */
+ g_free(tmp_name);
+ return FALSE;
+#endif
+ }
+ if(chown(tmp_name, statbuf.st_uid, statbuf.st_gid) != 0)
+ {
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to chown filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+#if VFAT_DOESNT_SUCK /* chown always fails on vfat fs */
+ g_free(tmp_name);
return FALSE;
+#endif
}
}
- } while(count_read > 0);
-
- close(orig_fd);
- close(bkup_fd);
-
- return TRUE;
-}
-
-static gboolean
-gnc_int_link_or_make_backup(FileBackend *be, const char *orig, const char *bkup)
-{
- int err_ret = link(orig, bkup);
- if(err_ret != 0)
- {
- if(errno == EPERM || errno == EOPNOTSUPP)
+ if(unlink(datafile) != 0 && errno != ENOENT)
{
- err_ret = copy_file(orig, bkup);
+ qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
+ PWARN("unable to unlink filename %s: %s",
+ datafile ? datafile : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ g_free(tmp_name);
+ return FALSE;
}
-
- if(!err_ret)
+ if(!gnc_int_link_or_make_backup(fbe, tmp_name, datafile))
{
- qof_backend_set_error((QofBackend*)be, ERR_FILEIO_BACKUP_ERROR);
- PWARN ("unable to make file backup from %s to %s: %s",
- orig, bkup, strerror(errno) ? strerror(errno) : "");
+ qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
+ g_free(tmp_name);
return FALSE;
}
- }
-
- return TRUE;
-}
-
-static gboolean
-gnc_file_be_backup_file(FileBackend *be)
-{
- gboolean bkup_ret;
- char *timestamp;
- char *backup;
- const char *datafile;
- struct stat statbuf;
- int rc;
-
- datafile = be->fullpath;
-
- rc = stat (datafile, &statbuf);
- if (rc)
- return (errno == ENOENT);
+ if(unlink(tmp_name) != 0)
+ {
+ qof_backend_set_error(be, ERR_BACKEND_PERM);
+ PWARN("unable to unlink temp filename %s: %s",
+ tmp_name ? tmp_name : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ g_free(tmp_name);
+ return FALSE;
+ }
+ g_free(tmp_name);
- if(gnc_file_be_determine_file_type(datafile) == GNC_BOOK_BIN_FILE)
+ /* Since we successfully saved the book,
+ * we should mark it clean. */
+ qof_book_mark_saved (book);
+ LEAVE (" sucessful save of book=%p to file=%s", book, datafile);
+ return TRUE;
+ }
+ else
{
- /* make a more permament safer backup */
- const char *back = "-binfmt.bkup";
- char *bin_bkup = g_new(char, strlen(datafile) + strlen(back) + 1);
- strcpy(bin_bkup, datafile);
- strcat(bin_bkup, back);
- bkup_ret = gnc_int_link_or_make_backup(be, datafile, bin_bkup);
- g_free(bin_bkup);
- if(!bkup_ret)
+ if(unlink(tmp_name) != 0)
{
- return FALSE;
+ switch (errno) {
+ case ENOENT: /* tmp_name doesn't exist? Assume "RO" error */
+ case EACCES:
+ case EPERM:
+ case EROFS:
+ be_err = ERR_BACKEND_READONLY;
+ break;
+ default:
+ be_err = ERR_BACKEND_MISC;
+ }
+ qof_backend_set_error(be, be_err);
+ PWARN("unable to unlink temp_filename %s: %s",
+ tmp_name ? tmp_name : "(null)",
+ strerror(errno) ? strerror(errno) : "");
+ /* already in an error just flow on through */
}
+ g_free(tmp_name);
+ return FALSE;
}
-
- timestamp = xaccDateUtilGetStampNow ();
- backup = g_new (char, strlen (datafile) + strlen (timestamp) + 6);
- strcpy (backup, datafile);
- strcat (backup, ".");
- strcat (backup, timestamp);
- strcat (backup, ".xac");
- g_free (timestamp);
-
- bkup_ret = gnc_int_link_or_make_backup(be, datafile, backup);
- g_free(backup);
-
- return bkup_ret;
+ return TRUE;
}
+/* ================================================================= */
+
static int
gnc_file_be_select_files (const struct dirent *d)
{
@@ -766,132 +679,189 @@
closedir (dir);
}
-/* ---------------------------------------------------------------------- */
-
-static gboolean
-gnc_file_be_write_to_file(FileBackend *fbe,
- QofBook *book,
- const gchar *datafile,
- gboolean make_backup)
+static void
+file_sync_all(QofBackend* be, QofBook *book)
{
- QofBackend *be = &fbe->be;
- char *tmp_name;
- struct stat statbuf;
- int rc;
- QofBackendError be_err;
-
- ENTER (" book=%p file=%s", book, datafile);
+ FileBackend *fbe = (FileBackend *) be;
+ ENTER ("book=%p, primary=%p", book, fbe->primary_book);
- /* If the book is 'clean', recently saved, then don't save again. */
- /* XXX this is currently broken due to faulty 'Save As' logic. */
- /* if (FALSE == qof_book_not_saved (book)) return FALSE; */
+ /* We make an important assumption here, that we might want to change
+ * in the future: when the user says 'save', we really save the one,
+ * the only, the current open book, and nothing else. We do this
+ * because we assume that any other books that we are dealing with
+ * are 'read-only', non-editable, because they are closed books.
+ * If we ever want to have more than one book open read-write,
+ * this will have to change.
+ */
+ if (NULL == fbe->primary_book) fbe->primary_book = book;
+ if (book != fbe->primary_book) return;
- tmp_name = g_new(char, strlen(datafile) + 12);
- strcpy(tmp_name, datafile);
- strcat(tmp_name, ".tmp-XXXXXX");
+ gnc_file_be_write_to_file (fbe, book, fbe->fullpath, TRUE);
+ gnc_file_be_remove_old_files (fbe);
+ LEAVE ("book=%p", book);
+}
- if(!mktemp(tmp_name))
- {
- qof_backend_set_error(be, ERR_BACKEND_MISC);
- return FALSE;
- }
-
- if(make_backup)
+/* ================================================================= */
+/* Routines to deal with the creation of multiple books.
+ * The core design assumption here is that the book
+ * begin-edit/commit-edit routines are used solely to write out
+ * closed accounting periods to files. They're not currently
+ * designed to do anything other than this. (Although they could be).
+ */
+
+static char *
+build_period_filepath (FileBackend *fbe, QofBook *book)
+{
+ int len;
+ char *str, *p, *q;
+
+ len = strlen (fbe->fullpath) + GUID_ENCODING_LENGTH + 14;
+ str = g_new (char, len);
+ strcpy (str, fbe->fullpath);
+
+ /* XXX it would be nice for the user if we made the book
+ * closing date and/or title part of the file-name. */
+ p = strrchr (str, '/');
+ p++;
+ p = stpcpy (p, "book-");
+ p = guid_to_string_buff (qof_book_get_guid(book), p);
+ p = stpcpy (p, "-");
+ q = strrchr (fbe->fullpath, '/');
+ q++;
+ p = stpcpy (p, q);
+ p = stpcpy (p, ".gml");
+
+ return str;
+}
+
+static void
+file_begin_edit (QofBackend *be, QofInstance *inst)
+{
+ if (0) build_period_filepath(0, 0);
+#if BORKEN_FOR_NOW
+ FileBackend *fbe = (FileBackend *) be;
+ QofBook *book = gp;
+ const char * filepath;
+
+ QofIdTypeConst typ = QOF_ENTITY(inst)->e_type;
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ filepath = build_period_filepath(fbe, book);
+ PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+
+ if (NULL == fbe->primary_book)
{
- if(!gnc_file_be_backup_file(fbe))
- {
- return FALSE;
- }
+ PERR ("You should have saved the data "
+ "at least once before closing the books!\n");
}
-
- if(gnc_book_write_to_xml_file_v2(book, tmp_name, file_compression))
- {
- /* Record the file's permissions before unlinking it */
- rc = stat(datafile, &statbuf);
- if(rc == 0)
- {
- /* Use the permissions from the original data file */
- if(chmod(tmp_name, statbuf.st_mode) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to chmod filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
-#if VFAT_DOESNT_SUCK /* chmod always fails on vfat fs */
- g_free(tmp_name);
- return FALSE;
+ /* XXX To be anal about it, we should really be checking to see
+ * if there already is a file with this book GUID, and disallowing
+ * further progress. This is because we are not allowed to
+ * modify books that are closed (They should be treated as
+ * 'read-only').
+ */
#endif
- }
- if(chown(tmp_name, statbuf.st_uid, statbuf.st_gid) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to chown filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
-#if VFAT_DOESNT_SUCK /* chown always fails on vfat fs */
- g_free(tmp_name);
- return FALSE;
+}
+
+static void
+file_rollback_edit (QofBackend *be, QofInstance *inst)
+{
+#if BORKEN_FOR_NOW
+ QofBook *book = gp;
+
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ PINFO ("book=%p", book);
#endif
- }
- }
- if(unlink(datafile) != 0 && errno != ENOENT)
- {
- qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
- PWARN("unable to unlink filename %s: %s",
- datafile ? datafile : "(null)",
- strerror(errno) ? strerror(errno) : "");
- g_free(tmp_name);
- return FALSE;
- }
- if(!gnc_int_link_or_make_backup(fbe, tmp_name, datafile))
- {
- qof_backend_set_error(be, ERR_FILEIO_BACKUP_ERROR);
- g_free(tmp_name);
- return FALSE;
- }
- if(unlink(tmp_name) != 0)
- {
- qof_backend_set_error(be, ERR_BACKEND_PERM);
- PWARN("unable to unlink temp filename %s: %s",
- tmp_name ? tmp_name : "(null)",
- strerror(errno) ? strerror(errno) : "");
- g_free(tmp_name);
- return FALSE;
- }
- g_free(tmp_name);
+}
- /* Since we successfully saved the book,
- * we should mark it clean. */
- qof_book_mark_saved (book);
- LEAVE (" sucessful save of book=%p to file=%s", book, datafile);
- return TRUE;
+static void
+file_commit_edit (QofBackend *be, QofInstance *inst)
+{
+#if BORKEN_FOR_NOW
+ FileBackend *fbe = (FileBackend *) be;
+ QofBook *book = gp;
+ const char * filepath;
+
+ if (strcmp (GNC_ID_PERIOD, typ)) return;
+ filepath = build_period_filepath(fbe, book);
+ PINFO (" ====================== book=%p filepath=%s\n", book, filepath);
+ gnc_file_be_write_to_file(fbe, book, filepath, FALSE);
+
+ /* We want to force a save of the current book at this point,
+ * because if we don't, and the user forgets to do so, then
+ * there'll be the same transactions in the closed book,
+ * and also in the current book. */
+ gnc_file_be_write_to_file (fbe, fbe->primary_book, fbe->fullpath, TRUE);
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+
+
+/* Load financial data from a file into the book, automtically
+ detecting the format of the file, if possible. Return FALSE on
+ error, and set the error parameter to indicate what went wrong if
+ it's not NULL. This function does not manage file locks in any
+ way. */
+
+static void
+gnc_file_be_load_from_file (QofBackend *bend, QofBook *book)
+{
+ QofBackendError error = ERR_BACKEND_NO_ERR;
+ gboolean rc;
+ FileBackend *be = (FileBackend *) bend;
+
+ be->primary_book = book;
+
+ switch (gnc_file_be_determine_file_type(be->fullpath))
+ {
+ case GNC_BOOK_XML2_FILE:
+ rc = qof_session_load_from_xml_file_v2 (be, book);
+ if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
+ break;
+
+ case GNC_BOOK_XML1_FILE:
+ rc = qof_session_load_from_xml_file (book, be->fullpath);
+ if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
+ break;
+
+ case GNC_BOOK_BIN_FILE:
+ /* presume it's an old-style binary file */
+ qof_session_load_from_binfile(book, be->fullpath);
+ error = gnc_get_binfile_io_error();
+ break;
+
+ default:
+ PWARN("File not any known type");
+ error = ERR_FILEIO_UNKNOWN_FILE_TYPE;
+ break;
}
- else
+
+ if(error != ERR_BACKEND_NO_ERR)
{
- if(unlink(tmp_name) != 0)
- {
- switch (errno) {
- case ENOENT: /* tmp_name doesn't exist? Assume "RO" error */
- case EACCES:
- case EPERM:
- case EROFS:
- be_err = ERR_BACKEND_READONLY;
- break;
- default:
- be_err = ERR_BACKEND_MISC;
- }
- qof_backend_set_error(be, be_err);
- PWARN("unable to unlink temp_filename %s: %s",
- tmp_name ? tmp_name : "(null)",
- strerror(errno) ? strerror(errno) : "");
- /* already in an error just flow on through */
- }
- g_free(tmp_name);
- return FALSE;
+ qof_backend_set_error(bend, error);
}
- return TRUE;
+
+ /* We just got done loading, it can't possibly be dirty !! */
+ qof_book_mark_saved (book);
}
+/* ---------------------------------------------------------------------- */
+
+static gboolean
+gnc_file_be_save_may_clobber_data (QofBackend *bend)
+{
+ struct stat statbuf;
+
+ if (!bend->fullpath) return FALSE;
+
+ /* FIXME: Make sure this doesn't need more sophisticated semantics
+ * in the face of special file, devices, pipes, symlinks, etc. */
+ if (stat(bend->fullpath, &statbuf) == 0) return TRUE;
+
+ return FALSE;
+}
+
+
static void
gnc_file_be_write_accounts_to_file(QofBackend *be, QofBook *book)
{
@@ -901,4 +871,54 @@
gnc_book_write_accounts_to_xml_file_v2(be, book, datafile);
}
+/* ================================================================= */
+
+QofBackend *
+libgncmod_backend_file_LTX_gnc_backend_new(void)
+{
+ FileBackend *fbe;
+ QofBackend *be;
+
+ fbe = g_new0(FileBackend, 1);
+ be = (QofBackend*)fbe;
+ qof_backend_init(be);
+
+ be->session_begin = file_session_begin;
+ be->session_end = file_session_end;
+ be->destroy_backend = file_destroy_backend;
+
+ be->load = gnc_file_be_load_from_file;
+ be->save_may_clobber_data = gnc_file_be_save_may_clobber_data;
+
+ /* The file backend treats accounting periods transactionally. */
+ be->begin = file_begin_edit;
+ be->commit = file_commit_edit;
+ be->rollback = file_rollback_edit;
+
+ /* The file backend always loads all data ... */
+ be->compile_query = NULL;
+ be->free_query = NULL;
+ be->run_query = NULL;
+ be->price_lookup = NULL;
+
+ be->counter = NULL;
+
+ /* The file backend will never be multi-user... */
+ be->events_pending = NULL;
+ be->process_events = NULL;
+
+ be->sync = file_sync_all;
+ be->export = gnc_file_be_write_accounts_to_file;
+
+ fbe->dirname = NULL;
+ fbe->fullpath = NULL;
+ fbe->lockfile = NULL;
+ fbe->linkfile = NULL;
+ fbe->lockfd = -1;
+
+ fbe->primary_book = NULL;
+
+ return be;
+}
+
/* ========================== END OF FILE ===================== */
Index: gw-engine-spec.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gw-engine-spec.scm,v
retrieving revision 1.72
retrieving revision 1.73
diff -Lsrc/engine/gw-engine-spec.scm -Lsrc/engine/gw-engine-spec.scm -u -r1.72 -r1.73
--- src/engine/gw-engine-spec.scm
+++ src/engine/gw-engine-spec.scm
@@ -21,6 +21,7 @@
ws
(lambda (wrapset client-wrapset)
(list
+ "#include <config.h>\n"
"#include <glib.h>\n"
"#include <guid.h>\n"
"#include <Group.h>\n"
Index: qofsession.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -Lsrc/engine/qofsession.c -Lsrc/engine/qofsession.c -u -r1.10 -r1.11
--- src/engine/qofsession.c
+++ src/engine/qofsession.c
@@ -59,13 +59,8 @@
#include "qofsession-p.h"
/* Some gnucash-specific code */
-#ifdef GNUCASH
+#ifdef GNUCASH_MAJOR_VERSION
#include "gnc-module.h"
-#include "TransLog.h"
-#else
-#define xaccLogSetBaseName(x)
-#define xaccLogEnable()
-#define xaccLogDisable()
#endif /* GNUCASH */
static QofSession * current_session = NULL;
@@ -172,8 +167,6 @@
session->books = g_list_append (NULL, qof_book_new ());
session->book_id = NULL;
- session->fullpath = NULL;
- session->logpath = NULL;
session->backend = NULL;
qof_session_clear_error (session);
@@ -265,7 +258,8 @@
qof_session_get_file_path (QofSession *session)
{
if (!session) return NULL;
- return session->fullpath;
+ if (!session->backend) return NULL;
+ return session->backend->fullpath;
}
const char *
@@ -277,7 +271,7 @@
/* ====================================================================== */
-#ifdef GNUCASH
+#ifdef GNUCASH_MAJOR_VERSION
static void
qof_session_int_backend_load_error(QofSession *session,
@@ -285,12 +279,6 @@
{
PWARN ("%s %s", message, dll_err ? dll_err : "");
- g_free(session->fullpath);
- session->fullpath = NULL;
-
- g_free(session->logpath);
- session->logpath = NULL;
-
g_free(session->book_id);
session->book_id = NULL;
@@ -437,57 +425,30 @@
LEAVE("push error missing book_id");
return;
}
- /* Store the sessionid URL */
- session->book_id = g_strdup (book_id);
- /* XXX we should probably move this resolve function to the
- * file backend. I think the idea would be to open the backend
- * and then ask it if it can contact it's storage media (disk,
- * network, server, etc.) and abort if it can't. Mal-formed
- * file URL's would be handled the same way!
- */
- /* ResolveURL tries to find the file in the file system. */
- session->fullpath = xaccResolveURL(book_id);
- if (!session->fullpath)
- {
- qof_session_push_error (session, ERR_FILEIO_FILE_NOT_FOUND, NULL);
- LEAVE("push error: can't resolve file path");
- return;
- }
- PINFO ("filepath=%s", session->fullpath ? session->fullpath : "(null)");
-
- session->logpath = xaccResolveFilePath(session->fullpath);
- PINFO ("logpath=%s", session->logpath ? session->logpath : "(null)");
+ /* Store the session URL */
+ session->book_id = g_strdup (book_id);
/* destroy the old backend */
qof_session_destroy_backend(session);
- /* check to see if this is a type we know how to handle */
- if (!g_strncasecmp(book_id, "file:", 5) ||
- *session->fullpath == '/')
+ /* Look for somthing of the form of "file:/", "http://" or
+ * "postgres://". Everything before the colon is the access
+ * method. Load the first backend found for that access method.
+ */
+ char * p = strchr (book_id, ':');
+ if (p)
{
- qof_session_load_backend(session, "file" );
+ char * access_method = g_strdup (book_id);
+ p = strchr (access_method, ':');
+ *p = 0;
+ qof_session_load_backend(session, access_method);
+ g_free (access_method);
}
else
{
- /* Look for somthing of the form of "http://" or
- * "postgres://". Everything before the colon is the access
- * method. Load the first backend found for that access method.
- */
- char * p = strchr (book_id, ':');
- if (p)
- {
- char * access_method = g_strdup (book_id);
- p = strchr (access_method, ':');
- *p = 0;
- qof_session_load_backend(session, access_method);
- g_free (access_method);
- }
- else
- {
- /* If no colon found, assume it must be a file-path */
- qof_session_load_backend(session, "file");
- }
+ /* If no colon found, assume it must be a file-path */
+ qof_session_load_backend(session, "file");
}
/* No backend was found. That's bad. */
@@ -513,10 +474,6 @@
msg = qof_backend_get_message(session->backend);
if (err != ERR_BACKEND_NO_ERR)
{
- g_free(session->fullpath);
- session->fullpath = NULL;
- g_free(session->logpath);
- session->logpath = NULL;
g_free(session->book_id);
session->book_id = NULL;
qof_session_push_error (session, err, msg);
@@ -560,8 +517,6 @@
session->books = g_list_append (NULL, newbook);
PINFO ("new book=%p", newbook);
- xaccLogSetBaseName(session->logpath);
-
qof_session_clear_error (session);
/* This code should be sufficient to initialize *any* backend,
@@ -580,7 +535,6 @@
*/
if (be)
{
- xaccLogDisable();
be->percentage = percentage_func;
if (be->load)
@@ -588,7 +542,6 @@
be->load (be, newbook);
qof_session_push_error (session, qof_backend_get_error(be), NULL);
}
- xaccLogEnable();
}
err = qof_session_get_error(session);
@@ -597,24 +550,20 @@
(err != ERR_SQL_DB_TOO_OLD))
{
/* Something broke, put back the old stuff */
- xaccLogDisable();
qof_book_set_backend (newbook, NULL);
qof_book_destroy (newbook);
g_list_free (session->books);
session->books = oldbooks;
LEAVE("error from backend %d", qof_session_get_error(session));
- xaccLogEnable();
return;
}
- xaccLogDisable();
for (node=oldbooks; node; node=node->next)
{
QofBook *ob = node->data;
qof_book_set_backend (ob, NULL);
qof_book_destroy (ob);
}
- xaccLogEnable();
LEAVE ("sess = %p, book_id=%s", session, qof_session_get_url(session)
? qof_session_get_url(session) : "(null)");
@@ -625,19 +574,11 @@
gboolean
qof_session_save_may_clobber_data (QofSession *session)
{
- struct stat statbuf;
-
if (!session) return FALSE;
- if (!session->fullpath) return FALSE;
-
- /* FIXME: This should really be sent to the backend. The stat is
- * correct only for the file backend */
-
- /* FIXME: Make sure this doesn't need more sophisticated semantics
- * in the face of special file, devices, pipes, symlinks, etc. */
- if (stat(session->fullpath, &statbuf) == 0) return TRUE;
+ if (!session->backend) return FALSE;
+ if (!session->backend->save_may_clobber_data) return FALSE;
- return FALSE;
+ return (*(session->backend->save_may_clobber_data)) (session->backend);
}
static gboolean
@@ -717,7 +658,11 @@
}
/* ====================================================================== */
-/* XXX what does this function do ?? */
+/* XXX This exports the list of accounts to a file. It does not export
+ * any transactions. Its a place-holder until full book-closing is implemented.
+ */
+
+#ifdef GNUCASH_MAJOR_VERSION
gboolean
qof_session_export (QofSession *tmp_session,
@@ -752,6 +697,7 @@
return TRUE;
}
+#endif /* GNUCASH_MAJOR_VERSION */
/* ====================================================================== */
@@ -771,12 +717,6 @@
qof_session_clear_error (session);
- g_free (session->fullpath);
- session->fullpath = NULL;
-
- g_free (session->logpath);
- session->logpath = NULL;
-
g_free (session->book_id);
session->book_id = NULL;
@@ -794,7 +734,6 @@
qof_session_get_url(session)
? qof_session_get_url(session) : "(null)");
- xaccLogDisable();
qof_session_end (session);
/* destroy the backend */
@@ -811,8 +750,6 @@
if (session == current_session)
current_session = NULL;
- xaccLogEnable();
-
g_free (session);
LEAVE ("sess=%p", session);
@@ -874,273 +811,14 @@
}
/* ====================================================================== */
-/*
- * If $HOME/.gnucash/data directory doesn't exist, then create it.
- */
-
-static void
-MakeHomeDir (void)
-{
- int rc;
- struct stat statbuf;
- char *home;
- char *path;
- char *data;
-
- /* Punt. Can't figure out where home is. */
- home = getenv ("HOME");
- if (!home) return;
-
- path = g_strconcat(home, "/.gnucash", NULL);
-
- rc = stat (path, &statbuf);
- if (rc)
- {
- /* assume that the stat failed only because the dir is absent,
- * and not because its read-protected or other error.
- * Go ahead and make it. Don't bother much with checking mkdir
- * for errors; seems pointless. */
- mkdir (path, S_IRWXU); /* perms = S_IRWXU = 0700 */
- }
-
- data = g_strconcat (path, "/data", NULL);
- rc = stat (data, &statbuf);
- if (rc)
- mkdir (data, S_IRWXU);
-
- g_free (path);
- g_free (data);
-}
-
-/* ====================================================================== */
-
-/* XXX hack alert -- we should be yanking this out of some config file */
-static char * searchpaths[] =
-{
- "/usr/share/gnucash/data/",
- "/usr/local/share/gnucash/data/",
- "/usr/share/gnucash/accounts/",
- "/usr/local/share/gnucash/accounts/",
- NULL,
-};
-
-typedef gboolean (*pathGenerator)(char *pathbuf, int which);
-static gboolean
-xaccAddEndPath(char *pathbuf, const char *ending, int len)
-{
- if(len + strlen(pathbuf) >= PATH_MAX)
- return FALSE;
-
- strcat (pathbuf, ending);
- return TRUE;
-}
-
-static gboolean
-xaccCwdPathGenerator(char *pathbuf, int which)
-{
- if(which != 0)
- {
- return FALSE;
- }
- else
- {
- /* try to find a file by this name in the cwd ... */
- if (getcwd (pathbuf, PATH_MAX) == NULL)
- return FALSE;
-
- strcat (pathbuf, "/");
- return TRUE;
- }
-}
-
-static gboolean
-xaccDataPathGenerator(char *pathbuf, int which)
-{
- char *path;
-
- if(which != 0)
- {
- return FALSE;
- }
- else
- {
- path = getenv ("HOME");
- if (!path)
- return FALSE;
-
- if (PATH_MAX <= (strlen (path) + 20))
- return FALSE;
-
- strcpy (pathbuf, path);
- strcat (pathbuf, "/.gnucash/data/");
- return TRUE;
- }
-}
-
-static gboolean
-xaccUserPathPathGenerator(char *pathbuf, int which)
-{
- char *path = NULL;
-
- if(searchpaths[which] == NULL)
- {
- return FALSE;
- }
- else
- {
- path = searchpaths[which];
-
- if (PATH_MAX <= strlen(path))
- return FALSE;
-
- strcpy (pathbuf, path);
- return TRUE;
- }
-}
-
-/* ====================================================================== */
-
-char *
-xaccResolveFilePath (const char * filefrag)
-{
- struct stat statbuf;
- char pathbuf[PATH_MAX];
- pathGenerator gens[4];
- char *filefrag_dup;
- int namelen;
- int i;
-
- /* seriously invalid */
- if (!filefrag)
- {
- PERR("filefrag is NULL");
- return NULL;
- }
-
- ENTER ("filefrag=%s", filefrag);
-
- /* ---------------------------------------------------- */
- /* OK, now we try to find or build an absolute file path */
-
- /* check for an absolute file path */
- if (*filefrag == '/')
- return g_strdup (filefrag);
-
- if (!g_strncasecmp(filefrag, "file:", 5))
- {
- char *ret = g_new(char, strlen(filefrag) - 5 + 1);
- strcpy(ret, filefrag + 5);
- return ret;
- }
-
- /* get conservative on the length so that sprintf(getpid()) works ... */
- /* strlen ("/.LCK") + sprintf (%x%d) */
- namelen = strlen (filefrag) + 25;
-
- gens[0] = xaccCwdPathGenerator;
- gens[1] = xaccDataPathGenerator;
- gens[2] = xaccUserPathPathGenerator;
- gens[3] = NULL;
-
- for (i = 0; gens[i] != NULL; i++)
- {
- int j;
- for(j = 0; gens[i](pathbuf, j) ; j++)
- {
- if(xaccAddEndPath(pathbuf, filefrag, namelen))
- {
- int rc = stat (pathbuf, &statbuf);
- if ((!rc) && (S_ISREG(statbuf.st_mode)))
- {
- return (g_strdup (pathbuf));
- }
- }
- }
- }
- /* OK, we didn't find the file. */
-
- /* make sure that the gnucash home dir exists. */
- MakeHomeDir();
-
- filefrag_dup = g_strdup (filefrag);
-
- /* Replace '/' with ',' for non file backends */
- if (strstr (filefrag, "://"))
- {
- char *p;
-
- p = strchr (filefrag_dup, '/');
- while (p) {
- *p = ',';
- p = strchr (filefrag_dup, '/');
- }
- }
-
- /* Lets try creating a new file in $HOME/.gnucash/data */
- if (xaccDataPathGenerator(pathbuf, 0))
- {
- if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
- {
- g_free (filefrag_dup);
- return (g_strdup (pathbuf));
- }
- }
-
- /* OK, we still didn't find the file */
- /* Lets try creating a new file in the cwd */
- if (xaccCwdPathGenerator(pathbuf, 0))
- {
- if(xaccAddEndPath(pathbuf, filefrag_dup, namelen))
- {
- g_free (filefrag_dup);
- return (g_strdup (pathbuf));
- }
- }
-
- g_free (filefrag_dup);
-
- return NULL;
-}
-
-/* ====================================================================== */
-
-char *
-xaccResolveURL (const char * pathfrag)
-{
- /* seriously invalid */
- if (!pathfrag) return NULL;
-
- /* At this stage of checking, URL's are always, by definition,
- * resolved. If there's an error connecting, we'll find out later.
- *
- * FIXME -- we should probably use ghttp_uri_validate
- * to make sure the uri is in good form.
- */
-
- if (!g_strncasecmp (pathfrag, "http://", 7) ||
- !g_strncasecmp (pathfrag, "https://", 8) ||
- !g_strncasecmp (pathfrag, "postgres://", 11) ||
- !g_strncasecmp (pathfrag, "rpc://", 6))
- {
- return g_strdup(pathfrag);
- }
-
- if (!g_strncasecmp (pathfrag, "file:", 5)) {
- return (xaccResolveFilePath (pathfrag));
- }
-
- return (xaccResolveFilePath (pathfrag));
-}
-
-/* ====================================================================== */
+#ifdef GNUCASH_MAJOR_VERSION
/* this should go in a separate binary to create a rpc server */
void
gnc_run_rpc_server (void)
{
-#ifdef GNUCASH
const char * dll_err;
void * dll_handle;
int (*rpc_run)(short);
@@ -1173,7 +851,7 @@
ret = (*rpc_run)(0);
/* XXX How do we force an exit? */
-#endif /* GNUCASH */
}
+#endif /* GNUCASH_MAJOR_VERSION */
/* =================== END OF FILE ====================================== */
Index: qofbackend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -Lsrc/engine/qofbackend.c -Lsrc/engine/qofbackend.c -u -r1.4 -r1.5
--- src/engine/qofbackend.c
+++ src/engine/qofbackend.c
@@ -130,9 +130,12 @@
be->error_msg = NULL;
be->percentage = NULL;
+#ifdef GNUCASH_MAJOR_VERSION
/* XXX remove these */
+ be->fullpath = NULL;
be->price_lookup = NULL;
be->export = NULL;
+#endif
}
/************************* END OF FILE ********************************/
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/Makefile.am,v
retrieving revision 1.121
retrieving revision 1.122
diff -Lsrc/engine/Makefile.am -Lsrc/engine/Makefile.am -u -r1.121 -r1.122
--- src/engine/Makefile.am
+++ src/engine/Makefile.am
@@ -30,6 +30,7 @@
gnc-engine-util.c \
gnc-engine.c \
gnc-event.c \
+ gnc-filepath-utils.c \
gnc-lot.c \
gnc-numeric.c \
gnc-pricedb.c \
@@ -83,6 +84,7 @@
gnc-engine-util.h \
gnc-engine.h \
gnc-event.h \
+ gnc-filepath-utils.h \
gnc-numeric.h \
gnc-pricedb.h \
gnc-session.h \
Index: qofbackend-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofbackend-p.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -Lsrc/engine/qofbackend-p.h -Lsrc/engine/qofbackend-p.h -u -r1.5 -r1.6
--- src/engine/qofbackend-p.h
+++ src/engine/qofbackend-p.h
@@ -1,8 +1,6 @@
/********************************************************************\
* qofbackend-p.h -- private api for data storage backend *
* *
- * Copyright (c) 2000, 2001 Linas Vepstas <linas at linas.org> *
- * *
* 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; either version 2 of *
@@ -34,6 +32,10 @@
The callbacks will be called at the appropriate times during
a book session to allow the backend to store the data as needed.
+
+ @file qofbackend-p.h
+ @brief private api for data storage backend
+ @author Copyright (c) 2000,2001,2004 Linas Vepstas <linas at linas.org>
@{ */
#ifndef QOF_BACKEND_P_H
@@ -242,7 +244,6 @@
struct QofBackend_s
{
-
void (*session_begin) (QofBackend *be,
QofSession *session,
const char *book_id,
@@ -265,14 +266,24 @@
gint64 (*counter) (QofBackend *, const char *counter_name);
- gboolean (*events_pending) (QofBackend *be);
- gboolean (*process_events) (QofBackend *be);
+ gboolean (*events_pending) (QofBackend *);
+ gboolean (*process_events) (QofBackend *);
QofBePercentageFunc percentage;
+ /** Document Me !!! what is this supposed to do ?? */
+ gboolean (*save_may_clobber_data) (QofBackend *);
+
QofBackendError last_err;
char * error_msg;
+ /** XXX the file backend resolves the if to a fully-qualified file
+ * path. This holds the filepath and communicates it to the GUI.
+ * This is temprary scaffolding and should be removed. Deprecated.
+ */
+ char * fullpath;
+
+#ifdef GNUCASH_MAJOR_VERSION
/** XXX price_lookup should be removed during the redesign
* of the SQL backend... prices can now be queried using
* the generic query mechanism.
@@ -285,12 +296,15 @@
/** XXX Export should really _NOT_ be here, but is left here for now.
* I'm not sure where this should be going to. It should be
- * removed ASAP.
+ * removed ASAP. This is a temporary hack-around until period-closing
+ * is fully implemented.
*/
void (*export) (QofBackend *, QofBook *);
+#endif
+
};
-/** Let the ssytem know about a new provider of backends. This function
+/** Let the sytem know about a new provider of backends. This function
* is typically called by the provider library at library load time.
* This function allows the backend library to tell the QOF infrastructure
* that it can handle URL's of a certain type. Note that a single
@@ -299,26 +313,21 @@
*/
void qof_backend_register_provider (QofBackendProvider *);
-/**
- * The qof_backend_set_error() routine pushes an error code onto the error
- * stack. (FIXME: the stack is 1 deep in current implementation).
+/** The qof_backend_set_error() routine pushes an error code onto the error
+ * stack. (FIXME: the stack is 1 deep in current implementation).
*/
void qof_backend_set_error (QofBackend *be, QofBackendError err);
-/**
- * The qof_backend_get_error() routine pops an error code off the error
- * stack.
+/** The qof_backend_get_error() routine pops an error code off the error stack.
*/
QofBackendError qof_backend_get_error (QofBackend *be);
-/**
- * The qof_backend_set_message() assigns a string to the backend error
- * message.
+
+/** The qof_backend_set_message() assigns a string to the backend error message.
*/
void qof_backend_set_message(QofBackend *be, const char *format, ...);
-/**
- * The qof_backend_get_message() pops the error message string from
- * the Backend. This string should be freed with g_free().
+/** The qof_backend_get_message() pops the error message string from
+ * the Backend. This string should be freed with g_free().
*/
char * qof_backend_get_message(QofBackend *be);
Index: qofsession.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -Lsrc/engine/qofsession.h -Lsrc/engine/qofsession.h -u -r1.6 -r1.7
--- src/engine/qofsession.h
+++ src/engine/qofsession.h
@@ -156,11 +156,6 @@
void qof_session_load (QofSession *session,
QofPercentageFunc percentage_func);
-/** XXX session_export really doesn't belong here */
-gboolean qof_session_export (QofSession *tmp_session,
- QofSession *real_session,
- QofPercentageFunc percentage_func);
-
/** @name Session Errors
@{ */
/** The qof_session_get_error() routine can be used to obtain the reason
@@ -251,22 +246,20 @@
gboolean qof_session_process_events (QofSession *session);
/* @} */
-/** The xaccResolveFilePath() routine is a utility that will accept
- * a fragmentary filename as input, and resolve it into a fully
- * qualified path in the file system, i.e. a path that begins with
- * a leading slash. First, the current working directory is
- * searched for the file. Next, the directory $HOME/.gnucash/data,
- * and finally, a list of other (configurable) paths. If the file
- * is not found, then the path $HOME/.gnucash/data is used. If
- * $HOME is not defined, then the current working directory is
- * used.
- */
-char * xaccResolveFilePath (const char * filefrag);
-char * xaccResolveURL (const char * pathfrag);
-
+#ifdef GNUCASH_MAJOR_VERSION
/** Run the RPC Server
* @deprecated will go away */
void gnc_run_rpc_server (void);
+/** XXX session_export really doesn't belong here .
+ * This functino exports the list of accounts to a file. Its a stop-gap
+ * measure until full book-closing is implemented.
+ */
+gboolean qof_session_export (QofSession *tmp_session,
+ QofSession *real_session,
+ QofPercentageFunc percentage_func);
+
+#endif /* GNUCASH_MJOR_VERSION */
+
#endif /* QOF_SESSION_H */
/** @} */
Index: qofsession-p.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession-p.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lsrc/engine/qofsession-p.h -Lsrc/engine/qofsession-p.h -u -r1.3 -r1.4
--- src/engine/qofsession-p.h
+++ src/engine/qofsession-p.h
@@ -53,9 +53,6 @@
QofBackendError last_err;
char *error_message;
- char *fullpath;
- char *logpath;
-
/* ---------------------------------------------------- */
/* Pointer to the backend that is actually used to move data
* between the persistant store and the local engine. */
Index: test-resolve-file-path.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-resolve-file-path.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -Lsrc/engine/test/test-resolve-file-path.c -Lsrc/engine/test/test-resolve-file-path.c -u -r1.4 -r1.5
--- src/engine/test/test-resolve-file-path.c
+++ src/engine/test/test-resolve-file-path.c
@@ -5,6 +5,7 @@
#include "test-stuff.h"
#include "gnc-engine-util.h"
+#include "gnc-filepath-utils.h"
#include "qofsession.h"
struct test_strings_struct
More information about the gnucash-changes
mailing list