summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2013-05-28 03:21:28 (GMT)
committerJason R. Coombs <jaraco@jaraco.com>2013-05-28 03:21:28 (GMT)
commit3a09286790c58522195eadc3eaa4a21e8da89ea1 (patch)
tree493319a3666f3ed24f52759ab425e31da6b832f8 /Modules/posixmodule.c
parentdb4e5c53c9a68cbb19a8daca0c454360d1045c6f (diff)
downloadcpython-3a09286790c58522195eadc3eaa4a21e8da89ea1.zip
cpython-3a09286790c58522195eadc3eaa4a21e8da89ea1.tar.gz
cpython-3a09286790c58522195eadc3eaa4a21e8da89ea1.tar.bz2
Issue #13772: Restored directory detection of targets in `os.symlink` on Windows, which was temporarily removed in Python 3.2.3 due to an incomplete implementation. The implementation now works even if the symlink is created in a location other than the current directory.
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c129
1 files changed, 127 insertions, 2 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 0cb1836..7c96a67 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7200,6 +7200,124 @@ check_CreateSymbolicLink()
return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA);
}
+void _dirnameW(WCHAR *path) {
+ /* Remove the last portion of the path */
+
+ WCHAR *ptr;
+
+ /* walk the path from the end until a backslash is encountered */
+ for(ptr = path + wcslen(path); ptr != path; ptr--)
+ {
+ if(*ptr == *L"\\" || *ptr == *L"/") {
+ break;
+ }
+ }
+ *ptr = 0;
+}
+
+void _dirnameA(char *path) {
+ /* Remove the last portion of the path */
+
+ char *ptr;
+
+ /* walk the path from the end until a backslash is encountered */
+ for(ptr = path + strlen(path); ptr != path; ptr--)
+ {
+ if(*ptr == '\\' || *ptr == '/') {
+ break;
+ }
+ }
+ *ptr = 0;
+}
+
+int _is_absW(WCHAR *path) {
+ /* Is this path absolute? */
+
+ return path[0] == L'\\' || path[0] == L'/' || path[1] == L':';
+
+}
+
+int _is_absA(char *path) {
+ /* Is this path absolute? */
+
+ return path[0] == '\\' || path[0] == '/' || path[1] == ':';
+
+}
+
+void _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest) {
+ /* join root and rest with a backslash */
+ int root_len;
+
+ if(_is_absW(rest)) {
+ wcscpy(dest_path, rest);
+ return;
+ }
+
+ root_len = wcslen(root);
+
+ wcscpy(dest_path, root);
+ if(root_len) {
+ dest_path[root_len] = *L"\\";
+ root_len += 1;
+ }
+ wcscpy(dest_path+root_len, rest);
+}
+
+void _joinA(char *dest_path, const char *root, const char *rest) {
+ /* join root and rest with a backslash */
+ int root_len;
+
+ if(_is_absA(rest)) {
+ strcpy(dest_path, rest);
+ return;
+ }
+
+ root_len = strlen(root);
+
+ strcpy(dest_path, root);
+ if(root_len) {
+ dest_path[root_len] = '\\';
+ root_len += 1;
+ }
+ strcpy(dest_path+root_len, rest);
+}
+
+int _check_dirW(WCHAR *src, WCHAR *dest)
+{
+ /* Return True if the path at src relative to dest is a directory */
+ WIN32_FILE_ATTRIBUTE_DATA src_info;
+ WCHAR dest_parent[MAX_PATH];
+ WCHAR src_resolved[MAX_PATH] = L"";
+
+ /* dest_parent = os.path.dirname(dest) */
+ wcscpy(dest_parent, dest);
+ _dirnameW(dest_parent);
+ /* src_resolved = os.path.join(dest_parent, src) */
+ _joinW(src_resolved, dest_parent, src);
+ return (
+ GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info)
+ && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
+ );
+}
+
+int _check_dirA(char *src, char *dest)
+{
+ /* Return True if the path at src relative to dest is a directory */
+ WIN32_FILE_ATTRIBUTE_DATA src_info;
+ char dest_parent[MAX_PATH];
+ char src_resolved[MAX_PATH] = "";
+
+ /* dest_parent = os.path.dirname(dest) */
+ strcpy(dest_parent, dest);
+ _dirnameW(dest_parent);
+ /* src_resolved = os.path.join(dest_parent, src) */
+ _joinW(src_resolved, dest_parent, src);
+ return (
+ GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info)
+ && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
+ );
+}
+
#endif
static PyObject *
@@ -7256,13 +7374,20 @@ posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
}
#ifdef MS_WINDOWS
+
Py_BEGIN_ALLOW_THREADS
- if (dst.wide)
+ if (dst.wide) {
+ /* if src is a directory, ensure target_is_directory==1 */
+ target_is_directory |= _check_dirW(src.wide, dst.wide);
result = Py_CreateSymbolicLinkW(dst.wide, src.wide,
target_is_directory);
- else
+ }
+ else {
+ /* if src is a directory, ensure target_is_directory==1 */
+ target_is_directory |= _check_dirA(src.narrow, dst.narrow);
result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow,
target_is_directory);
+ }
Py_END_ALLOW_THREADS
if (!result) {