]> arthur.barton.de Git - bup.git/blob - cmd/xstat-cmd.py
Add symbolic mode information to xstat output, i.e. (drwxr-xr-x).
[bup.git] / cmd / xstat-cmd.py
1 #!/usr/bin/env python
2 # Copyright (C) 2010 Rob Browning
3 #
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
10
11 def fstimestr(fstime):
12     (s, ns) = xstat.fstime_to_timespec(fstime)
13     if(s < 0):
14         s += 1
15     if ns == 0:
16         return '%d' % s
17     else:
18         return '%d.%09d' % (s, ns)
19
20
21 optspec = """
22 bup xstat pathinfo [OPTION ...] <PATH ...>
23 --
24 v,verbose       increase log output (can be used more than once)
25 q,quiet         don't show progress meter
26 exclude-fields= exclude comma-separated fields
27 include-fields= include comma-separated fields (definitive if first)
28 """
29
30 target_filename = ''
31 all_fields = frozenset(['path',
32                         'mode',
33                         'link-target',
34                         'rdev',
35                         'uid',
36                         'gid',
37                         'owner',
38                         'group',
39                         'atime',
40                         'mtime',
41                         'ctime',
42                         'linux-attr',
43                         'linux-xattr',
44                         'posix1e-acl'])
45 active_fields = all_fields
46
47 handle_ctrl_c()
48
49 o = options.Options(optspec)
50 (opt, flags, remainder) = o.parse(sys.argv[1:])
51
52 treat_include_fields_as_definitive = True
53 for flag, value in flags:
54     if flag == '--exclude-fields':
55         exclude_fields = frozenset(value.split(','))
56         for f in exclude_fields:
57             if not f in all_fields:
58                 o.fatal(f + ' is not a valid field name')
59         active_fields = active_fields - exclude_fields
60         treat_include_fields_as_definitive = False
61     elif flag == '--include-fields':
62         include_fields = frozenset(value.split(','))
63         for f in include_fields:
64             if not f in all_fields:
65                 o.fatal(f + ' is not a valid field name')
66         if treat_include_fields_as_definitive:
67             active_fields = include_fields
68             treat_include_fields_as_definitive = False
69         else:
70             active_fields = active_fields | include_fields
71
72 opt.verbose = opt.verbose or 0
73 opt.quiet = opt.quiet or 0
74 metadata.verbose = opt.verbose - opt.quiet
75
76 for path in remainder:
77     try:
78         m = metadata.from_path(path, archive_path = path)
79     except (OSError,IOError), e:
80         if e.errno == errno.ENOENT:
81             add_error(e)
82             continue
83         else:
84             raise
85     if 'path' in active_fields:
86         print 'path:', m.path
87     if 'mode' in active_fields:
88         print 'mode: %s (%s)' % (oct(m.mode),
89                                  xstat.mode_str(m.mode))
90     if 'link-target' in active_fields and stat.S_ISLNK(m.mode):
91         print 'link-target:', m.symlink_target
92     if 'rdev' in active_fields:
93         print 'rdev:', m.rdev
94     if 'uid' in active_fields:
95         print 'uid:', m.uid
96     if 'gid' in active_fields:
97         print 'gid:', m.gid
98     if 'owner' in active_fields:
99         print 'owner:', m.owner
100     if 'group' in active_fields:
101         print 'group:', m.group
102     if 'atime' in active_fields:
103         # If we don't have utimensat, that means we have to use
104         # utime(), and utime() has no way to set the mtime/atime of a
105         # symlink.  Thus, the mtime/atime of a symlink is meaningless,
106         # so let's not report it.  (That way scripts comparing
107         # before/after won't trigger.)
108         if xstat.lutime or not stat.S_ISLNK(m.mode):
109             print 'atime: ' + fstimestr(m.atime)
110         else:
111             print 'atime: 0'
112     if 'mtime' in active_fields:
113         if xstat.lutime or not stat.S_ISLNK(m.mode):
114             print 'mtime: ' + fstimestr(m.mtime)
115         else:
116             print 'mtime: 0'
117     if 'ctime' in active_fields:
118         print 'ctime: ' + fstimestr(m.ctime)
119     if 'linux-attr' in active_fields and m.linux_attr:
120         print 'linux-attr:', hex(m.linux_attr)
121     if 'linux-xattr' in active_fields and m.linux_xattr:
122         for name, value in m.linux_xattr:
123             print 'linux-xattr: %s -> %s' % (name, repr(value))
124     if 'posix1e-acl' in active_fields and m.posix1e_acl and metadata.posix1e:
125         flags = metadata.posix1e.TEXT_ABBREVIATE
126         if stat.S_ISDIR(m.mode):
127             acl = m.posix1e_acl[0]
128             default_acl = m.posix1e_acl[2]
129             print acl.to_any_text('posix1e-acl: ', '\n', flags)
130             print acl.to_any_text('posix1e-acl-default: ', '\n', flags)
131         else:
132             acl = m.posix1e_acl[0]
133             print acl.to_any_text('posix1e-acl: ', '\n', flags)
134
135 if saved_errors:
136     log('WARNING: %d errors encountered.\n' % len(saved_errors))
137     sys.exit(1)
138 else:
139     sys.exit(0)