From 1b9df3962088142300728724c485425a93eb5f2a Mon Sep 17 00:00:00 2001 From: Brian Curtin Date: Wed, 24 Nov 2010 20:24:31 +0000 Subject: [PATCH] Fix #8879. Add os.link support to Windows. Additionally, the st_ino attribute of stat structures was not being filled in. This was left out of the fix to #10027 and was noticed due to test_tarfile failing when applying the patch for this issue. An earlier version of the fix to #10027 included st_ino, but that attribute got lost in the shuffle of a few review/fix cycles. All tests pass. --- Doc/library/os.rst | 5 ++++- Lib/test/test_os.py | 28 ++++++++++++++++++++++++++++ Misc/NEWS | 2 ++ Modules/posixmodule.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index cb9d9c43649..b2c439c2eb6 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1058,7 +1058,10 @@ Files and Directories Create a hard link pointing to *source* named *link_name*. - Availability: Unix. + Availability: Unix, Windows. + + .. versionchanged:: 3.2 + Added Windows support. .. function:: listdir(path='.') diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 129367e9942..978364c4789 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -860,6 +860,33 @@ class TestInvalidFD(unittest.TestCase): if hasattr(os, "write"): self.check(os.write, b" ") + +class LinkTests(unittest.TestCase): + def setUp(self): + self.file1 = support.TESTFN + self.file2 = os.path.join(support.TESTFN + "2") + + for file in (self.file1, self.file2): + if os.path.exists(file): + os.unlink(file) + + tearDown = setUp + + def _test_link(self, file1, file2): + with open(file1, "w") as f1: + f1.write("test") + + os.link(file1, file2) + with open(file1, "r") as f1, open(file2, "r") as f2: + self.assertTrue(os.path.sameopenfile(f1.fileno(), f2.fileno())) + + def test_link(self): + self._test_link(self.file1, self.file2) + + def test_link_bytes(self): + self._test_link(bytes(self.file1, sys.getfilesystemencoding()), + bytes(self.file2, sys.getfilesystemencoding())) + if sys.platform != 'win32': class Win32ErrorTests(unittest.TestCase): pass @@ -1221,6 +1248,7 @@ def test_main(): FSEncodingTests, PidTests, LoginTests, + LinkTests, ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS index fb61ac818d9..6891d1ebec8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ What's New in Python 3.2 Beta 1? Core and Builtins ----------------- +- Issue #8879. Add os.link support for Windows. + - Issue #10027. st_nlink was not being set on Windows calls to os.stat or os.lstat. Patch by Hirokazu Yamamoto. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index cba8a9dcafc..8b7d7e9d12e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1035,6 +1035,7 @@ attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, struct win32_stat *resu FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); result->st_nlink = info->nNumberOfLinks; + result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; return 0; } @@ -2239,6 +2240,36 @@ posix_link(PyObject *self, PyObject *args) } #endif /* HAVE_LINK */ +#ifdef MS_WINDOWS +PyDoc_STRVAR(win32_link__doc__, +"link(src, dst)\n\n\ +Create a hard link to a file."); + +static PyObject * +win32_link(PyObject *self, PyObject *args) +{ + PyObject *osrc, *odst; + char *src, *dst; + BOOL rslt; + + if (!PyArg_ParseTuple(args, "O&O&:link", PyUnicode_FSConverter, &osrc, + PyUnicode_FSConverter, &odst)) + return NULL; + + src = PyBytes_AsString(osrc); + dst = PyBytes_AsString(odst); + + Py_BEGIN_ALLOW_THREADS + rslt = CreateHardLink(dst, src, NULL); + Py_END_ALLOW_THREADS + + if (rslt == 0) + return posix_error(); + + Py_RETURN_NONE; +} +#endif /* MS_WINDOWS */ + PyDoc_STRVAR(posix_listdir__doc__, "listdir([path]) -> list_of_strings\n\n\ @@ -7808,6 +7839,7 @@ static PyMethodDef posix_methods[] = { #ifdef MS_WINDOWS {"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__}, {"kill", win32_kill, METH_VARARGS, win32_kill__doc__}, + {"link", win32_link, METH_VARARGS, win32_link__doc__}, #endif #ifdef HAVE_SETUID {"setuid", posix_setuid, METH_VARARGS, posix_setuid__doc__},