@@ -455,6 +455,11 @@ def last_access_time_ns(self) -> int:
455455 """Return the ``$FILE_NAME`` file ``LastAccessTime`` in nanoseconds."""
456456 return ts_to_ns (self .attr .LastAccessTime )
457457
458+ @property
459+ def allocated_size (self ) -> int :
460+ """Return the ``$FILE_NAME`` file ``AllocatedLength``."""
461+ return self .attr .AllocatedLength
462+
458463 @property
459464 def file_size (self ) -> int :
460465 """Return the ``$FILE_NAME`` file ``FileSize``."""
@@ -463,7 +468,16 @@ def file_size(self) -> int:
463468 @property
464469 def file_attributes (self ) -> int :
465470 """Return the ``$FILE_NAME`` file ``FileAttributes``."""
466- return self .attr .FileAttributes
471+ attributes = self .attr .FileAttributes
472+
473+ if attributes & c_ntfs .FILE_NAME_INDEX_PRESENT :
474+ attributes &= ~ c_ntfs .FILE_NAME_INDEX_PRESENT
475+ attributes |= c_ntfs .FILE_ATTRIBUTE .DIRECTORY .value
476+
477+ if attributes == 0 :
478+ attributes |= c_ntfs .FILE_ATTRIBUTE .NORMAL .value
479+
480+ return c_ntfs .FILE_ATTRIBUTE (attributes )
467481
468482 @property
469483 def flags (self ) -> int :
@@ -479,6 +493,47 @@ def full_path(self) -> str:
479493 """Use the parent directory reference to try to generate a full path from this file name."""
480494 return get_full_path (self .record .ntfs .mft , self .file_name , self .attr .ParentDirectory )
481495
496+ def is_dir (self ) -> bool :
497+ """Return whether this ``$FILE_NAME`` attribute represents a directory."""
498+ return bool (self .attr .FileAttributes & c_ntfs .FILE_NAME_INDEX_PRESENT )
499+
500+ def is_file (self ) -> bool :
501+ """Return whether this ``$FILE_NAME`` attribute represents a file."""
502+ return not self .is_dir ()
503+
504+ def is_reparse_point (self ) -> bool :
505+ """Return whether this ``$FILE_NAME`` attribute represents a reparse point."""
506+ return bool (self .attr .FileAttributes & c_ntfs .FILE_ATTRIBUTE .REPARSE_POINT )
507+
508+ def is_symlink (self ) -> bool :
509+ """Return whether this ``$FILE_NAME`` attribute represents a symlink reparse point."""
510+ return self .is_reparse_point () and self .attr .ReparsePointTag == IO_REPARSE_TAG .SYMLINK
511+
512+ def is_mount_point (self ) -> bool :
513+ """Return whether this ``$FILE_NAME`` attribute represents a mount point reparse point."""
514+ return self .is_reparse_point () and self .attr .ReparsePointTag == IO_REPARSE_TAG .MOUNT_POINT
515+
516+ def is_cloud_file (self ) -> bool :
517+ """Return whether this ``$FILE_NAME`` attribute represents a cloud file."""
518+ return self .is_reparse_point () and self .attr .ReparsePointTag in (
519+ IO_REPARSE_TAG .CLOUD ,
520+ IO_REPARSE_TAG .CLOUD_1 ,
521+ IO_REPARSE_TAG .CLOUD_2 ,
522+ IO_REPARSE_TAG .CLOUD_3 ,
523+ IO_REPARSE_TAG .CLOUD_4 ,
524+ IO_REPARSE_TAG .CLOUD_5 ,
525+ IO_REPARSE_TAG .CLOUD_6 ,
526+ IO_REPARSE_TAG .CLOUD_7 ,
527+ IO_REPARSE_TAG .CLOUD_8 ,
528+ IO_REPARSE_TAG .CLOUD_9 ,
529+ IO_REPARSE_TAG .CLOUD_A ,
530+ IO_REPARSE_TAG .CLOUD_B ,
531+ IO_REPARSE_TAG .CLOUD_C ,
532+ IO_REPARSE_TAG .CLOUD_D ,
533+ IO_REPARSE_TAG .CLOUD_E ,
534+ IO_REPARSE_TAG .CLOUD_F ,
535+ )
536+
482537
483538class ReparsePoint (AttributeRecord ):
484539 """Specific :class:`AttributeRecord` parser for ``$REPARSE_POINT``."""
0 commit comments