o
    +ke_                     @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	m
Z
 d dlmZ ddlmZmZ erCd dlZdd ZndZdd Zdd	lmZ e Zdd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZmZm Z m!Z!m"Z"m#Z# ddlm$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/ dd Z0dZ1G dd dZ2G dd dZ3G dd dej4e3Z5dS )    N)defaultdict)SIGINT   )llfusehas_pyfuse3c                    s   t   fdd}|S )Nc                     s    | i |S N )argskwargsfnr   -usr/lib/python3.10/site-packages/borg/fuse.pywrapper   s   zasync_wrapper.<locals>.wrapper)	functoolswraps)r   r   r   r   r   async_wrapper   s   r   c                 C   s   | S r   r   r   r   r   r   r      s   )create_logger)blake2b_128)Archiver)Archiveget_item_uid_gid)FuseVersionsIndex)	daemonizedaemonizinghardlinkablesignal_handlerformat_file_sizeError)msgpack)Item)LRUCache)uid2user	gid2group)	is_darwin)RemoteRepositoryc                   C   s0   t rz	ttj W d S    Y dS tjddS )Nr   )workers)r   triorunr   mainr   r   r   r   	fuse_main/   s   r)      c                   @   sF   e Zd ZdZdZedZejdksJ dd Z	dd Z
dddZd	S )	ItemCachez
    This is the "meat" of the file system's metadata storage.

    This class generates inode numbers that efficiently index items in archives,
    and retrieves items from these inode numbers.
    i    z=cII	   c                 C   sJ   || _ t | _d| _d| _tjdd| _tddd d| _	d| _
d| _d S )	Nr   i@B zborg-tmp)prefix
   c                 S      d S r   r   _r   r   r   <lambda>s       z$ItemCache.__init__.<locals>.<lambda>capacityZdispose)decrypted_repository	bytearraymetawrite_offsetoffsettempfileTemporaryFilefdr    chunksindirect_itemsdirect_items)selfr6   r   r   r   __init__U   s   
zItemCache.__init__c                 C   s"  || j  }|dk rtd| j| tdkr`| j| j|\}}}|| }t| j||d  }| j|}|sHt	| j
|g\}	}|| j|< t||d  }
t }||
 tt	|dS | j| tdkrt| j|d |d  d	}| j|tj tt	tj| jd
ddS td)Nr   z3ItemCache.get() called with an invalid inode number   I    Zinternal_dict   Sr   r,   littlei   )Z	read_sizezInvalid entry type in self.meta)r:   
ValueErrorr8   ordindirect_entry_structunpack_frombytesr>   getnextr6   get_many
memoryviewr   Unpackerfeedr   int
from_bytesr=   seekioSEEK_SET)rA   inoder:   r1   Zchunk_id_relative_offsetchunk_offsetZchunk_id_offsetchunk_idchunkcsizedataunpackerZ	fd_offsetr   r   r   rM   {   s(   


zItemCache.getNFc              	   c   s$   t  }d}d}d}d}| j}	| j}
| jj}t|| j|D ]\}\}}|	d t	|
kr8|
t
| j  | _}
||
|	|	d < |	}|	d7 }	||7 }t	|}|| 	 z| }d}W n t jyh   d}Y nw || }|rut	|| n| | }|||||  7 }||7 }|rnt|d}|r||r|sd|v rd}qS|}t	|}|| |k }d}|	d t	|
kr|
t
| j  | _}
|r| jdtj}| j| d	|d
d |
|	|	d < |  jd7  _n|| | }||
|	d|	| | |  jd7  _|	| j }|	d7 }	||fV  qTq |	| _d S )Nr       rD   TFrE   partr,   rF      rG   r   rC   )r   rQ   r9   r8   rJ   	pack_intozipr6   rO   lenrL   GROW_META_BYrR   unpackZ	OutOfDatatellr   r=   rU   rV   SEEK_ENDwriteto_bytesr@   r?   r:   )rA   Zarchive_item_idsfilterconsider_part_filesr^   Zstream_offsetZchunk_beginZlast_chunk_lengthZmsgpacked_bytesr9   r8   Zpack_indirect_intokeyr\   r]   Zcurrent_id_offsetitemZneed_more_datastartlengthZcurrent_itemZcurrent_item_lengthZcurrent_spans_chunksposZitem_offsetrX   r   r   r   iter_archive_items   sn   




