INSTALL=install
PYTHON=python
- MANDIR=$(DESTDIR)/usr/share/man
- DOCDIR=$(DESTDIR)/usr/share/doc/bup
- BINDIR=$(DESTDIR)/usr/bin
- LIBDIR=$(DESTDIR)/usr/lib/bup
+ PREFIX=/usr
+ MANDIR=$(DESTDIR)$(PREFIX)/share/man
+ DOCDIR=$(DESTDIR)$(PREFIX)/share/doc/bup
+ BINDIR=$(DESTDIR)$(PREFIX)/bin
+ LIBDIR=$(DESTDIR)$(PREFIX)/lib/bup
install: all
$(INSTALL) -d $(MANDIR)/man1 $(DOCDIR) $(BINDIR) \
$(LIBDIR)/bup $(LIBDIR)/cmd $(LIBDIR)/tornado \
%/clean:
$(MAKE) -C $* clean
+
+ config/config.h: config/Makefile config/configure config/configure.inc \
+ $(wildcard config/*.in)
+ cd config && make config.h
lib/bup/_helpers$(SOEXT): \
+ config/config.h \
lib/bup/bupsplit.c lib/bup/_helpers.c lib/bup/csetup.py
@rm -f $@
- cd lib/bup && LDFLAGS="$(LDFLAGS)" CFLAGS="$(CFLAGS)" $(PYTHON) csetup.py build
+ cd lib/bup && \
+ LDFLAGS="$(LDFLAGS)" CFLAGS="$(CFLAGS)" $(PYTHON) csetup.py build
cp lib/bup/build/*/_helpers$(SOEXT) lib/bup/
.PHONY: lib/bup/_version.py
git archive origin/html | (cd Documentation; tar -xvf -)
git archive origin/man | (cd Documentation; tar -xvf -)
-# tgit.py plays with permissions on lib/bup/t/pybuptest.tmp, so we should
-# ensure that we can delete the directory before doing it.
clean: Documentation/clean
rm -f *.o lib/*/*.o *.so lib/*/*.so *.dll *.exe \
.*~ *~ */*~ lib/*/*~ lib/*/*/*~ \
#define _LARGEFILE64_SOURCE 1
#undef NDEBUG
+ #include "../../config/config.h"
#include "bupsplit.h"
#include <Python.h>
#include <assert.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef linux
#include <linux/fs.h>
#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
#endif
static int istty2 = 0;
}
close(fd);
- return Py_BuildValue("i", 1);
+ return Py_BuildValue("O", Py_None);
}
#endif /* def linux */
-
+ #ifdef HAVE_UTIMENSAT
#if defined(_ATFILE_SOURCE) \
|| _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
#define HAVE_BUP_UTIMENSAT 1
if (rc != 0)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
- return Py_BuildValue("i", 1);
+ return Py_BuildValue("O", Py_None);
}
#endif /* defined(_ATFILE_SOURCE)
|| _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L */
-
+ #endif /* HAVE_UTIMENSAT */
-#ifdef linux /* and likely others */
+static PyObject *stat_struct_to_py(const struct stat *st)
+{
+ /* Enforce the current timespec nanosecond range expectations. */
+ if (st->st_atim.tv_nsec < 0 || st->st_atim.tv_nsec > 999999999)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid atime timespec nanoseconds");
+ return NULL;
+ }
+ if (st->st_mtim.tv_nsec < 0 || st->st_mtim.tv_nsec > 999999999)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid mtime timespec nanoseconds");
+ return NULL;
+ }
+ if (st->st_ctim.tv_nsec < 0 || st->st_ctim.tv_nsec > 999999999)
+ {
+ PyErr_SetString(PyExc_ValueError, "invalid ctime timespec nanoseconds");
+ return NULL;
+ }
+
+ return Py_BuildValue("kkkkkkkk(Ll)(Ll)(Ll)",
+ (unsigned long) st->st_mode,
+ (unsigned long) st->st_ino,
+ (unsigned long) st->st_dev,
+ (unsigned long) st->st_nlink,
+ (unsigned long) st->st_uid,
+ (unsigned long) st->st_gid,
+ (unsigned long) st->st_rdev,
+ (unsigned long) st->st_size,
+ (long long) st->st_atime,
+ (long) st->st_atim.tv_nsec,
+ (long long) st->st_mtime,
+ (long) st->st_mtim.tv_nsec,
+ (long long) st->st_ctime,
+ (long) st->st_ctim.tv_nsec);
+}
+
-#define HAVE_BUP_STAT 1
static PyObject *bup_stat(PyObject *self, PyObject *args)
{
int rc;
rc = stat(filename, &st);
if (rc != 0)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ return stat_struct_to_py(&st);
+}
+
- return Py_BuildValue("kkkkkkkk"
- "(ll)"
- "(ll)"
- "(ll)",
- (unsigned long) st.st_mode,
- (unsigned long) st.st_ino,
- (unsigned long) st.st_dev,
- (unsigned long) st.st_nlink,
- (unsigned long) st.st_uid,
- (unsigned long) st.st_gid,
- (unsigned long) st.st_rdev,
- (unsigned long) st.st_size,
- (long) st.st_atime,
- (long) st.st_atim.tv_nsec,
- (long) st.st_mtime,
- (long) st.st_mtim.tv_nsec,
- (long) st.st_ctime,
- (long) st.st_ctim.tv_nsec);
-}
-
-
-#define HAVE_BUP_LSTAT 1
static PyObject *bup_lstat(PyObject *self, PyObject *args)
{
int rc;
rc = lstat(filename, &st);
if (rc != 0)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ return stat_struct_to_py(&st);
+}
+
- return Py_BuildValue("kkkkkkkk"
- "(ll)"
- "(ll)"
- "(ll)",
- (unsigned long) st.st_mode,
- (unsigned long) st.st_ino,
- (unsigned long) st.st_dev,
- (unsigned long) st.st_nlink,
- (unsigned long) st.st_uid,
- (unsigned long) st.st_gid,
- (unsigned long) st.st_rdev,
- (unsigned long) st.st_size,
- (long) st.st_atime,
- (long) st.st_atim.tv_nsec,
- (long) st.st_mtime,
- (long) st.st_mtim.tv_nsec,
- (long) st.st_ctime,
- (long) st.st_ctim.tv_nsec);
-}
-
-
-#define HAVE_BUP_FSTAT 1
static PyObject *bup_fstat(PyObject *self, PyObject *args)
{
int rc, fd;
rc = fstat(fd, &st);
if (rc != 0)
return PyErr_SetFromErrno(PyExc_OSError);
-
- return Py_BuildValue("kkkkkkkk"
- "(ll)"
- "(ll)"
- "(ll)",
- (unsigned long) st.st_mode,
- (unsigned long) st.st_ino,
- (unsigned long) st.st_dev,
- (unsigned long) st.st_nlink,
- (unsigned long) st.st_uid,
- (unsigned long) st.st_gid,
- (unsigned long) st.st_rdev,
- (unsigned long) st.st_size,
- (long) st.st_atime,
- (long) st.st_atim.tv_nsec,
- (long) st.st_mtime,
- (long) st.st_mtim.tv_nsec,
- (long) st.st_ctime,
- (long) st.st_ctim.tv_nsec);
+ return stat_struct_to_py(&st);
}
-#endif /* def linux */
-
static PyMethodDef helper_methods[] = {
{ "selftest", selftest, METH_VARARGS,
{ "utimensat", bup_utimensat, METH_VARARGS,
"Change file timestamps with nanosecond precision." },
#endif
-#ifdef HAVE_BUP_STAT
{ "stat", bup_stat, METH_VARARGS,
"Extended version of stat." },
-#endif
-#ifdef HAVE_BUP_LSTAT
{ "lstat", bup_lstat, METH_VARARGS,
"Extended version of lstat." },
-#endif
-#ifdef HAVE_BUP_FSTAT
{ "fstat", bup_fstat, METH_VARARGS,
"Extended version of fstat." },
-#endif
{ NULL, NULL, 0, NULL }, // sentinel
};
PyModule_AddObject(m, "AT_FDCWD", Py_BuildValue("i", AT_FDCWD));
PyModule_AddObject(m, "AT_SYMLINK_NOFOLLOW",
Py_BuildValue("i", AT_SYMLINK_NOFOLLOW));
-#endif
-#ifdef HAVE_BUP_STAT
- PyModule_AddIntConstant(m, "_have_ns_fs_timestamps", 1);
-#else
- PyModule_AddIntConstant(m, "_have_ns_fs_timestamps", 0);
#endif
e = getenv("BUP_FORCE_TTY");
istty2 = isatty(2) || (atoi(e ? e : "0") & 2);
"""
import os, sys, zlib, time, subprocess, struct, stat, re, tempfile, glob
from bup.helpers import *
-from bup import _helpers, path, midx, bloom
+from bup import _helpers, path, midx, bloom, xstat
max_pack_size = 1000*1000*1000 # larger packs will slow down pruning
max_pack_objects = 200*1000 # cache memory usage is about 83 bytes per object
yield (int(mode, 8), name, sha)
- def _encode_packobj(type, content):
+ def _encode_packobj(type, content, compression_level=1):
szout = ''
sz = len(content)
szbits = (sz & 0x0f) | (_typemap[type]<<4)
break
szbits = sz & 0x7f
sz >>= 7
- z = zlib.compressobj(1)
+ if compression_level > 9:
+ compression_level = 9
+ elif compression_level < 0:
+ compression_level = 0
+ z = zlib.compressobj(compression_level)
yield szout
yield z.compress(content)
yield z.flush()
- def _encode_looseobj(type, content):
- z = zlib.compressobj(1)
+ def _encode_looseobj(type, content, compression_level=1):
+ z = zlib.compressobj(compression_level)
yield z.compress('%s %d\0' % (type, len(content)))
yield z.compress(content)
yield z.flush()
else:
midxl.append(mx)
midxl.sort(key=lambda ix:
- (-len(ix), -os.stat(ix.name).st_mtime))
+ (-len(ix), -xstat.stat(ix.name).st_mtime))
for ix in midxl:
any_needed = False
for sub in ix.idxnames:
class PackWriter:
"""Writes Git objects inside a pack file."""
- def __init__(self, objcache_maker=_make_objcache):
+ def __init__(self, objcache_maker=_make_objcache, compression_level=1):
self.count = 0
self.outbytes = 0
self.filename = None
self.idx = None
self.objcache_maker = objcache_maker
self.objcache = None
+ self.compression_level = compression_level
def __del__(self):
self.close()
log('>')
if not sha:
sha = calc_hash(type, content)
- size, crc = self._raw_write(_encode_packobj(type, content), sha=sha)
+ size, crc = self._raw_write(_encode_packobj(type, content,
+ self.compression_level),
+ sha=sha)
if self.outbytes >= max_pack_size or self.count >= max_pack_objects:
self.breakpoint()
return sha
except OSError, e:
if e.errno == errno.ENOENT:
if repodir != home_repodir:
- log('error: %r is not a bup/git repository\n' % repo())
+ log('error: %r is not a bup repository; run "bup init"\n'
+ % repo())
sys.exit(15)
else:
init_repo()
# Public License as described in the bup LICENSE file.
import errno, os, sys, stat, pwd, grp, struct, re
from cStringIO import StringIO
-from bup import vint
+from bup import vint, xstat
from bup.drecurse import recursive_dirlist
- from bup.helpers import add_error, mkdirp, log
- from bup.xstat import utime, lutime
+ from bup.helpers import add_error, mkdirp, log, is_superuser
-from bup.xstat import utime, lutime, lstat, FSTime
++from bup.xstat import utime, lutime, lstat
import bup._helpers as _helpers
try:
add_error("no group name for id %s '%s'" % (st.st_gid, path))
def _encode_common(self):
- atime = self.atime.to_timespec()
- mtime = self.mtime.to_timespec()
- ctime = self.ctime.to_timespec()
+ atime = xstat.nsecs_to_timespec(self.atime)
+ mtime = xstat.nsecs_to_timespec(self.mtime)
+ ctime = xstat.nsecs_to_timespec(self.ctime)
result = vint.pack('VVsVsVvVvVvV',
self.mode,
self.uid,
mtime_ns,
self.ctime,
ctime_ns) = vint.unpack('VVsVsVvVvVvV', data)
- 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))
+ self.atime = xstat.timespec_to_nsecs((self.atime, atime_ns))
+ self.mtime = xstat.timespec_to_nsecs((self.mtime, mtime_ns))
+ self.ctime = xstat.timespec_to_nsecs((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)
+ st = xstat.lstat(path)
except OSError, e:
if e.errno != errno.ENOENT:
raise
uid = -1
add_error('ignoring missing owner for "%s"\n' % path)
else:
- if os.geteuid() != 0:
+ if not is_superuser():
uid = -1 # Not root; assume we can't change owner.
else:
try:
def from_path(path, statinfo=None, archive_path=None, save_symlinks=True):
result = Metadata()
result.path = archive_path
- st = statinfo or lstat(path)
+ st = statinfo or xstat.lstat(path)
result._add_common(path, st)
if save_symlinks:
result._add_symlink_target(path, st)
(
rm -rf "$TOP/bupmeta.tmp/src"
mkdir -p "$TOP/bupmeta.tmp/src"
- cp -a Documentation cmd lib t "$TOP/bupmeta.tmp"/src
+ #cp -a Documentation cmd lib t "$TOP/bupmeta.tmp"/src
+ cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
) || WVFAIL
# Use the test tree to check bup meta.
chown root:root testfs
chmod 0700 testfs
- cp -a src testfs/src
+ #cp -a src testfs/src
+ cp -pPR src testfs/src
(cd testfs && test-src-create-extract)
WVSTART 'meta - atime (as root)'
mkdir testfs/src/foo
touch testfs/src/bar
PYTHONPATH="$TOP/lib" \
- python -c "from bup.xstat import lutime, FSTime; \
- x = FSTime.from_secs(42);\
- lutime('testfs/src/foo', (x, x));\
- lutime('testfs/src/bar', (x, x));"
+ python -c "from bup import xstat; \
+ x = xstat.timespec_to_nsecs((42, 0));\
+ xstat.lutime('testfs/src/foo', (x, x));\
+ xstat.lutime('testfs/src/bar', (x, x));"
cd testfs
WVPASS bup meta -v --create --recurse --file src.meta src
bup meta -tvf src.meta