Reputation: 2669
So, I need to clean a directory that is not empty. I have created the following function.For testing reasons I tried to remove a JDK installation
def clean_dir(location):
fileList = os.listdir(location)
for fileName in fileList:
fullpath=os.path.join(location, fileName)
if os.path.isfile(fullpath):
os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
os.remove(location + "/" + fileName)
elif os.path.isdir(fullpath):
if len(os.listdir(fullpath)) > 0:
clean_dir(fullpath)
#os.rmdir(location + "/" + fileName)
shutil.rmtree(location + "/" + fileName)
return
I tried to use rmtree and rmdir, but it fails.
The error I got using rmtree is:
OSError: Cannot call rmtree on a symbolic link
And this is the error I got when I used rmdir:
OSError: [Errno 66] Directory not empty: '/tmp/jdk1.8.0_25/jre/lib/amd64/server'
The code works correctly on windows. But for some reason it fails on linux.
Upvotes: 0
Views: 6528
Reputation: 2669
kronenpj thanks, that was the idea. But when you have a symlink it tries to delete is as a normal file and fails. I had to add a new elif and add the unlink option for the symlink
def clean_dir(location):
fileList = os.listdir(location)
for fileName in fileList:
fullpath=os.path.join(location, fileName)
if os.path.isfile(fullpath):
os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
os.remove(os.path.join(location, fileName))
elif os.path.islink(fullpath):
os.unlink(fullpath)
elif os.path.isdir(fullpath):
if len(os.listdir(fullpath)) > 0:
clean_dir(fullpath)
#os.rmdir(location + "/" + fileName)
shutil.rmtree(os.path.join(location, fileName))
return
Upvotes: 2
Reputation: 221
You're encountering one of the differences between the way Windows and Linux (UNIX really) handle filesystems. I believe adding an additional case to your code will at least help:
...
for fileName in fileList:
fullpath = os.path.join(location, fileName)
## |<-- Handle symlink -->|
if os.path.islink(fullpath) or os.path.isfile(fullpath):
os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
os.remove(os.path.join(location, fileName))
elif os.path.isdir(fullpath):
if len(os.listdir(fullpath)) > 0:
clean_dir(fullpath)
#os.rmdir(os.path.join(location, fileName))
shutil.rmtree(os.path.join(location, fileName))
...
This should properly handle the case where the entry is a symlink and remove it just like a file. I'm not sure the chmod
is necessary - it probably works on the target of the link, but it shouldn't hurt to handle it the same way as a file.
However, I just checked and os.path.file
against a symbolic link returns the type of the "thing" that is pointed to, so the additional check is needed to differentiate between the link itself and the thing pointed to. Also to be portable, instead of appending "/" use os.path.join
as newly edited above.
Upvotes: 3