88- Simple, composable operations following Unix philosophy
99"""
1010
11+ import base64
12+ import builtins
1113import hashlib
1214import json
13- import time
1415import os
16+ import time
17+ from collections import defaultdict
1518from dataclasses import dataclass , field , asdict
16- from typing import Dict , List , Optional , Set , Union , Any
1719from enum import IntEnum
18- from collections import defaultdict
19- import random
20- import string
20+ from typing import Dict , List , Optional , Set , Tuple , Union , Any
2121
2222
2323class Mode (IntEnum ):
@@ -65,19 +65,19 @@ def to_dict(self) -> dict:
6565
6666 def is_file (self ) -> bool :
6767 """Check if this is a regular file."""
68- return (self .mode & Mode . IFDIR ) == 0 and ( self . mode & Mode .IFCHR ) == 0
68+ return (self .mode & 0o170000 ) == Mode .IFREG
6969
7070 def is_dir (self ) -> bool :
7171 """Check if this is a directory."""
72- return (self .mode & Mode . IFDIR ) != 0
72+ return (self .mode & 0o170000 ) == Mode . IFDIR
7373
7474 def is_device (self ) -> bool :
7575 """Check if this is a device."""
76- return (self .mode & Mode . IFCHR ) != 0
76+ return (self .mode & 0o170000 ) == Mode . IFCHR
7777
7878 def is_symlink (self ) -> bool :
7979 """Check if this is a symbolic link."""
80- return (self .mode & Mode . IFLNK ) == Mode .IFLNK
80+ return (self .mode & 0o170000 ) == Mode .IFLNK
8181
8282
8383@dataclass (frozen = True )
@@ -98,7 +98,6 @@ def __init__(self, content: Union[str, bytes] = b"", mode: int = Mode.FILE_DEFAU
9898 def to_dict (self ) -> dict :
9999 d = super ().to_dict ()
100100 # Store content as base64 for JSON serialization
101- import base64
102101 d ['content' ] = base64 .b64encode (self .content ).decode ('ascii' )
103102 d ['type' ] = 'file'
104103 return d
@@ -328,7 +327,7 @@ def _resolve_path(self, path: str, follow_symlinks: bool = True,
328327
329328 return node_hash
330329
331- def _get_parent_path (self , path : str ) -> tuple [str , str ]:
330+ def _get_parent_path (self , path : str ) -> Tuple [str , str ]:
332331 """Split path into parent directory and basename."""
333332 path = os .path .normpath (path )
334333 if path == '/' :
@@ -706,7 +705,7 @@ def _create_file(self, path: str, content: bytes, mode: str, mtime: Optional[flo
706705
707706 # User and permission management
708707
709- def lookup_user (self , username : str ) -> tuple [int , int ]:
708+ def lookup_user (self , username : str ) -> Tuple [int , int ]:
710709 """Look up user ID and primary group ID from /etc/passwd."""
711710 passwd_hash = self ._resolve_path ('/etc/passwd' )
712711 if not passwd_hash :
@@ -813,8 +812,6 @@ def export_to_real(self, target_path: str, preserve_permissions: bool = True,
813812 Returns:
814813 Number of files/directories exported
815814 """
816- import shutil
817-
818815 # Default mappings (virtual -> real)
819816 if uid_map is None :
820817 uid_map = {0 : 0 , 1000 : os .getuid (), 1001 : os .getuid (), 1002 : os .getuid ()}
@@ -851,7 +848,7 @@ def export_to_real(self, target_path: str, preserve_permissions: bool = True,
851848 mode = node .mode & 0o777
852849 try :
853850 os .chmod (real_path , mode )
854- except :
851+ except Exception :
855852 pass # Ignore permission errors
856853
857854 elif node .is_file ():
@@ -860,7 +857,6 @@ def export_to_real(self, target_path: str, preserve_permissions: bool = True,
860857 os .makedirs (parent_dir , exist_ok = True )
861858
862859 # Write file content
863- import builtins
864860 with builtins .open (real_path , 'wb' ) as f :
865861 f .write (node .content )
866862 exported += 1
@@ -870,7 +866,7 @@ def export_to_real(self, target_path: str, preserve_permissions: bool = True,
870866 mode = node .mode & 0o777
871867 try :
872868 os .chmod (real_path , mode )
873- except :
869+ except Exception :
874870 pass # Ignore permission errors
875871
876872 # Try to set ownership if running as root
@@ -879,7 +875,7 @@ def export_to_real(self, target_path: str, preserve_permissions: bool = True,
879875 real_gid = gid_map .get (node .gid , node .gid )
880876 try :
881877 os .chown (real_path , real_uid , real_gid )
882- except :
878+ except Exception :
883879 pass # Ignore if can't change ownership
884880
885881 return exported
@@ -905,8 +901,6 @@ def import_from_real(self, source_path: str, target_path: str = '/',
905901 FileNotFoundError: If source_path doesn't exist
906902 ValueError: If target_path is invalid
907903 """
908- import builtins
909-
910904 if uid is None :
911905 uid = 1000
912906 if gid is None :
@@ -1046,13 +1040,12 @@ def from_json(cls, json_str: str) -> 'FileSystem':
10461040 fs .refs = defaultdict (int )
10471041
10481042 # Reconstruct nodes
1049- import base64
10501043 for hash , node_data in data ['nodes' ].items ():
1051- node_type = node_data .pop ('type' , 'file' )
1044+ node_type = node_data .get ('type' , 'file' )
10521045
10531046 if node_type == 'file' :
1054- content = base64 .b64decode (node_data .pop ('content' , '' ))
1055- node = FileNode (content = content , ** {k : v for k , v in node_data .items () if k != ' content' })
1047+ content = base64 .b64decode (node_data .get ('content' , '' ))
1048+ node = FileNode (content = content , ** {k : v for k , v in node_data .items () if k not in ( 'type' , ' content') })
10561049 elif node_type == 'dir' :
10571050 node = DirNode (** {k : v for k , v in node_data .items () if k != 'type' })
10581051 elif node_type == 'device' :
0 commit comments