File kfile/kfile.md artifact e76252504c part of check-in d77ef26adf
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, usekfplace()
instead ofkfopen()
. the arguments work likekfopen()
, except thatfile
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 seeenum 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 intobuffer
, or returnkfcond_fail
ifbuffer
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; usekfplace()
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 ofkf_read
orkf_write
must be passed. seeenum 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 aksraw
string rather than aconst char*
.kfcond kfset(struct kfile file, enum kfset_mode mode, sz position)
- repositions the read/write head atposition
bytes into the file (if mode iskfset_top
) or atposition
bytes from the end of the file (if mode iskfset_end
). attempting to index past the end of the file will returnkfcond_bad_index
. returnskfcond_ok
on success.kfcond kfstep(struct kfile file, offset position)
- moves the read/write headposition
bytes ahead ifposition
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 returnkfcond_overstep
. returnskfcond_ok
on success.kfcond kfshred(struct kfile file, sz count)
- write overfile
with random datacount
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. akfile
struct should always be initialized withkfopen()
orkfconf()
before use, or the values it contains will be meaningless and useless!enum kfile_kind kind
- eitherkfile_closed
if the object does not represent an open file, orkfile_open
if it doesenum kfopen mode
- details about the open file.kf_new
is only set if the file was created by akf_new
-flagged open callstruct kiochan chan
- a channel that can be used to read or write to a fileu8* content
- a pointer to the start of the file in memory, if it is loaded withkf_map
sz len
- size of the file as of open. this is not updated bykiosend()
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 ifnull
or the empty string are passed asfile
,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 ofXDG_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 ofXDG_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 ofXDG_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 ofXDG_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 ofXDG_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
- likekfplace_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;
}