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
9 from bup import _helpers
12 def fstimestr(fstime):
13 (s, ns) = fstime.secs_nsecs()
17 return '%d.%09d' % (s, ns)
21 bup pathinfo [OPTION ...] <PATH ...>
23 v,verbose increase log output (can be used more than once)
24 q,quiet don't show progress meter
25 exclude-fields= exclude comma-separated fields
26 include-fields= include comma-separated fields (definitive if first)
30 all_fields = frozenset(['path',
44 active_fields = all_fields
48 o = options.Options(optspec)
49 (opt, flags, remainder) = o.parse(sys.argv[1:])
51 treat_include_fields_as_definitive = True
52 for flag, value in flags:
53 if flag == '--verbose' or flag == '-v':
55 elif flag == '--quiet' or flag == '-q':
57 elif flag == '--exclude-fields':
58 exclude_fields = frozenset(value.split(','))
59 for f in exclude_fields:
60 if not f in all_fields:
61 o.fatal(f + ' is not a valid field name')
62 active_fields = active_fields - exclude_fields
63 treat_include_fields_as_definitive = False
64 elif flag == '--include-fields':
65 include_fields = frozenset(value.split(','))
66 for f in include_fields:
67 if not f in all_fields:
68 o.fatal(f + ' is not a valid field name')
69 if treat_include_fields_as_definitive:
70 active_fields = include_fields
71 treat_include_fields_as_definitive = False
73 active_fields = active_fields | include_fields
75 for path in remainder:
77 m = metadata.from_path(path, archive_path = path)
78 except (OSError,IOError), e:
79 if e.errno == errno.ENOENT:
84 if 'path' in active_fields:
86 if 'mode' in active_fields:
87 print 'mode:', oct(m.mode)
88 if 'link-target' in active_fields and stat.S_ISLNK(m.mode):
89 print 'link-target:', m.symlink_target
90 if 'rdev' in active_fields:
92 if 'uid' in active_fields:
94 if 'gid' in active_fields:
96 if 'owner' in active_fields:
97 print 'owner:', m.owner
98 if 'group' in active_fields:
99 print 'group:', m.group
100 if 'atime' in active_fields:
101 # if we don't have_ns_fs_timestamps, that means we have to use
102 # utime(), and utime() has no way to set the mtime/atime of a
103 # symlink. Thus, the mtime/atime of a symlink is meaningless, so
104 # let's not report it. (That way scripts comparing before/after
106 if _helpers._have_ns_fs_timestamps or not stat.S_ISLNK(m.mode):
107 print 'atime: ' + fstimestr(m.atime)
110 if 'mtime' in active_fields:
111 if _helpers._have_ns_fs_timestamps or not stat.S_ISLNK(m.mode):
112 print 'mtime: ' + fstimestr(m.mtime)
115 if 'ctime' in active_fields:
116 print 'ctime: ' + fstimestr(m.ctime)
117 if 'linux-attr' in active_fields and m.linux_attr:
118 print 'linux-attr:', hex(m.linux_attr)
119 if 'linux-xattr' in active_fields and m.linux_xattr:
120 for name, value in m.linux_xattr:
121 print 'linux-xattr: %s -> %s' % (name, repr(value))
122 if 'posix1e-acl' in active_fields and m.posix1e_acl and metadata.posix1e:
123 flags = metadata.posix1e.TEXT_ABBREVIATE
124 if stat.S_ISDIR(m.mode):
125 acl = m.posix1e_acl[0]
126 default_acl = m.posix1e_acl[2]
127 print acl.to_any_text('posix1e-acl: ', '\n', flags)
128 print acl.to_any_text('posix1e-acl-default: ', '\n', flags)
130 acl = m.posix1e_acl[0]
131 print acl.to_any_text('posix1e-acl: ', '\n', flags)
134 log('WARNING: %d errors encountered.\n' % len(saved_errors))