Project

General

Profile

Feature #4052 ยป lutime.patch

runpaint (Run Paint Run Run), 11/14/2010 10:23 AM

View differences:

configure.in
1291 1291
fi
1292 1292
AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eaccess\
1293 1293
	      truncate ftruncate chsize times utimes utimensat fcntl lockf lstat\
1294
	      link symlink readlink readdir_r fsync fdatasync fchown\
1294
	      link lutimes symlink readlink readdir_r fsync fdatasync fchown\
1295 1295
	      setitimer setruid seteuid setreuid setresuid setproctitle socketpair\
1296 1296
	      setrgid setegid setregid setresgid issetugid pause lchown lchmod\
1297 1297
	      getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\
file.c
2195 2195
struct utime_args {
2196 2196
    const struct timespec* tsp;
2197 2197
    VALUE atime, mtime;
2198
    int follow; /* Whether to act on symlinks (1) or their referent (0) */
2198 2199
};
2199 2200

  
2200 2201
#if defined DOSISH || defined __CYGWIN__
......
2246 2247

  
2247 2248
#ifdef HAVE_UTIMENSAT
2248 2249
    static int try_utimensat = 1;
2250
    static int try_utimensat_follow = 1;
2251
    int flags = 0;
2249 2252

  
2250
    if (try_utimensat) {
2251
        if (utimensat(AT_FDCWD, path, tsp, 0) < 0) {
2253
    if ((v->follow && try_utimensat_follow) || (!v->follow && try_utimensat)) {
2254
	if (v->follow) {
2255
#ifdef AT_SYMLINK_NOFOLLOW
2256
	    flags = AT_SYMLINK_NOFOLLOW;
2257
#else
2258
	    try_utimensat_follow = 0;
2259
	    goto no_utimensat;
2260
#endif
2261
	}
2262

  
2263
        if (utimensat(AT_FDCWD, path, tsp, flags) < 0) {
2252 2264
            if (errno == ENOSYS) {
2253
                try_utimensat = 0;
2265
		try_utimensat_follow = 0;
2266
                if (!v->follow)
2267
		    try_utimensat = 0;
2254 2268
                goto no_utimensat;
2255 2269
            }
2256 2270
            utime_failed(path, tsp, v->atime, v->mtime);
......
2267 2281
        tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
2268 2282
        tvp = tvbuf;
2269 2283
    }
2270
    if (utimes(path, tvp) < 0)
2284

  
2285
    if (v->follow) {
2286
#ifdef HAVE_LUTIMES
2287
	if (lutimes(path, tvp) < 0)
2288
	    utime_failed(path, tsp, v->atime, v->mtime);
2289
#else
2290
	rb_notimplement();
2291
#endif
2292
    }
2293
    else if (utimes(path, tvp) < 0)
2271 2294
	utime_failed(path, tsp, v->atime, v->mtime);
2272 2295
}
2273 2296

  
......
2297 2320

  
2298 2321
#endif
2299 2322

  
2300
/*
2301
 * call-seq:
2302
 *  File.utime(atime, mtime, file_name,...)   ->  integer
2303
 *
2304
 * Sets the access and modification times of each
2305
 * named file to the first two arguments. Returns
2306
 * the number of file names in the argument list.
2307
 */
2308

  
2309 2323
static VALUE
2310
rb_file_s_utime(int argc, VALUE *argv)
2324
utime_internal_i(int argc, VALUE *argv, int follow)
2311 2325
{
2312 2326
    VALUE rest;
2313 2327
    struct utime_args args;
......
2317 2331
    rb_secure(2);
2318 2332
    rb_scan_args(argc, argv, "2*", &args.atime, &args.mtime, &rest);
2319 2333

  
2334
    args.follow = follow;
2335

  
2320 2336
    if (!NIL_P(args.atime) || !NIL_P(args.mtime)) {
2321 2337
	tsp = tss;
2322 2338
	tsp[0] = rb_time_timespec(args.atime);
......
2328 2344
    return LONG2FIX(n);
2329 2345
}
2330 2346

  
2347
/*
2348
 * call-seq:
2349
 *  File.utime(atime, mtime, file_name,...)   ->  integer
2350
 *
2351
 * Sets the access and modification times of each named file to the
2352
 * first two arguments. If a file is a symlink, this method acts upon
2353
 * its referent rather than the link itself; for the inverse
2354
 * behavior see <code>File.lutime</code>. Returns the number of file
2355
 * names in the argument list.
2356
 */
2357

  
2358
static VALUE
2359
rb_file_s_utime(int argc, VALUE *argv)
2360
{
2361
    return utime_internal_i(argc, argv, 0);
2362
}
2363

  
2364
#if defined(HAVE_UTIMES) && (defined(HAVE_LUTIMES) || (defined(HAVE_UTIMENSAT) && defined(AT_SYMLINK_NOFOLLOW)))
2365

  
2366
/*
2367
 * call-seq:
2368
 *  File.lutime(atime, mtime, file_name,...)   ->  integer
2369
 *
2370
 * Sets the access and modification times of each named file to the
2371
 * first two arguments. If a file is a symlink, this method acts upon
2372
 * the link itself as opposed to its referent; for the inverse
2373
 * behavior, see <code>File.utime</code>. Returns the number of file
2374
 * names in the argument list.
2375
 */
2376

  
2377
static VALUE
2378
rb_file_s_lutime(int argc, VALUE *argv)
2379
{
2380
    return utime_internal_i(argc, argv, 1);
2381
}
2382
#else
2383
#define rb_file_s_lutime rb_f_notimplement
2384
#endif
2385

  
2331 2386
NORETURN(static void sys_fail2(VALUE,VALUE));
2332 2387
static void
2333 2388
sys_fail2(VALUE s1, VALUE s2)
......
5319 5374
    rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1);
5320 5375
    rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1);
5321 5376
    rb_define_singleton_method(rb_cFile, "lchown", rb_file_s_lchown, -1);
5377
    rb_define_singleton_method(rb_cFile, "lutime", rb_file_s_lutime, -1);
5322 5378

  
5323 5379
    rb_define_singleton_method(rb_cFile, "link", rb_file_s_link, 2);
5324 5380
    rb_define_singleton_method(rb_cFile, "symlink", rb_file_s_symlink, 2);
test/ruby/test_file_exhaustive.rb
346 346
    File.utime(t + 1, t + 2, @zerofile)
347 347
    assert_equal(t + 1, File.atime(@zerofile))
348 348
    assert_equal(t + 2, File.mtime(@zerofile))
349
    skip("File.symlink not implemented") unless (File.respond_to?(:symlink) and @symlinkfile)
350
    stat_ln = File.lstat(@symlinkfile)
351
    assert_equal(File.utime(t, t, @symlinkfile), 1)
352
    assert_equal(File.stat(@file).atime, t)
353
    assert_equal(File.stat(@file).mtime, t)
354
    assert_equal(File.lstat(@symlinkfile).atime, stat_ln.atime)
355
    assert_equal(File.lstat(@symlinkfile).mtime, stat_ln.mtime)
356
  end
357

  
358
  def test_lutime
359
    skip("File.lutime not implemented") unless File.respond_to?(:lutime)
360
    Dir.mktmpdir('rubytest-lutime') do |tmp|
361
      Dir.chdir(tmp) do
362
        open('f',?w){}
363
        times = [Time.now - 24*100, Time.now - 24*1_000].map(&:round)
364
        assert_equal(File.lutime(times[0], times[0], ?f), 1)
365
        assert_equal(File.stat(?f).atime.round, times[0])
366
        assert_equal(File.stat(?f).mtime.round, times[0])
367

  
368
        # Assume that a platform supporting changing utimens on symlinks
369
        # also supports symlinks
370
        File.symlink(?f, ?l)
371
        assert_equal(File.lutime(times[1], times[1], ?l), 1)
372
        assert_equal(File.stat(?f).atime.round, times[0])
373
        assert_equal(File.stat(?f).mtime.round, times[0])
374
        assert_equal(File.lstat(?l).atime.round, times[1])
375
        assert_equal(File.lstat(?l).mtime.round, times[1])
376

  
377
        assert_equal(File.lutime(times[1], times[0], ?l, ?f), 2)
378
        assert_equal(File.stat(?f).atime.round, times[1])
379
        assert_equal(File.stat(?f).mtime.round, times[0])
380
        assert_equal(File.lstat(?l).atime.round, times[1])
381
        assert_equal(File.lstat(?l).mtime.round, times[0])
382
      end
383
    end
349 384
  end
350 385

  
351 386
  def test_hardlink