GnuCash 2.4.99
gnc-filepath-utils.c
00001 /********************************************************************\
00002  * gnc-filepath-utils.c -- file path resolutin utilitie             *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020 \********************************************************************/
00021 
00022 /*
00023  * @file gnc-filepath-utils.c
00024  * @brief file path resolution utilities
00025  * @author Copyright (c) 1998-2004 Linas Vepstas <linas@linas.org>
00026  * @author Copyright (c) 2000 Dave Peticolas
00027  */
00028 
00029 #include "config.h"
00030 
00031 #include <glib.h>
00032 #include <glib/gi18n.h>
00033 #include <glib/gprintf.h>
00034 #include <glib/gstdio.h>
00035 
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #ifdef HAVE_UNISTD_H
00042 # include <unistd.h>
00043 #endif
00044 #include <errno.h>
00045 
00046 #include "gnc-path.h"
00047 #include "gnc-filepath-utils.h"
00048 
00049 #ifdef _MSC_VER
00050 #include <glib/gwin32.h>
00051 #define PATH_MAX MAXPATHLEN
00052 #endif
00053 
00054 
00061 static void
00062 scrub_filename(char* filename)
00063 {
00064     char* p;
00065 
00066 #define STRANGE_CHARS "/:"
00067     p = strpbrk(filename, STRANGE_CHARS);
00068     while (p)
00069     {
00070         *p = '_';
00071         p = strpbrk(filename, STRANGE_CHARS);
00072     }
00073 }
00074 
00081 static gchar *
00082 check_path_return_if_valid(gchar *path)
00083 {
00084     if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
00085     {
00086         return path;
00087     }
00088     g_free (path);
00089     return NULL;
00090 }
00091 
00119 gchar *
00120 gnc_resolve_file_path (const gchar * filefrag)
00121 {
00122     int namelen;
00123     gchar *fullpath = NULL, *tmp_path = NULL;
00124 
00125     /* seriously invalid */
00126     if (!filefrag)
00127     {
00128         g_critical("filefrag is NULL");
00129         return NULL;
00130     }
00131 
00132     /* ---------------------------------------------------- */
00133     /* OK, now we try to find or build an absolute file path */
00134 
00135     /* check for an absolute file path */
00136     if (g_path_is_absolute(filefrag))
00137         return g_strdup (filefrag);
00138 
00139     /* get conservative on the length so that sprintf(getpid()) works ... */
00140     /* strlen ("/.LCK") + sprintf (%x%d) */
00141     namelen = strlen (filefrag) + 25;
00142 
00143     /* Look in the current working directory */
00144     tmp_path = g_get_current_dir();
00145     fullpath = g_build_filename(tmp_path, filefrag, (gchar *)NULL);
00146     g_free(tmp_path);
00147     fullpath = check_path_return_if_valid(fullpath);
00148     if (fullpath != NULL)
00149         return fullpath;
00150 
00151     /* Look in the data dir (e.g. $PREFIX/share/gnucash) */
00152     tmp_path = gnc_path_get_pkgdatadir();
00153     fullpath = g_build_filename(tmp_path, filefrag, (gchar *)NULL);
00154     g_free(tmp_path);
00155     fullpath = check_path_return_if_valid(fullpath);
00156     if (fullpath != NULL)
00157         return fullpath;
00158 
00159     /* Look in the config dir (e.g. $PREFIX/share/gnucash/accounts) */
00160     tmp_path = gnc_path_get_accountsdir();
00161     fullpath = g_build_filename(tmp_path, filefrag, (gchar *)NULL);
00162     g_free(tmp_path);
00163     fullpath = check_path_return_if_valid(fullpath);
00164     if (fullpath != NULL)
00165         return fullpath;
00166 
00167     /* Look in the users config dir (e.g. $HOME/.gnucash/data) */
00168     fullpath = gnc_build_data_path(filefrag);
00169     if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR))
00170         return fullpath;
00171 
00172     /* OK, it's not there. Note that it needs to be created and pass it
00173      * back anyway */
00174     g_warning("create new file %s", fullpath);
00175     return fullpath;
00176 
00177 }
00178 
00179 /* ====================================================================== */
00180 
00186 static void
00187 gnc_validate_directory (const gchar *dirname)
00188 {
00189     struct stat statbuf;
00190     gint rc;
00191 
00192     rc = g_stat (dirname, &statbuf);
00193     if (rc)
00194     {
00195         switch (errno)
00196         {
00197         case ENOENT:
00198             rc = g_mkdir (dirname,
00199 #ifdef G_OS_WIN32
00200                           0          /* The mode argument is ignored on windows */
00201 #else
00202                           S_IRWXU    /* perms = S_IRWXU = 0700 */
00203 #endif
00204                          );
00205             if (rc)
00206             {
00207                 g_fprintf(stderr,
00208                           _("An error occurred while creating the directory:\n"
00209                             "  %s\n"
00210                             "Please correct the problem and restart GnuCash.\n"
00211                             "The reported error was '%s' (errno %d).\n"),
00212                           dirname, g_strerror(errno) ? g_strerror(errno) : "", errno);
00213                 exit(1);
00214             }
00215             g_stat (dirname, &statbuf);
00216             break;
00217 
00218         case EACCES:
00219             g_fprintf(stderr,
00220                       _("The directory\n"
00221                         "  %s\n"
00222                         "exists but cannot be accessed.  This program \n"
00223                         "must have full access (read/write/execute) to \n"
00224                         "the directory in order to function properly.\n"),
00225                       dirname);
00226             exit(1);
00227 
00228         case ENOTDIR:
00229             g_fprintf(stderr,
00230                       _("The path\n"
00231                         "  %s\n"
00232                         "exists but it is not a directory. Please delete\n"
00233                         "the file and start GnuCash again.\n"),
00234                       dirname);
00235             exit(1);
00236 
00237         default:
00238             g_fprintf(stderr,
00239                       _("An unknown error occurred when validating that the\n"
00240                         "  %s\n"
00241                         "directory exists and is usable. Please correct the\n"
00242                         "problem and restart GnuCash.  The reported error \n"
00243                         "was '%s' (errno %d)."),
00244                       dirname, g_strerror(errno) ? g_strerror(errno) : "", errno);
00245             exit(1);
00246         }
00247     }
00248 
00249     if ((statbuf.st_mode & S_IFDIR) != S_IFDIR)
00250     {
00251         g_fprintf(stderr,
00252                   _("The path\n"
00253                     "  %s\n"
00254                     "exists but it is not a directory. Please delete\n"
00255                     "the file and start GnuCash again.\n"),
00256                   dirname);
00257         exit(1);
00258     }
00259 #ifndef G_OS_WIN32
00260     /* The mode argument is ignored on windows anyway */
00261     if ((statbuf.st_mode & S_IRWXU) != S_IRWXU)
00262     {
00263         g_fprintf(stderr,
00264                   _("The permissions are wrong on the directory\n"
00265                     "  %s\n"
00266                     "They must be at least 'rwx' for the user.\n"),
00267                   dirname);
00268         exit(1);
00269     }
00270 #endif
00271 }
00272 
00281 const gchar *
00282 gnc_dotgnucash_dir (void)
00283 {
00284     static gchar *dotgnucash = NULL;
00285     gchar *tmp_dir;
00286 
00287     if (dotgnucash)
00288         return dotgnucash;
00289 
00290     dotgnucash = g_strdup(g_getenv("GNC_DOT_DIR"));
00291 
00292     if (!dotgnucash)
00293     {
00294         const gchar *home = g_get_home_dir();
00295         if (!home)
00296         {
00297             g_warning("Cannot find home directory. Using tmp directory instead.");
00298             home = g_get_tmp_dir();
00299         }
00300         g_assert(home);
00301 
00302         dotgnucash = g_build_filename(home, ".gnucash", (gchar *)NULL);
00303     }
00304     gnc_validate_directory(dotgnucash);
00305 
00306     /* Since we're in code that is only executed once.... */
00307     tmp_dir = g_build_filename(dotgnucash, "books", (gchar *)NULL);
00308     gnc_validate_directory(tmp_dir);
00309     g_free(tmp_dir);
00310     tmp_dir = g_build_filename(dotgnucash, "checks", (gchar *)NULL);
00311     gnc_validate_directory(tmp_dir);
00312     g_free(tmp_dir);
00313     tmp_dir = g_build_filename(dotgnucash, "translog", (gchar *)NULL);
00314     gnc_validate_directory(tmp_dir);
00315     g_free(tmp_dir);
00316 
00317     return dotgnucash;
00318 }
00319 
00328 gchar *
00329 gnc_build_dotgnucash_path (const gchar *filename)
00330 {
00331     return g_build_filename(gnc_dotgnucash_dir(), filename, (gchar *)NULL);
00332 }
00333 
00342 gchar *
00343 gnc_build_book_path (const gchar *filename)
00344 {
00345     gchar* filename_dup = g_strdup(filename);
00346     gchar* result = NULL;
00347 
00348     scrub_filename(filename_dup);
00349     result = g_build_filename(gnc_dotgnucash_dir(), "books",
00350                               filename_dup, (gchar *)NULL);
00351     g_free(filename_dup);
00352     return result;
00353 }
00354 
00363 gchar *
00364 gnc_build_translog_path (const gchar *filename)
00365 {
00366     gchar* filename_dup = g_strdup(filename);
00367     gchar* result = NULL;
00368 
00369     scrub_filename(filename_dup);
00370     result = g_build_filename(gnc_dotgnucash_dir(), "translog",
00371                               filename_dup, (gchar *)NULL);
00372     g_free(filename_dup);
00373     return result;
00374 }
00375 
00384 gchar *
00385 gnc_build_data_path (const gchar *filename)
00386 {
00387     gchar* filename_dup = g_strdup(filename);
00388     gchar* result;
00389 
00390     scrub_filename(filename_dup);
00391     result = g_build_filename(gnc_dotgnucash_dir(), "data", filename_dup, (gchar *)NULL);
00392     g_free(filename_dup);
00393     return result;
00394 }
00395 
00404 gchar *
00405 gnc_build_report_path (const gchar *filename)
00406 {
00407     gchar *result = g_build_filename(gnc_path_get_reportdir(), filename, (gchar *)NULL);
00408     return result;
00409 }
00410 
00419 gchar *
00420 gnc_build_stdreports_path (const gchar *filename)
00421 {
00422     gchar *result = g_build_filename(gnc_path_get_stdreportsdir(), filename, (gchar *)NULL);
00423     return result;
00424 }
00425 
00426 
00427 /* =============================== END OF FILE ========================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines