utilnt.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /* Various utilities - NT versions
  2. Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
  3. Written 1994, 1995, 1996 by:
  4. Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
  5. Jakub Jelinek, Mauricio Plaza.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17. #include <config.h>
  18. #include <sys/types.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <windows.h>
  22. #include <io.h>
  23. #include <fcntl.h>
  24. #include <signal.h> /* my_system */
  25. #include <limits.h> /* INT_MAX */
  26. #include <errno.h>
  27. #include <sys/time.h> /* select: timeout */
  28. #include <sys/param.h>
  29. #include <sys/stat.h>
  30. #include <stdarg.h>
  31. #include <process.h>
  32. #include <fs.h>
  33. #include <util.h>
  34. #include "util.Win32.h"
  35. #ifdef __BORLANDC__
  36. #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
  37. #endif
  38. char *get_owner (int uid)
  39. {
  40. return "none";
  41. }
  42. char *get_group (int gid)
  43. {
  44. return "none";
  45. }
  46. /* Pipes are guaranteed to be able to hold at least 4096 bytes */
  47. /* More than that would be unportable */
  48. #define MAX_PIPE_SIZE 4096
  49. static int error_pipe[2]; /* File descriptors of error pipe */
  50. static int old_error; /* File descriptor of old standard error */
  51. /* Creates a pipe to hold standard error for a later analysis. */
  52. /* The pipe can hold 4096 bytes. Make sure no more is written */
  53. /* or a deadlock might occur. */
  54. void open_error_pipe (void)
  55. {
  56. if (pipe (error_pipe) < 0){
  57. message (0, " Warning ", " Pipe failed ");
  58. }
  59. old_error = dup (2);
  60. if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
  61. message (0, " Warning ", " Dup failed ");
  62. close (error_pipe[0]);
  63. close (error_pipe[1]);
  64. }
  65. close (error_pipe[1]);
  66. }
  67. void close_error_pipe (int error, char *text)
  68. {
  69. char *title;
  70. char msg[MAX_PIPE_SIZE];
  71. int len = 0;
  72. if (error)
  73. title = " Error ";
  74. else
  75. title = " Warning ";
  76. if (old_error >= 0){
  77. close (2);
  78. dup (old_error);
  79. close (old_error);
  80. len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
  81. if (len >= 0)
  82. msg[len] = 0;
  83. close (error_pipe[0]);
  84. }
  85. if (error < 0)
  86. return; /* Just ignore error message */
  87. if (text == NULL){
  88. if (len == 0) return; /* Nothing to show */
  89. /* Show message from pipe */
  90. message (error, title, msg);
  91. } else {
  92. /* Show given text and possible message from pipe */
  93. message (error, title, " %s \n %s ", text, msg);
  94. }
  95. }
  96. void check_error_pipe (void)
  97. {
  98. char error[MAX_PIPE_SIZE];
  99. int len = 0;
  100. if (old_error >= 0){
  101. while (len < MAX_PIPE_SIZE)
  102. {
  103. int rvalue;
  104. rvalue = read (error_pipe[0], error + len, 1);
  105. len ++;
  106. if (rvalue <= 0)
  107. break;
  108. }
  109. error[len] = 0;
  110. close (error_pipe[0]);
  111. }
  112. if (len > 0)
  113. message (0, " Warning ", error);
  114. }
  115. int my_system (int as_shell_command, const char *shell, const char *command)
  116. {
  117. int status = 0;
  118. #if 0
  119. /* .ado: temp. turn out */
  120. if (as_shell_command) {
  121. /* It is only the shell, /c will not work */
  122. if (command)
  123. spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
  124. else
  125. spawnlp (P_WAIT, shell, (char *) 0);
  126. } else
  127. spawnl (P_WAIT, shell, shell, command, (char *) 0);
  128. if (win32_GetPlatform() == OS_Win95) {
  129. SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
  130. }
  131. #endif
  132. if (as_shell_command) {
  133. if (!access(command, 0)) {
  134. switch(win32_GetEXEType (shell)) {
  135. case EXE_win16: /* Windows 3.x archive or OS/2 */
  136. case EXE_win32GUI: /* NT or Chicago GUI API */
  137. spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
  138. break;
  139. case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
  140. case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
  141. case EXE_Unknown:
  142. default:
  143. spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
  144. break;
  145. }
  146. }
  147. else
  148. spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
  149. }
  150. else
  151. spawnl (P_WAIT, shell, shell, command, (char *) 0);
  152. if (win32_GetPlatform() == OS_Win95) {
  153. SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
  154. }
  155. return status;
  156. }
  157. /* get_default_shell
  158. Get the default shell for the current hardware platform
  159. */
  160. char* get_default_shell()
  161. {
  162. if (win32_GetPlatform() == OS_WinNT)
  163. return "cmd.exe";
  164. else
  165. return "command.com";
  166. }
  167. char *tilde_expand (char *directory)
  168. {
  169. return strdup (directory);
  170. }
  171. /* sleep: Call Windows API.
  172. Can't do simple define. That would need <windows.h> in every source
  173. */
  174. void sleep(unsigned long dwMiliSecs)
  175. {
  176. Sleep(dwMiliSecs);
  177. }
  178. /* Canonicalize path, and return a new path. Do everything in situ.
  179. * [call OS API]
  180. */
  181. char *canonicalize_pathname (char *path)
  182. {
  183. /* This holds an unused pointer to the start of file name in path */
  184. char *pName;
  185. char pCanonical[MC_MAXPATHLEN];
  186. GetFullPathName (path, MC_MAXPATHLEN, pCanonical, &pName);
  187. /* FIXME: buffer large enough? */
  188. strcpy (path, pCanonical);
  189. return path;
  190. }
  191. /* Do 'manual' canonicalizing, needed for some VFS functions
  192. Canonicalize path, and return a new path. Do everything in situ.
  193. The new path differs from path in:
  194. Multiple `/'s are collapsed to a single `/'.
  195. Leading `./'s and trailing `/.'s are removed.
  196. Trailing `/'s are removed.
  197. Non-leading `../'s and trailing `..'s are handled by removing
  198. portions of the path. */
  199. char *unixlike_canonicalize_pathname (char *path)
  200. {
  201. int i, start;
  202. char stub_char;
  203. stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
  204. /* Walk along path looking for things to compact. */
  205. i = 0;
  206. for (;;) {
  207. if (!path[i])
  208. break;
  209. while (path[i] && path[i] != PATH_SEP)
  210. i++;
  211. start = i++;
  212. /* If we didn't find any slashes, then there is nothing left to do. */
  213. if (!path[start])
  214. break;
  215. /* Handle multiple `/'s in a row. */
  216. while (path[i] == PATH_SEP)
  217. i++;
  218. if ((start + 1) != i) {
  219. strcpy (path + start + 1, path + i);
  220. i = start + 1;
  221. }
  222. /* Handle backquoted `/'. */
  223. if (start > 0 && path[start - 1] == '\\')
  224. continue;
  225. /* Check for trailing `/'. */
  226. if (start && !path[i]) {
  227. zero_last:
  228. path[--i] = '\0';
  229. break;
  230. }
  231. /* Check for `../', `./' or trailing `.' by itself. */
  232. if (path[i] == '.') {
  233. /* Handle trailing `.' by itself. */
  234. if (!path[i + 1])
  235. goto zero_last;
  236. /* Handle `./'. */
  237. if (path[i + 1] == PATH_SEP) {
  238. strcpy (path + i, path + i + 1);
  239. i = start;
  240. continue;
  241. }
  242. /* Handle `../' or trailing `..' by itself.
  243. Remove the previous ?/ part with the exception of
  244. ../, which we should leave intact. */
  245. if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
  246. while (--start > -1 && path[start] != PATH_SEP);
  247. if (!strncmp (path + start + 1, "../", 3))
  248. continue;
  249. strcpy (path + start + 1, path + i + 2);
  250. i = start;
  251. continue;
  252. }
  253. }
  254. }
  255. if (!*path) {
  256. *path = stub_char;
  257. path[1] = '\0';
  258. }
  259. return path;
  260. }
  261. #ifndef USE_VFS
  262. /*
  263. int mc_rmdir (char *path);
  264. Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
  265. of ENOTEMPTY.
  266. */
  267. int mc_rmdir (char *path)
  268. {
  269. if (win32_GetPlatform() == OS_Win95) {
  270. if (rmdir(path)) {
  271. SetLastError (ERROR_DIR_NOT_EMPTY);
  272. _doserrno = ERROR_DIR_NOT_EMPTY; /* FIXME: We are always saying the same thing! */
  273. errno = ENOTEMPTY;
  274. return -1;
  275. } else
  276. return 0;
  277. }
  278. else
  279. return rmdir(path); /* No trouble in Windows NT */
  280. }
  281. static int conv_nt_unx_rc(int rc)
  282. {
  283. int errCode;
  284. switch (rc) {
  285. case ERROR_FILE_NOT_FOUND:
  286. case ERROR_PATH_NOT_FOUND:
  287. case ERROR_TOO_MANY_OPEN_FILES:
  288. errCode = ENOENT;
  289. break;
  290. case ERROR_INVALID_HANDLE:
  291. case ERROR_ARENA_TRASHED:
  292. case ERROR_ACCESS_DENIED:
  293. case ERROR_INVALID_ACCESS:
  294. case ERROR_WRITE_PROTECT:
  295. case ERROR_WRITE_FAULT:
  296. case ERROR_READ_FAULT:
  297. case ERROR_SHARING_VIOLATION:
  298. errCode = EACCES;
  299. break;
  300. case ERROR_NOT_ENOUGH_MEMORY:
  301. errCode = ENOMEM;
  302. break;
  303. case ERROR_INVALID_BLOCK:
  304. case ERROR_INVALID_FUNCTION:
  305. case ERROR_INVALID_DRIVE:
  306. errCode = ENODEV;
  307. break;
  308. case ERROR_CURRENT_DIRECTORY:
  309. errCode = ENOTDIR;
  310. break;
  311. case ERROR_NOT_READY:
  312. errCode = EINVAL;
  313. break;
  314. default:
  315. errCode = EINVAL;
  316. break;
  317. } /* endswitch */
  318. return errCode;
  319. }
  320. /*
  321. int mc_unlink (char *pathName)
  322. For Windows 95 and NT, files should be able to be deleted even
  323. if they don't have write-protection. We should build a question box
  324. like: Delete anyway? Yes <No> All
  325. */
  326. int mc_unlink (char *pathName)
  327. {
  328. char *fileName;
  329. char *trunced_name;
  330. static int erase_all = 0;
  331. BOOL rc;
  332. DWORD returnError;
  333. rc = DeleteFile(pathName);
  334. returnError = GetLastError();
  335. if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
  336. int result;
  337. if (!erase_all) {
  338. errno = conv_nt_unx_rc(returnError);
  339. trunced_name = name_trunc(pathName, 30);
  340. fileName = (char *) malloc(strlen(trunced_name) + 16);
  341. strcpy(fileName, "File ");
  342. strcat(fileName, trunced_name);
  343. strcat(fileName, " protected");
  344. result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
  345. free(fileName);
  346. switch (result) {
  347. case 0:
  348. do_refresh ();
  349. return -1;
  350. case 1:
  351. do_refresh ();
  352. break;
  353. case 2:
  354. do_refresh ();
  355. erase_all = 1;
  356. break;
  357. default:
  358. do_refresh ();
  359. return -1;
  360. break;
  361. }
  362. }
  363. chmod(pathName, S_IWRITE); /* make it writable */
  364. rc = DeleteFile(pathName);
  365. returnError = GetLastError();
  366. if (rc == FALSE) {
  367. errno = conv_nt_unx_rc(returnError);
  368. return -1;
  369. }
  370. }
  371. if (rc == TRUE) return 0;
  372. else
  373. return -1;
  374. }
  375. /*
  376. int mc_rename (char *original, char *target)
  377. Fix for Win95 and WinNT BUG in rename: they will return ENOACCESS instead
  378. of EXDEV.
  379. */
  380. int mc_rename (char* original, char *target)
  381. {
  382. /* check same device: easy with FAT/NTFS, first letter is drive
  383. FIXME: network paths will fail this test */
  384. if (*original != *target) {
  385. SetLastError (ERROR_NOT_SAME_DEVICE);
  386. _doserrno = ERROR_NOT_SAME_DEVICE;
  387. errno = EXDEV;
  388. return -1;
  389. }
  390. else
  391. return rename(original,target);
  392. }
  393. #endif /*USE_VFS*/
  394. void my_statfs (struct my_statfs *myfs_stats, char *path)
  395. {
  396. int i, len = 0;
  397. DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
  398. DWORD lpMaximumComponentLength, dw, lpFileSystemFlags;
  399. static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
  400. GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
  401. &lpFreeClusters, &lpClusters);
  402. /* KBytes available */
  403. myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
  404. /* KBytes total */
  405. myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
  406. myfs_stats->nfree = lpFreeClusters;
  407. myfs_stats->nodes = lpClusters;
  408. GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
  409. &lpMaximumComponentLength, &lpFileSystemFlags,
  410. lpFileSystemNameBuffer, 30);
  411. myfs_stats->mpoint = lpFileSystemNameBuffer;
  412. myfs_stats->device = lpVolumeNameBuffer;
  413. myfs_stats->type = GetDriveType(NULL);
  414. switch (myfs_stats->type) {
  415. /*
  416. * mmm. DeviceIoControl may fail if you are not root case
  417. * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
  418. * myfs_stats->typename = "5.25\" 1.2MB"; break; case
  419. * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
  420. * myfs_stats->typename = "3.5\" 1.44MB"; break; case
  421. * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
  422. * myfs_stats->typename = "3.5\" 2.88MB"; break; case
  423. * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
  424. * myfs_stats->typename = "3.5\" 20.8MB"; break; case
  425. * F3_720_512, 3.5", 720KB, 512 bytes/sector
  426. * myfs_stats->typename = "3.5\" 720MB"; break; case
  427. * F5_360_512, 5.25", 360KB, 512 bytes/sector
  428. * myfs_stats->typename = "5.25\" 360KB"; break; case
  429. * F5_320_512, 5.25", 320KB, 512 bytes/sector
  430. * case F5_320_1024, 5.25", 320KB, 1024
  431. * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
  432. * case F5_180_512, 5.25", 180KB, 512
  433. * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
  434. * case F5_160_512, 5.25", 160KB, 512
  435. * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
  436. * case RemovableMedia, Removable media other than
  437. * floppy myfs_stats->typename = "Removable"; break; case
  438. * FixedMedia Fixed hard disk media
  439. * myfs_stats->typename = "Hard Disk"; break; case Unknown:
  440. * Format is unknown
  441. */
  442. case DRIVE_REMOVABLE:
  443. myfs_stats->typename = "Removable";
  444. break;
  445. case DRIVE_FIXED:
  446. myfs_stats->typename = "Hard Disk";
  447. break;
  448. case DRIVE_REMOTE:
  449. myfs_stats->typename = "Networked";
  450. break;
  451. case DRIVE_CDROM:
  452. myfs_stats->typename = "CD-ROM";
  453. break;
  454. case DRIVE_RAMDISK:
  455. myfs_stats->typename = "RAM disk";
  456. break;
  457. default:
  458. myfs_stats->typename = "unknown";
  459. break;
  460. };
  461. }
  462. int gettimeofday (struct timeval* tvp, void *p)
  463. {
  464. if (p != NULL)
  465. return 0;
  466. /* Since MC only calls this func from get_random_hint we return
  467. some value, not exactly the "correct" one */
  468. tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
  469. tvp->tv_usec = GetTickCount();
  470. }
  471. // FAKE funcs
  472. int
  473. look_for_exe(const char* pathname)
  474. {
  475. int j;
  476. char *p;
  477. int lgh = strlen(pathname);
  478. if (lgh < 4) {
  479. return 0;
  480. } else {
  481. p = (char *) pathname;
  482. for (j=0; j<lgh-4; j++) {
  483. p++;
  484. } /* endfor */
  485. if (!stricmp(p, ".exe") ||
  486. !stricmp(p, ".bat") ||
  487. !stricmp(p, ".com") ||
  488. !stricmp(p, ".cmd")) {
  489. return 1;
  490. }
  491. }
  492. return 0;
  493. }
  494. int
  495. lstat (const char* pathname, struct stat *buffer)
  496. {
  497. int rc = stat (pathname, buffer);
  498. #ifdef __BORLANDC__
  499. if (rc == 0) {
  500. if (!(buffer->st_mode & S_IFDIR)) {
  501. if (!look_for_exe(pathname)) {
  502. buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
  503. }
  504. }
  505. }
  506. #endif
  507. return rc;
  508. }
  509. int getuid ()
  510. {
  511. /* SID sid;
  512. LookupAccountName (NULL, &sid...
  513. return 0;
  514. */
  515. return 0;
  516. }
  517. int getgid ()
  518. {
  519. return 0;
  520. }
  521. int readlink (char* path, char* buf, int size)
  522. {
  523. return -1;
  524. }
  525. int symlink (char *n1, char *n2)
  526. {
  527. return -1;
  528. }
  529. int link (char *p1, char *p2)
  530. {
  531. return -1;
  532. }
  533. int chown (char *path, int owner, int group)
  534. {
  535. return -1;
  536. }
  537. int mknod (char *path, int mode, int dev)
  538. {
  539. return -1;
  540. }
  541. void init_uid_gid_cache (void)
  542. {
  543. return;
  544. }
  545. int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
  546. {
  547. return 0;
  548. }
  549. int mc_doublepclose (int pipe, pid_t pid)
  550. {
  551. /* win32Trace(("mc_doublepclose called")); */
  552. return 0;
  553. }
  554. /*hacks to get it compile, remove these after vfs works */
  555. #ifndef USE_VFS
  556. char *vfs_get_current_dir (void)
  557. {
  558. return NULL;
  559. }
  560. int vfs_current_is_extfs (void)
  561. {
  562. return 0;
  563. }
  564. int vfs_file_is_ftp (char *filename)
  565. {
  566. return 0;
  567. }
  568. int mc_utime (char *path, struct utimbuf *times)
  569. {
  570. return 0;
  571. }
  572. void extfs_run (char *file)
  573. {
  574. return;
  575. }
  576. #endif
  577. int strncasecmp (char *s, char *d, int count)
  578. {
  579. register char result;
  580. while (count > 0){
  581. if (result = (0x20 | *s) - (0x20 | *d))
  582. break;
  583. if (!*s)
  584. return 0;
  585. s++;
  586. d++;
  587. count--;
  588. }
  589. return result;
  590. }
  591. char *
  592. get_default_editor (void)
  593. {
  594. return "vi.exe";
  595. }
  596. int
  597. errno_dir_not_empty (int err)
  598. {
  599. if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
  600. return 1;
  601. return 0;
  602. }
  603. /* The MC library directory is by default the directory where mc.exe
  604. is situated. It is possible to specify this directory via MCHOME
  605. environment variable */
  606. char *
  607. get_mc_lib_dir ()
  608. {
  609. char *cur;
  610. char *mchome = getenv("MCHOME");
  611. if (mchome && *mchome)
  612. return mchome;
  613. mchome = malloc(MC_MAXPATHLEN);
  614. GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
  615. for (cur = mchome + strlen(mchome); \
  616. (cur > mchome) && (*cur != PATH_SEP); cur--);
  617. *cur = 0;
  618. cur = strdup(mchome);
  619. free(mchome);
  620. if (!cur || !*cur) {
  621. free(cur);
  622. return "C:\\MC";
  623. }
  624. return cur;
  625. }
  626. int get_user_rights (struct stat *buf)
  627. {
  628. return 2;
  629. }
  630. void init_groups (void)
  631. {
  632. }
  633. void delete_groups (void)
  634. {
  635. }