³ò
OÉcIc           @   s  d  Z  d d k l Z d d k Z d d k Z d d k Z d d k Z d d k Z d d k Z d d k	 Z	 d d k
 Z
 d d k Z d d k Z d d k Z d d k Z d d k Z d d k Z d d k Z d d k Z d a d a d e f d „  ƒ  YZ d „  Z d „  Z d „  Z d	 „  Z d
 „  Z d „  Z d „  Z d „  Z d e i  f d „  ƒ  YZ! d e
 i" f d „  ƒ  YZ# d „  Z$ d S(   s±  Code for reverting the rdiff-backup directory to prev state

This module is used after an aborted session, and the rdiff-backup
destination directory may be in-between states.  In this situation we
need to bring back the directory as it was after the last successful
backup.  The basic strategy is to restore all the attributes from the
metadata file (which we assume is intact) and delete the extra
increments.  For regular files we examine the mirror file and use the
increment file to get the old data if the mirror file is out of date.

Currently this does not recover hard links.  This may make the
regressed directory take up more disk space, but hard links can still
be recovered.

iÿÿÿÿ(   t
   generatorsNt   RegressExceptionc           B   s   e  Z d  Z RS(   s*   Raised on any exception in regress process(   t   __name__t
   __module__t   __doc__(    (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   1   s   c         C   s  t  i i d ƒ } |  i d j o | i d j p t ‚ |  i ƒ  o | i ƒ  p t ‚ |  i | i j o t  i j n p t ‚ t ƒ  \ } } t	 ƒ  t
 | ƒ t i t g  ƒ } x' t |  | ƒ D] } | | i | ƒ qÊ W| i ƒ  | o t i ƒ  | i ƒ  n d S(   s:  Bring mirror and inc directory back to regress_to_time

	Also affects the rdiff-backup-data directory, so Globals.rbdir
	should be set.  Regress should only work one step at a time
	(i.e. don't "regress" through two separate backup sets.  This
	function should be run locally to the rdiff-backup-data directory.

	t
   incrementsN(    (    (   t   Globalst   rbdirt   append_patht   indext   AssertionErrort   isdirt   connt   local_connectiont   set_regress_timet   set_restore_timest   regress_rbdirt   rorpitert   IterTreeReducert   RegressITRBt   iterate_meta_rfst   Finisht   Ct   synct   delete(   t	   mirror_rpt	   inc_rpatht   managert   former_current_mirror_rpt   ITRt   rf(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   Regress6   s    	'!.
  

c          C   s   t  i ƒ  }  |  i d ƒ } t | ƒ d j p t d t | ƒ ‚ | d } | d i ƒ  a | i ƒ  a t i	 d t
 i t ƒ d ƒ |  | f S(   s¥   Set global regress_time to previous sucessful backup

	If there are two current_mirror increments, then the last one
	corresponds to a backup session that failed.

	t   current_mirrori   s)   Found %s current_mirror flags, expected 2i    i   s   Regressing to i   (   t   metadatat
   SetManagert   sorted_prefix_inclistt   lenR
   t
   getinctimet   regress_timet   unsuccessful_backup_timet   logt   Logt   Timet   timetopretty(   R   t   curmir_incst   mirror_rp_to_delete(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   M   s    
c           C   s   t  t i _ t t i _ d S(   s´   Set _rest_time and _mirror_time in the restore module

	_rest_time (restore time) corresponds to the last successful
	backup time.  _mirror_time is the unsuccessful backup time.

	N(   R'   t   restoret   MirrorStructt   _mirror_timeR&   t
   _rest_time(    (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   _   s    c         C   s9  d
 \ } } xl |  i  t D]] } | i ƒ  d j oD | i ƒ  d j o
 d } qw | i ƒ  d j p
 t | ‚ d } q q W| o | o t |  ƒ n xM |  i  t D]> } | i ƒ  d j o% t i d | i	 d ƒ | i
 ƒ  q¦ q¦ WxJ |  i  t D]; } | i ƒ  d j o" | i ƒ  d j o | i
 ƒ  Pqö qö Wd	 S(   s¡  Delete the increments in the rdiff-backup-data directory

	Returns the former current mirror rp so we can delete it later.
	All of the other rp's should be deleted before the actual regress,
	to clear up disk space the rest of the procedure may need.

	Also, in case the previous session failed while diffing the
	metadata file, either recreate the mirror_metadata snapshot, or
	delete the extra regress_time diff.

	i    t   mirror_metadatat   snapshoti   t   diffR    s   Deleting old diff at i   N(   i    i    (   t	   timerpmapR&   t   getincbase_strt
   getinctypeR
   t   recreate_metaR'   R(   R)   t   pathR   (   t   meta_managert   has_meta_difft   has_meta_snapt   old_rpt   new_rpt   rp(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   i   s*      
   
c            sä   t  i t i ƒ g ‰  ‡  f d †  } t i ˆ  d d d d d | ƒ} x' |  i t d ƒ D] } | i	 | ƒ qY W| i
 ƒ  t i i d t i t ƒ ƒ } | i ƒ  p
 t | ‚ t i ˆ  d | ƒ t i o t i i ƒ  n d S(   sÍ   Make regress_time mirror_metadata snapshot by patching

	We write to a tempfile first.  Otherwise, in case of a crash, it
	would seem we would have an intact snapshot and partial diff, not
	the reverse.

	c            s   |  ˆ  d <d  S(   Ni    (    (   R?   (   t   temprp(    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   callback‘   s    i    t   wt
   check_pathRA   s   mirror_metadata.%s.snapshot.gzN(   t   TempFilet
   new_in_dirR   R   R!   t   MetadataFilet   get_meta_at_timeR&   t   Nonet   write_objectt   closet   appendR*   t   timetostringt   lstatR
   t   rpatht   renamet   fsync_directoriest   fsync(   R:   RA   t   writert   rorpt   finalrp(    (   R@   s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR8   ˆ   s    " 

 c            s4   t  |  | t i | ƒ ƒ } ‡  f d †  ‰  ˆ  | ƒ S(   s¹   Iterate all RegressFile objects in mirror/inc directory

	Also changes permissions of unreadable files.  We don't have to
	change them back later because regress will do that for us.

	c         3   sé   |  i  } t i d j op | i ƒ  o) | i ƒ  o | i d | i ƒ  Bƒ q‰ | i ƒ  o) | i ƒ  o | i d | i ƒ  Bƒ q‰ n |  V|  i  i ƒ  p |  i	 i ƒ  o7 x4 |  i
 ƒ  D]" } x ˆ  | ƒ D] } | VqÎ Wq» Wn d  S(   Ni    i   iÀ  (   R   R   t   process_uidt   isregt   readablet   chmodt   getpermsR   t   hasfullpermst   inc_rpt   yield_sub_rfs(   R   R   t   sub_rft
   sub_sub_rf(   t   helper(    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR_   ¥   s    	   (   t   RegressFileR.   t   get_inclist(   R   R[   t   root_rf(    (   R_   s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   iterate_raw_rfs   s    c          C   sR   t  i ƒ  t  i i t ƒ }  |  o |  Sn t i i d t i	 t ƒ t f ƒ d S(   s6   Iterate rorps from metadata file, if any are availables2   No metadata for time %s (%s) found,
cannot regressN(
   R!   R"   t
   ManagerObjt	   GetAtTimeR&   R(   R)   t
   FatalErrorR*   R+   (   t   metadata_iter(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   yield_metadata³   s    
 c         c   s‘   t  |  | ƒ } t i | t ƒ  ƒ } xf | D]^ \ } } t i | | |  ƒ } | p$ t i d | i ƒ  f d ƒ q+ n | i	 | ƒ | Vq+ Wd S(   sØ   Yield RegressFile objects with extra metadata information added

	Each RegressFile will have an extra object variable .metadata_rorp
	which will contain the metadata attributes of the mirror file at
	regress_time.

	sK   Warning, metadata file has entry for %s,
but there are no associated files.i   N(
   Rc   R   t   Collate2ItersRh   t   longnamet   update_regressfileR(   R)   t   get_indexpatht   set_metadata_rorp(   R   R[   t   raw_rfst   collatedt   raw_rft   metadata_rorp(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   »   s     	R`   c           B   s2   e  Z d  Z d „  Z d „  Z d „  Z d „  Z RS(   sÍ   Like RestoreFile but with metadata

	Hold mirror_rp and related incs, but also put metadata info for
	the mirror file at regress time in self.metadata_rorp.
	self.metadata_rorp is not set in this class.

	c         C   s'   t  i i |  | | | ƒ |  i ƒ  d  S(   N(   R.   t   RestoreFilet   __init__t   set_regress_inc(   t   selfR   R[   t   inc_list(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyRs   Ø   s    c         C   s-   | o | |  _  n t i |  i ƒ |  _  d S(   s4   Set self.metadata_rorp, creating empty if given NoneN(   Rq   RN   t   RORPathR	   (   Ru   Rq   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyRm   Ü   s     c         C   s1   |  i  o |  i  i ƒ  p |  i o |  i i ƒ  S(   s4   Return true if regress needs before/after processing(   Rq   R   R   (   Ru   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   á   s    c         C   sN   |  i  ƒ  } t | ƒ d j p
 t d ‚ | o | d |  _ n
 d |  _ d S(   s9   Set self.regress_inc to increment to be removed (or None)i   s   Too many recent incrementsi    N(   t   get_newer_incsR$   R
   t   regress_incRH   (   Ru   t
   newer_incs(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyRt   æ   s
     (   R   R   R   Rs   Rm   R   Rt   (    (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR`   Ð   s
   			R   c           B   sD   e  Z d  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z RS(   sI  Turn back state of dest directory (use with IterTreeReducer)

	The arguments to the ITR will be RegressFiles.  There are two main
	assumptions this procedure makes (besides those mentioned above):

	1.  The mirror_rp and the metadata_rorp equal_loose correctly iff
	    they contain the same data.  If this is the case, then the inc
	    file is unnecessary and we can delete it.

	2.  If the don't match, then applying the inc file will
	    successfully get us back to the previous state.

	Since the metadata file is required, the two above really only
	matter for regular files.

	c         C   s   d |  _ d S(   s&   Just initialize some variables to NoneN(   RH   R   (   Ru   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyRs   ÿ   s    c         C   s   | i  i ƒ  o | i i ƒ  S(   s&   True if none of the rps is a directory(   R   R   Rq   (   Ru   R	   R   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   can_fast_process  s    c         C   sþ   | i  i | i ƒ p¯ t i d | i  i ƒ  d ƒ | i  i ƒ  o |  i | ƒ qÅ | i i ƒ  o | i i	 ƒ  n | i  i
 ƒ  o& t i d t i | i  | i f ƒ qÅ t i | i  | i ƒ n | i o+ t i d | i i d ƒ | i i	 ƒ  n d S(   s#   Process when nothing is a directorys   Regressing file %si   s   Deleting increment N(   Rq   t   equal_looseR   R(   R)   Rl   RV   t   restore_orig_regfileRM   R   t	   isspecialt   robustt   check_common_errorRH   RN   t   copy_with_attribsRy   R9   (   Ru   R	   R   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   fast_process  s    	  
c         C   sò   | i  i ƒ  p t ‚ | i i ƒ  oY t i | i ƒ } | i | i ƒ  ƒ | i ƒ  t	 i
 | i  | ƒ t	 i | | i ƒ nN | i i ƒ  o | i i ƒ  n | i i | i ƒ  ƒ t	 i
 | i  | i ƒ t i o | i i ƒ  i ƒ  n d S(   s´   Restore original regular file

		This is the trickiest case for avoiding information loss,
		because we don't want to delete the increment before the
		mirror is fully written.

		N(   Rq   RV   R
   R   RD   t   newt   write_from_fileobjt   get_restore_fpt   fsync_with_dirRN   t   copy_attribsRO   RM   R   R   RP   t   get_parent_rpRQ   (   Ru   R   t   tf(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR}     s    
 
c         C   s‡   | i  i ƒ  oj | i i ƒ  p2 | i i ƒ  o | i i ƒ  n | i i ƒ  n | i i ƒ  p | i i d ƒ qz n | |  _ d S(   s   Start processing directoryiÀ  N(	   Rq   R   R   RM   R   t   mkdirRZ   RX   R   (   Ru   R	   R   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   start_process-  s      c         C   ss  |  i  } | i i ƒ  o¬ | i i ƒ  o[ | i i ƒ  | i i | i ƒ p4 t i d | i i d ƒ t	 i
 | i | i ƒ qÁ q:| i i ƒ  t i d | i i d ƒ t	 i | i | i ƒ nv | i i ƒ  p t ‚ t i d | i i d ƒ | i i ƒ  o |  i | ƒ n$ | i i ƒ  t	 i | i | i ƒ | i o+ t i d | i i d ƒ | i i ƒ  n d S(   s   Finish processing a directorys   Regressing attributes of i   s   Regressing file s   Replacing directory s   Deleting increment N(   R   Rq   R   R   t   setdataR|   R(   R)   R9   RN   R‡   R   R   R
   RV   R}   Ry   (   Ru   R   (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   end_process7  s&    	 
(	   R   R   R   Rs   R{   R‚   R}   R‹   R   (    (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyR   î   s   					
c            s¤   t  i d t  i t  i Bƒ ‰  ‡  f d †  } d „  } xi |  D]a } t i | i j p t ‚ | | ƒ } | d j	 o( | | ƒ o t	 i
 i d | f ƒ q; q; Wd S(   sB   Check PIDs in curmir markers to make sure rdiff-backup not runnings   ^PID\s*([0-9]+)c            s;   ˆ  i  |  i ƒ  ƒ } | p d Sn t | i d ƒ ƒ Sd S(   s6   Return process ID from a current mirror marker, if anyi   N(   t   searcht   get_dataRH   t   intt   group(   t	   curmir_rpt   match(   t   pid_re(    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   extract_pidS  s     c      
   S   s:  y t  i |  d ƒ Wnt j
 o< } | d t i j o d Sq6t i d |  f d ƒ nÙ t j
 oÌ t  i d j p t	 ‚ d d k
 } d d k } d d k } y | i | i d |  ƒ } WnK | i j
 o< } | d d j o d Sqd } t i | |  d ƒ n X| o | i | ƒ d Sn d Sn Xd S(	   s8   True if we know if process with pid is currently runningi    s0   Warning: unable to check if PID %d still runningi   t   ntiÿÿÿÿNiW   i   (   t   ost   killt   OSErrort   errnot   ESRCHR(   R)   t   AttributeErrort   nameR
   t   win32apit   win32cont
   pywintypest   OpenProcesst   PROCESS_ALL_ACCESSt   errort   CloseHandle(   t   pidt   excRž   RŸ   R    t   processR£   t   msg(    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt   pid_runningY  s,      $ 	s  It appears that a previous rdiff-backup session with process
id %d is still running.  If two different rdiff-backup processes write
the same repository simultaneously, data corruption will probably
result.  To proceed with regress anyway, rerun rdiff-backup with the
--force option.N(   t   ret   compilet   It   MR   R   R   R
   RH   R(   R)   Rf   (   R,   R•   R©   R’   R¥   (    (   R”   s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pyt
   check_pidsP  s    	 	(%   R   t
   __future__R    t   signalRš   Rª   R—   R   R.   R(   R   RD   R!   RN   R   R*   t   backupR   Rj   RH   R&   R'   t	   ExceptionR   R   R   R   R   R8   Rc   Rh   R   Rr   R`   t	   ITRBranchR   R®   (    (    (    s9   /var/lib/python-support/python2.5/rdiff_backup/regress.pys   <module>"   s"   0			
					b