UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 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 <cx/hash_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 CxMap *vfs_type_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_fdopendir, 56 sys_vfs_mkdir, 57 sys_vfs_unlink, 58 sys_vfs_rmdir, 59 VFS_CHECKS_ACL, 60 NULL 61 }; 62 63 static VFS_IO sys_file_io = { 64 sys_file_read, 65 sys_file_write, 66 sys_file_pread, 67 sys_file_pwrite, 68 sys_file_seek, 69 sys_file_close, 70 //sys_file_aioread, 71 //sys_file_aiowrite, 72 NULL, // aioread 73 NULL, // aiowrite 74 NULL // getetag 75 }; 76 77 static VFS_DIRIO sys_dir_io = { 78 sys_dir_read, 79 sys_dir_close 80 }; 81 82 int vfs_init(void) { 83 vfs_type_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); 84 if(!vfs_type_map) { 85 return -1; 86 } 87 return 0; 88 } 89 90 int vfs_register_type(const char *name, vfs_init_func vfsInit, vfs_create_func vfsCreate) { 91 WS_ASSERT(name); 92 93 if(!vfs_type_map) { 94 if(vfs_init()) { 95 return 1; 96 } 97 } 98 99 VfsType *vfsType = malloc(sizeof(VfsType)); 100 if(!vfsType) { 101 return 1; 102 } 103 vfsType->init = vfsInit; 104 vfsType->create = vfsCreate; 105 106 return cxMapPut(vfs_type_map, cx_hash_key_str(name), vfsType); 107 } 108 109 VfsType* vfs_get_type(cxstring vfs_class) { 110 return cxMapGet(vfs_type_map, cx_hash_key_bytes((const unsigned char*)vfs_class.ptr, vfs_class.length)); 111 } 112 113 void* vfs_init_backend(ServerConfiguration *cfg, pool_handle_t *pool, VfsType *vfs_class, WSConfigNode *config, int *error) { 114 *error = 0; 115 if(vfs_class->init) { 116 void *initData = vfs_class->init(cfg, pool, config); 117 if(!initData) { 118 *error = 1; 119 } 120 return initData; 121 } else { 122 return NULL; 123 } 124 } 125 126 VFS* vfs_create(Session *sn, Request *rq, const char *vfs_class, pblock *pb, void *initData) { 127 VfsType *vfsType = cxMapGet(vfs_type_map, cx_hash_key_str(vfs_class)); 128 if(!vfsType) { 129 log_ereport(LOG_MISCONFIG, "vfs_create: unkown VFS type %s", vfs_class); 130 return NULL; 131 } 132 133 return vfsType->create(sn, rq, pb, initData); 134 } 135 136 VFSContext* vfs_request_context(Session *sn, Request *rq) { 137 WS_ASSERT(sn); 138 WS_ASSERT(rq); 139 140 VFSContext *ctx = pool_malloc(sn->pool, sizeof(VFSContext)); 141 if(!ctx) { 142 return NULL; 143 } 144 ctx->sn = sn; 145 ctx->rq = rq; 146 ctx->vfs = rq->vfs ? rq->vfs : &sys_vfs; 147 ctx->user = acllist_getuser(sn, rq, rq->acllist); 148 ctx->acllist = rq->acllist; 149 ctx->aclreqaccess = rq->aclreqaccess; 150 ctx->pool = sn->pool; 151 ctx->vfs_errno = 0; 152 ctx->error_response_set = 0; 153 return ctx; 154 } 155 156 SYS_FILE vfs_open(VFSContext *ctx, const char *path, int oflags) { 157 WS_ASSERT(ctx); 158 WS_ASSERT(path); 159 160 uint32_t access_mask = ctx->aclreqaccess | acl_oflag2mask(oflags); 161 162 // ctx->aclreqaccess should be the complete access mask 163 uint32_t m = ctx->aclreqaccess; // save original access mask 164 ctx->aclreqaccess = access_mask; // set mask for vfs->open call 165 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { 166 // VFS does not evaluates the ACL itself, so we have to do it here 167 SysACL sysacl; 168 if(sys_acl_check(ctx, access_mask, &sysacl)) { 169 return NULL; 170 } 171 } 172 SYS_FILE file = ctx->vfs->open(ctx, path, oflags); 173 ctx->aclreqaccess = m; // restore original access mask 174 if(!file && ctx) { 175 sys_set_error_status(ctx); 176 } 177 return file; 178 } 179 180 SYS_FILE vfs_openRO(VFSContext *ctx, const char *path) { 181 return vfs_open(ctx, path, O_RDONLY); 182 } 183 184 SYS_FILE vfs_openWO(VFSContext *ctx, const char *path) { 185 return vfs_open(ctx, path, O_WRONLY | O_CREAT); 186 } 187 188 SYS_FILE vfs_openRW(VFSContext *ctx, const char *path) { 189 return vfs_open(ctx, path, O_RDONLY | O_WRONLY | O_CREAT); 190 } 191 192 int vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { 193 WS_ASSERT(ctx); 194 WS_ASSERT(path); 195 196 uint32_t access_mask = ctx->aclreqaccess | ACL_READ_ATTRIBUTES; 197 198 // ctx->aclreqaccess should be the complete access mask 199 uint32_t m = ctx->aclreqaccess; // save original access mask 200 ctx->aclreqaccess = access_mask; // set mask for vfs->open call 201 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { 202 // VFS does not evaluates the ACL itself, so we have to do it here 203 SysACL sysacl; 204 if(sys_acl_check(ctx, access_mask, &sysacl)) { 205 return -1; 206 } 207 } 208 int ret = ctx->vfs->stat(ctx, path, buf); 209 ctx->aclreqaccess = m; // restore original access mask 210 if(ret && ctx) { 211 sys_set_error_status(ctx); 212 } 213 return ret; 214 } 215 216 int vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { 217 WS_ASSERT(ctx); 218 WS_ASSERT(fd); 219 WS_ASSERT(buf); 220 221 int ret = ctx->vfs->fstat(ctx, fd, buf); 222 if(ret && ctx) { 223 sys_set_error_status(ctx); 224 } 225 return ret; 226 } 227 228 const char * vfs_getetag(SYS_FILE fd) { 229 WS_ASSERT(fd); 230 231 if(fd->io->opt_getetag) { 232 return fd->io->opt_getetag(fd); 233 } 234 return NULL; 235 } 236 237 void vfs_close(SYS_FILE fd) { 238 WS_ASSERT(fd); 239 240 fd->io->close(fd); 241 if(fd->ctx) { 242 pool_free(fd->ctx->pool, fd); 243 } else { 244 free(fd); 245 } 246 } 247 248 VFS_DIR vfs_opendir(VFSContext *ctx, const char *path) { 249 WS_ASSERT(ctx); 250 WS_ASSERT(path); 251 252 uint32_t access_mask = ctx->aclreqaccess | ACL_LIST; 253 254 // ctx->aclreqaccess should be the complete access mask 255 uint32_t m = ctx->aclreqaccess; // save original access mask 256 ctx->aclreqaccess = access_mask; // set mask for vfs->open call 257 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { 258 // VFS does not evaluates the ACL itself, so we have to do it here 259 SysACL sysacl; 260 if(sys_acl_check(ctx, access_mask, &sysacl)) { 261 return NULL; 262 } 263 } 264 VFS_DIR dir = ctx->vfs->opendir(ctx, path); 265 ctx->aclreqaccess = m; // restore original access mask 266 if(!dir && ctx) { 267 sys_set_error_status(ctx); 268 } 269 return dir; 270 } 271 272 VFS_DIR vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { 273 WS_ASSERT(ctx); 274 WS_ASSERT(path); 275 276 uint32_t access_mask = ctx->aclreqaccess | ACL_LIST; 277 278 // ctx->aclreqaccess should be the complete access mask 279 uint32_t m = ctx->aclreqaccess; // save original access mask 280 ctx->aclreqaccess = access_mask; // set mask for vfs->open call 281 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { 282 // VFS does not evaluates the ACL itself, so we have to do it here 283 SysACL sysacl; 284 if(sys_acl_check(ctx, access_mask, &sysacl)) { 285 return NULL; 286 } 287 } 288 VFS_DIR dir = ctx->vfs->fdopendir(ctx, fd); 289 ctx->aclreqaccess = m; // restore original access mask 290 if(!dir && ctx) { 291 sys_set_error_status(ctx); 292 } 293 return dir; 294 } 295 296 int vfs_readdir(VFS_DIR dir, VFS_ENTRY *entry) { 297 WS_ASSERT(dir); 298 WS_ASSERT(entry); 299 300 return dir->io->readdir(dir, entry, 0); 301 } 302 303 int vfs_readdir_stat(VFS_DIR dir, VFS_ENTRY *entry) { 304 WS_ASSERT(dir); 305 WS_ASSERT(entry); 306 307 return dir->io->readdir(dir, entry, 1); 308 } 309 310 void vfs_closedir(VFS_DIR dir) { 311 WS_ASSERT(dir); 312 313 dir->io->close(dir); 314 if(dir->ctx) { 315 VFS_FREE(dir->ctx->pool, dir); 316 } else { 317 free(dir); 318 } 319 } 320 321 int vfs_mkdir(VFSContext *ctx, const char *path) { 322 WS_ASSERT(ctx); 323 WS_ASSERT(path); 324 325 return vfs_path_op(ctx, path, ctx->vfs->mkdir, ACL_ADD_FILE); 326 } 327 328 int vfs_unlink(VFSContext *ctx, const char *path) { 329 WS_ASSERT(ctx); 330 WS_ASSERT(path); 331 332 return vfs_path_op(ctx, path, ctx->vfs->unlink, ACL_DELETE); 333 } 334 335 int vfs_rmdir(VFSContext *ctx, const char *path) { 336 WS_ASSERT(ctx); 337 WS_ASSERT(path); 338 339 return vfs_path_op(ctx, path, ctx->vfs->rmdir, ACL_DELETE); 340 } 341 342 // private 343 int vfs_path_op(VFSContext *ctx, const char *path, vfs_op_f op, uint32_t access) { 344 uint32_t access_mask = ctx->aclreqaccess; 345 access_mask |= access; 346 347 // ctx->aclreqaccess should be the complete access mask 348 uint32_t m = ctx->aclreqaccess; // save original access mask 349 ctx->aclreqaccess = access_mask; // set mask for vfs function call 350 if((ctx->vfs->flags & VFS_CHECKS_ACL) != VFS_CHECKS_ACL) { 351 // VFS does not evaluates the ACL itself, so we have to do it here 352 SysACL sysacl; 353 if(sys_acl_check(ctx, access_mask, &sysacl)) { 354 return -1; 355 } 356 } 357 int ret = op(ctx, path); 358 ctx->aclreqaccess = m; // restore original access mask 359 if(ret && ctx) { 360 sys_set_error_status(ctx); 361 } 362 return ret; 363 } 364 365 /* system vfs implementation */ 366 367 SYS_FILE sys_vfs_open(VFSContext *ctx, const char *path, int oflags) { 368 uint32_t access_mask = ctx->aclreqaccess; 369 pool_handle_t *pool = ctx->pool; 370 371 // check ACLs 372 SysACL sysacl; 373 if(sys_acl_check(ctx, access_mask, &sysacl)) { 374 return NULL; 375 } 376 377 if(sysacl.acl) { 378 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) { 379 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); 380 return NULL; 381 } 382 } 383 384 // open file 385 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 386 int fd = open(path, oflags, mode); 387 if(fd == -1) { 388 if(ctx) { 389 ctx->vfs_errno = errno; 390 sys_set_error_status(ctx); 391 } 392 return NULL; 393 } 394 395 // if a file system acl is active, we set the owner for newly created files 396 if(((oflags & O_CREAT) == O_CREAT) && sysacl.acl) { 397 if(fchown(fd, sysacl.user_uid, sysacl.user_gid)) { 398 perror("vfs_open: fchown"); 399 system_close(fd); 400 return NULL; 401 } 402 } 403 404 VFSFile *file = VFS_MALLOC(pool, sizeof(VFSFile)); 405 if(!file) { 406 system_close(fd); 407 return NULL; 408 } 409 file->ctx = ctx; 410 file->data = NULL; 411 file->fd = fd; 412 file->io = &sys_file_io; 413 return file; 414 } 415 416 int sys_vfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { 417 uint32_t access_mask = ctx->aclreqaccess; 418 419 // check ACLs 420 SysACL sysacl; 421 if(sys_acl_check(ctx, access_mask, &sysacl)) { 422 return -1; 423 } 424 425 if(sysacl.acl) { 426 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) { 427 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); 428 return -1; 429 } 430 } 431 432 // stat 433 if(stat(path, buf)) { 434 if(ctx) { 435 ctx->vfs_errno = errno; 436 sys_set_error_status(ctx); 437 } 438 return -1; 439 } 440 441 return 0; 442 } 443 444 int sys_vfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { 445 // stat 446 if(fstat(fd->fd, buf)) { 447 if(ctx) { 448 ctx->vfs_errno = errno; 449 } 450 return -1; 451 } 452 453 return 0; 454 } 455 456 VFS_DIR sys_vfs_opendir(VFSContext *ctx, const char *path) { 457 uint32_t access_mask = ctx->aclreqaccess; 458 pool_handle_t *pool = ctx->pool; 459 460 // check ACLs 461 SysACL sysacl; 462 if(sys_acl_check(ctx, access_mask, &sysacl)) { 463 return NULL; 464 } 465 466 if(sysacl.acl) { 467 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) { 468 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); 469 return NULL; 470 } 471 } 472 473 // open directory 474 #ifdef BSD 475 DIR *sys_dir = opendir(path); 476 int dir_fd = sys_dir ? dirfd(sys_dir) : 0; 477 #else 478 int dir_fd = open(path, O_RDONLY); 479 if(dir_fd == -1) { 480 if(ctx) { 481 ctx->vfs_errno = errno; 482 sys_set_error_status(ctx); 483 } 484 return NULL; 485 } 486 DIR *sys_dir = fdopendir(dir_fd); 487 #endif 488 if(!sys_dir) { 489 if(dir_fd > 0) { 490 close(dir_fd); 491 } 492 if(ctx) { 493 ctx->vfs_errno = errno; 494 sys_set_error_status(ctx); 495 } 496 return NULL; 497 } 498 499 SysVFSDir *dir_data = VFS_MALLOC(pool, sizeof(SysVFSDir)); 500 if(!dir_data) { 501 closedir(sys_dir); 502 return NULL; 503 } 504 long maxfilelen = fpathconf(dir_fd, _PC_NAME_MAX); 505 size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1; 506 dir_data->cur = VFS_MALLOC(pool, entry_len); 507 if(!dir_data->cur) { 508 closedir(sys_dir); 509 VFS_FREE(pool, dir_data); 510 return NULL; 511 } 512 dir_data->dir = sys_dir; 513 514 VFSDir *dir = VFS_MALLOC(pool, sizeof(VFSDir)); 515 if(!dir) { 516 closedir(sys_dir); 517 VFS_FREE(pool, dir_data->cur); 518 VFS_FREE(pool, dir_data); 519 return NULL; 520 } 521 dir->ctx = ctx; 522 dir->data = dir_data; 523 dir->fd = dir_fd; 524 dir->io = &sys_dir_io; 525 return dir; 526 } 527 528 VFS_DIR sys_vfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { 529 uint32_t access_mask = ctx->aclreqaccess; 530 pool_handle_t *pool = ctx->pool; 531 532 // check ACLs 533 SysACL sysacl; 534 if(sys_acl_check(ctx, access_mask, &sysacl)) { 535 return NULL; 536 } 537 538 if(sysacl.acl) { 539 if(!fs_acl_check_fd(&sysacl, ctx->user, fd->fd, access_mask)) { 540 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); 541 return NULL; 542 } 543 } 544 545 // open directory 546 DIR *sys_dir = fdopendir(fd->fd); 547 if(!sys_dir) { 548 if(ctx) { 549 ctx->vfs_errno = errno; 550 sys_set_error_status(ctx); 551 } 552 return NULL; 553 } 554 555 SysVFSDir *dir_data = VFS_MALLOC(pool, sizeof(SysVFSDir)); 556 if(!dir_data) { 557 closedir(sys_dir); 558 return NULL; 559 } 560 long maxfilelen = fpathconf(fd->fd, _PC_NAME_MAX); 561 size_t entry_len = offsetof(struct dirent, d_name) + maxfilelen + 1; 562 dir_data->cur = VFS_MALLOC(pool, entry_len); 563 if(!dir_data->cur) { 564 closedir(sys_dir); 565 VFS_FREE(pool, dir_data); 566 return NULL; 567 } 568 dir_data->dir = sys_dir; 569 570 VFSDir *dir = VFS_MALLOC(pool, sizeof(VFSDir)); 571 if(!dir) { 572 closedir(sys_dir); 573 VFS_FREE(pool, dir_data->cur); 574 VFS_FREE(pool, dir_data); 575 return NULL; 576 } 577 dir->ctx = ctx; 578 dir->data = dir_data; 579 dir->fd = fd->fd; 580 dir->io = &sys_dir_io; 581 return dir; 582 } 583 584 int sys_vfs_mkdir(VFSContext *ctx, const char *path) { 585 return sys_path_op(ctx, path, sys_mkdir); 586 } 587 588 int sys_vfs_unlink(VFSContext *ctx, const char *path) { 589 return sys_path_op(ctx, path, sys_unlink); 590 } 591 592 int sys_vfs_rmdir(VFSContext *ctx, const char *path) { 593 return sys_path_op(ctx, path, sys_rmdir); 594 } 595 596 597 int sys_path_op(VFSContext *ctx, const char *path, sys_op_f op) { 598 uint32_t access_mask = ctx->aclreqaccess; 599 600 // check ACLs 601 SysACL sysacl; 602 if(sys_acl_check(ctx, access_mask, &sysacl)) { 603 return -1; 604 } 605 606 if(sysacl.acl) { 607 if(!fs_acl_check(&sysacl, ctx->user, path, access_mask)) { 608 acl_set_error_status(ctx->sn, ctx->rq, sysacl.acl, ctx->user); 609 return -1; 610 } 611 } 612 613 // do path operation 614 if(op(ctx, path, &sysacl)) { 615 // error 616 ctx->vfs_errno = errno; 617 sys_set_error_status(ctx); 618 return -1; 619 } 620 621 return 0; 622 } 623 624 int sys_acl_check(VFSContext *ctx, uint32_t access_mask, SysACL *sysacl) { 625 if(sysacl) { 626 sysacl->acl = NULL; 627 } 628 if(!ctx) { 629 return 0; 630 } 631 632 ACLListHandle *acllist = ctx->acllist; 633 if(acllist) { 634 ACLList *acl = acl_evallist( 635 acllist, 636 ctx->user, 637 access_mask, 638 &sysacl->acl); 639 640 if(acl) { 641 acl_set_error_status(ctx->sn, ctx->rq, acl, ctx->user); 642 return 1; 643 } 644 } 645 646 return 0; 647 } 648 649 void sys_set_error_status(VFSContext *ctx) { 650 if(ctx->sn && ctx->rq && !ctx->error_response_set) { 651 int status = util_errno2status(ctx->vfs_errno); 652 protocol_status(ctx->sn, ctx->rq, status, NULL); 653 ctx->error_response_set = TRUE; 654 } 655 } 656 657 ssize_t sys_file_read(SYS_FILE fd, void *buf, size_t nbyte) { 658 return read(fd->fd, buf, nbyte); 659 } 660 661 ssize_t sys_file_write(SYS_FILE fd, const void *buf, size_t nbyte) { 662 return write(fd->fd, buf, nbyte); 663 } 664 665 ssize_t sys_file_pread(SYS_FILE fd, void *buf, size_t nbyte, off_t offset) { 666 return pread(fd->fd, buf, nbyte, offset); 667 } 668 669 ssize_t sys_file_pwrite(SYS_FILE fd, const void *buf, size_t nbyte, off_t offset) { 670 return pwrite(fd->fd, buf, nbyte, offset); 671 } 672 673 off_t sys_file_seek(SYS_FILE fd, off_t offset, int whence) { 674 return lseek(fd->fd, offset, whence); 675 } 676 677 void sys_file_close(SYS_FILE fd) { 678 system_close(fd->fd); 679 } 680 681 int sys_file_aioread(aiocb_s *aiocb) { 682 WS_ASSERT(aiocb->buf); 683 WS_ASSERT(aiocb->nbytes > 0); 684 return ev_aioread(aiocb->filedes->fd, aiocb); 685 } 686 687 int sys_file_aiowrite(aiocb_s *aiocb) { 688 WS_ASSERT(aiocb->buf); 689 WS_ASSERT(aiocb->nbytes > 0); 690 return ev_aiowrite(aiocb->filedes->fd, aiocb); 691 } 692 693 694 int sys_dir_read(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { 695 SysVFSDir *dirdata = dir->data; 696 struct dirent *result = NULL; 697 int s = readdir_r(dirdata->dir, dirdata->cur, &result); 698 if(!s && result) { 699 char *name = result->d_name; 700 if(!strcmp(name, ".") || !strcmp(name, "..")) { 701 return sys_dir_read(dir, entry, getstat); 702 } else { 703 entry->name = name; 704 if(getstat) { 705 // TODO: check ACLs again for new path 706 entry->stat_errno = 0; 707 if(fstatat(dir->fd, result->d_name, &entry->stat, 0)) { 708 entry->stat_errno = errno; 709 } 710 entry->stat_extra = NULL; 711 } 712 return 1; 713 } 714 } else { 715 return 0; 716 } 717 } 718 719 void sys_dir_close(VFS_DIR dir) { 720 SysVFSDir *dirdata = dir->data; 721 closedir(dirdata->dir); 722 723 pool_handle_t *pool = dir->ctx->pool; 724 if(pool) { 725 pool_free(pool, dirdata->cur); 726 pool_free(pool, dirdata); 727 pool_free(pool, dir); 728 } else { 729 free(dirdata->cur); 730 free(dirdata); 731 free(dir); 732 } 733 } 734 735 int sys_mkdir(VFSContext *ctx, const char *path, SysACL *sysacl) { 736 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 737 int ret = mkdir(path, mode); 738 if(ret == 0) { 739 if(sysacl->user_uid != -1) { 740 if(chown(path, sysacl->user_uid, sysacl->user_gid)) { 741 // TODO: error 742 } 743 } 744 } 745 return ret; 746 } 747 748 int sys_unlink(VFSContext *ctx, const char *path, SysACL *sysacl) { 749 return unlink(path); 750 } 751 752 int sys_rmdir(VFSContext *ctx, const char *path, SysACL *sysacl) { 753 return rmdir(path); 754 } 755 756 /* public file api */ 757 758 NSAPI_PUBLIC int system_fread(SYS_FILE fd, void *buf, int nbyte) { 759 return fd->io->read(fd, buf, nbyte); 760 } 761 762 NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, const void *buf, int nbyte) { 763 return fd->io->write(fd, buf, nbyte); 764 } 765 766 NSAPI_PUBLIC int system_pread(SYS_FILE fd, void *buf, int nbyte, off_t offset) { 767 return fd->io->pread(fd, buf, nbyte, offset); 768 } 769 770 NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, const void *buf, int nbyte, off_t offset) { 771 return fd->io->pwrite(fd, buf, nbyte, offset); 772 } 773 774 NSAPI_PUBLIC off_t system_lseek(SYS_FILE fd, off_t offset, int whence) { 775 return fd->io->seek(fd, offset, whence); 776 } 777 778 NSAPI_PUBLIC int system_fclose(SYS_FILE fd) { 779 vfs_close(fd); 780 return 0; 781 } 782 783 NSAPI_PUBLIC int vfs_is_sys(VFS *vfs) { 784 if(!vfs) return 1; 785 if(vfs == &sys_vfs) return 1; 786 return 0; 787 } 788 789 // AIO API 790 791 NSAPI_PUBLIC int system_aio_read(aiocb_s *aiocb) { 792 if(!aiocb->event || !aiocb->evhandler) { 793 return -1; 794 } 795 796 SYS_FILE file = aiocb->filedes; 797 aiocb->event->object = (intptr_t)aiocb; 798 if(file->io->opt_aioread) { 799 return file->io->opt_aioread(aiocb); 800 } else { 801 vfs_queue_aio(aiocb, VFS_AIO_READ); 802 return 0; 803 } 804 } 805 806 NSAPI_PUBLIC int system_aio_write(aiocb_s *aiocb) { 807 if(!aiocb->event || !aiocb->evhandler) { 808 return -1; 809 } 810 811 SYS_FILE file = aiocb->filedes; 812 aiocb->event->object = (intptr_t)aiocb; 813 if(file->io->opt_aiowrite) { 814 return file->io->opt_aiowrite(aiocb); 815 } else { 816 vfs_queue_aio(aiocb, VFS_AIO_WRITE); 817 return 0; 818 } 819 } 820 821 static void* vfs_aio_read(aiocb_s *aiocb) { 822 int result = system_pread(aiocb->filedes, aiocb->buf, aiocb->nbytes, aiocb->offset); 823 aiocb->result = result; 824 if(result < 0) { 825 aiocb->result_errno = errno; 826 } 827 event_send(aiocb->evhandler, aiocb->event); 828 return NULL; 829 } 830 831 static void* vfs_aio_write(aiocb_s *aiocb) { 832 int result = system_pwrite(aiocb->filedes, aiocb->buf, aiocb->nbytes, aiocb->offset); 833 aiocb->result = result; 834 if(result < 0) { 835 aiocb->result_errno = errno; 836 } 837 event_send(aiocb->evhandler, aiocb->event); 838 return NULL; 839 } 840 841 void vfs_queue_aio(aiocb_s *aiocb, VFSAioOp op) { 842 threadpool_t *pool = get_default_iopool(); // TODO: use specific IOPool 843 if(op == VFS_AIO_READ) { 844 threadpool_run(pool, (job_callback_f)vfs_aio_read, aiocb); 845 } else if(VFS_AIO_WRITE) { 846 threadpool_run(pool, (job_callback_f)vfs_aio_write, aiocb); 847 } 848 } 849