summaryrefslogtreecommitdiff
path: root/src/shared/fsutil.c
diff options
context:
space:
mode:
authordzwdz2022-07-29 16:16:24 +0200
committerdzwdz2022-07-29 16:16:24 +0200
commitc6424fbc55298399f133ca1ede11e1f0b4a5c824 (patch)
treed8dd1c160a7184a99ea3c72779dce95b4bbee692 /src/shared/fsutil.c
parenta0b16620e1699504e8d21a481e019dec40d7ee1b (diff)
use a shared fs_normslice() function to handle offsets
Diffstat (limited to 'src/shared/fsutil.c')
-rw-r--r--src/shared/fsutil.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/shared/fsutil.c b/src/shared/fsutil.c
new file mode 100644
index 0000000..a1dabfd
--- /dev/null
+++ b/src/shared/fsutil.c
@@ -0,0 +1,55 @@
+#include <camellia/fsutil.h>
+#include <limits.h>
+
+// TODO shared assert
+#define assert(...) {}
+
+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 = *offset = 0;
+ 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 (true || *length > maxlen)
+ *length = maxlen;
+ } else {
+ /* regular EOF */
+ *length = *offset = 0;
+ goto end;
+ }
+ }
+
+end:
+ if (*length > 0) {
+ assert(0 <= *offset);
+ if (!expand)
+ assert(*offset + *length <= max);
+ } else {
+ /* EOF, *offset is undefined. */
+ }
+}