diff --git a/amiga/misc.c b/amiga/misc.c index ac9912f5b..67240006d 100755 --- a/amiga/misc.c +++ b/amiga/misc.c @@ -19,8 +19,10 @@ #include #include #include +#include #include +#include #include #include @@ -362,12 +364,76 @@ static nserror amiga_basename(const char *path, char **str, size_t *size) return NSERROR_OK; } +/** + * Ensure that all directory elements needed to store a filename exist. + * + * @param fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ +static nserror amiga_mkdir_all(const char *fname) +{ + char *dname; + char *sep; + struct stat sb; + + dname = strdup(fname); + + sep = strrchr(dname, '/'); + if (sep == NULL) { + /* no directory separator path is just filename so its ok */ + free(dname); + return NSERROR_OK; + } + + *sep = 0; /* null terminate directory path */ + + if (stat(dname, &sb) == 0) { + free(dname); + if (S_ISDIR(sb.st_mode)) { + /* path to file exists and is a directory */ + return NSERROR_OK; + } + return NSERROR_NOT_DIRECTORY; + } + *sep = '/'; /* restore separator */ + + sep = dname; + while (*sep == '/') { + sep++; + } + while ((sep = strchr(sep, '/')) != NULL) { + *sep = 0; + if (stat(dname, &sb) != 0) { + if (nsmkdir(dname, S_IRWXU) != 0) { + /* could not create path element */ + free(dname); + return NSERROR_NOT_FOUND; + } + } else { + if (! S_ISDIR(sb.st_mode)) { + /* path element not a directory */ + free(dname); + return NSERROR_NOT_DIRECTORY; + } + } + *sep = '/'; /* restore separator */ + /* skip directory separators */ + while (*sep == '/') { + sep++; + } + } + + free(dname); + return NSERROR_OK; +} + /* amiga file handling operations */ static struct gui_file_table file_table = { .mkpath = amiga_vmkpath, .basename = amiga_basename, .nsurl_to_path = amiga_nsurl_to_path, .path_to_nsurl = amiga_path_to_nsurl, + .mkdir_all = amiga_mkdir_all, }; struct gui_file_table *amiga_file_table = &file_table; diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c index 7ad649248..d29fcaac7 100644 --- a/content/fs_backing_store.c +++ b/content/fs_backing_store.c @@ -627,7 +627,7 @@ store_open(struct store_state *state, /** @todo mkdir only on write flag */ /* ensure path to file is usable */ - ret = filepath_mkdir_all(fname); + ret = netsurf_mkdir_all(fname); if (ret != NSERROR_OK) { LOG(("file path \"%s\" could not be created", fname)); free(fname); @@ -835,7 +835,9 @@ write_control(struct store_state *state) return ret; } - ret = filepath_mkdir_all(fname); + LOG(("writing control file \"%s\"", fname)); + + ret = netsurf_mkdir_all(fname); if (ret != NSERROR_OK) { free(fname); return ret; @@ -881,6 +883,8 @@ read_control(struct store_state *state) return ret; } + LOG(("opening control file \"%s\"", fname)); + fcontrol = fopen(fname, "rb"); free(fname); diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c index b3a27fea2..fd0867491 100644 --- a/desktop/gui_factory.c +++ b/desktop/gui_factory.c @@ -506,6 +506,15 @@ static nserror verify_file_register(struct gui_file_table *gft) if (gft->basename == NULL) { return NSERROR_BAD_PARAMETER; } + if (gft->nsurl_to_path == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->path_to_nsurl == NULL) { + return NSERROR_BAD_PARAMETER; + } + if (gft->mkdir_all == NULL) { + return NSERROR_BAD_PARAMETER; + } return NSERROR_OK; } diff --git a/gtk/gui.c b/gtk/gui.c index 6933c2e1e..7de448c0b 100644 --- a/gtk/gui.c +++ b/gtk/gui.c @@ -1092,7 +1092,7 @@ static nserror create_config_home(char **config_home_out) } /* ensure all elements of path exist (the trailing / is required) */ - ret = filepath_mkdir_all(config_home); + ret = netsurf_mkdir_all(config_home); if (ret != NSERROR_OK) { free(config_home); return ret; @@ -1190,7 +1190,7 @@ static nserror create_cache_home(char **cache_home_out) } /* ensure all elements of path exist (the trailing / is required) */ - ret = filepath_mkdir_all(cache_home); + ret = netsurf_mkdir_all(cache_home); if (ret != NSERROR_OK) { free(cache_home); return ret; diff --git a/riscos/Makefile.defaults b/riscos/Makefile.defaults index 8081e5c1a..f719ee3de 100644 --- a/riscos/Makefile.defaults +++ b/riscos/Makefile.defaults @@ -26,5 +26,8 @@ NETSURF_USE_PLUGINS := NO # Valid options: YES, NO NETSURF_USE_DRAW_EXPORT := YES +# Enable building the source object cache filesystem based backing store. +NETSURF_FS_BACKING_STORE := YES + # Optimisation levels CFLAGS += -O2 diff --git a/riscos/gui.c b/riscos/gui.c index e6602acf8..4c04c72ab 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -53,6 +53,7 @@ #include "desktop/netsurf.h" #include "content/urldb.h" #include "content/hlcache.h" +#include "content/backing_store.h" #include "riscos/gui.h" #include "riscos/wimputils.h" @@ -335,22 +336,6 @@ static nserror set_defaults(struct nsoption_s *defaults) } -/** - * Create directory structure for a path - * - * Given a path of x.y.z directories x and x.y will be created - * - * \param path the directory path to create - */ -static void ro_gui_create_dir(char *path) -{ - char *cur = path; - while ((cur = strchr(cur, '.'))) { - *cur = '\0'; - xosfile_create_dir(path, 0); - *cur++ = '.'; - } -} /** @@ -367,23 +352,23 @@ static void ro_gui_create_dirs(void) die("Failed to find NetSurf Choices save path"); snprintf(buf, sizeof(buf), "%s", path); - ro_gui_create_dir(buf); + netsurf_mkdir_all(buf); /* URL */ snprintf(buf, sizeof(buf), "%s", nsoption_charp(url_save)); - ro_gui_create_dir(buf); + netsurf_mkdir_all(buf); /* Hotlist */ snprintf(buf, sizeof(buf), "%s", nsoption_charp(hotlist_save)); - ro_gui_create_dir(buf); + netsurf_mkdir_all(buf); /* Recent */ snprintf(buf, sizeof(buf), "%s", nsoption_charp(recent_save)); - ro_gui_create_dir(buf); + netsurf_mkdir_all(buf); /* Theme */ snprintf(buf, sizeof(buf), "%s", nsoption_charp(theme_save)); - ro_gui_create_dir(buf); + netsurf_mkdir_all(buf); /* and the final directory part (as theme_save is a directory) */ xosfile_create_dir(buf, 0); } @@ -2337,6 +2322,33 @@ static nserror riscos_basename(const char *path, char **str, size_t *size) } +/** + * Ensure that all directory elements needed to store a filename exist. + * + * Given a path of x.y.z directories x and x.y will be created. + * + * @param fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ +static nserror riscos_mkdir_all(const char *fname) +{ + char *dname; + char *cur; + + dname = strdup(fname); + + cur = dname; + while ((cur = strchr(cur, '.'))) { + *cur = '\0'; + xosfile_create_dir(dname, 0); + *cur++ = '.'; + } + + free(dname); + + return NSERROR_OK; +} + /** * Find screen size in OS units. */ @@ -2382,6 +2394,7 @@ static struct gui_file_table riscos_file_table = { .basename = riscos_basename, .nsurl_to_path = ro_nsurl_to_path, .path_to_nsurl = ro_path_to_nsurl, + .mkdir_all = riscos_mkdir_all, }; static struct gui_fetch_table riscos_fetch_table = { @@ -2403,11 +2416,30 @@ static struct gui_browser_table riscos_browser_table = { }; +static char *get_cachepath(void) +{ + char *cachedir; + char *cachepath = NULL; + nserror ret; + + cachedir = getenv("Cache$Dir"); + if ((cachedir == NULL) || (cachedir[0] == 0)) { + LOG(("cachedir was null")); + return NULL; + } + ret = netsurf_mkpath(&cachepath, NULL, 2, cachedir, "NetSurf"); + if (ret != NSERROR_OK) { + return NULL; + } + return cachepath; +} + /** * Normal entry point from RISC OS. */ int main(int argc, char** argv) { + char *cachepath; char path[40]; int length; os_var_type type; @@ -2423,6 +2455,7 @@ int main(int argc, char** argv) .file = &riscos_file_table, .utf8 = riscos_utf8_table, .search = riscos_search_table, + .llcache = filesystem_llcache_table, }; ret = netsurf_register(&riscos_table); @@ -2473,10 +2506,14 @@ int main(int argc, char** argv) die("Failed to locate Messages resource."); } + /* obtain cache path */ + cachepath = get_cachepath(); + /* common initialisation */ - ret = netsurf_init(path, NULL); + ret = netsurf_init(path, cachepath); + free(cachepath); if (ret != NSERROR_OK) { - die("NetSurf failed to initialise"); + die("NetSurf failed to initialise core"); } artworks_init(); diff --git a/utils/file.c b/utils/file.c index a2f1e94d0..14441e00e 100644 --- a/utils/file.c +++ b/utils/file.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include "desktop/gui_factory.h" @@ -194,6 +197,69 @@ static nserror posix_path_to_nsurl(const char *path, struct nsurl **url_out) return ret; } +/** + * Ensure that all directory elements needed to store a filename exist. + * + * @param fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ +static nserror posix_mkdir_all(const char *fname) +{ + char *dname; + char *sep; + struct stat sb; + + dname = strdup(fname); + + sep = strrchr(dname, '/'); + if (sep == NULL) { + /* no directory separator path is just filename so its ok */ + free(dname); + return NSERROR_OK; + } + + *sep = 0; /* null terminate directory path */ + + if (stat(dname, &sb) == 0) { + free(dname); + if (S_ISDIR(sb.st_mode)) { + /* path to file exists and is a directory */ + return NSERROR_OK; + } + return NSERROR_NOT_DIRECTORY; + } + *sep = '/'; /* restore separator */ + + sep = dname; + while (*sep == '/') { + sep++; + } + while ((sep = strchr(sep, '/')) != NULL) { + *sep = 0; + if (stat(dname, &sb) != 0) { + if (nsmkdir(dname, S_IRWXU) != 0) { + /* could not create path element */ + free(dname); + return NSERROR_NOT_FOUND; + } + } else { + if (! S_ISDIR(sb.st_mode)) { + /* path element not a directory */ + free(dname); + return NSERROR_NOT_DIRECTORY; + } + } + *sep = '/'; /* restore separator */ + /* skip directory separators */ + while (*sep == '/') { + sep++; + } + } + + free(dname); + return NSERROR_OK; +} + /** * default to using the posix file handling */ @@ -202,6 +268,7 @@ static struct gui_file_table file_table = { .basename = posix_basename, .nsurl_to_path = posix_nsurl_to_path, .path_to_nsurl = posix_path_to_nsurl, + .mkdir_all = posix_mkdir_all, }; struct gui_file_table *default_file_table = &file_table; @@ -230,3 +297,9 @@ nserror netsurf_path_to_nsurl(const char *path, struct nsurl **url) { return guit->file->path_to_nsurl(path, url); } + +/* exported interface documented in utils/file.h */ +nserror netsurf_mkdir_all(const char *fname) +{ + return guit->file->mkdir_all(fname); +} diff --git a/utils/file.h b/utils/file.h index 2e47e1fa1..7baf2f019 100644 --- a/utils/file.h +++ b/utils/file.h @@ -106,6 +106,14 @@ struct gui_file_table { * code on faliure. */ nserror (*path_to_nsurl)(const char *path, struct nsurl **url); + + /** + * Ensure that all directory elements needed to store a filename exist. + * + * @param[in] fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ + nserror (*mkdir_all)(const char *fname); }; /** Default (posix) file operation table. */ @@ -156,4 +164,12 @@ nserror netsurf_nsurl_to_path(struct nsurl *url, char **path_out); */ nserror netsurf_path_to_nsurl(const char *path, struct nsurl **url); +/** + * Ensure that all directory elements needed to store a filename exist. + * + * @param fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ +nserror netsurf_mkdir_all(const char *fname); + #endif diff --git a/utils/filepath.c b/utils/filepath.c index c28a821d7..c07cc4874 100644 --- a/utils/filepath.c +++ b/utils/filepath.c @@ -325,60 +325,3 @@ void filepath_free_strvec(char **pathv) free(pathv); } -/* exported interface documented in filepath.h */ -nserror filepath_mkdir_all(const char *fname) -{ - char *dname; - char *sep; - struct stat sb; - - dname = strdup(fname); - - sep = strrchr(dname, '/'); - if (sep == NULL) { - /* no directory separator path is just filename so its ok */ - free(dname); - return NSERROR_OK; - } - - *sep = 0; /* null terminate directory path */ - - if (stat(dname, &sb) == 0) { - free(dname); - if (S_ISDIR(sb.st_mode)) { - /* path to file exists and is a directory */ - return NSERROR_OK; - } - return NSERROR_NOT_DIRECTORY; - } - *sep = '/'; /* restore separator */ - - sep = dname; - while (*sep == '/') { - sep++; - } - while ((sep = strchr(sep, '/')) != NULL) { - *sep = 0; - if (stat(dname, &sb) != 0) { - if (nsmkdir(dname, S_IRWXU) != 0) { - /* could not create path element */ - free(dname); - return NSERROR_NOT_FOUND; - } - } else { - if (! S_ISDIR(sb.st_mode)) { - /* path element not a directory */ - free(dname); - return NSERROR_NOT_DIRECTORY; - } - } - *sep = '/'; /* restore separator */ - /* skip directory separators */ - while (*sep == '/') { - sep++; - } - } - - free(dname); - return NSERROR_OK; -} diff --git a/utils/filepath.h b/utils/filepath.h index 61b7209cc..ad077e2ce 100644 --- a/utils/filepath.h +++ b/utils/filepath.h @@ -127,13 +127,5 @@ char **filepath_path_to_strvec(const char *path); void filepath_free_strvec(char **pathv); -/** - * Ensure that all directory elements needed to store a filename exist. - * - * @param fname The filename to ensure the path to exists. - * @return NSERROR_OK on success or error code on failure. - */ -nserror filepath_mkdir_all(const char *fname); - #endif /* _NETSURF_UTILS_FILEPATH_H_ */ diff --git a/windows/gui.c b/windows/gui.c index 8cf36d020..21eff0ef4 100644 --- a/windows/gui.c +++ b/windows/gui.c @@ -2009,12 +2009,76 @@ static nserror windows_path_to_nsurl(const char *path, struct nsurl **url_out) return ret; } +/** + * Ensure that all directory elements needed to store a filename exist. + * + * @param fname The filename to ensure the path to exists. + * @return NSERROR_OK on success or error code on failure. + */ +static nserror windows_mkdir_all(const char *fname) +{ + char *dname; + char *sep; + struct stat sb; + + dname = strdup(fname); + + sep = strrchr(dname, '\\'); + if (sep == NULL) { + /* no directory separator path is just filename so its ok */ + free(dname); + return NSERROR_OK; + } + + *sep = 0; /* null terminate directory path */ + + if (stat(dname, &sb) == 0) { + free(dname); + if (S_ISDIR(sb.st_mode)) { + /* path to file exists and is a directory */ + return NSERROR_OK; + } + return NSERROR_NOT_DIRECTORY; + } + *sep = '\\'; /* restore separator */ + + sep = dname; + while (*sep == '\\') { + sep++; + } + while ((sep = strchr(sep, '\\')) != NULL) { + *sep = 0; + if (stat(dname, &sb) != 0) { + if (nsmkdir(dname, S_IRWXU) != 0) { + /* could not create path element */ + free(dname); + return NSERROR_NOT_FOUND; + } + } else { + if (! S_ISDIR(sb.st_mode)) { + /* path element not a directory */ + free(dname); + return NSERROR_NOT_DIRECTORY; + } + } + *sep = '\\'; /* restore separator */ + /* skip directory separators */ + while (*sep == '\\') { + sep++; + } + } + + free(dname); + return NSERROR_OK; +} + /* windows file handling */ static struct gui_file_table file_table = { .mkpath = windows_mkpath, .basename = windows_basename, .nsurl_to_path = windows_nsurl_to_path, .path_to_nsurl = windows_path_to_nsurl, + .mkdir_all = windows_mkdir_all, }; struct gui_file_table *win32_file_table = &file_table;