
    Yi(                         S r SSKrSSKrSSKrSSKrSSKJr  SSKJrJ	r	J
r
JrJr  SSKJr  SSKr " S S5      r\" SS	9rg)
u   
CTF题目文件管理服务

提供统一的文件操作接口，包括：
- 文件完整性校验
- 文件存储和读取
- 目录管理
- 存储统计
    N)Path)DictListOptionalTupleAny)datetimec                       \ rS rSrSrSS\4S jjrS\S\4S jrS\S\4S	 jrS\S\	\\
4   4S
 jrS\S\S\\   4S jrS\S\4S jrS\	\\
4   4S jrS\S\S\4S jrS\\	\\
4      4S jrS\S\4S jrSrg)ChallengeFileManager   u   题目文件管理器	base_pathc                 $    [        U5      U l        g)uq   初始化文件管理器

Args:
    base_path: 基础存储路径（默认为 ge10，不再使用 ge10/output）
N)r   r   )selfr   s     K   /Users/yu22x/Desktop/ddd_副本131/ctf/app/services/storage/file_manager.py__init__ChallengeFileManager.__init__   s     i    filepathreturnc                 <  ^ [         R                  " 5       n [        US5       m[        U4S jS5       H  nUR	                  U5        M     SSS5        UR                  5       $ ! , (       d  f       N= f! [         a  n[        SU SU 35         SnAgSnAff = f)uh   计算单个文件的MD5哈希值

Args:
    filepath: 文件路径
    
Returns:
    str: MD5哈希值
rbc                  &   > T R                  S5      $ Ni   readfs   r   <lambda>:ChallengeFileManager.calculate_file_hash.<locals>.<lambda>.   s    !&&,r   r   Nu   计算文件哈希失败 :  )hashlibmd5openiterupdate	hexdigest	Exceptionprint)r   r   hash_md5chunker   s        @r   calculate_file_hash(ChallengeFileManager.calculate_file_hash"   s     ;;=	h%!"6<EOOE* = & %%'' &%  	-hZr!=>	s.   A6 )A%A6 %
A3/A6 6
B BB	directoryc                   ^ [         R                  " 5       n[        U5      nUR                  5       (       d  g [	        UR                  S5      5       H  nUR                  5       (       d  M  UR                  U5      nUR                  [        U5      R                  S5      5        [        US5       m[        U4S jS5       H  nUR                  U5        M     SSS5        M     UR                  5       $ ! , (       d  f       M  = f! [         a0  n[        SU S	U 35        [         R"                  " 5          SnAgSnAff = f)
uf   计算目录的整体哈希值

Args:
    directory: 目录路径
    
Returns:
    str: MD5哈希值
r!   *utf-8r   c                  &   > T R                  S5      $ r   r   r   s   r   r   ?ChallengeFileManager.calculate_directory_hash.<locals>.<lambda>N   s    !&&,r   r   Nu   计算目录哈希失败 r    )r"   r#   r   existssortedrglobis_filerelative_tor&   strencoder$   r%   r'   r(   r)   	traceback	print_exc)	r   r/   r*   dir_pathr   rel_pathr+   r,   r   s	           @r   calculate_directory_hash-ChallengeFileManager.calculate_directory_hash5   s    ;;=	?  	"8>>##67##%%'33H=HOOCM$8$8$AB h-%)*>%DE$OOE2 &E .- 8 %%''	 .-
  	-i[1#>?!	s6   0D
 -AD
 3)C8D
 8
D	D
 

