diff options
-rw-r--r-- | src/eval.c | 13 | ||||
-rw-r--r-- | src/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/fileio.c | 175 | ||||
-rw-r--r-- | src/fileio.h | 1 | ||||
-rw-r--r-- | src/memline.c | 2 | ||||
-rw-r--r-- | src/os/fs.c | 45 | ||||
-rw-r--r-- | src/os/os.h | 5 | ||||
-rw-r--r-- | test/unit/os/fs.moon | 44 |
8 files changed, 89 insertions, 198 deletions
diff --git a/src/eval.c b/src/eval.c index 94eca72b4e..75245fc148 100644 --- a/src/eval.c +++ b/src/eval.c @@ -12329,13 +12329,14 @@ static void f_remove(typval_T *argvars, typval_T *rettv) */ static void f_rename(typval_T *argvars, typval_T *rettv) { - char_u buf[NUMBUFLEN]; - - if (check_restricted() || check_secure()) + if (check_restricted() || check_secure()) { rettv->vval.v_number = -1; - else - rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]), - get_tv_string_buf(&argvars[1], buf)); + } else { + char_u buf[NUMBUFLEN]; + char_u *from = get_tv_string(&argvars[0]); + char_u *to = get_tv_string_buf(&argvars[1], buf); + rettv->vval.v_number = os_rename(from, to) == OK ? 0 : -1; + } } /* diff --git a/src/ex_cmds.c b/src/ex_cmds.c index d8839d213c..0c5ac107bf 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -1711,7 +1711,7 @@ void write_viminfo(char_u *file, int forceit) * In case of an error keep the original viminfo file. * Otherwise rename the newly written file. */ - if (viminfo_errcnt || vim_rename(tempname, fname) == -1) + if (viminfo_errcnt || os_rename(tempname, fname) == FAIL) mch_remove(tempname); } diff --git a/src/fileio.c b/src/fileio.c index 06a094e7b7..c32291b42a 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3314,7 +3314,7 @@ nobackup: * If the renaming of the original file to the backup file * works, quit here. */ - if (vim_rename(fname, backup) == 0) + if (os_rename(fname, backup) == OK) break; vim_free(backup); /* don't do the rename below */ @@ -3520,18 +3520,18 @@ restore_backup: /* * There is a small chance that we removed the original, * try to move the copy in its place. - * This may not work if the vim_rename() fails. + * This may not work if the os_rename() fails. * In that case we leave the copy around. */ /* If file does not exist, put the copy in its place */ if (mch_stat((char *)fname, &st) < 0) - vim_rename(backup, fname); + os_rename(backup, fname); /* if original file does exist throw away the copy */ if (mch_stat((char *)fname, &st) >= 0) mch_remove(backup); } else { /* try to put the original file back */ - vim_rename(backup, fname); + os_rename(backup, fname); } } @@ -3827,7 +3827,7 @@ restore_backup: close(fd); /* ignore errors for closing read file */ } } else { - if (vim_rename(backup, fname) == 0) + if (os_rename(backup, fname) == OK) end = 1; } } @@ -3934,7 +3934,7 @@ restore_backup: if (org == NULL) EMSG(_("E205: Patchmode: can't save original file")); else if (mch_stat(org, &st) < 0) { - vim_rename(backup, (char_u *)org); + os_rename(backup, (char_u *)org); vim_free(backup); /* don't delete the file */ backup = NULL; #ifdef UNIX @@ -4969,169 +4969,6 @@ int tag_fgets(char_u *buf, int size, FILE *fp) } #endif -/* - * rename() only works if both files are on the same file system, this - * function will (attempts to?) copy the file across if rename fails -- webb - * Return -1 for failure, 0 for success. - */ -int vim_rename(char_u *from, char_u *to) -{ - int fd_in; - int fd_out; - int n; - char *errmsg = NULL; - char *buffer; - struct stat st; - long perm; -#ifdef HAVE_ACL - vim_acl_T acl; /* ACL from original file */ -#endif - int use_tmp_file = FALSE; - - /* - * When the names are identical, there is nothing to do. When they refer - * to the same file (ignoring case and slash/backslash differences) but - * the file name differs we need to go through a temp file. - */ - if (fnamecmp(from, to) == 0) { - if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0) - use_tmp_file = TRUE; - else - return 0; - } - - /* - * Fail if the "from" file doesn't exist. Avoids that "to" is deleted. - */ - if (mch_stat((char *)from, &st) < 0) - return -1; - -#ifdef UNIX - { - struct stat st_to; - - /* It's possible for the source and destination to be the same file. - * This happens when "from" and "to" differ in case and are on a FAT32 - * filesystem. In that case go through a temp file name. */ - if (mch_stat((char *)to, &st_to) >= 0 - && st.st_dev == st_to.st_dev - && st.st_ino == st_to.st_ino) - use_tmp_file = TRUE; - } -#endif - - if (use_tmp_file) { - char tempname[MAXPATHL + 1]; - - /* - * Find a name that doesn't exist and is in the same directory. - * Rename "from" to "tempname" and then rename "tempname" to "to". - */ - if (STRLEN(from) >= MAXPATHL - 5) - return -1; - STRCPY(tempname, from); - for (n = 123; n < 99999; ++n) { - sprintf((char *)path_tail((char_u *)tempname), "%d", n); - if (mch_stat(tempname, &st) < 0) { - if (rename((char *)from, tempname) == 0) { - if (rename(tempname, (char *)to) == 0) - return 0; - /* Strange, the second step failed. Try moving the - * file back and return failure. */ - rename(tempname, (char *)from); - return -1; - } - /* If it fails for one temp name it will most likely fail - * for any temp name, give up. */ - return -1; - } - } - return -1; - } - - /* - * Delete the "to" file, this is required on some systems to make the - * rename() work, on other systems it makes sure that we don't have - * two files when the rename() fails. - */ - - mch_remove(to); - - /* - * First try a normal rename, return if it works. - */ - if (rename((char *)from, (char *)to) == 0) - return 0; - - /* - * Rename() failed, try copying the file. - */ - perm = os_getperm(from); -#ifdef HAVE_ACL - /* For systems that support ACL: get the ACL from the original file. */ - acl = mch_get_acl(from); -#endif - fd_in = mch_open((char *)from, O_RDONLY|O_EXTRA, 0); - if (fd_in == -1) { -#ifdef HAVE_ACL - mch_free_acl(acl); -#endif - return -1; - } - - /* Create the new file with same permissions as the original. */ - fd_out = mch_open((char *)to, - O_CREAT|O_EXCL|O_WRONLY|O_EXTRA|O_NOFOLLOW, (int)perm); - if (fd_out == -1) { - close(fd_in); -#ifdef HAVE_ACL - mch_free_acl(acl); -#endif - return -1; - } - - buffer = (char *)alloc(BUFSIZE); - if (buffer == NULL) { - close(fd_out); - close(fd_in); -#ifdef HAVE_ACL - mch_free_acl(acl); -#endif - return -1; - } - - while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0) - if (write_eintr(fd_out, buffer, n) != n) { - errmsg = _("E208: Error writing to \"%s\""); - break; - } - - vim_free(buffer); - close(fd_in); - if (close(fd_out) < 0) - errmsg = _("E209: Error closing \"%s\""); - if (n < 0) { - errmsg = _("E210: Error reading \"%s\""); - to = from; - } -#ifndef UNIX /* for Unix mch_open() already set the permission */ - os_setperm(to, perm); -#endif -#ifdef HAVE_ACL - mch_set_acl(to, acl); - mch_free_acl(acl); -#endif -#ifdef HAVE_SELINUX - mch_copy_sec(from, to); -#endif - if (errmsg != NULL) { - EMSG2(errmsg, to); - return -1; - } - mch_remove(from); - return 0; -} - static int already_warned = FALSE; /* diff --git a/src/fileio.h b/src/fileio.h index ce04b53e1e..ed9119dc7b 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -39,7 +39,6 @@ char_u *buf_modname(int shortname, char_u *fname, char_u *ext, int prepend_dot); int vim_fgets(char_u *buf, int size, FILE *fp); int tag_fgets(char_u *buf, int size, FILE *fp); -int vim_rename(char_u *from, char_u *to); int check_timestamps(int focus); int buf_check_timestamp(buf_T *buf, int focus); void buf_reload(buf_T *buf, int orig_mode); diff --git a/src/memline.c b/src/memline.c index fb5da647d8..b1bd7e056f 100644 --- a/src/memline.c +++ b/src/memline.c @@ -598,7 +598,7 @@ void ml_setname(buf_T *buf) } /* try to rename the swap file */ - if (vim_rename(mfp->mf_fname, fname) == 0) { + if (os_rename(mfp->mf_fname, fname) == OK) { success = TRUE; vim_free(mfp->mf_fname); mfp->mf_fname = fname; diff --git a/src/os/fs.c b/src/os/fs.c index 489109bc24..c97a38f1c7 100644 --- a/src/os/fs.c +++ b/src/os/fs.c @@ -5,6 +5,9 @@ #include "misc1.h" #include "misc2.h" +// Many fs functions from libuv return that value on success. +static const int kLibuvSuccess = 0; + int os_chdir(const char *path) { if (p_verbose >= 5) { verbose_enter(); @@ -19,7 +22,7 @@ int os_dirname(char_u *buf, size_t len) assert(buf && len); int errno; - if ((errno = uv_cwd((char *)buf, &len)) != 0) { + if ((errno = uv_cwd((char *)buf, &len)) != kLibuvSuccess) { vim_strncpy(buf, (char_u *)uv_strerror(errno), len - 1); return FAIL; } @@ -46,11 +49,11 @@ int os_full_dir_name(char *directory, char *buffer, int len) } // We have to get back to the current dir at the end, check if that works. - if (os_chdir(old_dir) != 0) { + if (os_chdir(old_dir) != kLibuvSuccess) { return FAIL; } - if (os_chdir(directory) != 0) { + if (os_chdir(directory) != kLibuvSuccess) { // Do not return immediatly since we may be in the wrong directory. retval = FAIL; } @@ -60,7 +63,7 @@ int os_full_dir_name(char *directory, char *buffer, int len) retval = FAIL; } - if (os_chdir(old_dir) != 0) { + if (os_chdir(old_dir) != kLibuvSuccess) { // That shouldn't happen, since we've tested if it works. retval = FAIL; EMSG(_(e_prev_dir)); @@ -241,11 +244,11 @@ int os_stat(const char_u *name, uv_stat_t *statbuf) *statbuf = request.statbuf; uv_fs_req_cleanup(&request); - if (result == 0) { + if (result == kLibuvSuccess) { return OK; - } else { - return FAIL; } + + return FAIL; } int32_t os_getperm(const char_u *name) @@ -265,11 +268,11 @@ int os_setperm(const char_u *name, int perm) (const char*)name, perm, NULL); uv_fs_req_cleanup(&request); - if (result != 0) { - return FAIL; - } else { + if (result == kLibuvSuccess) { return OK; } + + return FAIL; } int os_file_exists(const char_u *name) @@ -277,18 +280,18 @@ int os_file_exists(const char_u *name) uv_stat_t statbuf; if (os_stat(name, &statbuf) == OK) { return TRUE; - } else { - return FALSE; } + + return FALSE; } int os_file_is_readonly(const char *name) { if (access(name, W_OK) == 0) { return FALSE; - } else { - return TRUE; } + + return TRUE; } int os_file_is_writable(const char *name) @@ -302,3 +305,17 @@ int os_file_is_writable(const char *name) return 0; } +int os_rename(const char_u *path, const char_u *new_path) +{ + uv_fs_t request; + int result = uv_fs_rename(uv_default_loop(), &request, + (const char *)path, (const char *)new_path, NULL); + uv_fs_req_cleanup(&request); + + if (result == kLibuvSuccess) { + return OK; + } + + return FAIL; +} + diff --git a/src/os/os.h b/src/os/os.h index a319b02343..bc3da1c8ff 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -73,6 +73,11 @@ int os_file_is_readonly(const char *name); /// @return `2` for a directory which we have rights to write into. int os_file_is_writable(const char *name); +/// Rename a file or directory. +/// +/// @return `OK` for success, `FAIL` for failure. +int os_rename(const char_u *path, const char_u *new_path); + long_u os_total_mem(int special); const char *os_getenv(const char *name); int os_setenv(const char *name, const char *value, int overwrite); diff --git a/test/unit/os/fs.moon b/test/unit/os/fs.moon index 5c04bef2e5..734c8a2c5d 100644 --- a/test/unit/os/fs.moon +++ b/test/unit/os/fs.moon @@ -21,6 +21,7 @@ int os_setperm(char_u *name, long perm); int os_file_exists(const char_u *name); int os_file_is_readonly(char *fname); int os_file_is_writable(const char *name); +int os_rename(const char_u *path, const char_u *new_path); ]] -- import constants parsed by ffi @@ -361,12 +362,43 @@ describe 'fs function', -> it 'returns 2 when given a folder with rights to write into', -> eq 2, os_file_is_writable 'unit-test-directory' - describe 'os_file_exists', -> + describe 'file operations', -> os_file_exists = (filename) -> fs.os_file_exists (to_cstr filename) - it 'returns FALSE when given a non-existing file', -> - eq FALSE, (os_file_exists 'non-existing-file') - - it 'returns TRUE when given an existing file', -> - eq TRUE, (os_file_exists 'unit-test-directory/test.file') + os_rename = (path, new_path) -> + fs.os_rename (to_cstr path), (to_cstr new_path) + + describe 'os_file_exists', -> + it 'returns FALSE when given a non-existing file', -> + eq FALSE, (os_file_exists 'non-existing-file') + + it 'returns TRUE when given an existing file', -> + eq TRUE, (os_file_exists 'unit-test-directory/test.file') + + describe 'os_rename', -> + test = 'unit-test-directory/test.file' + not_exist = 'unit-test-directory/not_exist.file' + + it 'can rename file if destination file does not exist', -> + eq OK, (os_rename test, not_exist) + eq FALSE, (os_file_exists test) + eq TRUE, (os_file_exists not_exist) + eq OK, (os_rename not_exist, test) -- restore test file + + it 'fail if source file does not exist', -> + eq FAIL, (os_rename not_exist, test) + + it 'can overwrite destination file if it exists', -> + other = 'unit-test-directory/other.file' + file = io.open other, 'w' + file\write 'other' + file\flush! + file\close! + + eq OK, (os_rename other, test) + eq FALSE, (os_file_exists other) + eq TRUE, (os_file_exists test) + file = io.open test, 'r' + eq 'other', (file\read '*all') + file\close! |