Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(58043)

Side by Side Diff: Lib/shutil.py

Issue 15238: shutil.copystat should copy Linux extended attributes
Patch Set: Created 6 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Doc/library/shutil.rst ('k') | Lib/test/test_shutil.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """Utility functions for copying and archiving files and directory trees. 1 """Utility functions for copying and archiving files and directory trees.
2 2
3 XXX The functions here don't copy the resource fork or other metadata on Mac. 3 XXX The functions here don't copy the resource fork or other metadata on Mac.
4 4
5 """ 5 """
6 6
7 import os 7 import os
8 import sys 8 import sys
9 import stat 9 import stat
10 from os.path import abspath 10 from os.path import abspath
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 stat_func, chmod_func = os.lstat, os.lchmod 124 stat_func, chmod_func = os.lstat, os.lchmod
125 else: 125 else:
126 return 126 return
127 elif hasattr(os, 'chmod'): 127 elif hasattr(os, 'chmod'):
128 stat_func, chmod_func = os.stat, os.chmod 128 stat_func, chmod_func = os.stat, os.chmod
129 else: 129 else:
130 return 130 return
131 131
132 st = stat_func(src) 132 st = stat_func(src)
133 chmod_func(dst, stat.S_IMODE(st.st_mode)) 133 chmod_func(dst, stat.S_IMODE(st.st_mode))
134
135 if hasattr(os, 'listxattr'):
136 def _copyxattr(src, dst, symlinks=False):
137 """Copy extended filesystem attributes from `src` to `dst`.
138
139 Overwrite existing attributes.
140
141 If the optional flag `symlinks` is set, symlinks won't be followed.
142
143 """
144
145 for name in os.listxattr(src, follow_symlinks=symlinks):
146 try:
147 value = os.getxattr(src, name, follow_symlinks=symlinks)
148 os.setxattr(dst, name, value, follow_symlinks=symlinks)
149 except OSError as e:
150 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
151 raise
152 else:
153 def _copyxattr(*args, **kwargs):
154 pass
134 155
135 def copystat(src, dst, symlinks=False): 156 def copystat(src, dst, symlinks=False):
136 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst. 157 """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
137 158
138 If the optional flag `symlinks` is set, symlinks aren't followed if and 159 If the optional flag `symlinks` is set, symlinks aren't followed if and
139 only if both `src` and `dst` are symlinks. 160 only if both `src` and `dst` are symlinks.
140 161
141 """ 162 """
142 def _nop(*args, ns=None, follow_symlinks=None): 163 def _nop(*args, ns=None, follow_symlinks=None):
143 pass 164 pass
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 pass 198 pass
178 if hasattr(st, 'st_flags'): 199 if hasattr(st, 'st_flags'):
179 try: 200 try:
180 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow) 201 lookup("chflags")(dst, st.st_flags, follow_symlinks=follow)
181 except OSError as why: 202 except OSError as why:
182 for err in 'EOPNOTSUPP', 'ENOTSUP': 203 for err in 'EOPNOTSUPP', 'ENOTSUP':
183 if hasattr(errno, err) and why.errno == getattr(errno, err): 204 if hasattr(errno, err) and why.errno == getattr(errno, err):
184 break 205 break
185 else: 206 else:
186 raise 207 raise
187 208 _copyxattr(src, dst, symlinks=follow)
188 if hasattr(os, 'listxattr'):
189 def _copyxattr(src, dst, symlinks=False):
190 """Copy extended filesystem attributes from `src` to `dst`.
191
192 Overwrite existing attributes.
193
194 If the optional flag `symlinks` is set, symlinks won't be followed.
195
196 """
197
198 for name in os.listxattr(src, follow_symlinks=symlinks):
199 try:
200 value = os.getxattr(src, name, follow_symlinks=symlinks)
201 os.setxattr(dst, name, value, follow_symlinks=symlinks)
202 except OSError as e:
203 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
204 raise
205 else:
206 def _copyxattr(*args, **kwargs):
207 pass
208 209
209 def copy(src, dst, symlinks=False): 210 def copy(src, dst, symlinks=False):
210 """Copy data and mode bits ("cp src dst"). Return the file's destination. 211 """Copy data and mode bits ("cp src dst"). Return the file's destination.
211 212
212 The destination may be a directory. 213 The destination may be a directory.
213 214
214 If the optional flag `symlinks` is set, symlinks won't be followed. This 215 If the optional flag `symlinks` is set, symlinks won't be followed. This
215 resembles GNU's "cp -P src dst". 216 resembles GNU's "cp -P src dst".
216 217
217 """ 218 """
(...skipping 10 matching lines...) Expand all
228 The destination may be a directory. 229 The destination may be a directory.
229 230
230 If the optional flag `symlinks` is set, symlinks won't be followed. This 231 If the optional flag `symlinks` is set, symlinks won't be followed. This
231 resembles GNU's "cp -P src dst". 232 resembles GNU's "cp -P src dst".
232 233
233 """ 234 """
234 if os.path.isdir(dst): 235 if os.path.isdir(dst):
235 dst = os.path.join(dst, os.path.basename(src)) 236 dst = os.path.join(dst, os.path.basename(src))
236 copyfile(src, dst, symlinks=symlinks) 237 copyfile(src, dst, symlinks=symlinks)
237 copystat(src, dst, symlinks=symlinks) 238 copystat(src, dst, symlinks=symlinks)
238 _copyxattr(src, dst, symlinks=symlinks)
239 return dst 239 return dst
240 240
241 def ignore_patterns(*patterns): 241 def ignore_patterns(*patterns):
242 """Function that can be used as copytree() ignore parameter. 242 """Function that can be used as copytree() ignore parameter.
243 243
244 Patterns is a sequence of glob-style patterns 244 Patterns is a sequence of glob-style patterns
245 that are used to exclude files""" 245 that are used to exclude files"""
246 def _ignore_patterns(path, names): 246 def _ignore_patterns(path, names):
247 ignored_names = [] 247 ignored_names = []
248 for pattern in patterns: 248 for pattern in patterns:
(...skipping 844 matching lines...) Expand 10 before | Expand all | Expand 10 after
1093 seen = set() 1093 seen = set()
1094 for dir in path: 1094 for dir in path:
1095 dir = os.path.normcase(dir) 1095 dir = os.path.normcase(dir)
1096 if not dir in seen: 1096 if not dir in seen:
1097 seen.add(dir) 1097 seen.add(dir)
1098 for thefile in files: 1098 for thefile in files:
1099 name = os.path.join(dir, thefile) 1099 name = os.path.join(dir, thefile)
1100 if _access_check(name, mode): 1100 if _access_check(name, mode):
1101 return name 1101 return name
1102 return None 1102 return None
OLDNEW
« no previous file with comments | « Doc/library/shutil.rst ('k') | Lib/test/test_shutil.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+