diff options
Diffstat (limited to 'base/gpmisc.c')
-rw-r--r-- | base/gpmisc.c | 159 |
1 files changed, 114 insertions, 45 deletions
diff --git a/base/gpmisc.c b/base/gpmisc.c index 34cd71fb..bae297d8 100644 --- a/base/gpmisc.c +++ b/base/gpmisc.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2019 Artifex Software, Inc. +/* Copyright (C) 2001-2020 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or @@ -401,16 +401,16 @@ generic_pread(gp_file *f, size_t count, gs_offset_t offset, void *buf) int c; int64_t os, curroff = gp_ftell(f); if (curroff < 0) return curroff; - + os = gp_fseek(f, offset, 0); if (os < 0) return os; - + c = gp_fread(buf, 1, count, f); if (c < 0) return c; - + os = gp_fseek(f, curroff, 0); if (os < 0) return os; - + return c; } @@ -420,20 +420,20 @@ generic_pwrite(gp_file *f, size_t count, gs_offset_t offset, const void *buf) int c; int64_t os, curroff = gp_ftell(f); if (curroff < 0) return curroff; - + os = gp_fseek(f, offset, 0); if (os < 0) return os; - + c = gp_fwrite(buf, 1, count, f); if (c < 0) return c; - + os = gp_fseek(f, curroff, 0); if (os < 0) return os; - + return c; } -gp_file *gp_file_alloc(gs_memory_t *mem, const gp_file_ops_t *prototype, size_t size, const char *cname) +gp_file *gp_file_alloc(const gs_memory_t *mem, const gp_file_ops_t *prototype, size_t size, const char *cname) { gp_file *file = (gp_file *)gs_alloc_bytes(mem->non_gc_memory, size, cname ? cname : "gp_file"); if (file == NULL) @@ -764,15 +764,17 @@ gp_open_printer(const gs_memory_t *mem, return file; } -gp_file * -gp_open_scratch_file(const gs_memory_t *mem, +static gp_file * +do_open_scratch_file(const gs_memory_t *mem, const char *prefix, char *fname, - const char *mode) + const char *mode, + int rm) { gp_file *file = NULL; gs_lib_ctx_t *ctx = mem->gs_lib_ctx; gs_fs_list_t *fs = ctx->core->fs; + int code = 0; /* If the prefix is absolute, then we must check it's a permissible * path. If not, we're OK. */ @@ -782,46 +784,74 @@ gp_open_scratch_file(const gs_memory_t *mem, for (fs = ctx->core->fs; fs != NULL; fs = fs->next) { - int code = 0; if (fs->fs.open_scratch) - code = fs->fs.open_scratch(mem, fs->secret, prefix, fname, mode, 0, &file); + code = fs->fs.open_scratch(mem, fs->secret, prefix, fname, mode, rm, &file); if (code < 0) return NULL; if (file != NULL) break; } + if (file == NULL) { + /* The file failed to open. Don't add it to the list. */ + } else if (rm) { + /* This file has already been deleted by the underlying system. + * We don't need to add it to the lists as it will never be + * deleted manually, nor do we need to tidy it up on closedown. */ + } else { + /* This file was not requested to be deleted. We add it to the + * list so that it will either be deleted by any future call to + * zdeletefile, OR on closedown. */ + /* Add the scratch file name to the lists. We can't do this any + * earlier as we didn't know the name until now! Unfortunately + * that makes cleanup harder. */ + code = gs_add_control_path_flags(mem, gs_permit_file_control, fname, + gs_path_control_flag_is_scratch_file); + if (code >= 0) + code = gs_add_control_path_flags(mem, gs_permit_file_reading, fname, + gs_path_control_flag_is_scratch_file); + if (code >= 0) + code = gs_add_control_path_flags(mem, gs_permit_file_writing, fname, + gs_path_control_flag_is_scratch_file); + + if (code < 0) { + gp_fclose(file); + file = NULL; + /* Call directly through to the unlink implementation. We know + * we're 'permitted' to do this, but we might not be on all the + * required permit lists because of the failure. The only bad + * thing here, is that we're deleting an fname that might not + * have come from the filing system itself. */ + if (fname && fname[0]) + gp_unlink_impl(ctx->memory, fname); + (void)gs_remove_control_path_flags(mem, gs_permit_file_control, fname, + gs_path_control_flag_is_scratch_file); + (void)gs_remove_control_path_flags(mem, gs_permit_file_reading, fname, + gs_path_control_flag_is_scratch_file); + (void)gs_remove_control_path_flags(mem, gs_permit_file_writing, fname, + gs_path_control_flag_is_scratch_file); + } + } + return file; } gp_file * +gp_open_scratch_file(const gs_memory_t *mem, + const char *prefix, + char *fname, + const char *mode) +{ + return do_open_scratch_file(mem, prefix, fname, mode, 0); +} + +gp_file * gp_open_scratch_file_rm(const gs_memory_t *mem, const char *prefix, char *fname, const char *mode) { - gp_file *file = NULL; - gs_lib_ctx_t *ctx = mem->gs_lib_ctx; - gs_fs_list_t *fs = ctx->core->fs; - - /* If the prefix is absolute, then we must check it's a permissible - * path. If not, we're OK. */ - if (gp_file_name_is_absolute(prefix, strlen(prefix)) && - gp_validate_path(mem, prefix, mode) != 0) - return NULL; - - for (fs = ctx->core->fs; fs != NULL; fs = fs->next) - { - int code = 0; - if (fs->fs.open_scratch) - code = fs->fs.open_scratch(mem, fs->secret, prefix, fname, mode, 1, &file); - if (code < 0) - return NULL; - if (file != NULL) - break; - } - - return file; + return do_open_scratch_file(mem, prefix, fname, mode, 1); } int @@ -901,7 +931,7 @@ validate(const gs_memory_t *mem, gs_path_control_t type) { gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core; - const gs_path_control_set_t *control; + gs_path_control_set_t *control; unsigned int i, n; switch (type) { @@ -921,7 +951,7 @@ validate(const gs_memory_t *mem, n = control->num; for (i = 0; i < n; i++) { const char *a = path; - const char *b = control->paths[i]; + const char *b = control->entry[i].path; while (1) { if (*a == 0) { if (*b == 0) @@ -963,7 +993,7 @@ validate(const gs_memory_t *mem, /* Continue matching */ a--; /* Subtract 1 as the loop will increment it again later */ } else if (*b == 0) { - if (b != control->paths[i] && + if (b != control->entry[i].path && gs_file_name_check_separator(b, -1, b)) { const char *a2 = a; const char *aend = path + strlen(path); @@ -1003,14 +1033,14 @@ validate(const gs_memory_t *mem, return gs_error_invalidfileaccess; found: - return 0; + return control->entry[i].flags; } int gp_validate_path_len(const gs_memory_t *mem, - const char *path, - const uint len, - const char *mode) + const char *path, + const uint len, + const char *mode) { char *buffer, *bufferfull; uint rlen; @@ -1072,6 +1102,13 @@ gp_validate_path_len(const gs_memory_t *mem, case 'c': /* "Control" */ code = validate(mem, buffer, gs_permit_file_control); break; + case 'd': /* "Delete" (special case of control) */ + code = validate(mem, buffer, gs_permit_file_control); + break; + case 'f': /* "Rename from" */ + code = (validate(mem, buffer, gs_permit_file_writing) | + validate(mem, buffer, gs_permit_file_control)); + break; case 't': /* "Rename to" */ code = (validate(mem, buffer, gs_permit_file_writing) | validate(mem, buffer, gs_permit_file_control)); @@ -1092,13 +1129,23 @@ gp_validate_path_len(const gs_memory_t *mem, } break; } + if (code > 0 && (mode[0] == 'd' || mode[0] == 'f') && + (code & gs_path_control_flag_is_scratch_file) != 0) { + (void)gs_remove_control_path_flags(mem, gs_permit_file_reading, buffer, + gs_path_control_flag_is_scratch_file); + (void)gs_remove_control_path_flags(mem, gs_permit_file_writing, buffer, + gs_path_control_flag_is_scratch_file); + (void)gs_remove_control_path_flags(mem, gs_permit_file_control, buffer, + gs_path_control_flag_is_scratch_file); + } gs_free_object(mem->non_gc_memory, bufferfull, "gp_validate_path"); #ifdef EACCES if (code == gs_error_invalidfileaccess) errno = EACCES; #endif - return code; + + return code < 0 ? code : 0; } int @@ -1108,3 +1155,25 @@ gp_validate_path(const gs_memory_t *mem, { return gp_validate_path_len(mem, path, strlen(path), mode); } + +int +gp_unlink(gs_memory_t *mem, const char *fname) +{ + if (gp_validate_path(mem, fname, "d") != 0) + return gs_error_invalidaccess; + + return gp_unlink_impl(mem, fname); +} + +int +gp_rename(gs_memory_t *mem, const char *from, const char *to) +{ + /* Always check 'to' before 'from', in case 'from' is a tempfile, + * and testing it might remove it from the list! */ + if (gp_validate_path(mem, to, "t") != 0) + return gs_error_invalidaccess; + if (gp_validate_path(mem, from, "f") != 0) + return gs_error_invalidaccess; + + return gp_rename_impl(mem, from, to); +} |