-zItemCache.iter_archive_items)NF)__name__
__module____qualname____doc__re   structStructrJ   sizerB   rM   rr   r   r   r   r   r+   B   s    
&r+   c                   @   sj   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdddZ	g fddZ
g fddZdd Zdd ZdS )FuseBackendzJVirtual filesystem based on archive(s) to provide information to fuse
    c                 C   s   || _ || _|j| _|| _|| _i | _ttdd d| _d| _	i | _
tt| _t | _t | _d | _i | _t|| _d| _d| _d | _d | _d| _d S )Nc                 S   r/   r   r   r0   r   r   r   r2      r3   z&FuseBackend.__init__.<locals>.<lambda>r4   r   F)repository_uncached_argsnumeric_ids	_manifestrm   _itemsr    FILES_inode_cacheinode_countparentr   dictcontentsosgetuiddefault_uidgetgiddefault_giddefault_dirpending_archivesr+   cacheallow_damaged_filesversions
uid_forced
gid_forcedumask)rA   rm   manifest
repositoryr	   r6   r   r   r   rB      s(   




zFuseBackend.__init__c                 C   s   | j dd | jjjr| jrtd| | jjj d S t | _| j	j
| jD ]+}| jr4| |j q(| j dt|j d d}|| jd t|j< |j| j|< q(d S )Nr   )r   z_for versions view, do not specify a single archive, but always give the repository as location.    eA)r   mtime)_create_dirr|   locationarchiver   r   _process_archiver   versions_indexr~   ZarchivesZlist_consideringnamerS   ts	timestampr   r   fsencoder   )rA   r   Zarchive_inoder   r   r   _create_filesystem  s   
zFuseBackend._create_filesystemc                 C   sR   | j |}|d ur|S z| j| W S  ty(   | j|}|| j |< | Y S w r   )r   rM   r   KeyErrorr   )rA   rX   rn   r   r   r   get_item$  s   
zFuseBackend.get_itemc                 C   s2   | j |d }|d ur| |t|g d S d S r   )r   popr   r   r   )rA   rX   archive_namer   r   r   check_pending_archive1  s   z!FuseBackend.check_pending_archivec                 C   s   |  j d7  _ | j S )Nr   )r   rA   r   r   r   _allocate_inode7  s   zFuseBackend._allocate_inodeNc                 C   sN   |   }|durt| j d| j|< || j| _n| j| j|< || j|< |S )zCreate directory
        NrE   )r   r   r   as_dictr   r   r   )rA   r   r   inor   r   r   r   ;  s   
zFuseBackend._create_dirc                 C   s.   || d }d}|D ]	}| j| | }q|S )N   /r   )splitr   )rA   pathr-   segmentsrX   segmentr   r   r   
find_inodeG  s
   zFuseBackend.find_inodec                    s|  i | _ t }t| j| j| j|| jjd}| jj	}t
| jj| jj}|  p)|r.i nd  fdd}t
|||}| jj|jj|| jjdD ]b\}	}
|ratj|
jtj|d |
_t|
j}t|
j}|rz| ||}W n	 ty   Y nw |
| j|< qK||d }d}|dd D ]}|  ||}q| !|d |
||||	 | qKt | }t"#d	||j$ dS )
z9Build FUSE inode hierarchy from archive metadata
        )rl   Nc                    sV   r!|s#t | jr%| ddr'd| vr)| dd f | d< d S d S d S d S d S d S )NZhardlink_masterTsourcer>   r   )r   moderM   )rn   Zmatchedhardlink_mastersZpartial_extractr   r   peek_and_store_hardlink_mastersZ  s   
