libk  kfile.md at [c0e04b9015]

File mod/kfile/kfile.md artifact e76252504c part of check-in c0e04b9015


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;
}