Boost Filesystem operations.hpp Header

# boost/filesystem/operations.hpp

Introduction
Header synopsis
Class directory_iterator
Constructors
Destructor
Other_functions
Operations functions
exists
symbolic_link_exists
is_directory
is_empty
equivalent
file_size
last_write_time
create_directory
remove
remove_all
rename
copy_file
initial_path
complete
system_complete

## Introduction

The boost/filesystem/operations.hpp header provides operations on files and directories.

These operations traffic in paths; see boost/filesystem/path.hpp documentation.

For file I/O streams, see boost/filesystem/fstream.hpp documentation.

The Filesystem Library's Common Specifications apply to all member and non-member functions supplied by this header.

## Header boost/filesystem/operations.hpp synopsis

    namespace boost
    {
      namespace filesystem
      {

        class directory_iterator
        {
        public:
          typedef path                     value_type;
          typedef std::ptrdiff_t           difference_type;
          typedef const path *             pointer;
          typedef const path &             reference;
          typedef std::input_iterator_tag  iterator_category;

          directory_iterator();
          explicit directory_iterator( const path & directory_ph );

          // other functions
          // ...
        };

        bool exists( const path & ph );
        bool symbolic_link_exists( const path & ph );
        bool is_directory( const path & ph );
        bool is_empty( const path & ph );
        bool equivalent( const path & ph1, const path & ph2 );

        boost::intmax_t file_size( const path & ph );

        std::time_t last_write_time( const path & ph );
        void last_write_time( const path & ph, std::time_t new_time );

        bool create_directory( const path & directory_ph );
        bool remove( const path & ph );
        unsigned long remove_all( const path & ph );
        void rename( const path & from_path,
                     const path & to_path );
        void copy_file( const path & source_file,
                        const path & target_file );

        const path & initial_path();
        path current_path();
        path complete( const path & ph,
                       const path & base = initial_path() );
        path system_complete( const path & ph );

      } // namespace filesystem
    } // namespace boost

## Class directory_iterator

Class directory_iterator provides a C++ standard conforming input iterator which accesses the contents of a directory.

The value type is boost::filesystem::path, so dereferencing a directory_iterator yields a path to a file or sub-directory contained within the directory represented by the directory-path argument supplied at construction. The path returned by dereferencing a directory_iterator is composed by appending the name of the directory entry to the directory path supplied at construction.

The order of the path entries returned by dereferencing successive increments of a directory_iterator is unspecified. Thus depending on the ordering provided by a particular implementation will result in non-portable code.

A path returned by dereferencing a directory_iterator is, if representing a directory, suitable for use as an argument to Filesystem Library functions specified as accepting paths or directory paths. If not representing a directory, the dereferenced path is suitable for use as an argument to Filesystem Library functions specified as accepting paths or file paths, or C++ Standard Library functions specified as taking file names. The leaf of a path returned by dereferencing a directory_iterator will never be `".."` or `"."`.

Note: The implication of the above requirement is that if an operating system's directories can contain entries which are not usable by Filesystem Library or Standard Library functions, these entries will be skipped during directory iteration. Such entries are by definition non-portable, but can always be accessed via the native operating system API if required.

Warning: Programs performing directory iteration may wish to test, via exists(), if the path returned by dereferencing an iterator actually exists. It could be a symbolic link to a non-existent file or directory. Programs recursively walking directory trees for purposes of removing and renaming entries may wish to avoid following symbolic links, which can be detected with symbolic_link_exists().

Warning: If a file or sub-directory is removed from or added to a directory after the construction of a directory_iterator for the directory, it is unspecified whether or not subsequent incrementing of the iterator will ever result in an iterator whose value is the removed or added directory entry.

### Constructors

> `directory_iterator();`

> Effects: Constructs a directory_iterator having the past-the-end value as described in the C++ standard, section 24.1.

> `explicit directory_iterator( const path & directory_ph );`

> Effects: Constructs a directory_iterator with a value representing the first path in directory_ph, or if `empty(directory_ph)`, the past-the-end value.

> Throws: if `!exists( directory_ph )`

> Note: To iterate over the current directory, write `directory_iterator(current_path())` rather than `directory_iterator("")`.

### Other functions

Class directory_iterator also supplies all the other functions required by the C++ standard clause 24 for input iterators, such as operator==, operator++, and operator*.

## Non-member functions

The non-member functions provide common operations on files and directories. They follow traditional practice of the C and C++ standard libraries, except that they:

- Traffic in paths rather than `char*`'s, for much enhanced portability.
- Report errors by throwing exceptions, for safer and better error handling.
- Tighten specifications slightly, for improved portability.

Rationale: Functions which already exist in the C++ Standard Library, such as remove() and rename(), retain the same names and general behavior in the Filesystem Library, to minimize surprises.

