1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #define _POSIX_PTHREAD_SEMANTIS
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <aio.h>
36 #include <ucx/map.h>
37
38 #include "../util/pool.h"
39 #include "netsite.h"
40 #include "acl.h"
41 #include "vfs.h"
42 #include "threadpools.h"
43 #include "event.h"
44
45 #define VFS_MALLOC(pool, size) pool ? pool_malloc(pool, size) : malloc(size)
46 #define VFS_FREE(pool, ptr) pool ? pool_free(pool, ptr) : free(ptr)
47
48 static UcxMap *vfs_map;
49
50 static VFS sys_vfs = {
51 sys_vfs_open,
52 sys_vfs_stat,
53 sys_vfs_fstat,
54 sys_vfs_opendir,
55 sys_vfs_mkdir,
56 sys_vfs_unlink,
57 VFS_CHECKS_ACL
58 };
59
60 static VFS_IO sys_file_io = {
61 sys_file_read,
62 sys_file_write,
63 sys_file_pread,
64 sys_file_pwrite,
65 sys_file_seek,
66 sys_file_close,
67
68
69 NULL,
70 NULL
71 };
72
73 static VFS_DIRIO sys_dir_io = {
74 sys_dir_read,
75 sys_dir_close
76 };
77
78 int vfs_init() {
79 vfs_map = ucx_map_new(
16);
80 if(!vfs_map) {
81 return -
1;
82 }
83 return 0;
84 }
85
86 void vfs_add(
char *name,
VFS *vfs) {
87 WS_ASSERT(name);
88
89 if(!vfs_map) {
90 vfs_init();
91 }
92 ucx_map_cstr_put(vfs_map, name, vfs);
93 }
94
95 VFSContext* vfs_request_context(Session *sn, Request *rq) {
96 WS_ASSERT(sn);
97 WS_ASSERT(rq);
98
99 VFSContext *ctx = pool_malloc(sn->pool,
sizeof(VFSContext));
100 ctx->sn = sn;
101 ctx->rq = rq;
102 ctx->vfs = rq->vfs ? rq->vfs : &sys_vfs;
103 ctx->user = acllist_getuser(sn, rq, rq->acllist);
104 ctx->acllist = rq->acllist;
105 ctx->aclreqaccess = rq->aclreqaccess;
106 ctx->pool = sn->pool;
107 ctx->vfs_errno =
0;
108 return ctx;
109 }
110
111 SYS_FILE vfs_open(VFSContext *ctx,
char *path,
int oflags) {
112 WS_ASSERT(ctx);
113 WS_ASSERT(path);
114
115 uint32_t access_mask = ctx->aclreqaccess | acl_oflag2mask(oflags);
116
117
118 uint32_t m = ctx->aclreqaccess;
119 ctx->aclreqaccess = access_mask;
120 if((ctx->vfs->flags &
VFS_CHECKS_ACL) !=
VFS_CHECKS_ACL) {
121
122 SysACL sysacl;
123 if(sys_acl_check(ctx, access_mask, &sysacl)) {
124 return NULL;
125 }
126 }
127 SYS_FILE file = ctx->vfs->open(ctx, path, oflags);
128 ctx->aclreqaccess = m;
129 return file;
130 }
131
132 SYS_FILE vfs_openRO(VFSContext *ctx,
char *path) {
133 return vfs_open(ctx, path,
O_RDONLY);
134 }
135
136 SYS_FILE vfs_openWO(VFSContext *ctx,
char *path) {
137 return vfs_open(ctx, path,
O_WRONLY |
O_CREAT);
138 }
139
140 SYS_FILE vfs_openRW(VFSContext *ctx,
char *path) {
141 return vfs_open(ctx, path,
O_RDONLY |
O_WRONLY |
O_CREAT);
142 }
143
144 int vfs_stat(VFSContext *ctx,
char *path,
struct stat *buf) {
145 WS_ASSERT(ctx);
146 WS_ASSERT(path);
147
148 uint32_t access_mask = ctx->aclreqaccess |
ACL_READ_ATTRIBUTES;
149
150
151 uint32_t m = ctx->aclreqaccess;
152 ctx->aclreqaccess = access_mask;
153 if((ctx->vfs->flags &
VFS_CHECKS_ACL) !=
VFS_CHECKS_ACL) {
154
155 SysACL sysacl;
156 if(sys_acl_check(ctx, access_mask, &sysacl)) {
157 return -
1;
158 }
159 }
160 int ret = ctx->vfs->stat(ctx, path, buf);
161 ctx->aclreqaccess = m;
162 return ret;
163 }
164
165 int vfs_fstat(VFSContext *ctx,
SYS_FILE fd,
struct stat *buf) {
166 WS_ASSERT(ctx);
167 WS_ASSERT(fd);
168 WS_ASSERT(buf);
169
170 return ctx->vfs->fstat(ctx, fd, buf);
171 }
172
173 void vfs_close(
SYS_FILE fd) {
174 WS_ASSERT(fd);
175
176 fd->io->close(fd);
177 if(fd->ctx) {
178 pool_free(fd->ctx->pool, fd);
179 }
else {
180 free(fd);
181 }
182 }
183
184 VFS_DIR vfs_opendir(VFSContext *ctx,
char *path) {
185 WS_ASSERT(ctx);
186 WS_ASSERT(path);
187
188 uint32_t access_mask = ctx->aclreqaccess |
ACL_LIST;
189
190
191 uint32_t m = ctx->aclreqaccess;
192 ctx->aclreqaccess = access_mask;
193 if((ctx->vfs->flags &
VFS_CHECKS_ACL) !=
VFS_CHECKS_ACL) {
194
195 SysACL sysacl;
196 if(sys_acl_check(ctx, access_mask, &sysacl)) {
197 return NULL;
198 }
199 }
200 VFS_DIR dir = ctx->vfs->opendir(ctx, path);
201 ctx->aclreqaccess = m;
202 return dir;
203 }
204
205 int vfs_readdir(
VFS_DIR dir,
VFS_ENTRY *entry) {
206 WS_ASSERT(dir);
207 WS_ASSERT(entry);
208
209 return dir->io->readdir(dir, entry,
0);
210 }
211
212 int vfs_readdir_stat(
VFS_DIR dir,
VFS_ENTRY *entry) {
213 WS_ASSERT(dir);
214 WS_ASSERT(entry);
215
216 return dir->io->readdir(dir, entry,
1);
217 }
218
219 void vfs_closedir(
VFS_DIR dir) {
220 WS_ASSERT(dir);
221
222 dir->io->close(dir);
223 if(dir->ctx) {
224 VFS_FREE(dir->ctx->pool, dir);
225 }
else {
226 free(dir);
227 }
228 }
229
230 int vfs_mkdir(VFSContext *ctx,
char *path) {
231 WS_ASSERT(ctx);
232 WS_ASSERT(path);
233
234 return vfs_path_op(ctx, path, ctx->vfs->mkdir,
ACL_ADD_FILE);
235 }
236
237 int vfs_unlink(VFSContext *ctx,
char *path) {
238 WS_ASSERT(ctx);
239 WS_ASSERT(path);
240
241 return vfs_path_op(ctx, path, ctx->vfs->unlink,
ACL_DELETE);
242 }
243
244
245
246 int vfs_path_op(VFSContext *ctx,
char *path, vfs_op_f op,
uint32_t access) {
247 uint32_t access_mask = ctx->aclreqaccess;
248 access_mask |= access;
249
250
251 uint32_t m = ctx->aclreqaccess;
252 ctx->aclreqaccess = access_mask;
253 if((ctx->vfs->flags &
VFS_CHECKS_ACL) !=
VFS_CHECKS_ACL) {
254
255 SysACL sysacl;
256 if(sys_acl_check(ctx, access_mask, &sysacl)) {
257 return -
1;
258 }
259 }
260 int ret = op(ctx, path);
261 ctx->aclreqaccess = m;
262 return ret;
263 }
264
265
266
267 SYS_FILE sys_vfs_open(VFSContext *ctx,
char *path,
int oflags) {
268 uint32_t access_mask = ctx->aclreqaccess;
269 pool_handle_t *pool = ctx->pool;
270
271
272 SysACL sysacl;
273 if(sys_acl_check(ctx, access_mask, &sysacl)) {
274 return NULL;
275 }
276
277 if(sysacl.acl) {
278 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) {
279 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user);
280 return NULL;
281 }
282 }
283
284
285 mode_t mode =
S_IRUSR |
S_IWUSR |
S_IRGRP |
S_IROTH;
286 int fd = open(path, oflags, mode);
287 if(fd == -
1) {
288 if(ctx) {
289 ctx->vfs_errno = errno;
290 sys_set_error_status(ctx);
291 }
292 return NULL;
293 }
294
295
296 if(((oflags &
O_CREAT) ==
O_CREAT) && sysacl.user_uid != -
1) {
297 if(fchown(fd, sysacl.user_uid, sysacl.user_gid)) {
298 perror(
"vfs_open: fchown");
299 system_close(fd);
300 return NULL;
301 }
302 }
303
304 VFSFile *file =
VFS_MALLOC(pool,
sizeof(VFSFile));
305 if(!file) {
306 system_close(fd);
307 return NULL;
308 }
309 file->ctx = ctx;
310 file->data =
NULL;
311 file->fd = fd;
312 file->io = &sys_file_io;
313 return file;
314 }
315
316 int sys_vfs_stat(VFSContext *ctx,
char *path,
struct stat *buf) {
317 uint32_t access_mask = ctx->aclreqaccess;
318
319
320 SysACL sysacl;
321 if(sys_acl_check(ctx, access_mask, &sysacl)) {
322 return -
1;
323 }
324
325 if(sysacl.acl) {
326 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) {
327 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user);
328 return -
1;
329 }
330 }
331
332
333 if(stat(path, buf)) {
334 if(ctx) {
335 ctx->vfs_errno = errno;
336 sys_set_error_status(ctx);
337 }
338 return -
1;
339 }
340
341 return 0;
342 }
343
344 int sys_vfs_fstat(VFSContext *ctx,
SYS_FILE fd,
struct stat *buf) {
345
346 if(fstat(fd->fd, buf)) {
347 if(ctx) {
348 ctx->vfs_errno = errno;
349 }
350 return -
1;
351 }
352
353 return 0;
354 }
355
356 VFS_DIR sys_vfs_opendir(VFSContext *ctx,
char *path) {
357 uint32_t access_mask = ctx->aclreqaccess;
358 pool_handle_t *pool = ctx->pool;
359
360
361 SysACL sysacl;
362 if(sys_acl_check(ctx, access_mask, &sysacl)) {
363 return NULL;
364 }
365
366 if(sysacl.acl) {
367 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) {
368 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user);
369 return NULL;
370 }
371 }
372
373
374 #ifdef BSD
375 DIR *sys_dir = opendir(path);
376 int dir_fd = sys_dir ? dirfd(sys_dir) :
0;
377 #else
378 int dir_fd = open(path,
O_RDONLY);
379 if(dir_fd == -
1) {
380 if(ctx) {
381 ctx->vfs_errno = errno;
382 sys_set_error_status(ctx);
383 }
384 return NULL;
385 }
386 DIR *sys_dir = fdopendir(dir_fd);
387 #endif
388 if(!sys_dir) {
389 if(ctx) {
390 ctx->vfs_errno = errno;
391 sys_set_error_status(ctx);
392 }
393 return NULL;
394 }
395
396 SysVFSDir *dir_data =
VFS_MALLOC(pool,
sizeof(SysVFSDir));
397 if(!dir_data) {
398 closedir(sys_dir);
399 return NULL;
400 }
401 long maxfilelen = fpathconf(dir_fd,
_PC_NAME_MAX);
402 size_t entry_len = offsetof(
struct dirent, d_name) + maxfilelen +
1;
403 dir_data->cur =
VFS_MALLOC(pool, entry_len);
404 if(!dir_data->cur) {
405 closedir(sys_dir);
406 VFS_FREE(pool, dir_data);
407 return NULL;
408 }
409 dir_data->dir = sys_dir;
410
411 VFSDir *dir =
VFS_MALLOC(pool,
sizeof(VFSDir));
412 if(!dir) {
413 closedir(sys_dir);
414 VFS_FREE(pool, dir_data->cur);
415 VFS_FREE(pool, dir_data);
416 return NULL;
417 }
418 dir->ctx = ctx;
419 dir->data = dir_data;
420 dir->fd = dir_fd;
421 dir->io = &sys_dir_io;
422 return dir;
423 }
424
425 int sys_vfs_mkdir(VFSContext *ctx,
char *path) {
426 return sys_path_op(ctx, path, sys_mkdir);
427 }
428
429 int sys_vfs_unlink(VFSContext *ctx,
char *path) {
430 return sys_path_op(ctx, path, sys_unlink);
431 }
432
433
434 int sys_path_op(VFSContext *ctx,
char *path, sys_op_f op) {
435 uint32_t access_mask = ctx->aclreqaccess;
436
437
438 SysACL sysacl;
439 if(sys_acl_check(ctx, access_mask, &sysacl)) {
440 return -
1;
441 }
442
443 if(sysacl.acl) {
444 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) {
445 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user);
446 return -
1;
447 }
448 }
449
450
451 if(op(ctx, path, &sysacl)) {
452
453 ctx->vfs_errno = errno;
454 sys_set_error_status(ctx);
455 return -
1;
456 }
457
458 return 0;
459 }
460
461 int sys_acl_check(VFSContext *ctx,
uint32_t access_mask, SysACL *sysacl) {
462 if(sysacl) {
463 sysacl->acl =
NULL;
464 }
465 if(!ctx) {
466 return 0;
467 }
468
469 ACLListHandle *acllist = ctx->acllist;
470 if(acllist) {
471 ACLList *acl = acl_evallist(
472 acllist,
473 ctx->user,
474 access_mask,
475 &sysacl->acl);
476
477 if(acl) {
478 acl_set_error_status(ctx->sn, ctx->rq, acl, ctx->user);
479 return 1;
480 }
481 }
482
483 return 0;
484 }
485
486 void sys_set_error_status(VFSContext *ctx) {
487 if(ctx->sn && ctx->rq) {
488 int status = util_errno2status(ctx->vfs_errno);
489 protocol_status(ctx->sn, ctx->rq, status,
NULL);
490 }
491 }
492
493 ssize_t sys_file_read(
SYS_FILE fd,
void *buf,
size_t nbyte) {
494 return read(fd->fd, buf, nbyte);
495 }
496
497 ssize_t sys_file_write(
SYS_FILE fd,
const void *buf,
size_t nbyte) {
498 return write(fd->fd, buf, nbyte);
499 }
500
501 ssize_t sys_file_pread(
SYS_FILE fd,
void *buf,
size_t nbyte,
off_t offset) {
502 return pread(fd->fd, buf, nbyte, offset);
503 }
504
505 ssize_t sys_file_pwrite(
SYS_FILE fd,
const void *buf,
size_t nbyte,
off_t offset) {
506 return pwrite(fd->fd, buf, nbyte, offset);
507 }
508
509 off_t sys_file_seek(
SYS_FILE fd,
off_t offset,
int whence) {
510 return lseek(fd->fd, offset, whence);
511 }
512
513 void sys_file_close(
SYS_FILE fd) {
514 system_close(fd->fd);
515 }
516
517 int sys_file_aioread(aiocb_s *aiocb) {
518 WS_ASSERT(aiocb->buf);
519 WS_ASSERT(aiocb->nbytes >
0);
520 return ev_aioread(aiocb->filedes->fd, aiocb);
521 }
522
523 int sys_file_aiowrite(aiocb_s *aiocb) {
524 WS_ASSERT(aiocb->buf);
525 WS_ASSERT(aiocb->nbytes >
0);
526 return ev_aiowrite(aiocb->filedes->fd, aiocb);
527 }
528
529
530 int sys_dir_read(
VFS_DIR dir,
VFS_ENTRY *entry,
int getstat) {
531 SysVFSDir *dirdata = dir->data;
532 struct dirent *result =
NULL;
533 int s = readdir_r(dirdata->dir, dirdata->cur, &result);
534 if(!s && result) {
535 char *name = result->d_name;
536 if(!strcmp(name,
".") || !strcmp(name,
"..")) {
537 return sys_dir_read(dir, entry, getstat);
538 }
else {
539 entry->name = name;
540 if(getstat) {
541
542 if(fstatat(dir->fd, result->d_name, &entry->stat,
0)) {
543 entry->stat_errno = errno;
544 }
545 entry->stat_extra =
NULL;
546 }
547 return 1;
548 }
549 }
else {
550 return 0;
551 }
552 }
553
554 void sys_dir_close(
VFS_DIR dir) {
555 SysVFSDir *dirdata = dir->data;
556 closedir(dirdata->dir);
557
558 pool_handle_t *pool = dir->ctx->pool;
559 if(pool) {
560 pool_free(pool, dirdata->cur);
561 pool_free(pool, dirdata);
562 pool_free(pool, dir);
563 }
else {
564 free(dirdata->cur);
565 free(dirdata);
566 free(dir);
567 }
568 }
569
570 int sys_mkdir(VFSContext *ctx,
char *path, SysACL *sysacl) {
571 mode_t mode =
S_IRWXU |
S_IRGRP |
S_IXGRP |
S_IROTH |
S_IXOTH;
572 int ret = mkdir(path, mode);
573 if(ret ==
0) {
574 if(sysacl->user_uid != -
1) {
575 if(chown(path, sysacl->user_uid, sysacl->user_gid)) {
576
577 }
578 }
579 }
580 return ret;
581 }
582
583 int sys_unlink(VFSContext *ctx,
char *path, SysACL *sysacl) {
584 return unlink(path);
585 }
586
587
588
589 NSAPI_PUBLIC int system_fread(
SYS_FILE fd,
void *buf,
int nbyte) {
590 return fd->io->read(fd, buf, nbyte);
591 }
592
593 NSAPI_PUBLIC int system_fwrite(
SYS_FILE fd,
const void *buf,
int nbyte) {
594 return fd->io->write(fd, buf, nbyte);
595 }
596
597 NSAPI_PUBLIC int system_pread(
SYS_FILE fd,
void *buf,
int nbyte,
off_t offset) {
598 return fd->io->pread(fd, buf, nbyte, offset);
599 }
600
601 NSAPI_PUBLIC int system_pwrite(
SYS_FILE fd,
const void *buf,
int nbyte,
off_t offset) {
602 return fd->io->pwrite(fd, buf, nbyte, offset);
603 }
604
605 NSAPI_PUBLIC off_t system_lseek(
SYS_FILE fd,
off_t offset,
int whence) {
606 return fd->io->seek(fd, offset, whence);
607 }
608
609 NSAPI_PUBLIC int system_fclose(
SYS_FILE fd) {
610 vfs_close(fd);
611 return 0;
612 }
613
614
615
616 NSAPI_PUBLIC int system_aio_read(aiocb_s *aiocb) {
617 if(!aiocb->event || !aiocb->evhandler) {
618 return -
1;
619 }
620
621 SYS_FILE file = aiocb->filedes;
622 aiocb->event->object = (
intptr_t)aiocb;
623 if(file->io->opt_aioread) {
624 return file->io->opt_aioread(aiocb);
625 }
else {
626 vfs_queue_aio(aiocb,
VFS_AIO_READ);
627 return 0;
628 }
629 }
630
631 NSAPI_PUBLIC int system_aio_write(aiocb_s *aiocb) {
632 if(!aiocb->event || !aiocb->evhandler) {
633 return -
1;
634 }
635
636 SYS_FILE file = aiocb->filedes;
637 aiocb->event->object = (
intptr_t)aiocb;
638 if(file->io->opt_aiowrite) {
639 return file->io->opt_aiowrite(aiocb);
640 }
else {
641 vfs_queue_aio(aiocb,
VFS_AIO_WRITE);
642 return 0;
643 }
644 }
645
646 static void* vfs_aio_read(aiocb_s *aiocb) {
647 int result = system_pread(aiocb->filedes, aiocb->buf, aiocb->nbytes, aiocb->offset);
648 aiocb->result = result;
649 if(result <
0) {
650 aiocb->result_errno = errno;
651 }
652 event_send(aiocb->evhandler, aiocb->event);
653 return NULL;
654 }
655
656 static void* vfs_aio_write(aiocb_s *aiocb) {
657 int result = system_pwrite(aiocb->filedes, aiocb->buf, aiocb->nbytes, aiocb->offset);
658 aiocb->result = result;
659 if(result <
0) {
660 aiocb->result_errno = errno;
661 }
662 event_send(aiocb->evhandler, aiocb->event);
663 return NULL;
664 }
665
666 void vfs_queue_aio(aiocb_s *aiocb, VFSAioOp op) {
667 threadpool_t *pool = get_default_iopool();
668 if(op ==
VFS_AIO_READ) {
669 threadpool_run(pool, (job_callback_f)vfs_aio_read, aiocb);
670 }
else if(
VFS_AIO_WRITE) {
671 threadpool_run(pool, (job_callback_f)vfs_aio_write, aiocb);
672 }
673 }
674