Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

File System

File and path utilities: existence checks, permissions, mkdir/rmdir, copy/move, size, mtime, and safe path building.

Source code:

file_exists()

The file_exists() function checks if a given file exists within a specified directory and is a regular file.

BOOL file_exists(
    const char *directory,
    const char *filename
);

Parameters

KeyTypeDescription
directoryconst char *The path to the directory where the file is expected to be located.
filenameconst char *The name of the file to check for existence.

Returns

Returns TRUE if the file exists and is a regular file, otherwise returns FALSE.

Notes

This function constructs the full file path by combining directory and filename, then checks if the file exists and is a regular file using is_regular_file().


file_permission()

The file_permission() function retrieves the permission mode of a specified file path.

mode_t file_permission(const char *path);

Parameters

KeyTypeDescription
pathconst char *The file path whose permission mode is to be retrieved.

Returns

Returns the permission mode of the file as a mode_t value. If the file does not exist or an error occurs, returns 0.

Notes

This function internally uses stat() to obtain the file’s mode and extracts the permission bits using bitwise operations.


file_remove()

file_remove() deletes a specified file from a given directory if it exists and is a regular file.

int file_remove(
    const char *directory,
    const char *filename
);

Parameters

KeyTypeDescription
directoryconst char *The path to the directory containing the file.
filenameconst char *The name of the file to be removed.

Returns

Returns 0 on success, or -1 if the file does not exist or is not a regular file.

Notes

This function checks if the file exists and is a regular file before attempting to delete it.


file_size()

file_size() returns the size of a file in bytes, given its path.

off_t file_size(const char *path);

Parameters

KeyTypeDescription
pathconst char *Path to the file whose size is to be determined.

Returns

Returns the file size in bytes on success. Returns 0 if the file does not exist or an error occurs.

Notes

This function uses stat() to retrieve file information. If stat() fails, the function returns 0.


filesize()

filesize() returns the size of a file in bytes by using the stat() system call.

off_t filesize(const char *path);

Parameters

KeyTypeDescription
pathconst char *Path to the file whose size is to be determined.

Returns

Returns the size of the file in bytes. If the file does not exist or an error occurs, returns 0.

Notes

This function relies on stat(), which can fail if the file does not exist or if there are insufficient permissions.


filesize2()

filesize2() returns the size of an open file descriptor in bytes.

off_t filesize2(int fd);

Parameters

KeyTypeDescription
fdintThe file descriptor of the open file.

Returns

Returns the size of the file in bytes. If an error occurs, returns 0.

Notes

This function uses fstat() to retrieve the file size.


is_directory()

The is_directory() function checks whether the given path corresponds to a directory by using the stat() system call.

BOOL is_directory(const char *path);

Parameters

KeyTypeDescription
pathconst char *The file system path to check.

Returns

Returns TRUE if the path is a directory, otherwise returns FALSE.

Notes

This function relies on stat() to determine the file type. If stat() fails, the function returns FALSE.


is_regular_file()

The is_regular_file() function checks if the given path corresponds to a regular file.

BOOL is_regular_file(const char *path);

Parameters

KeyTypeDescription
pathconst char *The file system path to check.

Returns

Returns TRUE if the path corresponds to a regular file, otherwise returns FALSE.

Notes

[‘This function uses stat() to determine the file type.’, ‘If stat() fails, the function returns FALSE.’]


lock_file()

The lock_file() function applies an advisory write lock to the specified file descriptor using the fcntl system call.

int lock_file(int fd);

Parameters

KeyTypeDescription
fdintThe file descriptor of the file to be locked.

Returns

Returns 0 on success. On failure, returns -1 and sets errno to indicate the error.

Notes

This function uses fcntl with F_SETLKW to apply a blocking write lock. Make sure that the file descriptor is valid before calling this function.


mkrdir()

mkrdir() creates a directory and all its parent directories if they do not exist, similar to the mkdir -p command.

int mkrdir(
    const char *path,
    int xpermission
);

Parameters

KeyTypeDescription
pathconst char *The directory path to be created.
xpermissionintThe permission mode for the created directories.

Returns

Returns 0 on success, or -1 if an error occurs.

Notes

If a directory in the path already exists, it is not modified. The function makes sure that all parent directories are created as needed.

