diff -x '*.lo' -x '*.mk' -x 'config.*' -x 'Makefile*' -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.*' -x 'Makefile*' -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.*' -x 'Makefile*' -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.*' -x 'Makefile*' -ur ../apr.20080417222010/test/abts_tests.h ./test/abts_tests.h --- ../apr.20080417222010/test/abts_tests.h 2008-04-17 21:01:23.000000000 -0400 +++ ./test/abts_tests.h 2008-04-18 18:48:26.000000000 -0400 @@ -30,6 +30,7 @@ {testenv}, {testfile}, {testfilecopy}, + {testfilelink}, {testfileinfo}, {testflock}, {testfmt}, diff -x '*.lo' -x '*.mk' -x 'config.*' -x 'Makefile*' -ur ../apr.20080417222010/test/testfilelink.c ./test/testfilelink.c --- ../apr.20080417222010/test/testfilelink.c 2008-04-18 18:57:18.000000000 -0400 +++ ./test/testfilelink.c 2008-04-18 18:52:00.000000000 -0400 @@ -0,0 +1,49 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "testutil.h" +#include "apr_file_io.h" +#include "apr_file_info.h" +#include "apr_errno.h" +#include "apr_pools.h" + +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 *testfilelink(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, link_existing, NULL); + abts_run_test(suite, link_nonexisting, NULL); + + return suite; +} + diff -x '*.lo' -x '*.mk' -x 'config.*' -x 'Makefile*' -ur ../apr.20080417222010/test/testutil.h ./test/testutil.h --- ../apr.20080417222010/test/testutil.h 2008-04-17 21:01:23.000000000 -0400 +++ ./test/testutil.h 2008-04-18 18:50:19.000000000 -0400 @@ -68,6 +68,7 @@ abts_suite *testfile(abts_suite *suite); abts_suite *testfilecopy(abts_suite *suite); abts_suite *testfileinfo(abts_suite *suite); +abts_suite *testfilelink(abts_suite *suite); abts_suite *testflock(abts_suite *suite); abts_suite *testfmt(abts_suite *suite); abts_suite *testfnmatch(abts_suite *suite);