]> arthur.barton.de Git - bup.git/blob - lib/bup/xstat.py
timespec_to_nsecs(): don't destructure arguments
[bup.git] / lib / bup / xstat.py
1 """Enhanced stat operations for bup."""
2
3 from __future__ import absolute_import
4 import os, sys
5 import stat as pystat
6 from bup import _helpers
7
8 try:
9     _bup_utimensat = _helpers.bup_utimensat
10 except AttributeError as e:
11     _bup_utimensat = False
12
13 try:
14     _bup_utimes = _helpers.bup_utimes
15 except AttributeError as e:
16     _bup_utimes = False
17
18 try:
19     _bup_lutimes = _helpers.bup_lutimes
20 except AttributeError as e:
21     _bup_lutimes = False
22
23
24 def timespec_to_nsecs(ts):
25     ts_s, ts_ns = ts
26     return ts_s * 10**9 + ts_ns
27
28
29 def nsecs_to_timespec(ns):
30     """Return (s, ns) where ns is always non-negative
31     and t = s + ns / 10e8""" # metadata record rep
32     ns = int(ns)
33     return (ns / 10**9, ns % 10**9)
34
35
36 def nsecs_to_timeval(ns):
37     """Return (s, us) where ns is always non-negative
38     and t = s + us / 10e5"""
39     ns = int(ns)
40     return (ns / 10**9, (ns % 10**9) / 1000)
41
42
43 def fstime_floor_secs(ns):
44     """Return largest integer not greater than ns / 10e8."""
45     return int(ns) / 10**9;
46
47
48 def fstime_to_timespec(ns):
49     return nsecs_to_timespec(ns)
50
51
52 def fstime_to_sec_str(fstime):
53     (s, ns) = fstime_to_timespec(fstime)
54     if(s < 0):
55         s += 1
56     if ns == 0:
57         return '%d' % s
58     else:
59         return '%d.%09d' % (s, ns)
60
61
62 if _bup_utimensat:
63     def utime(path, times):
64         """Times must be provided as (atime_ns, mtime_ns)."""
65         atime = nsecs_to_timespec(times[0])
66         mtime = nsecs_to_timespec(times[1])
67         _bup_utimensat(_helpers.AT_FDCWD, path, (atime, mtime), 0)
68     def lutime(path, times):
69         """Times must be provided as (atime_ns, mtime_ns)."""
70         atime = nsecs_to_timespec(times[0])
71         mtime = nsecs_to_timespec(times[1])
72         _bup_utimensat(_helpers.AT_FDCWD, path, (atime, mtime),
73                        _helpers.AT_SYMLINK_NOFOLLOW)
74 else: # Must have these if utimensat isn't available.
75     def utime(path, times):
76         """Times must be provided as (atime_ns, mtime_ns)."""
77         atime = nsecs_to_timeval(times[0])
78         mtime = nsecs_to_timeval(times[1])
79         _bup_utimes(path, (atime, mtime))
80     def lutime(path, times):
81         """Times must be provided as (atime_ns, mtime_ns)."""
82         atime = nsecs_to_timeval(times[0])
83         mtime = nsecs_to_timeval(times[1])
84         _bup_lutimes(path, (atime, mtime))
85
86 _cygwin_sys = sys.platform.startswith('cygwin')
87
88 def _fix_cygwin_id(id):
89     if id < 0:
90         id += 0x100000000
91         assert(id >= 0)
92     return id
93
94
95 class stat_result:
96     @staticmethod
97     def from_xstat_rep(st):
98         global _cygwin_sys
99         result = stat_result()
100         (result.st_mode,
101          result.st_ino,
102          result.st_dev,
103          result.st_nlink,
104          result.st_uid,
105          result.st_gid,
106          result.st_rdev,
107          result.st_size,
108          result.st_atime,
109          result.st_mtime,
110          result.st_ctime) = st
111         # Inlined timespec_to_nsecs after profiling
112         result.st_atime = result.st_atime[0] * 10**9 + result.st_atime[1]
113         result.st_mtime = result.st_mtime[0] * 10**9 + result.st_mtime[1]
114         result.st_ctime = result.st_ctime[0] * 10**9 + result.st_ctime[1]
115         if _cygwin_sys:
116             result.st_uid = _fix_cygwin_id(result.st_uid)
117             result.st_gid = _fix_cygwin_id(result.st_gid)
118         return result
119
120
121 def stat(path):
122     return stat_result.from_xstat_rep(_helpers.stat(path))
123
124
125 def fstat(path):
126     return stat_result.from_xstat_rep(_helpers.fstat(path))
127
128
129 def lstat(path):
130     return stat_result.from_xstat_rep(_helpers.lstat(path))
131
132
133 def mode_str(mode):
134     result = ''
135     # FIXME: Other types?
136     if pystat.S_ISREG(mode):
137         result += '-'
138     elif pystat.S_ISDIR(mode):
139         result += 'd'
140     elif pystat.S_ISCHR(mode):
141         result += 'c'
142     elif pystat.S_ISBLK(mode):
143         result += 'b'
144     elif pystat.S_ISFIFO(mode):
145         result += 'p'
146     elif pystat.S_ISLNK(mode):
147         result += 'l'
148     elif pystat.S_ISSOCK(mode):
149         result += 's'
150     else:
151         result += '?'
152
153     result += 'r' if (mode & pystat.S_IRUSR) else '-'
154     result += 'w' if (mode & pystat.S_IWUSR) else '-'
155     result += 'x' if (mode & pystat.S_IXUSR) else '-'
156     result += 'r' if (mode & pystat.S_IRGRP) else '-'
157     result += 'w' if (mode & pystat.S_IWGRP) else '-'
158     result += 'x' if (mode & pystat.S_IXGRP) else '-'
159     result += 'r' if (mode & pystat.S_IROTH) else '-'
160     result += 'w' if (mode & pystat.S_IWOTH) else '-'
161     result += 'x' if (mode & pystat.S_IXOTH) else '-'
162     return result
163
164
165 def classification_str(mode, include_exec):
166     if pystat.S_ISREG(mode):
167         if include_exec \
168            and (pystat.S_IMODE(mode) \
169                 & (pystat.S_IXUSR | pystat.S_IXGRP | pystat.S_IXOTH)):
170             return '*'
171         else:
172             return ''
173     elif pystat.S_ISDIR(mode):
174         return '/'
175     elif pystat.S_ISLNK(mode):
176         return '@'
177     elif pystat.S_ISFIFO(mode):
178         return '|'
179     elif pystat.S_ISSOCK(mode):
180         return '='
181     else:
182         return ''