A symbolic link to a directory counts as a directory, as in mkdir -p. These are errors, logged, and the function returns -1:

Up to 7.25.4 the function returned 0 in both cases, with no directory there, and the log of a component in the middle of the path showed an old errno.

A path of PATH_MAX bytes or more is refused: the log is “Path too long, not created”, and the function returns -1. Up to 7.25.4 the path was cut to PATH_MAX without a log, the cut path was created, and the function returned 0.

On -1, errno is the cause, after the function’s own log: the errno of the stat() or mkdir() that failed, ENOTDIR for a component that is not a directory, ENAMETOOLONG for a path too long, EINVAL for an empty one. A caller can log strerror(errno) and name the same cause (see Log: a log leaves errno as it found it). Up to 7.25.4 the log in between could change it, and the callers’ logs said “Success”.

Example

char path[PATH_MAX];
build_path(path, sizeof(path), yuneta_root_dir(), "store", "my_topic", NULL);
if(mkrdir(path, yuneta_xpermission()) < 0) {
    // Error already logged; errno is still the cause
    if(errno == ENOTDIR) {
        // a component of the path is a file
    }
    return -1;
}

newdir()

newdir() creates a new directory with the specified permissions. This makes sure that the umask is set to zero for controlled permission handling.

int newdir(
    const char *path,
    int xpermission
);

Parameters

KeyTypeDescription
pathconst char *The path of the directory to be created.
xpermissionintThe permission mode for the new directory.

Returns

Returns 0 on success, or -1 if an error occurs.

Notes

This function makes sure that the umask is cleared before creating the directory to allow precise permission control.


newfile()

newfile() creates a new file with the specified permissions, optionally overwriting an existing file.

int newfile(
    const char *path,
    int rpermission,
    BOOL overwrite
);

Parameters

KeyTypeDescription
pathconst char *The file path to create.
permissionintThe file permission mode (for example 0660).
overwriteBOOLIf TRUE, an existing file will be truncated. Otherwise, creation fails if the file exists.

Returns

Returns a file descriptor on success, or -1 on failure.

Notes

This function sets umask(0) to make sure that the specified permissions are applied.


open_exclusive()

open_exclusive() opens a file with exclusive access. This makes sure that no other process can lock it simultaneously.

int open_exclusive(
    const char *path,
    int flags,
    int rpermission
);

Parameters

KeyTypeDescription
pathconst char *The file path to be opened.
flagsintFlags for opening the file. If set to 0, default flags (O_RDWR | O_NOFOLLOW) are used.
permissionintThe file permission mode, used when creating a new file.

Returns

Returns a file descriptor on success, or -1 on failure.

Notes

This function applies an exclusive lock (LOCK_EX | LOCK_NB) to the file. This makes sure that no other process can acquire a lock on it.


rmrcontentdir()

The function rmrcontentdir recursively removes the contents of a directory without deleting the directory itself.

int rmrcontentdir(const char *root_dir);

Parameters

KeyTypeDescription
root_dirconst char *Path to the directory whose contents must be removed.

Returns

Returns 0 on success, or -1 if an error occurs.

Notes

This function does not remove the root directory itself, only its contents. It skips special entries like . and .. and handles both files and subdirectories recursively.

A symbolic link inside the directory is removed as a link. The function never goes into it, so the files of the link target stay (see rmrdir()). An entry that another process removes during the walk is not an error. Every failure is logged. A tree that is too long or too deep is refused, as in rmrdir().

A readdir() that fails (EIO, a stale NFS handle) is a removal that fails: the function returns -1 and logs “Cannot remove the content of directory, readdir() FAILED” (or, in a subdirectory, “Cannot remove directory, readdir() FAILED”), with the errno. What was not read yet stays. Up to 7.25.4 the failure was taken as the end of the directory: the function returned 0 with the content still there and nothing logged.

Example

// Empty the cache directory, keep the directory
if(rmrcontentdir("/yuneta/store/cache") < 0) {
    // Error already logged
}

rmrdir()

rmrdir() recursively removes a directory and all its contents, including subdirectories and files.

int rmrdir(
    const char *path
);

Parameters

KeyTypeDescription
pathconst char *The path of the directory to be removed.

