libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
stream.c
1#include <clod/stream.h>
2#include "syscall.h"
3#include "clod/file.h"
4#include <dirent.h>
5
6int clod_file_stream_close(clod_stream *self);
7int clod_file_stream_read(clod_stream *self, struct clod_string *dst);
8int clod_file_stream_readdir(clod_stream *self, struct clod_string *dst);
9int clod_file_stream_write(clod_stream *self, struct clod_string *src);
10
11#define O_RDONLY 0
12#define O_WRONLY 1
13#define O_RDWR 2
14#define O_CREAT 0100
15#define O_TRUNC 01000
16#define O_APPEND 02000
17#define O_DIRECTORY 0200000
18
20 long int ino;
21 long int off;
22 unsigned short size;
23 unsigned char type;
24 char name[];
25};
26static_assert(offsetof(struct linux_dirent, name) == offsetof(struct clod_dirent, name));
27
28int clod_file(
29 clod_stream *stream_out,
30 const clod_stream *directory,
31 const char *path,
32 const int flags
33) {
34 int o_flags = 0;
35 switch (flags & (CLOD_FILE_READ | CLOD_FILE_WRITE | CLOD_FILE_TRUNCATE | CLOD_FILE_DIRECTORY)) {
36 case CLOD_FILE_READ:
37 o_flags |= O_RDONLY; break;
38 case CLOD_FILE_READ | CLOD_FILE_DIRECTORY:
39 o_flags |= O_RDONLY | O_DIRECTORY; break;
40 case CLOD_FILE_READ | CLOD_FILE_WRITE:
41 o_flags |= O_RDWR; break;
42 case CLOD_FILE_READ | CLOD_FILE_WRITE | CLOD_FILE_TRUNCATE:
43 o_flags |= O_RDWR | O_TRUNC; break;
44 case CLOD_FILE_WRITE:
45 o_flags |= O_WRONLY; break;
46 case CLOD_FILE_WRITE | CLOD_FILE_TRUNCATE:
47 o_flags |= O_WRONLY | O_TRUNC; break;
48 case CLOD_FILE_DIRECTORY:
49 o_flags |= O_DIRECTORY; break;
50
51 default:
52 return CLOD_STREAM_INVALID;
53 }
54
55 if (flags & CLOD_FILE_CREATE) {
56 o_flags |= O_CREAT;
57 }
58
59 if (flags & CLOD_FILE_APPEND) {
60 o_flags |= O_APPEND;
61 }
62
63 long res;
64 if (directory)
65 res = syscall(__NR_openat, (int)(long)directory->impl, (long)path, o_flags, 0664);
66 else
67 res = syscall(__NR_open, (long)path, o_flags, 0664);
68
69 if (res == -EINVAL || res == -EFAULT || res == -EBADF) return CLOD_STREAM_INVALID;
70 if (res == -ENOENT) return CLOD_STREAM_EOF;
71 if (res < 0) return (int)-res;
72
73 stream_out->impl = (uintptr_t)res;
74
75 if (flags & CLOD_FILE_READ) {
76 if (flags & CLOD_FILE_DIRECTORY) {
77 stream_out->read = clod_file_stream_readdir;
78 } else {
79 stream_out->read = clod_file_stream_read;
80 }
81 } else {
82 stream_out->read = nullptr;
83 }
84
85 if (flags & CLOD_FILE_WRITE) {
86 stream_out->write = clod_file_stream_write;
87 } else {
88 stream_out->write = nullptr;
89 }
90
91 stream_out->close = clod_file_stream_close;
92
93 return CLOD_STREAM_OK;
94}
95
96int clod_file_stream_read(clod_stream *self, struct clod_string *dst) {
97 if (dst->cap <= dst->len)
98 return CLOD_STREAM_OK;
99
100 const long ret = syscall(__NR_read, (long)self->impl, (long)(dst->ptr + dst->len), dst->cap - dst->len);
101 if (ret < 0) return (int)-ret;
102 if (ret == 0) {
103 return CLOD_STREAM_EOF;
104 }
105 dst->len += ret;
106 return CLOD_STREAM_OK;
107}
108int clod_file_stream_readdir(clod_stream *self, struct clod_string *dst) {
109 if (dst->cap <= dst->len)
110 return CLOD_STREAM_OK;
111
112 long res = syscall(__NR_getdents64, (long)self->impl, (long)(dst->ptr + dst->len), dst->cap - dst->len);
113 if (res == 0) return CLOD_STREAM_EOF;
114 if (res == -EBADF) return CLOD_STREAM_INVALID;
115 if (res < 0) return (int)-res;
116
117 size_t off = 0;
118 while (off < (size_t)res) {
119 void *ptr = dst->ptr + dst->len + off;
120 const struct linux_dirent ent = *(struct linux_dirent*)ptr;
121 struct clod_dirent *clod_ent = ptr;
122
123 off += ent.size;
124
125 clod_ent->next = off < (size_t)res ? (struct clod_dirent*)((char*)ptr + ent.size) : nullptr;
126 clod_ent->id = (uintptr_t)ent.ino;
127 clod_ent->name_size = ent.size - (unsigned short)offsetof(struct linux_dirent, name) - 1;
128 switch (ent.type) {
129 case DT_DIR: clod_ent->type = CLOD_DIRENT_DIRECTORY; break;
130 case DT_REG: clod_ent->type = CLOD_DIRENT_FILE; break;
131 default: clod_ent->type = ent.type;
132 }
133 }
134 return CLOD_STREAM_OK;
135}
136int clod_file_stream_write(clod_stream *self, struct clod_string *src) {
137 if (src->len == 0)
138 return CLOD_STREAM_OK;
139
140 while (src->len) {
141 const long ret = syscall(__NR_write, (long)self->impl, (long)src->ptr, src->len);
142
143 if (ret > 0) {
144 src->ptr += ret;
145 src->len -= ret;
146 if (src->cap) src->cap -= ret;
147 }
148
149 if (ret < 0) return (int)-ret;
150 }
151
152 return CLOD_STREAM_OK;
153}
154
155int clod_file_stream_close(clod_stream *self) {
156 const long ret = syscall(__NR_close, (long)self->impl);
157 if (ret < 0) return (int)-ret;
158 return CLOD_STREAM_OK;
159}
160
161clod_stream *clod_stdin = &(clod_stream){
162 .impl = 0,
163 .read = clod_file_stream_read,
164 .close = clod_file_stream_close,
165};
166
167clod_stream *clod_stdout = &(clod_stream){
168 .impl = 1,
169 .write = clod_file_stream_write,
170 .close = clod_file_stream_close
171};
172
173clod_stream *clod_stderr = &(clod_stream){
174 .impl = 2,
175 .write = clod_file_stream_write,
176 .close = clod_file_stream_close,
177};
struct clod_dirent * next
Pointer to the next directory entry.
Definition file.h:23
char name[]
Name of the entry.
Definition file.h:35
uintptr_t id
Unique identifier for the entry.
Definition file.h:26
int(* write)(clod_stream *self, struct clod_string *src)
Definition stream.h:88
uintptr_t impl
Definition stream.h:59
int(* read)(clod_stream *self, struct clod_string *dst)
Definition stream.h:72
int(* close)(clod_stream *self)
Definition stream.h:102
char * ptr
Definition string.h:28
ptrdiff_t len
Definition string.h:32
ptrdiff_t cap
Definition string.h:36