Files and directories

#include <libcork/os.h>

The functions in this section let you interact with files and directories in the local filesystem.

Paths

We provide several functions for constructing and handling paths into the local filesystem.

struct cork_path

Represents a path in the local filesystem. The path can be relative or absolute. The paths don’t have to refer to existing files or directories.

struct cork_path *cork_path_new(const char *path)
struct cork_path *cork_path_clone(const struct cork_path *other)

Construct a new path object from the given path string, or as a copy of another path object.

void cork_path_free(struct cork_path *path)

Free a path object.

const char *cork_path_get(const struct cork_path *path)

Return the string content of a path. This is not normalized in any way. The result is guaranteed to be non-NULL, but may refer to an empty string. The return value belongs to the path object; you must not modify the contents of the string, nor should you try to free the underlying memory.

struct cork_path *cork_path_absolute(const struct cork_path *other)
int cork_path_make_absolute(struct cork_path path)

Convert a relative path into an absolute path. The first variant constructs a new path object to hold the result; the second variant overwritesthe contents of path.

If there is a problem obtaining the current working directory, these functions will return an error condition.

struct cork_path *cork_path_join(const struct cork_path *path, const char *more)
struct cork_path *cork_path_join_path(const struct cork_path *path, const struct cork_path *more)
void *cork_path_append(struct cork_path path, const char *more)
void *cork_path_append_path(struct cork_path *path, const struct cork_path *more)

Concatenate two paths together. The join variants create a new path object containing the concatenated results. The append variants overwrite the contents of path with the concatenated results.

struct cork_path *cork_path_basename(const struct cork_path *path)
void *cork_path_set_basename(struct cork_path *path)

Extract the base name of path. This is the portion after the final trailing slash. The first variant constructs a new path object to hold the result; the second variant overwritesthe contents of path.

Note

These functions return a different result than the standard basename(3) function. We consider a trailing slash to be significant, whereas basename(3) does not:

basename("a/b/c/") == "c"
cork_path_basename("a/b/c/") == ""
struct cork_path *cork_path_dirname(const struct cork_path *path)
void *cork_path_set_dirname(struct cork_path *path)

Extract the directory name of path. This is the portion before the final trailing slash. The first variant constructs a new path object to hold the result; the second variant overwritesthe contents of path.

Note

These functions return a different result than the standard dirname(3) function. We consider a trailing slash to be significant, whereas dirname(3) does not:

dirname("a/b/c/") == "a/b"
cork_path_dirname("a/b/c/") == "a/b/c"

Lists of paths

struct cork_path_list

A list of paths in the local filesystem.

struct cork_path_list *cork_path_list_new_empty(void)
struct cork_path_list *cork_path_list_new(const char *list)

Create a new list of paths. The first variant creates a list that is initially empty. The second variant takes in a colon-separated list of paths as a single string, and adds each of those paths to the new list.

void cork_path_list_free(struct cork_path_list *list)

Free a path list.

void cork_path_list_add(struct cork_path_list *list, struct cork_path *path)

Add path to list. The list takes control of the path instance; you must not try to free path yourself.

size_t cork_path_list_size(const struct cork_path_list *list)

Return the number of paths in list.

const struct cork_path *cork_path_list_get(const struct cork_path_list *list, size_t index)

Return the path in list at the given index. The list still owns the path instance that’s returned; you must not try to free it or modify its contents.

const char *cork_path_list_to_string(const struct cork_path_list *list)

Return a string containing all of the paths in list separated by colons.

struct cork_file *cork_path_list_find_file(const struct cork_path_list *list, const char *rel_path)
struct cork_file_list *cork_path_list_find_files(const struct cork_path_list *list, const char *rel_file)

Search for a file in a list of paths. rel_path gives the path of the sought-after file, relative to each of the directories in list.

The first variant returns a cork_file instance for the first match. In no file can be found, it returns NULL and sets an error condition.

The second variant returns a cork_file_list instance containing all of the matches. In no file can be found, we return an empty list. (Unlike the first variant, this is not considered an error.)

Standard paths

struct cork_path *cork_path_home(void)

Return a cork_path that refers to the current user’s home directory. If we can’t determine the current user’s home directory, we set an error condition and return NULL.

On POSIX systems, this directory is determined by the HOME environment variable.

struct cork_path_list *cork_path_config_paths(void)

Return a cork_path_list that includes all of the standard directories that can be used to store configuration files. This includes a user-specific directory that allows the user to override any global configuration files.

On POSIX systems, these directories are defined XDG Base Directory Specification.

struct cork_path_list *cork_path_data_paths(void)

Return a cork_path_list that includes all of the standard directories that can be used to store application data files. This includes a user-specific directory that allows the user to override any global data files.

On POSIX systems, these directories are defined XDG Base Directory Specification.

struct cork_path *cork_path_user_cache_path(void)

Return a cork_path that refers to a directory that can be used to store cache files created on behalf of the current user. This directory should only be used to store data that you can reproduce if needed.

On POSIX systems, these directories are defined XDG Base Directory Specification.

struct cork_path *cork_path_user_runtime_path(void)

Return a cork_path that refers to a directory that can be used to store small runtime management files on behalf of the current user.

On POSIX systems, these directories are defined XDG Base Directory Specification.

Files

struct cork_file

Represents a file on the local filesystem. The file in question does not necessarily have to exist; you can use cork_file instances to refer to files that you have not yet created, for instance.

typedef unsigned int cork_file_mode

Represents a Unix-style file permission set.

struct cork_file *cork_file_new(const char *path)
struct cork_file *cork_file_new_from_path(struct cork_path *path)

