| 1487 | } |
| 1488 | |
| 1489 | int __syscall_fcntl64(int fd, int cmd, ...) { |
| 1490 | auto fileTable = wasmFS.getFileTable().locked(); |
| 1491 | auto openFile = fileTable.getEntry(fd); |
| 1492 | if (!openFile) { |
| 1493 | return -EBADF; |
| 1494 | } |
| 1495 | |
| 1496 | switch (cmd) { |
| 1497 | case F_DUPFD: { |
| 1498 | int newfd; |
| 1499 | va_list v1; |
| 1500 | va_start(v1, cmd); |
| 1501 | newfd = va_arg(v1, int); |
| 1502 | va_end(v1); |
| 1503 | if (newfd < 0) { |
| 1504 | return -EINVAL; |
| 1505 | } |
| 1506 | |
| 1507 | // Find the first available fd at arg or after. |
| 1508 | // TODO: Should we check for a limit on the max FD number, if we have one? |
| 1509 | while (1) { |
| 1510 | if (!fileTable.getEntry(newfd)) { |
| 1511 | (void)fileTable.setEntry(newfd, openFile); |
| 1512 | return newfd; |
| 1513 | } |
| 1514 | newfd++; |
| 1515 | } |
| 1516 | } |
| 1517 | case F_GETFD: |
| 1518 | case F_SETFD: |
| 1519 | // FD_CLOEXEC makes no sense for a single process. |
| 1520 | return 0; |
| 1521 | case F_GETFL: |
| 1522 | return openFile->locked().getFlags(); |
| 1523 | case F_SETFL: { |
| 1524 | int flags; |
| 1525 | va_list v1; |
| 1526 | va_start(v1, cmd); |
| 1527 | flags = va_arg(v1, int); |
| 1528 | va_end(v1); |
| 1529 | |
| 1530 | auto lockedOpenFile = openFile->locked(); |
| 1531 | auto oldFlags = lockedOpenFile.getFlags(); |
| 1532 | // This syscall should ignore most flags. |
| 1533 | int mask = O_APPEND | O_NONBLOCK | O_ASYNC | O_DIRECT | O_NOATIME; |
| 1534 | lockedOpenFile.setFlags((oldFlags & ~mask) | (flags & mask)); |
| 1535 | return 0; |
| 1536 | } |
| 1537 | case F_GETLK: { |
| 1538 | // If these constants differ then we'd need a case for both. |
| 1539 | static_assert(F_GETLK == F_GETLK64); |
| 1540 | flock* data; |
| 1541 | va_list v1; |
| 1542 | va_start(v1, cmd); |
| 1543 | data = va_arg(v1, flock*); |
| 1544 | va_end(v1); |
| 1545 | // We're always unlocked for now, until we implement byte-range locks. |
| 1546 | data->l_type = F_UNLCK; |