def _createHard(self, idRev, openedconn): self._logger.debug ( 'Doing a hard revision on %s', str(idRev) ) deltaList = self._getDeltasSinceEvent ('hardexist', 1, idRev) self._logger.debug ( "received this deltaList: %s", repr(deltaList) ) if type(deltaList) == int: self._seterrormsg( 'Could not create internal chain of deltas. '+ 'Internal error: ' + str(deltaList) ) return ERR_INTERNAL # join everything # first throw away this, but save for later hardRev = deltaList.pop() self._logger.debug ( "Generating internal delta" ) try: listoffiles = [os.path.join(self._deltasdir, str(i)) for i in deltaList] delta = Deltas.multiOpen(listoffiles) except: return ERR_FS # the last one, now will have hardcopy openedconn.execute ( '''update revisions set hardexist=1 where idrev=?''' , (idRev,) ) infile = os.path.join(self._hardsdir,str(hardRev)) outfile = os.path.join(self._hardsdir,str(idRev)) delta.patch(infile, outfile) return 0
def GetDelta(self, idRev, idFromRev): ''' Get a delta (see rsync algorithm) from the server to jump to a newer revision. The delta is known to the server or fabricated from some deltas @param idRev: "Destination revision" @param irFromRev: "Origin revision" @return: Binary information of the petition (asked delta) ''' with self._conn as c: # First, check permissions row = c.execute ("select idfile from revisions where idrev=?", (idFromRev,) ).fetchone() if not row: self._seterrormsg("Unknown origin revision") return ERR_NOTEXIST row = c.execute ("select path,isfolder from files where idfile=?", (row['idfile'],) ) if not row: self._seterrormsg('Unconsistent files table (database error)') return ERR_INTERNAL if row['isfolder']: self._seterrormsg('Cannot get a delta for a folder') return ERR_CANNOT originpath = row['path'] ret = self._checkPerms(originpath, auth.READ) if ret < 0: return ret # Until now everything seems fine, let's check "destination" revRow = c.execute( "select * from revisions where idrev=?" , (idRev,) ).fetchone() if not revRow: self._seterrormsg('Unknown destination revision') return ERR_NOTEXIST row = c.execute ("select path,isfolder from files where idfile=?" , (revRow['idfile']) ).fetchone() if not row: self._seterrormsg('Inconsistent files table (database error)') return ERR_INTERNAL if row['isfolder']: self._seterrormsg('Cannot get a delta for a folder') return ERR_CANNOT # only check permissions if there is a folder change if originpath != row['path']: ret = self._checkperms(row['path'], auth.READ) if ret < 0: return ret #if it's the easy way, we do it the easy way (most likely to hapen) if (revRow['fromrev'] == idFromRev) and (revRow['fromtype'] == REV_MODIFIED): #yes, we are lucky! try: return Deltas.open(os.path.join(self._deltasdir,str(idRev))).getXMLRPCBinary() except: return ERR_FS else: # 1st: check that exists a chain of non-deletions between # this two revisions (save the first hardcopy for later) deltaList = self._getDeltasSinceEvent ( 'fromrev' , idFromRev , idRev ) if type(deltaList) == int: return deltaList # 2nd: try to join everything try: listoffiles = [os.path.join(self._deltasdir, str(i)) for i in deltaList] delta = Deltas.multiOpen(listoffiles) except: return ERR_FS # 3rd: Send delta return delta.getXMLRPCBinary()
def SendDelta(self, idRev, sentdelta, chksum = None, size = 'NULL'): ''' Send a delta (see rsync algorithm) to server @param idRev: The identifier of the origin revision @param sentdelta: Binary of the delta @param chksum: Checksum of the file (not the delta) @param size: Size of the file (not the delta) @return: Pair of the identifier of the actual revision (once applied this delta) and the server timestamp of this file. ''' tsnow = datetime.fromtimestamp(int(time.time())) # get real checksum self._logger.debug("Receiving delta, now()=%s", repr(tsnow) ) self._logger.debug("Chksum received: %s", repr(chksum) ) #check if everything is ok with self._conn as c: self._logger.debug ( "Getting row of revisions . . ." ) rowRev = c.execute ( "select * from revisions where idrev=?" , (idRev,)).fetchone() if not rowRev: self._seterrormsg('Unknown revision') return ERR_NOTEXIST self._logger.debug ( "Getting row of file information . . ." ) rowFile = c.execute ( "select * from files where idfile=?" , (rowRev['idfile'],) ).fetchone() if not rowFile: self._seterrormsg('Data not found in the database, '+ 'check revision existance') return ERR_NOTEXIST # Authentication check self._checkPerms(rowFile['path'], auth.WRITE) # Basic checks if rowFile['lastrev'] != idRev: self._seterrormsg("Outdated client: not the last revision") return ERR_OUTDATED if rowFile['deleted'] == 1: self._seterrormsg("File is deleted, cannot add revisions to it") return ERR_DELETED if rowFile['isfolder']: self._seterrormsg('The file is a folder, cannot add revisions to it') return ERR_CANNOT # Now do really something self._logger.debug ( "Inserting new revision into database . . ." ) cur = c.execute ( '''insert into revisions (idfile,uid,timestamp,fromrev,typefrom,chksum,size,hardexist) values (?,?,?,?,?,?,?,0)''' , (rowRev['idfile'], self._getUID(), tsnow, idRev, REV_MODIFIED, chksum, size ) ) nextRev = cur.lastrowid c.execute ( '''update files set lastrev=? where idfile=?''' , (nextRev , rowRev['idfile'] ) ) self._logger.debug ( "Going to write the delta file" ) #save the delta delta = Deltas.load(sentdelta) delta.save(os.path.join(self._deltasdir,str(nextRev))) self._logger.debug ( "Latest revision: %s" , int(nextRev) ) return nextRev, tsnow