util_nt.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "../src/fs.h"
  33. #include "../src/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 = -1; // read (error_pipe[0], error + len, 1);
  105. if (rvalue <= 0)
  106. break;
  107. len ++;
  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. Cannot do simple define. That would need <windows.h> in every source
  173. */
  174. #ifndef __EMX__
  175. void sleep(unsigned long dwMiliSecs)
  176. {
  177. Sleep(dwMiliSecs);
  178. }
  179. #endif
  180. /* Canonicalize path, and return a new path. Do everything in situ.
  181. The new path differs from path in:
  182. Multiple `/'s are collapsed to a single `/'.
  183. Leading `./'s and trailing `/.'s are removed.
  184. Trailing `/'s are removed.
  185. Non-leading `../'s and trailing `..'s are handled by removing
  186. portions of the path. */
  187. char *canonicalize_pathname (char *path)
  188. {
  189. int i, start;
  190. char stub_char;
  191. stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
  192. /* Walk along path looking for things to compact. */
  193. i = 0;
  194. for (;;) {
  195. if (!path[i])
  196. break;
  197. while (path[i] && path[i] != PATH_SEP)
  198. i++;
  199. start = i++;
  200. /* If we didn't find any slashes, then there is nothing left to do. */
  201. if (!path[start])
  202. break;
  203. /* Handle multiple `/'s in a row. */
  204. while (path[i] == PATH_SEP)
  205. i++;
  206. if ((start + 1) != i) {
  207. strcpy (path + start + 1, path + i);
  208. i = start + 1;
  209. }
  210. /* Check for trailing `/'. */
  211. if (start && !path[i]) {
  212. zero_last:
  213. path[--i] = '\0';
  214. break;
  215. }
  216. /* Check for `../', `./' or trailing `.' by itself. */
  217. if (path[i] == '.') {
  218. /* Handle trailing `.' by itself. */
  219. if (!path[i + 1])
  220. goto zero_last;
  221. /* Handle `./'. */
  222. if (path[i + 1] == PATH_SEP) {
  223. strcpy (path + i, path + i + 1);
  224. i = start;
  225. continue;
  226. }
  227. /* Handle `../' or trailing `..' by itself.
  228. Remove the previous ?/ part with the exception of
  229. ../, which we should leave intact. */
  230. if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
  231. while (--start > -1 && path[start] != PATH_SEP);
  232. if (!strncmp (path + start + 1, "../", 3))
  233. continue;
  234. strcpy (path + start + 1, path + i + 2);
  235. i = start;
  236. continue;
  237. }
  238. }
  239. }
  240. if (!*path) {
  241. *path = stub_char;
  242. path[1] = '\0';
  243. }
  244. return path;
  245. }
  246. #ifndef USE_VFS
  247. /*
  248. int mc_rmdir (char *path);
  249. Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
  250. of ENOTEMPTY.
  251. */
  252. int mc_rmdir (char *path)
  253. {
  254. if (win32_GetPlatform() == OS_Win95) {
  255. if (rmdir(path)) {
  256. SetLastError (ERROR_DIR_NOT_EMPTY);
  257. #ifndef __EMX__
  258. /* FIXME: We are always saying the same thing! */
  259. _doserrno = ERROR_DIR_NOT_EMPTY;
  260. #endif
  261. errno = ENOTEMPTY;
  262. return -1;
  263. } else
  264. return 0;
  265. }
  266. else
  267. return rmdir(path); /* No trouble in Windows NT */
  268. }
  269. static int conv_nt_unx_rc(int rc)
  270. {
  271. int errCode;
  272. switch (rc) {
  273. case ERROR_FILE_NOT_FOUND:
  274. case ERROR_PATH_NOT_FOUND:
  275. case ERROR_TOO_MANY_OPEN_FILES:
  276. errCode = ENOENT;
  277. break;
  278. case ERROR_INVALID_HANDLE:
  279. case ERROR_ARENA_TRASHED:
  280. case ERROR_ACCESS_DENIED:
  281. case ERROR_INVALID_ACCESS:
  282. case ERROR_WRITE_PROTECT:
  283. case ERROR_WRITE_FAULT:
  284. case ERROR_READ_FAULT:
  285. case ERROR_SHARING_VIOLATION:
  286. errCode = EACCES;
  287. break;
  288. case ERROR_NOT_ENOUGH_MEMORY:
  289. errCode = ENOMEM;
  290. break;
  291. case ERROR_INVALID_BLOCK:
  292. case ERROR_INVALID_FUNCTION:
  293. case ERROR_INVALID_DRIVE:
  294. errCode = ENODEV;
  295. break;
  296. case ERROR_CURRENT_DIRECTORY:
  297. errCode = ENOTDIR;
  298. break;
  299. case ERROR_NOT_READY:
  300. errCode = EINVAL;
  301. break;
  302. default:
  303. errCode = EINVAL;
  304. break;
  305. } /* endswitch */
  306. return errCode;
  307. }
  308. /*
  309. int mc_unlink (char *pathName)
  310. For Windows 95 and NT, files should be able to be deleted even
  311. if they don't have write-protection. We should build a question box
  312. like: Delete anyway? Yes <No> All
  313. */
  314. int mc_unlink (char *pathName)
  315. {
  316. char *fileName;
  317. char *trunced_name;
  318. static int erase_all = 0;
  319. BOOL rc;
  320. DWORD returnError;
  321. rc = DeleteFile(pathName);
  322. returnError = GetLastError();
  323. if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
  324. int result;
  325. if (!erase_all) {
  326. errno = conv_nt_unx_rc(returnError);
  327. trunced_name = name_trunc(pathName, 30);
  328. fileName = (char *) malloc(strlen(trunced_name) + 16);
  329. strcpy(fileName, "File ");
  330. strcat(fileName, trunced_name);
  331. strcat(fileName, " protected");
  332. result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
  333. free(fileName);
  334. switch (result) {
  335. case 0:
  336. do_refresh ();
  337. return -1;
  338. case 1:
  339. do_refresh ();
  340. break;
  341. case 2:
  342. do_refresh ();
  343. erase_all = 1;
  344. break;
  345. default:
  346. do_refresh ();
  347. return -1;
  348. break;
  349. }
  350. }
  351. chmod(pathName, S_IWRITE); /* make it writable */
  352. rc = DeleteFile(pathName);
  353. returnError = GetLastError();
  354. if (rc == FALSE) {
  355. errno = conv_nt_unx_rc(returnError);
  356. return -1;
  357. }
  358. }
  359. if (rc == TRUE) return 0;
  360. else
  361. return -1;
  362. }
  363. #endif /*USE_VFS*/
  364. void my_statfs (struct my_statfs *myfs_stats, char *path)
  365. {
  366. int len = 0;
  367. DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
  368. DWORD lpMaximumComponentLength, lpFileSystemFlags;
  369. static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
  370. GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
  371. &lpFreeClusters, &lpClusters);
  372. /* KBytes available */
  373. myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
  374. /* KBytes total */
  375. myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
  376. myfs_stats->nfree = lpFreeClusters;
  377. myfs_stats->nodes = lpClusters;
  378. GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
  379. &lpMaximumComponentLength, &lpFileSystemFlags,
  380. lpFileSystemNameBuffer, 30);
  381. myfs_stats->mpoint = lpFileSystemNameBuffer;
  382. myfs_stats->device = lpVolumeNameBuffer;
  383. myfs_stats->type = GetDriveType(NULL);
  384. switch (myfs_stats->type) {
  385. /*
  386. * mmm. DeviceIoControl may fail if you are not root case
  387. * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
  388. * myfs_stats->typename = "5.25\" 1.2MB"; break; case
  389. * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
  390. * myfs_stats->typename = "3.5\" 1.44MB"; break; case
  391. * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
  392. * myfs_stats->typename = "3.5\" 2.88MB"; break; case
  393. * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
  394. * myfs_stats->typename = "3.5\" 20.8MB"; break; case
  395. * F3_720_512, 3.5", 720KB, 512 bytes/sector
  396. * myfs_stats->typename = "3.5\" 720MB"; break; case
  397. * F5_360_512, 5.25", 360KB, 512 bytes/sector
  398. * myfs_stats->typename = "5.25\" 360KB"; break; case
  399. * F5_320_512, 5.25", 320KB, 512 bytes/sector
  400. * case F5_320_1024, 5.25", 320KB, 1024
  401. * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
  402. * case F5_180_512, 5.25", 180KB, 512
  403. * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
  404. * case F5_160_512, 5.25", 160KB, 512
  405. * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
  406. * case RemovableMedia, Removable media other than
  407. * floppy myfs_stats->typename = "Removable"; break; case
  408. * FixedMedia Fixed hard disk media
  409. * myfs_stats->typename = "Hard Disk"; break; case Unknown:
  410. * Format is unknown
  411. */
  412. case DRIVE_REMOVABLE:
  413. myfs_stats->typename = "Removable";
  414. break;
  415. case DRIVE_FIXED:
  416. myfs_stats->typename = "Hard Disk";
  417. break;
  418. case DRIVE_REMOTE:
  419. myfs_stats->typename = "Networked";
  420. break;
  421. case DRIVE_CDROM:
  422. myfs_stats->typename = "CD-ROM";
  423. break;
  424. case DRIVE_RAMDISK:
  425. myfs_stats->typename = "RAM disk";
  426. break;
  427. default:
  428. myfs_stats->typename = "unknown";
  429. break;
  430. };
  431. }
  432. int gettimeofday (struct timeval* tvp, void *p)
  433. {
  434. if (p != NULL)
  435. return 0;
  436. /* Since MC only calls this func from get_random_hint we return
  437. some value, not exactly the "correct" one */
  438. tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
  439. tvp->tv_usec = GetTickCount();
  440. }
  441. /* FAKE functions */
  442. int
  443. look_for_exe(const char* pathname)
  444. {
  445. int j;
  446. char *p;
  447. int lgh = strlen(pathname);
  448. if (lgh < 4) {
  449. return 0;
  450. } else {
  451. p = (char *) pathname;
  452. for (j=0; j<lgh-4; j++) {
  453. p++;
  454. } /* endfor */
  455. if (!stricmp(p, ".exe") ||
  456. !stricmp(p, ".bat") ||
  457. !stricmp(p, ".com") ||
  458. !stricmp(p, ".cmd")) {
  459. return 1;
  460. }
  461. }
  462. return 0;
  463. }
  464. int
  465. lstat (const char* pathname, struct stat *buffer)
  466. {
  467. int rc = stat (pathname, buffer);
  468. #ifdef __BORLANDC__
  469. if (rc == 0) {
  470. if (!(buffer->st_mode & S_IFDIR)) {
  471. if (!look_for_exe(pathname)) {
  472. buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
  473. }
  474. }
  475. }
  476. #endif
  477. return rc;
  478. }
  479. int getuid ()
  480. {
  481. /* SID sid;
  482. LookupAccountName (NULL, &sid...
  483. return 0;
  484. */
  485. return 0;
  486. }
  487. int getgid ()
  488. {
  489. return 0;
  490. }
  491. int readlink (char* path, char* buf, int size)
  492. {
  493. return -1;
  494. }
  495. int symlink (char *n1, char *n2)
  496. {
  497. return -1;
  498. }
  499. int link (char *p1, char *p2)
  500. {
  501. return -1;
  502. }
  503. int chown (char *path, int owner, int group)
  504. {
  505. return -1;
  506. }
  507. int mknod (char *path, int mode, int dev)
  508. {
  509. return -1;
  510. }
  511. void init_uid_gid_cache (void)
  512. {
  513. return;
  514. }
  515. /* INHANDLE is a result of some mc_open call to any vfs, this function
  516. returns a normal handle (to be used with read) of a pipe for reading
  517. of the output of COMMAND with arguments ... (must include argv[0] as
  518. well) which gets as its input at most INLEN bytes from the INHANDLE
  519. using mc_read. You have to call mc_doublepclose to close the returned
  520. handle afterwards. If INLEN is -1, we read as much as we can :) */
  521. int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
  522. {
  523. int pipe0 [2], pipe1 [2], std_sav [2];
  524. #define MAXARGS 16
  525. int argno;
  526. char *args[MAXARGS];
  527. char buffer [8192];
  528. int i;
  529. va_list ap;
  530. pid_t pid;
  531. // Create the pipes
  532. if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
  533. exit (1);
  534. if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
  535. exit (1);
  536. // Duplicate stdin/stdout handles (next line will close original)
  537. std_sav[0] = _dup(_fileno(stdin));
  538. std_sav[1] = _dup(_fileno(stdout));
  539. // Duplicate read end of pipe0 to stdin handle
  540. if(_dup2(pipe0[0], _fileno(stdin)) != 0)
  541. exit (1);
  542. // Duplicate write end of pipe1 to stdout handle
  543. if(_dup2(pipe1[1], _fileno(stdout)) != 0)
  544. exit (1);
  545. // Close original read end of pipe0
  546. close(pipe0[0]);
  547. // Close original write end of pipe1
  548. close(pipe1[1]);
  549. va_start (ap, command);
  550. argno = 0;
  551. while ((args[argno++] = va_arg(ap, char *)) != NULL)
  552. if (argno == (MAXARGS - 1)) {
  553. args[argno] = NULL;
  554. break;
  555. }
  556. va_end (ap);
  557. // Spawn process
  558. pid = spawnvp(P_NOWAIT,command, args);// argv[1], (const char* const*)&argv[1]);
  559. if(!pid)
  560. exit (1);
  561. // Duplicate copy of original stdin back into stdin
  562. if(_dup2(std_sav[0], _fileno(stdin)) != 0)
  563. exit (1);
  564. // Duplicate copy of original stdout back into stdout
  565. if(_dup2(std_sav[1], _fileno(stdout)) != 0)
  566. exit (1);
  567. // Close duplicate copy of original stdout and stdin
  568. close(std_sav[0]);
  569. close(std_sav[1]);
  570. while ((i = _read (inhandle, buffer,
  571. (inlen == -1 || inlen > 8192)
  572. ? 8192 : inlen)) > 0) {
  573. write (pipe0 [1], buffer, i);
  574. if (inlen != -1) {
  575. inlen -= i;
  576. if (!inlen)
  577. break;
  578. }
  579. }
  580. close (pipe0 [1]);
  581. *the_pid = pid;
  582. return pipe1 [0];
  583. }
  584. int mc_doublepclose (int pipe, pid_t pid)
  585. {
  586. int status = 0;
  587. close (pipe);
  588. _cwait ( &status, pid, 0);
  589. return status;
  590. }
  591. /*hacks to get it compile, remove these after vfs works */
  592. /*hacks to get it compile, remove these after vfs works */
  593. #ifndef USE_VFS
  594. char *vfs_get_current_dir (void)
  595. {
  596. return NULL;
  597. }
  598. int vfs_current_is_extfs (void)
  599. {
  600. return 0;
  601. }
  602. int vfs_file_is_ftp (char *filename)
  603. {
  604. return 0;
  605. }
  606. int mc_utime (char *path, void *times)
  607. {
  608. return 0;
  609. }
  610. void extfs_run (char *file)
  611. {
  612. return;
  613. }
  614. #endif
  615. char *
  616. get_default_editor (void)
  617. {
  618. return "notepad.exe";
  619. }
  620. int
  621. errno_dir_not_empty (int err)
  622. {
  623. if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
  624. return 1;
  625. return 0;
  626. }
  627. /* The MC library directory is by default the directory where mc.exe
  628. is situated. It is possible to specify this directory via MCHOME
  629. environment variable */
  630. char *
  631. get_mc_lib_dir ()
  632. {
  633. char *cur;
  634. char *mchome = getenv("MCHOME");
  635. if (mchome && *mchome)
  636. return mchome;
  637. mchome = malloc(MC_MAXPATHLEN);
  638. GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
  639. for (cur = mchome + strlen(mchome); \
  640. (cur > mchome) && (*cur != PATH_SEP); cur--);
  641. *cur = 0;
  642. cur = strdup(mchome);
  643. free(mchome);
  644. if (!cur || !*cur) {
  645. free(cur);
  646. return "C:\\MC";
  647. }
  648. return cur;
  649. }
  650. int get_user_rights (struct stat *buf)
  651. {
  652. return 2;
  653. }
  654. void init_groups (void)
  655. {
  656. }
  657. void delete_groups (void)
  658. {
  659. }