Rationale: Some errors which might at first glance appear to be preconditions are not specified as such, but instead will throw exceptions. This is because the possibility of race-conditions makes it unreliable to test for preconditions before calling the function. As a design practice, preconditions are not specified when it is not reasonable for a program to test for them before calling the function.

Empty path rationale: Some errors, particularly function arguments of empty paths, are specified both in Precondition and in Throws paragraphs. A non-empty path is specified as a precondition because an empty path is almost certainly an error, the error meets the usual criteria for Preconditions as specified in the C++ Standard clause 17, and user pre-detection of the error does not suffer from the precondition race problem described above. The error condition is also specified in the Throws paragraph to ensure that the error results in well-defined rather than implementation-defined behavior, and because existing practice for the equivalent operating system function is usually to treat an empty path as an error. The intended use of the Filesystem Library in script-like programs makes undefined behavior particularly unattractive.

Naming Rationale: See class path Naming Rationale.

### exists

> `bool exists( const path & ph );`

> Returns: True if the operating system reports the path represented by ph exists, else false.

> Note: Even if `exists( ph ) == true`, there is no guarantee that it will be possible to perform other operations on the file or directory. Access rights or other security concerns, for example, may cause other operations to fail.

> Note: `exists("")` is valid and returns false;

### symbolic_link_exists

> `bool symbolic_link_exists( const path & ph );`

> Returns: True if the operating system reports the path represented by ph is present and is a symbolic link, else false.

> Note: See the directory iterator warning for one use of `symbolic_link_exists()`.

> Note: The Microsoft Windows operating system does not currently support symbolic links, so `symbolic_link_exists()` always returns false on that platform. (Short-cut files (.lnk) are a Windows application feature, not an O/S feature.) Programmers should still test for symbolic links where applicable in case Windows adds the feature, and also so that programs will be portable to systems like POSIX, where symbolic links may be present.

> Rationale: The function does not throw if ph is not present, and is accordingly named `symbolic_link_exists` rather than `is_symbolic_link`. Non-throwing behavior permits testing for all four possible conditions:

> - ph not present: `!exists(ph) && !symbolic_link_exists(ph)`
> - ph present and is not a symbolic link: `exists(ph) && !symbolic_link_exists(ph)`
> - ph present and is a symbolic link to a non-existent file or directory: `!exists(ph) && symbolic_link_exists(ph)`
> - ph present and is a symbolic link to an existing file or directory: `exists(ph) && symbolic_link_exists(ph)`

### is_directory

> `bool is_directory( const path & ph );`

> Returns: True if the operating system reports the path represented by ph is a directory, else false.

> Throws: if `!exists(ph)`

> Rationale: Treating `!exists(ph)` as an exception rather than just returning false came about because in real code `!exists(ph)` has often been the first indicate of a programming error. A compound function returning `exists(ph) && is_directory(ph)` can always be added later.

### is_empty

> `bool is_empty( const path & ph );`

> Returns: True if the operating system reports the path represented by ph is an empty file or empty directory, else false.

> Throws: if `!exists(ph)`

> This function determines if the file or directory identified by the contents of ph is empty. To determine if a path string itself is empty, use the path::empty() function.

### equivalent

>     bool equivalent( const path & ph1, const path & ph2 );

> Returns: `false` if `!exists(ph1) || !exists(ph2)`. Otherwise, returns `true` if ph1 and ph2 resolve to the same file or directory, else `false`. The criteria used to determine sameness are implementation defined:

