require "crystal/system/file_info" class File # Represents the various behaviour-altering flags which can be set on files. # Not all flags will be supported on all platforms. @[::Flags] enum Flags : UInt8 SetUser SetGroup Sticky end # Represents the type of a file. Not all types will be supported on all # platforms. enum Type : UInt8 File Directory Symlink Socket Pipe CharacterDevice BlockDevice Unknown # Returns true if `self` is a `CharacterDevice` or a `BlockDevice`. def device? character_device? || block_device? end end # Represents a set of access permissions for a file. Not all permission sets # will be supported on all platforms. # # The binary representation of this enum is defined to be same representation # as the permission bits of a unix `st_mode` field. `File::Permissions` # can also be compared to its underlying bitset, for example # `File::Permissions::All == 0o777` will always be `true`. # # On windows, only the `OwnerWrite` bit is effective. All file permissions # will either be `0o444` for read-only files or `0o666` for read-write files. # Directories are always mode `0o555` for read-only or `0o777`. @[::Flags] enum Permissions : Int16 OtherExecute = 0o001 OtherWrite = 0o002 OtherRead = 0o004 OtherAll = 0o007 GroupExecute = 0o010 GroupWrite = 0o020 GroupRead = 0o040 GroupAll = 0o070 OwnerExecute = 0o100 OwnerWrite = 0o200 OwnerRead = 0o400 OwnerAll = 0o700 def self.new(int : Int) new(int.to_i16) end def to_s(io : IO) : Nil io << (owner_read? ? 'r' : '-') io << (owner_write? ? 'w' : '-') io << (owner_execute? ? 'x' : '-') io << (group_read? ? 'r' : '-') io << (group_write? ? 'w' : '-') io << (group_execute? ? 'x' : '-') io << (other_read? ? 'r' : '-') io << (other_write? ? 'w' : '-') io << (other_execute? ? 'x' : '-') io << " (0o" << self.to_i.to_s(8) << ')' end end # A `File::Info` contains metadata regarding a file. # It is returned by `File.info`, `File#info` and `File.info?`. struct Info include Crystal::System::FileInfo # Size of the file, in bytes. def size : Int64 system_size end # The permissions of the file. def permissions : Permissions system_permissions end # The type of the file. def type : Type system_type end # The special flags this file has set. def flags : Flags system_flags end # The last time this file was modified. def modification_time : Time system_modification_time end # The user ID that the file belongs to. def owner_id : String system_owner_id end # The group ID that the file belongs to. def group_id : String system_group_id end # Returns true if this `Info` and *other* are of the same file. # # On Unix-like systems, this compares device and inode fields, and will # compare equal for hard linked files. def same_file?(other : self) : Bool system_same_file?(other) end # Returns true if this `Info` represents a standard file. Shortcut for # `type.file?`. def file? type.file? end # Returns true if this `Info` represents a directory. Shortcut for # `type.directory?`. def directory? type.directory? end # Returns true if this `Info` represents a symbolic link to another file. # Shortcut for `type.symlink?`. def symlink? type.symlink? end # Returns `true` if *path* is readable by the real user id of this process else returns `false`. # # ``` # File.write("foo", "foo") # File::Info.readable?("foo") # => true # ``` # # This method returns the readable property as reported by the file system # which provides no indication of whether `File.read` would be a valid # operation because it applies to all file types, including directories. def self.readable?(path : Path | String) : Bool Crystal::System::File.readable?(path.to_s) end # Returns `true` if *path* is writable by the real user id of this process else returns `false`. # # ``` # File.write("foo", "foo") # File::Info.writable?("foo") # => true # ``` # # This method returns the readable property as reported by the file system # which provides no indication of whether `File.write` would be a valid # operation because it applies to all file types, including directories. def self.writable?(path : Path | String) : Bool Crystal::System::File.writable?(path.to_s) end # Returns `true` if *path* is executable by the real user id of this process else returns `false`. # # ``` # File.write("foo", "foo") # File::Info.executable?("foo") # => false # ``` # # This method returns the readable property as reported by the file system # which provides no indication of whether `Process.execute` would be a valid # operation because it applies to all file types, including directories # (which typically *are* executable to signal it's allowed to list their # contents). def self.executable?(path : Path | String) : Bool Crystal::System::File.executable?(path.to_s) end end end