0001-Add-support-for-lutimes-3-to-file.c-as-File-lutime.patch

Krzysztof Wilczynski, 10/19/2012 03:54 AM

Download (6.86 KB)

View differences:

configure.in
1496 1496
  AC_LIBOBJ([signbit])
1497 1497
fi
1498 1498
AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot getcwd eaccess\
1499
	      truncate ftruncate ftello chsize times utimes utimensat fcntl lockf lstat\
1499
	      truncate ftruncate ftello chsize times utimes lutimes utimensat fcntl lockf lstat\
1500 1500
	      truncate64 ftruncate64 ftello64 fseeko fseeko64 \
1501 1501
	      link symlink readlink readdir_r fsync fdatasync fchown posix_fadvise\
1502 1502
	      setitimer setruid seteuid setreuid setresuid socketpair\
file.c
2206 2206
#define rb_file_s_lchown rb_f_notimplement
2207 2207
#endif
2208 2208

  
2209
typedef enum utime_mode utime_mode_t;
2210

  
2211
enum utime_mode {
2212
    M_SYMLINK_FOLLOW = 0,
2213
    M_SYMLINK_NOFOLLOW
2214
};
2215

  
2209 2216
struct utime_args {
2210 2217
    const struct timespec* tsp;
2211 2218
    VALUE atime, mtime;
2219
    utime_mode_t mode;
2212 2220
};
2213 2221

  
2222
#if !defined(FOLLOW_SYMLINK_P)
2223
# define FOLLOW_SYMLINK_P(x) ((x)->mode == M_SYMLINK_FOLLOW)
2224
#endif
2225

  
2214 2226
#if defined DOSISH || defined __CYGWIN__
2215 2227
NORETURN(static void utime_failed(VALUE, const struct timespec *, VALUE, VALUE));
2216 2228

  
......
2252 2264
#if defined(HAVE_UTIMES)
2253 2265

  
2254 2266
static void
2255
utime_internal(const char *path, VALUE pathv, void *arg)
2267
utime_helper(const char *path, VALUE pathv, void *arg)
2256 2268
{
2257 2269
    struct utime_args *v = arg;
2258 2270
    const struct timespec *tsp = v->tsp;
......
2260 2272

  
2261 2273
#ifdef HAVE_UTIMENSAT
2262 2274
    static int try_utimensat = 1;
2275
    const int flags = FOLLOW_SYMLINK_P(v) ? 0 : AT_SYMLINK_NOFOLLOW;
2263 2276

  
2264 2277
    if (try_utimensat) {
2265
        if (utimensat(AT_FDCWD, path, tsp, 0) < 0) {
2278
        if (utimensat(AT_FDCWD, path, tsp, flags) < 0) {
2266 2279
            if (errno == ENOSYS) {
2267 2280
                try_utimensat = 0;
2268 2281
                goto no_utimensat;
......
2281 2294
        tvbuf[1].tv_usec = (int)(tsp[1].tv_nsec / 1000);
2282 2295
        tvp = tvbuf;
2283 2296
    }
2284
    if (utimes(path, tvp) < 0)
2297
    if ((FOLLOW_SYMLINK_P(v) ? utimes(path, tvp) : lutimes(path, tvp)) < 0)
2285 2298
	utime_failed(pathv, tsp, v->atime, v->mtime);
2286 2299
}
2287 2300

  
......
2295 2308
#endif
2296 2309

  
2297 2310
static void
2298
utime_internal(const char *path, VALUE pathv, void *arg)
2311
utime_helper(const char *path, VALUE pathv, void *arg)
2299 2312
{
2300 2313
    struct utime_args *v = arg;
2301 2314
    const struct timespec *tsp = v->tsp;
......
2305 2318
        utbuf.modtime = tsp[1].tv_sec;
2306 2319
        utp = &utbuf;
2307 2320
    }
2308
    if (utime(path, utp) < 0)
2321
    if ((FOLLOW_SYMLINK_P(v) ? utimes(path, utp) : lutimes(path, utp)) < 0)
2309 2322
	utime_failed(pathv, tsp, v->atime, v->mtime);
2310 2323
}
2311 2324

  
2312 2325
#endif
2313 2326

  
2314
/*
2315
 * call-seq:
2316
 *  File.utime(atime, mtime, file_name,...)   ->  integer
2317
 *
2318
 * Sets the access and modification times of each
2319
 * named file to the first two arguments. Returns
2320
 * the number of file names in the argument list.
2321
 */
2322

  
2323 2327
static VALUE
2324
rb_file_s_utime(int argc, VALUE *argv)
2328
utime_internal(int argc, VALUE *argv, utime_mode_t mode)
2325 2329
{
2326 2330
    VALUE rest;
2327 2331
    struct utime_args args;
......
2337 2341
	tsp[1] = rb_time_timespec(args.mtime);
2338 2342
    }
2339 2343
    args.tsp = tsp;
2344
#ifdef HAVE_LUTIMES
2345
    args.mode = mode;
2346
#else
2347
    args.mode = M_SYMLINK_FOLLOW;
2348
#endif
2340 2349

  
2341
    n = apply2files(utime_internal, rest, &args);
2350
    n = apply2files(utime_helper, rest, &args);
2342 2351
    return LONG2FIX(n);
2343 2352
}
2344 2353

  
2354
/*
2355
 * call-seq:
2356
 *  File.utime(atime, mtime, file_name,...)   ->  integer
2357
 *
2358
 * Sets the access and modification times of each
2359
 * named file to the first two arguments. Returns
2360
 * the number of file names in the argument list.
2361
 * See also File::lutime.
2362
 */
2363

  
2364
static inline VALUE
2365
rb_file_s_utime(int argc, VALUE *argv)
2366
{
2367
    return utime_internal(argc, argv, M_SYMLINK_FOLLOW);
2368
}
2369

  
2370
#ifdef HAVE_LUTIMES
2371
/*
2372
 * call-seq:
2373
 *  File.lutime(atime, mtime, file_name,...)   ->  integer
2374
 *
2375
 * Equivalent to File::utime, but does not follow
2376
 * symbolic links (so it will change the +atime+
2377
 * and +mtime+ associated with the link, not the
2378
 * file referenced by the link). Often not available.
2379
 *
2380
 * See also File::utime.
2381
 */
2382

  
2383
static VALUE
2384
rb_file_s_lutime(int argc, VALUE *argv)
2385
{
2386
    return utime_internal(argc, argv, M_SYMLINK_NOFOLLOW);
2387
}
2388
#else
2389
#define rb_file_s_lutime rb_f_notimplement
2390
#endif
2391

  
2392
#if defined(FOLLOW_SYMLINK_P)
2393
# undef FOLLOW_SYMLINK_P
2394
#endif
2395

  
2345 2396
NORETURN(static void sys_fail2(VALUE,VALUE));
2346 2397
static void
2347 2398
sys_fail2(VALUE s1, VALUE s2)
......
5439 5490
    rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1);
