diff --git a/ChangeLog b/ChangeLog index d43ba242d1..0270d5e69a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2005-11-23 David Hampton + + * src/import-export/qif-import/qif-guess-map.scm: + * src/scm/command-line.scm: + * src/scm/main.scm: + * src/scm/main-window.scm: + * src/scm/path.scm: + * src/engine/gnc-filepath-utils.c: + * src/engine/gnc-filepath-utils.h: + * src/engine/gw-engine-spec.scm: + * src/app-utils/gnc-exp-parser.c: Consolidate the creation of all + file names under ~/.gnucash, and also consolidate checks for the + existence of ~/.gnucash and ~/.gnucash/books. Add better error + messages when there is a problem. + 2005-11-22 David Hampton * src/import-export/schemas/apps_gnucash_import_generic_matcher.schemas: diff --git a/src/app-utils/gnc-exp-parser.c b/src/app-utils/gnc-exp-parser.c index 57461a85b9..d679c4ba60 100644 --- a/src/app-utils/gnc-exp-parser.c +++ b/src/app-utils/gnc-exp-parser.c @@ -29,6 +29,7 @@ #include "finproto.h" #include "fin_spl_protos.h" +#include "gnc-filepath-utils.h" #include "gnc-gkeyfile-utils.h" #include "gnc-exp-parser.h" #include "gnc-ui-util.h" @@ -56,7 +57,7 @@ static gboolean parser_inited = FALSE; static gchar * gnc_exp_parser_filname (void) { - return g_build_filename(g_get_home_dir(), ".gnucash", "expressions-2.0", NULL); + return gnc_build_dotgnucash_path("expressions-2.0"); } void diff --git a/src/engine/gnc-filepath-utils.c b/src/engine/gnc-filepath-utils.c index 309785e30e..de25438b09 100644 --- a/src/engine/gnc-filepath-utils.c +++ b/src/engine/gnc-filepath-utils.c @@ -32,13 +32,18 @@ #include "config.h" +#include +#include +#include + #include +#include #include #include #include #include +#include -#include #include "gnc-engine.h" #include "gnc-filepath-utils.h" @@ -304,4 +309,118 @@ xaccResolveURL (const char * pathfrag) return (xaccResolveFilePath (pathfrag)); } +/* ====================================================================== */ + +static void +gnc_validate_directory (const gchar *dirname) +{ + struct stat statbuf; + gint rc; + + rc = stat (dirname, &statbuf); + if (rc) { + switch (errno) { + case ENOENT: + rc = mkdir (dirname, S_IRWXU); /* perms = S_IRWXU = 0700 */ + if (rc) { + g_fprintf(stderr, + _("An error occurred wile creating the directory:\n" + " %s\n" + "Please correct the problem and restart gnucash\n" + "The reported error was '%s' (errno %d).\n"), + dirname, strerror(errno), errno); + exit(1); + } + stat (dirname, &statbuf); + break; + + case EACCES: + g_fprintf(stderr, + _("The directory\n" + " %s\n" + "exists but cannot be accessed. This program \n" + "must have full access (read/write/execute) to \n" + "the directory in order to function properly.\n"), + dirname); + exit(1); + + case ENOTDIR: + g_fprintf(stderr, + _("The path\n" + " %s\n" + "exists but it is not a directory. Please delete\n" + "the file and start gnucash again.\n"), + dirname); + exit(1); + + default: + g_fprintf(stderr, + _("An unknown error occurred when validating that the\n" + " %s\n" + "directory exists and is usable. Please correct the\n" + "problem and restart gnucash. The reported error \n" + "was '%s' (errno %d)."), + dirname, strerror(errno), errno); + exit(1); + } + } + + if ((statbuf.st_mode & S_IFDIR) != S_IFDIR) { + g_fprintf(stderr, + _("The path\n" + " %s\n" + "exists but it is not a directory. Please delete\n" + "the file and start gnucash again.\n"), + dirname); + exit(1); + } + if ((statbuf.st_mode & S_IRWXU) != S_IRWXU) { + g_fprintf(stderr, + _("The permissions are wrong on the directory\n" + " %s\n" + "They must be at least 'rwx' for the user.\n"), + dirname); + exit(1); + } +} + +const gchar * +gnc_dotgnucash_dir (void) +{ + static gchar *dotgnucash = NULL, *books_dir; + const gchar *home; + + if (dotgnucash) + return dotgnucash; + + home = g_get_home_dir(); + if (!home) { + g_warning("Cannot find home directory. Using tmp directory instead."); + home = g_get_tmp_dir(); + } + g_assert(home); + + dotgnucash = g_build_filename(home, ".gnucash", (gchar *)NULL); + gnc_validate_directory(dotgnucash); + + /* Since we're in code that is only executed once.... */ + books_dir = g_build_filename(dotgnucash, "books", (gchar *)NULL); + gnc_validate_directory(books_dir); + g_free(books_dir); + + return dotgnucash; +} + +gchar * +gnc_build_dotgnucash_path (const gchar *filename) +{ + return g_build_filename(gnc_dotgnucash_dir(), filename, (gchar *)NULL); +} + +gchar * +gnc_build_book_path (const gchar *filename) +{ + return g_build_filename(gnc_dotgnucash_dir(), "books", filename, (gchar *)NULL); +} + /* =============================== END OF FILE ========================== */ diff --git a/src/engine/gnc-filepath-utils.h b/src/engine/gnc-filepath-utils.h index a093fc94f0..46ea611584 100644 --- a/src/engine/gnc-filepath-utils.h +++ b/src/engine/gnc-filepath-utils.h @@ -46,4 +46,8 @@ char * xaccResolveFilePath (const char * filefrag); char * xaccResolveURL (const char * pathfrag); +const gchar *gnc_dotgnucash_dir (void); +gchar *gnc_build_dotgnucash_path (const gchar *filename); +gchar *gnc_build_book_path (const gchar *filename); + #endif /* GNC_FILEPATH_UTILS_H */ diff --git a/src/engine/gw-engine-spec.scm b/src/engine/gw-engine-spec.scm index cf308eb667..5b5bd40504 100644 --- a/src/engine/gw-engine-spec.scm +++ b/src/engine/gw-engine-spec.scm @@ -29,6 +29,7 @@ "#include \n" "#include \n" "#include \n" + "#include \n" "#include \n" "#include \n" "#include \n" @@ -2419,6 +2420,26 @@ of having a parent transaction with which one is working...") "Convert a timepair on a certain day (localtime) to\ the timepair representing midday on that day") +;; +;; gnc-filepath-utils.h +;; + +(gw:wrap-function + ws + 'gnc:build-dotgnucash-path + '( caller-owned) + "gnc_build_dotgnucash_path" + '((( caller-owned) filename)) + "Convert a relative path name into a full path name in the .gnucash directory") + +(gw:wrap-function + ws + 'gnc:build-book-path + '( caller-owned) + "gnc_build_book_path" + '((( caller-owned) filename)) + "Convert a relative path name into a full path name in the .gnucash/books directory") + ;; ;; gnc-lot.h ;; diff --git a/src/import-export/qif-import/qif-guess-map.scm b/src/import-export/qif-import/qif-guess-map.scm index f77b06bd0a..6b78642ed0 100644 --- a/src/import-export/qif-import/qif-guess-map.scm +++ b/src/import-export/qif-import/qif-guess-map.scm @@ -63,15 +63,12 @@ ;; (older saved prefs may not have this one) ;; - a hash of QIF stock name to gnc-commodity* ;; (older saved prefs may not have this one) - (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) - (pref-filename (build-path pref-dir "qif-accounts-map")) + (let* ((pref-filename (gnc:build-dotgnucash-path "qif-accounts-map")) (results '())) ;; first, read the account map and category map from the ;; user's qif-accounts-map file. - (if (and (access? pref-dir F_OK) - (access? pref-dir X_OK) - (access? pref-filename R_OK)) + (if (access? pref-filename R_OK) (with-input-from-file pref-filename (lambda () (let ((qif-account-list #f) @@ -178,22 +175,10 @@ (define (qif-import:save-map-prefs acct-map cat-map memo-map stock-map) - (let* ((pref-dir (build-path (getenv "HOME") ".gnucash")) - (pref-filename (build-path pref-dir "qif-accounts-map")) - (save-ok #f)) + (let* ((pref-filename (gnc:build-dotgnucash-path "qif-accounts-map"))) ;; does the file exist? if not, create it; in either case, ;; make sure it's a directory and we have write and execute ;; permission. - (let ((perm (access? pref-dir F_OK))) - (if (not perm) - (mkdir pref-dir)) - (let ((stats (stat pref-dir))) - (if (and (eq? (stat:type stats) 'directory) - (access? pref-dir X_OK) - (access? pref-dir W_OK)) - (set! save-ok #t)))) - - (if save-ok (with-output-to-file pref-filename (lambda () (display ";;; qif-accounts-map\n") @@ -214,7 +199,7 @@ (display ";;; map from QIF stock name to GNC commodity") (newline) (qif-import:write-commodities stock-map) - (newline)))))) + (newline))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/scm/command-line.scm b/src/scm/command-line.scm index f48fd9f875..7ee5880688 100644 --- a/src/scm/command-line.scm +++ b/src/scm/command-line.scm @@ -145,7 +145,7 @@ Each element must be a string representing a directory or a symbol \ where 'default expands to the default path, and 'current expands to \ the current value of the path.") (let ((result (cons - (build-path (getenv "HOME") ".gnucash" "html") + (gnc:build-dotgnucash-path "html") gnc:_install-doc-path_))) (lambda () result)))) diff --git a/src/scm/main-window.scm b/src/scm/main-window.scm index 1d235118a4..944fbbb644 100644 --- a/src/scm/main-window.scm +++ b/src/scm/main-window.scm @@ -101,20 +101,10 @@ the account instead of opening a register.") #f)) (define (gnc:main-window-save-state session) (let* ((book-url (gnc:session-get-url session)) (conf-file-name (gnc:html-encode-string book-url)) - (dotgnucash-dir (build-path (getenv "HOME") ".gnucash")) - (file-dir (build-path dotgnucash-dir "books")) - (save-file? #f) (book-path #f)) - ;; make sure ~/.gnucash/books is there - (set! save-file? (and (gnc:make-dir dotgnucash-dir) - (gnc:make-dir file-dir))) - - (if (not save-file?) (gnc:warn (_ "Can't save window state"))) - - (if (and save-file? conf-file-name) - (let ((book-path (build-path (getenv "HOME") ".gnucash" "books" - conf-file-name))) + (if (conf-file-name) + (let ((book-path (gnc:build-book-path conf-file-name))) (with-output-to-port (open-output-file book-path) (lambda () (hash-fold @@ -148,7 +138,7 @@ the account instead of opening a register.") #f)) (define (gnc:main-window-book-open-handler session) (define (try-load file-suffix) - (let ((file (build-path (getenv "HOME") ".gnucash" "books" file-suffix))) + (let ((file (gnc:build-book-path file-suffix))) ;; make sure the books directory is there (if (access? file F_OK) (if (not (false-if-exception (primitive-load file))) diff --git a/src/scm/main.scm b/src/scm/main.scm index 9737527c0b..de154fe959 100644 --- a/src/scm/main.scm +++ b/src/scm/main.scm @@ -61,7 +61,6 @@ (re-export string-split) ;; from path.scm -(export gnc:make-home-dir) (export gnc:current-config-auto) (export gnc:current-saved-reports) (export gnc:current-saved-stylesheets) diff --git a/src/scm/path.scm b/src/scm/path.scm index b8eff4d0e5..4f91de5ad3 100644 --- a/src/scm/path.scm +++ b/src/scm/path.scm @@ -35,24 +35,20 @@ #t (false-if-exception (mkdir dir #o700)))) -(define (gnc:make-home-dir) - (let ((home-dir (build-path (getenv "HOME") ".gnucash"))) - (gnc:make-dir home-dir))) - (define gnc:current-config-auto - (build-path (getenv "HOME") ".gnucash" "config-2.0.auto")) + (gnc:build-dotgnucash-path "config-2.0.auto")) (define gnc:current-saved-reports - (build-path (getenv "HOME") ".gnucash" "saved-reports-2.0")) + (gnc:build-dotgnucash-path "saved-reports-2.0")) (define gnc:current-saved-stylesheets - (build-path (getenv "HOME") ".gnucash" "stylesheets-2.0")) + (gnc:build-dotgnucash-path "stylesheets-2.0")) (define gnc:load-user-config-if-needed (let ((user-config-loaded? #f)) (define (try-load-no-set file-suffix) - (let ((file (build-path (getenv "HOME") ".gnucash" file-suffix))) + (let ((file (gnc:build-dotgnucash-path file-suffix))) (gnc:debug "trying to load " file) (if (access? file F_OK) (if (false-if-exception (primitive-load file))