diff options
Diffstat (limited to 'src/nvim/memline.c')
-rw-r--r-- | src/nvim/memline.c | 123 |
1 files changed, 76 insertions, 47 deletions
diff --git a/src/nvim/memline.c b/src/nvim/memline.c index d90e91be5d..aa3e0e0b1c 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -406,10 +406,12 @@ void ml_setname(buf_T *buf) * Try all directories in the 'directory' option. */ dirp = p_dir; + bool found_existing_dir = false; for (;; ) { if (*dirp == NUL) /* tried all directories, fail */ break; - fname = findswapname(buf, &dirp, mfp->mf_fname); + fname = (char_u *)findswapname(buf, (char **)&dirp, (char *)mfp->mf_fname, + &found_existing_dir); /* alloc's fname */ if (dirp == NULL) /* out of memory */ break; @@ -504,13 +506,15 @@ void ml_open_file(buf_T *buf) * Try all directories in 'directory' option. */ dirp = p_dir; + bool found_existing_dir = false; for (;; ) { if (*dirp == NUL) break; - /* There is a small chance that between choosing the swap file name - * and creating it, another Vim creates the file. In that case the - * creation will fail and we will use another directory. */ - fname = findswapname(buf, &dirp, NULL); /* allocates fname */ + // There is a small chance that between choosing the swap file name + // and creating it, another Vim creates the file. In that case the + // creation will fail and we will use another directory. + fname = (char_u *)findswapname(buf, (char **)&dirp, NULL, + &found_existing_dir); if (dirp == NULL) break; /* out of memory */ if (fname == NULL) @@ -3222,45 +3226,56 @@ static int do_swapexists(buf_T *buf, char_u *fname) return 0; } -/* - * Find out what name to use for the swap file for buffer 'buf'. - * - * Several names are tried to find one that does not exist - * Returns the name in allocated memory or NULL. - * When out of memory "dirp" is set to NULL. - * - * Note: If BASENAMELEN is not correct, you will get error messages for - * not being able to open the swap or undo file - * Note: May trigger SwapExists autocmd, pointers may change! - */ -static char_u * -findswapname ( - buf_T *buf, - char_u **dirp, /* pointer to list of directories */ - char_u *old_fname /* don't give warning for this file name */ -) +/// Find out what name to use for the swap file for buffer 'buf'. +/// +/// Several names are tried to find one that does not exist. Last directory in +/// option is automatically created. +/// +/// @note If BASENAMELEN is not correct, you will get error messages for +/// not being able to open the swap or undo file. +/// @note May trigger SwapExists autocmd, pointers may change! +/// +/// @param[in] buf Buffer for which swap file names needs to be found. +/// @param[in,out] dirp Pointer to a list of directories. When out of memory, +/// is set to NULL. Is advanced to the next directory in +/// the list otherwise. +/// @param[in] old_fname Allowed existing swap file name. Except for this +/// case, name of the non-existing file is used. +/// @param[in,out] found_existing_dir If points to true, then new directory +/// for swap file is not created. At first +/// findswapname() call this argument must +/// point to false. This parameter may only +/// be set to true by this function, it is +/// never set to false. +/// +/// @return [allocated] Name of the swap file. +static char *findswapname(buf_T *buf, char **dirp, char *old_fname, + bool *found_existing_dir) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4) { - char_u *fname; - int n; - char_u *dir_name; - char_u *buf_fname = buf->b_fname; + char *fname; + size_t n; + char *dir_name; + char *buf_fname = (char *) buf->b_fname; /* * Isolate a directory name from *dirp and put it in dir_name. * First allocate some memory to put the directory name in. */ - dir_name = xmalloc(STRLEN(*dirp) + 1); - (void)copy_option_part(dirp, dir_name, 31000, ","); + const size_t dir_len = strlen(*dirp); + dir_name = xmalloc(dir_len + 1); + (void)copy_option_part((char_u **) dirp, (char_u *) dir_name, dir_len, ","); /* * we try different names until we find one that does not exist yet */ - fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name); + fname = (char *)makeswapname((char_u *)buf_fname, buf->b_ffname, buf, + (char_u *)dir_name); for (;; ) { if (fname == NULL) /* must be out of memory */ break; - if ((n = (int)STRLEN(fname)) == 0) { /* safety check */ + if ((n = strlen(fname)) == 0) { /* safety check */ xfree(fname); fname = NULL; break; @@ -3269,7 +3284,7 @@ findswapname ( // Extra security check: When a swap file is a symbolic link, this // is most likely a symlink attack. FileInfo file_info; - bool file_or_link_found = os_fileinfo_link((char *)fname, &file_info); + bool file_or_link_found = os_fileinfo_link(fname, &file_info); if (!file_or_link_found) { break; } @@ -3300,7 +3315,7 @@ findswapname ( * Try to read block 0 from the swap file to get the original * file name (and inode number). */ - fd = os_open((char *)fname, O_RDONLY, 0); + fd = os_open(fname, O_RDONLY, 0); if (fd >= 0) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { /* @@ -3311,7 +3326,7 @@ findswapname ( if (b0.b0_flags & B0_SAME_DIR) { if (fnamecmp(path_tail(buf->b_ffname), path_tail(b0.b0_fname)) != 0 - || !same_directory(fname, buf->b_ffname)) { + || !same_directory((char_u *) fname, buf->b_ffname)) { /* Symlinks may point to the same file even * when the name differs, need to check the * inode too. */ @@ -3351,12 +3366,12 @@ findswapname ( * user anyway. */ if (swap_exists_action != SEA_NONE - && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) - choice = do_swapexists(buf, fname); + && has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf)) + choice = do_swapexists(buf, (char_u *) fname); if (choice == 0) { /* Show info about the existing swap file. */ - attention_message(buf, fname); + attention_message(buf, (char_u *) fname); /* We don't want a 'q' typed at the more-prompt * interrupt loading a file. */ @@ -3364,20 +3379,21 @@ findswapname ( } if (swap_exists_action != SEA_NONE && choice == 0) { - char_u *name; + char *name; - name = xmalloc(STRLEN(fname) - + STRLEN(_("Swap file \"")) - + STRLEN(_("\" already exists!")) + 5); + const size_t fname_len = strlen(fname); + name = xmalloc(fname_len + + strlen(_("Swap file \"")) + + strlen(_("\" already exists!")) + 5); STRCPY(name, _("Swap file \"")); - home_replace(NULL, fname, name + STRLEN(name), - 1000, TRUE); + home_replace(NULL, (char_u *) fname, (char_u *)&name[strlen(name)], + fname_len, true); STRCAT(name, _("\" already exists!")); choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), - name == NULL - ? (char_u *)_("Swap file already exists!") - : name, + (char_u *)(name == NULL + ? _("Swap file already exists!") + : name), # if defined(UNIX) process_still_running ? (char_u *)_( @@ -3409,7 +3425,7 @@ findswapname ( swap_exists_action = SEA_RECOVER; break; case 4: - os_remove((char *)fname); + os_remove(fname); break; case 5: swap_exists_action = SEA_QUIT; @@ -3421,7 +3437,7 @@ findswapname ( } /* If the file was deleted this fname can be used. */ - if (!os_file_exists(fname)) + if (!os_file_exists((char_u *) fname)) break; } else { @@ -3454,6 +3470,19 @@ findswapname ( --fname[n - 1]; /* ".swo", ".swn", etc. */ } + if (os_isdir((char_u *) dir_name)) { + *found_existing_dir = true; + } else if (!*found_existing_dir && **dirp == NUL) { + int ret; + char *failed_dir; + if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir)) != 0) { + EMSG3(_("E303: Unable to create directory \"%s\" for swap file, " + "recovery impossible: %s"), + failed_dir, os_strerror(ret)); + xfree(failed_dir); + } + } + xfree(dir_name); return fname; } |