diff -x '*.lo' -x '*.mk' -x 'config.*' -ur ../apr.20080417222010/file_io/unix/copy.c ./file_io/unix/copy.c --- ../apr.20080417222010/file_io/unix/copy.c 2008-04-17 21:01:23.000000000 -0400 +++ ./file_io/unix/copy.c 2008-04-18 18:22:22.000000000 -0400 @@ -110,3 +110,13 @@ perms, pool); } + +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path) +{ + if (link(from_path, to_path) == -1) { + return errno; + } + + return APR_SUCCESS; +} diff -x '*.lo' -x '*.mk' -x 'config.*' -ur ../apr.20080417222010/file_io/win32/open.c ./file_io/win32/open.c --- ../apr.20080417222010/file_io/win32/open.c 2008-04-17 21:01:23.000000000 -0400 +++ ./file_io/win32/open.c 2008-04-18 18:21:36.000000000 -0400 @@ -578,6 +578,36 @@ return apr_get_os_error(); } +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path) +{ + apr_status_t rv; + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wfrom_path[APR_PATH_MAX]; + apr_wchar_t wto_path[APR_PATH_MAX]; + + if (rv = utf8_to_unicode_path(wfrom_path, sizeof(wfrom_path) + / sizeof(apr_wchar_t), from_path)) + return rv; + if (rv = utf8_to_unicode_path(wto_path, sizeof(wto_path) + / sizeof(apr_wchar_t), to_path)) + return rv; + + if (!CreateHardLinkW(wto_path, wfrom_path)) + return apr_get_os_error() + } +#endif +#if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI { + if (!CreateHardLinkA(wto_path, wfrom_path)) + return apr_get_os_error() + } +#endif +} + APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, apr_file_t *file) { diff -x '*.lo' -x '*.mk' -x 'config.*' -ur ../apr.20080417222010/include/apr_file_io.h ./include/apr_file_io.h --- ../apr.20080417222010/include/apr_file_io.h 2008-04-17 21:01:23.000000000 -0400 +++ ./include/apr_file_io.h 2008-04-18 18:23:13.000000000 -0400 @@ -265,6 +265,15 @@ apr_pool_t *pool); /** + * Create a hard link to the specified file. + * @param from_path The full path to the original file (using / on all systems) + * @param to_path The full path to the new file (using / on all systems) + * @remark Both files must reside on the same device. + */ +APR_DECLARE(apr_status_t) apr_file_link(const char *from_path, + const char *to_path); + +/** * Copy the specified file to another file. * @param from_path The full path to the original file (using / on all systems) * @param to_path The full path to the new file (using / on all systems) diff -x '*.lo' -x '*.mk' -x 'config.*' -ur ../apr.20080417222010/test/testfilecopy.c ./test/testfilecopy.c --- ../apr.20080417222010/test/testfilecopy.c 2008-04-17 21:01:23.000000000 -0400 +++ ./test/testfilecopy.c 2008-04-18 19:53:33.000000000 -0400 @@ -123,6 +123,23 @@ APR_ASSERT_SUCCESS(tc, "Couldn't remove copy file", rv); } +static void link_existing(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_link("data/file_datafile.txt", "data/file_datafile2.txt"); + apr_file_remove("data/file_datafile2.txt", p); + ABTS_ASSERT(tc, "Couldn't create hardlink to file", rv == APR_SUCCESS); +} + +static void link_nonexisting(abts_case *tc, void *data) +{ + apr_status_t rv; + + rv = apr_file_link("data/does_not_exist.txt", "data/fake.txt"); + ABTS_ASSERT(tc, "", rv != APR_SUCCESS); +} + abts_suite *testfilecopy(abts_suite *suite) { suite = ADD_SUITE(suite) @@ -133,6 +150,9 @@ abts_run_test(suite, append_nonexist, NULL); abts_run_test(suite, append_exist, NULL); + abts_run_test(suite, link_existing, NULL); + abts_run_test(suite, link_nonexisting, NULL); + return suite; }