]> arthur.barton.de Git - bup.git/blob - lib/bup/xstat.py
Depend on python 3 for utime when using 3
[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     @staticmethod
106     def from_xstat_rep(st):
107         global _cygwin_sys
108         result = stat_result()
109         (result.st_mode,
110          result.st_ino,
111          result.st_dev,
112          result.st_nlink,
113          result.st_uid,
114          result.st_gid,
115          result.st_rdev,
116          result.st_size,
117          result.st_atime,
118          result.st_mtime,
119          result.st_ctime) = st
120         # Inlined timespec_to_nsecs after profiling
121         result.st_atime = result.st_atime[0] * 10**9 + result.st_atime[1]
122         result.st_mtime = result.st_mtime[0] * 10**9 + result.st_mtime[1]
123         result.st_ctime = result.st_ctime[0] * 10**9 + result.st_ctime[1]
124         if _cygwin_sys:
125             result.st_uid = _fix_cygwin_id(result.st_uid)
126             result.st_gid = _fix_cygwin_id(result.st_gid)
127         return result
128
129
130 def stat(path):
131     return stat_result.from_xstat_rep(_helpers.stat(path))
132
133
134 def fstat(path):
135     return stat_result.from_xstat_rep(_helpers.fstat(path))
136
137
138 def lstat(path):
139     return stat_result.from_xstat_rep(_helpers.lstat(path))
140
141
142 def mode_str(mode):
143     result = ''
144     # FIXME: Other types?
145     if pystat.S_ISREG(mode):
146         result += '-'
147     elif pystat.S_ISDIR(mode):
148         result += 'd'
149     elif pystat.S_ISCHR(mode):
150         result += 'c'
151     elif pystat.S_ISBLK(mode):
152         result += 'b'
153     elif pystat.S_ISFIFO(mode):
154         result += 'p'
155     elif pystat.S_ISLNK(mode):
156         result += 'l'
157     elif pystat.S_ISSOCK(mode):
158         result += 's'
159     else:
160         result += '?'
161
162     result += 'r' if (mode & pystat.S_IRUSR) else '-'
163     result += 'w' if (mode & pystat.S_IWUSR) else '-'
164     result += 'x' if (mode & pystat.S_IXUSR) else '-'
165     result += 'r' if (mode & pystat.S_IRGRP) else '-'
166     result += 'w' if (mode & pystat.S_IWGRP) else '-'
167     result += 'x' if (mode & pystat.S_IXGRP) else '-'
168     result += 'r' if (mode & pystat.S_IROTH) else '-'
169     result += 'w' if (mode & pystat.S_IWOTH) else '-'
170     result += 'x' if (mode & pystat.S_IXOTH) else '-'
171     return result
172
173
174 def classification_str(mode, include_exec):
175     if pystat.S_ISREG(mode):
176         if include_exec \
177            and (pystat.S_IMODE(mode) \
178                 & (pystat.S_IXUSR | pystat.S_IXGRP | pystat.S_IXOTH)):
179             return '*'
180         else:
181             return ''
182     elif pystat.S_ISDIR(mode):
183         return '/'
184     elif pystat.S_ISLNK(mode):
185         return '@'
186     elif pystat.S_ISFIFO(mode):
187         return '|'
188     elif pystat.S_ISSOCK(mode):
189         return '='
190     else:
191         return ''