Project

General

Profile

Feature #13696 ยป patch.diff

Glass_saga (Masaki Matsushita), 06/30/2017 03:42 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, replace: 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
 *  If <i>replace<i> is false (default is true), new_name will not be
2862
 *  overwritten and an exception will be raised.
2847 2863
 */
2848 2864

  
2849 2865
static VALUE
2850
rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
2866
rb_file_s_rename(int argc, VALUE *argv, VALUE klass)
2851 2867
{
2868
    static ID keyword_id;
2852 2869
    const char *src, *dst;
2853
    VALUE f, t;
2870
    unsigned int flags = 0;
2871
    VALUE from, to, f, t, opt, vreplace;
2854 2872

  
2873
    if (!keyword_id) {
2874
	CONST_ID(keyword_id, "replace");
2875
    }
2876

  
2877
    rb_scan_args(argc, argv, "2:", &from, &to, &opt);
2855 2878
    FilePathValue(from);
2856 2879
    FilePathValue(to);
2857 2880
    f = rb_str_encode_ospath(from);
......
2861 2884
#if defined __CYGWIN__
2862 2885
    errno = 0;
2863 2886
#endif
2887
    if (!NIL_P(opt)) {
2888
	rb_get_kwargs(opt, &keyword_id, 0, 1, &vreplace);
2889
	if (vreplace != Qundef && !RTEST(vreplace)) { /* replace: false */
2890
	    flags |= RENAME_NOREPLACE;
2891
	}
2892
	if (flags) { /* use renameat2 */
2893
#if defined __linux__ && defined __NR_renameat2
2894
	    if (syscall(__NR_renameat2, AT_FDCWD, src, AT_FDCWD, dst, flags) < 0) {
2895
		int e = errno;
2896
		syserr_fail2(e, from, to);
2897
	    }
2898
	    return INT2FIX(0);
2899
#else
2900
	    rb_raise(rb_eNotImpError, "additional flags are not supported");
2901
#endif
2902
	}
2903
    }
2864 2904
    if (rename(src, dst) < 0) {
2865 2905
	int e = errno;
2866 2906
#if defined DOSISH
......
2880 2920

  
2881 2921
/*
2882 2922
 *  call-seq:
2923
 *     File.exchange(old_name, new_name)   -> 0
2924
 *
2925
 *  Exchange two files atomically. This will cause NotImplementedError if
2926
 *  renameat2(2) is not available.
2927
 */
2928

  
2929
static VALUE
2930
rb_file_s_exchange(VALUE klass, VALUE from, VALUE to)
2931
{
2932
    const char *src, *dst;
2933
    VALUE f, t;
2934

  
2935
    FilePathValue(from);
2936
    FilePathValue(to);
2937
    f = rb_str_encode_ospath(from);
2938
    t = rb_str_encode_ospath(to);
2939
    src = StringValueCStr(f);
2940
    dst = StringValueCStr(t);
2941
#if defined __CYGWIN__
2942
    errno = 0;
2943
#endif
2944
#if defined __linux__ && defined __NR_renameat2
2945
    if (syscall(__NR_renameat2, AT_FDCWD, src, AT_FDCWD, dst, RENAME_EXCHANGE) < 0) {
2946
	int e = errno;
2947
	syserr_fail2(e, from, to);
2948
    }
2949
#else
2950
    rb_raise(rb_eNotImpError, "atomic exchange is not supported");
2951
#endif
2952

  
2953
    return INT2FIX(0);
2954
}
2955

  
2956
/*
2957
 *  call-seq:
2883 2958
 *     File.umask()          -> integer
2884 2959
 *     File.umask(integer)   -> integer
2885 2960
 *
......
6015 6090

  
6016 6091
    rb_define_singleton_method(rb_cFile, "unlink", rb_file_s_unlink, -1);
6017 6092
    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);
6093
    rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, -1);
6094
    rb_define_singleton_method(rb_cFile, "exchange", rb_file_s_exchange, 2);
6019 6095
    rb_define_singleton_method(rb_cFile, "umask", rb_file_s_umask, -1);
6020 6096
    rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2);
6021 6097
    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_replace
720
    assert_equal(0, File.rename(regular_file, nofile, replace: false))
721
    assert_file.not_exist?(regular_file)
722
    assert_file.exist?(nofile)
723
    assert_equal(0, File.rename(nofile, regular_file, replace: false))
724
    assert_raise(Errno::EEXIST) { assert_equal(0, File.rename(regular_file, zerofile, replace: false)) }
725
  rescue NotImplementedError
726
  end if POSIX
727

  
728
  def test_exchange
729
    content = File.read(regular_file)
730
    assert_equal(0, File.exchange(regular_file, zerofile))
731
    assert_file.exist?(regular_file)
732
    assert_equal(true, File.empty?(regular_file))
733
    assert_equal(content, File.read(zerofile))
734
    assert_raise(Errno::ENOENT) { File.exchange(regular_file, nofile) }
735
  rescue NotImplementedError
736
  end if POSIX
737

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