Returns

Returns 0 on success, or -1 if an error occurs.

Notes

This function removes all files and subdirectories within the specified directory before deleting the directory itself.

A symbolic link is removed as a link and is never followed:

Up to 7.25.4 the function used stat(), which follows links. A link to a directory made it go into the target and delete the files there, outside the tree. A dangling link made it fail.

A path that does not exist returns -1 without a log, because callers use rmrdir() to make sure that a directory is gone. Every other failure is logged.

An entry inside the tree that another process removes during the walk (between readdir() and lstat()) is already gone, so it is not an error: the walk continues. Up to 7.25.4 that case returned -1 with no log.

An entry that another process makes in a directory while it is walked (after its last readdir(), before its rmdir()) makes the rmdir() fail with ENOTEMPTY: the directory is walked once more, and only a second failure is logged. Up to 7.25.21 the first one was an ERROR, even when the caller’s own retry then removed the directory (a timeranger2 reader closing a feed the master was still linking into).

A readdir() that fails inside the tree returns -1 with “Cannot remove directory, readdir() FAILED” and its errno, and what was not read stays. Up to 7.25.4 the failure was taken as the end of the directory, and the log blamed the rmdir() that followed (“rmdir() FAILED”, ENOTEMPTY).

A tree whose paths do not fit in PATH_MAX, or deeper than 1024 levels, is refused: the log is “Path too long, the tree is not removed” or “Tree too deep, it is not removed”, and the function returns -1. What the walk removed before it stays removed, the rest stays. The walk keeps one path buffer for the whole tree, and one open directory for each level. To remove such a tree, use rm -rf.

Example

char path[PATH_MAX];
build_path(path, sizeof(path), "/yuneta/store", "old_topic", NULL);
if(is_directory(path)) {
    if(rmrdir(path) < 0) {
        // Error already logged
    }
}

subdir_exists()

Checks if a given subdirectory exists within a specified directory.

BOOL subdir_exists(
    const char *directory,
    const char *subdir
);

Parameters

KeyTypeDescription
directoryconst char *The path of the parent directory.
subdirconst char *The name of the subdirectory to check.

Returns

Returns TRUE if the subdirectory exists, otherwise returns FALSE.

Notes

This function constructs the full path of the subdirectory and verifies its existence using is_directory().


unlock_file()

The unlock_file() function releases an advisory lock on a file descriptor using the fcntl system call.

int unlock_file(int fd);

Parameters

KeyTypeDescription
fdintThe file descriptor of the file to be unlocked.

Returns

Returns 0 on success, or -1 if an error occurs.

Notes

This function is typically used in conjunction with lock_file() to manage file locking in multi-process environments.


copyfile()

Copies a file from source to destination using kernel-space operations for efficiency.

int copyfile(
    const char* source,
    const char* destination,
    int permission,
    BOOL overwrite
);

Parameters

KeyTypeDescription
sourceconst char *Path to the source file.
destinationconst char *Path to the destination file.
permissionintThe permission mode for the destination file.
overwriteBOOLIf TRUE, an existing destination file will be overwritten. Otherwise, the copy fails if the file exists.

Returns

Returns 0 on success, or -1 on error.


read_process_cmdline()

Reads the command-line arguments of a process into a buffer.

int read_process_cmdline(
    char *bf,
    size_t bfsize,
    pid_t pid
);

Parameters

KeyTypeDescription
bfchar *Buffer to receive the command-line string.
bfsizesize_tSize of the buffer in bytes.
pidpid_tProcess ID to read. Pass 0 for the current process.

Returns

Returns 0 on success, or -1 on error.

Notes

On Linux, this function reads from /proc/[pid]/cmdline.


set_cloexec()

Sets the FD_CLOEXEC flag on a file descriptor to prevent inheritance by child processes.

int set_cloexec(
    int fd
);

Parameters

KeyTypeDescription
fdintThe file descriptor to modify.

Returns

Returns 0 on success, or -1 on error.


set_nonblocking()

Sets a file descriptor to non-blocking mode.

int set_nonblocking(
    int fd
);

Parameters

KeyTypeDescription
fdintThe file descriptor to set to non-blocking mode.

Returns

Returns 0.