Ticket #2885: rmdirRecursive.py

File rmdirRecursive.py, 3.2 KB (added by sa2ajj, 5 years ago)

commands/util.py that worked here under native Windows 7 and Cygwin

Line 
1def rmdirRecursiveSub(dir, do_ignore_remove_fails):
2    """This is a replacement for shutil.rmtree that works better under
3    windows. Thanks to Bear at the OSAF for the code."""
4    if not os.path.exists(dir):
5        return
6
7    try:
8
9        if os.path.islink(dir) or os.path.isfile(dir):
10            os.remove(dir)
11            return
12
13        # Verify the directory is read/write/execute for the current user
14        os.chmod(dir, 0700)
15
16        # os.listdir below only returns a list of unicode filenames if the parameter is unicode
17        # Thus, if a non-unicode-named dir contains a unicode filename, that filename will get garbled.
18        # So force dir to be unicode.
19        if not isinstance(dir, unicode):
20            try:
21                dir = unicode(dir, "utf-8")
22            except:
23                log.err("rmdirRecursive: decoding from UTF-8 failed (ignoring)")
24
25        try:
26            list = os.listdir(dir)
27        except WindowsError, e:
28            msg = ("rmdirRecursive: unable to listdir %s (%s). Trying to "
29                   "remove like a dir" % (dir, e.strerror.decode('mbcs')))
30            log.msg(msg.encode('utf-8'))
31            os.rmdir(dir)
32            return
33
34        for name in list:
35            full_name = os.path.join(dir, name)
36            # on Windows, if we don't have write permission we can't remove
37            # the file/directory either, so turn that on
38            if os.name == 'nt':
39                if not os.access(full_name, os.W_OK):
40                    # I think this is now redundant, but I don't have an NT
41                    # machine to test on, so I'm going to leave it in place
42                    # -warner
43                    os.chmod(full_name, 0600)
44
45            if os.path.islink(full_name):
46                os.remove(full_name)  # as suggested in bug #792
47            elif os.path.isdir(full_name):
48                rmdirRecursiveSub(full_name, True)
49            else:
50                if os.path.isfile(full_name):
51                    os.chmod(full_name, 0700)
52                os.remove(full_name)
53
54        os.rmdir(dir)
55
56    except OSError as e:
57        if e.errno in (errno.ENOTEMPTY, errno.EBUSY, errno.EACCES):
58            if not do_ignore_remove_fails:
59                msg = None
60                try:
61                    list2 = os.listdir(dir)
62                    msg = 'rmdirRecursive: directory not empty: {0}. Contains: {1}. New: {2}.'
63                    msg = msg.format(repr(dir), repr(list2), repr(sorted(set(list2) - set(list))))
64                except:
65                    pass
66                if msg is None:
67                    raise
68                raise OSError(e.errno, msg)
69        elif e.errno == errno.ENOENT:
70            pass
71        else:
72            raise
73
74
75def rmdirRecursive(dir):
76    tries_left = 5 # number of tries
77    delay_between_tries = 5 # dely in seconds between tries
78
79    while True:
80        try:
81            rmdirRecursiveSub(dir, False)
82            break
83        except OSError as e:
84            tries_left -= 1
85            if not e.errno in (errno.ENOTEMPTY, errno.EBUSY, errno.EACCES):
86                raise
87            if tries_left <= 0:
88                raise
89            # try again after some waiting
90            time.sleep(delay_between_tries)