libk  kfile.md at [5393623a84]

File kfile/kfile.md artifact e76252504c part of check-in 5393623a84


# kfile
kfile is libk's file handling library. kfile uses the short naming convention and its sigil is `f`. it is designed to abstract over OS idioms so that developers can write code that simply expresses their intent, and kfile will figure out the correct thing to do on a given platform. to that end, one of kfile's most important functions is `kfplace()` - see below.

## functions

  * `struct kfile kfplace(enum kfplace location, const char* file, enum kfopen mode)` - when you need to open a file in a location that will vary between environments, such as configuration directories, download dirs, image dirs, etc, use `kfplace()` instead of `kfopen()`. the arguments work like `kfopen()`, except that `file` is not a normal path. instead, it specifies a file in the program's configuration directory to open, and the lead constant will tell it what kind of file you are trying to open. in most cases, a null or empty filename is an error, but see `enum kfplace` for exceptions. `file` must not begin with a slash; if they do, `kfcond_bad_domain` will be returned.
  * `kfcond kfget(enum kfplace, ksmut buffer)` - this function will write the prefix for a particular environment directory into `buffer`, or return `kfcond_fail` if `buffer` is not big enough. the best way to use this function is with a for loop; see examples. do not use this to generate paths for file access; use `kfplace()` instead.
  * `struct kfile kfopen(const char* file, enum kfopen mode)` - opens a file at the specified pathname. mode is a bit mask . if null is passed as a filename, a temporary file will be created in the appropriate place, using memfds or similar if available and the system temporary directory otherwise. `mode` is a bit flag; the lowest nine bits represent filesystem permissions to be used when creating a file and the rest control how the file will be opened - at least one of `kf_read` or `kf_write` must be passed. see `enum kfopen`. **do not** use kfopen to attempt direct access to configuration files in root of the user's home directory; libk **will** detect this and instruct your users to file bug reports. use kfplace(kfplace_conf) instead to open files in the configuration directory appropriate to the local environment.
  * `struct kfile kfopens(const ksraw file, enum kfopen mode)` - like kfopen but allows specifying the filename via a `ksraw` string rather than a `const char*`.
  * `kfcond kfset(struct kfile file, enum kfset_mode mode, sz position)` - repositions the read/write head at `position` bytes into the file (if mode is `kfset_top`) or at `position` bytes from the end of the file (if mode is `kfset_end`). attempting to index past the end of the file will return `kfcond_bad_index`. returns `kfcond_ok` on success.
  * `kfcond kfstep(struct kfile file, offset position)` - moves the read/write head `position` bytes ahead if `position` is a positive number, or backwards otherwise. attempting to move past the start or end of the file will move the cursor to the start or end and return `kfcond_overstep`. returns `kfcond_ok` on success.
  * `kfcond kfshred(struct kfile file, sz count)` - write over `file` with random data `count` times, then truncate it.
  * **posix functions** - POSIX has a wide array of nonportable file IO calls that are important particularly with regards to `exec()` and piping data across processes. for this reason, on POSIX platforms, libk exposes these calls to the user.
   * kfposix_pipe() - creates a pipe in memory
   * kfposix_fifo() - creates a named pipe at the specified path

## structs
 * `struct kfile` - represents an open file. a `kfile` struct should always be initialized with `kfopen()` or `kfconf()` before use, or the values it contains will be meaningless and useless!
   * `enum kfile_kind kind` - either `kfile_closed` if the object does not represent an open file, or `kfile_open` if it does
   * `enum kfopen mode` - details about the open file. `kf_new` is only set if the file was created by a `kf_new`-flagged open call
   * `struct kiochan chan` - a channel that can be used to read or write to a file
   * `u8* content` - a pointer to the start of the file in memory, if it is loaded with `kf_map`
   * `sz len` - size of the file as of open. this is not updated by `kiosend()` calls!

## enums

