it.po converted in UTF-8, changed some upper/lower convention in a more 'italian...
[midnight-commander.git] / pc / util_nt.c
blob41ecb383703b477ce19ca9457600f447d1dd679a
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 <signal.h> /* my_system */
29 #include <limits.h> /* INT_MAX */
30 #include <errno.h>
31 #include <sys/stat.h>
32 #include <stdarg.h>
33 #include <process.h>
34 #include "../src/global.h"
35 #include "../src/util.h"
36 #include "util_win32.h"
38 #ifdef __BORLANDC__
39 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
40 #endif
42 char *get_owner (int uid)
44 return "none";
47 char *get_group (int gid)
49 return "none";
52 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
53 /* More than that would be unportable */
54 #define MAX_PIPE_SIZE 4096
56 static int error_pipe[2]; /* File descriptors of error pipe */
57 static int old_error; /* File descriptor of old standard error */
59 /* Creates a pipe to hold standard error for a later analysis. */
60 /* The pipe can hold 4096 bytes. Make sure no more is written */
61 /* or a deadlock might occur. */
62 void open_error_pipe (void)
64 if (pipe (error_pipe) < 0){
65 message (0, "Warning", " Pipe failed ");
67 old_error = dup (2);
68 if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
69 message (0, "Warning", " Dup failed ");
70 close (error_pipe[0]);
71 close (error_pipe[1]);
73 close (error_pipe[1]);
77 * Returns true if an error was displayed
79 int close_error_pipe (int error, char *text)
81 char *title;
82 char msg[MAX_PIPE_SIZE];
83 int len = 0;
85 if (error)
86 title = "Error";
87 else
88 title = "Warning";
89 if (old_error >= 0){
90 close (2);
91 dup (old_error);
92 close (old_error);
93 len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
95 if (len >= 0)
96 msg[len] = 0;
97 close (error_pipe[0]);
99 if (error < 0)
100 return 0; /* Just ignore error message */
101 if (text == NULL){
102 if (len == 0) return 0; /* Nothing to show */
104 /* Show message from pipe */
105 message (error, title, "%s", msg);
106 } else {
107 /* Show given text and possible message from pipe */
108 message (error, title, " %s \n %s ", text, msg);
110 return 1;
113 void check_error_pipe (void)
115 char error[MAX_PIPE_SIZE];
116 int len = 0;
117 if (old_error >= 0){
118 while (len < MAX_PIPE_SIZE)
120 int rvalue;
122 rvalue = -1; /* read (error_pipe[0], error + len, 1); */
123 if (rvalue <= 0)
124 break;
125 len ++;
127 error[len] = 0;
128 close (error_pipe[0]);
130 if (len > 0)
131 message (0, "Warning", "%s", error);
134 int my_system (int as_shell_command, const char *shell, const char *command)
136 int status = 0;
138 #if 0
139 /* .ado: temp. turn out */
140 if (as_shell_command) {
141 /* It is only the shell, /c will not work */
142 if (command)
143 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
144 else
145 spawnlp (P_WAIT, shell, (char *) 0);
146 } else
147 spawnl (P_WAIT, shell, shell, command, (char *) 0);
149 if (win32_GetPlatform() == OS_Win95) {
150 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
152 #endif
153 if (as_shell_command) {
154 if (!access(command, 0)) {
155 switch(win32_GetEXEType (shell)) {
156 case EXE_win16: /* Windows 3.x archive or OS/2 */
157 case EXE_win32GUI: /* NT or Chicago GUI API */
158 spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
159 break;
160 case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
161 case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
162 case EXE_Unknown:
163 default:
164 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
165 break;
168 else
169 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
171 else
172 spawnl (P_WAIT, shell, shell, command, (char *) 0);
174 if (win32_GetPlatform() == OS_Win95) {
175 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
178 return status;
181 /* get_default_shell
182 Get the default shell for the current hardware platform
184 char* get_default_shell()
186 if (win32_GetPlatform() == OS_WinNT)
187 return "cmd.exe";
188 else
189 return "command.com";
192 char *tilde_expand (const char *directory)
194 return strdup (directory);
197 /* sleep: Call Windows API.
198 Cannot do simple define. That would need <windows.h> in every source
200 #ifndef __EMX__
201 void sleep(unsigned long dwMiliSecs)
203 Sleep(dwMiliSecs);
205 #endif
207 /* Canonicalize path, and return a new path. Do everything in situ.
208 The new path differs from path in:
209 Multiple `/'s are collapsed to a single `/'.
210 Leading `./'s and trailing `/.'s are removed.
211 Trailing `/'s are removed.
212 Non-leading `../'s and trailing `..'s are handled by removing
213 portions of the path. */
214 char *canonicalize_pathname (char *path)
216 int i, start;
217 char stub_char;
219 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
221 /* Walk along path looking for things to compact. */
222 i = 0;
223 for (;;) {
224 if (!path[i])
225 break;
227 while (path[i] && path[i] != PATH_SEP)
228 i++;
230 start = i++;
232 /* If we didn't find any slashes, then there is nothing left to do. */
233 if (!path[start])
234 break;
236 /* Handle multiple `/'s in a row. */
237 while (path[i] == PATH_SEP)
238 i++;
240 if ((start + 1) != i) {
241 strcpy (path + start + 1, path + i);
242 i = start + 1;
245 /* Check for trailing `/'. */
246 if (start && !path[i]) {
247 zero_last:
248 path[--i] = '\0';
249 break;
252 /* Check for `../', `./' or trailing `.' by itself. */
253 if (path[i] == '.') {
254 /* Handle trailing `.' by itself. */
255 if (!path[i + 1])
256 goto zero_last;
258 /* Handle `./'. */
259 if (path[i + 1] == PATH_SEP) {
260 strcpy (path + i, path + i + 1);
261 i = start;
262 continue;
265 /* Handle `../' or trailing `..' by itself.
266 Remove the previous ?/ part with the exception of
267 ../, which we should leave intact. */
268 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
269 while (--start > -1 && path[start] != PATH_SEP);
270 if (!strncmp (path + start + 1, "../", 3))
271 continue;
272 strcpy (path + start + 1, path + i + 2);
273 i = start;
274 continue;
279 if (!*path) {
280 *path = stub_char;
281 path[1] = '\0';
283 return path;
286 #ifndef USE_VFS
288 int mc_rmdir (char *path);
289 Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
290 of ENOTEMPTY.
292 int mc_rmdir (char *path)
294 if (win32_GetPlatform() == OS_Win95) {
295 if (rmdir(path)) {
296 SetLastError (ERROR_DIR_NOT_EMPTY);
297 #ifndef __EMX__
298 /* FIXME: We are always saying the same thing! */
299 _doserrno = ERROR_DIR_NOT_EMPTY;
300 #endif
301 errno = ENOTEMPTY;
302 return -1;
303 } else
304 return 0;
306 else
307 return rmdir(path); /* No trouble in Windows NT */
310 static int conv_nt_unx_rc(int rc)
312 int errCode;
313 switch (rc) {
314 case ERROR_FILE_NOT_FOUND:
315 case ERROR_PATH_NOT_FOUND:
316 case ERROR_TOO_MANY_OPEN_FILES:
317 errCode = ENOENT;
318 break;
319 case ERROR_INVALID_HANDLE:
320 case ERROR_ARENA_TRASHED:
321 case ERROR_ACCESS_DENIED:
322 case ERROR_INVALID_ACCESS:
323 case ERROR_WRITE_PROTECT:
324 case ERROR_WRITE_FAULT:
325 case ERROR_READ_FAULT:
326 case ERROR_SHARING_VIOLATION:
327 errCode = EACCES;
328 break;
329 case ERROR_NOT_ENOUGH_MEMORY:
330 errCode = ENOMEM;
331 break;
332 case ERROR_INVALID_BLOCK:
333 case ERROR_INVALID_FUNCTION:
334 case ERROR_INVALID_DRIVE:
335 errCode = ENODEV;
336 break;
337 case ERROR_CURRENT_DIRECTORY:
338 errCode = ENOTDIR;
339 break;
340 case ERROR_NOT_READY:
341 errCode = EINVAL;
342 break;
343 default:
344 errCode = EINVAL;
345 break;
346 } /* endswitch */
347 return errCode;
351 int mc_unlink (char *pathName)
352 For Windows 95 and NT, files should be able to be deleted even
353 if they don't have write-protection. We should build a question box
354 like: Delete anyway? Yes <No> All
356 int mc_unlink (char *pathName)
358 char *fileName;
359 char *trunced_name;
360 static int erase_all = 0;
361 BOOL rc;
362 DWORD returnError;
364 rc = DeleteFile(pathName);
365 returnError = GetLastError();
366 if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
367 int result;
368 if (!erase_all) {
369 errno = conv_nt_unx_rc(returnError);
370 trunced_name = name_trunc(pathName, 30);
371 fileName = (char *) malloc(strlen(trunced_name) + 16);
372 strcpy(fileName, "File ");
373 strcat(fileName, trunced_name);
374 strcat(fileName, " protected");
375 result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
376 free(fileName);
378 switch (result) {
379 case 0:
380 do_refresh ();
381 return -1;
382 case 1:
383 do_refresh ();
384 break;
385 case 2:
386 do_refresh ();
387 erase_all = 1;
388 break;
389 default:
390 do_refresh ();
391 return -1;
392 break;
396 chmod(pathName, S_IWRITE); /* make it writable */
397 rc = DeleteFile(pathName);
398 returnError = GetLastError();
399 if (rc == FALSE) {
400 errno = conv_nt_unx_rc(returnError);
401 return -1;
404 if (rc == TRUE) return 0;
405 else
406 return -1;
408 #endif /*USE_VFS*/
410 void my_statfs (struct my_statfs *myfs_stats, char *path)
412 int len = 0;
413 DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
414 DWORD lpMaximumComponentLength, lpFileSystemFlags;
415 static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
417 GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
418 &lpFreeClusters, &lpClusters);
420 /* KBytes available */
421 myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
423 /* KBytes total */
424 myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
425 myfs_stats->nfree = lpFreeClusters;
426 myfs_stats->nodes = lpClusters;
428 GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
429 &lpMaximumComponentLength, &lpFileSystemFlags,
430 lpFileSystemNameBuffer, 30);
432 myfs_stats->mpoint = lpFileSystemNameBuffer;
433 myfs_stats->device = lpVolumeNameBuffer;
436 myfs_stats->type = GetDriveType(NULL);
437 switch (myfs_stats->type) {
439 * mmm. DeviceIoControl may fail if you are not root case
440 * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
441 * myfs_stats->typename = "5.25\" 1.2MB"; break; case
442 * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
443 * myfs_stats->typename = "3.5\" 1.44MB"; break; case
444 * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
445 * myfs_stats->typename = "3.5\" 2.88MB"; break; case
446 * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
447 * myfs_stats->typename = "3.5\" 20.8MB"; break; case
448 * F3_720_512, 3.5", 720KB, 512 bytes/sector
449 * myfs_stats->typename = "3.5\" 720MB"; break; case
450 * F5_360_512, 5.25", 360KB, 512 bytes/sector
451 * myfs_stats->typename = "5.25\" 360KB"; break; case
452 * F5_320_512, 5.25", 320KB, 512 bytes/sector
453 * case F5_320_1024, 5.25", 320KB, 1024
454 * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
455 * case F5_180_512, 5.25", 180KB, 512
456 * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
457 * case F5_160_512, 5.25", 160KB, 512
458 * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
459 * case RemovableMedia, Removable media other than
460 * floppy myfs_stats->typename = "Removable"; break; case
461 * FixedMedia Fixed hard disk media
462 * myfs_stats->typename = "Hard Disk"; break; case Unknown:
463 * Format is unknown
465 case DRIVE_REMOVABLE:
466 myfs_stats->typename = "Removable";
467 break;
468 case DRIVE_FIXED:
469 myfs_stats->typename = "Hard Disk";
470 break;
471 case DRIVE_REMOTE:
472 myfs_stats->typename = "Networked";
473 break;
474 case DRIVE_CDROM:
475 myfs_stats->typename = "CD-ROM";
476 break;
477 case DRIVE_RAMDISK:
478 myfs_stats->typename = "RAM disk";
479 break;
480 default:
481 myfs_stats->typename = "unknown";
482 break;
486 int gettimeofday (struct timeval* tvp, void *p)
488 if (p != NULL)
489 return 0;
491 /* Since MC only calls this func from get_random_hint we return
492 some value, not exactly the "correct" one */
493 tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
494 tvp->tv_usec = GetTickCount();
497 /* FAKE functions */
499 int
500 look_for_exe(const char* pathname)
502 int j;
503 char *p;
504 int lgh = strlen(pathname);
506 if (lgh < 4) {
507 return 0;
508 } else {
509 p = (char *) pathname;
510 for (j=0; j<lgh-4; j++) {
511 p++;
512 } /* endfor */
513 if (!stricmp(p, ".exe") ||
514 !stricmp(p, ".bat") ||
515 !stricmp(p, ".com") ||
516 !stricmp(p, ".cmd")) {
517 return 1;
520 return 0;
523 int
524 lstat (const char* pathname, struct stat *buffer)
526 int rc = stat (pathname, buffer);
527 #ifdef __BORLANDC__
528 if (rc == 0) {
529 if (!(buffer->st_mode & S_IFDIR)) {
530 if (!look_for_exe(pathname)) {
531 buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
535 #endif
536 return rc;
539 int getuid ()
541 /* SID sid;
542 LookupAccountName (NULL, &sid...
543 return 0;
545 return 0;
548 int getgid ()
550 return 0;
553 int readlink (char* path, char* buf, int size)
555 return -1;
557 int symlink (char *n1, char *n2)
559 return -1;
561 int link (char *p1, char *p2)
563 return -1;
565 int chown (char *path, int owner, int group)
567 return -1;
569 int mknod (char *path, int mode, int dev)
571 return -1;
574 void init_uid_gid_cache (void)
576 return;
579 /* INHANDLE is a result of some mc_open call to any vfs, this function
580 returns a normal handle (to be used with read) of a pipe for reading
581 of the output of COMMAND with arguments ... (must include argv[0] as
582 well) which gets as its input at most INLEN bytes from the INHANDLE
583 using mc_read. You have to call mc_doublepclose to close the returned
584 handle afterwards. If INLEN is -1, we read as much as we can :) */
585 int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
587 int pipe0 [2], pipe1 [2], std_sav [2];
588 #define MAXARGS 16
589 int argno;
590 char *args[MAXARGS];
591 char buffer [8192];
592 int i;
593 va_list ap;
595 pid_t pid;
597 /* Create the pipes */
598 if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
599 exit (1);
600 if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
601 exit (1);
602 /* Duplicate stdin/stdout handles (next line will close original) */
603 std_sav[0] = _dup(_fileno(stdin));
604 std_sav[1] = _dup(_fileno(stdout));
605 /* Duplicate read end of pipe0 to stdin handle */
606 if(_dup2(pipe0[0], _fileno(stdin)) != 0)
607 exit (1);
608 /* Duplicate write end of pipe1 to stdout handle */
609 if(_dup2(pipe1[1], _fileno(stdout)) != 0)
610 exit (1);
611 /* Close original read end of pipe0 */
612 close(pipe0[0]);
613 /* Close original write end of pipe1 */
614 close(pipe1[1]);
616 va_start (ap, command);
617 argno = 0;
618 while ((args[argno++] = va_arg(ap, char *)) != NULL)
619 if (argno == (MAXARGS - 1)) {
620 args[argno] = NULL;
621 break;
623 va_end (ap);
624 /* Spawn process */
625 pid = spawnvp(P_NOWAIT,command, args);/* argv[1], (const char* const*)&argv[1]); */
626 if(!pid)
627 exit (1);
628 /* Duplicate copy of original stdin back into stdin */
629 if(_dup2(std_sav[0], _fileno(stdin)) != 0)
630 exit (1);
631 /* Duplicate copy of original stdout back into stdout */
632 if(_dup2(std_sav[1], _fileno(stdout)) != 0)
633 exit (1);
634 /* Close duplicate copy of original stdout and stdin */
635 close(std_sav[0]);
636 close(std_sav[1]);
639 while ((i = _read (inhandle, buffer,
640 (inlen == -1 || inlen > 8192)
641 ? 8192 : inlen)) > 0) {
642 write (pipe0 [1], buffer, i);
643 if (inlen != -1) {
644 inlen -= i;
645 if (!inlen)
646 break;
649 close (pipe0 [1]);
650 *the_pid = pid;
651 return pipe1 [0];
655 int mc_doublepclose (int pipe, pid_t pid)
657 int status = 0;
659 close (pipe);
660 _cwait ( &status, pid, 0);
661 return status;
664 /*hacks to get it compile, remove these after vfs works */
666 /*hacks to get it compile, remove these after vfs works */
667 #ifndef USE_VFS
668 char *vfs_get_current_dir (void)
670 return NULL;
673 int vfs_current_is_extfs (void)
675 return 0;
678 int vfs_file_is_ftp (char *filename)
680 return 0;
683 int mc_utime (char *path, void *times)
685 return 0;
689 void extfs_run (char *file)
691 return;
693 #endif
695 char *
696 get_default_editor (void)
698 return "notepad.exe";
702 errno_dir_not_empty (int err)
704 if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
705 return 1;
706 return 0;
709 /* The MC library directory is by default the directory where mc.exe
710 is situated. It is possible to specify this directory via MCHOME
711 environment variable */
712 char *
713 get_mc_lib_dir ()
715 char *cur;
716 char *mchome = getenv("MCHOME");
718 if (mchome && *mchome)
719 return mchome;
720 mchome = malloc(MC_MAXPATHLEN);
721 GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
722 for (cur = mchome + strlen(mchome); \
723 (cur > mchome) && (*cur != PATH_SEP); cur--);
724 *cur = 0;
725 cur = strdup(mchome);
726 free(mchome);
727 if (!cur || !*cur) {
728 free(cur);
729 return "C:\\MC";
731 return cur;
733 int get_user_rights (struct stat *buf)
735 return 2;
737 void init_groups (void)
740 void delete_groups (void)