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

Side by Side Diff: tools/checkperms/checkperms.py

Issue 10831194: Add permission checking to the presumit checks. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 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 | « PRESUBMIT.py ('k') | 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 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Makes sure files have the right permissions. 6 """Makes sure files have the right permissions.
7 7
8 Some developers have broken SCM configurations that flip the svn:executable 8 Some developers have broken SCM configurations that flip the svn:executable
9 permission on for no good reason. Unix developers who run ls --color will then 9 permission on for no good reason. Unix developers who run ls --color will then
10 see .cc files in green and get confused. 10 see .cc files in green and get confused.
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 253
254 254
255 def has_shebang(full_path): 255 def has_shebang(full_path):
256 """Returns if the file starts with #!/. 256 """Returns if the file starts with #!/.
257 257
258 file_path is the absolute path to the file. 258 file_path is the absolute path to the file.
259 """ 259 """
260 with open(full_path, 'rb') as f: 260 with open(full_path, 'rb') as f:
261 return f.read(3) == '#!/' 261 return f.read(3) == '#!/'
262 262
263 def check_file(full_path, bare_output):
264 """Checks file_path's permissions and returns an error if it is
265 inconsistent.
266
267 It is assumed that the file is not ignored by is_ignored().
268
269 If the file name is matched with must_be_executable() or
270 must_not_be_executable(), only its executable bit is checked.
271 Otherwise, the 3 first bytes of the file are read to verify if it has a
272 shebang and compares this with the executable bit on the file.
273 """
274 try:
275 bit = has_executable_bit(full_path)
276 except OSError:
277 # It's faster to catch exception than call os.path.islink(). Chromium
278 # tree happens to have invalid symlinks under
279 # third_party/openssl/openssl/test/.
280 return None
281
282 if must_be_executable(full_path):
Lei Zhang 2013/11/08 00:15:11 And this is wrong because must_be_executable() tak
283 if not bit:
284 if bare_output:
285 return full_path
286 return '%s: Must have executable bit set' % full_path
287 return
288 if must_not_be_executable(full_path):
289 if bit:
290 if bare_output:
291 return full_path
292 return '%s: Must not have executable bit set' % full_path
293 return
294
295 # For the others, it depends on the shebang.
296 shebang = has_shebang(full_path)
297 if bit != shebang:
298 if bare_output:
299 return full_path
300 if bit:
301 return '%s: Has executable bit but not shebang' % full_path
302 else:
303 return '%s: Has shebang but not executable bit' % full_path
304
305
306 def check_files(root, files, bare_output):
307 errors = []
308 for file_path in files:
309 if is_ignored(file_path):
310 continue
311
312 full_file_path = os.path.join(root, file_path)
313
314 error = check_file(full_file_path, bare_output)
315 if error:
316 errors.append(error)
317
318 return errors
263 319
264 class ApiBase(object): 320 class ApiBase(object):
265 def __init__(self, root_dir, bare_output): 321 def __init__(self, root_dir, bare_output):
266 self.root_dir = root_dir 322 self.root_dir = root_dir
267 self.bare_output = bare_output 323 self.bare_output = bare_output
268 self.count = 0 324 self.count = 0
269 self.count_shebang = 0 325 self.count_shebang = 0
270 326
271 def check_file(self, rel_path): 327 def check_file(self, rel_path):
272 """Checks file_path's permissions and returns an error if it is
273 inconsistent.
274
275 It is assumed that the file is not ignored by is_ignored().
276
277 If the file name is matched with must_be_executable() or
278 must_not_be_executable(), only its executable bit is checked.
279 Otherwise, the 3 first bytes of the file are read to verify if it has a
280 shebang and compares this with the executable bit on the file.
281 """
282 logging.debug('check_file(%s)' % rel_path) 328 logging.debug('check_file(%s)' % rel_path)
283 self.count += 1 329 self.count += 1
284 330
331 if (not must_be_executable(rel_path) and
332 not must_not_be_executable(rel_path)):
333 self.count_shebang += 1
334
285 full_path = os.path.join(self.root_dir, rel_path) 335 full_path = os.path.join(self.root_dir, rel_path)
286 try: 336 return check_file(full_path, self.bare_output)
287 bit = has_executable_bit(full_path)
288 except OSError:
289 # It's faster to catch exception than call os.path.islink(). Chromium
290 # tree happens to have invalid symlinks under
291 # third_party/openssl/openssl/test/.
292 return None
293
294 if must_be_executable(rel_path):
295 if not bit:
296 if self.bare_output:
297 return rel_path
298 return '%s: Must have executable bit set' % rel_path
299 return
300 if must_not_be_executable(rel_path):
301 if bit:
302 if self.bare_output:
303 return rel_path
304 return '%s: Must not have executable bit set' % rel_path
305 return
306
307 # For the others, it depends on the shebang.
308 shebang = has_shebang(full_path)
309 self.count_shebang += 1
310 if bit != shebang:
311 if self.bare_output:
312 return rel_path
313 if bit:
314 return '%s: Has executable bit but not shebang' % rel_path
315 else:
316 return '%s: Has shebang but not executable bit' % rel_path
317 337
318 def check_dir(self, rel_path): 338 def check_dir(self, rel_path):
319 return self.check(rel_path) 339 return self.check(rel_path)
320 340
321 def check(self, start_dir): 341 def check(self, start_dir):
322 """Check the files in start_dir, recursively check its subdirectories.""" 342 """Check the files in start_dir, recursively check its subdirectories."""
323 errors = [] 343 errors = []
324 items = self.list_dir(start_dir) 344 items = self.list_dir(start_dir)
325 logging.info('check(%s) -> %d' % (start_dir, len(items))) 345 logging.info('check(%s) -> %d' % (start_dir, len(items)))
326 for item in items: 346 for item in items:
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 '--root', 453 '--root',
434 help='Specifies the repository root. This defaults ' 454 help='Specifies the repository root. This defaults '
435 'to the checkout repository root') 455 'to the checkout repository root')
436 parser.add_option( 456 parser.add_option(
437 '-v', '--verbose', action='count', default=0, help='Print debug logging') 457 '-v', '--verbose', action='count', default=0, help='Print debug logging')
438 parser.add_option( 458 parser.add_option(
439 '--bare', 459 '--bare',
440 action='store_true', 460 action='store_true',
441 default=False, 461 default=False,
442 help='Prints the bare filename triggering the checks') 462 help='Prints the bare filename triggering the checks')
463 parser.add_option(
464 '--file', action='append', dest='files',
465 help='Specifics a list of files to check the permissions of. Only these '
466 'files will be checked')
443 options, args = parser.parse_args() 467 options, args = parser.parse_args()
444 468
445 levels = [logging.ERROR, logging.INFO, logging.DEBUG] 469 levels = [logging.ERROR, logging.INFO, logging.DEBUG]
446 logging.basicConfig(level=levels[min(len(levels) - 1, options.verbose)]) 470 logging.basicConfig(level=levels[min(len(levels) - 1, options.verbose)])
447 471
448 if len(args) > 1: 472 if len(args) > 1:
449 parser.error('Too many arguments used') 473 parser.error('Too many arguments used')
450 474
451 if options.root: 475 if options.root:
452 options.root = os.path.abspath(options.root) 476 options.root = os.path.abspath(options.root)
453 477
478 if options.files:
479 errors = check_files(options.root, options.files, options.bare)
480 print '\n'.join(errors)
481 return bool(errors)
482
454 api = get_scm(options.root, options.bare) 483 api = get_scm(options.root, options.bare)
455 if args: 484 if args:
456 start_dir = args[0] 485 start_dir = args[0]
457 else: 486 else:
458 start_dir = api.root_dir 487 start_dir = api.root_dir
459 488
460 errors = api.check(start_dir) 489 errors = api.check(start_dir)
461 490
462 if not options.bare: 491 if not options.bare:
463 print 'Processed %s files, %d files where tested for shebang' % ( 492 print 'Processed %s files, %d files where tested for shebang' % (
464 api.count, api.count_shebang) 493 api.count, api.count_shebang)
465 494
466 if errors: 495 if errors:
467 if not options.bare: 496 if not options.bare:
468 print '\nFAILED\n' 497 print '\nFAILED\n'
469 print '\n'.join(errors) 498 print '\n'.join(errors)
470 return 1 499 return 1
471 if not options.bare: 500 if not options.bare:
472 print '\nSUCCESS\n' 501 print '\nSUCCESS\n'
473 return 0 502 return 0
474 503
475 504
476 if '__main__' == __name__: 505 if '__main__' == __name__:
477 sys.exit(main()) 506 sys.exit(main())
OLDNEW
« no previous file with comments | « PRESUBMIT.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698