zEFuseBackend._process_archive.<locals>.peek_and_store_hardlink_masters)rk   rl   r   r   z9fuse: _process_archive completed in %.1f s for archive %s)%file_versionstimeperf_counterr   r{   rm   r~   r|   rl   strip_componentsr   Zbuild_matcherpatternspathsemptyZbuild_filterr   rr   metadataitemsr   sepjoinr   r   r   statS_ISDIRr   r   r   r   _process_inner_process_leafloggerdebugr   )rA   r   r-   t0r   r   Zmatcherr   rk   
item_inodern   r   is_dirrX   r   r   r   Zdurationr   r   r   r   N  sF    
zFuseBackend._process_archivec	                    s  |j }	|` |pi } fdd}
ddd}d|v rt|jrtj|jtj|d  }||jd |f\}}|r{t	|} j
rM j| }|||dd}z ||}W n tyf   td	|	| Y d S w  |}|d
dd |_| j|< n|d ur||_|}| j|< |rd |	f||j< n|} j
r|s ||}t	|	}|
||}|d ur|||}| j|< | j|< |r| j| |< d S d S )Nc                    sb   d| v r/t |} j|d\}}t ddd | jD }||kr-|d7 }||f j|< |S d S )Nr>   )r   Nr_   c                 s   s    | ]\}}}|V  qd S r   r   ).0rZ   r1   r   r   r   	<genexpr>  s    zBFuseBackend._process_leaf.<locals>.file_version.<locals>.<genexpr>r   )r   r   rM   r   r>   )rn   r   Zfile_idZcurrent_versionZprevious_idZcontents_idr   r   r   file_version  s   z/FuseBackend._process_leaf.<locals>.file_versionFc                 S   sJ   |r|  dd}| d|d  7 } tj| \} }td| }| | | S )Nr   r   r   z.%05d)rsplitr   r   splitextr   )r   versionadd_dirZ
path_fnameextZversion_encr   r   r   make_versioned_name  s   z6FuseBackend._process_leaf.<locals>.make_versioned_namer   T)r   z#Skipping broken hard link: %s -> %snlinkr   F)r   r   r   r   r   r   r   r   rM   r   r   r   r   r   r   warningr   r   r   r>   r   r   r   )rA   r   rn   r   r-   r   r   r   Zstripped_componentsr   r   r   r   r>   Zlink_targetr   rX   Zenc_pathr   r   r   r   z  sR   











zFuseBackend._process_leafc                 C   s8   | j | }||v r|| }|S | |}|r|||< |S r   )r   r   )rA   r   parent_inodedirrX   r   r   r   r     s   

zFuseBackend._process_innerr   )rs   rt   ru   rv   rB   r   r   r   r   r   r   r   r   r   r   r   r   r   rz      s    
,Frz   c                   @   s   e Zd ZdZdd Zdd Zd!ddZed"d
dZd"ddZ	ed"ddZ
ed"ddZed"ddZed"ddZed"ddZed"ddZedd ZerVdd Zndd Zed"dd Zd	S )#FuseOperationsz(Export archive as a FUSE filesystem
    c                 C   st   t j|  t| ||||| || _ttjdt	 pd}t
d| t|dd d| _ttdd d| _d S )NZBORG_MOUNT_DATA_CACHE_ENTRIESr   z$mount data cache capacity: %d chunksc                 S   r/   r   r   r0   r   r   r   r2     r3   z)FuseOperations.__init__.<locals>.<lambda>r4   c                 S   r/   r   r   r0   r   r   r   r2     r3   )r   
OperationsrB   rz   r6   rS   r   environrM   	cpu_countr   r   r    
data_cacher   	_last_pos)rA   rm   r   r   r	   r6   Zdata_cache_capacityr   r   r   rB     s   zFuseOperations.__init__c                 C   s   t d| jt| jtt| jt| jt| j   t dt| j t d| j	j
| j	j | j	j
| j	jtt| j	jtt| j	j j t dt| j | jjttdd | j D  | j  d S )Nz$fuse: %d synth inodes, %d edges (%s)zfuse: %d pending archivesz]fuse: ItemCache %d entries (%d direct, %d indirect), meta-array size %s, direct items size %sz#fuse: data cache: %d/%d entries, %sc                 s   s    | ]	\}}t |V  qd S r   )rd   )r   rm   r[   r   r   r   r     s    z2FuseOperations.sig_info_handler.<locals>.<genexpr>)r   r   r   rd   r   r   sys	getsizeofr   r   r@   r?   r8   r   r   r=   filenost_sizer   r   	_capacitysumr6   Zlog_instrumentation)rA   Zsig_nostackr   r   r   sig_info_handler  s   $zFuseOperations.sig_info_handlerFc              	   C   st  ddd}g d}|r| |d tr0||dddt}|p'tj| d}|d	|  ||d
ddt}|rB||dddt ||dddt| _	||dddt| _
||dddt| _||dddt| _||dddtdd| _| jdury| jn| j}| jdur| jn| j}	t|}
t|	}t|
tsJ t|tsJ d| j @ }t|tt d |
|||	d| _|   t| || |st| jtrt  n!t \}}td | j || W d   n1 sw   Y  d}zEt!d| j"" t!d| j" t# }W d   n	1 sw   Y  W d   n	1 sw   Y  |du p+|t$ko+|}W t%| dS t%| w )z6Mount filesystem on *mountpoint* with *mount_options*.r   c           
   	   S   s  t | tsJ t| D ]s\}}||kr| | |  S ||d r~| | |ddd }|tu rL| }	|	dv r? dS |	dv rF dS td| |t	u rhz	t	||dW   S  tyg   td| d w z||W   S  ty}   td| d w q|S )	N=r   )yyestrue1T)nnofalse0Fzunsupported value in option: %s)base)

isinstancelist	enumerater   
startswithr   boollowerrH   rS   )
optionsrm   ZpresentZnot_presentZwanted_typeint_baseidxoptionvaluevr   r   r   
pop_option  s8   

z(FuseOperations.mount.<locals>.pop_option)zfsname=borgfsrodefault_permissions,volname z	 (borgfs)zvolname=ignore_permissionsTFr   r   r   uidNgidr   ra   )r   iA  r   )r   r   usergroupr  r  z<fuse: mount local repo, going to background: migrating lock.SIGUSR1ZSIGINFO)r   )&extendr   r#   strr   r   basenameappendr   r   r   rS   r   r   r   r   r   r!   r"   r   r   r   r   r   r   initr{   r$   r   r   r   r   Zmigrate_lockr   r   r)   r   close)rA   Z
mountpointZmount_optionsZ
foregroundr   r   r   r  Zdir_uidZdir_gidZdir_userZ	dir_groupZdir_modeZold_idZnew_idumountsignalr   r   r   mount  s\   
!


 zFuseOperations.mountNc                 C   sB   t  }d|_d|_d|_d|_d|_d|_d|_d|_	d|_
|S )N   r      )r   ZStatvfsDataf_bsizef_frsizef_blocksf_bfreef_bavailf_filesf_ffreef_favail	f_namemax)rA   ctxZstat_r   r   r   statfsC  s   zFuseOperations.statfsc                 C   s   |  |}t }||_d|_d|_d|_|j| j @ |_	|
dd|_t|| j| j| j| j| jd\|_|_|
dd|_| |_d|_|j|j d |j |_|j |_}|
d||_|
d	||_|
d
||_|S )Nr   i,  r   r   )numericZuid_defaultZgid_defaultr   r   Zrdevr  atimectimeZ	birthtime)r   r   ZEntryAttributesst_inoZ
generationZentry_timeoutZattr_timeoutr   r   st_moderM   st_nlinkr   r}   r   r   r   r   st_uidst_gidst_rdevZget_sizer   
st_blksize	st_blocksr   st_mtime_nsst_atime_nsst_ctime_nsZst_birthtime_ns)rA   rX   r  rn   entryZmtime_nsr   r   r   _getattrQ  s*   

zFuseOperations._getattrc                 C   s   | j ||dS )N)r  )r-  rA   rX   r  r   r   r   getattrh  s   zFuseOperations.getattrc                 C   s   |  |}|di  S )Nxattrs)r   rM   keysrA   rX   r  rn   r   r   r   	listxattrl  s   
zFuseOperations.listxattrc                 C   s>   |  |}z|di | pdW S  ty   ttjd w )Nr0  r_   )r   rM   r   r   	FUSEErrorZENOATTR)rA   rX   r   r  rn   r   r   r   getxattrq  s   
zFuseOperations.getxattrc                 C   sV   |  | |dkr|}n|dkr| j| }n| j| |}|s&ttj| |S )N   .   ..)	r   r   r   rM   r   r4  errnoENOENTr-  )rA   r   r   r  rX   r   r   r   lookupy  s   

zFuseOperations.lookupc                 C   sB   | j s| |}d|v rtd ttjtrtj	|dS |S )NZchunks_healthyzzFile has damaged (all-zero) chunks. Try running borg check --repair. Mount with allow_damaged_files to read damaged files.)fh)
r   r   r   r   r   r4  r8  ZEIOr   ZFileInfo)rA   rX   flagsr  rn   r   r   r   open  s   

zFuseOperations.openc                 C   s   |  | |S r   )r   r.  r   r   r   opendir  s   
zFuseOperations.opendirc                 C   sN  g }|  |}| j|d\}}||krd\}}||8 }|j}t|t|D ]{}	||	 \}
}}||k r@||8 }||7 }|d7 }q&t||| }|
| jv r^| j|
 }|| t|kr]| j|
= n| j	|
| j
|
}|| t|k rv|| j|
< |||||   d}||8 }|s|| jv r| j|||f n||f| j|<  nq&d|S )N)r   r   r   r   r_   )r   r   rM   r>   rangerd   minr   rm   Zdecryptr{   r  Zupdr   )rA   r;  r:   ry   partsrn   Zchunk_norY   r>   r   idsr\   r   r]   r   r   r   read  sB   





zFuseOperations.readc           	         st   d|fd| j | fg}|| j|   t||d  |D ]\}\}}| |}t||||d s7 d S qd S Nr6  r7  r   )r   r  r   r   r   r-  r   Zreaddir_reply)	rA   r;  offtokenentriesir   rX   attrsr   r   r   readdir  s   
zFuseOperations.readdirc                 c   sj    d|fd| j | fg}|| j|   t||d  |D ]\}\}}| |}|||d fV  qd S rE  )r   r  r   r   r   r-  )rA   r;  rF  rH  rI  r   rX   rJ  r   r   r   rK    s   
c                 C   s   |  |}t|jS r   )r   r   r   r   r2  r   r   r   readlink  s   
zFuseOperations.readlinkr   r   )rs   rt   ru   rv   rB   r   r  r   r  r-  r/  r3  r5  r:  r=  r>  rD  r   rK  rL  r   r   r   r   r     s6    	
\

,
	r   )6r8  r   rV   r   r   rw   r   r;   r   collectionsr   r  r   Z	fuse_implr   r   r&   r   r   r   Zcrypto.low_levelr   archiverr   r   r   r   Z	hashindexr   helpersr   r   r   r   r   r   r   rn   r   Zlrucacher    platformr!   r"   Zplatformflagsr#   Zremoter$   r)   r   r+   rz   r   r   r   r   r   r   <module>   sJ    
  - ^