To: vim-dev@vim.org Subject: Patch 5.7.025 (fixed) Fcc: outbox From: Bram Moolenaar ------------ NOTE: This patch was sent before, but contained a patch for src/os_msdos.h, which is only in the extra archive. That part has been moved to patch 5.7.026 now. Otherwise it's the same patch again. Patch 5.7.025 (fixed) Problem: Creating a temp file has a race condition. Solution: Create a private directory to write the temp files in. Files: src/fileio.c, src/misc1.c, src/proto/misc1.pro, src/proto/fileio.pro, src/memline.c, src/os_unix.h *** ../vim-5.7.24/src/fileio.c Tue Jun 27 20:54:03 2000 --- src/fileio.c Thu Mar 8 14:35:54 2001 *************** *** 3015,3020 **** --- 3015,3053 ---- write_no_eol_lnum += offset; } + #if defined(TEMPDIRNAMES) || defined(PROTO) + static char_u *vim_tempdir = NULL; /* Name of Vim's own temp dir. */ + static long temp_count = 0; /* Temp filename counter. */ + + /* + * Delete the temp directory and all files it contains. + */ + void + vim_deltempdir() + { + char_u **files; + int file_count; + int i; + + if (vim_tempdir != NULL) + { + sprintf((char *)NameBuff, "%s*", vim_tempdir); + if (gen_expand_wildcards(1, &NameBuff, &file_count, &files, + EW_DIR|EW_FILE|EW_SILENT) == OK) + { + for (i = 0; i < file_count; ++i) + mch_remove(files[i]); + FreeWild(file_count, files); + } + gettail(NameBuff)[-1] = NUL; + (void)mch_rmdir(NameBuff); + + vim_free(vim_tempdir); + vim_tempdir = NULL; + } + } + #endif + /* * vim_tempname(): Return a unique name that can be used for a temp file. * *************** *** 3027,3091 **** vim_tempname(extra_char) int extra_char; /* character to use in the name instead of '?' */ { - #ifdef WIN32 - char szTempFile[_MAX_PATH+1]; - char buf4[4]; - #endif #ifdef USE_TMPNAM char_u itmp[L_tmpnam]; /* use tmpnam() */ #else char_u itmp[TEMPNAMELEN]; #endif - #if defined(TEMPDIRNAMES) || !defined(USE_TMPNAM) - char_u *p; - #endif #ifdef TEMPDIRNAMES static char *(tempdirs[]) = {TEMPDIRNAMES}; - static int first_dir = 0; - int first_try = TRUE; int i; /* ! * Try a few places to put the temp file. ! * To avoid waisting time with non-existing environment variables and ! * directories, they are skipped next time. */ ! for (i = first_dir; i < sizeof(tempdirs) / sizeof(char *); ++i) { ! /* expand $TMP, leave room for '/', "v?XXXXXX" and NUL */ ! expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 10); ! if (mch_isdir(itmp)) /* directory exists */ { ! if (first_try) ! first_dir = i; /* start here next time */ ! first_try = FALSE; # ifdef __EMX__ ! /* ! * if $TMP contains a forward slash (perhaps because we're using ! * bash or tcsh, right Stefan?), don't add a backslash to the ! * directory before tacking on the file name; use a forward slash! ! * I first tried adding 2 backslashes, but somehow that didn't ! * work (something in the EMX system() ate them, I think). ! */ ! if (vim_strchr(itmp, '/')) ! STRCAT(itmp, "/"); ! else # endif ! add_pathsep(itmp); ! STRCAT(itmp, TEMPNAME); ! if ((p = vim_strchr(itmp, '?')) != NULL) ! *p = extra_char; ! if (mktemp((char *)itmp) == NULL) ! continue; ! return vim_strsave(itmp); } } return NULL; #else /* !TEMPDIRNAMES */ # ifdef WIN32 STRCPY(itmp, ""); if (GetTempPath(_MAX_PATH, szTempFile) == 0) szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */ --- 3060,3172 ---- vim_tempname(extra_char) int extra_char; /* character to use in the name instead of '?' */ { #ifdef USE_TMPNAM char_u itmp[L_tmpnam]; /* use tmpnam() */ #else char_u itmp[TEMPNAMELEN]; #endif #ifdef TEMPDIRNAMES static char *(tempdirs[]) = {TEMPDIRNAMES}; int i; + long nr; + long off; + # ifndef EEXIST + struct stat st; + # endif /* ! * This will create a directory for private use by this instance of Vim. ! * This is done once, and the same directory is used for all temp files. ! * This method avoids security problems because of symlink attacks et al. ! * It's also a bit faster, because we only need to check for an existing ! * file when creating the directory and not for each temp file. */ ! if (vim_tempdir == NULL) { ! /* ! * Try the entries in TEMPDIRNAMES to create the temp directory. ! */ ! for (i = 0; i < sizeof(tempdirs) / sizeof(char *); ++i) { ! /* expand $TMP, leave room for "/v1100000/999999999" */ ! expand_env((char_u *)tempdirs[i], itmp, TEMPNAMELEN - 20); ! if (mch_isdir(itmp)) /* directory exists */ ! { # ifdef __EMX__ ! /* If $TMP contains a forward slash (perhaps using bash or ! * tcsh), don't add a backslash, use a forward slash! ! * Adding 2 backslashes didn't work. */ ! if (vim_strchr(itmp, '/') != NULL) ! STRCAT(itmp, "/"); ! else # endif ! add_pathsep(itmp); ! ! /* Get an arbitrary number of up to 6 digits. When it's ! * unlikely that it already exists it will be faster, ! * otherwise it doesn't matter. The use of mkdir() avoids any ! * security problems because of the predictable number. */ ! nr = (mch_get_pid() + (long)time(NULL)) % 1000000L; ! ! /* Try up to 10000 different values until we find a name that ! * doesn't exist. */ ! for (off = 0; off < 10000L; ++off) ! { ! sprintf((char *)itmp + STRLEN(itmp), "v%ld", nr + off); ! # ifndef EEXIST ! /* If mkdir() does not set errno to EEXIST, check for ! * existing file here. There is a race condition then, ! * although it's fail-safe. */ ! if (mch_stat((char *)itmp, &st) >= 0) ! continue; ! # endif ! if (vim_mkdir(itmp, 0700) == 0) ! { ! /* Directory was created, use this name. */ ! # ifdef __EMX__ ! if (vim_strchr(itmp, '/') != NULL) ! STRCAT(itmp, "/"); ! else ! # endif ! add_pathsep(itmp); ! /* Use the full path; When using the current directory ! * a ":cd" would confuse us. */ ! vim_tempdir = FullName_save(itmp, FALSE); ! break; ! } ! # ifdef EEXIST ! /* If the mkdir() didn't fail because the file/dir exists, ! * we probably can't create any dir here, try another ! * place. */ ! if (errno != EEXIST) ! # endif ! break; ! } ! if (vim_tempdir != NULL) ! break; ! } } } + + if (vim_tempdir != NULL) + { + /* There is no need to check if the file exists, because we own the + * directory and nobody else creates a file in it. */ + sprintf((char *)itmp, "%s%ld", vim_tempdir, temp_count++); + return vim_strsave(itmp); + } + return NULL; #else /* !TEMPDIRNAMES */ # ifdef WIN32 + char szTempFile[_MAX_PATH + 1]; + char buf4[4]; + char_u *retval; + char_u *p; + STRCPY(itmp, ""); if (GetTempPath(_MAX_PATH, szTempFile) == 0) szTempFile[0] = NUL; /* GetTempPath() failed, use current dir */ *************** *** 3095,3106 **** return NULL; /* GetTempFileName() will create the file, we don't want that */ (void)DeleteFile(itmp); ! # else # ifdef USE_TMPNAM /* tmpnam() will make its own name */ if (*tmpnam((char *)itmp) == NUL) return NULL; # else # ifdef VMS_TEMPNAM /* mktemp() is not working on VMS. It seems to be * a do-nothing function. Therefore we use tempnam(). --- 3176,3201 ---- return NULL; /* GetTempFileName() will create the file, we don't want that */ (void)DeleteFile(itmp); ! ! /* Backslashes in a temp file name cause problems when filtering with ! * "sh". NOTE: This also checks 'shellcmdflag' to help those people who ! * didn't set 'shellslash'. */ ! retval = vim_strsave(itmp); ! if (*p_shcf == '-' || p_ssl) ! for (p = retval; *p; ++p) ! if (*p == '\\') ! *p = '/'; ! return retval; ! ! # else /* WIN32 */ ! # ifdef USE_TMPNAM /* tmpnam() will make its own name */ if (*tmpnam((char *)itmp) == NUL) return NULL; # else + char_u *p; + # ifdef VMS_TEMPNAM /* mktemp() is not working on VMS. It seems to be * a do-nothing function. Therefore we use tempnam(). *************** *** 3125,3149 **** return NULL; # endif # endif ! # endif - # ifdef WIN32 - { - char_u *retval; - - /* Backslashes in a temp file name cause problems when filtering with - * "sh". NOTE: This ignores 'shellslash' because forward slashes - * always work here. */ - retval = vim_strsave(itmp); - if (*p_shcf == '-') - for (p = retval; *p; ++p) - if (*p == '\\') - *p = '/'; - return retval; - } - # else return vim_strsave(itmp); - # endif #endif /* !TEMPDIRNAMES */ } --- 3220,3228 ---- return NULL; # endif # endif ! # endif /* WIN32 */ return vim_strsave(itmp); #endif /* !TEMPDIRNAMES */ } *** ../vim-5.7.24/src/misc1.c Tue Nov 28 22:50:07 2000 --- src/misc1.c Thu Mar 8 15:00:22 2001 *************** *** 5298,5307 **** } } - #ifndef NO_EXPANDPATH - static int gen_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)); - #endif - /* * Expand wildcards. Calls gen_expand_wildcards() and removes files matching * 'wildignore'. --- 5298,5303 ---- *************** *** 5446,5452 **** * Return OK when some files found. "num_file" is set to the number of * matches, "file" to the array of matches. Call FreeWild() later. */ ! static int gen_expand_wildcards(num_pat, pat, num_file, file, flags) int num_pat; /* number of input patterns */ char_u **pat; /* array of input patterns */ --- 5442,5448 ---- * Return OK when some files found. "num_file" is set to the number of * matches, "file" to the array of matches. Call FreeWild() later. */ ! int gen_expand_wildcards(num_pat, pat, num_file, file, flags) int num_pat; /* number of input patterns */ char_u **pat; /* array of input patterns */ *** ../vim-5.7.24/src/proto/fileio.pro Sat Jun 24 11:18:39 2000 --- src/proto/fileio.pro Thu Mar 8 14:52:32 2001 *************** *** 11,16 **** --- 11,17 ---- void check_timestamps __ARGS((int focus)); int buf_check_timestamp __ARGS((BUF *buf, int focus)); void write_lnum_adjust __ARGS((linenr_t offset)); + void vim_deltempdir __ARGS((void)); char_u *vim_tempname __ARGS((int extra_char)); void do_augroup __ARGS((char_u *arg)); int check_ei __ARGS((void)); *** ../vim-5.7.24/src/proto/misc1.pro Sat Jun 24 11:18:53 2000 --- src/proto/misc1.pro Thu Mar 8 14:59:24 2001 *************** *** 59,64 **** --- 59,65 ---- void line_breakcheck __ARGS((void)); int expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)); int match_suffix __ARGS((char_u *fname)); + int gen_expand_wildcards __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)); void addfile __ARGS((struct growarray *gap, char_u *f, int flags)); char_u *get_cmd_output __ARGS((char_u *cmd, int flags)); void FreeWild __ARGS((int num, char_u **file)); *** ../vim-5.7.24/src/memline.c Wed Jun 7 21:08:32 2000 --- src/memline.c Thu Mar 8 14:38:05 2001 *************** *** 567,572 **** --- 567,575 ---- for (buf = firstbuf; buf != NULL; buf = buf->b_next) ml_close(buf, del_file); + #ifdef TEMPDIRNAMES + vim_deltempdir(); /* delete created temp directory */ + #endif } /* *** ../vim-5.7.24/src/os_unix.h Wed Jun 7 13:56:51 2000 --- src/os_unix.h Thu Mar 8 14:51:55 2001 *************** *** 85,90 **** --- 85,92 ---- /* always use unlink() to remove files */ #ifndef PROTO + # define vim_mkdir(x, y) mkdir((char *)(x), y) + # define mch_rmdir(x) rmdir((char *)(x)) # define mch_remove(x) unlink((char *)(x)) #endif *************** *** 276,282 **** # define TEMPNAME "v?XXXXXX" # define TEMPNAMELEN 128 #else ! # define TEMPDIRNAMES "$TMPDIR", "/tmp", "" # define TEMPNAME "v?XXXXXX" # define TEMPNAMELEN 256 #endif --- 278,284 ---- # define TEMPNAME "v?XXXXXX" # define TEMPNAMELEN 128 #else ! # define TEMPDIRNAMES "$TMPDIR", "/tmp", ".", "$HOME" # define TEMPNAME "v?XXXXXX" # define TEMPNAMELEN 256 #endif *** ../vim-5.7.24/src/version.c Mon Jan 29 21:37:18 2001 --- src/version.c Thu Mar 8 14:48:26 2001 *************** *** 439,440 **** --- 439,442 ---- { /* Add new patch number below this line */ + /**/ + 25, /**/ -- hundred-and-one symptoms of being an internet addict: 97. Your mother tells you to remember something, and you look for a File/Save command. /// Bram Moolenaar -- Bram@moolenaar.net -- http://www.moolenaar.net \\\ ((( Creator of Vim - http://www.vim.org -- ftp://ftp.vim.org/pub/vim ))) \\\ Help me helping AIDS orphans in Uganda - http://iccf-holland.org ///