From 1e842bc4450f5456c6bd700e9f179d12f95238fe Mon Sep 17 00:00:00 2001 From: sgerwk Date: Wed, 31 Mar 2021 19:24:26 +0200 Subject: [PATCH] join temp file name creation and file creation --- src/osdep/osdep.c | 81 ++++++++++++++++++++++++++++++++++++++++++ src/osdep/osdep.h | 1 + src/session/download.c | 39 ++++++++------------ src/session/download.h | 7 +++- 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/src/osdep/osdep.c b/src/osdep/osdep.c index 23d04cf8e..5863d6961 100644 --- a/src/osdep/osdep.c +++ b/src/osdep/osdep.c @@ -1018,3 +1018,84 @@ get_system_str(int xwin) { return xwin ? SYSTEM_STR "-xwin" : SYSTEM_STR; } + +#if _DEFAULT_SOURCE || _SVID_SOURCE || _BSD_SOURCE + +/* tempnam() replacement without races */ + +int isdirectory(char *path) { + struct stat ss; + if (path == NULL) + return 0; + if (-1 == stat(path, &ss)) + return 0; + return S_ISDIR(ss.st_mode); +} + +char *tempname(char *dir, char *pfx, char *suff) { + struct string path; + char *ret; + int fd; + + if (isdirectory(getenv("TMPDIR"))) + dir = getenv("TMPDIR"); + else if (dir != NULL) + dir = dir; + else if (isdirectory(P_tmpdir)) + dir = P_tmpdir; + else if (isdirectory("/tmp")) + dir = "/tmp"; + else { + errno = ENOTDIR; + return NULL; + } + + if (!init_string(&path)) { + errno = ENOMEM; + return NULL; + } + add_to_string(&path, dir); + add_to_string(&path, "/"); + add_to_string(&path, pfx); + add_to_string(&path, "XXXXXX"); + if (suff) + add_shell_safe_to_string(&path, suff, strlen(suff)); + + fd = mkstemps(path.source, suff ? strlen(suff) : 0); + if (fd == -1) { + done_string(&path); + errno = ENOENT; + return NULL; + } + close(fd); + + ret = strdup(path.source); + done_string(&path); + return ret; +} + +#else + +#warning mkstemps does not exist, using tempnam +char *tempname(char *dir, char *pfx, char *suff) { + char *temp, *ret; + struct string name; + + temp = tempnam(dir, pfx); + if (temp == NULL) + return NULL; + + if (!init_string(&name)) { + free(temp); + return NULL; + } + add_to_string(&name, temp); + free(temp); + add_shell_safe_to_string(&name, suff, strlen(suff)); + + ret = strdup(name.source); + done_string(&name); + return ret; +} + +#endif diff --git a/src/osdep/osdep.h b/src/osdep/osdep.h index 046aeb511..06a9eac98 100644 --- a/src/osdep/osdep.h +++ b/src/osdep/osdep.h @@ -52,6 +52,7 @@ int resize_window(int, int, int, int); int can_resize_window(int); int can_open_os_shell(int); void set_highpri(void); +char *tempname(char *dir, char *pfx, char *suff); #ifdef USE_OPEN_PREALLOC int open_prealloc(char *, int, int, off_t); diff --git a/src/session/download.c b/src/session/download.c index a0f1c4fdd..d4efa348d 100644 --- a/src/session/download.c +++ b/src/session/download.c @@ -800,7 +800,7 @@ lookup_unique_name(struct terminal *term, char *ofile, } /* Check if the file already exists (file != ofile). */ - file = get_unique_name(ofile); + file = (flags & DOWNLOAD_OVERWRITE) ? ofile : get_unique_name(ofile); if (!file || overwrite == 1 || file == ofile) { /* Still nothing special to do... */ @@ -885,7 +885,9 @@ create_download_file_do(struct terminal *term, char *file, * --pasky */ h = open(file, O_CREAT | O_WRONLY | (flags & DOWNLOAD_RESUME_SELECTED ? 0 : O_TRUNC) - | (sf && !(flags & DOWNLOAD_RESUME_SELECTED) ? O_EXCL : 0), + | (sf && + !(flags & DOWNLOAD_RESUME_SELECTED) && + !(flags & DOWNLOAD_OVERWRITE) ? O_EXCL : 0), sf ? 0600 : 0666); saved_errno = errno; /* Saved in case of ... --Zas */ @@ -999,31 +1001,17 @@ create_download_file(struct terminal *term, char *fi, static char * get_temp_name(struct uri *uri) { - struct string name; char *extension; - /* FIXME - * We use tempnam() here, which is unsafe (race condition), for now. - * This should be changed at some time, but it needs an in-depth work - * of whole download code. --Zas */ - char *nm = tempnam(NULL, ELINKS_TEMPNAME_PREFIX); - - if (!nm) return NULL; - - if (!init_string(&name)) { - free(nm); - return NULL; - } - - add_to_string(&name, nm); - free(nm); + char *nm; extension = get_extension_from_uri(uri); - if (extension) { - add_shell_safe_to_string(&name, extension, strlen(extension)); - mem_free(extension); - } + if (!extension) + extension = stracpy(""); - return name.source; + nm = tempname(NULL, ELINKS_TEMPNAME_PREFIX, extension); + mem_free(extension); + + return nm; } @@ -1321,7 +1309,6 @@ continue_download(void *data, char *file) } if (type_query->external_handler) { - /* FIXME: get_temp_name() calls tempnam(). --Zas */ file = get_temp_name(type_query->uri); if (!file) { mem_free(codw_hop); @@ -1338,7 +1325,9 @@ continue_download(void *data, char *file) create_download_file(type_query->ses->tab->term, file, &codw_hop->real_file, type_query->external_handler - ? DOWNLOAD_RESUME_ALLOWED | DOWNLOAD_EXTERNAL + ? DOWNLOAD_RESUME_ALLOWED | + DOWNLOAD_EXTERNAL | + DOWNLOAD_OVERWRITE : DOWNLOAD_RESUME_ALLOWED, continue_download_do, codw_hop); } diff --git a/src/session/download.h b/src/session/download.h index 3d3085f7c..0fd657342 100644 --- a/src/session/download.h +++ b/src/session/download.h @@ -39,7 +39,12 @@ enum download_flags { DOWNLOAD_RESUME_SELECTED = 2, /** The file will be opened in an external handler. */ - DOWNLOAD_EXTERNAL = 4 + DOWNLOAD_EXTERNAL = 4, + + /** File overwriting is allowed. This is for temp names, since + * the file is created by the same function that chooses its + * name. */ + DOWNLOAD_OVERWRITE = 8 }; struct download {