Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: client/utils/file_path.py

Issue 2949253002: Try 'sudo chmod' in make_tree_deleteable() as last effort (Closed)
Patch Set: . Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2013 The LUCI Authors. All rights reserved. 1 # Copyright 2013 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 """Provides functions: get_native_path_case(), isabs() and safe_join(). 5 """Provides functions: get_native_path_case(), isabs() and safe_join().
6 6
7 This module assumes that filesystem is not changing while current process 7 This module assumes that filesystem is not changing while current process
8 is running and thus it caches results of functions that depend on FS state. 8 is running and thus it caches results of functions that depend on FS state.
9 """ 9 """
10 10
11 import ctypes 11 import ctypes
12 import getpass 12 import getpass
13 import logging 13 import logging
14 import os 14 import os
15 import posixpath 15 import posixpath
16 import re 16 import re
17 import shlex 17 import shlex
18 import stat 18 import stat
19 import sys 19 import sys
20 import tempfile 20 import tempfile
21 import time 21 import time
22 import unicodedata 22 import unicodedata
23 23
24 from utils import fs 24 from utils import fs
25 from utils import subprocess42
25 from utils import tools 26 from utils import tools
26 27
27 28
28 # Types of action accepted by link_file(). 29 # Types of action accepted by link_file().
29 HARDLINK, HARDLINK_WITH_FALLBACK, SYMLINK, SYMLINK_WITH_FALLBACK, COPY = range( 30 HARDLINK, HARDLINK_WITH_FALLBACK, SYMLINK, SYMLINK_WITH_FALLBACK, COPY = range(
30 1, 6) 31 1, 6)
31 32
32 33
33 ## OS-specific imports 34 ## OS-specific imports
34 35
(...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 fs.stat(outfile).st_mode | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) 870 fs.stat(outfile).st_mode | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
870 871
871 872
872 def set_read_only(path, read_only): 873 def set_read_only(path, read_only):
873 """Sets or resets the write bit on a file or directory. 874 """Sets or resets the write bit on a file or directory.
874 875
875 Zaps out access to 'group' and 'others'. 876 Zaps out access to 'group' and 'others'.
876 """ 877 """
877 mode = fs.lstat(path).st_mode 878 mode = fs.lstat(path).st_mode
878 # TODO(maruel): Stop removing GO bits. 879 # TODO(maruel): Stop removing GO bits.
879 mode = (mode & 0500) if read_only else (mode | 0200) 880 if read_only:
881 mode &= stat.S_IRUSR|stat.S_IXUSR # 0500
882 else:
883 mode |= stat.S_IRUSR|stat.S_IWUSR # 0600
884 if sys.platform != 'win32' and stat.S_ISDIR(mode):
885 mode |= stat.S_IXUSR # 0100
880 if hasattr(os, 'lchmod'): 886 if hasattr(os, 'lchmod'):
881 fs.lchmod(path, mode) # pylint: disable=E1101 887 fs.lchmod(path, mode) # pylint: disable=E1101
882 else: 888 else:
883 if stat.S_ISLNK(mode): 889 if stat.S_ISLNK(mode):
884 # Skip symlink without lchmod() support. 890 # Skip symlink without lchmod() support.
885 logging.debug( 891 logging.debug(
886 'Can\'t change %sw bit on symlink %s', 892 'Can\'t change %sw bit on symlink %s',
887 '-' if read_only else '+', path) 893 '-' if read_only else '+', path)
888 return 894 return
889 895
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
1090 1096
1091 On Windows, the files are modified. On other platforms, modify the directory. 1097 On Windows, the files are modified. On other platforms, modify the directory.
1092 It only does the minimum so the files can be deleted safely. 1098 It only does the minimum so the files can be deleted safely.
1093 1099
1094 Warning on Windows: since file permission is modified, the file node is 1100 Warning on Windows: since file permission is modified, the file node is
1095 modified. This means that for hard-linked files, every directory entry for the 1101 modified. This means that for hard-linked files, every directory entry for the
1096 file node has its file permission modified. 1102 file node has its file permission modified.
1097 """ 1103 """
1098 logging.debug('make_tree_deleteable(%s)', root) 1104 logging.debug('make_tree_deleteable(%s)', root)
1099 err = None 1105 err = None
1106 sudo_failed = False
1107
1108 def try_sudo(p):
1109 if sys.platform == 'linux2' and not sudo_failed:
1110 # Try passwordless sudo, just in case. In practice, it is preferable
1111 # to use linux capabilities.
1112 with open(os.devnull, 'rb') as f:
1113 if not subprocess42.call(
1114 ['sudo', '-n', 'chmod', 'a+rwX', p], stdin=f):
1115 return False
1116 logging.debug('sudo chmod %s failed', p)
1117 return True
1118
1100 if sys.platform != 'win32': 1119 if sys.platform != 'win32':
1101 e = set_read_only_swallow(root, False) 1120 e = set_read_only_swallow(root, False)
1121 if e:
1122 sudo_failed = try_sudo(root)
1102 if not err: 1123 if not err:
1103 err = e 1124 err = e
1104 for dirpath, dirnames, filenames in fs.walk(root, topdown=True): 1125 for dirpath, dirnames, filenames in fs.walk(root, topdown=True):
1105 if sys.platform == 'win32': 1126 if sys.platform == 'win32':
1106 for filename in filenames: 1127 for filename in filenames:
1107 e = set_read_only_swallow(os.path.join(dirpath, filename), False) 1128 e = set_read_only_swallow(os.path.join(dirpath, filename), False)
1108 if not err: 1129 if not err:
1109 err = e 1130 err = e
1110 else: 1131 else:
1111 for dirname in dirnames: 1132 for dirname in dirnames:
1112 e = set_read_only_swallow(os.path.join(dirpath, dirname), False) 1133 p = os.path.join(dirpath, dirname)
1134 e = set_read_only_swallow(p, False)
1135 if e:
1136 sudo_failed = try_sudo(p)
1113 if not err: 1137 if not err:
1114 err = e 1138 err = e
1115 if err: 1139 if err:
1116 # pylint: disable=raising-bad-type 1140 # pylint: disable=raising-bad-type
1117 raise err 1141 raise err
1118 1142
1119 1143
1120 def rmtree(root): 1144 def rmtree(root):
1121 """Wrapper around shutil.rmtree() to retry automatically on Windows. 1145 """Wrapper around shutil.rmtree() to retry automatically on Windows.
1122 1146
1123 On Windows, forcibly kills processes that are found to interfere with the 1147 On Windows, forcibly kills processes that are found to interfere with the
1124 deletion. 1148 deletion.
1125 1149
1126 Returns: 1150 Returns:
1127 True on normal execution, False if berserk techniques (like killing 1151 True on normal execution, False if berserk techniques (like killing
1128 processes) had to be used. 1152 processes) had to be used.
1129 """ 1153 """
1130 logging.info('rmtree(%s)', root) 1154 logging.info('rmtree(%s)', root)
1131 assert sys.getdefaultencoding() == 'utf-8', sys.getdefaultencoding() 1155 assert isinstance(root, unicode) or sys.getdefaultencoding() == 'utf-8', (
1132 # Do not assert here yet because this would break too much code. 1156 repr(root), sys.getdefaultencoding())
1133 root = unicode(root) 1157 root = unicode(root)
1134 try: 1158 try:
1135 make_tree_deleteable(root) 1159 make_tree_deleteable(root)
1136 except OSError as e: 1160 except OSError as e:
1137 logging.warning('Swallowing make_tree_deleteable() error: %s', e) 1161 logging.warning('Swallowing make_tree_deleteable() error: %s', e)
1138 1162
1139 # First try the soft way: tries 3 times to delete and sleep a bit in between. 1163 # First try the soft way: tries 3 times to delete and sleep a bit in between.
1140 # Retries help if test subprocesses outlive main process and try to actively 1164 # Retries help if test subprocesses outlive main process and try to actively
1141 # use or write to the directory while it is being deleted. 1165 # use or write to the directory while it is being deleted.
1142 max_tries = 3 1166 max_tries = 3
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1195 sys.stderr.write( 1219 sys.stderr.write(
1196 'Failed to delete %s. The following files remain:\n' % root) 1220 'Failed to delete %s. The following files remain:\n' % root)
1197 # The same path may be listed multiple times. 1221 # The same path may be listed multiple times.
1198 for path in sorted(set(path for _, path, _ in errors)): 1222 for path in sorted(set(path for _, path, _ in errors)):
1199 sys.stderr.write('- %s\n' % path) 1223 sys.stderr.write('- %s\n' % path)
1200 raise errors[0][2][0], errors[0][2][1], errors[0][2][2] 1224 raise errors[0][2][0], errors[0][2][1], errors[0][2][2]
1201 return False 1225 return False
1202 1226
1203 1227
1204 ## Private code. 1228 ## Private code.
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698