*** empty log message ***
[midnight-commander.git] / pc / util_nt.c
bloba3a447c92f86ce5ef9467f30adf5448f92a3bc57
1 /* Various utilities - NT versions
2 Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
4 Written 1994, 1995, 1996 by:
5 Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
6 Jakub Jelinek, Mauricio Plaza.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 #include <config.h>
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <windows.h>
27 #include <io.h>
28 #include <fcntl.h>
29 #include <signal.h> /* my_system */
30 #include <limits.h> /* INT_MAX */
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <stdarg.h>
34 #include <process.h>
35 #include "../src/global.h"
36 #include "../src/util.h"
37 #include "util_win32.h"
39 #ifdef __BORLANDC__
40 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
41 #endif
43 char *get_owner (int uid)
45 return "none";
48 char *get_group (int gid)
50 return "none";
53 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
54 /* More than that would be unportable */
55 #define MAX_PIPE_SIZE 4096
57 static int error_pipe[2]; /* File descriptors of error pipe */
58 static int old_error; /* File descriptor of old standard error */
60 /* Creates a pipe to hold standard error for a later analysis. */
61 /* The pipe can hold 4096 bytes. Make sure no more is written */
62 /* or a deadlock might occur. */
63 void open_error_pipe (void)
65 if (pipe (error_pipe) < 0){
66 message (0, " Warning ", " Pipe failed ");
68 old_error = dup (2);
69 if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
70 message (0, " Warning ", " Dup failed ");
71 close (error_pipe[0]);
72 close (error_pipe[1]);
74 close (error_pipe[1]);
78 * Returns true if an error was displayed
80 int close_error_pipe (int error, char *text)
82 char *title;
83 char msg[MAX_PIPE_SIZE];
84 int len = 0;
86 if (error)
87 title = " Error ";
88 else
89 title = " Warning ";
90 if (old_error >= 0){
91 close (2);
92 dup (old_error);
93 close (old_error);
94 len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
96 if (len >= 0)
97 msg[len] = 0;
98 close (error_pipe[0]);
100 if (error < 0)
101 return 0; /* Just ignore error message */
102 if (text == NULL){
103 if (len == 0) return 0; /* Nothing to show */
105 /* Show message from pipe */
106 message (error, title, "%s", msg);
107 } else {
108 /* Show given text and possible message from pipe */
109 message (error, title, " %s \n %s ", text, msg);
111 return 1;
114 void check_error_pipe (void)
116 char error[MAX_PIPE_SIZE];
117 int len = 0;
118 if (old_error >= 0){
119 while (len < MAX_PIPE_SIZE)
121 int rvalue;
123 rvalue = -1; /* read (error_pipe[0], error + len, 1); */
124 if (rvalue <= 0)
125 break;
126 len ++;
128 error[len] = 0;
129 close (error_pipe[0]);
131 if (len > 0)
132 message (0, " Warning ", "%s", error);
135 int my_system (int as_shell_command, const char *shell, const char *command)
137 int status = 0;
139 #if 0
140 /* .ado: temp. turn out */
141 if (as_shell_command) {
142 /* It is only the shell, /c will not work */
143 if (command)
144 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
145 else
146 spawnlp (P_WAIT, shell, (char *) 0);
147 } else
148 spawnl (P_WAIT, shell, shell, command, (char *) 0);
150 if (win32_GetPlatform() == OS_Win95) {
151 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
153 #endif
154 if (as_shell_command) {
155 if (!access(command, 0)) {
156 switch(win32_GetEXEType (shell)) {
157 case EXE_win16: /* Windows 3.x archive or OS/2 */
158 case EXE_win32GUI: /* NT or Chicago GUI API */
159 spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
160 break;
161 case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
162 case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
163 case EXE_Unknown:
164 default:
165 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
166 break;
169 else
170 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
172 else
173 spawnl (P_WAIT, shell, shell, command, (char *) 0);
175 if (win32_GetPlatform() == OS_Win95) {
176 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
179 return status;
182 /* get_default_shell
183 Get the default shell for the current hardware platform
185 char* get_default_shell()
187 if (win32_GetPlatform() == OS_WinNT)
188 return "cmd.exe";
189 else
190 return "command.com";
193 char *tilde_expand (const char *directory)
195 return strdup (directory);
198 /* sleep: Call Windows API.
199 Cannot do simple define. That would need <windows.h> in every source
201 #ifndef __EMX__
202 void sleep(unsigned long dwMiliSecs)
204 Sleep(dwMiliSecs);
206 #endif
208 /* Canonicalize path, and return a new path. Do everything in situ.
209 The new path differs from path in:
210 Multiple `/'s are collapsed to a single `/'.
211 Leading `./'s and trailing `/.'s are removed.
212 Trailing `/'s are removed.
213 Non-leading `../'s and trailing `..'s are handled by removing
214 portions of the path. */
215 char *canonicalize_pathname (char *path)
217 int i, start;
218 char stub_char;
220 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
222 /* Walk along path looking for things to compact. */
223 i = 0;
224 for (;;) {
225 if (!path[i])
226 break;
228 while (path[i] && path[i] != PATH_SEP)
229 i++;
231 start = i++;
233 /* If we didn't find any slashes, then there is nothing left to do. */
234 if (!path[start])
235 break;
237 /* Handle multiple `/'s in a row. */
238 while (path[i] == PATH_SEP)
239 i++;
241 if ((start + 1) != i) {
242 strcpy (path + start + 1, path + i);
243 i = start + 1;
246 /* Check for trailing `/'. */
247 if (start && !path[i]) {
248 zero_last:
249 path[--i] = '\0';
250 break;
253 /* Check for `../', `./' or trailing `.' by itself. */
254 if (path[i] == '.') {
255 /* Handle trailing `.' by itself. */
256 if (!path[i + 1])
257 goto zero_last;
259 /* Handle `./'. */
260 if (path[i + 1] == PATH_SEP) {
261 strcpy (path + i, path + i + 1);
262 i = start;
263 continue;
266 /* Handle `../' or trailing `..' by itself.
267 Remove the previous ?/ part with the exception of
268 ../, which we should leave intact. */
269 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
270 while (--start > -1 && path[start] != PATH_SEP);
271 if (!strncmp (path + start + 1, "../", 3))
272 continue;
273 strcpy (path + start + 1, path + i + 2);
274 i = start;
275 continue;
280 if (!*path) {
281 *path = stub_char;
282 path[1] = '\0';
284 return path;
287 #ifndef USE_VFS
289 int mc_rmdir (char *path);
290 Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
291 of ENOTEMPTY.
293 int mc_rmdir (char *path)
295 if (win32_GetPlatform() == OS_Win95) {
296 if (rmdir(path)) {
297 SetLastError (ERROR_DIR_NOT_EMPTY);
298 #ifndef __EMX__
299 /* FIXME: We are always saying the same thing! */
300 _doserrno = ERROR_DIR_NOT_EMPTY;
301 #endif
302 errno = ENOTEMPTY;
303 return -1;
304 } else
305 return 0;
307 else
308 return rmdir(path); /* No trouble in Windows NT */
311 static int conv_nt_unx_rc(int rc)
313 int errCode;
314 switch (rc) {
315 case ERROR_FILE_NOT_FOUND:
316 case ERROR_PATH_NOT_FOUND:
317 case ERROR_TOO_MANY_OPEN_FILES:
318 errCode = ENOENT;
319 break;
320 case ERROR_INVALID_HANDLE:
321 case ERROR_ARENA_TRASHED:
322 case ERROR_ACCESS_DENIED:
323 case ERROR_INVALID_ACCESS:
324 case ERROR_WRITE_PROTECT:
325 case ERROR_WRITE_FAULT:
326 case ERROR_READ_FAULT:
327 case ERROR_SHARING_VIOLATION:
328 errCode = EACCES;
329 break;
330 case ERROR_NOT_ENOUGH_MEMORY:
331 errCode = ENOMEM;
332 break;
333 case ERROR_INVALID_BLOCK:
334 case ERROR_INVALID_FUNCTION:
335 case ERROR_INVALID_DRIVE:
336 errCode = ENODEV;
337 break;
338 case ERROR_CURRENT_DIRECTORY:
339 errCode = ENOTDIR;
340 break;
341 case ERROR_NOT_READY:
342 errCode = EINVAL;
343 break;
344 default:
345 errCode = EINVAL;
346 break;
347 } /* endswitch */
348 return errCode;
352 int mc_unlink (char *pathName)
353 For Windows 95 and NT, files should be able to be deleted even
354 if they don't have write-protection. We should build a question box
355 like: Delete anyway? Yes <No> All
357 int mc_unlink (char *pathName)
359 char *fileName;
360 char *trunced_name;
361 static int erase_all = 0;
362 BOOL rc;
363 DWORD returnError;
365 rc = DeleteFile(pathName);
366 returnError = GetLastError();
367 if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
368 int result;
369 if (!erase_all) {
370 errno = conv_nt_unx_rc(returnError);
371 trunced_name = name_trunc(pathName, 30);
372 fileName = (char *) malloc(strlen(trunced_name) + 16);
373 strcpy(fileName, "File ");
374 strcat(fileName, trunced_name);
375 strcat(fileName, " protected");
376 result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
377 free(fileName);
379 switch (result) {
380 case 0:
381 do_refresh ();
382 return -1;
383 case 1:
384 do_refresh ();
385 break;
386 case 2:
387 do_refresh ();
388 erase_all = 1;
389 break;
390 default:
391 do_refresh ();
392 return -1;
393 break;
397 chmod(pathName, S_IWRITE); /* make it writable */
398 rc = DeleteFile(pathName);
399 returnError = GetLastError();
400 if (rc == FALSE) {
401 errno = conv_nt_unx_rc(returnError);
402 return -1;
405 if (rc == TRUE) return 0;
406 else
407 return -1;
409 #endif /*USE_VFS*/
411 void my_statfs (struct my_statfs *myfs_stats, char *path)
413 int len = 0;
414 DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
415 DWORD lpMaximumComponentLength, lpFileSystemFlags;
416 static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
418 GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
419 &lpFreeClusters, &lpClusters);
421 /* KBytes available */
422 myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
424 /* KBytes total */
425 myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
426 myfs_stats->nfree = lpFreeClusters;
427 myfs_stats->nodes = lpClusters;
429 GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
430 &lpMaximumComponentLength, &lpFileSystemFlags,
431 lpFileSystemNameBuffer, 30);
433 myfs_stats->mpoint = lpFileSystemNameBuffer;
434 myfs_stats->device = lpVolumeNameBuffer;
437 myfs_stats->type = GetDriveType(NULL);
438 switch (myfs_stats->type) {
440 * mmm. DeviceIoControl may fail if you are not root case
441 * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
442 * myfs_stats->typename = "5.25\" 1.2MB"; break; case
443 * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
444 * myfs_stats->typename = "3.5\" 1.44MB"; break; case
445 * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
446 * myfs_stats->typename = "3.5\" 2.88MB"; break; case
447 * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
448 * myfs_stats->typename = "3.5\" 20.8MB"; break; case
449 * F3_720_512, 3.5", 720KB, 512 bytes/sector
450 * myfs_stats->typename = "3.5\" 720MB"; break; case
451 * F5_360_512, 5.25", 360KB, 512 bytes/sector
452 * myfs_stats->typename = "5.25\" 360KB"; break; case
453 * F5_320_512, 5.25", 320KB, 512 bytes/sector
454 * case F5_320_1024, 5.25", 320KB, 1024
455 * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
456 * case F5_180_512, 5.25", 180KB, 512
457 * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
458 * case F5_160_512, 5.25", 160KB, 512
459 * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
460 * case RemovableMedia, Removable media other than
461 * floppy myfs_stats->typename = "Removable"; break; case
462 * FixedMedia Fixed hard disk media
463 * myfs_stats->typename = "Hard Disk"; break; case Unknown:
464 * Format is unknown
466 case DRIVE_REMOVABLE:
467 myfs_stats->typename = "Removable";
468 break;
469 case DRIVE_FIXED:
470 myfs_stats->typename = "Hard Disk";
471 break;
472 case DRIVE_REMOTE:
473 myfs_stats->typename = "Networked";
474 break;
475 case DRIVE_CDROM:
476 myfs_stats->typename = "CD-ROM";
477 break;
478 case DRIVE_RAMDISK:
479 myfs_stats->typename = "RAM disk";
480 break;
481 default:
482 myfs_stats->typename = "unknown";
483 break;
487 int gettimeofday (struct timeval* tvp, void *p)
489 if (p != NULL)
490 return 0;
492 /* Since MC only calls this func from get_random_hint we return
493 some value, not exactly the "correct" one */
494 tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
495 tvp->tv_usec = GetTickCount();
498 /* FAKE functions */
500 int
501 look_for_exe(const char* pathname)
503 int j;
504 char *p;
505 int lgh = strlen(pathname);
507 if (lgh < 4) {
508 return 0;
509 } else {
510 p = (char *) pathname;
511 for (j=0; j<lgh-4; j++) {
512 p++;
513 } /* endfor */
514 if (!stricmp(p, ".exe") ||
515 !stricmp(p, ".bat") ||
516 !stricmp(p, ".com") ||
517 !stricmp(p, ".cmd")) {
518 return 1;
521 return 0;
524 int
525 lstat (const char* pathname, struct stat *buffer)
527 int rc = stat (pathname, buffer);
528 #ifdef __BORLANDC__
529 if (rc == 0) {
530 if (!(buffer->st_mode & S_IFDIR)) {
531 if (!look_for_exe(pathname)) {
532 buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
536 #endif
537 return rc;
540 int getuid ()
542 /* SID sid;
543 LookupAccountName (NULL, &sid...
544 return 0;
546 return 0;
549 int getgid ()
551 return 0;
554 int readlink (char* path, char* buf, int size)
556 return -1;
558 int symlink (char *n1, char *n2)
560 return -1;
562 int link (char *p1, char *p2)
564 return -1;
566 int chown (char *path, int owner, int group)
568 return -1;
570 int mknod (char *path, int mode, int dev)
572 return -1;
575 void init_uid_gid_cache (void)
577 return;
580 /* INHANDLE is a result of some mc_open call to any vfs, this function
581 returns a normal handle (to be used with read) of a pipe for reading
582 of the output of COMMAND with arguments ... (must include argv[0] as
583 well) which gets as its input at most INLEN bytes from the INHANDLE
584 using mc_read. You have to call mc_doublepclose to close the returned
585 handle afterwards. If INLEN is -1, we read as much as we can :) */
586 int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
588 int pipe0 [2], pipe1 [2], std_sav [2];
589 #define MAXARGS 16
590 int argno;
591 char *args[MAXARGS];
592 char buffer [8192];
593 int i;
594 va_list ap;
596 pid_t pid;
598 /* Create the pipes */
599 if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
600 exit (1);
601 if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
602 exit (1);
603 /* Duplicate stdin/stdout handles (next line will close original) */
604 std_sav[0] = _dup(_fileno(stdin));
605 std_sav[1] = _dup(_fileno(stdout));
606 /* Duplicate read end of pipe0 to stdin handle */
607 if(_dup2(pipe0[0], _fileno(stdin)) != 0)
608 exit (1);
609 /* Duplicate write end of pipe1 to stdout handle */
610 if(_dup2(pipe1[1], _fileno(stdout)) != 0)
611 exit (1);
612 /* Close original read end of pipe0 */
613 close(pipe0[0]);
614 /* Close original write end of pipe1 */
615 close(pipe1[1]);
617 va_start (ap, command);
618 argno = 0;
619 while ((args[argno++] = va_arg(ap, char *)) != NULL)
620 if (argno == (MAXARGS - 1)) {
621 args[argno] = NULL;
622 break;
624 va_end (ap);
625 /* Spawn process */
626 pid = spawnvp(P_NOWAIT,command, args);/* argv[1], (const char* const*)&argv[1]); */
627 if(!pid)
628 exit (1);
629 /* Duplicate copy of original stdin back into stdin */
630 if(_dup2(std_sav[0], _fileno(stdin)) != 0)
631 exit (1);
632 /* Duplicate copy of original stdout back into stdout */
633 if(_dup2(std_sav[1], _fileno(stdout)) != 0)
634 exit (1);
635 /* Close duplicate copy of original stdout and stdin */
636 close(std_sav[0]);
637 close(std_sav[1]);
640 while ((i = _read (inhandle, buffer,
641 (inlen == -1 || inlen > 8192)
642 ? 8192 : inlen)) > 0) {
643 write (pipe0 [1], buffer, i);
644 if (inlen != -1) {
645 inlen -= i;
646 if (!inlen)
647 break;
650 close (pipe0 [1]);
651 *the_pid = pid;
652 return pipe1 [0];
656 int mc_doublepclose (int pipe, pid_t pid)
658 int status = 0;
660 close (pipe);
661 _cwait ( &status, pid, 0);
662 return status;
665 /*hacks to get it compile, remove these after vfs works */
667 /*hacks to get it compile, remove these after vfs works */
668 #ifndef USE_VFS
669 char *vfs_get_current_dir (void)
671 return NULL;
674 int vfs_current_is_extfs (void)
676 return 0;
679 int vfs_file_is_ftp (char *filename)
681 return 0;
684 int mc_utime (char *path, void *times)
686 return 0;
690 void extfs_run (char *file)
692 return;
694 #endif
696 char *
697 get_default_editor (void)
699 return "notepad.exe";
703 errno_dir_not_empty (int err)
705 if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
706 return 1;
707 return 0;
710 /* The MC library directory is by default the directory where mc.exe
711 is situated. It is possible to specify this directory via MCHOME
712 environment variable */
713 char *
714 get_mc_lib_dir ()
716 char *cur;
717 char *mchome = getenv("MCHOME");
719 if (mchome && *mchome)
720 return mchome;
721 mchome = malloc(MC_MAXPATHLEN);
722 GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
723 for (cur = mchome + strlen(mchome); \
724 (cur > mchome) && (*cur != PATH_SEP); cur--);
725 *cur = 0;
726 cur = strdup(mchome);
727 free(mchome);
728 if (!cur || !*cur) {
729 free(cur);
730 return "C:\\MC";
732 return cur;
734 int get_user_rights (struct stat *buf)
736 return 2;
738 void init_groups (void)
741 void delete_groups (void)