5

I am trying to create symlinks using Python on Windows 8. I found This Post and this is part of my script.

import os

link_dst = unicode(os.path.join(style_path, album_path))
link_src = unicode(album_path)
kdll = ctypes.windll.LoadLibrary("kernel32.dll")
kdll.CreateSymbolicLinkW(link_dst, link_src, 1)

Firstly, It can create symlinks only when it is executed through administrator cmd. Why is that happening?

Secondly, When I am trying to open those symlinks from windows explorer I get This Error:

...Directory is not accessible. The Name Of The File Cannot Be Resolved By The System.

Is there a better way of creating symlinks using Python? If not, How can I solve this?

EDIT

This is the for loop in album_linker:

def album_Linker(album_path, album_Genre, album_Style):
genre_basedir = "E:\Music\#02.Genre"
artist_basedir = "E:\Music\#03.Artist"
release_data_basedir = "E:\Music\#04.ReleaseDate"
for genre in os.listdir(genre_basedir):
    genre_path = os.path.join(genre_basedir, "_" + album_Genre)
    if not os.path.isdir(genre_path):
        os.mkdir(genre_path)
    album_Style_list = album_Style.split(', ')
    print album_Style_list
    for style in album_Style_list:
        style_path = os.path.join(genre_path, "_" + style)
        if not os.path.isdir(style_path):
            os.mkdir(style_path)
        album_path_list = album_path.split("_")
        print album_path_list
        #link_dst = unicode(os.path.join(style_path, album_path_list[2] + "_" + album_path_list[1] + "_" + album_path_list[0]))
        link_dst = unicode(os.path.join(style_path, album_path))
        link_src = unicode(album_path)
        kdll = ctypes.windll.LoadLibrary("kernel32.dll")
        kdll.CreateSymbolicLinkW(link_dst, link_src, 1)

It takes album_Genre and album_Style And then It creates directories under E:\Music\#02.Genre . It also takes album_path from the main body of the script. This album_path is the path of directory which i want to create the symlink under E:\Music\#02.Genre\Genre\Style . So album_path is a variable taken from another for loop in the main body of the script

for label in os.listdir(basedir):
label_path = os.path.join(basedir, label)
for album in os.listdir(label_path):
    album_path = os.path.join(label_path, album)
    if not os.path.isdir(album_path):
        # Not A Directory
        continue
    else:
        # Is A Directory
        os.mkdir(os.path.join(album_path + ".copy"))
        # Let Us Count
        j = 1
        z = 0
        # Change Directory
        os.chdir(album_path)
Community
  • 1
  • 1
