windows-nt/Source/XPSP1/NT/base/subsys/posix/client/dllfile.c
2020-09-26 16:20:57 +08:00

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;
}