6 Module N_FILES
gullradriel edited this page 2026-10-29 20:54:40 +01:00

FILES: files utilies

Structures

Name
struct N_FILE_INFO
common file information

Functions

Name
int n_scan_dir(const char * dir, LIST * result, const int recurse)
scan a directory and store file information in the result list
void n_free_file_info(void * ptr)
free a N_FILE_INFO structure
int n_file_write_atomic(const char * path, const unsigned char * data, size_t len, int mode)
durably and atomically write len bytes to path: write a ".tmp" sibling created with mode from the outset (POSIX; 0 or Windows = leave default), flush it to stable storage, then atomically rename it over path (MoveFileEx REPLACE_EXISTING
int n_file_same_content(const char * a, const char * b)
Do two files hold the same bytes.
int n_file_read_bounded(const char * path, size_t max_size, unsigned char ** out, size_t * out_len)
read a whole file into a freshly allocated, NUL-terminated buffer, refusing a file larger than max_size bytes.
int n_file_free_space(const char * path, uint64_t * bytes)
Space left for this user on the filesystem that holds a path.
int n_file_copy_verified(const char * from, const char * to, size_t * copied)
Copy a file, check the copy against the original, and only then give it its name.

Functions Documentation

function n_scan_dir

int n_scan_dir(
    const char * dir,
    LIST * result,
    const int recurse
)

scan a directory and store file information in the result list

Parameters:

  • dir Directory to scan (non-NULL)
  • result LIST to fill (non-NULL)
  • recurse TRUE/FALSE recursion flag

Return: TRUE on success, FALSE on fatal error.

Scan a directory and append only regular files into a sorted list (oldest first).

scan a directory and store file information in the result list

This function:

  • Opens dir with opendir()
  • Iterates entries via readdir()
  • Builds full path for each entry (no chdir())
  • Uses stat() to detect file type and modification time
  • If recursion enabled and entry is a directory, scans it recursively
  • If entry is a regular file, pushes an allocated N_FILE_INFO into result, keeping result sorted by n_comp_file_info (oldest -> newest).

Error handling:

  • If opendir() fails: returns FALSE.
  • If stat() fails for an entry: logs and continues.
  • If readdir() fails: logs and returns FALSE.

function n_free_file_info

void n_free_file_info(
    void * ptr
)

free a N_FILE_INFO structure

Parameters:

Cross-platform directory scanning (Linux / Solaris / Windows via MinGW) WITHOUT chdir().

free a N_FILE_INFO structure

This implementation uses ONLY POSIX-style APIs:

  • opendir / readdir / closedir
  • stat

MinGW provides these APIs on Windows, so no WinAPI (FindFirstFile...) is required.

Sorting:

  • Files are inserted sorted by modification time (mtime), oldest first.
  • Comparator uses seconds then nanoseconds (if available).

Notes:

  • This version stores FULL PATH in N_FILE_INFO->name so recursion is unambiguous. If you prefer basename only, replace strdup(fullpath) with strdup(entry->d_name).

helper to free N_FILE_INFO structs

function n_file_write_atomic

int n_file_write_atomic(
    const char * path,
    const unsigned char * data,
    size_t len,
    int mode
)

durably and atomically write len bytes to path: write a ".tmp" sibling created with mode from the outset (POSIX; 0 or Windows = leave default), flush it to stable storage, then atomically rename it over path (MoveFileEx REPLACE_EXISTING|WRITE_THROUGH on Windows, which replaces an existing target where the CRT rename() would fail).

A crash leaves either the old file or the new one, never a truncated file. Returns TRUE on success, FALSE otherwise (the temp file is removed on failure).

function n_file_same_content

int n_file_same_content(
    const char * a,
    const char * b
)

Do two files hold the same bytes.

Parameters:

  • a first file
  • b second file

Return: TRUE when both can be read and are equal, FALSE otherwise

function n_file_read_bounded

int n_file_read_bounded(
    const char * path,
    size_t max_size,
    unsigned char ** out,
    size_t * out_len
)

read a whole file into a freshly allocated, NUL-terminated buffer, refusing a file larger than max_size bytes.

On success *out receives the malloc'd buffer (free with Free()/free()) and *out_len its byte length (0 for an empty file). Returns TRUE on success, FALSE on a NULL argument, an unreadable file, or one exceeding max_size.

function n_file_free_space

int n_file_free_space(
    const char * path,
    uint64_t * bytes
)

Space left for this user on the filesystem that holds a path.

Parameters:

  • path an existing file or folder on that filesystem
  • bytes receives the free bytes; 0 on failure
  • path an existing file or folder on that filesystem
  • bytes receives the bytes an unprivileged process may still write

Return:

  • TRUE on success, FALSE on a NULL argument or a path the system cannot look up (logged)
  • TRUE on success, FALSE on a NULL argument or a path the system cannot look up

space left for this user on the filesystem that holds a path

What an unprivileged process may still write there: statvfs()'s f_bavail on POSIX, which leaves out the blocks kept for root, and the caller's share from GetDiskFreeSpaceExA() on Windows, quotas included. For a file not written yet, pass its folder. Space left for this user on the filesystem that holds a path.

function n_file_copy_verified

int n_file_copy_verified(
    const char * from,
    const char * to,
    size_t * copied
)

Copy a file, check the copy against the original, and only then give it its name.

Parameters:

  • from the original, opened read only
  • to where the copy goes; its folder must exist
  • copied receives the number of bytes copied on success; may be NULL

Return: TRUE when a verified copy is at to, FALSE otherwise (the reason is logged)

For a backup that has to be trusted. The copy is written to ".part", flushed to stable storage, closed, then read back from disk and compared with the original byte for byte; only a copy that compares equal is renamed to to. A copy that failed or differs is removed, so to is either absent or a verified copy, never a partial one. to is never replaced: an existing file makes the call fail, and the caller decides whether that file is the same one (see n_file_same_content()) or needs another name. Streams in blocks; memory does not grow with the file.