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