Project

General

Profile

Feature #13696 ยป patch.diff

Glass_saga (Masaki Matsushita), 06/29/2017 02:06 AM

View differences:

file.c
93 93
#include <sys/time.h>
94 94
#endif
95 95

  
96
#ifdef HAVE_SYSCALL_H
97
# include <syscall.h>
98
#elif defined HAVE_SYS_SYSCALL_H
99
# include <sys/syscall.h>
100
#endif
101
#ifndef RENAME_NOREPLACE
102
# define RENAME_NOREPLACE 1
103
#endif
104
#ifndef RENAME_EXCHANGE
105
# define RENAME_EXCHANGE 2
106
#endif
107

  
96 108
#if !defined HAVE_LSTAT && !defined lstat
97 109
#define lstat stat
98 110
#endif
......
2839 2851
/*
2840 2852
 *  call-seq:
2841 2853
 *     File.rename(old_name, new_name)   -> 0
2854
 *     File.rename(old_name, new_name, exhcnage: bool, noreplace: bool)   -> 0
2842 2855
 *
2843 2856
 *  Renames the given file to the new name. Raises a
2844 2857
 *  <code>SystemCallError</code> if the file cannot be renamed.
2845 2858
 *
2846 2859
 *     File.rename("afile", "afile.bak")   #=> 0
2860
 *
2861
 *  When <i>exchange</i> is true, old_name and new_name will be atomically
2862
 *  changed. If <i>noreplace<i> is true, new_name will not be overwritten and
2863
 *  an exception will be raised.
2847 2864
 */
2848 2865

  
2849 2866
static VALUE
2850
rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
2867
rb_file_s_rename(int argc, VALUE *argv, VALUE klass)
2851 2868
{
2869
    static ID keyword_ids[2];
2852 2870
    const char *src, *dst;
2853
    VALUE f, t;
2871
    unsigned int flags = 0;
2872
    VALUE from, to, f, t, opt, vnoreplace, vexchange;
2873
    VALUE kwargs[2];
2874

  
2875
    if (!keyword_ids[0]) {
2876
	CONST_ID(keyword_ids[0], "noreplace");
2877
	CONST_ID(keyword_ids[1], "exchange");
2878
    }
2854 2879

  
2880
    rb_scan_args(argc, argv, "2:", &from, &to, &opt);
2855 2881
    FilePathValue(from);
2856 2882
    FilePathValue(to);
2857 2883
    f = rb_str_encode_ospath(from);
......
2861 2887
#if defined __CYGWIN__
2862 2888
    errno = 0;
2863 2889
#endif
2890
    if (!NIL_P(opt)) {
2891
	rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
2892
	vnoreplace = kwargs[0];
2893
	vexchange = kwargs[1];
2894
	if (vnoreplace != Qundef && !NIL_P(vnoreplace)) {
2895
	    flags |= RENAME_NOREPLACE;
2896
	}
2897
	if (vexchange != Qundef && !NIL_P(vexchange)) {
2898
	    flags |= RENAME_EXCHANGE;
2899
	}
2900
	if (flags) { /* use renameat2 */
2901
#if defined __linux__ && defined __NR_renameat2
2902
	    if (syscall(__NR_renameat2, AT_FDCWD, src, AT_FDCWD, dst, flags) < 0) {
2903
		int e = errno;
2904
		syserr_fail2(e, from, to);
2905
	    }
2906
	    return INT2FIX(0);
2907
#else
2908
	    rb_raise(rb_eNotImpError, "additional flags are not supported");
2909
#endif
2910
	}
2911
    }
2864 2912
    if (rename(src, dst) < 0) {
2865 2913
	int e = errno;
2866 2914
#if defined DOSISH
......
6015 6063

  
6016 6064
    rb_define_singleton_method(rb_cFile, "unlink", rb_file_s_unlink, -1);
6017 6065
    rb_define_singleton_method(rb_cFile, "delete", rb_file_s_unlink, -1);
6018
    rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, 2);
6066
    rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, -1);
6019 6067
    rb_define_singleton_method(rb_cFile, "umask", rb_file_s_umask, -1);
6020 6068
    rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
6021 6069
    rb_define_singleton_method(rb_cFile, "mkfifo", rb_file_s_mkfifo, -1);
test/ruby/test_file_exhaustive.rb
716 716
    end
717 717
  end
718 718

  
719
  def test_rename_exchange
720
    content = File.read(regular_file)
721
    assert_equal(0, File.rename(regular_file, zerofile, exchange: true))
722
    assert_file.exist?(regular_file)
723
    assert_equal(true, File.empty?(regular_file))
724
    assert_equal(content, File.read(zerofile))
725
    assert_raise(Errno::ENOENT) { File.rename(regular_file, nofile, exchange: true) }
726
    assert_raise(Errno::EINVAL) { File.rename(regular_file, nofile, exchange: true, noreplace: true) }
727
  rescue NotImplementedError
728
  end if POSIX
729

  
730
  def test_rename_noreplace
731
    assert_equal(0, File.rename(regular_file, nofile, noreplace: true))
732
    assert_file.not_exist?(regular_file)
733
    assert_file.exist?(nofile)
734
    assert_equal(0, File.rename(nofile, regular_file, noreplace: true))
735
    assert_raise(Errno::EEXIST) { assert_equal(0, File.rename(regular_file, zerofile, noreplace: true)) }
736
  rescue NotImplementedError
737
  end if POSIX
738

  
719 739
  def test_umask
720 740
    prev = File.umask(0777)
721 741
    assert_equal(0777, File.umask)