2 # Copyright (C) 2010 Rob Browning
4 # This code is covered under the terms of the GNU Library General
5 # Public License as described in the bup LICENSE file.
6 import sys, stat, errno
7 from bup import metadata, options, xstat
8 from bup.helpers import handle_ctrl_c, saved_errors, add_error, log
11 def fstimestr(fstime):
12 (s, ns) = fstime.secs_nsecs()
16 return '%d.%09d' % (s, ns)
20 bup pathinfo [OPTION ...] <PATH ...>
22 v,verbose increase log output (can be used more than once)
23 q,quiet don't show progress meter
24 exclude-fields= exclude comma-separated fields
25 include-fields= include comma-separated fields (definitive if first)
29 all_fields = frozenset(['path',
43 active_fields = all_fields
47 o = options.Options(optspec)
48 (opt, flags, remainder) = o.parse(sys.argv[1:])
50 treat_include_fields_as_definitive = True
51 for flag, value in flags:
52 if flag == '--verbose' or flag == '-v':
54 elif flag == '--quiet' or flag == '-q':
56 elif flag == '--exclude-fields':
57 exclude_fields = frozenset(value.split(','))
58 for f in exclude_fields:
59 if not f in all_fields:
60 o.fatal(f + ' is not a valid field name')
61 active_fields = active_fields - exclude_fields
62 treat_include_fields_as_definitive = False
63 elif flag == '--include-fields':
64 include_fields = frozenset(value.split(','))
65 for f in include_fields:
66 if not f in all_fields:
67 o.fatal(f + ' is not a valid field name')
68 if treat_include_fields_as_definitive:
69 active_fields = include_fields
70 treat_include_fields_as_definitive = False
72 active_fields = active_fields | include_fields
74 for path in remainder:
76 m = metadata.from_path(path, archive_path = path)
77 except (OSError,IOError), e:
78 if e.errno == errno.ENOENT:
83 if 'path' in active_fields:
85 if 'mode' in active_fields:
86 print 'mode:', oct(m.mode)
87 if 'link-target' in active_fields and stat.S_ISLNK(m.mode):
88 print 'link-target:', m.symlink_target
89 if 'rdev' in active_fields:
91 if 'uid' in active_fields:
93 if 'gid' in active_fields:
95 if 'owner' in active_fields:
96 print 'owner:', m.owner
97 if 'group' in active_fields:
98 print 'group:', m.group
99 if 'atime' in active_fields:
100 # If we don't have utimensat, that means we have to use
101 # utime(), and utime() has no way to set the mtime/atime of a
102 # symlink. Thus, the mtime/atime of a symlink is meaningless,
103 # so let's not report it. (That way scripts comparing
104 # before/after won't trigger.)
105 if xstat._have_utimensat or not stat.S_ISLNK(m.mode):
106 print 'atime: ' + fstimestr(m.atime)
109 if 'mtime' in active_fields:
110 if xstat._have_utimensat or not stat.S_ISLNK(m.mode):
111 print 'mtime: ' + fstimestr(m.mtime)
114 if 'ctime' in active_fields:
115 print 'ctime: ' + fstimestr(m.ctime)
116 if 'linux-attr' in active_fields and m.linux_attr:
117 print 'linux-attr:', hex(m.linux_attr)
118 if 'linux-xattr' in active_fields and m.linux_xattr:
119 for name, value in m.linux_xattr:
120 print 'linux-xattr: %s -> %s' % (name, repr(value))
121 if 'posix1e-acl' in active_fields and m.posix1e_acl and metadata.posix1e:
122 flags = metadata.posix1e.TEXT_ABBREVIATE
123 if stat.S_ISDIR(m.mode):
124 acl = m.posix1e_acl[0]
125 default_acl = m.posix1e_acl[2]
126 print acl.to_any_text('posix1e-acl: ', '\n', flags)
127 print acl.to_any_text('posix1e-acl-default: ', '\n', flags)
129 acl = m.posix1e_acl[0]
130 print acl.to_any_text('posix1e-acl: ', '\n', flags)
133 log('WARNING: %d errors encountered.\n' % len(saved_errors))