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., 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include <sys/types.h>
29 #include <signal.h> /* my_system */
30 #include <limits.h> /* INT_MAX */
33 #include <sys/time.h___> /* select: timeout */
35 #include <sys/time.h> /* select: timeout */
37 #include <sys/param.h>
41 #include "../src/fs.h"
42 #include "../src/util.h"
43 #include "util_win32.h"
46 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
49 char *get_owner (int uid
)
54 char *get_group (int gid
)
59 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
60 /* More than that would be unportable */
61 #define MAX_PIPE_SIZE 4096
63 static int error_pipe
[2]; /* File descriptors of error pipe */
64 static int old_error
; /* File descriptor of old standard error */
66 /* Creates a pipe to hold standard error for a later analysis. */
67 /* The pipe can hold 4096 bytes. Make sure no more is written */
68 /* or a deadlock might occur. */
69 void open_error_pipe (void)
71 if (pipe (error_pipe
) < 0){
72 message (0, _(" Warning "), _(" Pipe failed ") );
75 if(old_error
< 0 || close(2) || dup (error_pipe
[1]) != 2){
76 message (0, _(" Warning "), _(" Dup failed ") );
77 close (error_pipe
[0]);
78 close (error_pipe
[1]);
80 close (error_pipe
[1]);
83 void close_error_pipe (int error
, char *text
)
86 char msg
[MAX_PIPE_SIZE
];
92 title
= _(" Warning ");
97 len
= read (error_pipe
[0], msg
, MAX_PIPE_SIZE
);
101 close (error_pipe
[0]);
104 return; /* Just ignore error message */
106 if (len
== 0) return; /* Nothing to show */
108 /* Show message from pipe */
109 message (error
, title
, msg
);
111 /* Show given text and possible message from pipe */
112 message (error
, title
, " %s \n %s ", text
, msg
);
116 void check_error_pipe (void)
118 char error
[MAX_PIPE_SIZE
];
121 while (len
< MAX_PIPE_SIZE
)
125 rvalue
= -1; // read (error_pipe[0], error + len, 1);
131 close (error_pipe
[0]);
134 message (0, _(" Warning "), error
);
137 int my_system (int as_shell_command
, const char *shell
, const char *command
)
142 /* .ado: temp. turn out */
143 if (as_shell_command
) {
144 /* It is only the shell, /c will not work */
146 spawnlp (P_WAIT
, shell
, shell
, "/c", command
, (char *) 0);
148 spawnlp (P_WAIT
, shell
, (char *) 0);
150 spawnl (P_WAIT
, shell
, shell
, command
, (char *) 0);
152 if (win32_GetPlatform() == OS_Win95
) {
153 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
156 if (as_shell_command
) {
157 if (!access(command
, 0)) {
158 switch(win32_GetEXEType (shell
)) {
159 case EXE_win16
: /* Windows 3.x archive or OS/2 */
160 case EXE_win32GUI
: /* NT or Chicago GUI API */
161 spawnlp (P_NOWAIT
, shell
, shell
, "/c", command
, (char *) 0); /* don't wait for GUI programs to end */
163 case EXE_otherCUI
: /* DOS COM, MZ, ZM, Phar Lap */
164 case EXE_win32CUI
: /* NT or Chicago Console API, also OS/2 */
167 spawnlp (P_WAIT
, shell
, shell
, "/c", command
, (char *) 0);
172 spawnlp (P_WAIT
, shell
, shell
, "/c", command
, (char *) 0);
175 spawnl (P_WAIT
, shell
, shell
, command
, (char *) 0);
177 if (win32_GetPlatform() == OS_Win95
) {
178 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
185 Get the default shell for the current hardware platform
187 char* get_default_shell()
189 if (win32_GetPlatform() == OS_WinNT
)
192 return "command.com";
195 char *tilde_expand (char *directory
)
197 return strdup (directory
);
200 /* sleep: Call Windows API.
201 Can't do simple define. That would need <windows.h> in every source
204 void sleep(unsigned long dwMiliSecs
)
210 /* Canonicalize path, and return a new path. Do everything in situ.
211 The new path differs from path in:
212 Multiple `/'s are collapsed to a single `/'.
213 Leading `./'s and trailing `/.'s are removed.
214 Trailing `/'s are removed.
215 Non-leading `../'s and trailing `..'s are handled by removing
216 portions of the path. */
217 char *canonicalize_pathname (char *path
)
222 stub_char
= (*path
== PATH_SEP
) ? PATH_SEP
: '.';
224 /* Walk along path looking for things to compact. */
230 while (path
[i
] && path
[i
] != PATH_SEP
)
235 /* If we didn't find any slashes, then there is nothing left to do. */
239 /* Handle multiple `/'s in a row. */
240 while (path
[i
] == PATH_SEP
)
243 if ((start
+ 1) != i
) {
244 strcpy (path
+ start
+ 1, path
+ i
);
248 /* Handle backquoted `/'. */
249 if (start
> 0 && path
[start
- 1] == '\\')
252 /* Check for trailing `/'. */
253 if (start
&& !path
[i
]) {
259 /* Check for `../', `./' or trailing `.' by itself. */
260 if (path
[i
] == '.') {
261 /* Handle trailing `.' by itself. */
266 if (path
[i
+ 1] == PATH_SEP
) {
267 strcpy (path
+ i
, path
+ i
+ 1);
272 /* Handle `../' or trailing `..' by itself.
273 Remove the previous ?/ part with the exception of
274 ../, which we should leave intact. */
275 if (path
[i
+ 1] == '.' && (path
[i
+ 2] == PATH_SEP
|| !path
[i
+ 2])) {
276 while (--start
> -1 && path
[start
] != PATH_SEP
);
277 if (!strncmp (path
+ start
+ 1, "../", 3))
279 strcpy (path
+ start
+ 1, path
+ i
+ 2);
295 int mc_rmdir (char *path);
296 Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
299 int mc_rmdir (char *path
)
301 if (win32_GetPlatform() == OS_Win95
) {
303 SetLastError (ERROR_DIR_NOT_EMPTY
);
305 /* FIXME: We are always saying the same thing! */
306 _doserrno
= ERROR_DIR_NOT_EMPTY
;
314 return rmdir(path
); /* No trouble in Windows NT */
317 static int conv_nt_unx_rc(int rc
)
321 case ERROR_FILE_NOT_FOUND
:
322 case ERROR_PATH_NOT_FOUND
:
323 case ERROR_TOO_MANY_OPEN_FILES
:
326 case ERROR_INVALID_HANDLE
:
327 case ERROR_ARENA_TRASHED
:
328 case ERROR_ACCESS_DENIED
:
329 case ERROR_INVALID_ACCESS
:
330 case ERROR_WRITE_PROTECT
:
331 case ERROR_WRITE_FAULT
:
332 case ERROR_READ_FAULT
:
333 case ERROR_SHARING_VIOLATION
:
336 case ERROR_NOT_ENOUGH_MEMORY
:
339 case ERROR_INVALID_BLOCK
:
340 case ERROR_INVALID_FUNCTION
:
341 case ERROR_INVALID_DRIVE
:
344 case ERROR_CURRENT_DIRECTORY
:
347 case ERROR_NOT_READY
:
358 int mc_unlink (char *pathName)
359 For Windows 95 and NT, files should be able to be deleted even
360 if they don't have write-protection. We should build a question box
361 like: Delete anyway? Yes <No> All
363 int mc_unlink (char *pathName
)
367 static int erase_all
= 0;
371 rc
= DeleteFile(pathName
);
372 returnError
= GetLastError();
373 if ((rc
== FALSE
) && (returnError
== ERROR_ACCESS_DENIED
)) {
376 errno
= conv_nt_unx_rc(returnError
);
377 trunced_name
= name_trunc(pathName
, 30);
378 fileName
= (char *) malloc(strlen(trunced_name
) + 16);
379 strcpy(fileName
, _("File "));
380 strcat(fileName
, trunced_name
);
381 strcat(fileName
, _(" protected"));
382 result
= query_dialog(fileName
, _("Delete anyway?"), 3, 3, _(" No "), _(" Yes "), _(" All in the future!"));
403 chmod(pathName
, S_IWRITE
); /* make it writable */
404 rc
= DeleteFile(pathName
);
405 returnError
= GetLastError();
407 errno
= conv_nt_unx_rc(returnError
);
411 if (rc
== TRUE
) return 0;
417 void my_statfs (struct my_statfs
*myfs_stats
, char *path
)
420 DWORD lpSectorsPerCluster
, lpBytesPerSector
, lpFreeClusters
, lpClusters
;
421 DWORD lpMaximumComponentLength
, lpFileSystemFlags
;
422 static char lpVolumeNameBuffer
[256], lpFileSystemNameBuffer
[30];
424 GetDiskFreeSpace(NULL
, &lpSectorsPerCluster
, &lpBytesPerSector
,
425 &lpFreeClusters
, &lpClusters
);
427 /* KBytes available */
428 myfs_stats
->avail
= (unsigned int)( ((double)lpSectorsPerCluster
* lpBytesPerSector
* lpFreeClusters
) / 1024 );
431 myfs_stats
->total
= (unsigned int)( ((double)lpSectorsPerCluster
* lpBytesPerSector
* lpClusters
) / 1024 );
432 myfs_stats
->nfree
= lpFreeClusters
;
433 myfs_stats
->nodes
= lpClusters
;
435 GetVolumeInformation(NULL
, lpVolumeNameBuffer
, 255, NULL
,
436 &lpMaximumComponentLength
, &lpFileSystemFlags
,
437 lpFileSystemNameBuffer
, 30);
439 myfs_stats
->mpoint
= lpFileSystemNameBuffer
;
440 myfs_stats
->device
= lpVolumeNameBuffer
;
443 myfs_stats
->type
= GetDriveType(NULL
);
444 switch (myfs_stats
->type
) {
446 * mmm. DeviceIoControl may fail if you are not root case
447 * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
448 * myfs_stats->typename = "5.25\" 1.2MB"; break; case
449 * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
450 * myfs_stats->typename = "3.5\" 1.44MB"; break; case
451 * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
452 * myfs_stats->typename = "3.5\" 2.88MB"; break; case
453 * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
454 * myfs_stats->typename = "3.5\" 20.8MB"; break; case
455 * F3_720_512, 3.5", 720KB, 512 bytes/sector
456 * myfs_stats->typename = "3.5\" 720MB"; break; case
457 * F5_360_512, 5.25", 360KB, 512 bytes/sector
458 * myfs_stats->typename = "5.25\" 360KB"; break; case
459 * F5_320_512, 5.25", 320KB, 512 bytes/sector
460 * case F5_320_1024, 5.25", 320KB, 1024
461 * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
462 * case F5_180_512, 5.25", 180KB, 512
463 * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
464 * case F5_160_512, 5.25", 160KB, 512
465 * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
466 * case RemovableMedia, Removable media other than
467 * floppy myfs_stats->typename = "Removable"; break; case
468 * FixedMedia Fixed hard disk media
469 * myfs_stats->typename = "Hard Disk"; break; case Unknown:
472 case DRIVE_REMOVABLE
:
473 myfs_stats
->typename
= _("Removable");
476 myfs_stats
->typename
= _("Hard Disk");
479 myfs_stats
->typename
= _("Networked");
482 myfs_stats
->typename
= _("CD-ROM");
485 myfs_stats
->typename
= _("RAM disk");
488 myfs_stats
->typename
= _("unknown");
493 int gettimeofday (struct timeval
* tvp
, void *p
)
498 /* Since MC only calls this func from get_random_hint we return
499 some value, not exactly the "correct" one */
500 tvp
->tv_sec
= GetTickCount()/1000; /* Number of milliseconds since Windows //started*/
501 tvp
->tv_usec
= GetTickCount();
507 look_for_exe(const char* pathname
)
511 int lgh
= strlen(pathname
);
516 p
= (char *) pathname
;
517 for (j
=0; j
<lgh
-4; j
++) {
520 if (!stricmp(p
, ".exe") ||
521 !stricmp(p
, ".bat") ||
522 !stricmp(p
, ".com") ||
523 !stricmp(p
, ".cmd")) {
531 lstat (const char* pathname
, struct stat
*buffer
)
533 int rc
= stat (pathname
, buffer
);
536 if (!(buffer
->st_mode
& S_IFDIR
)) {
537 if (!look_for_exe(pathname
)) {
538 buffer
->st_mode
&= !S_IXUSR
& !S_IXGRP
& !S_IXOTH
;
549 LookupAccountName (NULL, &sid...
560 int readlink (char* path
, char* buf
, int size
)
564 int symlink (char *n1
, char *n2
)
568 int link (char *p1
, char *p2
)
572 int chown (char *path
, int owner
, int group
)
576 int mknod (char *path
, int mode
, int dev
)
581 void init_uid_gid_cache (void)
586 /* INHANDLE is a result of some mc_open call to any vfs, this function
587 returns a normal handle (to be used with read) of a pipe for reading
588 of the output of COMMAND with arguments ... (must include argv[0] as
589 well) which gets as its input at most INLEN bytes from the INHANDLE
590 using mc_read. You have to call mc_doublepclose to close the returned
591 handle afterwards. If INLEN is -1, we read as much as we can :) */
592 int mc_doublepopen (int inhandle
, int inlen
, pid_t
*the_pid
, char *command
, ...)
594 int pipe0
[2], pipe1
[2], std_sav
[2];
605 if(_pipe(pipe0
, 8192, O_BINARY
| O_NOINHERIT
) == -1)
607 if(_pipe(pipe1
, 8192, O_BINARY
| O_NOINHERIT
) == -1)
609 // Duplicate stdin/stdout handles (next line will close original)
610 std_sav
[0] = _dup(_fileno(stdin
));
611 std_sav
[1] = _dup(_fileno(stdout
));
612 // Duplicate read end of pipe0 to stdin handle
613 if(_dup2(pipe0
[0], _fileno(stdin
)) != 0)
615 // Duplicate write end of pipe1 to stdout handle
616 if(_dup2(pipe1
[1], _fileno(stdout
)) != 0)
618 // Close original read end of pipe0
620 // Close original write end of pipe1
623 va_start (ap
, command
);
625 while ((args
[argno
++] = va_arg(ap
, char *)) != NULL
)
626 if (argno
== (MAXARGS
- 1)) {
632 pid
= spawnvp(P_NOWAIT
,command
, (const char* const*)args
);// argv[1], (const char* const*)&argv[1]);
635 // Duplicate copy of original stdin back into stdin
636 if(_dup2(std_sav
[0], _fileno(stdin
)) != 0)
638 // Duplicate copy of original stdout back into stdout
639 if(_dup2(std_sav
[1], _fileno(stdout
)) != 0)
641 // Close duplicate copy of original stdout and stdin
646 while ((i
= _read (inhandle
, buffer
,
647 (inlen
== -1 || inlen
> 8192)
648 ? 8192 : inlen
)) > 0) {
649 write (pipe0
[1], buffer
, i
);
662 int mc_doublepclose (int pipe
, pid_t pid
)
667 _cwait ( &status
, pid
, 0);
671 /*hacks to get it compile, remove these after vfs works */
673 /*hacks to get it compile, remove these after vfs works */
675 char *vfs_get_current_dir (void)
680 int vfs_current_is_extfs (void)
685 int vfs_file_is_ftp (char *filename
)
690 int mc_utime (char *path
, void *times
)
696 void extfs_run (char *file
)
703 get_default_editor (void)
705 return "notepad.exe";
709 errno_dir_not_empty (int err
)
711 if (err
== ENOTEMPTY
|| err
== EEXIST
|| err
== EACCES
)
716 /* The MC library directory is by default the directory where mc.exe
717 is situated. It is possible to specify this directory via MCHOME
718 environment variable */
723 char *mchome
= getenv("MCHOME");
725 if (mchome
&& *mchome
)
727 mchome
= malloc(MC_MAXPATHLEN
);
728 GetModuleFileName(NULL
, mchome
, MC_MAXPATHLEN
);
729 for (cur
= mchome
+ strlen(mchome
); \
730 (cur
> mchome
) && (*cur
!= PATH_SEP
); cur
--);
732 cur
= strdup(mchome
);
740 int get_user_rights (struct stat
*buf
)
744 void init_groups (void)
747 void delete_groups (void)