ubelt._win32_links module¶
For dealing with symlinks, junctions, and hard-links on windows.
Note
The termonology used here was written before I really understood the difference between symlinks, hardlinks, and junctions. As such it may be inconsistent or incorrect in some places. This might be fixed in the future.
References
http://timgolden.me.uk/python/win32_how_do_i/see_if_two_files_are_the_same_file.html
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365006(v=vs.85).aspx
- Weird Behavior:
- [ ] In many cases using the win32 API seems to result in privilege errors
but using shell commands does not have this problem.
- ubelt._win32_links._win32_can_symlink(verbose=0, force=0, testing=0)[source]¶
- Parameters:
verbose (int, default=0) – flag
force (int, default=0) – flag
testing (int, default=0) – flag
Example
>>> # xdoctest: +REQUIRES(WIN32) >>> import ubelt as ub >>> _win32_can_symlink(verbose=3, force=1, testing=1)
- ubelt._win32_links._symlink(path, link, overwrite=0, verbose=0)[source]¶
Windows helper for ub.symlink
- ubelt._win32_links._win32_symlink2(path, link, allow_fallback=True, verbose=0)[source]¶
Perform a real symbolic link if possible. However, on most versions of windows you need special privledges to create a real symlink. Therefore, we try to create a symlink, but if that fails we fallback to using a junction.
AFAIK, the main difference between symlinks and junctions are that symlinks can reference relative or absolute paths, where as junctions always reference absolute paths. Not 100% on this though. Windows is weird.
Note that junctions will not register as links via islink, but I believe real symlinks will.
- ubelt._win32_links._win32_symlink(path, link, verbose=0)[source]¶
Creates real symlink. This will only work in versions greater than Windows Vista. Creating real symlinks requires admin permissions or at least specially enabled symlink permissions. On Windows 10 enabling developer mode should give you these permissions.
- ubelt._win32_links._win32_junction(path, link, verbose=0)[source]¶
On older (pre 10) versions of windows we need admin privledges to make symlinks, however junctions seem to work.
For paths we do a junction (softlink) and for files we use a hard link
Example
>>> # xdoc: +REQUIRES(WIN32) >>> import ubelt as ub >>> root = ub.Path.appdir('ubelt', 'win32_junction').ensuredir() >>> ub.delete(root) >>> ub.ensuredir(root) >>> fpath = join(root, 'fpath.txt') >>> dpath = join(root, 'dpath') >>> fjunc = join(root, 'fjunc.txt') >>> djunc = join(root, 'djunc') >>> ub.touch(fpath) >>> ub.ensuredir(dpath) >>> ub.ensuredir(join(root, 'djunc_fake')) >>> ub.ensuredir(join(root, 'djunc_fake with space')) >>> ub.touch(join(root, 'djunc_fake with space file')) >>> _win32_junction(fpath, fjunc) >>> _win32_junction(dpath, djunc) >>> # thank god colons are not allowed >>> djunc2 = join(root, 'djunc2 [with pathological attrs]') >>> _win32_junction(dpath, djunc2) >>> _win32_is_junction(djunc) >>> ub.writeto(join(djunc, 'afile.txt'), 'foo') >>> assert ub.readfrom(join(dpath, 'afile.txt')) == 'foo' >>> ub.writeto(fjunc, 'foo')
- ubelt._win32_links._win32_is_junction(path)[source]¶
Determines if a path is a win32 junction
Note
on PyPy this is bugged and will currently return True for a symlinked directory.
- Return type:
Example
>>> # xdoctest: +REQUIRES(WIN32) >>> from ubelt._win32_links import _win32_junction, _win32_is_junction >>> import ubelt as ub >>> root = ub.Path.appdir('ubelt', 'win32_junction').ensuredir() >>> ub.delete(root) >>> ub.ensuredir(root) >>> dpath = root / 'dpath' >>> djunc = root / 'djunc' >>> dpath.ensuredir() >>> _win32_junction(dpath, djunc) >>> assert _win32_is_junction(djunc) is True >>> assert _win32_is_junction(dpath) is False >>> assert _win32_is_junction('notafile') is False
- ubelt._win32_links._is_reparse_point(path)[source]¶
Check if a directory is a reparse point in windows.
Note: a reparse point seems like it could be a junction or symlink.
[SO54678399]
- ubelt._win32_links._win32_read_junction(path)[source]¶
Returns the location that the junction points, raises ValueError if path is not a junction.
Example
>>> # xdoc: +REQUIRES(WIN32) >>> import ubelt as ub >>> root = ub.Path.appdir('ubelt', 'win32_junction').ensuredir() >>> ub.delete(root) >>> ub.ensuredir(root) >>> dpath = join(root, 'dpath') >>> djunc = join(root, 'djunc') >>> ub.ensuredir(dpath) >>> _win32_junction(dpath, djunc) >>> path = djunc >>> pointed = _win32_read_junction(path) >>> print('pointed = {!r}'.format(pointed))
- ubelt._win32_links._win32_rmtree(path, verbose=0)[source]¶
rmtree for win32 that treats junctions like directory symlinks. The junction removal portion may not be safe on race conditions.
There is a known issue [CPythonBug31226] that prevents
shutil.rmtree()
from deleting directories with junctions.References
- ubelt._win32_links._win32_is_hardlinked(fpath1, fpath2)[source]¶
Test if two hard links point to the same location
Example
>>> # xdoc: +REQUIRES(WIN32) >>> import ubelt as ub >>> root = ub.Path.appdir('ubelt', 'win32_hardlink').ensuredir() >>> ub.delete(root) >>> ub.ensuredir(root) >>> fpath1 = join(root, 'fpath1') >>> fpath2 = join(root, 'fpath2') >>> ub.touch(fpath1) >>> ub.touch(fpath2) >>> fjunc1 = _win32_junction(fpath1, join(root, 'fjunc1')) >>> fjunc2 = _win32_junction(fpath2, join(root, 'fjunc2')) >>> assert _win32_is_hardlinked(fjunc1, fpath1) >>> assert _win32_is_hardlinked(fjunc2, fpath2) >>> assert not _win32_is_hardlinked(fjunc2, fpath1) >>> assert not _win32_is_hardlinked(fjunc1, fpath2)