E&D??Ec           	         [        U5      nUR                  5       (       d  SSSS/ S.$ SnSn/ n UR                  S5       H  nUR                  5       (       d  M  US-  nUR	                  5       R
                  nXG-  nUR                  U5      nUR                  [        U5      U[        R                  " UR	                  5       R                  5      R                  5       S.5        M     SUUU R                  U5      US.$ ! [         aB  n	[        S	U S
U	 35        [         R"                  " 5         SSSS/ [        U	5      S.s Sn	A	$ Sn	A	ff = f)u   获取目录的详细信息

Args:
    directory: 目录路径
    
Returns:
    dict: 包含文件数量、总大小、哈希值等信息
Fr   r!   )r5   
file_count
total_sizehashfilesr1      )pathsizemodifiedTu   获取目录信息失败 r    )r5   rC   rD   rE   rF   errorN)r   r5   r7   r8   statst_sizer9   appendr:   r	   fromtimestampst_mtime	isoformatr@   r(   r)   r<   r=   )
r   r/   r>   rC   rD   rF   r   	file_sizer?   r,   s
             r   get_directory_info'ChallengeFileManager.get_directory_infoW   sU    	?    

	$NN3/##%%!OJ ( 7 7I+J'33H=HLL #H )$,$:$:8==?;S;S$T$^$^$`"  0 ((55i@   
	-i[1#>?!Q 
	s$   'D B&D 
E7E	E	Erelative_pathc           	          [        U5      U-  nUR                  5       n[        U5      R                  5       n[        U5      R                  [        U5      5      (       d  [	        SU 35        gUR                  5       (       a  UR                  5       (       d  g[        USSSS9 nUR                  5       sSSS5        $ ! , (       d  f       g= f! [         a  n[	        SU SU S	U 35         SnAgSnAff = f)
u   读取文件内容

Args:
    directory: 目录路径
    relative_path: 相对路径
    
Returns:
    str: 文件内容，失败返回None
u+   安全检查失败：文件不在目录内 Nrr2   ignore)encodingerrorsu   读取文件失败 /r    )
r   resolver:   
startswithr)   r5   r8   r$   r   r(   )r   r/   rU   r   r>   r   r,   s          r   get_file_content%ChallengeFileManager.get_file_content   s    	I6H  '')HI..0Hx=++CM::CH:NO??$$H,<,<,>,>hghG1vvx HGG 	'	{!M?"QCHI	sB   A-C 0*C C 'C7	C 
CC C 
C:C55C:c                 
    [        U5      nUR                  5       (       a%  [        R                  " U5        [	        SU 35        gg! [
         a0  n[	        SU SU 35        [        R                  " 5          SnAgSnAff = f)ui   删除目录及其所有内容

Args:
    directory: 目录路径

Returns:
    bool: 是否成功删除
u   已删除目录: TFu   删除目录失败 r    N)r   r5   shutilrmtreer)   r(   r<   r=   )r   r/   r>   r,   s       r   delete_directory%ChallengeFileManager.delete_directory   st    
	IH  h'))56 	'	{"QC89!	s   AA 
B&A==Bc                 b   SnSnSn/ n U R                   R                  5       (       d  SSS/ S.$ U R                   R                  5        H  nUR                  5       (       d  M  US-  nU R	                  [        U5      5      nXS   -  nX&S   -  nUR                  UR                  [        U5      US   US   [        R                  " UR                  5       R                  5      R                  5       [        R                  " UR                  5       R                  5      R                  5       S.5        M     UR                  S SS	9  UUUU[        U R                   5      S
.$ ! [         a>  n[!        SU 35        ["        R$                  " 5         SSS/ [        U5      S.s SnA$ SnAff = f)ud   获取存储统计信息

Returns:
    dict: 包含总大小、文件数量、目录数量等信息
r   )rD   total_files
total_dirs
challengesrG   rD   rC   namerH   rI   rC   createdrJ   c                     U S   $ NrJ    xs    r   r   8ChallengeFileManager.get_storage_stats.<locals>.<lambda>       !J-r   Tkeyreverse)rD   rf   rg   rh   r   u   获取存储统计失败: )rD   rf   rg   rh   rK   Nr   r5   iterdiris_dirrS   r:   rN   rj   r	   rO   rL   st_ctimerQ   rP   sortr(   r)   r<   r=   )r   rD   rf   rg   rh   challenge_dirdir_infor,   s           r   get_storage_stats&ChallengeFileManager.get_storage_stats   s    


.	>>((**"##$"#"$	  "&!7!7!9 ''))!OJ#66s=7IJH<"88JL#99K%% - 2 2 #M 2 ( 6&.|&<#+#9#9-:L:L:N:W:W#X#b#b#d$,$:$:=;M;M;O;X;X$Y$c$c$e'  ":$ OO 7OF )*(( 0   		.qc23!  Q 		s)   %E& 0E& $DE& &
F.03F)#F.)F.expected_hashc                 ,    U R                  U5      nX2:H  $ )u   验证目录完整性

Args:
    directory: 目录路径
    expected_hash: 期望的哈希值

Returns:
    bool: 是否完整
)r@   )r   r/   r   actual_hashs       r   verify_integrity%ChallengeFileManager.verify_integrity   s     33I>++r   c                    / n U R                   R                  5       (       d  / $ U R                   R                  5        H  nUR                  5       (       d  M  U R	                  [        U5      5      nUR                  UR                  [        U5      US   US   [        R                  " UR                  5       R                  5      R                  5       [        R                  " UR                  5       R                  5      R                  5       S.5        M     UR                  S SS9  U$ ! [         a/  n[!        SU 35        ["        R$                  " 5         / s SnA$ SnAff = f)	u@   列出所有题目目录

Returns:
    list: 题目目录列表
rD   rC   ri   c                     U S   $ rm   rn   ro   s    r   r   6ChallengeFileManager.list_challenges.<locals>.<lambda>#  rr   r   Trs   u   列出题目目录失败: Nrv   )r   rh   r{   r|   r,   s        r   list_challenges$ChallengeFileManager.list_challenges
  s+    
	>>((**	!%!7!7!9 ''))#66s=7IJH%% - 2 2 #M 2 ( 6&.|&<#+#9#9-:L:L:N:W:W#X#b#b#d$,$:$:=;M;M;O;X;X$Y$c$c$e'  ": OO 7OF 	.qc23!I	s)    D/ 0D/ CD/ /
E(9$E#E(#E(
size_bytesc                 J    S H  nUS:  a
  US SU 3s  $ US-  nM     US S3$ )ur   格式化文件大小

Args:
    size_bytes: 字节数

Returns:
    str: 格式化后的大小（如：1.5 MB）
)BKBMBGBTBg      @z.2f z PBrn   )r   r   units      r   format_size ChallengeFileManager.format_size*  sF     2DF"$S)4&11& J 2 S!%%r   r   N)ge10)__name__
__module____qualname____firstlineno____doc__r:   r   r-   r@   r   r   rS   r   r^   boolrc   r}   r   r   r   intr   __static_attributes__rn   r   r   r   r      s    )# )C C & #  #  D7C 7DcN 7r# c hsm :# $ *94S> 9v,# ,c ,d ,d38n!5 @&c &c &r   r   r   r   )r   osra   r"   jsonpathlibr   typingr   r   r   r   r   r	   r<   r   challenge_file_managerrn   r   r   <module>r      sA    
     3 3  b& b&N	 .? r   