### enum kfplace
`enum kfplace` contains constants that refer to standardized locations that may vary across environments. on POSIX, the XDG specification will be respected to allow the user to select her own directories. unlike `kfopen()`, `kfplace()` will also create any necessary directories if `kf_new` or `kf_create` are passed.

  * `kfplace_conf` - this mode is designed specifically for opening configuration files.  the configuration directory is determined based on OS, environment variables, and the name of the binary; on POSIX OSes, it will use `$XDG_CONFIG_HOME/argv[0]` as the configuration base, cleanly falling back to platform defaults (`$HOME/.config`, and determining home directories based on $USER or failing that UID if `$HOME` is unset). on OSX, it will use `~/Library/argv[0]`. note that if `null` or the empty string are passed as `file`, `kfconf()` will open a file with the name of the configuration base, instead of treating it as a folder to look for configuration files in.
  * `kfplace_home` - open a file in the user's home folder. on POSIX, it will use the value of `$HOME` or get the user's home directory with the appropriate calls if `$HOME` is unset. **THINK CAREFULLY BEFORE USING THIS FUNCTIONALITY - NEVER USE IT FOR STORING CONFIGURATION.** if you use this flag to create dotfiles in the homedir, libk **will** inform the user and instruct her to file a bug report.
  * `kfplace_desk` - open a file on the user's desktop, or failing that, home folder. on POSIX, it will use the value of `XDG_DESKTOP_DIR` in `$XDG_CONFIG_HOME/user-dirs.dirs`; on OSX, it will use `$HOME/Downloads`. the same restriction against dotfiles applies here as well.
  * `kfplace_dl` - open a file in the user's download directory. on POSIX, it will use the value of `XDG_DOWNLOAD_DIR` in `$XDG_CONFIG_HOME/user-dirs.dirs`; on OSX, it will use `$HOME/Downloads`.
  * `kfplace_img` - open a file in the user's image directory. on POSIX, it will use the value of `XDG_PICTURES_DIR` in `$XDG_CONFIG_HOME/user-dirs.dirs`; on OSX, it will use `$HOME/Pictures`.
  * `kfplace_vid` - open a file in the user's video directory. on POSIX, it will use the value of `XDG_VIDEOS_DIR` in `$XDG_CONFIG_HOME/user-dirs.dirs`; on OSX, it will use `$HOME/Movies`.
  * `kfplace_msc` - open a file in the user's video directory. on POSIX, it will use the value of `XDG_MUSIC_DIR` in `$XDG_CONFIG_HOME/user-dirs.dirs`; on OSX, it will use `$HOME/Music`.
  * `kfplace_dat` - open a file in the user data directory, the homedir equivalent of `/usr/share`. on POSIX, it will use the value of `$XDG_DATA_HOME/argv[0]`; on OSX, it will use `$HOME/Library/Application Support/argv[0]`.
  * `kfplace_share` - open a file in the system data directory. this is typified by `/usr/share/argv[0]` on POSIX. on OSX, it will use `/Library/Application Support/argv[0]`.
  * `kfplace_share_global` - like `kfplace_share`, except without the program-specific suffix.
  * `kfplace_cache` - open a file in the user's cache directory. on POSIX, this will generally be `$HOME/.cache/argv[0]`.

### enum kfopen
`enum kfopen` contains flags that may be OR'd together and passed to `kfopen()` to alter its behavior.
  * `kf_read` - opens a file for reading
  * `kf_write` - opens a file for writing
  * `kf_ascii` - opens a file in ascii mode, where available. if not set, the file will be opened in binary mode.
  * `kf_new` - creates a new file with the chosen name if one does not already exist, opening the existing file otherwise
  * `kf_create` - creates a new file with the chosen name if it does not already exist, failing otherwise
  * `kf_load` - loads the file directly into memory, allowing it to be read via indexing into a pointer rather than kiosend() and kiorecv() calls. this is most useful for quickly opening files for reading. if kf_write is also passed, a kiochan will be created to permit writing to the file via standard mechanisms. note: `kf_load` will use mmap() to load the file where possible, but on systems without `mmap()` or `MMAP_SHARED`, `kf_load` will be implemented using standard file IO primitives. for this reason, writing to the region of memory containing the file is implementation-defined behavior. if you really want to be able to modify the file in memory, use `kf_map` instead - it is guaranteed to memory-map the file, but will fail outright on platforms without memory mapping available, so its use is discouraged unless absolutely necessary, or as a platform-specific optimization.
  * `kf_top` - if passed, the kiochan will be positioned at the top of the file. this is the default if kf_read is passed; otherwise, it will be positioned at the end so the file can be appended to.
   * if you wish to read the file with kiorecv() calls: `kf_read | kf_top`
   * if you wish your writes to overwrite what is already present in the file: `kf_write | kf_top`
   * if you wish to append to an existing file: `kf_write | kf_end`
  * `kf_end` - positions the `kiochan` at the end of the file. see above.
  * `kf_wipe` - if a file already exists, erase its contents before writing. to prevent accidental deletions, it is an error to pass `kf_read | kf_wipe`.
  * kfopen also has constants that can be used to spell out file permissions; these are guaranteed to be the standard POSIX octal triple on all platforms. on POSIX platforms, the triple will be passed through to the OS unmodified; on others, libk itself will interpret it.
  * `kf_ur` - represents the owner's permission to read the file
  * `kf_uw` - represents the owner's permission to write to the file
  * `kf_ux` - represents the owner's permission to execute the file
  * `kf_gr` - represents the group's permission to read the file
  * `kf_gw` - represents the group's permission to write to the file
  * `kf_gx` - represents the group's permission to execute the file
  * `kf_or` - represents all other users' permission to read the file
  * `kf_ow` - represents all other users' permission to write to the file
  * `kf_ox` - represents all other users' permission to execute the file

## macros
if `KFclean` is not defined, the following macros will be:

 * `KFsep` is the string used to separate directories in file paths. it will be set to `"\\"` on Windows, `"/"` on POSIX, and so on.

## examples
`kfget()` is somewhat tricky to use. this is a feature, not a bug - there are very few legitimate uses for it and it should not be convenient to use. use `kfplace()` instead.

    for (sz len = 80; len < kf_path_max; len << 2) {
    	char path [len];
    	if (kfget(kfplace_desk, (ksmut){len, path}) != kfcond_ok)
    		continue;
    	kiosend(env.std, (ksraw){len, path}, null);
    	break;
    }