/*
 * call-seq:
 *   File.identical?(file_1, file_2)   =>  true or false
 *
 * Returns <code>true</code> if the named files are identical.
 *
 *     open("a", "w") {}
 *     p File.identical?("a", "a")      #=> true
 *     p File.identical?("a", "./a")    #=> true
 *     File.link("a", "b")
 *     p File.identical?("a", "b")      #=> true
 *     File.symlink("a", "c")
 *     p File.identical?("a", "c")      #=> true
 *     open("d", "w") {}
 *     p File.identical?("a", "d")      #=> false
 */

static VALUE
test_identical(obj, fname1, fname2)
    VALUE obj, fname1, fname2;
{
#ifndef DOSISH
    struct stat st1, st2;

    if (rb_stat(fname1, &st1) < 0) return Qfalse;
    if (rb_stat(fname2, &st2) < 0) return Qfalse;
    if (st1.st_dev != st2.st_dev) return Qfalse;
    if (st1.st_ino != st2.st_ino) return Qfalse;
#else
#ifdef _WIN32
    BY_HANDLE_FILE_INFORMATION st1, st2;
    HANDLE f1 = 0, f2 = 0;
#endif

    rb_secure(2);
#ifdef _WIN32
    f1 = w32_io_info(&fname1, &st1);
    if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
    f2 = w32_io_info(&fname2, &st2);
    if (f1) CloseHandle(f1);
    if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
    if (f2) CloseHandle(f2);

    if (st1.dwVolumeSerialNumber == st2.dwVolumeSerialNumber &&
        st1.nFileIndexHigh == st2.nFileIndexHigh &&
        st1.nFileIndexLow == st2.nFileIndexLow)
        return Qtrue;
    if (!f1 || !f2) return Qfalse;
    if (rb_w32_iswin95()) return Qfalse;
#else
    SafeStringValue(fname1);
    fname1 = rb_str_new4(fname1);
    SafeStringValue(fname2);
    if (access(RSTRING(fname1)->ptr, 0)) return Qfalse;
    if (access(RSTRING(fname2)->ptr, 0)) return Qfalse;
#endif
    fname1 = rb_file_expand_path(fname1, Qnil);
    fname2 = rb_file_expand_path(fname2, Qnil);
    if (RSTRING(fname1)->len != RSTRING(fname2)->len) return Qfalse;
    if (rb_memcicmp(RSTRING(fname1)->ptr, RSTRING(fname2)->ptr, RSTRING(fname1)->len))
        return Qfalse;
#endif
    return Qtrue;
}