from cStringIO import StringIO
from bup import vint
-from bup.helpers import add_error, mkdirp, log, utime, lutime, lstat
-from bup._helpers import get_linux_file_attr, set_linux_file_attr
+from bup.helpers import add_error, mkdirp, log, utime, lutime, lstat, FSTime
+import bup._helpers as _helpers
+
+if _helpers.get_linux_file_attr:
+ from bup._helpers import get_linux_file_attr, set_linux_file_attr
# WARNING: the metadata encoding is *not* stable yet. Caveat emptor!
return result
-def _normalize_ts(stamp):
- # For the purposes of normalization, t = s + ns.
- s = stamp[0]
- ns = stamp[1]
- if ns < 0 or ns >= 10**9:
- t = (s * 10**9) + ns
- if t == 0:
- return (0, 0)
- return ((t / 10**9), t % 10**9)
- return stamp
-
-
# These tags are currently conceptually private to Metadata, and they
# must be unique, and must *never* be changed.
_rec_tag_end = 0
self.group = grp.getgrgid(st.st_gid)[0]
def _encode_common(self):
- atime = _normalize_ts(self.atime)
- mtime = _normalize_ts(self.mtime)
- ctime = _normalize_ts(self.ctime)
+ atime = self.atime.to_timespec()
+ mtime = self.mtime.to_timespec()
+ ctime = self.ctime.to_timespec()
result = vint.pack('VVsVsVvVvVvV',
self.mode,
self.uid,
mtime_ns,
self.ctime,
ctime_ns) = vint.unpack('VVsVsVvVvVvV', data)
- self.atime = (self.atime, atime_ns)
- self.mtime = (self.mtime, mtime_ns)
- self.ctime = (self.ctime, ctime_ns)
- if self.atime[1] >= 10**9:
- path = ' for ' + self.path if self.path else ''
- log('bup: warning - normalizing bad atime%s\n' % (path))
- self.atime = _normalize_ts(self.atime)
- if self.mtime[1] >= 10**9:
- path = ' for ' + self.path if self.path else ''
- log('bup: warning - normalizing bad mtime%s\n' % (path))
- self.mtime = _normalize_ts(self.mtime)
- if self.ctime[1] >= 10**9:
- path = ' for ' + self.path if self.path else ''
- log('bup: warning - normalizing bad ctime%s\n' % (path))
- self.ctime = _normalize_ts(self.ctime)
+ self.atime = FSTime.from_timespec((self.atime, atime_ns))
+ self.mtime = FSTime.from_timespec((self.mtime, mtime_ns))
+ self.ctime = FSTime.from_timespec((self.ctime, ctime_ns))
def _create_via_common_rec(self, path, create_symlinks=True):
+ # If the path already exists and is a dir, try rmdir.
+ # If the path already exists and is anything else, try unlink.
+ st = None
+ try:
+ st = lstat(path)
+ except IOError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ if st:
+ if stat.S_ISDIR(st.st_mode):
+ try:
+ os.rmdir(path)
+ except OSError, e:
+ if e.errno == errno.ENOTEMPTY:
+ msg = 'refusing to overwrite non-empty dir' + path
+ raise Exception(msg)
+ raise
+ else:
+ os.unlink(path)
+
if stat.S_ISREG(self.mode):
os.mknod(path, 0600 | stat.S_IFREG)
elif stat.S_ISDIR(self.mode):
elif not stat.S_ISLNK(self.mode):
os.chmod(path, 0)
+ # Don't try to restore owner unless we're root, and even
+ # if asked, don't try to restore the owner or group if
+ # it doesn't exist in the system db.
uid = self.uid
gid = self.gid
if not restore_numeric_ids:
- uid = pwd.getpwnam(self.owner)[2]
- gid = grp.getgrnam(self.group)[2]
+ if os.geteuid() == 0:
+ try:
+ uid = pwd.getpwnam(self.owner)[2]
+ except KeyError:
+ uid = -1
+ log('bup: ignoring unknown owner %s for "%s"\n'
+ % (self.owner, path))
+ else:
+ uid = -1 # Not root; assume we can't change owner.
+ try:
+ gid = grp.getgrnam(self.group)[2]
+ except KeyError:
+ gid = -1
+ log('bup: ignoring unknown group %s for "%s"\n'
+ % (self.group, path))
os.lchown(path, uid, gid)
if _have_lchmod: