o wa;r@s\dZddlmZddlmZeddlmZddlmZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlmZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlTdZdaGdddeZGdddeZ GdddeZ!Gddde!Z"Gddde"Z#Gddde$Z%dS)zWrapper class around a file like "/usr/bin/env" This class makes certain file operations more convenient and associates stat information with filenames )print_function)standard_library)str)objectN) cached_ops)config)dup_time) file_naming)gpg)librsync)log)tarfile)util)*ic@seZdZdZdZdS) StatResultz3Used to emulate the output of os.stat() and relatedrN)__name__ __module__ __qualname____doc__st_moderr0/usr/lib/python3/dist-packages/duplicity/path.pyr;src@s eZdZdS) PathExceptionN)rrrrrrrrBsrc@seZdZdZd>ddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd?d2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdtt | dt |rGd|_n t |rPd |_ntd t||_|jd vrzt|jjt|jjf|_WdSttd t | |jjfd |_YdSdS)z4Set the value of self.type, self.mode from self.statNregdirsymfifozis a socket, unsupported by tarsockchrblkz Unknown type)r*r+z7Warning: %s invalid devnums (0x%X), treating as (0, 0).rr)rr rS_ISREGS_ISDIRS_ISLNKS_ISFIFOS_ISSOCKrrfsdecodeget_relative_pathS_ISCHRS_ISBLKS_IMODEr!osmajorst_rdevminorr"r Warn_)r#rrrr set_from_statTs@              zROPath.set_from_statcCsd\|_|_dS)z*Black out self - set type and stat to NonerN)r rr#rrrblankwsz ROPath.blankcCs|jS)z!True if corresponding file existsr r>rrrexists{sz ROPath.existscC |jdkS)z(True if self corresponds to regular filer%r@r>rrrisreg z ROPath.isregcCrB)zTrue if self is dirr&r@r>rrrisdirrDz ROPath.isdircCrB)zTrue if self is symr'r@r>rrrissymrDz ROPath.issymcCrB)zTrue if self is fifor(r@r>rrrisfiforDz ROPath.isfifocCrB)zTrue is self is socketr)r@r>rrrissockrDz ROPath.issockcCs|jdkp |jdkS)zTrue is self is a device filer*r+r@r>rrrisdevz ROPath.isdevcC|jjS)z$Return device number path resides on)rst_devr>rrr getdevloczROPath.getdevloccCrK)z'Return length in bytes from stat object)rst_sizer>rrrgetsizerNzROPath.getsizecCs t|jjS)z"Return mod time of path in seconds)intrst_mtimer>rrrgetmtime zROPath.getmtimecCs|jr d|jSdS)z(Return relative path, created from index/.)rjoinr>rrrr3s zROPath.get_relative_pathcCs|j}d|j|j|jfS)z(Return permissions mode, owner and groupz%s:%s %o)rst_uidst_gidr!)r#s1rrrgetpermsszROPath.getpermscCs6|dkr |jr |jrJd||j|jfd|_|jS)z#Return fileobj associated with selfrbz%s %s %srrrr#r!rrropens z ROPath.opencCs"|d}|}|rJ|S)z/Return contents of associated fileobj in stringr\)r_readclose)r#finbufrrrget_datas  zROPath.get_datacCs|jrJ||_d|_dS)z"Set file object returned by open()Nr])r#rrrr setfileobjs  zROPath.setfileobjcCs|j}|tjks |tjkrd|_n]|tjkrtd|tjkr5d|_|j|_t |jdj r4t |j|_n9|tj krEd|_|j|jf|_n)|tjkrUd|_|j|jf|_n|tjkr^d|_n|tjkrgd|_ntd |f|j|_t|_ ztjr}tt|jd |j_Wnty|j|j_Ynwztjrtt|j d |j_!Wnty|j"|j_!Ynwt#|j$|j_%|jj%d krt&'t(d |j)d |j_%|j*|j_+d S)z5Set data from tarinfo object (part of tarfile module)r%zHard links not supported yetr'r*r+r&r(zUnknown tarinfo type %sr.Warning: %s has negative mtime, treating as 0.N),r r REGTYPEAREGTYPELNKTYPErSYMTYPElinknamesymtext isinstance __class__rfsencodeCHRTYPEdevmajordevminorr"BLKTYPEDIRTYPEFIFOTYPEr!rrr numeric_ownerKeyErrorrgetpwnamunamerXuidgetgrnamgnamerYgidrQmtimerRr r;r<uc_namesizerO)r#tarinfor rrrinit_from_tarinfos\          zROPath.init_from_tarinfocCsVt|j|j}|j|j|_|_|r|j|_n|r!|j|_| r)|j|_|S)zReturn ropath copy of self) rrrr r!rFrnrIr"rA)r# new_ropathrrr get_ropaths zROPath.get_ropathcCs t}|jrtd|j|_nd|_|r |jd7_d|_|j r| r4tj |_ |j j |_nO|r=tj|_ nF|rFtj|_ n=|r`tj|_ |j|_t|jtr_t|j|_n#|rz|j dkrntj|_ ntj|_ |j\|_|_n tdt|j |j|_|j j |j j!|_"|_#|j j$dkrt%&t'dt|(d|_)nt*|j j$|_)z t+,|j"d|_-Wn t.yd|_-Ynwz t+/|j#d|_0Wn t.yd|_0Ynw|j tjtjfvrt1t2d rt1t2d r|j\|_|_|Sd \|_|_|S) zGenerate a tarfile.TarInfo object based on self Doesn't set size based on stat, because we may want to replace data wiht other stream. Size should be set separately by calling function. rU./rr*zUnrecognized type rhrfr8r:r,)3r TarInforrr2rWnamerErr rCrirrOrvrGrwrFrlrnrmrobytesrIrrrur"rsrtrrr!rXrYr|rrRr r;r<r3rrQrgetpwuidr{rygetgrgidr~hasattrr7)r#tirrr get_tarinfosf              zROPath.get_tarinfocCs|js|jsdS|js|js|js|jrdS|j|jkrdS|s*|s*|rK||s1dSt|jjt|jjkr?dS|jjdkoJ|jjdkS|rU|j |j kS| rd||oc|j |j kSJ)z6Used to compare two ROPaths. Doesn't look at fileobjsrr) r rrCrErG perms_equalrQrRrFrnrIr"r#otherrrr__eq__Ks"    z ROPath.__eq__cCs || SN)rrrrr__ne__d z ROPath.__ne__rcs fdd}|dur dSjs|jsdSjs"|jr"|tddS|js0jr0|tddSj|jkrD|td |jjfdSsPsPr|se|td |fdStjj t|jj krjj dks}|jj dkr|td t t|jj t tjj fdSr |rdS|td dSdS r҈j|jksˆjttj|jkrdS|td |jjfdSr|s|td |fdSj|jkr|td|jjfdSdSJ)a'Compare ROPaths like __eq__, but log reason if different This is placed in a separate function from __eq__ because __eq__ should be very time sensitive, and logging statements would slow it down. Used when verifying. Only run if include_data is true. cs,tdd|}t|tdS)NzDifference found: )r<r Noticerr2r3) log_stringlog_strr>rrlog_diffqsz(ROPath.compare_verbose..log_diffFTrz New file %srzFile %s is missingz!File %%s has type %s, expected %sz(File %%s has permissions %s, expected %sz"File %%s has mtime %s, expected %szData for file %s is differentz%Symlink %%s points to %s, expected %sz+Device file %%s has numbers %s, expected %s)r rr<rCrErGrr[rQrRr timetopretty compare_datarFrnrrqr7seprIr")r#r include_datarrr>rcompare_verbosegsp           $    zROPath.compare_verbosecsZ|d|dfdd} t}t}||kr%|dS|s,|dSq)z8Compare data from two regular files, return true if samer\csrJr JdSr)rarf1f2rrras z"ROPath.compare_data..closerr)r_r`_copy_blocksize)r#rrabuf1buf2rrrrs    zROPath.compare_datacCs2|j|j}}|j|jko|j|jko|j|jkS)z:True if self and other have same permissions and ownership)rr!rYrX)r#rrZs2rrrrs    zROPath.perms_equalcCs|r ||dn^|rt|jnS|r9t|j |jt j s3t |j|j j|j j|dS|rDt|jn'|rSttj|jn|rk|jdkr_d}nd}|j|g|jR||dS)z:Copy self to other. Also copies data. Other must be Pathr\Nr*cb)rC writefileobjr_rEr7mkdirrrFsymlinkrnrdo_not_restore_ownershiplchownrrXrYsetdatarGmkfiforHsocketAF_UNIXbindrIr makedevr" copy_attribs)r#rdevtyperrrcopys( z ROPath.copycsttr3s-jrtjstfddtfddtfdddStt s:Jt }jj jj |_ |_ t jj|_|_j_dS)z'Only copy attributes from self to othercstjjjjjSr)r7chownrrrXrYrrr#rrsz%ROPath.copy_attribs..cstjjSr)r7chmodrr!rrrrrscstjtjjfSr)r7utimertimerrRrrrrrsN)roPathrFrrrrmaybe_ignore_errorsrrrrXrYrQrRr!)r#rrrrrrs    zROPath.copy_attribscCsdt|j|jfS)Return string representationz(%s %s))ruindexrr r>rrr__str__szROPath.__str__r)r)!rrrrr$r=r?rArCrErFrGrHrIrMrPrSr3r[r_rdrerrrrrrrrrrrrrrrrFs> #7 E D rc@seZdZdZedZddZdd0d1Zd2d3Zd>d4d5Zd6d7Zd8d9Z d:d;Z!d/S)?rz Path class - wrapper around ordinary local files Besides caching stat() results, this class organizes various file code. z [\\\"\$`]cCstjr|s|Stjtjj|}g}|r/|tjvr/tj|\}}|d||r/|tjvs|r?tj|t tj |S|S)Nr) rrenamer7pathnormcaserWsplitinsertrrqr)r#rrtailextrarrr rename_indexs  zPath.rename_indexrcCsdd\|_|_t|trt|}||_|||_t j j |g|jR|_ t |j |_|dS)zPath initializerrN)rrrorrrqbaserrr7rrWrr2rr)r#rrrrrr$ s     z Path.__init__c Csztjr t|j|_nt|j|_Wn(ty<}ztj|j}|dvr0d\|_|_ d|_ nWYd}~dSd}~ww| | rNt |j|_dSdS)zRefresh stat cache)ENOENTENOTDIRELOOPENOTCONNENODEVrN)r copy_linksr7rrlstatOSErrorerrno errorcoder r!r=rFreadlinkrn)r#e err_stringrrrrs$  z Path.setdatacCs,t|djr t|}||j|j|fS)z'Return new Path with ext added to indexrf)rorprrqrr)r#extrrrappend4s  z Path.appendcCs||j|S)z Return new Path with index index)rpr)r#rrrr new_index:szPath.new_indexcCs t|jS)z#Return list generated by os.listdir)r7listdirrr>rrrr>rTz Path.listdircCs|o| S)z/Return true if path is a directory and is empty)rErr>rrr isemptydirBszPath.isemptydircCs*t|djr t|}|o||vS)z5Return true if path is a directory and contains childrf)rorprrqrEr)r#childrrrcontainsFs  z Path.containsr\cCs*|jrJ|jr |j}|St|j|}|S)z Return fileobj associated with self Usually this is just the file data on disk, but can be replaced with arbitrary data using the setfileobj method. )rrr_r)r#r!resultrrrr_Ns  z Path.opencCsDd|j|t|t|g}ttjd|dkrtd||dS)z8Make a device file with specified type, major/minor numsmknodrzError running %sN)rrr7spawnvpP_WAITrr)r#r r8r:cmdlistrrrr\s  z Path.makedevcCsZttd|jzt|jWnty&tj s$t d|jdYnw| dS)z#Make directory(s) at specified pathzMaking directory %szError creating directory %sN) r Infor<rr7makedirsrrrforcerrr>rrrrcs  z Path.mkdircCsJttd|j|rttj|j nttj |j | dS)zRemove this filez Deleting %sN) r rr<rrErignore_missingr7rmdirrunlinkrr>rrrdeletems  z Path.deletecCs*ttd|j|d}|dS)z#Open the file, write 0 bytes, closez Touching %swbN)r rr<rr_ra)r#fprrrtouchvs  z Path.touchcCs^ddlm}ttd|jttg}|| D]}||j |q| | dS)z2Remove self by recursively deleting files under itr selectionzDeleting tree %sN) duplicityrr rr<rIterTreeReducer PathDeleterSelectset_iterrFinishr)r#ritrrrrrdeltree|s   z Path.deltreecCsZ|jrt|j|jddS|jd}t|dkr"|ds"tdStd|ddS)z Return directory that self is inNrUrgr)rrrrlenrWr# componentsrrrget_parent_dirs  zPath.get_parent_dircCsL|d} |t}|sn||q|s|r td|dS)z4Copy file object fin to self. Close both when done.rrzError closing file objectN)r_r`rwriterarr)r#rbfoutrcrrrrs    zPath.writefileobjcCs$t|j|j||dS)z(Rename file at current path to new_path.N)shutilmoverrr#new_pathrrrrs z Path.renamecCs|||dS)z;Like rename but destination may be on different file systemN)rrrrrrrs  z Path.movecCst|j||dS)zChange permissions of the pathN)r7rrrr^rrrrs z Path.chmodcCsv|r|s J|}|d}|d}t||}|||r)J|r/J||||dS)z2Patch self with diff and then copy attributes overr\N) rCget_temp_in_same_dirr_r PatchedFilerrarr)r# diff_ropath temp_pathfbasefdiff patch_fileobjrrrpatch_with_attribss       zPath.patch_with_attribscCsF|} |dtt}|js|Std7atdks"Jd|jq)z7Return temp non existent path in same directory as selfrzduplicity_temp.i'z(Warning too many temp files created for )rrr_tmp_path_counterr r)r# parent_dirr rrrrs zPath.get_temp_in_same_dirNcCs6ddlm}||}||}t|||S)z7Compare self to other Path, descending down directoriesrr)rrrrIterequal)r#rverboserselfselotherselrrrcompare_recursives zPath.compare_recursivecCsd|j|j|jfS)rz (%s %s %s))rrr r>rrr__repr__rJz Path.__repr__cCs |s|j}d|jdd|S)z Return quoted version of s (defaults to self.name) The output is meant to be interpreted with shells, so can be used with os.system. z"%s"cSsd|dS)N\r)group)mrrrrszPath.quote..)rregex_chars_to_quotesub)r#srrrquotesz Path.quotecCs|d|dkrdksJJd}d}|t|dkrC||dkr1|||d7}|d7}n |||7}|d7}|t|dks|S)z?Return unquoted version of string s, as quoted by above quote()rr"rfrrrg)r)r#rrirrrunquotes$   z Path.unquotecCs$|jd}|r |dsJ|dS)z!Return filename of last componentrUr)rrrrrr get_filenames zPath.get_filenamecCs>ddd|jdD}|jddkrd|S|r|SdS)z Return string of canonical version of path Remove ".", and trailing slashes where possible. Note that it's harder to remove "..", as "foo/bar/.." is not necessarily "foo", so we can't use path.normpath() rUcSsg|] }|r|dkr|qS)rVr).0xrrr sz&Path.get_canonical..rrrV)rWrrr)r#newpathrrr get_canonicals zPath.get_canonical)r)r\r)"rrrrrecompilerrr$rrrrrrr_rrrrrrrrrrr rrrrr r!r&rrrrrs<            rc@s$eZdZdZd ddZd ddZdS) DupPathz Represent duplicity data files Based on the file name, files that are compressed or encrypted will have different open() methods. rNcCsL|r||_nt|dksJt|d|_|jsJdt|||dS)z DupPath initializer The actual filename (no directory) must be the single element of the index, unless parseresults is given. rrz%must be a recognizable duplicity fileN)prrr parserr$)r#rr parseresultsrrrr$ s zDupPath.__init__r\cCs|js|jrJ|jjr|jjrJ|r|jjsJ|jjr%t|j|S|jjrF|s.tj }|dkr9t d||S|dkrDt d||SdS| |S)z Return fileobj with appropriate encryption/compression If encryption is specified but no gpg_profile, use config.default_profile. r\FrTN) rrr* encrypted compressedgzipGzipFilerr gpg_profiler GPGFiler_)r#r!r1rrr filtered_opens  zDupPath.filtered_open)rN)r\N)rrrrr$r3rrrrr)s r)c@s0eZdZdZddZddZddZdd Zd S) rz+Delete a directory. Called by Path.deltreecCs ||_dSr)rr#rrrrr start_process5 zPathDeleter.start_processcCs|jdSr)rrr>rrr end_process8szPathDeleter.end_processcCs | Sr)rEr4rrrcan_fast_process;r6zPathDeleter.can_fast_processcCs |dSr)rr4rrr fast_process>rzPathDeleter.fast_processN)rrrrr5r7r8r9rrrrr3s  r)&r __future__rfuturerinstall_aliasesbuiltinsrrrr/r7r'rrrrrrrrr r r r r rduplicity.lazyrrr Exceptionrrrr) ITRBranchrrrrrsJ             01