Create a new cork_file instance to represent the file with the given path. The _from_path variant uses an existing cork_path instance to specify the path. The new file instance will take control of the :c:type`cork_path` instance, so you should not try to free it yourself.

void cork_file_free(struct cork_file *file)

Free a file instance.

const struct cork_path *cork_file_path(struct cork_file *file)

Return the path of a file. The cork_path instance belongs to the file; you must not try to modify or free the path instance.

int cork_file_exists(struct cork_file *file, bool *exists)

Check whether a file exists in the filesystem, storing the result in exists. The function returns an error condition if we are unable to determine whether the file exists — for instance, because you do not have permission to look into one of the containing directories.

int cork_file_type(struct cork_file *file, enum cork_file_type *type)

Return what kind of file the given cork_file instance refers to. The function returns an error condition if there is an error accessing the file — for instance, because you do not have permission to look into one of the containing directories.

If the function succeeds, it will fill in type with one of the following values:

enum cork_file_type
CORK_FILE_MISSING

file does not exist.

CORK_FILE_REGULAR

file is a regular file.

CORK_FILE_DIRECTORY

file is a directory.

file is a symbolic link.

CORK_FILE_UNKNOWN

We can access file, but we do not know what type of file it is.

int cork_file_remove(struct cork_file *file, unsigned int flags)

Remove file from the filesystem. flags must be the bitwise OR (|) of the following flags. (Use 0 if you do not want any of the flags.)

CORK_FILE_PERMISSIVE

If this flag is given, then it is not considered an error if file does not exist. If the flag is not given, then the function function returns an error if file doesn’t exist. (This mimics the standard rm -f command.)

CORK_FILE_RECURSIVE

If this flag is given, and file refers to a directory, then the function will automatically remove the directory and all of its contents. If the flag is not given, and file refers to a directory, then the directory must be empty for this function to succeed. If file does not refer to a directory, this flag has no effect. (This mimics the standard rmdir -r command.)

Directories

Certain functions can only be applied to a cork_file instance that refers to a directory.

int cork_file_mkdir(struct cork_file *directory, cork_file_mode mode, unsigned int flags)

Create a new directory in the filesystem, with permissions given by mode. flags must be the bitwise OR (|) of the following flags. (Use 0 if you do not want any of the flags.)

CORK_FILE_PERMISSIVE

If this flag is given, then it is not considered an error if directory already exists. If the flag is not given, then the function function returns an error if directory exists. (This mimics part of the standard mkdir -p command.)

CORK_FILE_RECURSIVE

If this flag is given, then the function will ensure that all of the parent directories of directory exist, creating them if necessary. Each directory created will have permissions given by mode. (This mimics part of the standard mkdir -p command.)

int cork_file_iterate_directory(struct cork_file *directory, cork_file_directory_iterator iterator, void *user_data)

Call iterator for each file or subdirectory contained in directory (not including the directory’s . and .. entries). This function does not recurse into any subdirectories; it only iterates through the immediate children of directory.

If your iteration function returns a non-zero result, we will abort the iteration and return that value. Otherwise, if each call to the iteration function returns 0, then we will return 0 as well.

iterator must be an instance of the following function type:

typedef int (*cork_file_directory_iterator)(struct cork_file *child, const char *rel_name, void *user_data)

Called for each child entry in directory. child will be a file instance referring to the child entry. rel_name gives the relative name of the child entry within its parent directory.

Lists of files

struct cork_file_list

A list of files in the local filesystem.

struct cork_file_list *cork_file_list_new_empty(void)
struct cork_file_list *cork_file_list_new(struct cork_path_list *path_list)

Create a new list of files. The first variant creates a list that is initially empty. The second variant adds a new file instance for each of the paths in path_list.

void cork_file_list_free(struct cork_file_list *list)

Free a file list.

void cork_file_list_add(struct cork_file_list *list, struct cork_file *file)

Add file to list. The list takes control of the file instance; you must not try to free file yourself.

size_t cork_file_list_size(const struct cork_file_list *list)

Return the number of files in list.

struct cork_file *cork_file_list_get(const struct cork_file_list *list, size_t index)

Return the file in list at the given index. The list still owns the file instance that’s returned; you must not try to free it.

Directory walking

int cork_walk_directory(const char *path, struct cork_dir_walker *walker)

Walk through the contents of a directory. path can be an absolute or relative path. If it’s relative, it will be interpreted relative to the current directory. If path doesn’t exist, or there are any problems reading the contents of the directory, we’ll set an error condition and return -1.

To process the contents of the directory, you must provide a walker object, which contains several callback methods that we will call when files and subdirectories of path are encountered. Each method should return 0 on success. Unless otherwise noted, if we receive any other return result, we will abort the directory walk, and return that same result from the cork_walk_directory() call itself.

In all of the following methods, base_name will be the base name of the entry within its immediate subdirectory. rel_path will be the relative path of the entry within the path that you originally asked to walk through. full_path will the full path to the entry, including path itself.

struct cork_dir_walker
int (*file)(struct cork_dir_walker *walker, const char *full_path, const char *rel_path, const char *base_name)

Called when a regular file is encountered.

int (*enter_directory)(struct cork_dir_walker *walker, const char *full_path, const char *rel_path, const char *base_name)

Called when a subdirectory of path of encountered. If you don’t want to recurse into this directory, return CORK_SKIP_DIRECTORY.

CORK_SKIP_DIRECTORY
int (*leave_directory)(struct cork_dir_walker *walker, const char *full_path, const char *rel_path, const char *base_name)

Called when a subdirectory has been fully processed.