
    yf4                         S SK r S SKrS SKrS SKrSSKJrJr  SSKJr  SSK	J
r
  SSK	JrJrJr  SSKJr  SSKJr  SS	KJrJr  \" \5      rS
r " S S\5      r " S S\5      r " S S\5      r " S S\5      rg)    N   )
KeyfileKeyKeyfileNotFoundError)REPOSITORY_README)ProgressIndicatorPercent)get_base_dirget_keys_dirget_cache_dir)Lock)create_logger)
RepositoryMAGICs   ATTICSEGc                      ^  \ rS rSrU 4S jrSS jrS r\SS j5       r\SS j5       r	S r
\S 5       rS	 rS
 rSrU =r$ )AtticRepositoryUpgrader   c                 :   > SUS'   SUS'   [         TU ]  " U0 UD6  g )NFlockcheck_segment_magic)super__init__)selfargskw	__class__s      //usr/lib/python3/dist-packages/borg/upgrader.pyr    AtticRepositoryUpgrader.__init__   s)    6
$) !$%"%    c                    U    SnU(       dy  U R                    S[        R                  R                  5       S 3n[        R	                  SU5        U(       d.  [
        R                  " U R                   U[        R                  S9  [        R	                  S5        [        [        R                   R                  U R                   S5      SS	S
9R                  5       U l        U R                  R                  5        VVs/ s H  u  pVUPM	     nnn U R                  5       nU R!                  X5        SSS5        [        [        R                   R                  U R                   S5      SS9R                  5       U l         U R'                  U5        U R)                  XS9  U R+                  WXUS9  U R-                  5         U R                  R/                  5         SU l        W$ s  snnf ! ["         a    [        R%                  S5         Nf = f! , (       d  f       N= f! U R                  R/                  5         SU l        f = f)ab  convert an attic repository to a borg repository

those are the files that need to be upgraded here, from most
important to least important: segments, key files, and various
caches, the latter being optional, as they will be rebuilt if
missing.

we nevertheless do the order in reverse, as we prefer to do
the fast stuff first, to improve interactivity.
Nz.before-upgrade-z%Y-%m-%d-%H:%M:%Szmaking a hardlink copy in %s)copy_functionz1opening attic repository with borg and convertingr   Tg      ?)	exclusivetimeout no key file found for repository)r    )dryruninplace)r#   r$   progress)pathdatetimenowloggerinfoshutilcopytreeoslinkr   joinacquirer   iosegment_iteratorfind_attic_keyfileconvert_keyfilesr   warningconvert_cacheconvert_repo_indexconvert_segmentsborg_readmerelease)	r   r#   r$   r%   backupifilenamesegmentskeyfiles	            r   upgradeAtticRepositoryUpgrader.upgrade   s    F II;&6x7H7H7L7L7NO`6ab:FCOODIIvRWWMKKKLRWW\\$))V<VYZbbdDI48GG4L4L4NO4N[Q4NHO7113 %%g6! $ dii8DIQQS		v&##6#C!!(6U]!^IIDI# P ( CABC T2 IIDIsO   C;H>G#HG) H?AH #H)HH
HH
H#Ic                     [         R                  R                  U R                  S5      n[         R                  " U5        [	        US5       nUR                  [        5        S S S 5        g ! , (       d  f       g = f)NREADMEw)r-   r&   r/   removeopenwriter   )r   readmefds      r   r9   #AtticRepositoryUpgrader.borg_readmeA   sK    dii2
		&&#"HH&' s   A,,
