diff options
Diffstat (limited to 'source/blender/blenlib/intern/BLI_bfile.c')
-rw-r--r-- | source/blender/blenlib/intern/BLI_bfile.c | 357 |
1 files changed, 106 insertions, 251 deletions
diff --git a/source/blender/blenlib/intern/BLI_bfile.c b/source/blender/blenlib/intern/BLI_bfile.c index 3306283ad3f..b9ac6875b20 100644 --- a/source/blender/blenlib/intern/BLI_bfile.c +++ b/source/blender/blenlib/intern/BLI_bfile.c @@ -1,4 +1,5 @@ -/* +/* -*- indent-tabs-mode:t; tab-width:4; -*- + * * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -33,6 +34,7 @@ #else #include <io.h> #include "BLI_winstuff.h" + static char* find_in_pathlist(char* filename, char* pathlist); #endif #include <sys/types.h> #include <sys/stat.h> @@ -46,8 +48,6 @@ #include "BLI_storage.h" #include "BLI_bfile.h" -#include "GHOST_C-api.h" - /* Internal bfile classification flags */ #define BCF_OPEN (0) #define BCF_FOPEN (1<<0) @@ -62,17 +62,14 @@ /* Declaration of internal functions */ -void chomp(char* line); -void expand_envvars(char* src, char* dst); -void fill_paths(BFILE *bfile, const char *path); -char* find_in_pathlist(char* filename, char* pathlist); -void init_vars_from_file(const char* path); -void setup_temp(); +static void fill_paths(BFILE *bfile, const char *path, const char *relpath); +static void free_paths(BFILE* bfile); + /*** Exported functions ***/ BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags, - BEnvVarFam envvars) + const char *relpath) { BFILE *bfile; @@ -88,50 +85,85 @@ BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags, a BCF_AT_END | BCF_WRITE a+ BCF_AT_END | BCF_WRITE | BCF_READ */ - if(strchr(mode, 'r')) + if (strchr(mode, 'r')) bfile->classf |= BCF_READ; - if(strchr(mode, 'w')) + if (strchr(mode, 'w')) bfile->classf |= (BCF_DISCARD | BCF_WRITE); - if(strchr(mode, 'a')) + if (strchr(mode, 'a')) bfile->classf |= (BCF_AT_END | BCF_WRITE); - if(strchr(mode, '+')) + if (strchr(mode, '+')) bfile->classf |= (BCF_READ | BCF_WRITE); - fill_paths(bfile, path); + fill_paths(bfile, path, relpath); bfile->stream = fopen(bfile->tpath, mode); - // detect failed fopen + if (!(bfile->stream)) { + free_paths(bfile); + MEM_freeN(bfile); + return NULL; + } + bfile->fd = fileno(bfile->stream); + return bfile; } BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags, - BEnvVarFam envvars) + const char *relpath) { BFILE *bfile; + char fopen_mode[3]; bfile = MEM_mallocN(sizeof(BFILE), "bfile-open"); bfile->classf = BCF_OPEN; bfile->uflags = bflags; /* Easy mapping for open() */ - if(flags & O_RDONLY) + if (flags & O_RDONLY) bfile->classf |= BCF_READ; - if(flags & O_WRONLY) + if (flags & O_WRONLY) bfile->classf |= BCF_WRITE; - if(flags & O_RDWR) + if (flags & O_RDWR) bfile->classf |= (BCF_READ | BCF_WRITE); - if(flags & O_APPEND) + if (flags & O_APPEND) bfile->classf |= BCF_AT_END; - if(flags & O_TRUNC) + if (flags & O_TRUNC) bfile->classf |= BCF_DISCARD; - fill_paths(bfile, pathname); + fill_paths(bfile, pathname, relpath); bfile->fd = open(bfile->tpath, flags); - // detect failed open -// bfile->stream = fdopen(bfile->fd, XXX); /* MSWindows _fdopen? */ + if (bfile->fd == -1) { + free_paths(bfile); + MEM_freeN(bfile); + return NULL; + } + + fopen_mode[0] = 'r'; + fopen_mode[1] = '\0'; + fopen_mode[2] = '\0'; + if (bfile->classf & BCF_DISCARD) { + fopen_mode[0] = 'w'; + if (bfile->classf & BCF_READ) { + fopen_mode[1] = '+'; + } + } else if (bfile->classf & BCF_AT_END) { + fopen_mode[0] = 'a'; + if (bfile->classf & BCF_READ) { + fopen_mode[1] = '+'; + } + } else if (bfile->classf & BCF_WRITE) { + fopen_mode[1] = '+'; + } + + bfile->stream = fdopen(bfile->fd, fopen_mode); /* MSWindows _fdopen? */ + if (!(bfile->stream)) { + free_paths(bfile); + MEM_freeN(bfile); + return NULL; + } + return bfile; } @@ -175,8 +207,11 @@ size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, { size_t ret; + if (f == NULL) + return 0; + ret = fwrite(ptr, size, nmemb, f->stream); - if (ret < 0) { + if (ret <= 0) { f->error = 1; } @@ -187,8 +222,11 @@ size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) { size_t ret; + if (f == NULL) + return 0; + ret = fread(ptr, size, nmemb, f->stream); - if ((ret < 0) && ferror(f->stream)) { + if ((ret <= 0) && ferror(f->stream)) { f->error = 1; } @@ -197,21 +235,23 @@ size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) { void BLI_bfile_close(BFILE *bfile) { - if((bfile->classf | BCF_WRITE) && - !(bfile->uflags | BFILE_RAW)) { + if ((bfile->classf | BCF_WRITE) && + !(bfile->uflags | BFILE_RAW)) { + int error; /* Make sure data is on disk */ + error = fsync(bfile->fd); + /* fsync the directory too? */ /* Move to final name if no errors */ + if (!(bfile->error) && !error) { + rename(bfile->tpath, bfile->fpath); + } } /* Normal close */ /* Cleanup */ - if(bfile->fpath) { - MEM_freeN(bfile->fpath); - } - if(bfile->tpath) { - MEM_freeN(bfile->tpath); - } + free_paths(bfile); + MEM_freeN(bfile); } @@ -228,197 +268,9 @@ void BLI_bfile_set_error(BFILE *bfile, int error) { } -void BLI_bfile_init_vars() { - char file[MAXPATHLEN]; - char temp[MAXPATHLEN]; - extern char bprogname[]; - FILE* fp; - - /* This one is unconditional */ - sprintf(temp, "%d", BLENDER_VERSION); - BLI_setenv("BLENDER_VERSION", temp); - - /* Is this unpack&run? */ - sprintf(temp, "%s/%d/environment", dirname(bprogname), BLENDER_VERSION); - if(BLI_exist(temp)) { - BLI_setenv_if_new("BLENDER_SHARE", dirname(bprogname)); - } else { - BLI_setenv_if_new("BLENDER_SHARE", (const char*)GHOST_getSystemDir()); - } - - strcpy(file, (const char*)GHOST_getUserDir()); - BLI_add_slash(file); - strcat(file, LAST_SESSION_FILE); - fp = fopen(file, "r"); - /* 1st line, read previous version */ - if (fp && (fscanf(fp, "%3c\n", temp) == 1)) { - temp[3] = '\0'; - BLI_setenv("BLENDER_VERSION_PREV", temp); - /* 2nd line, read previous session path if needed */ - if(!getenv("BLENDER_TEMP")) { - if ((fgets(temp, MAXPATHLEN, fp) != NULL)) { - /* Clean any \n */ - chomp(temp); - /* Check the dir is still there or generate new one */ - if(!BLI_exist(temp)) { - setup_temp(); - } - } else { - /* We have to generate it for sure */ - setup_temp(); - } - } - } else { - /* Probably new user, or only <=249 before */ - BLI_setenv("BLENDER_VERSION_PREV", "0"); - setup_temp(); - } - - if(fp) { - fclose(fp); - } - - /* Load vars from user and system files */ - strcpy(file, (const char *)GHOST_getUserDir()); - BLI_add_slash(file); - strcat(file, ENVIRONMENT_FILE); - init_vars_from_file(file); - sprintf(temp, "/%d/environment", BLENDER_VERSION); - BLI_make_file_string("/", file, getenv("BLENDER_SHARE"), temp); - init_vars_from_file(file); -} - - /*** Internal functions ***/ /** - Eliminate trailing EOL by writing a \0 over it. - Name taken from Perl. - */ -void chomp(char* line) { - int len = strlen(line); -#ifndef WIN32 - if (line[len - 1] == '\n') { - line[len - 1] = '\0'; - } -#else - if ((line[len - 2] == '\r' ) && ((line[len - 1] == '\n'))) { - line[len - 2] = '\0'; - } -#endif /* WIN32 */ -} - - -/** - Parse a file with lines like FOO=bar (comment lines have # as first - character) assigning to envvar FOO the value bar if FOO does not - exist yet. - Any white space before FOO, around the = or trailing will be used, - so beware. - */ -#define MAX_LINE 4096 -#define ENV_VAR 256 -#define VAR_LEN 8192 -void init_vars_from_file(const char* path) { - char line[MAX_LINE]; - char name[ENV_VAR]; - FILE *fp; - char* separator; - char expanded[VAR_LEN]; - - fp = fopen(path, "r"); - if (!fp) return; - - while (fgets(line, MAX_LINE, fp) != NULL) { - /* Ignore comment lines */ - if (line[0] == '#') - continue; - - /* Split into envvar name and contents */ - separator = strchr(line, '='); - if(separator && ((separator - line) < ENV_VAR)) { - /* First remove EOL */ - chomp(line); - strncpy(name, line, separator - line); - name[separator - line] = '\0'; - expand_envvars(separator + 1, expanded); - BLI_setenv_if_new(name, expanded); - } - } - fclose(fp); -} - - -/** - Look for ${} (or %%) env vars in src and expand if the var - exists (even if empty value). If not exist, the name is left as is. - The process is done all over src, and nested ${${}} is not supported. - src must be \0 terminated, and dst must be big enough. -*/ -#ifndef WIN32 - #define ENVVAR_PREFFIX "${" - #define ENVVAR_P_SIZE 2 - #define ENVVAR_SUFFIX "}" - #define ENVVAR_S_SIZE 1 -#else - #define ENVVAR_PREFFIX "%" - #define ENVVAR_P_SIZE 1 - #define ENVVAR_SUFFIX "%" - #define ENVVAR_S_SIZE 1 -#endif /* WIN32 */ -void expand_envvars(char* src, char* dst) { - char* hit1; - char* hit2; - char name[ENV_VAR]; - char* value; - int prevlen; - int done = 0; - char* source = src; - - dst[0] = '\0'; - while (!done) { - hit1 = strstr(source, ENVVAR_PREFFIX); - if (hit1) { - hit2 = strstr(hit1 + ENVVAR_P_SIZE, ENVVAR_SUFFIX); - if (hit2) { - /* "Copy" the leading part, if any */ - if (hit1 != source) { - prevlen = strlen(dst); - strncat(dst, source, hit1 - source); - dst[prevlen + (hit1 - source)] = '\0'; - } - /* Figure the name of the env var we just found */ - strncpy(name, hit1 + ENVVAR_P_SIZE, - hit2 - (hit1 + ENVVAR_P_SIZE)); - name[hit2 - (hit1 + ENVVAR_P_SIZE)] = '\0'; - /* See if we can get something with that name */ - value = getenv(name); - if (value) { - /* Push the var value */ - strcat(dst, value); - } else { - /* Leave the var name, so it is clear that it failed */ - strcat(dst, ENVVAR_PREFFIX); - strcat(dst, name); - strcat(dst, ENVVAR_SUFFIX); - } - /* Continue after closing mark, like a new string */ - source = hit2 + ENVVAR_S_SIZE; - } else { - /* Non terminated var so "copy as is" and finish */ - strcat(dst, source); - done = 1; - } - } else { - /* "Copy" whatever is left */ - strcat(dst, source); - done = 1; - } - } -} - - -/** Return a full path if the filename exists when combined with any item from pathlist. Or NULL otherwise. */ @@ -427,7 +279,9 @@ void expand_envvars(char* src, char* dst) { #else #define SEPARATOR ':' #endif -char* find_in_pathlist(char* filename, char* pathlist) { + +#ifdef WIN32 +static char* find_in_pathlist(char* filename, char* pathlist) { char first[FILE_MAX + 10]; char* rest = NULL; @@ -445,51 +299,58 @@ char* find_in_pathlist(char* filename, char* pathlist) { /* Check if combination exists */ BLI_add_slash(first); strcat(first, filename); - if(BLI_exist(first)) { + if (BLI_exist(first)) { return strdup(first); } /* First path failed, try with rest of paths if possible */ - if(rest) { + if (rest) { return find_in_pathlist(filename, rest); } else { return NULL; } } - +#endif /** Setup fpath and tpath based in the needs of the bfile. */ -void fill_paths(BFILE *bfile, const char *path) { +static void fill_paths(BFILE *bfile, const char *path, const char *relpath) { char* source_path = NULL; char* temp_path = NULL; int bflags = bfile->uflags; - if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) { + if (bflags & BFILE_NORMAL || bflags & BFILE_RAW) { // bfile->fpath is path with // replaced } - if(bflags & BFILE_TEMP) { + if (bflags & BFILE_TEMP) { temp_path = MEM_mallocN(MAXPATHLEN, "bfile-fpath-1"); snprintf(temp_path, MAXPATHLEN, "%s/%s", getenv("BLENDER_TEMP"), path); bfile->fpath = temp_path; } - if(bflags & BFILE_CONFIG) { + if (bflags & (BFILE_CONFIG_BASE | BFILE_CONFIG_DATAFILES | + BFILE_CONFIG_PYTHON | BFILE_CONFIG_PLUGINS)) { +// evars // bfile->fpath is userdir+version+path // source_path is first hit in (if using fallback to older versions) // userdir+curversion+path (... userdir+limitversion+path) sysdir+path // (limitversion is based in path, using some kind of regex or "tables") } - if(bfile->classf & BCF_WRITE && !(bflags & BFILE_RAW)) { - /* Generate temp path */ + if (bfile->classf & BCF_WRITE && !(bflags & BFILE_RAW)) { + /* Generate random named path */ temp_path = MEM_mallocN(MAXPATHLEN, "bfile-fpath-2"); snprintf(temp_path, MAXPATHLEN, "%s.XXXXXX", path); - bfile->tpath = mkdtemp(temp_path); - if(!(bfile->classf & BCF_DISCARD)) { - /* Copy data to tpath */ - if(source_path) { - // copy it from older version or sys version + bfile->fd = mkstemp(temp_path); + bfile->tpath = temp_path; + /* It will be reopened in upper levels, later */ + close(bfile->fd); + if (!(bfile->classf & BCF_DISCARD)) { + /* Copy original data into temp location */ + if (source_path) { + BLI_copy_fileops(source_path, bfile->tpath); + } else { + BLI_copy_fileops(bfile->fpath, bfile->tpath); } } } else { @@ -499,19 +360,13 @@ void fill_paths(BFILE *bfile, const char *path) { /** - Create a temp directory in safe and multiuser way. + Free memory used for path strings. */ -void setup_temp() { - char template[MAXPATHLEN]; - char* tempdir; - - if(getenv("TMPDIR")) { - sprintf(template, "%s/blender-XXXXXX", getenv("TMPDIR")); - } else { - sprintf(template, "/tmp/blender-XXXXXX"); -// MacOSX NSTemporaryDirectory and WIN32 ??? +static void free_paths(BFILE* bfile) { + if (bfile->fpath) { + MEM_freeN(bfile->fpath); + } + if (bfile->tpath) { + MEM_freeN(bfile->tpath); } - tempdir = mkdtemp(template); - BLI_setenv("BLENDER_TEMP", tempdir); } - |