> > - POSIX: stat() reports identical st_dev, st_ino, st_size, and st_mtime values. The POSIX implementation does not protect against race conditions.
> > - Windows: stat() reports identical st_dev values and GetFileInformationByHandle() reports identical dwVolumeSerialNumber, nFileIndexHigh, nFileIndexLow, nFileSizeHigh, and nFileSizeLow values. Note that for identical media (particularly bit-for-bit duplicate CD's, Floppies, or memory cards) on the same lettered drive of different network shared systems, equivalent() will return `true` even though the media are physically different. The Windows implementation does protect against race conditions.

> Throws: if `!exists(ph1) && !exists(ph2)`

> Warning: This function may be impossible to implement on some operating systems; users may wish to avoid use for code which may be ported to operating systems with limited filesystem support.

### file_size

> `boost::intmax_t file_size( const path & ph );`

> Returns: The size of the file in bytes as reported by the operating system.

> Throws: if `!exists(ph) || is_directory(ph)`

> Warming: If a compiler does not support `maxint_t` large enough to represent the operating system's maximum file size, or if the implementation does not know how to query the operating system for large file sizes, the returned value could be incorrect. This is not a problem with modern compilers on modern versions of Linux or Windows. Users on other platforms should build and run the file_size.cpp sample program against a large file to verify correct operation.

> Rationale: Directories are excluded because the complexity of finding the size of a file is typically constant, while finding the size of a directory is typically linear. It was felt this would be surprising. The function is named accordingly. Users needing the size of a directory can trivially provide a user function which iterates over a directory returning a count.

### last_write_time

> Warning: The times associated with files are subject to many vicissitudes. Each type of filesystem differs slightly in the details and resolution of how times are recorded. The resolution is as low as one hour on some filesystems. It is not uncommon for a program to simultaneously have access to files maintained by FAT, ISO9660, NTFS, and POSIX filesystems, and so experience different last_write_time behavior for different files. During program execution, the system clock may be set to a new value by some other, possibly automatic, process. Another thread or process may write to a file, causing the last write time to change unexpectedly.

> `std::time_t last_write_time( const path & ph );`

> Returns: The time the file was last modified, as reported by the operating system. If the time cannot be determined, returns (std::time_t)(-1).

> To convert the returned value to UTC or local time, use `std::gmtime()` or `std::localtime()` respectively.

> Throws: if `!exists(ph)`

> `void last_write_time( const path & ph, std::time_t new_time );`

> Effects: Asks the operating system to set the last write time to `new_time`, or to the current time if `new_time==std::time_t()`.

> Throws: if `!exists(ph)`

> Rationale: `last_write_time(ph)==new_time` is not specified as a postcondition because the times may differ somewhat on some operating systems.

### create_directory

> `bool create_directory( const path & directory_ph );`

> Precondition: `!directory_ph.empty()`

> Returns: The value of `!exists( directory_ph )` prior to the establishment of the postcondition.

> Postcondition: `exists(directory_ph) && is_directory(directory_ph)`

> Throws: if `directory_ph.empty() || (exists(directory_ph) && !is_directory(directory_ph)) || !exists(directory_ph/"..")`. See empty path rationale.

### remove

> `bool remove( const path & ph );`

> Precondition: `!ph.empty()`

> Returns: The value of `exists( ph )` prior to the establishment of the postcondition.

> Postcondition: `!exists( ph )`

> Throws: if`ph.empty() || (exists(ph) && is_directory(ph) && !is_empty(ph))`. See empty path rationale.

> Note: Symbolic links are themselves deleted, rather than what they point to being deleted.

> Rationale: Does not throw when `!exists( ph )` because not throwing:

> - Works correctly if `ph` is a dangling symbolic link.
> - Is slightly easier-to-use for many common use cases.
> - Is slightly higher-level because it implies use of postcondition semantics rather than effects semantics, which would be specified in the somewhat lower-level terms of interactions with the operating system.

> There is, however, a slight decrease in safety because some errors will slip by which otherwise would have been detected. For example, a misspelled path name could go undetected for a long time.

> The initial version of the library threw an exception when the path did not exist; it was changed to reflect user complaints.

### remove_all

> `unsigned long remove_all( const path & ph );`

> Precondition: `!ph.empty()`

> Postcondition: `!exists( ph ) && !symbolic_link_exists( ph )`

> Returns: The number of files and directories removed.

> Throws: if`ph.empty()`. See empty path rationale.

> Note: Symbolic links are themselves deleted, rather than what they point to being deleted.

### rename

> `void rename( const path & source, const path & target );`

> Precondition: `!source.empty() && !target.empty()`

> Effects: Changes the name of file or directory source to target. Specifically:

> Source | Target | Result is "as if" these actions occur
> !exists() |  | Throw filesystem_error. Note that !exists() covers the source.empty() case. [case 1]
> | target.empty() | Throw filesystem_error. See create_directory() rationale. [case 2]
> | exists() | Throw filesystem_error. [case 3]
> !is_directory() |  | If !exists( target / ".." ) throw filesystem_error. [case 4A] The source.leaf() name is changed to target.leaf(). [case 4B] If source / ".." resolves to a different directory than target / "..", the renamed source file is moved there. [case 4C]
> is_directory() |  | If !exists( target / ".." ) throw filesystem_error. [case 5A] The source.leaf() name is changed to target.leaf(). [case 5B] If system_complete(source.banch_path()) resolves to a different directory than system_complete(target.branch_path()), the renamed source directory is moved there. [case 5C]

> Postconditions: `!exists(source) && exists(target)`, and the source file or directory contents and attributes are otherwise unchanged.

> Throws: See Effects table above. See empty path rationale.

> Rationale: Because rename is logically the same operation as move, there is no need for a separate move function. The choice of the name is based on existing practice in the C, C++, and POSIX libraries, and because the name move implies physical file movement, which does not in fact occur.

> Note: Some operating systems with multiple roots do not allow rename operations between roots, and such an attempted rename with throw a filesystem_error exception.. Implementations should not take heroic efforts, such as switching to a copy mode, to make an otherwise failing rename succeed across roots.

> Note: Symbolic links are themselves renamed, rather than what they point to being renamed.

### copy_file

> `void copy_file( const path & source_file, const path & target_file );`

> Precondition: `!source.empty() && !target.empty()`

> Effects: Copies the file represented by source_file to target_file.

> Throws: if `!exists(source_file) || is_directory(source_file) || exists(target_file) || target_file.empty() || !exists(to_file_path/".."))`. See empty path rationale.

> Note: File attributes are also copied. Specifically, POSIX stat::st_mode, and Windows BY_HANDLE_FILE_INFORMATION::dwFileAttributes.

### initial_path

> `const path & initial_path();`

> Effects: The first time called, stores the path returned by current_path().

> The preferred implementation would be to call initial_path() during program initialization, before the call to main(). This is, however, not possible with changing the C++ runtime library.

> Returns: A reference to the stored path.

> Rationale: The semantics, in effect, turn a dangerous global variable into a safer global constant. The preferred implementation requires runtime library support, so alternate semantics are supplied for those implementations which cannot change an existing the runtime library.

> Note: It is good practice for a program dependent on initial_path() to call it immediately upon entering main(). That protects against another function altering the current working directory (using a native platform function) before the first call to initial_path().

### current_path

>     path current_path();

> Returns: The current path as maintained by the operating system.

> Postcondition: `current_path().is_complete()`

> Note: The equivalent POSIX function is getcwd(). The equivalent Windows function is GetCurrentDirectoryA().

> Warning: The current path maintained by the operating system is in-effect a dangerous global variable. It may be changed unexpectedly by a third-party or system library function, or by another thread. For a safer alternative, see initial_path().

> Rationale: Although dangerous, the function is useful in dealing with other libraries. The current_path() name was chosen to emphasize that the function returns a complete path, not just a single directory name.

### complete

> `path complete( const path & ph, const path & base = initial_path() );`

> Precondition: `!ph.empty() && base.is_complete() && (ph.is_complete() || !ph.has_root_name())`

> Effects: Composes a complete path from `ph` and `base`, using the following rules:

> For single-root operating systems (POSIX-like systems, for example), if `ph.empty()` or `ph.is_complete()`, the composed path is `ph`, otherwise the composed path is `base/ph`.

> For multi-root operating systems (Windows, Classic Mac, many others), the rules are give by this table:

> | `ph.has_root_directory()` | `!ph.has_root_directory()`
> `ph.has_root_name()` | `ph` | `(precondition failure)`
> `!ph.has_root_name()` | `base.root_name() / ph` | `base / ph`

> Returns: The composed path.

> Postcondition: For the returned path, `p,` `p.is_complete()` is true.

> Throws: On precondition failure. See empty path rationale.

> Note: When portable behavior is required, use complete(). When operating system dependent behavior is required, use system_complete().

> Portable behavior is preferred when dealing with paths created internally within a program, particularly where the program should exhibit the same behavior on all operating systems.

> Operating system dependent behavior is preferred when dealing with paths supplied by user input, reported to program users, or which should result in program behavior familiar to and expected by program users. The simple_ls.cpp program, for example, operates on a path supplied in the native operating system format, so uses system_complete() to ensure that the path behaves as expected for the particular operating system.

> Rationale: The `!ph.has_root_name()` portion of the precondition disallows the error condition of `ph.root_name()` being not equivalent to `base.root_name()`. The restriction is broader that would appear necessary, in that is also prohibits the case where they are equivalent. There is, however, no portable way to express the root_name() equivalence requirement.

### system_complete

> `path system_complete( const path & ph );`

> Precondition: `!ph.empty()`

> Effects: Composes a complete path from `ph`, using the same rules used by the operating system to resolve a path passed as the filename argument to standard library open functions.

> For POSIX-like systems, system_complete( ph ) has the same semantics as `complete( ph, current_path() )`.

> For Widows, system_complete( ph ) has the same semantics as `complete( ph, current_path() )` if ph.is_complete() || !ph.has_root_name() or ph and base have the same root_name(). Otherwise it acts like `complete( ph, kinky )`, where `kinky` is the current directory for the `ph.root_name()` drive. This will be the current directory of that drive the last time it was set, and thus may well be residue left over from some prior program run by the command processor! Although these semantics are often useful, they are also very error-prone, and certainly deserve to be called "kinky".

> Returns: The composed path.

> Postcondition: For the returned path, `p,` `p.is_complete()` is true.

> Throws: If `ph.empty()`. See empty path rationale.

> Note: See complete() note for usage suggestions.

> Warning: This function relies on a global variable (current_path()), and so tends to be more error-prone than the similar function complete(). This function is doubly dangerous on Windows, where under cross-drive conditions it may be relying on a directory set by a prior program run by the command processor.

Revised 21 March, 2004

© Copyright Beman Dawes, 2002

Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)