@@ -691,10 +691,17 @@ def resolve_glob_path(self, path: str) -> Iterator[fsutil.TargetPath]:
691691
692692 def check_file (self , path : str ) -> fsutil .TargetPath | None :
693693 path = self .resolve_path (path )
694+
694695 if not path .exists ():
695696 print (f"{ path } : No such file" )
696697 return None
697698
699+ # Check a special case where a path can be both a file and directory (e.g. NTDS.dit)
700+ # We need to check this on the entry, as the path methods can't detect this because of how stat.S_IS* works
701+ entry = path .get ()
702+ if entry .is_file () and entry .is_dir ():
703+ return path
704+
698705 if path .is_dir ():
699706 print (f"{ path } : Is a directory" )
700707 return None
@@ -930,21 +937,22 @@ def cmd_attr(self, args: argparse.Namespace, stdout: TextIO) -> bool:
930937 @arg ("path" )
931938 def cmd_file (self , args : argparse .Namespace , stdout : TextIO ) -> bool :
932939 """determine file type"""
933-
934- path = self .check_file (args .path )
935- if not path :
940+ if not (path := self .check_file (args .path )):
936941 return False
937942
938- fh = path .open ()
939-
940- # We could just alias this to cat <path> | file -, but this is slow for large files
941- # This way we can explicitly limit to just 512 bytes
942943 p = subprocess .Popen (["file" , "-" ], stdin = subprocess .PIPE , stdout = subprocess .PIPE )
943- p .stdin .write (fh .read (512 ))
944+
945+ with path .open () as fh :
946+ # We could just alias this to cat <path> | file -, but this is slow for large files
947+ # This way we can explicitly limit to just 512 bytes
948+ p .stdin .write (fh .read (512 ))
949+
944950 p .stdin .close ()
945951 p .wait ()
952+
946953 filetype = p .stdout .read ().decode ().split (":" , 1 )[1 ].strip ()
947954 print (f"{ path } : { filetype } " , file = stdout )
955+
948956 return False
949957
950958 @arg ("path" , nargs = "+" )
@@ -1094,12 +1102,11 @@ def cmd_cat(self, args: argparse.Namespace, stdout: TextIO) -> bool:
10941102
10951103 stdout = stdout .buffer
10961104 for path in paths :
1097- path = self .check_file (path )
1098- if not path :
1105+ if not (path := self .check_file (path )):
10991106 continue
11001107
1101- fh = path .open ()
1102- shutil .copyfileobj (fh , stdout )
1108+ with path .open () as fh :
1109+ shutil .copyfileobj (fh , stdout )
11031110 stdout .flush ()
11041111 print ()
11051112 return False
@@ -1115,12 +1122,11 @@ def cmd_zcat(self, args: argparse.Namespace, stdout: TextIO) -> bool:
11151122
11161123 stdout = stdout .buffer
11171124 for path in paths :
1118- path = self .check_file (path )
1119- if not path :
1125+ if not (path := self .check_file (path )):
11201126 continue
11211127
1122- fh = fsutil .open_decompress (path )
1123- shutil .copyfileobj (fh , stdout )
1128+ with fsutil .open_decompress (path ) as fh :
1129+ shutil .copyfileobj (fh , stdout )
11241130 stdout .flush ()
11251131
11261132 return False
@@ -1157,36 +1163,38 @@ def cmd_hexdump(self, args: argparse.Namespace, stdout: TextIO) -> bool:
11571163 @alias ("shasum" )
11581164 def cmd_hash (self , args : argparse .Namespace , stdout : TextIO ) -> bool :
11591165 """print the MD5, SHA1 and SHA256 hashes of a file"""
1160- path = self .check_file (args .path )
1161- if not path :
1166+ if not (path := self .check_file (args .path )):
11621167 return False
11631168
11641169 md5 , sha1 , sha256 = path .get ().hash ()
11651170 print (f"MD5:\t { md5 } \n SHA1:\t { sha1 } \n SHA256:\t { sha256 } " , file = stdout )
1171+
11661172 return False
11671173
11681174 @arg ("path" )
11691175 @alias ("head" )
11701176 @alias ("more" )
11711177 def cmd_less (self , args : argparse .Namespace , stdout : TextIO ) -> bool :
11721178 """open the first 10 MB of a file with less"""
1173- path = self .check_file (args .path )
1174- if not path :
1179+ if not (path := self .check_file (args .path )):
11751180 return False
11761181
1177- pydoc .pager (path .open ("rt" , errors = "ignore" ).read (10 * 1024 * 1024 ))
1182+ with path .open ("rt" , errors = "ignore" ) as fh :
1183+ pydoc .pager (fh .read (10 * 1024 * 1024 ))
1184+
11781185 return False
11791186
11801187 @arg ("path" )
11811188 @alias ("zhead" )
11821189 @alias ("zmore" )
11831190 def cmd_zless (self , args : argparse .Namespace , stdout : TextIO ) -> bool :
11841191 """open the first 10 MB of a compressed file with zless"""
1185- path = self .check_file (args .path )
1186- if not path :
1192+ if not (path := self .check_file (args .path )):
11871193 return False
11881194
1189- pydoc .pager (fsutil .open_decompress (path , "rt" ).read (10 * 1024 * 1024 ))
1195+ with fsutil .open_decompress (path , "rt" ) as fh :
1196+ pydoc .pager (fh .read (10 * 1024 * 1024 ))
1197+
11901198 return False
11911199
11921200 @arg ("path" , nargs = "+" )
@@ -1212,8 +1220,7 @@ def cmd_registry(self, args: argparse.Namespace, stdout: TextIO) -> bool:
12121220
12131221 clikey = "registry"
12141222 if args .path :
1215- path = self .check_file (args .path )
1216- if not path :
1223+ if not (path := self .check_file (args .path )):
12171224 return False
12181225
12191226 hive = regutil .RegfHive (path )
0 commit comments