A:c                 t   [         R                  S[        U 5      -  5        [        U 5      n[        USSS9n[	        U 5       HZ  u  pgU(       a  UR                  U5        U(       a  [        R                  " S5        M<  [        R                  U[        [        US9  M\     U(       a  UR                  5         gg)zconvert repository segments from attic to borg

replacement pattern is `s/ATTICSEG/BORG_SEG/` in files in
`$ATTIC_REPO/data/**`.

luckily the magic string length didn't change so we can just
replace the 8 first bytes of all regular files in there.zconverting %d segments...zConverting segments %3.0f%%zupgrade.convert_segments)totalmsgmsgidgMbP?r$   N)r)   r*   lenr   	enumerateshowtimesleepr   header_replaceATTIC_MAGICr   finish)r>   r#   r$   r%   segment_countpir<   r=   s           r   r8   (AtticRepositoryUpgrader.convert_segmentsG   s     	/#h-?@H%M?\d~$X.KA


5!'66xe]d6e / IIK r   c                    [        U S5       nUR                  S5        UR                  [        U5      5      U:X  a  U(       a#  UR                  S5        UR	                  U5        Ow[
        R                  " X S-   5        [        U S5       nUR	                  U5        UR	                  UR                  5       5        S S S 5        [
        R                  " U S-   5        S S S 5        g ! , (       d  f       N0= f! , (       d  f       g = f)Nzr+br   z.tmpwb)rF   seekreadrP   rG   r-   renameunlink)r=   	old_magic	new_magicr$   segmentnew_segments         r   rU   &AtticRepositoryUpgrader.header_replace]   s    (E"gLLO||C	N+y8LLOMM),
 IIh6(9:h-#)))4#))',,.9 .
 IIh/0# #" .- #"s$   A?C81C'=!C8'
C5	1C88
Dc                 ,    [         R                  U 5      $ )a  find the attic keyfiles

the keyfiles are loaded by `KeyfileKey.find_key_file()`. that
finds the keys with the right identifier for the repo.

this is expected to look into $HOME/.attic/keys or
$ATTIC_KEYS_DIR for key files matching the given Borg
repository.

it is expected to raise an exception (KeyfileNotFoundError) if
no key is found. whether that exception is from Borg or Attic
is unclear.

this is split in a separate function in case we want to use
the attic code here directly, instead of our local
implementation.)AtticKeyfileKeyfind_key_filer   s    r   r3   *AtticRepositoryUpgrader.find_attic_keyfiler   s    " ,,T22r   c                 4   [         R                  SU -  5        [        U 5       nUR                  5       nSSS5        WR	                  [
        R                  [        R                  S5      n[        R                  R                  [        5       [        R                  R                  U 5      5      n [         R                  SU -  5        U(       d'  [        U S5       nUR                  U5        SSS5        gg! , (       d  f       N= f! , (       d  f       g= f)a  convert key files from attic to borg

replacement pattern is `s/ATTIC KEY/BORG_KEY/` in
`get_keys_dir()`, that is `$ATTIC_KEYS_DIR` or
`$HOME/.attic/keys`, and moved to `$BORG_KEYS_DIR` or
`$HOME/.config/borg/keys`.

no need to decrypt to convert. we need to rewrite the whole
key file because magic string length changed, but that's not a
problem because the keyfiles are small (compared to, say,
all the segments).zconverting keyfile %sNr   zwriting borg keyfile to %srD   )r)   r*   rF   r^   replacerg   FILE_IDr   r-   r&   r/   r	   basenamerG   )r?   r#   fdatas       r   r4   (AtticRepositoryUpgrader.convert_keyfiles   s     	+g56']a668D ||O33Z5G5GK'',,|~rww/?/?/HI07:;gs#q $#  ] $#s   C8D	8
D	
Dc                 6   U R                  5       nUc#  [        R                  SU R                  -  5        g[        R                  R                  U R                  SU-  5      n[        R                  SU-  5        U(       d  [        R                  USSUS9  gg)a  convert some repo files

those are all hash indexes, so we need to
`s/ATTICIDX/BORG_IDX/` in a few locations:

* the repository index (in `$ATTIC_REPO/index.%d`, where `%d`
  is the `Repository.get_index_transaction_id()`), which we
  should probably update, with a lock, see
  `Repository.open()`, which i'm not sure we should use
  because it may write data on `Repository.close()`...
Nz%no index file found for repository %szindex.%dzconverting repo index %s   ATTICIDX   BORG_IDXrO   )	get_index_transaction_idr)   r5   r&   r-   r/   r*   r   rU   )r   r#   r$   transaction_idindexs        r   r7   *AtticRepositoryUpgrader.convert_repo_index   s}     668!NNBTYYNOGGLLJ,GHEKK2U:;'66uk;`g6h r   c                   ^^^ [         R                  R                  S[         R                  R	                  [        5       SS5      5      m[         R                  R	                  TU R                  5      m[         R                  R	                  [        5       U R                  5      mUUU4S jn[         R                  R                  T5      (       a  [         R                  R                  T5      (       d  [         R                  " T5        S H  nU" U5        M     S HC  nU" U5      n[        R                  SU-  5        T(       a  M,  [        R                  USS	5        ME     g
g
)a  convert caches from attic to borg

those are all hash indexes, so we need to
`s/ATTICIDX/BORG_IDX/` in a few locations:

* the `files` and `chunks` cache (in `$ATTIC_CACHE_DIR` or
  `$HOME/.cache/attic/<repoid>/`), which we could just drop,
  but if we'd want to convert, we could open it with the
  `Cache.open()`, edit in place and then `Cache.close()` to
  make sure we have locking right
ATTIC_CACHE_DIRz.cacheatticc                   > [         R                  R                  TU 5      n[         R                  R                  U5      (       a  [         R                  R                  TU 5      n[         R                  R                  U5      (       a  [        R                  SU5        U$ [        R                  SU SU 35        T(       d  [        R                  " X5        U$ [        R                  SU  SU 35        g)a  copy the given attic cache path into the borg directory

does nothing if dryrun is True. also expects
attic_cache_dir and borg_cache_dir to be set in the parent
scope, to the directories path including the repository
identifier.

:params path: the basename of the cache file to copy
(example: "files" or "chunks") as a string

:returns: the borg file that was created or None if no
Attic cache file was found.

z<borg cache file already exists in %s, not copying from Atticzcopying attic cache file from z to zno z cache file found in N)	r-   r&   r/   existsr)   r5   r*   r+   copyfile)r&   
attic_file	borg_fileattic_cache_dirborg_cache_dirr#   s      r   copy_cache_file>AtticRepositoryUpgrader.convert_cache.<locals>.copy_cache_file   s     ot<Jww~~j))GGLL>	77>>),,NN#aclm
 !  KK"@DQZP[ \]!
>  TF*?
|LMr   )configfiles)chunkszconverting cache %srs   rt   N)r-   environgetr&   r/   r   id_strr
   r}   makedirsr)   r*   r   rU   )r   r#   r   cacher   r   s    `  @@r   r6   %AtticRepositoryUpgrader.convert_cache   s     **..):)+ln6>*IJ '',,Dmot{{C	> 77>>/**77>>.11N+ -& - $'.1E9:v+::5+{[	 $ +r   )r   TFF)T)__name__
__module____qualname____firstlineno__r   r@   r9   staticmethodr8   rU   r3   r4   r7   r6   __static_attributes____classcell__)r   s   @r   r   r      sf    &
&P(  * 1 1(3&  ,i*?\ ?\r   r   c                   <    \ rS rSrSrSr\S 5       r\S 5       r	Sr
g)rg      z*backwards compatible Attic key file parserz	ATTIC KEYc                      [         R                  R                  S[         R                  R	                  [        5       SS5      5      $ )z,Determine where to repository keys and cacheATTIC_KEYS_DIRz.attickeysr-   r   r   r&   r/   r    r   r   r	   AtticKeyfileKey.get_keys_dir   s4     zz~~. ggll<>8VLN 	Nr   c                 V   U R                   nU" 5       n[        R                  R                  U5      (       d  [	        UR                  U5      e[        R
                  " U5       H  n[        R                  R                  X45      n[        U5       nUR                  5       R                  5       nU(       a@  UR                  U R                  5      (       a   USS UR                  :X  a  UsSSS5        s  $ SSS5        M     [	        UR                  U5      e! , (       d  f       M  = f)a?  copy of attic's `find_key_file`_

this has two small modifications:

1. it uses the above `get_keys_dir`_ instead of the global one,
   assumed to be borg's

2. it uses `repository.path`_ instead of
   `repository._location.canonical_path`_ because we can't
   assume the repository has been opened by the archiver yet

   N)r	   r-   r&   r}   r   listdirr/   rF   readlinestrip
startswithrm   r   cls
repositoryr	   keys_dirnamer=   rI   lines           r   rh   AtticKeyfileKey.find_key_file   s     ''>ww~~h''&zAAJJx(Dww||H3Hh2{{}**,DOOCKK88T"#Y*J[J[=[#   ) #:??H==	  s   AD
D(	r   N)r   r   r   r   __doc__rm   r   r	   classmethodrh   r   r   r   r   rg   rg      s4    4G N N
 > >r   rg   c                   *    \ rS rSrSS jrS rS rSrg)BorgRepositoryUpgraderi  c                     [         R                  S5        U     U R                  5       nU R                  XA5        SSS5        g! [         a    [         R                  S5         N*f = f! , (       d  f       g= f)zDconvert an old borg repository to a current borg repository
        z$converting borg 0.xx to borg currentr"   N)r)   r*   find_borg0xx_keyfilemove_keyfilesr   r5   )r   r#   r$   r%   r?   s        r   r@   BorgRepositoryUpgrader.upgrade  sf     	:;4335 ""73 T ( CABC Ts-   A)AA)A&#A)%A&&A))
A7c                 ,    [         R                  U 5      $ N)Borg0xxKeyfileKeyrh   ri   s    r   r   +BorgRepositoryUpgrader.find_borg0xx_keyfile%  s     ..t44r   c                     [         R                  R                  U5      n[         R                  R                  [	        5       U5      n [         R
                  " X5        g ! [         a     g f = fr   )r-   r&   rn   r/   r	   r_   FileExistsError)r   r?   r#   r=   new_keyfiles        r   r   $BorgRepositoryUpgrader.move_keyfiles(  sO    77##G,ggll<>8<	IIg+ 		s   	A   
A-,A-r   Nr   )r   r   r   r   r@   r   r   r   r   r   r   r   r     s    
45r   r   c                   8    \ rS rSrSr\S 5       r\S 5       rSr	g)r   i2  z.backwards compatible borg 0.xx key file parserc                      [         R                  R                  S[         R                  R	                  [        5       SS5      5      $ )NBORG_KEYS_DIRz.borgr   r   r   r   r   r	   Borg0xxKeyfileKey.get_keys_dir5  s1    zz~~o ggll<>7FKM 	Mr   c                    U R                   nU" 5       n[        R                  R                  U5      (       d  [	        UR                  U5      e[        R
                  " U5       H  n[        R                  R                  X45      n[        U5       nUR                  5       R                  5       nU(       aV  UR                  U R                  5      (       a6  U[        U R                  5      S-   S  UR                  :X  a  UsS S S 5        s  $ S S S 5        M     [	        UR                  U5      e! , (       d  f       M  = f)Nr   )r	   r-   r&   r}   r   r   r/   rF   r   r   r   rm   rP   r   r   s           r   rh   Borg0xxKeyfileKey.find_key_file:  s    ''>ww~~h''&zAAJJx(Dww||H3Hh2{{}**,DOOCKK88T#ckkBRUVBVBW=X\f\m\m=m#   ) #:??H==	  s   A0D//
D>	r   N)
r   r   r   r   r   r   r	   r   rh   r   r   r   r   r   r   2  s-    8M M > >r   r   )r'   r-   r+   rS   
crypto.keyr   r   	constantsr   helpersr   r   r	   r
   lockingr   r)   r   r   r   r   r   rV   r   rg   r   r   r   r   r   <module>r      sn     	   8 ( - > >  ! )	x	 ]\j ]\@">j ">JZ 4>
 >r   