/*++ 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 #include #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; }