Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1014 lines
20 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dllfile.c
  5. Abstract:
  6. Client implementation of File and Directory functions for POSIX.
  7. Author:
  8. Mark Lucovsky (markl) 15-Dec-1989
  9. Revision History:
  10. --*/
  11. #include <unistd.h>
  12. #include <sys/stat.h>
  13. #include "psxdll.h"
  14. int __cdecl
  15. closedir(DIR *dirp)
  16. {
  17. int r = 0;
  18. try {
  19. if (-1 == close(dirp->Directory)) {
  20. return -1;
  21. }
  22. dirp->Directory = -1;
  23. dirp->Index = (unsigned long)-1;
  24. RtlFreeHeap(PdxHeap, 0, (PVOID)dirp);
  25. } except (EXCEPTION_EXECUTE_HANDLER) {
  26. r = -1;
  27. }
  28. return r;
  29. }
  30. DIR * __cdecl
  31. opendir(const char *dirname)
  32. {
  33. DIR *ReturnedDir;
  34. int fd, i;
  35. ReturnedDir = RtlAllocateHeap(PdxHeap, 0, sizeof(DIR));
  36. if (NULL == ReturnedDir) {
  37. errno = ENOMEM;
  38. return NULL;
  39. }
  40. fd = open(dirname, O_RDONLY);
  41. if (-1 == fd) {
  42. RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir);
  43. return NULL;
  44. }
  45. i = fcntl(fd, F_SETFD, FD_CLOEXEC);
  46. if (0 != i) {
  47. close(fd);
  48. RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir);
  49. return NULL;
  50. }
  51. ReturnedDir->Directory = fd;
  52. ReturnedDir->Dirent.d_name[0] = '\0';
  53. ReturnedDir->Index = 0;
  54. ReturnedDir->RestartScan = FALSE;
  55. return ReturnedDir;
  56. }
  57. struct dirent * __cdecl
  58. readdir(DIR *dirp)
  59. {
  60. PSX_API_MSG m;
  61. PPSX_READDIR_MSG args;
  62. NTSTATUS Status;
  63. char *buf;
  64. args = &m.u.ReadDir;
  65. buf = &dirp->Dirent.d_name[0];
  66. again:
  67. for (;;) {
  68. PSX_FORMAT_API_MSG(m, PsxReadDirApi, sizeof(*args));
  69. args->FileDes = dirp->Directory;
  70. args->Buf = buf;
  71. args->Nbytes = PATH_MAX;
  72. args->RestartScan = dirp->RestartScan;
  73. dirp->RestartScan = 0;
  74. Status = NtRequestWaitReplyPort(PsxPortHandle,
  75. (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m);
  76. #ifdef PSX_MORE_ERRORS
  77. ASSERT(NT_SUCCESS(Status));
  78. #endif
  79. if (EINTR == m.Error && SIGCONT == m.Signal) {
  80. //
  81. // The system call was stopped and continued. Call
  82. // again instead of returning EINTR.
  83. //
  84. continue;
  85. }
  86. if (m.Error) {
  87. errno = m.Error;
  88. return NULL;
  89. }
  90. break;
  91. }
  92. if (0 == m.ReturnValue) {
  93. return NULL;
  94. }
  95. //
  96. // Skip dot and dot-dot.
  97. //
  98. if (m.ReturnValue <= 2 && buf[0] == '.') {
  99. if (m.ReturnValue == 1 || buf[1] == '.') {
  100. goto again;
  101. }
  102. }
  103. try {
  104. ++dirp->Index;
  105. dirp->Dirent.d_name[m.ReturnValue] = '\0';
  106. return &dirp->Dirent;
  107. } except (EXCEPTION_EXECUTE_HANDLER) {
  108. errno = EFAULT;
  109. }
  110. // we've taken an exception.
  111. return NULL;
  112. }
  113. void
  114. __cdecl
  115. rewinddir(DIR *dirp)
  116. {
  117. dirp->RestartScan = TRUE;
  118. dirp->Index = 0;
  119. }
  120. int __cdecl
  121. chdir(const char *path)
  122. {
  123. NTSTATUS Status;
  124. HANDLE Directory;
  125. IO_STATUS_BLOCK Iosb;
  126. OBJECT_ATTRIBUTES ObjA;
  127. UNICODE_STRING Path_U;
  128. ANSI_STRING Path_A;
  129. PANSI_STRING pCWD;
  130. auto sigset_t set, oset;
  131. int ret_val = 0;
  132. if (!PdxCanonicalize((PSZ)path, &Path_U, PdxHeap)) {
  133. return -1;
  134. }
  135. InitializeObjectAttributes(&ObjA, &Path_U, OBJ_INHERIT, NULL, NULL);
  136. //
  137. // Make sure that the path is to a directory
  138. //
  139. Status = NtOpenFile(&Directory, SYNCHRONIZE, &ObjA, &Iosb,
  140. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  141. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
  142. if (!NT_SUCCESS(Status)) {
  143. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  144. errno = PdxStatusToErrnoPath(&Path_U);
  145. } else {
  146. errno = PdxStatusToErrno(Status);
  147. }
  148. RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer);
  149. return -1;
  150. }
  151. Status = NtClose(Directory);
  152. if (!NT_SUCCESS(Status)) {
  153. KdPrint(("PSXDLL: NtClose: 0x%x\n", Status));
  154. }
  155. RtlUnicodeStringToAnsiString(&Path_A, &Path_U, TRUE);
  156. RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer);
  157. pCWD = &PdxDirectoryPrefix.NtCurrentWorkingDirectory;
  158. //
  159. // The path was opened ok. Make sure that there is space for the
  160. // pathname in the PdxDirectoryPrefix buffer.
  161. //
  162. if (Path_A.Length > pCWD->MaximumLength + 2) {
  163. RtlFreeAnsiString(&Path_A);
  164. errno = ENOENT;
  165. return -1;
  166. }
  167. //
  168. // Keep the process from trying to use his CWD while we're modifying
  169. // it.
  170. //
  171. sigfillset(&set);
  172. sigprocmask(SIG_BLOCK, &set, &oset);
  173. //
  174. // Update NtCurrentWorkingDirectory
  175. //
  176. RtlMoveMemory(pCWD->Buffer, Path_A.Buffer, Path_A.Length);
  177. if ('\\' != pCWD->Buffer[Path_A.Length - 1]) {
  178. pCWD->Buffer[Path_A.Length] = '\\';
  179. pCWD->Buffer[Path_A.Length + 1] = '\0';
  180. pCWD->Length = Path_A.Length + 1;
  181. } else {
  182. pCWD->Buffer[Path_A.Length + 1] = '\0';
  183. pCWD->Length = Path_A.Length;
  184. }
  185. //
  186. // Set length of translated current working directory to zero.
  187. // getcwd() uses this as its hint to translate NtCurrentWorkingDirectory
  188. // to PsxCurrentWorkingDirectory.
  189. //
  190. PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Length = 0;
  191. //
  192. // Update the PsxRoot.
  193. //
  194. RtlMoveMemory(PdxDirectoryPrefix.PsxRoot.Buffer, Path_A.Buffer,
  195. PdxDirectoryPrefix.PsxRoot.Length);
  196. RtlFreeAnsiString(&Path_A);
  197. sigprocmask(SIG_SETMASK, &oset, NULL);
  198. return 0;
  199. }
  200. char *
  201. __cdecl
  202. getcwd(char *buf, size_t size)
  203. {
  204. USHORT i, j, CwdSize;
  205. PANSI_STRING pPsxCwd, pNtCwd, pPsxRoot;
  206. if (size <= 0) {
  207. errno = EINVAL;
  208. return NULL;
  209. }
  210. //
  211. // Note that NtCwd should always have a trailing backslash.
  212. //
  213. pNtCwd = &PdxDirectoryPrefix.NtCurrentWorkingDirectory;
  214. pPsxCwd = &PdxDirectoryPrefix.PsxCurrentWorkingDirectory;
  215. pPsxRoot = &PdxDirectoryPrefix.PsxRoot;
  216. CwdSize = pNtCwd->Length - pPsxRoot->Length;
  217. if (1 == CwdSize) {
  218. //
  219. // If the CWD is "/", then we'll have a trailing slash and
  220. // we'll need space for it.
  221. //
  222. ++CwdSize;
  223. }
  224. if (size < CwdSize) {
  225. errno = ERANGE;
  226. return NULL;
  227. }
  228. if (0 == pPsxCwd->Length) {
  229. for (i = 0, j = pPsxRoot->Length; i < CwdSize - 1; i++, j++) {
  230. pPsxCwd->Buffer[i] = (pNtCwd->Buffer[j] == '\\') ?
  231. '/' : pNtCwd->Buffer[j];
  232. }
  233. pPsxCwd->Buffer[CwdSize] = '\0';
  234. pPsxCwd->Length = CwdSize - 1;
  235. }
  236. try {
  237. RtlMoveMemory(buf, pPsxCwd->Buffer, pPsxCwd->Length);
  238. buf[pPsxCwd->Length] = '\0';
  239. } except (EXCEPTION_EXECUTE_HANDLER) {
  240. errno = EFAULT;
  241. buf = NULL;
  242. }
  243. return buf;
  244. }
  245. mode_t
  246. __cdecl
  247. umask(mode_t cmask)
  248. {
  249. PSX_API_MSG m;
  250. NTSTATUS Status;
  251. PPSX_UMASK_MSG args;
  252. args = &m.u.Umask;
  253. PSX_FORMAT_API_MSG(m, PsxUmaskApi, sizeof(*args));
  254. args->Cmask = cmask;
  255. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  256. (PPORT_MESSAGE)&m);
  257. #ifdef PSX_MORE_ERRORS
  258. ASSERT(NT_SUCCESS(Status));
  259. #endif
  260. if (m.Error) {
  261. errno = (int)m.Error;
  262. return (mode_t)-1;
  263. }
  264. return (mode_t)m.ReturnValue;
  265. }
  266. int
  267. __cdecl
  268. mkdir(const char *path, mode_t mode)
  269. {
  270. PSX_API_MSG m;
  271. NTSTATUS Status;
  272. PPSX_MKDIR_MSG args;
  273. UNICODE_STRING Path_U;
  274. args = &m.u.MkDir;
  275. PSX_FORMAT_API_MSG(m, PsxMkDirApi, sizeof(*args));
  276. if (!PdxCanonicalize((PSZ)path, &Path_U, PdxPortHeap)) {
  277. return -1;
  278. }
  279. args->Path_U = Path_U;
  280. args->Path_U.Buffer = (PVOID)((PCHAR)Path_U.Buffer +
  281. PsxPortMemoryRemoteDelta);
  282. args->Mode = mode;
  283. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  284. (PPORT_MESSAGE)&m);
  285. #ifdef PSX_MORE_ERRORS
  286. ASSERT(NT_SUCCESS(Status));
  287. #endif
  288. RtlFreeHeap(PdxPortHeap, 0, (PVOID)Path_U.Buffer);
  289. if (m.Error) {
  290. errno = (int)m.Error;
  291. return -1;
  292. }
  293. return (int)m.ReturnValue;
  294. }
  295. int
  296. __cdecl
  297. mkfifo(const char *path, mode_t mode)
  298. {
  299. PSX_API_MSG m;
  300. NTSTATUS Status;
  301. PPSX_MKFIFO_MSG args;
  302. PVOID p;
  303. args = &m.u.MkFifo;
  304. PSX_FORMAT_API_MSG(m,PsxMkFifoApi,sizeof(*args));
  305. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  306. return -1;
  307. }
  308. p = args->Path_U.Buffer;
  309. args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
  310. args->Mode = mode;
  311. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  312. (PPORT_MESSAGE)&m);
  313. #ifdef PSX_MORE_ERRORS
  314. ASSERT(NT_SUCCESS(Status));
  315. #endif
  316. RtlFreeHeap(PdxPortHeap, 0, p);
  317. if (m.Error) {
  318. errno = (int)m.Error;
  319. return -1;
  320. }
  321. return m.ReturnValue;
  322. }
  323. int
  324. __cdecl
  325. rmdir(const char *path)
  326. {
  327. PSX_API_MSG m;
  328. NTSTATUS Status;
  329. PPSX_RMDIR_MSG args;
  330. PVOID p;
  331. args = &m.u.RmDir;
  332. PSX_FORMAT_API_MSG(m,PsxRmDirApi,sizeof(*args));
  333. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  334. return -1;
  335. }
  336. p = args->Path_U.Buffer;
  337. args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
  338. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  339. (PPORT_MESSAGE)&m);
  340. #ifdef PSX_MORE_ERRORS
  341. ASSERT(NT_SUCCESS(Status));
  342. #endif
  343. RtlFreeHeap(PdxPortHeap, 0, p);
  344. if (m.Error) {
  345. errno = (int)m.Error;
  346. return -1;
  347. }
  348. return (int)m.ReturnValue;
  349. }
  350. int
  351. __cdecl
  352. stat(const char *path, struct stat *buf)
  353. {
  354. PSX_API_MSG m;
  355. NTSTATUS Status;
  356. PPSX_STAT_MSG args;
  357. struct stat *tmpbuf;
  358. void *p;
  359. int r;
  360. args = &m.u.Stat;
  361. PSX_FORMAT_API_MSG(m, PsxStatApi, sizeof(*args));
  362. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  363. return -1;
  364. }
  365. p = args->Path_U.Buffer;
  366. args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta);
  367. tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat));
  368. ASSERT(NULL != tmpbuf);
  369. args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta);
  370. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  371. (PPORT_MESSAGE)&m);
  372. #ifdef PSX_MORE_ERRORS
  373. ASSERT(NT_SUCCESS(Status));
  374. #endif
  375. RtlFreeHeap(PdxPortHeap, 0, p);
  376. if (m.Error) {
  377. RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
  378. errno = (int)m.Error;
  379. return -1;
  380. }
  381. r = 0;
  382. try {
  383. (void)memcpy(buf, tmpbuf, sizeof(struct stat));
  384. } except (EXCEPTION_EXECUTE_HANDLER) {
  385. r = -1;
  386. errno = EFAULT;
  387. }
  388. RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
  389. return r;
  390. }
  391. int
  392. __cdecl
  393. fstat(int fildes, struct stat *buf)
  394. {
  395. PSX_API_MSG m;
  396. NTSTATUS Status;
  397. PPSX_FSTAT_MSG args;
  398. struct stat *tmpbuf;
  399. int r;
  400. args = &m.u.FStat;
  401. PSX_FORMAT_API_MSG(m, PsxFStatApi, sizeof(*args));
  402. args->FileDes = fildes;
  403. tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat));
  404. if (! tmpbuf) {
  405. errno = ENOMEM;
  406. return -1;
  407. }
  408. args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta);
  409. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  410. (PPORT_MESSAGE)&m);
  411. #ifdef PSX_MORE_ERRORS
  412. ASSERT(NT_SUCCESS(Status));
  413. #endif
  414. if (m.Error) {
  415. RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
  416. errno = (int)m.Error;
  417. return -1;
  418. }
  419. r = 0;
  420. try {
  421. (void)memcpy(buf, tmpbuf, sizeof(struct stat));
  422. } except (EXCEPTION_EXECUTE_HANDLER) {
  423. r = -1;
  424. errno = EFAULT;
  425. }
  426. RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf);
  427. return r;
  428. }
  429. int
  430. __cdecl
  431. access(const char *path, int amode)
  432. {
  433. PSX_API_MSG m;
  434. NTSTATUS Status;
  435. PPSX_ACCESS_MSG args;
  436. if (0 != (amode & ~(W_OK | R_OK | X_OK))) {
  437. errno = EINVAL;
  438. return -1;
  439. }
  440. args = &m.u.Access;
  441. PSX_FORMAT_API_MSG(m,PsxAccessApi,sizeof(*args));
  442. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  443. return -1;
  444. }
  445. m.DataBlock = args->Path_U.Buffer;
  446. args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
  447. args->Amode = amode;
  448. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  449. (PPORT_MESSAGE)&m);
  450. #ifdef PSX_MORE_ERRORS
  451. ASSERT(NT_SUCCESS(Status));
  452. #endif
  453. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  454. if (m.Error) {
  455. errno = (int)m.Error;
  456. return -1;
  457. }
  458. return m.ReturnValue;
  459. }
  460. int
  461. __cdecl
  462. chmod(const char *path, mode_t mode)
  463. {
  464. PSX_API_MSG m;
  465. NTSTATUS Status;
  466. PPSX_CHMOD_MSG args;
  467. args = &m.u.Chmod;
  468. PSX_FORMAT_API_MSG(m,PsxChmodApi,sizeof(*args));
  469. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  470. return -1;
  471. }
  472. m.DataBlock = args->Path_U.Buffer;
  473. args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
  474. args->Mode = mode;
  475. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  476. (PPORT_MESSAGE)&m);
  477. #ifdef PSX_MORE_ERRORS
  478. ASSERT(NT_SUCCESS(Status));
  479. #endif
  480. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  481. if (m.Error) {
  482. errno = (int)m.Error;
  483. return -1;
  484. }
  485. return m.ReturnValue;
  486. }
  487. int
  488. __cdecl
  489. chown(const char *path, uid_t owner, gid_t group)
  490. {
  491. PSX_API_MSG m;
  492. NTSTATUS Status;
  493. PPSX_CHOWN_MSG args;
  494. args = &m.u.Chown;
  495. PSX_FORMAT_API_MSG(m, PsxChownApi, sizeof(*args));
  496. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  497. return -1;
  498. }
  499. m.DataBlock = args->Path_U.Buffer;
  500. args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
  501. args->Owner = owner;
  502. args->Group = group;
  503. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  504. (PPORT_MESSAGE)&m);
  505. #ifdef PSX_MORE_ERRORS
  506. ASSERT(NT_SUCCESS(Status));
  507. #endif
  508. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  509. if (m.Error) {
  510. errno = (int)m.Error;
  511. return -1;
  512. }
  513. return m.ReturnValue;
  514. }
  515. int
  516. __cdecl
  517. utime(const char *path, const struct utimbuf *times)
  518. {
  519. PSX_API_MSG m;
  520. NTSTATUS Status;
  521. PPSX_UTIME_MSG args;
  522. args = &m.u.Utime;
  523. PSX_FORMAT_API_MSG(m, PsxUtimeApi, sizeof(*args));
  524. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  525. return -1;
  526. }
  527. m.DataBlock = args->Path_U.Buffer;
  528. args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock +
  529. PsxPortMemoryRemoteDelta);
  530. args->TimesSpecified = (struct utimbuf *)times;
  531. if (NULL != times) {
  532. args->Times = *times;
  533. }
  534. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  535. (PPORT_MESSAGE)&m);
  536. #ifdef PSX_MORE_ERRORS
  537. ASSERT(NT_SUCCESS(Status));
  538. #endif
  539. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  540. if (m.Error) {
  541. errno = (int)m.Error;
  542. return -1;
  543. }
  544. return m.ReturnValue;
  545. }
  546. long
  547. __cdecl
  548. pathconf(const char *path, int name)
  549. {
  550. PSX_API_MSG m;
  551. NTSTATUS Status;
  552. PPSX_PATHCONF_MSG args;
  553. args = &m.u.PathConf;
  554. PSX_FORMAT_API_MSG(m, PsxPathConfApi, sizeof(*args));
  555. if (!PdxCanonicalize((PSZ)path, &args->Path, PdxPortHeap)) {
  556. return -1;
  557. }
  558. m.DataBlock = args->Path.Buffer;
  559. args->Path.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta);
  560. args->Name = name;
  561. Status = NtRequestWaitReplyPort(PsxPortHandle,
  562. (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m);
  563. #ifdef PSX_MORE_ERRORS
  564. ASSERT(NT_SUCCESS(Status));
  565. #endif
  566. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  567. if (m.Error) {
  568. errno = (int)m.Error;
  569. return -1;
  570. }
  571. return((long)(m.ReturnValue));
  572. }
  573. long
  574. __cdecl
  575. fpathconf(int fildes, int name)
  576. {
  577. PSX_API_MSG m;
  578. NTSTATUS Status;
  579. PPSX_FPATHCONF_MSG args;
  580. args = &m.u.FPathConf;
  581. PSX_FORMAT_API_MSG(m, PsxFPathConfApi, sizeof(*args));
  582. args->FileDes = fildes;
  583. args->Name = name;
  584. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  585. (PPORT_MESSAGE)&m);
  586. #ifdef PSX_MORE_ERRORS
  587. ASSERT(NT_SUCCESS(Status));
  588. #endif
  589. if (m.Error) {
  590. errno = (int)m.Error;
  591. return -1;
  592. }
  593. return m.ReturnValue;
  594. }
  595. int __cdecl
  596. rename(const char *old, const char *new)
  597. {
  598. NTSTATUS Status;
  599. UNICODE_STRING old_U, new_U;
  600. PSX_API_MSG m;
  601. PPSX_RENAME_MSG args;
  602. sigset_t set, oset;
  603. int r; // ret val
  604. static char path[PATH_MAX];
  605. char *pch, c;
  606. WCHAR *pwc;
  607. int i;
  608. struct stat st_buf1, st_buf2;
  609. static int been_here = 0; // prevent infinite recursion
  610. args = &m.u.Rename;
  611. PSX_FORMAT_API_MSG(m, PsxRenameApi, sizeof(*args));
  612. if (!PdxCanonicalize((PSZ)old, &old_U, PdxPortHeap)) {
  613. return -1;
  614. }
  615. if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) {
  616. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  617. return -1;
  618. }
  619. //
  620. // 1003.1-90 (5.5.3.4): EISDIR ... The /new/ argument points
  621. // to a directory, and the /old/ argument points to a file that
  622. // is not a directory.
  623. //
  624. // ENOTDIR ... the /old/ argument names a
  625. // directory and the /new/ argument names a nondirectory file.
  626. //
  627. i = errno;
  628. if (0 == stat(old, &st_buf1) && 0 == stat(new, &st_buf2)) {
  629. if (S_ISDIR(st_buf2.st_mode) && S_ISREG(st_buf1.st_mode)) {
  630. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  631. RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
  632. errno = EISDIR;
  633. return -1;
  634. }
  635. if (S_ISREG(st_buf2.st_mode) && S_ISDIR(st_buf1.st_mode)) {
  636. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  637. RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
  638. errno = ENOTDIR;
  639. return -1;
  640. }
  641. }
  642. errno = i;
  643. //
  644. // 1003.1-90 (5.5.3.4): EINVAL ... The /new/ directory
  645. // pathname contains a path prefix that names the /old/ directory.
  646. //
  647. pwc = wcsrchr(new_U.Buffer, L'\\');
  648. ASSERT(NULL != pwc);
  649. *pwc = 0;
  650. if (0 == wcsncmp(new_U.Buffer, old_U.Buffer, old_U.Length)) {
  651. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  652. RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
  653. errno = EINVAL;
  654. return -1;
  655. }
  656. *pwc = L'\\'; // put it back
  657. args->OldName = old_U;
  658. args->NewName = new_U;
  659. args->OldName.Buffer =
  660. (PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta);
  661. args->NewName.Buffer =
  662. (PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta);
  663. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  664. (PPORT_MESSAGE)&m);
  665. #ifdef PSX_MORE_ERRORS
  666. ASSERT(NT_SUCCESS(Status));
  667. #endif
  668. RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
  669. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  670. if (0 == m.Error) {
  671. return m.ReturnValue;
  672. }
  673. if (EACCES != m.Error) {
  674. errno = m.Error;
  675. return -1;
  676. }
  677. //
  678. // The rename operation failed because the target already
  679. // exists. This happens when trying to rename a directory
  680. // over an existing directory, which POSIX requires but
  681. // NT filesystems don't support. We emulate here.
  682. //
  683. if (been_here) {
  684. errno = EACCES;
  685. return -1;
  686. }
  687. been_here++;
  688. // block all signals during the operation.
  689. sigfillset(&set);
  690. sigprocmask(SIG_SETMASK, &set, &oset);
  691. r = 0;
  692. //
  693. // Figure out a temporary pathname to use. The temporary
  694. // dir is created in the same directory as 'new'.
  695. //
  696. strcpy(path, new);
  697. // take care of paths that end in slash...
  698. for (;;) {
  699. i = strlen(path) - 1;
  700. if ('/' == path[i]) {
  701. path[i] = '\0';
  702. } else {
  703. break;
  704. }
  705. }
  706. pch = strrchr(path, '/');
  707. if (NULL != pch) {
  708. ++pch;
  709. strcpy(pch, "_psxtmp.d");
  710. } else {
  711. // 'new' is in the cwd
  712. strcpy(path, "_psxtmp.d");
  713. pch = path;
  714. }
  715. for (c = 'a'; ; c++) {
  716. if (c > 'z') {
  717. errno = EEXIST;
  718. return -1;
  719. }
  720. *pch = c;
  721. if (-1 == (r = rename(new, path))) {
  722. if (EEXIST == errno) {
  723. // try the next letter for tmp path
  724. continue;
  725. }
  726. errno = EACCES; // reset errno
  727. break;
  728. }
  729. if (-1 == (r = rename(old, new))) {
  730. (void)rename(path, new);
  731. break;
  732. }
  733. if (-1 == rmdir(path)) {
  734. if (-1 == (r = rename(new, old))) {
  735. //
  736. // If we don't bail here, the following call
  737. // to rename will recurse infinitely.
  738. //
  739. break;
  740. }
  741. (void)rename(path, new);
  742. r = -1;
  743. break;
  744. }
  745. break;
  746. }
  747. been_here = 0;
  748. sigprocmask(SIG_SETMASK, &oset, NULL);
  749. return r;
  750. }
  751. int
  752. __cdecl
  753. unlink(const char *path)
  754. {
  755. PSX_API_MSG m;
  756. NTSTATUS Status;
  757. PPSX_UNLINK_MSG args;
  758. args = &m.u.Unlink;
  759. PSX_FORMAT_API_MSG(m, PsxUnlinkApi, sizeof(*args));
  760. if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) {
  761. return -1;
  762. }
  763. m.DataBlock = args->Path_U.Buffer;
  764. args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock +
  765. PsxPortMemoryRemoteDelta);
  766. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  767. (PPORT_MESSAGE)&m);
  768. #ifdef PSX_MORE_ERRORS
  769. ASSERT(NT_SUCCESS(Status));
  770. #endif
  771. RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock);
  772. if (m.Error) {
  773. errno = (int)m.Error;
  774. return -1;
  775. }
  776. return 0;
  777. }
  778. int
  779. __cdecl
  780. link(const char *existing, const char *new)
  781. {
  782. PPSX_LINK_MSG args;
  783. PSX_API_MSG m;
  784. UNICODE_STRING old_U, new_U;
  785. NTSTATUS Status;
  786. args = &m.u.Link;
  787. PSX_FORMAT_API_MSG(m, PsxLinkApi, sizeof(*args));
  788. if (!PdxCanonicalize((PSZ)existing, &old_U, PdxPortHeap)) {
  789. return -1;
  790. }
  791. if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) {
  792. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  793. return -1;
  794. }
  795. args->OldName = old_U;
  796. args->NewName = new_U;
  797. args->OldName.Buffer =
  798. (PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta);
  799. args->NewName.Buffer =
  800. (PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta);
  801. Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  802. (PPORT_MESSAGE)&m);
  803. #ifdef PSX_MORE_ERRORS
  804. ASSERT(NT_SUCCESS(Status));
  805. #endif
  806. RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer);
  807. RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer);
  808. if (0 != m.Error) {
  809. errno = m.Error;
  810. return -1;
  811. }
  812. return 0;
  813. }