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