5440 5491

  
5441 5492
    rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1);
5493
    rb_define_singleton_method(rb_cFile, "lutime", rb_file_s_lutime, -1);
5442 5494
    rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1);
5443 5495
    rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1);
5444 5496
    rb_define_singleton_method(rb_cFile, "lchmod", rb_file_s_lchmod, -1);
test/ruby/test_file_exhaustive.rb
374 374
    assert_equal(t + 2, File.mtime(@zerofile))
375 375
  end
376 376

  
377
  def test_lutime
378
    return unless @symlinkfile
379
    t = Time.local(2000)
380
    assert_equal(1, File.lutime(t + 1, t + 2, @symlinkfile))
381
    assert_equal(2, File.lutime(t + 1, t + 2, @symlinkfile, @symlinkfile))
382
    assert_equal(t + 1, File.lstat(@symlinkfile).atime)
383
    assert_equal(t + 2, File.lstat(@symlinkfile).mtime)
384
    assert_not_equal(t + 1, File.atime(@symlinkfile))
385
    assert_not_equal(t + 2, File.mtime(@symlinkfile))
386
    assert_raise(Errno::ENOENT) { File.lutime(t + 1, t + 2, @nofile) }
387
  rescue NotImplementedError
388
  end
389

  
377 390
  def test_hardlink
378 391
    return unless @hardlinkfile
379 392
    assert_equal("file", File.ftype(@hardlinkfile))
380
-