4.2.56. GNATCOLL.VFS

package GNATCOLL.VFS is

   ------------------------
   -- Filesystem strings --
   ------------------------

   type Filesystem_String is new String;
   type Filesystem_String_Access is access all Filesystem_String;
   --  A Filesystem_String represents an array of characters as they are
   --  represented on the filesystem, without any encoding consideration.

   function "+" (S : Filesystem_String) return String;
   pragma Inline ("+");
   function "+" (S : String) return Filesystem_String;
   pragma Inline ("+");
   function Equal (S1, S2 : Filesystem_String) return Boolean;
   pragma Inline (Equal);
   procedure Free is new Ada.Unchecked_Deallocation
     (Filesystem_String, Filesystem_String_Access);
   --  Conversion/Comparison/Concatenation functions

   type Cst_Filesystem_String_Access is access constant Filesystem_String;

   ----------------
   -- Exceptions --
   ----------------

   VFS_Directory_Error     : exception;
   VFS_Invalid_File_Error  : exception;
   VFS_Remote_Config_Error : exception;

   ------------------------------
   --  Virtual File definition --
   ------------------------------

   type Virtual_File is tagged private;
   No_File : aliased constant Virtual_File;
   --  Note: a default initialized Virtual_File object has the value No_File

   ---------------
   -- Constants --
   ---------------

   Local_Host : aliased constant String;

   -------------------
   -- Configuration --
   -------------------

   procedure Symbolic_Links_Support (Active : Boolean);
   --  Whether this package should do extra system calls to handle symbolic
   --  links.
   --  This is automatically False on platforms like Windows where this notion
   --  does not exist, but when you know you have no symbolic links manipulated
   --  by your application you can significantly reduce the number of system
   --  calls (which in turns speeds things up). If you set it to False, two
   --  symbolic links that point to the same physical file will be considered
   --  different by the "=" operator. If you set it to True they will be
   --  considered equal.
   --  Changing this is not thread safe. In fact, you should call this before
   --  manipulating any of the Virtual_File, because GNATCOLL.VFS caches the
   --  normalization of file names, and would not redo it for existing files
   --  after you call this function, so the results of "=" in particular might
   --  be unexpected.

   ----------------------------
   --  Creating Virtual_File --
   ----------------------------
   --  The following subprograms are used to create instances of Virtual_File.
   --  On the disk, a filename is typically just a series of bytes, with no
   --  special interpretation in utf8, iso-8859-1 or other pagesets (on most
   --  systems, windows always uses utf8 these days but has other
   --  specificities).
   --  As a result, a filename passed to these Create subprograms will not be
   --  interpreted through an encoding or another, but will just be stored as
   --  is. However, when comes the time to display the file on the disk, the
   --  filename needs to be converted to a known encoding, generally utf8.
   --  See the "Retrieving names" section below.

   function Create
     (Full_Filename : Filesystem_String;
      Host          : String := Local_Host;
      Normalize     : Boolean := False) return Virtual_File;
   --  Return a file, given its full filename.
   --  The latter can be found, for source files, through the functions in
   --  projects-registry.ads.
   --  If Normalize is set, then the VFS is created using the normalized
   --  Full_Filename. In that case note that the path passed is transformed
   --  into an absolute path.

   function Create_From_Dir
     (Dir       : Virtual_File;
      Base_Name : Filesystem_String;
      Normalize : Boolean := False) return Virtual_File;
   --  Creates a file from its directory and base name
   --  If Normalize is set, then Create_From_Dir will make sure that the
   --  path is normalized

   function Create_From_Base
     (Base_Name : Filesystem_String;
      Base_Dir  : Filesystem_String := "";
      Host      : String := Local_Host) return Virtual_File;
   --  Create a file from its base name.
   --  if Base_Name is an absolute path, then the file is created as is
   --  else the file is created relative to Base_Dir or the Current Directory
   --  if provided.

   function Create_From_UTF8
     (Full_Filename : String;
      Host          : String := Local_Host;
      Normalize     : Boolean := False) return Virtual_File;
   --  Creates a file from its display name
   --  If Normalize is set, then the VFS is created using the normalized
   --  Full_Filename.

   function Locate_On_Path
     (Base_Name : Filesystem_String;
      Host      : String := Local_Host) return Virtual_File;
   --  Locate the file from its base name and the PATH environment variable

   function Join
      (Self : Virtual_File; File : Virtual_File) return Virtual_File;
   function Join
      (Self : Virtual_File; Path : Filesystem_String) return Virtual_File;
   function "/"
      (Self : Virtual_File; File : Virtual_File) return Virtual_File;
   function "/"
      (Self : Virtual_File; Path : Filesystem_String) return Virtual_File;
   function "/"
      (Dir : Filesystem_String; File : Virtual_File) return Virtual_File;
   pragma Inline (Join, "/");
   --  Various ways to build paths from their elements. These are just
   --  convention functions on top of the Create_* functions, but might help
   --  make the code more concise. For instance:
   --      File : constant Virtual_File :=
   --         Get_Current_Dir / "filename.txt";

   ----------------------
   -- Retrieving names --
   ----------------------

   --  As mentioned above, a filename is stored internally as a series of bytes
   --  and not interpreted in anyway for an encoding. However, when you
   --  retrieve the name of a file for display, you will have to convert it to
   --  a known encoding.
   --  There are two sets of functions for retrieving names: Display_* will
   --  return the name converted through the Locale_To_Display function of the
   --  filesystem.
   --  All other functions will return the name as passed to the Create
   --  functions above, and therefore make no guarantee on the encoding of the
   --  file name.

   function Base_Name
     (File      : Virtual_File;
      Suffix    : Filesystem_String := "";
      Normalize : Boolean := False)
      return Filesystem_String;
   --  Return the base name of the file

   function Base_Dir_Name (File : Virtual_File) return Filesystem_String;
   --  Return the base name of the directory or the file

   function Full_Name
     (File          : Virtual_File;
      Normalize     : Boolean := False;
      Resolve_Links : Boolean := False) return Cst_Filesystem_String_Access;
   --  Return the full path to File.
   --  If Normalize is True, the file name is first normalized, note that links
   --  are not resolved there by default, unless you specify Resolve_Links to
   --  True.
   --  The returned value can be used to recreate a Virtual_File instance.
   --  If file names are case insensitive, the normalized name will always
   --  be all lower cases.

   function Full_Name
     (File      : Virtual_File;
      Normalize : Boolean := False) return Filesystem_String;
   --  Same as above, returning a filesystem_string

   function Full_Name_Hash
     (Key : Virtual_File) return Ada.Containers.Hash_Type;
   --  Return a Hash_Type computed from the full name of the given VFS.
   --  Could be used to instantiate an Ada 2005 container that uses a VFS as
   --  key and requires a hash function.
   --  See File_Sets below.

   function File_Extension
     (File      : Virtual_File;
      Normalize : Boolean := False) return Filesystem_String;
   --  Return the extension of the file, or the empty string if there is no
   --  extension. This extension includes the last dot and all the following
   --  characters.
   --  If Normalize is true, the casing is normalized (depending on whether the
   --  platform uses case insensitive file names).

   function Dir_Name (File : Virtual_File) return Filesystem_String;
   --  Return the directory name for File. This includes any available
   --  on the protocol, so that relative files names are properly found.

   function Display_Full_Name
     (File      : Virtual_File;
      Normalize : Boolean := False) return String;
   --  Same as Full_Name

   function Display_Base_Name
     (File   : Virtual_File;
      Suffix : Filesystem_String := "") return String;
   --  Same as Base_Name

   function Display_Dir_Name (File : Virtual_File) return String;
   --  Same as Dir_Name

   function Display_Base_Dir_Name (File : Virtual_File) return String;
   --  Same as Base_Dir_Name

   function Unix_Style_Full_Name
     (File         : Virtual_File;
      Cygwin_Style : Boolean := False;
      Normalize    : Boolean := False;
      Casing       : Boolean := False) return Filesystem_String;
   --  Returns the file path using a unix-style path.
   --  The casing of the filename is not impacted unless Casing is True
   --  (i.e. we do not convert to lower-cases on case-insensitive systems),
   --  because applications should preserve the original casing as much as
   --  possible.

   function Relative_Path
     (File : Virtual_File;
      From : Virtual_File) return Filesystem_String;
   --  Return the path of File relative to From. Return the full_name in case
   --  From and File are not on the same drive.

   function Has_Suffix
     (File : Virtual_File; Suffix : Filesystem_String) return Boolean;
   --  Tell if File has suffix Suffix

   function To_Remote
     (File : Virtual_File; To_Host : String) return Virtual_File;
   --  Convert the file format of File to the convention used on To_Host,
   --  using all available mount points defined for To_Host.

   function To_Local
     (File : Virtual_File) return Virtual_File;
   --  Convert the file format of File to the local filesystem's convention,
   --  potentially using mount points defined between File's host and local
   --  host.

   function To_Arg
     (File : Virtual_File;
      Host : String := Local_Host) return GNAT.Strings.String_Access;
   --  Convert the File to a String Access that can be used as argument for
   --  spawning a process on "Host". The returned value needs to be freed by
   --  the caller.

   ------------------------
   -- Getting attributes --
   ------------------------

   function Is_Local (File : Virtual_File) return Boolean;
   --  Whether File is local to the host or is a remote file

   function Get_Host (File : Virtual_File) return String;
   --  Retrieve the host of the file, or Local_Host if the file is local to the
   --  host.

   function Is_Regular_File (File : Virtual_File) return Boolean;
   --  Whether File corresponds to an actual file on the disk.
   --  This also works for remote files.

   function Size (File : Virtual_File) return Long_Integer;
   --  The size of the file

   overriding function "=" (File1, File2 : Virtual_File) return Boolean;
   --  Overloading of the standard operator

   function "<" (File1, File2 : Virtual_File) return Boolean;
   --  Compare two files, possibly case insensitively on file systems that
   --  require this.

   function Is_Parent (Parent, Child : Virtual_File) return Boolean;
   --  Compare Parent and Child directory and determines if Parent contains
   --  Child directory

   function Is_Readable (File : Virtual_File) return Boolean;
   --  Return True if File is readable by the current process

   function Is_Writable (File : Virtual_File) return Boolean;
   --  Return True if File is writable by the current process

   function Is_Directory (VF : Virtual_File) return Boolean;
   --  Return True if File is in fact a directory

   function Is_Symbolic_Link (File : Virtual_File) return Boolean;
   --  Return True if File is a symbolic link

   function Is_Absolute_Path (File : Virtual_File) return Boolean;
   --  Return True if File contains an absolute path name, False if it only
   --  contains the base name or a relative name.

   procedure Set_Writable (File : VFS.Virtual_File; Writable : Boolean);
   --  If Writable is True, grant write permissions to file's owner,
   --  otherwise revoke write permissions.

   procedure Set_Readable (File : VFS.Virtual_File; Readable : Boolean);
   --  If Readable is True, grant read permissions to file's owner,
   --  otherwise revoke read permissions.
   --  Note that this is not supported on remote Windows.

   function File_Time_Stamp (File : Virtual_File) return Ada.Calendar.Time;
   --  Return the timestamp for this file. This is UTC time, not local time.
   --  Note: we do not return GNAT.OS_Lib.OS_Time, since the latter cannot be
   --  created by anyone, and is just a private type.
   --  If the file doesn't exist, No_Time is returned.

   procedure Normalize_Path
     (File             : Virtual_File;
      Resolve_Symlinks : Boolean := False);
   --  Resolve '..' and '.' directories in path.
   --  If Resolve_Symlinks is set, then also resolve the symbolic links in
   --  path.

   --------------------
   -- Array of files --
   --------------------

   type File_Array is array (Positive range <>) of aliased Virtual_File;
   type File_Array_Access is access all File_Array;

   procedure Unchecked_Free (Arr : in out File_Array_Access);

   Empty_File_Array : constant File_Array;

   procedure Sort (Files : in out File_Array);
   --  Sort the array of files, in the order given by the full names

   procedure Append (Files : in out File_Array_Access; F : Virtual_File);
   procedure Append (Files : in out File_Array_Access; F : File_Array);
   procedure Prepend (Files : in out File_Array_Access; F : File_Array);
   --  Appends one or more files to Files. Files can be null, in which case a
   --  new File_Array is created.

   procedure Remove (Files : in out File_Array_Access; F : Virtual_File);
   --  Remove F from Files

   function To_Path (Paths : File_Array) return Filesystem_String;
   --  Translates a list of Paths into a path string (e.g. the same format as
   --  $PATH)

   function From_Path (Path : Filesystem_String) return File_Array;
   --  Translate a PATH string into a list of Virtual_File

   function Locate_On_Path
     (Base_Name : Filesystem_String;
      Path      : File_Array) return Virtual_File;
   --  Locate the file from its base name and the furnished list of
   --  directories.

   function Greatest_Common_Path
     (L : GNATCOLL.VFS.File_Array) return Virtual_File;
   --  Return the greatest common path to a list of files or directories
   --  No_File is returned if some files do not have the same root directory.

   function Locate_Regular_File
     (File_Name : Filesystem_String;
      Path      : File_Array) return Virtual_File;
   --  Locate a regular file from its base name and a list of paths

   -------------------------
   --  Manipulating files --
   -------------------------

   procedure Rename
     (File      : Virtual_File;
      Full_Name : Virtual_File;
      Success   : out Boolean);
   --  Rename a file or directory. This does not work for remote files

   procedure Copy
     (File        : Virtual_File;
      Target_Name : Filesystem_String;
      Success     : out Boolean);
   --  Copy a file or directory. This does not work for remote files

   procedure Delete (File : Virtual_File; Success : out Boolean);
   --  Remove file from the disk. This also works for remote files

   function Read_File (File : Virtual_File) return GNAT.Strings.String_Access;
   function Read_File (File : Virtual_File) return GNATCOLL.Strings.XString;
   --  Return the contents of an entire file, encoded with the locale encoding.
   --  If the file cannot be found, return null.
   --  The caller is responsible for freeing the returned memory.
   --  This works transparently for remote files.
   --  The second version returning a XString is in general more efficient,
   --  especially if you need to do operations like Split() on the resulting
   --  string.

   --------------------------
   -- Directory operations --
   --------------------------

   Local_Root_Dir : constant Virtual_File;

   function Dir (File : Virtual_File) return Virtual_File;
   --  Return the virtual file corresponding to the directory of the file
   --  If File denotes a directory, then it is returned.
   --  To retrieve the container of File (e.g. get the parent of File, even if
   --  it is a directory), use Get_Parent instead.

   function Get_Current_Dir (Host : String := Local_Host) return Virtual_File;
   --  Current dir on host

   function Get_Tmp_Directory
     (Host : String := Local_Host) return Virtual_File;
   --  Tmp dir on host

   function Get_Home_Directory
     (Host : String := Local_Host) return Virtual_File;
   --  Home dir on host

   function Get_Logical_Drives
     (Host : String := Local_Host) return File_Array_Access;
   --  List of all logical drives on host, or null if none. The list needs to
   --  be freed by the caller.

   procedure Ensure_Directory (Dir : Virtual_File);
   --  Ensures that the file is a directory: add directory separator if
   --  needed.

   function Get_Root (File : Virtual_File) return Virtual_File;
   --  Return root directory of the file

   function Get_Parent (Dir : Virtual_File) return Virtual_File;
   --  Return the parent directory if it exists, else No_File is returned

   function Sub_Dir
     (Dir : Virtual_File; Name : Filesystem_String) return Virtual_File;
   --  Return sub directory Name if it exists, else No_File is returned

   procedure Change_Dir (Dir : Virtual_File);
   --  Changes working directory. Raises Directory_Error if Dir_Name does not
   --  exist or is not a readable directory

   procedure Make_Dir (Dir : Virtual_File; Recursive : Boolean := True);
   --  Create a new directory named Dir_Name. Raises Directory_Error if
   --  Dir_Name cannot be created.
   --  If Recursive, create all intermediary directories needed.

   type Read_Dir_Filter is (All_Files, Dirs_Only, Files_Only);

   function Read_Dir
     (Dir    : Virtual_File;
      Filter : Read_Dir_Filter := All_Files) return File_Array_Access;
   --  Reads all entries from the directory and returns a File_Array containing
   --  those entries, according to filter. The list of files returned
   --  includes directories in systems providing a hierarchical directory
   --  structure, including . (the current directory) and .. (the parent
   --  directory) in systems providing these entries. Note that entries
   --  are not sorted.
   --  The result must be freed by the caller.

   function Read_Dir_Recursive
     (Dir       : Virtual_File;
      Extension : Filesystem_String := "";
      Filter    : Read_Dir_Filter := All_Files) return File_Array_Access;
   --  Reads all entries from the directory, recursively, and returns all
   --  files with the given extension (if specified) that match the filter.
   --  The entries "." and ".." are never returned. Note that entries
   --  are not sorted.
   --  The result must be freed by the caller.

   procedure Remove_Dir
     (Dir       : Virtual_File;
      Recursive : Boolean := False;
      Success   : out Boolean);
   --  Delete the directory Dir. If recursive is True, this also removes all
   --  files or subdirectories contained in it.

   function Read_Files_From_Dirs
     (Dirs : File_Array) return File_Array_Access;
   --  Read all files from the list of directories Dirs

   type Virtual_Dir is private;

   Invalid_Dir : constant Virtual_Dir;

   function Open_Dir (Dir : Virtual_File) return Virtual_Dir;
   --  Opens for reading a file

   procedure Read (VDir : in out Virtual_Dir; File : out Virtual_File);
   --  Returns next file or No_File is no file is left for current directory

   procedure Close (VDir : in out Virtual_Dir);
   --  Closes the Virtual_Dir

   -------------------
   -- Writing files --
   -------------------
   --  Writing is more complex than reading, since generally the whole buffer
   --  to write down is not available immediately, but the user wants to be
   --  able to write characters in a series of calls.
   --  The interface in this package will also support remote files. In this
   --  case, writing the small chunks is done in a temporary file, which is
   --  sent to the remote host only when the file is closed.

   type Writable_File is private;

   Invalid_File : constant Writable_File;
   --  Used when a file couldn't be open

   function "=" (Left : Writable_File; Right : Writable_File) return Boolean;
   --  Return True when points to the same file.

   function Write_File
     (File   : Virtual_File;
      Append : Boolean := False) return Writable_File;
   --  Open File for writing. The returned handler can be used for writing.
   --  You must close it, otherwise the file will not actually be written in
   --  some cases. If Append is True then writing will be done at the end of
   --  the file if the file exists otherwise the file is created.
   --  Return Invalid_File if the file couldn't be open for writing
   --
   --  For safety, the actual writes will occur in a temporary file unless
   --  Append is true, which will be renamed when calling Close. This ensures
   --  that the original file (if there was one) is not destroyed if for some
   --  reason the write fails.

   function Error_String
     (Self : Writable_File) return Ada.Strings.Unbounded.Unbounded_String;
   --  Return error message for last operation on file.

   procedure Write
     (File : in out Writable_File;
      Str  : String);
   procedure Write
     (File : in out Writable_File;
      Str  : chars_ptr);
   --  Write a string to File. The contents of Str are written as-is

   procedure Close (File : in out Writable_File);
   --  Closes File, and write the file to disk.
   --  Use_Error is raised if the file could not be saved.

   ----------------------------------
   -- Some internally used methods --
   ----------------------------------

   function Convert
     (File : Virtual_File; To_Host : String) return Virtual_File;
   function Convert
     (File     : Virtual_File;
      From_Dir : Virtual_File;
      To_Dir   : Virtual_File) return Virtual_File;
   --  Used in mount path conversions. These should be private, but can't
   --  as of RM 3.9.3(10)

end GNATCOLL.VFS;