summaryrefslogtreecommitdiff
path: root/src/libk/fsutil.c
diff options
context:
space:
mode:
authordzwdz2023-08-14 18:51:07 +0200
committerdzwdz2023-08-14 18:51:07 +0200
commit642b5fb0007b64c77d186fcb018d571152ee1d47 (patch)
tree1c466461f3602d306be309a053edae558ef2568e /src/libk/fsutil.c
parent8050069c57b729c18c19b1a03ab6e4bf63b4735e (diff)
reorganization: first steps
Diffstat (limited to 'src/libk/fsutil.c')
-rw-r--r--src/libk/fsutil.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/libk/fsutil.c b/src/libk/fsutil.c
new file mode 100644
index 0000000..05ca44a
--- /dev/null
+++ b/src/libk/fsutil.c
@@ -0,0 +1,51 @@
+#include <assert.h>
+#include <camellia/fsutil.h>
+#include <limits.h>
+
+void fs_normslice(long *restrict offset, size_t *restrict length, size_t max, bool expand)
+{
+ assert(max <= (size_t)LONG_MAX);
+
+ if (*offset < 0) {
+ /* Negative offsets are relative to EOF + 1.
+ * Thus:
+ * write(-1) writes right after the file ends; atomic append
+ * write(-n) writes, overriding the last (n-1) bytes
+ * read(-n) reads the last (n-1) bytes
+ */
+ *offset += max + 1;
+ if (*offset < 0) {
+ /* cursor went before the file, EOF */
+ *length = 0;
+ *offset = max;
+ goto end;
+ }
+ }
+
+ if (expand) {
+ /* This is a write() to a file with a dynamic size.
+ * We don't care if it goes past the current size, because the
+ * driver can handle expanding it. */
+ } else {
+ /* This operation can't extend the file, it's either:
+ * - any read()
+ * - a write() to a file with a static size (e.g. a framebuffer)
+ * *offset and *length describe a slice of a buffer with length max,
+ * so their sum must not overflow it. */
+ if ((size_t)*offset <= max) {
+ size_t maxlen = max - (size_t)*offset;
+ if (*length > maxlen)
+ *length = maxlen;
+ } else {
+ /* regular EOF */
+ *length = 0;
+ *offset = max;
+ goto end;
+ }
+ }
+
+end:
+ assert(0 <= *offset);
+ if (!expand)
+ assert(*offset + *length <= max);
+}