1015 lines
20 KiB
C
1015 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllfile.c
|
|
|
|
Abstract:
|
|
|
|
Client implementation of File and Directory functions for POSIX.
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 15-Dec-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include "psxdll.h"
|
|
|
|
int __cdecl
|
|
closedir(DIR *dirp)
|
|
{
|
|
int r = 0;
|
|
|
|
try {
|
|
if (-1 == close(dirp->Directory)) {
|
|
return -1;
|
|
}
|
|
dirp->Directory = -1;
|
|
dirp->Index = (unsigned long)-1;
|
|
|
|
RtlFreeHeap(PdxHeap, 0, (PVOID)dirp);
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
r = -1;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
DIR * __cdecl
|
|
opendir(const char *dirname)
|
|
{
|
|
DIR *ReturnedDir;
|
|
int fd, i;
|
|
|
|
ReturnedDir = RtlAllocateHeap(PdxHeap, 0, sizeof(DIR));
|
|
if (NULL == ReturnedDir) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
fd = open(dirname, O_RDONLY);
|
|
if (-1 == fd) {
|
|
RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir);
|
|
return NULL;
|
|
}
|
|
|
|
i = fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
if (0 != i) {
|
|
close(fd);
|
|
RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir);
|
|
return NULL;
|
|
}
|
|
|
|
ReturnedDir->Directory = fd;
|
|
ReturnedDir->Dirent.d_name[0] = '\0';
|
|
ReturnedDir->Index = 0;
|
|
ReturnedDir->RestartScan = FALSE;
|
|
|
|
return ReturnedDir;
|
|
}
|
|
|
|
struct dirent * __cdecl
|
|
readdir(DIR *dirp)
|
|
{
|
|
PSX_API_MSG m;
|
|
PPSX_READDIR_MSG args;
|
|
NTSTATUS Status;
|
|
char *buf;
|
|
|
|
args = &m.u.ReadDir;
|
|
|
|
buf = &dirp->Dirent.d_name[0];
|
|
|
|
again:
|
|
for (;;) {
|
|
PSX_FORMAT_API_MSG(m, PsxReadDirApi, sizeof(*args));
|
|
args->FileDes = dirp->Directory;
|
|
args->Buf = buf;
|
|
args->Nbytes = PATH_MAX;
|
|
args->RestartScan = dirp->RestartScan;
|
|
dirp->RestartScan = 0;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle,
|
|
(PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
if (EINTR == m.Error && SIGCONT == m.Signal) {
|
|
//
|
|
// The system call was stopped and continued. Call
|
|
// again instead of returning EINTR.
|
|
//
|
|
continue;
|
|
}
|
|
if (m.Error) {
|
|
errno = m.Error;
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (0 == m.ReturnValue) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Skip dot and dot-dot.
|
|
//
|
|
|
|
if (m.ReturnValue <= 2 && buf[0] == '.') {
|
|
if (m.ReturnValue == 1 || buf[1] == '.') {
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
try {
|
|
++dirp->Index;
|
|
|
|
dirp->Dirent.d_name[m.ReturnValue] = '\0';
|
|
return &dirp->Dirent;
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
errno = EFAULT;
|
|
}
|
|
// we've taken an exception.
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
__cdecl
|
|
rewinddir(DIR *dirp)
|
|
{
|
|
dirp->RestartScan = TRUE;
|
|
dirp->Index = 0;
|
|
}
|
|
|
|
int __cdecl
|
|
chdir(const char *path)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE Directory;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
ANSI_STRING Path_A;
|
|
PANSI_STRING pCWD;
|
|
auto sigset_t set, oset;
|
|
int ret_val = 0;
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &Path_U, PdxHeap)) {
|
|
return -1;
|
|
}
|
|
InitializeObjectAttributes(&ObjA, &Path_U, OBJ_INHERIT, NULL, NULL);
|
|
|
|
//
|
|
// Make sure that the path is to a directory
|
|
//
|
|
|
|
Status = NtOpenFile(&Directory, SYNCHRONIZE, &ObjA, &Iosb,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
errno = PdxStatusToErrnoPath(&Path_U);
|
|
} else {
|
|
errno = PdxStatusToErrno(Status);
|
|
}
|
|
RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer);
|
|
return -1;
|
|
}
|
|
|
|
Status = NtClose(Directory);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXDLL: NtClose: 0x%x\n", Status));
|
|
}
|
|
|
|
RtlUnicodeStringToAnsiString(&Path_A, &Path_U, TRUE);
|
|
RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer);
|
|
|
|
pCWD = &PdxDirectoryPrefix.NtCurrentWorkingDirectory;
|
|
|
|
//
|
|
// The path was opened ok. Make sure that there is space for the
|
|
// pathname in the PdxDirectoryPrefix buffer.
|
|
//
|
|
|
|
if (Path_A.Length > pCWD->MaximumLength + 2) {
|
|
RtlFreeAnsiString(&Path_A);
|
|
errno = ENOENT;
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Keep the process from trying to use his CWD while we're modifying
|
|
// it.
|
|
//
|
|
|
|
sigfillset(&set);
|
|
sigprocmask(SIG_BLOCK, &set, &oset);
|
|
|
|
//
|
|
// Update NtCurrentWorkingDirectory
|
|
//
|
|
|
|
RtlMoveMemory(pCWD->Buffer, Path_A.Buffer, Path_A.Length);
|
|
if ('\\' != pCWD->Buffer[Path_A.Length - 1]) {
|
|
pCWD->Buffer[Path_A.Length] = '\\';
|
|
pCWD->Buffer[Path_A.Length + 1] = '\0';
|
|
pCWD->Length = Path_A.Length + 1;
|
|
} else {
|
|
pCWD->Buffer[Path_A.Length + 1] = '\0';
|
|
pCWD->Length = Path_A.Length;
|
|
}
|
|
|
|
//
|
|
// Set length of translated current working directory to zero.
|
|
// getcwd() uses this as its hint to translate NtCurrentWorkingDirectory
|
|
// to PsxCurrentWorkingDirectory.
|
|
//
|
|
|
|
PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Length = 0;
|
|
|
|
//
|
|
// Update the PsxRoot.
|
|
//
|
|
|
|
RtlMoveMemory(PdxDirectoryPrefix.PsxRoot.Buffer, Path_A.Buffer,
|
|
PdxDirectoryPrefix.PsxRoot.Length);
|
|
|
|
RtlFreeAnsiString(&Path_A);
|
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
__cdecl
|
|
getcwd(char *buf, size_t size)
|
|
{
|
|
USHORT i, j, CwdSize;
|
|
PANSI_STRING pPsxCwd, pNtCwd, pPsxRoot;
|
|
|
|
if (size <= 0) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Note that NtCwd should always have a trailing backslash.
|
|
//
|
|
|
|
pNtCwd = &PdxDirectoryPrefix.NtCurrentWorkingDirectory;
|
|
pPsxCwd = &PdxDirectoryPrefix.PsxCurrentWorkingDirectory;
|
|
pPsxRoot = &PdxDirectoryPrefix.PsxRoot;
|
|
|
|
CwdSize = pNtCwd->Length - pPsxRoot->Length;
|
|
if (1 == CwdSize) {
|
|
//
|
|
// If the CWD is "/", then we'll have a trailing slash and
|
|
// we'll need space for it.
|
|
//
|
|
++CwdSize;
|
|
}
|
|
if (size < CwdSize) {
|
|
errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
|
|
if (0 == pPsxCwd->Length) {
|
|
for (i = 0, j = pPsxRoot->Length; i < CwdSize - 1; i++, j++) {
|
|
pPsxCwd->Buffer[i] = (pNtCwd->Buffer[j] == '\\') ?
|
|
'/' : pNtCwd->Buffer[j];
|
|
}
|
|
pPsxCwd->Buffer[CwdSize] = '\0';
|
|
pPsxCwd->Length = CwdSize - 1;
|
|
|
|
}
|
|
|
|
try {
|
|
RtlMoveMemory(buf, pPsxCwd->Buffer, pPsxCwd->Length);
|
|
buf[pPsxCwd->Length] = '\0';
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
errno = EFAULT;
|
|
buf = NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
mode_t
|
|
__cdecl
|
|
umask(mode_t cmask)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_UMASK_MSG args;
|
|
|
|
args = &m.u.Umask;
|
|
PSX_FORMAT_API_MSG(m, PsxUmaskApi, sizeof(*args));
|
|
|
|
args->Cmask = cmask;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return (mode_t)-1;
|
|
}
|
|
return (mode_t)m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
mkdir(const char *path, mode_t mode)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_MKDIR_MSG args;
|
|
UNICODE_STRING Path_U;
|
|
|
|
args = &m.u.MkDir;
|
|
PSX_FORMAT_API_MSG(m, PsxMkDirApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
args->Path_U = Path_U;
|
|
args->Path_U.Buffer = (PVOID)((PCHAR)Path_U.Buffer +
|
|
PsxPortMemoryRemoteDelta);
|
|
args->Mode = mode;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Path_U.Buffer);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return (int)m.ReturnValue;
|
|
}
|
|
|
|
|
|
int
|
|
__cdecl
|
|
mkfifo(const char *path, mode_t mode)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_MKFIFO_MSG args;
|
|
PVOID p;
|
|
|
|
args = &m.u.MkFifo;
|
|
|
|
PSX_FORMAT_API_MSG(m,PsxMkFifoApi,sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
p = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
|
|
args->Mode = mode;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, p);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
rmdir(const char *path)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_RMDIR_MSG args;
|
|
PVOID p;
|
|
|
|
args = &m.u.RmDir;
|
|
|
|
PSX_FORMAT_API_MSG(m,PsxRmDirApi,sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
p = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, p);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return (int)m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
stat(const char *path, struct stat *buf)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_STAT_MSG args;
|
|
struct stat *tmpbuf;
|
|
void *p;
|
|
int r;
|
|
|
|
args = &m.u.Stat;
|
|
PSX_FORMAT_API_MSG(m, PsxStatApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
p = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
|
|
|
|
tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat));
|
|
ASSERT(NULL != tmpbuf);
|
|
|
|
args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta);
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, p);
|
|
|
|
if (m.Error) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
|
|
r = 0;
|
|
|
|
try {
|
|
(void)memcpy(buf, tmpbuf, sizeof(struct stat));
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
r = -1;
|
|
errno = EFAULT;
|
|
}
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
|
|
return r;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
fstat(int fildes, struct stat *buf)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_FSTAT_MSG args;
|
|
struct stat *tmpbuf;
|
|
int r;
|
|
|
|
args = &m.u.FStat;
|
|
PSX_FORMAT_API_MSG(m, PsxFStatApi, sizeof(*args));
|
|
|
|
args->FileDes = fildes;
|
|
|
|
tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat));
|
|
if (! tmpbuf) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta);
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
if (m.Error) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
|
|
r = 0;
|
|
|
|
try {
|
|
(void)memcpy(buf, tmpbuf, sizeof(struct stat));
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
r = -1;
|
|
errno = EFAULT;
|
|
}
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
|
|
return r;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
access(const char *path, int amode)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
|
|
PPSX_ACCESS_MSG args;
|
|
|
|
if (0 != (amode & ~(W_OK | R_OK | X_OK))) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
args = &m.u.Access;
|
|
|
|
PSX_FORMAT_API_MSG(m,PsxAccessApi,sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
|
|
args->Amode = amode;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
chmod(const char *path, mode_t mode)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_CHMOD_MSG args;
|
|
|
|
args = &m.u.Chmod;
|
|
|
|
PSX_FORMAT_API_MSG(m,PsxChmodApi,sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
|
|
args->Mode = mode;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
chown(const char *path, uid_t owner, gid_t group)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_CHOWN_MSG args;
|
|
|
|
args = &m.u.Chown;
|
|
|
|
PSX_FORMAT_API_MSG(m, PsxChownApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
|
|
args->Owner = owner;
|
|
args->Group = group;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
utime(const char *path, const struct utimbuf *times)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
|
|
PPSX_UTIME_MSG args;
|
|
|
|
args = &m.u.Utime;
|
|
|
|
PSX_FORMAT_API_MSG(m, PsxUtimeApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock +
|
|
PsxPortMemoryRemoteDelta);
|
|
args->TimesSpecified = (struct utimbuf *)times;
|
|
|
|
if (NULL != times) {
|
|
args->Times = *times;
|
|
}
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
long
|
|
__cdecl
|
|
pathconf(const char *path, int name)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_PATHCONF_MSG args;
|
|
|
|
args = &m.u.PathConf;
|
|
PSX_FORMAT_API_MSG(m, PsxPathConfApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path.Buffer;
|
|
args->Path.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
|
|
args->Name = name;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle,
|
|
(PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return((long)(m.ReturnValue));
|
|
}
|
|
|
|
long
|
|
__cdecl
|
|
fpathconf(int fildes, int name)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_FPATHCONF_MSG args;
|
|
|
|
args = &m.u.FPathConf;
|
|
PSX_FORMAT_API_MSG(m, PsxFPathConfApi, sizeof(*args));
|
|
|
|
args->FileDes = fildes;
|
|
args->Name = name;
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return m.ReturnValue;
|
|
}
|
|
|
|
int __cdecl
|
|
rename(const char *old, const char *new)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING old_U, new_U;
|
|
PSX_API_MSG m;
|
|
PPSX_RENAME_MSG args;
|
|
sigset_t set, oset;
|
|
int r; // ret val
|
|
static char path[PATH_MAX];
|
|
char *pch, c;
|
|
WCHAR *pwc;
|
|
int i;
|
|
struct stat st_buf1, st_buf2;
|
|
static int been_here = 0; // prevent infinite recursion
|
|
|
|
args = &m.u.Rename;
|
|
PSX_FORMAT_API_MSG(m, PsxRenameApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)old, &old_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// 1003.1-90 (5.5.3.4): EISDIR ... The /new/ argument points
|
|
// to a directory, and the /old/ argument points to a file that
|
|
// is not a directory.
|
|
//
|
|
// ENOTDIR ... the /old/ argument names a
|
|
// directory and the /new/ argument names a nondirectory file.
|
|
//
|
|
|
|
i = errno;
|
|
if (0 == stat(old, &st_buf1) && 0 == stat(new, &st_buf2)) {
|
|
if (S_ISDIR(st_buf2.st_mode) && S_ISREG(st_buf1.st_mode)) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
|
|
errno = EISDIR;
|
|
return -1;
|
|
}
|
|
if (S_ISREG(st_buf2.st_mode) && S_ISDIR(st_buf1.st_mode)) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
|
|
errno = ENOTDIR;
|
|
return -1;
|
|
}
|
|
}
|
|
errno = i;
|
|
|
|
//
|
|
// 1003.1-90 (5.5.3.4): EINVAL ... The /new/ directory
|
|
// pathname contains a path prefix that names the /old/ directory.
|
|
//
|
|
|
|
pwc = wcsrchr(new_U.Buffer, L'\\');
|
|
ASSERT(NULL != pwc);
|
|
*pwc = 0;
|
|
|
|
if (0 == wcsncmp(new_U.Buffer, old_U.Buffer, old_U.Length)) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
*pwc = L'\\'; // put it back
|
|
|
|
args->OldName = old_U;
|
|
args->NewName = new_U;
|
|
|
|
args->OldName.Buffer =
|
|
(PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta);
|
|
args->NewName.Buffer =
|
|
(PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta);
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
|
|
if (0 == m.Error) {
|
|
return m.ReturnValue;
|
|
}
|
|
if (EACCES != m.Error) {
|
|
errno = m.Error;
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// The rename operation failed because the target already
|
|
// exists. This happens when trying to rename a directory
|
|
// over an existing directory, which POSIX requires but
|
|
// NT filesystems don't support. We emulate here.
|
|
//
|
|
|
|
if (been_here) {
|
|
errno = EACCES;
|
|
return -1;
|
|
}
|
|
been_here++;
|
|
|
|
// block all signals during the operation.
|
|
|
|
sigfillset(&set);
|
|
sigprocmask(SIG_SETMASK, &set, &oset);
|
|
|
|
r = 0;
|
|
|
|
//
|
|
// Figure out a temporary pathname to use. The temporary
|
|
// dir is created in the same directory as 'new'.
|
|
//
|
|
|
|
strcpy(path, new);
|
|
|
|
// take care of paths that end in slash...
|
|
|
|
for (;;) {
|
|
i = strlen(path) - 1;
|
|
if ('/' == path[i]) {
|
|
path[i] = '\0';
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pch = strrchr(path, '/');
|
|
if (NULL != pch) {
|
|
++pch;
|
|
strcpy(pch, "_psxtmp.d");
|
|
} else {
|
|
// 'new' is in the cwd
|
|
|
|
strcpy(path, "_psxtmp.d");
|
|
pch = path;
|
|
}
|
|
|
|
for (c = 'a'; ; c++) {
|
|
if (c > 'z') {
|
|
errno = EEXIST;
|
|
return -1;
|
|
}
|
|
*pch = c;
|
|
|
|
if (-1 == (r = rename(new, path))) {
|
|
if (EEXIST == errno) {
|
|
// try the next letter for tmp path
|
|
continue;
|
|
}
|
|
errno = EACCES; // reset errno
|
|
break;
|
|
}
|
|
if (-1 == (r = rename(old, new))) {
|
|
(void)rename(path, new);
|
|
break;
|
|
}
|
|
if (-1 == rmdir(path)) {
|
|
if (-1 == (r = rename(new, old))) {
|
|
//
|
|
// If we don't bail here, the following call
|
|
// to rename will recurse infinitely.
|
|
//
|
|
break;
|
|
}
|
|
(void)rename(path, new);
|
|
r = -1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
been_here = 0;
|
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
|
return r;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
unlink(const char *path)
|
|
{
|
|
PSX_API_MSG m;
|
|
NTSTATUS Status;
|
|
PPSX_UNLINK_MSG args;
|
|
|
|
args = &m.u.Unlink;
|
|
PSX_FORMAT_API_MSG(m, PsxUnlinkApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
m.DataBlock = args->Path_U.Buffer;
|
|
args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock +
|
|
PsxPortMemoryRemoteDelta);
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
|
|
|
|
if (m.Error) {
|
|
errno = (int)m.Error;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
link(const char *existing, const char *new)
|
|
{
|
|
PPSX_LINK_MSG args;
|
|
PSX_API_MSG m;
|
|
UNICODE_STRING old_U, new_U;
|
|
NTSTATUS Status;
|
|
|
|
args = &m.u.Link;
|
|
PSX_FORMAT_API_MSG(m, PsxLinkApi, sizeof(*args));
|
|
|
|
if (!PdxCanonicalize((PSZ)existing, &old_U, PdxPortHeap)) {
|
|
return -1;
|
|
}
|
|
|
|
if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) {
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
return -1;
|
|
}
|
|
|
|
args->OldName = old_U;
|
|
args->NewName = new_U;
|
|
|
|
args->OldName.Buffer =
|
|
(PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta);
|
|
args->NewName.Buffer =
|
|
(PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta);
|
|
|
|
Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
|
(PPORT_MESSAGE)&m);
|
|
#ifdef PSX_MORE_ERRORS
|
|
ASSERT(NT_SUCCESS(Status));
|
|
#endif
|
|
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
|
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
|
|
|
|
if (0 != m.Error) {
|
|
errno = m.Error;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|