feat: implement utime libc function, SYS_UTIME syscall, filesystem support (ext2 only)
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 94
|
#define MONTAUK_BUILD_NUMBER 95
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <Memory/Paging.hpp>
|
#include <Memory/Paging.hpp>
|
||||||
#include <Libraries/Memory.hpp>
|
#include <Libraries/Memory.hpp>
|
||||||
#include <Ipc/Ipc.hpp>
|
#include <Ipc/Ipc.hpp>
|
||||||
|
#include <Timekeeping/Time.hpp>
|
||||||
#include "Path.hpp"
|
#include "Path.hpp"
|
||||||
|
|
||||||
namespace montauk::abi {
|
namespace montauk::abi {
|
||||||
@@ -133,6 +134,18 @@ namespace montauk::abi {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Sys_Utime(const char* path, int64_t atime, int64_t mtime,
|
||||||
|
bool useCurrent) {
|
||||||
|
char resolved[256];
|
||||||
|
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
|
||||||
|
if (useCurrent) {
|
||||||
|
int64_t now = Timekeeping::GetUnixTimestamp();
|
||||||
|
atime = now;
|
||||||
|
mtime = now;
|
||||||
|
}
|
||||||
|
return Fs::Vfs::VfsSetTimes(resolved, atime, mtime);
|
||||||
|
}
|
||||||
|
|
||||||
static int Sys_FMkdir(const char* path) {
|
static int Sys_FMkdir(const char* path) {
|
||||||
char resolved[256];
|
char resolved[256];
|
||||||
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
|
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
|
||||||
|
|||||||
@@ -174,6 +174,12 @@ namespace montauk::abi {
|
|||||||
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
|
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
|
||||||
if (!UserMemory::Writable<FileStat>(frame->arg2)) return -1;
|
if (!UserMemory::Writable<FileStat>(frame->arg2)) return -1;
|
||||||
return (int64_t)Sys_Stat((const char*)frame->arg1, (FileStat*)frame->arg2);
|
return (int64_t)Sys_Stat((const char*)frame->arg1, (FileStat*)frame->arg2);
|
||||||
|
case SYS_UTIME:
|
||||||
|
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
|
||||||
|
return (int64_t)Sys_Utime((const char*)frame->arg1,
|
||||||
|
(int64_t)frame->arg2,
|
||||||
|
(int64_t)frame->arg3,
|
||||||
|
frame->arg4 != 0);
|
||||||
case SYS_TERMSIZE:
|
case SYS_TERMSIZE:
|
||||||
return (int64_t)Sys_TermSize();
|
return (int64_t)Sys_TermSize();
|
||||||
case SYS_GETARGS:
|
case SYS_GETARGS:
|
||||||
|
|||||||
@@ -310,6 +310,9 @@ namespace montauk::abi {
|
|||||||
/* Keyboard.hpp */
|
/* Keyboard.hpp */
|
||||||
static constexpr uint64_t SYS_GETCHAR_NB = 166; // () -> ascii, 0 if nothing pending; never blocks
|
static constexpr uint64_t SYS_GETCHAR_NB = 166; // () -> ascii, 0 if nothing pending; never blocks
|
||||||
|
|
||||||
|
// Set path access/modification times. (path, atime, mtime, useCurrent)
|
||||||
|
static constexpr uint64_t SYS_UTIME = 167;
|
||||||
|
|
||||||
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
|
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
|
||||||
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
|
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
|
||||||
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
|
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ namespace Fs {
|
|||||||
.GetLabel = RdGetLabel,
|
.GetLabel = RdGetLabel,
|
||||||
.ReadDirAt = RdReadDirAt,
|
.ReadDirAt = RdReadDirAt,
|
||||||
.Stat = RdStat,
|
.Stat = RdStat,
|
||||||
|
.SetTimes = nullptr,
|
||||||
// Statically allocated: nothing to release.
|
// Statically allocated: nothing to release.
|
||||||
.Unmount = nullptr,
|
.Unmount = nullptr,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1234,6 +1234,31 @@ namespace Fs::Ext2 {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int SetTimesImpl(int inst, const char* path, int64_t atime, int64_t mtime) {
|
||||||
|
if (InstanceAt(inst) == nullptr) return -4;
|
||||||
|
if (atime < 0 || atime > 0xFFFFFFFFLL ||
|
||||||
|
mtime < 0 || mtime > 0xFFFFFFFFLL) return -3;
|
||||||
|
auto& self = g_instances[inst];
|
||||||
|
|
||||||
|
uint32_t inodeNum;
|
||||||
|
Inode inode;
|
||||||
|
if (!TraversePath(self, path, &inodeNum, &inode)) return -1;
|
||||||
|
|
||||||
|
inode.i_atime = (uint32_t)atime;
|
||||||
|
inode.i_mtime = (uint32_t)mtime;
|
||||||
|
inode.i_ctime = Ext2Now();
|
||||||
|
if (!WriteInode(self, inodeNum, &inode)) return -4;
|
||||||
|
|
||||||
|
// Open files cache their inode. Keep every alias coherent so a later
|
||||||
|
// write through an existing handle cannot restore stale metadata.
|
||||||
|
for (int i = 0; i < MaxFilesPerInstance; i++) {
|
||||||
|
if (self.files[i].inUse && self.files[i].inodeNum == inodeNum) {
|
||||||
|
self.files[i].inode = inode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ReadImpl(int inst, int handle, uint8_t* buffer,
|
static int ReadImpl(int inst, int handle, uint8_t* buffer,
|
||||||
uint64_t offset, uint64_t size) {
|
uint64_t offset, uint64_t size) {
|
||||||
if (InstanceAt(inst) == nullptr) return -1;
|
if (InstanceAt(inst) == nullptr) return -1;
|
||||||
@@ -1830,6 +1855,7 @@ namespace Fs::Ext2 {
|
|||||||
static int DrvRename(void* c, const char* o, const char* n) { return RenameImpl(CtxToInst(c), o, n); }
|
static int DrvRename(void* c, const char* o, const char* n) { return RenameImpl(CtxToInst(c), o, n); }
|
||||||
static const char* DrvGetLabel(void* c) { return GetLabelImpl(CtxToInst(c)); }
|
static const char* DrvGetLabel(void* c) { return GetLabelImpl(CtxToInst(c)); }
|
||||||
static int DrvStat(void* c, const char* p, Vfs::StatInfo* o) { return StatImpl(CtxToInst(c), p, o); }
|
static int DrvStat(void* c, const char* p, Vfs::StatInfo* o) { return StatImpl(CtxToInst(c), p, o); }
|
||||||
|
static int DrvSetTimes(void* c, const char* p, int64_t a, int64_t m) { return SetTimesImpl(CtxToInst(c), p, a, m); }
|
||||||
|
|
||||||
// Release everything the mount owns. The driver is either not registered
|
// Release everything the mount owns. The driver is either not registered
|
||||||
// yet, or the VFS has deactivated its drive and drained dispatches.
|
// yet, or the VFS has deactivated its drive and drained dispatches.
|
||||||
@@ -2040,6 +2066,7 @@ namespace Fs::Ext2 {
|
|||||||
.GetLabel = DrvGetLabel,
|
.GetLabel = DrvGetLabel,
|
||||||
.ReadDirAt = DrvReadDirAt,
|
.ReadDirAt = DrvReadDirAt,
|
||||||
.Stat = DrvStat,
|
.Stat = DrvStat,
|
||||||
|
.SetTimes = DrvSetTimes,
|
||||||
.Unmount = DrvUnmount,
|
.Unmount = DrvUnmount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2099,6 +2099,7 @@ namespace Fs::Fat32 {
|
|||||||
.GetLabel = DrvGetLabel,
|
.GetLabel = DrvGetLabel,
|
||||||
.ReadDirAt = DrvReadDirAt,
|
.ReadDirAt = DrvReadDirAt,
|
||||||
.Stat = DrvStat,
|
.Stat = DrvStat,
|
||||||
|
.SetTimes = nullptr,
|
||||||
.Unmount = DrvUnmount,
|
.Unmount = DrvUnmount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -307,6 +307,21 @@ namespace Fs::Vfs {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VfsSetTimes(const char* path, int64_t atime, int64_t mtime) {
|
||||||
|
int drive;
|
||||||
|
const char* localPath;
|
||||||
|
|
||||||
|
if (!ParsePath(path, drive, localPath)) return -1;
|
||||||
|
|
||||||
|
vfsLock.Acquire();
|
||||||
|
FsDriver* driver = DriverForLocked(drive);
|
||||||
|
int result = (driver != nullptr && driver->SetTimes != nullptr)
|
||||||
|
? driver->SetTimes(driver->ctx, localPath, atime, mtime)
|
||||||
|
: -2;
|
||||||
|
vfsLock.Release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int VfsMkdir(const char* path) {
|
int VfsMkdir(const char* path) {
|
||||||
int drive;
|
int drive;
|
||||||
const char* localPath;
|
const char* localPath;
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ namespace Fs::Vfs {
|
|||||||
// Optional: fill metadata for a path. Drivers that leave this null do
|
// Optional: fill metadata for a path. Drivers that leave this null do
|
||||||
// not support stat and VfsStat returns -1 for their paths.
|
// not support stat and VfsStat returns -1 for their paths.
|
||||||
int (*Stat)(void* ctx, const char* path, StatInfo* out);
|
int (*Stat)(void* ctx, const char* path, StatInfo* out);
|
||||||
|
// Optional: set access and modification times for a path. Return 0 on
|
||||||
|
// success, -1 for a missing path, -3 for an unrepresentable time, or
|
||||||
|
// -4 for an I/O error. A null hook yields -2 (unsupported).
|
||||||
|
int (*SetTimes)(void* ctx, const char* path, int64_t atime, int64_t mtime);
|
||||||
// Optional: release everything this mount owns, including the FsDriver
|
// Optional: release everything this mount owns, including the FsDriver
|
||||||
// itself. Called either when registration fails, before the driver has
|
// itself. Called either when registration fails, before the driver has
|
||||||
// become reachable, or by UnregisterDrive once the slot is deactivated
|
// become reachable, or by UnregisterDrive once the slot is deactivated
|
||||||
@@ -90,6 +94,7 @@ namespace Fs::Vfs {
|
|||||||
|
|
||||||
int VfsDelete(const char* path);
|
int VfsDelete(const char* path);
|
||||||
int VfsStat(const char* path, StatInfo& out);
|
int VfsStat(const char* path, StatInfo& out);
|
||||||
|
int VfsSetTimes(const char* path, int64_t atime, int64_t mtime);
|
||||||
int VfsReadDir(const char* path, const char** outNames, int maxEntries);
|
int VfsReadDir(const char* path, const char** outNames, int maxEntries);
|
||||||
int VfsReadDirAt(const char* path, const char** outNames, int maxEntries, int startIndex);
|
int VfsReadDirAt(const char* path, const char** outNames, int maxEntries, int startIndex);
|
||||||
int VfsMkdir(const char* path);
|
int VfsMkdir(const char* path);
|
||||||
|
|||||||
@@ -27,5 +27,6 @@
|
|||||||
|
|
||||||
#define PATH_MAX 4096
|
#define PATH_MAX 4096
|
||||||
#define NAME_MAX 256
|
#define NAME_MAX 256
|
||||||
|
#define OPEN_MAX 128
|
||||||
|
|
||||||
#endif /* _LIBC_LIMITS_H */
|
#endif /* _LIBC_LIMITS_H */
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ struct utimbuf {
|
|||||||
time_t modtime;
|
time_t modtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Accepted for POSIX compatibility; the Montauk VFS does not support
|
/* Set access and modification times. Currently supported on ext2. */
|
||||||
setting file times. */
|
|
||||||
int utime(const char *path, const struct utimbuf *times);
|
int utime(const char *path, const struct utimbuf *times);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
+82
-25
@@ -118,6 +118,7 @@ static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
|
|||||||
#define SYS_DUPHANDLE 98
|
#define SYS_DUPHANDLE 98
|
||||||
#define SYS_KILL 62
|
#define SYS_KILL 62
|
||||||
#define SYS_STAT 152
|
#define SYS_STAT 152
|
||||||
|
#define SYS_UTIME 167
|
||||||
|
|
||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
errno
|
errno
|
||||||
@@ -2019,10 +2020,15 @@ done:
|
|||||||
fcntl.h / unistd.h POSIX-style file I/O
|
fcntl.h / unistd.h POSIX-style file I/O
|
||||||
======================================================================== */
|
======================================================================== */
|
||||||
|
|
||||||
/* fd position tracking for POSIX read/write (MontaukOS uses explicit offsets) */
|
/* fd position tracking for POSIX read/write (MontaukOS uses explicit offsets).
|
||||||
#define _FD_POS_MAX 64
|
OPEN_MAX is part of the userspace ABI and matches the kernel handle table. */
|
||||||
|
#define _FD_POS_MAX OPEN_MAX
|
||||||
static unsigned long _fd_pos[_FD_POS_MAX];
|
static unsigned long _fd_pos[_FD_POS_MAX];
|
||||||
|
|
||||||
|
static int _fd_pos_valid(int fd) {
|
||||||
|
return fd >= 0 && fd < _FD_POS_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
int access(const char *path, int mode) {
|
int access(const char *path, int mode) {
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -2069,7 +2075,12 @@ int open(const char *path, int flags, ...) {
|
|||||||
h = (int)_zos_syscall1(SYS_FCREATE, (long)path);
|
h = (int)_zos_syscall1(SYS_FCREATE, (long)path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h >= 0 && h < _FD_POS_MAX) {
|
if (h >= _FD_POS_MAX) {
|
||||||
|
_zos_syscall1(SYS_CLOSE, (long)h);
|
||||||
|
errno = EMFILE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (h >= 0) {
|
||||||
_fd_pos[h] = 0;
|
_fd_pos[h] = 0;
|
||||||
if (flags & O_APPEND) {
|
if (flags & O_APPEND) {
|
||||||
_fd_pos[h] = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)h);
|
_fd_pos[h] = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)h);
|
||||||
@@ -2110,9 +2121,14 @@ int read(int fd, void *buf, size_t count) {
|
|||||||
return (int)i;
|
return (int)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0;
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long pos = _fd_pos[fd];
|
||||||
int ret = (int)_zos_syscall4(SYS_READ, (long)fd, (long)buf, (long)pos, (long)count);
|
int ret = (int)_zos_syscall4(SYS_READ, (long)fd, (long)buf, (long)pos, (long)count);
|
||||||
if (ret > 0 && fd >= 0 && fd < _FD_POS_MAX)
|
if (ret > 0)
|
||||||
_fd_pos[fd] += (unsigned long)ret;
|
_fd_pos[fd] += (unsigned long)ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2127,9 +2143,14 @@ int write(int fd, const void *buf, size_t count) {
|
|||||||
return (int)count;
|
return (int)count;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0;
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long pos = _fd_pos[fd];
|
||||||
int ret = (int)_zos_syscall4(SYS_FWRITE, (long)fd, (long)buf, (long)pos, (long)count);
|
int ret = (int)_zos_syscall4(SYS_FWRITE, (long)fd, (long)buf, (long)pos, (long)count);
|
||||||
if (ret > 0 && fd >= 0 && fd < _FD_POS_MAX)
|
if (ret > 0)
|
||||||
_fd_pos[fd] += (unsigned long)ret;
|
_fd_pos[fd] += (unsigned long)ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2184,20 +2205,37 @@ int ftruncate(int fd, long length) {
|
|||||||
* offset is genuinely left alone.
|
* offset is genuinely left alone.
|
||||||
*/
|
*/
|
||||||
ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
|
ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
|
||||||
if (buf == NULL || offset < 0) return -1;
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (buf == NULL || offset < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return (ssize_t)_zos_syscall4(SYS_READ, (long)fd, (long)buf,
|
return (ssize_t)_zos_syscall4(SYS_READ, (long)fd, (long)buf,
|
||||||
(long)offset, (long)count);
|
(long)offset, (long)count);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) {
|
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) {
|
||||||
if (buf == NULL || offset < 0) return -1;
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (buf == NULL || offset < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return (ssize_t)_zos_syscall4(SYS_FWRITE, (long)fd, (long)buf,
|
return (ssize_t)_zos_syscall4(SYS_FWRITE, (long)fd, (long)buf,
|
||||||
(long)offset, (long)count);
|
(long)offset, (long)count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int close(int fd) {
|
int close(int fd) {
|
||||||
if (fd >= 0 && fd < _FD_POS_MAX)
|
if (!_fd_pos_valid(fd)) {
|
||||||
_fd_pos[fd] = 0;
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_fd_pos[fd] = 0;
|
||||||
if ((int)_zos_syscall1(SYS_CLOSE, (long)fd) < 0) {
|
if ((int)_zos_syscall1(SYS_CLOSE, (long)fd) < 0) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2206,7 +2244,12 @@ int close(int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long lseek(int fd, long offset, int whence) {
|
long lseek(int fd, long offset, int whence) {
|
||||||
unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0;
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long pos = _fd_pos[fd];
|
||||||
unsigned long newpos;
|
unsigned long newpos;
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case 0: /* SEEK_SET */
|
case 0: /* SEEK_SET */
|
||||||
@@ -2219,10 +2262,10 @@ long lseek(int fd, long offset, int whence) {
|
|||||||
newpos = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd) + (unsigned long)offset;
|
newpos = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd) + (unsigned long)offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fd >= 0 && fd < _FD_POS_MAX)
|
_fd_pos[fd] = newpos;
|
||||||
_fd_pos[fd] = newpos;
|
|
||||||
return (long)newpos;
|
return (long)newpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3322,12 +3365,21 @@ int fchmod(int fd, mode_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int utime(const char *path, const struct utimbuf *times) {
|
int utime(const char *path, const struct utimbuf *times) {
|
||||||
(void)times;
|
|
||||||
if (path == NULL) {
|
if (path == NULL) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0; /* file times cannot be set through the VFS */
|
|
||||||
|
long result = _zos_syscall4(SYS_UTIME, (long)path,
|
||||||
|
times != NULL ? (long)times->actime : 0,
|
||||||
|
times != NULL ? (long)times->modtime : 0,
|
||||||
|
times == NULL);
|
||||||
|
if (result == 0) return 0;
|
||||||
|
if (result == -2) errno = ENOTSUP;
|
||||||
|
else if (result == -3) errno = EOVERFLOW;
|
||||||
|
else if (result == -4) errno = EIO;
|
||||||
|
else errno = ENOENT;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
@@ -3740,7 +3792,7 @@ pid_t getpid(void) {
|
|||||||
allocation usually land there. The oldfd == newfd form (the common
|
allocation usually land there. The oldfd == newfd form (the common
|
||||||
validity probe) is handled exactly. */
|
validity probe) is handled exactly. */
|
||||||
int dup2(int oldfd, int newfd) {
|
int dup2(int oldfd, int newfd) {
|
||||||
if (oldfd < 0 || newfd < 0) {
|
if (!_fd_pos_valid(oldfd) || !_fd_pos_valid(newfd)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -3764,9 +3816,7 @@ int dup2(int oldfd, int newfd) {
|
|||||||
errno = EBUSY;
|
errno = EBUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (h < _FD_POS_MAX) {
|
_fd_pos[h] = _fd_pos[oldfd];
|
||||||
_fd_pos[h] = (oldfd < _FD_POS_MAX) ? _fd_pos[oldfd] : 0;
|
|
||||||
}
|
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3812,7 +3862,7 @@ int getpagesize(void) {
|
|||||||
long sysconf(int name) {
|
long sysconf(int name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 4: /* _SC_OPEN_MAX */
|
case 4: /* _SC_OPEN_MAX */
|
||||||
return 64;
|
return OPEN_MAX;
|
||||||
case 30: /* _SC_PAGESIZE */
|
case 30: /* _SC_PAGESIZE */
|
||||||
return 4096;
|
return 4096;
|
||||||
case 84: /* _SC_NPROCESSORS_ONLN */
|
case 84: /* _SC_NPROCESSORS_ONLN */
|
||||||
@@ -4066,14 +4116,21 @@ pid_t wait(int *status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int dup(int fd) {
|
int dup(int fd) {
|
||||||
|
if (!_fd_pos_valid(fd)) {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
int h = (int)_zos_syscall1(SYS_DUPHANDLE, (long)fd);
|
int h = (int)_zos_syscall1(SYS_DUPHANDLE, (long)fd);
|
||||||
if (h < 0) {
|
if (h < 0) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (h < _FD_POS_MAX) {
|
if (!_fd_pos_valid(h)) {
|
||||||
_fd_pos[h] = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0;
|
_zos_syscall1(SYS_CLOSE, (long)h);
|
||||||
|
errno = EMFILE;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
_fd_pos[h] = _fd_pos[fd];
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4089,7 +4146,7 @@ int fileno(FILE *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILE *fdopen(int fd, const char *mode) {
|
FILE *fdopen(int fd, const char *mode) {
|
||||||
if (fd < 0 || mode == NULL) {
|
if (!_fd_pos_valid(fd) || mode == NULL) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -4099,7 +4156,7 @@ FILE *fdopen(int fd, const char *mode) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
f->handle = fd;
|
f->handle = fd;
|
||||||
f->pos = (fd < _FD_POS_MAX) ? _fd_pos[fd] : 0;
|
f->pos = _fd_pos[fd];
|
||||||
f->size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd);
|
f->size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd);
|
||||||
f->eof = 0;
|
f->eof = 0;
|
||||||
f->error = 0;
|
f->error = 0;
|
||||||
|
|||||||
Binary file not shown.
@@ -27,5 +27,6 @@
|
|||||||
|
|
||||||
#define PATH_MAX 4096
|
#define PATH_MAX 4096
|
||||||
#define NAME_MAX 256
|
#define NAME_MAX 256
|
||||||
|
#define OPEN_MAX 128
|
||||||
|
|
||||||
#endif /* _LIBC_LIMITS_H */
|
#endif /* _LIBC_LIMITS_H */
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ struct utimbuf {
|
|||||||
time_t modtime;
|
time_t modtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Accepted for POSIX compatibility; the Montauk VFS does not support
|
/* Set access and modification times. Currently supported on ext2. */
|
||||||
setting file times. */
|
|
||||||
int utime(const char *path, const struct utimbuf *times);
|
int utime(const char *path, const struct utimbuf *times);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
Reference in New Issue
Block a user