]> arthur.barton.de Git - bup.git/blob - lib/bup/xstat.py
696cc1454b3ae10760462a716241d97385cd63c3
[bup.git] / lib / bup / xstat.py
1 """Enhanced stat operations for bup."""
2 import os
3 import bup._helpers as _helpers
4
5 class FSTime():
6     # Class to represent filesystem timestamps.  Use integer
7     # nanoseconds on platforms where we have the higher resolution
8     # lstat.  Use the native python stat representation (floating
9     # point seconds) otherwise.
10
11     def __cmp__(self, x):
12         return self._value.__cmp__(x._value)
13
14     def to_timespec(self):
15         """Return (s, ns) where ns is always non-negative
16         and t = s + ns / 10e8""" # metadata record rep (and libc rep)
17         s_ns = self.secs_nsecs()
18         if s_ns[0] > 0 or s_ns[1] >= 0:
19             return s_ns
20         return (s_ns[0] - 1, 10**9 + s_ns[1]) # ns is negative
21
22     if _helpers.lstat: # Use integer nanoseconds.
23
24         @staticmethod
25         def from_secs(secs):
26             ts = FSTime()
27             ts._value = int(secs * 10**9)
28             return ts
29
30         @staticmethod
31         def from_timespec(timespec):
32             ts = FSTime()
33             ts._value = timespec[0] * 10**9 + timespec[1]
34             return ts
35
36         @staticmethod
37         def from_stat_time(stat_time):
38             return FSTime.from_timespec(stat_time)
39
40         def approx_secs(self):
41             return self._value / 10e8;
42
43         def secs_nsecs(self):
44             "Return a (s, ns) pair: -1.5s -> (-1, -10**9 / 2)."
45             if self._value >= 0:
46                 return (self._value / 10**9, self._value % 10**9)
47             abs_val = -self._value
48             return (- (abs_val / 10**9), - (abs_val % 10**9))
49
50     else: # Use python default floating-point seconds.
51
52         @staticmethod
53         def from_secs(secs):
54             ts = FSTime()
55             ts._value = secs
56             return ts
57
58         @staticmethod
59         def from_timespec(timespec):
60             ts = FSTime()
61             ts._value = timespec[0] + (timespec[1] / 10e8)
62             return ts
63
64         @staticmethod
65         def from_stat_time(stat_time):
66             ts = FSTime()
67             ts._value = stat_time
68             return ts
69
70         def approx_secs(self):
71             return self._value
72
73         def secs_nsecs(self):
74             "Return a (s, ns) pair: -1.5s -> (-1, -5**9)."
75             x = math.modf(self._value)
76             return (x[1], x[0] * 10**9)
77
78
79 def lutime(path, times):
80     if _helpers.utimensat:
81         atime = times[0].to_timespec()
82         mtime = times[1].to_timespec()
83         return _helpers.utimensat(_helpers.AT_FDCWD, path, (atime, mtime),
84                                   _helpers.AT_SYMLINK_NOFOLLOW)
85     else:
86         return None
87
88
89 def utime(path, times):
90     if _helpers.utimensat:
91         atime = times[0].to_timespec()
92         mtime = times[1].to_timespec()
93         return _helpers.utimensat(_helpers.AT_FDCWD, path, (atime, mtime), 0)
94     else:
95         atime = times[0].approx_secs()
96         mtime = times[1].approx_secs()
97         os.utime(path, (atime, mtime))
98
99
100 class stat_result():
101
102     @staticmethod
103     def from_stat_rep(st):
104         result = stat_result()
105         if _helpers._have_ns_fs_timestamps:
106             (result.st_mode,
107              result.st_ino,
108              result.st_dev,
109              result.st_nlink,
110              result.st_uid,
111              result.st_gid,
112              result.st_rdev,
113              result.st_size,
114              atime,
115              mtime,
116              ctime) = st
117         else:
118             result.st_mode = st.st_mode
119             result.st_ino = st.st_ino
120             result.st_dev = st.st_dev
121             result.st_nlink = st.st_nlink
122             result.st_uid = st.st_uid
123             result.st_gid = st.st_gid
124             result.st_rdev = st.st_rdev
125             result.st_size = st.st_size
126             atime = FSTime.from_stat_time(st.st_atime)
127             mtime = FSTime.from_stat_time(st.st_mtime)
128             ctime = FSTime.from_stat_time(st.st_ctime)
129         result.st_atime = FSTime.from_stat_time(atime)
130         result.st_mtime = FSTime.from_stat_time(mtime)
131         result.st_ctime = FSTime.from_stat_time(ctime)
132         return result
133
134
135 def stat(path):
136     if _helpers.stat:
137         st = _helpers.stat(path)
138     else:
139         st = os.stat(path)
140     return stat_result.from_stat_rep(st)
141
142
143 def fstat(path):
144     if _helpers.fstat:
145         st = _helpers.fstat(path)
146     else:
147         st = os.fstat(path)
148     return stat_result.from_stat_rep(st)
149
150
151 def lstat(path):
152     if _helpers.lstat:
153         st = _helpers.lstat(path)
154     else:
155         st = os.lstat(path)
156     return stat_result.from_stat_rep(st)