gabriel
  • 257
  • 2
  • 4
  • 12
  • This [answer](http://stackoverflow.com/a/15043806/189134) may help – Andy Nov 06 '14 at 19:43
  • what are your paths? link_dst, link_src – User Nov 06 '14 at 19:47
  • @Andy I had tried that and I get Undefined Variable From Import: CreateSymbolicLinkW – gabriel Nov 06 '14 at 19:48
  • @User This Code exists in a `for` loop. So the paths are changing. As an example link_dst = "E:\Music\#02.Genre\_Electronic\_Bass Music\1-800Dinosaur-1-800-001_[JamesBlake-Voyeur(Dub)AndHolyGhost]_2013-05-00" and link_dst = "E:\Music\#01.Label\_1-800Dinosaur\1-800Dinosaur-1-800-001_[JamesBlake-Voyeur(Dub)AndHolyGhost]_2013-05-00" – gabriel Nov 06 '14 at 19:51
  • Those paths aren't escaped properly... try `link_dst = r"E:\Music...` – tdelaney Nov 06 '14 at 20:02
  • @tdelaney well each path, is taken from a `for` loop. As a result, "E:\Music..." is a variable in the script. I know that If I have the path then I should Use this "r" letter before the path ( Even if I do not know exactly what it does :( ). But what if i do not have the path but it is stored in a variable? Can I use r(link_dst) ?? – gabriel Nov 06 '14 at 20:09
  • @gabriel, the "r" tells python not to treat "\" specially. Without "r", `"\n"` is the newline character. With the "r", `r"\n"` is two characters, the backslash and the newline. The 'r" only works on assignment, like when you first write the "E:\Music..." variable. – tdelaney Nov 06 '14 at 20:12
  • @tdelaney Ok, now I understand why i should use "r" :P. I edited the post to explain that i cannot know the path as a string but only as a variable. As far I understand from what you wrote in the previous comment, I cannot type r(album_path), album_path--> path stored from a `for` loop. Right? Is there any other way to do this? For example u'E:\Music...' is the same as unicode(album_path) right? – gabriel Nov 06 '14 at 20:27
  • okay, since you got the strings from os.listdir, you don't need to worry about raw strings or backslash escaping. – tdelaney Nov 06 '14 at 20:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64434/discussion-between-gabriel-and-tdelaney). – gabriel Nov 06 '14 at 20:38
  • 1
    If you can use Python 3 it's simply [`os.symlink`](https://docs.python.org/3/library/os.html#os.symlink). – Eryk Sun Dec 07 '14 at 08:21

3 Answers3

9

Firstly, It can create symlinks only when it is executed through administrator cmd.

Users need "Create symbolic links" rights to create a symlink. By default, normal users don't have it but administrator does. One way to change that is with the security policy editor. Open a command prompt as administrator, run secpol.msc and then go to Security Settings\Local Policies\User Rights Assignment\Create symbolic links to make the change.

Secondly, When I am trying to open those symlinks from windows explorer I get This Error:

You aren't escaping the backslashes in the file name. Just by adding an "r" to the front for a raw string, the file name changes. You are setting a non-existant file name and so explorer can't find it.

>>> link_dst1 = "E:\Music\#02.Genre_Electronic_Bass Music\1-800Dinosaur-1-800-001_[JamesBlake-Voyeur(Dub)AndHolyGhost]_2013-05-00"
>>> link_dst2 = r"E:\Music\#02.Genre_Electronic_Bass Music\1-800Dinosaur-1-800-001_[JamesBlake-Voyeur(Dub)AndHolyGhost]_2013-05-00"
>>> link_dst1 == link_dst2
False
>>> print link_dst1
E:\Music\#02.Genre_Electronic_Bass Music☺-800Dinosaur-1-800-001_[JamesBlake-Voyeur(Dub)AndHolyGhost]_2013-05-00
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • Ok, I changed the policy so that myself as normal user can create symlinks, But it does not seem to work. – gabriel Nov 06 '14 at 20:15
  • What does it look like on the command line? Do a dir in the directory with the link, does it look something like `11/06/2014 01:28 PM link_dir [target_dir]` and can you cd into it? – tdelaney Nov 06 '14 at 20:30
  • No, `File Not Found` instead. This is because "r" does not exist before the paths in my script right? – gabriel Nov 06 '14 at 20:36
  • Not necesarily. It depends on where the string came from. If its a string in your program (common when trying to debug things) you need either the "r" or write backslashes as \\. If you got it from os.listdir, you're okay. How about posting the result of the dir command like I did above. It may give a clue. – tdelaney Nov 06 '14 at 20:38
5

os.symlink works out of the box since python 3.8 on windows, as long as Developer Mode is turned on.

BlackShift
  • 2,296
  • 2
  • 19
  • 27
1

If you're just trying to create a link to a directory, you could also create a "Junction", no admin privileges required:

import os
import _winapi

src_dir = "C:/Users/joe/Desktop/my_existing_folder"
dst_dir = "C:/Users/joe/Desktop/generated_link"

src_dir = os.path.normpath(os.path.realpath(src_dir))
dst_dir = os.path.normpath(os.path.realpath(dst_dir))

if not os.path.exists(dst_dir):
   os.makedirs(os.path.dirname(dst_dir), exist_ok=True)
   _winapi.CreateJunction(src_dir, dst_dir)
driedler
  • 3,750
  • 33
  • 26