mc/pc/util_nt.c
Pavel Roskin d3f0a2f61b Remove spaces around "Error" and "Warning" together with their translations.
Also remove spaces from "Quit" and "Search", but leave alone the
translations, that already have them without spaces.
2002-10-21 04:13:49 +00:00

743 lines
18 KiB
C

/* Various utilities - NT versions
Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
Written 1994, 1995, 1996 by:
Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
Jakub Jelinek, Mauricio Plaza.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <io.h>
#include <signal.h> /* my_system */
#include <limits.h> /* INT_MAX */
#include <errno.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <process.h>
#include "../src/global.h"
#include "../src/util.h"
#include "util_win32.h"
#ifdef __BORLANDC__
#define ENOTEMPTY ERROR_DIR_NOT_EMPTY
#endif
char *get_owner (int uid)
{
return "none";
}
char *get_group (int gid)
{
return "none";
}
/* Pipes are guaranteed to be able to hold at least 4096 bytes */
/* More than that would be unportable */
#define MAX_PIPE_SIZE 4096
static int error_pipe[2]; /* File descriptors of error pipe */
static int old_error; /* File descriptor of old standard error */
/* Creates a pipe to hold standard error for a later analysis. */
/* The pipe can hold 4096 bytes. Make sure no more is written */
/* or a deadlock might occur. */
void open_error_pipe (void)
{
if (pipe (error_pipe) < 0){
message (0, "Warning", " Pipe failed ");
}
old_error = dup (2);
if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
message (0, "Warning", " Dup failed ");
close (error_pipe[0]);
close (error_pipe[1]);
}
close (error_pipe[1]);
}
/*
* Returns true if an error was displayed
*/
int close_error_pipe (int error, char *text)
{
char *title;
char msg[MAX_PIPE_SIZE];
int len = 0;
if (error)
title = "Error";
else
title = "Warning";
if (old_error >= 0){
close (2);
dup (old_error);
close (old_error);
len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
if (len >= 0)
msg[len] = 0;
close (error_pipe[0]);
}
if (error < 0)
return 0; /* Just ignore error message */
if (text == NULL){
if (len == 0) return 0; /* Nothing to show */
/* Show message from pipe */
message (error, title, "%s", msg);
} else {
/* Show given text and possible message from pipe */
message (error, title, " %s \n %s ", text, msg);
}
return 1;
}
void check_error_pipe (void)
{
char error[MAX_PIPE_SIZE];
int len = 0;
if (old_error >= 0){
while (len < MAX_PIPE_SIZE)
{
int rvalue;
rvalue = -1; /* read (error_pipe[0], error + len, 1); */
if (rvalue <= 0)
break;
len ++;
}
error[len] = 0;
close (error_pipe[0]);
}
if (len > 0)
message (0, "Warning", "%s", error);
}
int my_system (int as_shell_command, const char *shell, const char *command)
{
int status = 0;
#if 0
/* .ado: temp. turn out */
if (as_shell_command) {
/* It is only the shell, /c will not work */
if (command)
spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
else
spawnlp (P_WAIT, shell, (char *) 0);
} else
spawnl (P_WAIT, shell, shell, command, (char *) 0);
if (win32_GetPlatform() == OS_Win95) {
SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
}
#endif
if (as_shell_command) {
if (!access(command, 0)) {
switch(win32_GetEXEType (shell)) {
case EXE_win16: /* Windows 3.x archive or OS/2 */
case EXE_win32GUI: /* NT or Chicago GUI API */
spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
break;
case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
case EXE_Unknown:
default:
spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
break;
}
}
else
spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
}
else
spawnl (P_WAIT, shell, shell, command, (char *) 0);
if (win32_GetPlatform() == OS_Win95) {
SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
}
return status;
}
/* get_default_shell
Get the default shell for the current hardware platform
*/
char* get_default_shell()
{
if (win32_GetPlatform() == OS_WinNT)
return "cmd.exe";
else
return "command.com";
}
char *tilde_expand (const char *directory)
{
return strdup (directory);
}
/* sleep: Call Windows API.
Cannot do simple define. That would need <windows.h> in every source
*/
#ifndef __EMX__
void sleep(unsigned long dwMiliSecs)
{
Sleep(dwMiliSecs);
}
#endif
/* Canonicalize path, and return a new path. Do everything in situ.
The new path differs from path in:
Multiple `/'s are collapsed to a single `/'.
Leading `./'s and trailing `/.'s are removed.
Trailing `/'s are removed.
Non-leading `../'s and trailing `..'s are handled by removing
portions of the path. */
char *canonicalize_pathname (char *path)
{
int i, start;
char stub_char;
stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
/* Walk along path looking for things to compact. */
i = 0;
for (;;) {
if (!path[i])
break;
while (path[i] && path[i] != PATH_SEP)
i++;
start = i++;
/* If we didn't find any slashes, then there is nothing left to do. */
if (!path[start])
break;
/* Handle multiple `/'s in a row. */
while (path[i] == PATH_SEP)
i++;
if ((start + 1) != i) {
strcpy (path + start + 1, path + i);
i = start + 1;
}
/* Check for trailing `/'. */
if (start && !path[i]) {
zero_last:
path[--i] = '\0';
break;
}
/* Check for `../', `./' or trailing `.' by itself. */
if (path[i] == '.') {
/* Handle trailing `.' by itself. */
if (!path[i + 1])
goto zero_last;
/* Handle `./'. */
if (path[i + 1] == PATH_SEP) {
strcpy (path + i, path + i + 1);
i = start;
continue;
}
/* Handle `../' or trailing `..' by itself.
Remove the previous ?/ part with the exception of
../, which we should leave intact. */
if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
while (--start > -1 && path[start] != PATH_SEP);
if (!strncmp (path + start + 1, "../", 3))
continue;
strcpy (path + start + 1, path + i + 2);
i = start;
continue;
}
}
}
if (!*path) {
*path = stub_char;
path[1] = '\0';
}
return path;
}
#ifndef USE_VFS
/*
int mc_rmdir (char *path);
Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
of ENOTEMPTY.
*/
int mc_rmdir (char *path)
{
if (win32_GetPlatform() == OS_Win95) {
if (rmdir(path)) {
SetLastError (ERROR_DIR_NOT_EMPTY);
#ifndef __EMX__
/* FIXME: We are always saying the same thing! */
_doserrno = ERROR_DIR_NOT_EMPTY;
#endif
errno = ENOTEMPTY;
return -1;
} else
return 0;
}
else
return rmdir(path); /* No trouble in Windows NT */
}
static int conv_nt_unx_rc(int rc)
{
int errCode;
switch (rc) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_TOO_MANY_OPEN_FILES:
errCode = ENOENT;
break;
case ERROR_INVALID_HANDLE:
case ERROR_ARENA_TRASHED:
case ERROR_ACCESS_DENIED:
case ERROR_INVALID_ACCESS:
case ERROR_WRITE_PROTECT:
case ERROR_WRITE_FAULT:
case ERROR_READ_FAULT:
case ERROR_SHARING_VIOLATION:
errCode = EACCES;
break;
case ERROR_NOT_ENOUGH_MEMORY:
errCode = ENOMEM;
break;
case ERROR_INVALID_BLOCK:
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_DRIVE:
errCode = ENODEV;
break;
case ERROR_CURRENT_DIRECTORY:
errCode = ENOTDIR;
break;
case ERROR_NOT_READY:
errCode = EINVAL;
break;
default:
errCode = EINVAL;
break;
} /* endswitch */
return errCode;
}
/*
int mc_unlink (char *pathName)
For Windows 95 and NT, files should be able to be deleted even
if they don't have write-protection. We should build a question box
like: Delete anyway? Yes <No> All
*/
int mc_unlink (char *pathName)
{
char *fileName;
char *trunced_name;
static int erase_all = 0;
BOOL rc;
DWORD returnError;
rc = DeleteFile(pathName);
returnError = GetLastError();
if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
int result;
if (!erase_all) {
errno = conv_nt_unx_rc(returnError);
trunced_name = name_trunc(pathName, 30);
fileName = (char *) malloc(strlen(trunced_name) + 16);
strcpy(fileName, "File ");
strcat(fileName, trunced_name);
strcat(fileName, " protected");
result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
free(fileName);
switch (result) {
case 0:
do_refresh ();
return -1;
case 1:
do_refresh ();
break;
case 2:
do_refresh ();
erase_all = 1;
break;
default:
do_refresh ();
return -1;
break;
}
}
chmod(pathName, S_IWRITE); /* make it writable */
rc = DeleteFile(pathName);
returnError = GetLastError();
if (rc == FALSE) {
errno = conv_nt_unx_rc(returnError);
return -1;
}
}
if (rc == TRUE) return 0;
else
return -1;
}
#endif /*USE_VFS*/
void my_statfs (struct my_statfs *myfs_stats, char *path)
{
int len = 0;
DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
DWORD lpMaximumComponentLength, lpFileSystemFlags;
static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
&lpFreeClusters, &lpClusters);
/* KBytes available */
myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
/* KBytes total */
myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
myfs_stats->nfree = lpFreeClusters;
myfs_stats->nodes = lpClusters;
GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
&lpMaximumComponentLength, &lpFileSystemFlags,
lpFileSystemNameBuffer, 30);
myfs_stats->mpoint = lpFileSystemNameBuffer;
myfs_stats->device = lpVolumeNameBuffer;
myfs_stats->type = GetDriveType(NULL);
switch (myfs_stats->type) {
/*
* mmm. DeviceIoControl may fail if you are not root case
* F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
* myfs_stats->typename = "5.25\" 1.2MB"; break; case
* F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
* myfs_stats->typename = "3.5\" 1.44MB"; break; case
* F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
* myfs_stats->typename = "3.5\" 2.88MB"; break; case
* F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
* myfs_stats->typename = "3.5\" 20.8MB"; break; case
* F3_720_512, 3.5", 720KB, 512 bytes/sector
* myfs_stats->typename = "3.5\" 720MB"; break; case
* F5_360_512, 5.25", 360KB, 512 bytes/sector
* myfs_stats->typename = "5.25\" 360KB"; break; case
* F5_320_512, 5.25", 320KB, 512 bytes/sector
* case F5_320_1024, 5.25", 320KB, 1024
* bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
* case F5_180_512, 5.25", 180KB, 512
* bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
* case F5_160_512, 5.25", 160KB, 512
* bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
* case RemovableMedia, Removable media other than
* floppy myfs_stats->typename = "Removable"; break; case
* FixedMedia Fixed hard disk media
* myfs_stats->typename = "Hard Disk"; break; case Unknown:
* Format is unknown
*/
case DRIVE_REMOVABLE:
myfs_stats->typename = "Removable";
break;
case DRIVE_FIXED:
myfs_stats->typename = "Hard Disk";
break;
case DRIVE_REMOTE:
myfs_stats->typename = "Networked";
break;
case DRIVE_CDROM:
myfs_stats->typename = "CD-ROM";
break;
case DRIVE_RAMDISK:
myfs_stats->typename = "RAM disk";
break;
default:
myfs_stats->typename = "unknown";
break;
};
}
int gettimeofday (struct timeval* tvp, void *p)
{
if (p != NULL)
return 0;
/* Since MC only calls this func from get_random_hint we return
some value, not exactly the "correct" one */
tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
tvp->tv_usec = GetTickCount();
}
/* FAKE functions */
int
look_for_exe(const char* pathname)
{
int j;
char *p;
int lgh = strlen(pathname);
if (lgh < 4) {
return 0;
} else {
p = (char *) pathname;
for (j=0; j<lgh-4; j++) {
p++;
} /* endfor */
if (!stricmp(p, ".exe") ||
!stricmp(p, ".bat") ||
!stricmp(p, ".com") ||
!stricmp(p, ".cmd")) {
return 1;
}
}
return 0;
}
int
lstat (const char* pathname, struct stat *buffer)
{
int rc = stat (pathname, buffer);
#ifdef __BORLANDC__
if (rc == 0) {
if (!(buffer->st_mode & S_IFDIR)) {
if (!look_for_exe(pathname)) {
buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
}
}
}
#endif
return rc;
}
int getuid ()
{
/* SID sid;
LookupAccountName (NULL, &sid...
return 0;
*/
return 0;
}
int getgid ()
{
return 0;
}
int readlink (char* path, char* buf, int size)
{
return -1;
}
int symlink (char *n1, char *n2)
{
return -1;
}
int link (char *p1, char *p2)
{
return -1;
}
int chown (char *path, int owner, int group)
{
return -1;
}
int mknod (char *path, int mode, int dev)
{
return -1;
}
void init_uid_gid_cache (void)
{
return;
}
/* INHANDLE is a result of some mc_open call to any vfs, this function
returns a normal handle (to be used with read) of a pipe for reading
of the output of COMMAND with arguments ... (must include argv[0] as
well) which gets as its input at most INLEN bytes from the INHANDLE
using mc_read. You have to call mc_doublepclose to close the returned
handle afterwards. If INLEN is -1, we read as much as we can :) */
int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
{
int pipe0 [2], pipe1 [2], std_sav [2];
#define MAXARGS 16
int argno;
char *args[MAXARGS];
char buffer [8192];
int i;
va_list ap;
pid_t pid;
/* Create the pipes */
if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
exit (1);
if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
exit (1);
/* Duplicate stdin/stdout handles (next line will close original) */
std_sav[0] = _dup(_fileno(stdin));
std_sav[1] = _dup(_fileno(stdout));
/* Duplicate read end of pipe0 to stdin handle */
if(_dup2(pipe0[0], _fileno(stdin)) != 0)
exit (1);
/* Duplicate write end of pipe1 to stdout handle */
if(_dup2(pipe1[1], _fileno(stdout)) != 0)
exit (1);
/* Close original read end of pipe0 */
close(pipe0[0]);
/* Close original write end of pipe1 */
close(pipe1[1]);
va_start (ap, command);
argno = 0;
while ((args[argno++] = va_arg(ap, char *)) != NULL)
if (argno == (MAXARGS - 1)) {
args[argno] = NULL;
break;
}
va_end (ap);
/* Spawn process */
pid = spawnvp(P_NOWAIT,command, args);/* argv[1], (const char* const*)&argv[1]); */
if(!pid)
exit (1);
/* Duplicate copy of original stdin back into stdin */
if(_dup2(std_sav[0], _fileno(stdin)) != 0)
exit (1);
/* Duplicate copy of original stdout back into stdout */
if(_dup2(std_sav[1], _fileno(stdout)) != 0)
exit (1);
/* Close duplicate copy of original stdout and stdin */
close(std_sav[0]);
close(std_sav[1]);
while ((i = _read (inhandle, buffer,
(inlen == -1 || inlen > 8192)
? 8192 : inlen)) > 0) {
write (pipe0 [1], buffer, i);
if (inlen != -1) {
inlen -= i;
if (!inlen)
break;
}
}
close (pipe0 [1]);
*the_pid = pid;
return pipe1 [0];
}
int mc_doublepclose (int pipe, pid_t pid)
{
int status = 0;
close (pipe);
_cwait ( &status, pid, 0);
return status;
}
/*hacks to get it compile, remove these after vfs works */
/*hacks to get it compile, remove these after vfs works */
#ifndef USE_VFS
char *vfs_get_current_dir (void)
{
return NULL;
}
int vfs_current_is_extfs (void)
{
return 0;
}
int vfs_file_is_ftp (char *filename)
{
return 0;
}
int mc_utime (char *path, void *times)
{
return 0;
}
void extfs_run (char *file)
{
return;
}
#endif
char *
get_default_editor (void)
{
return "notepad.exe";
}
int
errno_dir_not_empty (int err)
{
if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
return 1;
return 0;
}
/* The MC library directory is by default the directory where mc.exe
is situated. It is possible to specify this directory via MCHOME
environment variable */
char *
get_mc_lib_dir ()
{
char *cur;
char *mchome = getenv("MCHOME");
if (mchome && *mchome)
return mchome;
mchome = malloc(MC_MAXPATHLEN);
GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
for (cur = mchome + strlen(mchome); \
(cur > mchome) && (*cur != PATH_SEP); cur--);
*cur = 0;
cur = strdup(mchome);
free(mchome);
if (!cur || !*cur) {
free(cur);
return "C:\\MC";
}
return cur;
}
int get_user_rights (struct stat *buf)
{
return 2;
}
void init_groups (void)
{
}
void delete_groups (void)
{
}