X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fbup%2Fxstat.py;h=077020213f4378b6d816b3315cace6f78f05c043;hb=c40b3dd5fd74e72024fbaad3daf5a958aefa1c54;hp=c2533705ded008641213c4f407f659b164db8fb0;hpb=56dd4712e7d66a8623ec7b85753469f9500c6003;p=bup.git diff --git a/lib/bup/xstat.py b/lib/bup/xstat.py index c253370..0770202 100644 --- a/lib/bup/xstat.py +++ b/lib/bup/xstat.py @@ -1,28 +1,44 @@ """Enhanced stat operations for bup.""" -import os + +from __future__ import absolute_import +import os, sys +import stat as pystat from bup import _helpers +try: + _bup_utimensat = _helpers.bup_utimensat +except AttributeError as e: + _bup_utimensat = False try: - _have_utimensat = _helpers.utimensat -except AttributeError, e: - _have_utimensat = False + _bup_utimes = _helpers.bup_utimes +except AttributeError as e: + _bup_utimes = False + +try: + _bup_lutimes = _helpers.bup_lutimes +except AttributeError as e: + _bup_lutimes = False def timespec_to_nsecs((ts_s, ts_ns)): - # c.f. _helpers.c: timespec_vals_to_py_ns() - if ts_ns < 0 or ts_ns > 999999999: - raise Exception('invalid timespec nsec value') return ts_s * 10**9 + ts_ns def nsecs_to_timespec(ns): """Return (s, ns) where ns is always non-negative - and t = s + ns / 10e8""" # metadata record rep (and libc rep) + and t = s + ns / 10e8""" # metadata record rep ns = int(ns) return (ns / 10**9, ns % 10**9) +def nsecs_to_timeval(ns): + """Return (s, us) where ns is always non-negative + and t = s + us / 10e5""" + ns = int(ns) + return (ns / 10**9, (ns % 10**9) / 1000) + + def fstime_floor_secs(ns): """Return largest integer not greater than ns / 10e8.""" return int(ns) / 10**9; @@ -32,29 +48,53 @@ def fstime_to_timespec(ns): return nsecs_to_timespec(ns) -if _have_utimensat: - def lutime(path, times): +def fstime_to_sec_str(fstime): + (s, ns) = fstime_to_timespec(fstime) + if(s < 0): + s += 1 + if ns == 0: + return '%d' % s + else: + return '%d.%09d' % (s, ns) + + +if _bup_utimensat: + def utime(path, times): + """Times must be provided as (atime_ns, mtime_ns).""" atime = nsecs_to_timespec(times[0]) mtime = nsecs_to_timespec(times[1]) - _helpers.utimensat(_helpers.AT_FDCWD, path, (atime, mtime), - _helpers.AT_SYMLINK_NOFOLLOW) - def utime(path, times): + _bup_utimensat(_helpers.AT_FDCWD, path, (atime, mtime), 0) + def lutime(path, times): + """Times must be provided as (atime_ns, mtime_ns).""" atime = nsecs_to_timespec(times[0]) mtime = nsecs_to_timespec(times[1]) - _helpers.utimensat(_helpers.AT_FDCWD, path, (atime, mtime), 0) -else: + _bup_utimensat(_helpers.AT_FDCWD, path, (atime, mtime), + _helpers.AT_SYMLINK_NOFOLLOW) +else: # Must have these if utimensat isn't available. + def utime(path, times): + """Times must be provided as (atime_ns, mtime_ns).""" + atime = nsecs_to_timeval(times[0]) + mtime = nsecs_to_timeval(times[1]) + _bup_utimes(path, (atime, mtime)) def lutime(path, times): - return None + """Times must be provided as (atime_ns, mtime_ns).""" + atime = nsecs_to_timeval(times[0]) + mtime = nsecs_to_timeval(times[1]) + _bup_lutimes(path, (atime, mtime)) - def utime(path, times): - atime = fstime_floor_secs(times[0]) - mtime = fstime_floor_secs(times[1]) - os.utime(path, (atime, mtime)) +_cygwin_sys = sys.platform.startswith('cygwin') + +def _fix_cygwin_id(id): + if id < 0: + id += 0x100000000 + assert(id >= 0) + return id class stat_result: @staticmethod def from_xstat_rep(st): + global _cygwin_sys result = stat_result() (result.st_mode, result.st_ino, @@ -67,9 +107,13 @@ class stat_result: result.st_atime, result.st_mtime, result.st_ctime) = st - result.st_atime = timespec_to_nsecs(result.st_atime) - result.st_mtime = timespec_to_nsecs(result.st_mtime) - result.st_ctime = timespec_to_nsecs(result.st_ctime) + # Inlined timespec_to_nsecs after profiling + result.st_atime = result.st_atime[0] * 10**9 + result.st_atime[1] + result.st_mtime = result.st_mtime[0] * 10**9 + result.st_mtime[1] + result.st_ctime = result.st_ctime[0] * 10**9 + result.st_ctime[1] + if _cygwin_sys: + result.st_uid = _fix_cygwin_id(result.st_uid) + result.st_gid = _fix_cygwin_id(result.st_gid) return result @@ -83,3 +127,55 @@ def fstat(path): def lstat(path): return stat_result.from_xstat_rep(_helpers.lstat(path)) + + +def mode_str(mode): + result = '' + # FIXME: Other types? + if pystat.S_ISREG(mode): + result += '-' + elif pystat.S_ISDIR(mode): + result += 'd' + elif pystat.S_ISCHR(mode): + result += 'c' + elif pystat.S_ISBLK(mode): + result += 'b' + elif pystat.S_ISFIFO(mode): + result += 'p' + elif pystat.S_ISLNK(mode): + result += 'l' + elif pystat.S_ISSOCK(mode): + result += 's' + else: + result += '?' + + result += 'r' if (mode & pystat.S_IRUSR) else '-' + result += 'w' if (mode & pystat.S_IWUSR) else '-' + result += 'x' if (mode & pystat.S_IXUSR) else '-' + result += 'r' if (mode & pystat.S_IRGRP) else '-' + result += 'w' if (mode & pystat.S_IWGRP) else '-' + result += 'x' if (mode & pystat.S_IXGRP) else '-' + result += 'r' if (mode & pystat.S_IROTH) else '-' + result += 'w' if (mode & pystat.S_IWOTH) else '-' + result += 'x' if (mode & pystat.S_IXOTH) else '-' + return result + + +def classification_str(mode, include_exec): + if pystat.S_ISREG(mode): + if include_exec \ + and (pystat.S_IMODE(mode) \ + & (pystat.S_IXUSR | pystat.S_IXGRP | pystat.S_IXOTH)): + return '*' + else: + return '' + elif pystat.S_ISDIR(mode): + return '/' + elif pystat.S_ISLNK(mode): + return '@' + elif pystat.S_ISFIFO(mode): + return '|' + elif pystat.S_ISSOCK(mode): + return '=' + else: + return ''