def redo(self, dryrun): cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.ret.inode.ino) if not dryrun: if self.ob.args["flags"] & os.O_TRUNC: dbg.syscall("%d: %s" % (self.ob.ticket, self.ob)) dbg.syscall("creating empty file, %s" % cur_pn) open(cur_pn, "w").close()
def rollback(self, c): assert (isinstance(c, FileCheckpoint)) # XXX. hack to ignore /proc entries if any(c.d_pn.startswith(d) for d in ["/proc", "/dev"]): return cp_ino = None # ino of the directory _entry_ cpn = c.pn() if cpn: cp_ino = self._get_inode(cpn, self.name_in_dir) dev_pn = kutil.fsget(self.dev) dir_pn = kutil.iget(dev_pn, self.ino) cur_ino = self._get_inode(dir_pn, self.name_in_dir) if cp_ino == cur_ino: return if cur_ino is not None: # backup src = os.path.join(dir_pn, self.name_in_dir) dst = os.path.join(dev_pn, ".inodes", str(cur_ino)) dbg.infom("!", "#R<rename#>: %s -> %s" % (src, dst)) dbg.infom("readers %s" % str(self.readers)) dbg.infom("writers %s" % str(self.writers)) if not runopts.dryrun: os.rename(src, dst) if cp_ino is not None: src = kutil.iget(dev_pn, cp_ino) dst = os.path.join(dir_pn, self.name_in_dir) dbg.infom("!", "#R<link#>: %s -> %s" % (src, dst)) if not runopts.dryrun: os.link(src, dst) kutil.dcache_flush()
def get_file_dev_ino(self): """Get the (dev, ino) that this directory entry currently points to. Should be the same (dev, ino) pair that os.stat() would return when called on the pathname of this file.""" dev_pn = kutil.fsget(self.dev) dir_pn = kutil.iget(dev_pn, self.ino) cur_ino = self._get_inode(dir_pn, self.name_in_dir) return (self.dev, cur_ino)
def __init__(self, tic, tac, dev, ino): fs = kutil.fsget(dev) src = kutil.iget(fs, ino) dst = os.path.join(fs, ".inodes", str(ino) + "-" + str(tic[0])) shutil.copy(src, dst) self.name = ('File', dev, ino, dst) self.dev = dev self.ino = ino self.snap = dst super(FileContentCheckpoint, self).__init__(tic, tac)
def rollback(self, c): assert (isinstance(c, FileCheckpoint)) # XXX. hack to ignore /proc and /dev entries if any(c.d_pn.startswith(d) for d in ["/proc", "/dev"]): return None cpn = c.pn() try: dev_pn = kutil.fsget(self.dev) ino_pn = kutil.iget(dev_pn, self.ino) except kutil.MissingInode: if cpn is None: return dbg.infom("!", "#R<rollback#> %s(%s) -> %s" % (self.ino, ino_pn, cpn)) dbg.infom("readers %s" % str(self.readers)) dbg.infom("writers %s" % str(self.writers)) if runopts.dryrun: return cstat = os.lstat(cpn) if cpn else None istat = os.lstat(ino_pn) if (cstat and stat.S_IFMT(istat.st_mode) != stat.S_IFMT(cstat.st_mode)): raise Exception('inode changed types', cpn, ino_pn, cstat, istat) if stat.S_ISREG(istat.st_mode): if cpn: with open(cpn, 'r') as f1: f1data = f1.read() else: f1data = '' with open(ino_pn, 'r') as f2: f2data = f2.read() if f1data != f2data: with open(ino_pn, 'w') as f2: f2.write(f1data) elif stat.S_ISLNK(istat.st_mode): pass ## no way to change existing symlink elif stat.S_ISDIR(istat.st_mode): # XXX. pass else: raise Exception('cannot handle inode type', stat.S_IFMT(istat.st_mode))
def redo(self, dryrun): cur_pn = kutil.iget("/mnt/retro/trunk", self.ob.args["fd"].inode.ino) dbg.syscall("%d: %s" % (self.ob.ticket, self.ob)) dbg.syscall("re-writing to fd:%s" % cur_pn) if not dryrun: offset = self.ob.args["fd"].offset f = open(cur_pn, "r+") # append if offset == -1: f.seek(0, os.SEEK_END) else: f.seek(offset) f.write(self.ob.args["buf"]) f.close()
def pn(self): """Get the pathname to the snapshot of the file.""" try: return kutil.iget(self.d_pn, self.ino) except kutil.MissingInode: return None
def find_snapshot(ticket, inode, conn): logging.info("finding %s@%d" % (inode, ticket)) # fetch from the snapshot archive try: os.mkdir(path.join(snaproot, ".snap")) except: pass snapfile = path.join(snaproot, ".snap", "%s.%d" % (inode.ino, ticket)) if path.exists(snapfile): return snapfile t = ticket while t >= 0: # fetch from the fresh root (initial check point) if t == 0: return kutil.iget(freshroot, inode.ino) # search history t = t - 1 # apply current system calls r = record_by_ticket(t, conn) # filtering if r.name == "open" and r.ret.inode == inode: if r.args["flags"] & os.O_TRUNC: logging.info("@%d <- empty %s@%d" % (ticket, inode, r.ticket)) open(snapfile, "w").close() else: logging.info("@%d <- %s@%d" % (ticket, inode, r.ticket)) logging.info(" by %s" % r) parent = find_snapshot(r.ticket, inode, conn) copyfile(parent, snapfile) elif r.name == "write" and r.args["fd"].inode == inode: logging.info("@%d <- %s@%d" % (ticket, inode, r.ticket)) logging.info(" by %s" % r) parent = find_snapshot(r.ticket, inode, conn) copyfile(parent, snapfile) offset = r.args["fd"].offset f = open(snapfile, "r+") # append if offset == -1: f.seek(0, os.SEEK_END) else: f.seek(offset) f.write(r.args["buf"]) f.close() elif r.name == "unlink": # TODO restore the file from the .inodes pass else: continue return snapfile