[Python-ideas] Adding optional parameter to shutil.rmtree to not delete root.
eryk sun
eryksun at gmail.com
Thu Aug 25 00:48:49 EDT 2016
On Thu, Aug 25, 2016 at 2:29 AM, Nick Jacobson via Python-ideas
<python-ideas at python.org> wrote:
> I've been finding that a common scenario is where I want to remove
> everything in a directory, but leave the (empty) root directory behind, not
> removing it.
>
> So for example, if I have a directory C:\foo and it contains subdirectory
> C:\foo\bar and file C:\foo\myfile.txt, and I want to remove the subdirectory
> (and everything in it) and file, leaving only C:\foo behind.
>
> (This is useful e.g. when the root directory has special permissions, so it
> wouldn't be so simple to remove it and recreate it again.)
Here's a Windows workaround that clears the delete disposition after
rmtree 'deletes' the directory. A Windows file or directory absolutely
cannot be unlinked while there are handle or kernel references to it,
and a handle with DELETE access can set and unset the delete
disposition. This used to require the system call
NtSetInformationFile, but Vista added SetFileInformationByHandle to
the Windows API.
import contextlib
import ctypes
import _winapi
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
kernel32.SetFileInformationByHandle # Vista minimum (NT 6.0+)
DELETE = 0x00010000
SHARE_ALL = 7
OPEN_EXISTING = 3
BACKUP = 0x02000000
FileDispositionInfo = 4
@contextlib.contextmanager
def protect_file(path):
hFile = _winapi.CreateFile(path, DELETE, SHARE_ALL, 0,
OPEN_EXISTING, BACKUP, 0)
try:
yield
if not kernel32.SetFileInformationByHandle(
hFile, FileDispositionInfo,
(ctypes.c_ulong * 1)(0), 4):
raise ctypes.WinError(ctypes.get_last_error())
finally:
kernel32.CloseHandle(hFile)
For example:
>>> os.listdir('test')
['dir1', 'dir2', 'file']
>>> with protect_file('test'):
... shutil.rmtree('test')
...
>>> os.listdir('test')
[]
Another example:
>>> open('file', 'w').close()
>>> with protect_file('file'):
... os.remove('file')
...
>>> os.path.exists('file')
True
More information about the Python-ideas
mailing list