Added cs to the list of languages
[midnight-commander.git] / pc / util_nt.c
blob55f8d27a27d77c64f7a204214abb50131af5b3cd
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. */
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/time.h> /* select: timeout */
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <stdarg.h>
36 #include <process.h>
37 #include "../src/fs.h"
38 #include "../src/util.h"
39 #include "util_win32.h"
41 #ifdef __BORLANDC__
42 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
43 #endif
45 char *get_owner (int uid)
47 return "none";
50 char *get_group (int gid)
52 return "none";
55 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
56 /* More than that would be unportable */
57 #define MAX_PIPE_SIZE 4096
59 static int error_pipe[2]; /* File descriptors of error pipe */
60 static int old_error; /* File descriptor of old standard error */
62 /* Creates a pipe to hold standard error for a later analysis. */
63 /* The pipe can hold 4096 bytes. Make sure no more is written */
64 /* or a deadlock might occur. */
65 void open_error_pipe (void)
67 if (pipe (error_pipe) < 0){
68 message (0, " Warning ", " Pipe failed ");
70 old_error = dup (2);
71 if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
72 message (0, " Warning ", " Dup failed ");
73 close (error_pipe[0]);
74 close (error_pipe[1]);
76 close (error_pipe[1]);
79 void 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; /* Just ignore error message */
101 if (text == NULL){
102 if (len == 0) return; /* Nothing to show */
104 /* Show message from pipe */
105 message (error, title, msg);
106 } else {
107 /* Show given text and possible message from pipe */
108 message (error, title, " %s \n %s ", text, msg);
112 void check_error_pipe (void)
114 char error[MAX_PIPE_SIZE];
115 int len = 0;
116 if (old_error >= 0){
117 while (len < MAX_PIPE_SIZE)
119 int rvalue;
121 rvalue = -1; // read (error_pipe[0], error + len, 1);
122 if (rvalue <= 0)
123 break;
124 len ++;
126 error[len] = 0;
127 close (error_pipe[0]);
129 if (len > 0)
130 message (0, " Warning ", error);
133 int my_system (int as_shell_command, const char *shell, const char *command)
135 int status = 0;
137 #if 0
138 /* .ado: temp. turn out */
139 if (as_shell_command) {
140 /* It is only the shell, /c will not work */
141 if (command)
142 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
143 else
144 spawnlp (P_WAIT, shell, (char *) 0);
145 } else
146 spawnl (P_WAIT, shell, shell, command, (char *) 0);
148 if (win32_GetPlatform() == OS_Win95) {
149 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
151 #endif
152 if (as_shell_command) {
153 if (!access(command, 0)) {
154 switch(win32_GetEXEType (shell)) {
155 case EXE_win16: /* Windows 3.x archive or OS/2 */
156 case EXE_win32GUI: /* NT or Chicago GUI API */
157 spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
158 break;
159 case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
160 case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
161 case EXE_Unknown:
162 default:
163 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
164 break;
167 else
168 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
170 else
171 spawnl (P_WAIT, shell, shell, command, (char *) 0);
173 if (win32_GetPlatform() == OS_Win95) {
174 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
177 return status;
180 /* get_default_shell
181 Get the default shell for the current hardware platform
183 char* get_default_shell()
185 if (win32_GetPlatform() == OS_WinNT)
186 return "cmd.exe";
187 else
188 return "command.com";
191 char *tilde_expand (char *directory)
193 return strdup (directory);
196 /* sleep: Call Windows API.
197 Can't do simple define. That would need <windows.h> in every source
199 #ifndef __EMX__
200 void sleep(unsigned long dwMiliSecs)
202 Sleep(dwMiliSecs);
204 #endif
206 /* Canonicalize path, and return a new path. Do everything in situ.
207 The new path differs from path in:
208 Multiple `/'s are collapsed to a single `/'.
209 Leading `./'s and trailing `/.'s are removed.
210 Trailing `/'s are removed.
211 Non-leading `../'s and trailing `..'s are handled by removing
212 portions of the path. */
213 char *canonicalize_pathname (char *path)
215 int i, start;
216 char stub_char;
218 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
220 /* Walk along path looking for things to compact. */
221 i = 0;
222 for (;;) {
223 if (!path[i])
224 break;
226 while (path[i] && path[i] != PATH_SEP)
227 i++;
229 start = i++;
231 /* If we didn't find any slashes, then there is nothing left to do. */
232 if (!path[start])
233 break;
235 /* Handle multiple `/'s in a row. */
236 while (path[i] == PATH_SEP)
237 i++;
239 if ((start + 1) != i) {
240 strcpy (path + start + 1, path + i);
241 i = start + 1;
244 /* Handle backquoted `/'. */
245 if (start > 0 && path[start - 1] == '\\')
246 continue;
248 /* Check for trailing `/'. */
249 if (start && !path[i]) {
250 zero_last:
251 path[--i] = '\0';
252 break;
255 /* Check for `../', `./' or trailing `.' by itself. */
256 if (path[i] == '.') {
257 /* Handle trailing `.' by itself. */
258 if (!path[i + 1])
259 goto zero_last;
261 /* Handle `./'. */
262 if (path[i + 1] == PATH_SEP) {
263 strcpy (path + i, path + i + 1);
264 i = start;
265 continue;
268 /* Handle `../' or trailing `..' by itself.
269 Remove the previous ?/ part with the exception of
270 ../, which we should leave intact. */
271 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
272 while (--start > -1 && path[start] != PATH_SEP);
273 if (!strncmp (path + start + 1, "../", 3))
274 continue;
275 strcpy (path + start + 1, path + i + 2);
276 i = start;
277 continue;
282 if (!*path) {
283 *path = stub_char;
284 path[1] = '\0';
286 return path;
289 #ifndef USE_VFS
291 int mc_rmdir (char *path);
292 Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
293 of ENOTEMPTY.
295 int mc_rmdir (char *path)
297 if (win32_GetPlatform() == OS_Win95) {
298 if (rmdir(path)) {
299 SetLastError (ERROR_DIR_NOT_EMPTY);
300 #ifndef __EMX__
301 /* FIXME: We are always saying the same thing! */
302 _doserrno = ERROR_DIR_NOT_EMPTY;
303 #endif
304 errno = ENOTEMPTY;
305 return -1;
306 } else
307 return 0;
309 else
310 return rmdir(path); /* No trouble in Windows NT */
313 static int conv_nt_unx_rc(int rc)
315 int errCode;
316 switch (rc) {
317 case ERROR_FILE_NOT_FOUND:
318 case ERROR_PATH_NOT_FOUND:
319 case ERROR_TOO_MANY_OPEN_FILES:
320 errCode = ENOENT;
321 break;
322 case ERROR_INVALID_HANDLE:
323 case ERROR_ARENA_TRASHED:
324 case ERROR_ACCESS_DENIED:
325 case ERROR_INVALID_ACCESS:
326 case ERROR_WRITE_PROTECT:
327 case ERROR_WRITE_FAULT:
328 case ERROR_READ_FAULT:
329 case ERROR_SHARING_VIOLATION:
330 errCode = EACCES;
331 break;
332 case ERROR_NOT_ENOUGH_MEMORY:
333 errCode = ENOMEM;
334 break;
335 case ERROR_INVALID_BLOCK:
336 case ERROR_INVALID_FUNCTION:
337 case ERROR_INVALID_DRIVE:
338 errCode = ENODEV;
339 break;
340 case ERROR_CURRENT_DIRECTORY:
341 errCode = ENOTDIR;
342 break;
343 case ERROR_NOT_READY:
344 errCode = EINVAL;
345 break;
346 default:
347 errCode = EINVAL;
348 break;
349 } /* endswitch */
350 return errCode;
354 int mc_unlink (char *pathName)
355 For Windows 95 and NT, files should be able to be deleted even
356 if they don't have write-protection. We should build a question box
357 like: Delete anyway? Yes <No> All
359 int mc_unlink (char *pathName)
361 char *fileName;
362 char *trunced_name;
363 static int erase_all = 0;
364 BOOL rc;
365 DWORD returnError;
367 rc = DeleteFile(pathName);
368 returnError = GetLastError();
369 if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
370 int result;
371 if (!erase_all) {
372 errno = conv_nt_unx_rc(returnError);
373 trunced_name = name_trunc(pathName, 30);
374 fileName = (char *) malloc(strlen(trunced_name) + 16);
375 strcpy(fileName, "File ");
376 strcat(fileName, trunced_name);
377 strcat(fileName, " protected");
378 result = query_dialog(fileName, "Delete anyway?", 3, 3, " No ", " Yes ", " All in the future!");
379 free(fileName);
381 switch (result) {
382 case 0:
383 do_refresh ();
384 return -1;
385 case 1:
386 do_refresh ();
387 break;
388 case 2:
389 do_refresh ();
390 erase_all = 1;
391 break;
392 default:
393 do_refresh ();
394 return -1;
395 break;
399 chmod(pathName, S_IWRITE); /* make it writable */
400 rc = DeleteFile(pathName);
401 returnError = GetLastError();
402 if (rc == FALSE) {
403 errno = conv_nt_unx_rc(returnError);
404 return -1;
407 if (rc == TRUE) return 0;
408 else
409 return -1;
411 #endif /*USE_VFS*/
413 void my_statfs (struct my_statfs *myfs_stats, char *path)
415 int len = 0;
416 DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
417 DWORD lpMaximumComponentLength, lpFileSystemFlags;
418 static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
420 GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
421 &lpFreeClusters, &lpClusters);
423 /* KBytes available */
424 myfs_stats->avail = lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters / 1024;
426 /* KBytes total */
427 myfs_stats->total = lpSectorsPerCluster * lpBytesPerSector * lpClusters / 1024;
428 myfs_stats->nfree = lpFreeClusters;
429 myfs_stats->nodes = lpClusters;
431 GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
432 &lpMaximumComponentLength, &lpFileSystemFlags,
433 lpFileSystemNameBuffer, 30);
435 myfs_stats->mpoint = lpFileSystemNameBuffer;
436 myfs_stats->device = lpVolumeNameBuffer;
439 myfs_stats->type = GetDriveType(NULL);
440 switch (myfs_stats->type) {
442 * mmm. DeviceIoControl may fail if you are not root case
443 * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
444 * myfs_stats->typename = "5.25\" 1.2MB"; break; case
445 * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
446 * myfs_stats->typename = "3.5\" 1.44MB"; break; case
447 * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
448 * myfs_stats->typename = "3.5\" 2.88MB"; break; case
449 * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
450 * myfs_stats->typename = "3.5\" 20.8MB"; break; case
451 * F3_720_512, 3.5", 720KB, 512 bytes/sector
452 * myfs_stats->typename = "3.5\" 720MB"; break; case
453 * F5_360_512, 5.25", 360KB, 512 bytes/sector
454 * myfs_stats->typename = "5.25\" 360KB"; break; case
455 * F5_320_512, 5.25", 320KB, 512 bytes/sector
456 * case F5_320_1024, 5.25", 320KB, 1024
457 * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
458 * case F5_180_512, 5.25", 180KB, 512
459 * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
460 * case F5_160_512, 5.25", 160KB, 512
461 * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
462 * case RemovableMedia, Removable media other than
463 * floppy myfs_stats->typename = "Removable"; break; case
464 * FixedMedia Fixed hard disk media
465 * myfs_stats->typename = "Hard Disk"; break; case Unknown:
466 * Format is unknown
468 case DRIVE_REMOVABLE:
469 myfs_stats->typename = "Removable";
470 break;
471 case DRIVE_FIXED:
472 myfs_stats->typename = "Hard Disk";
473 break;
474 case DRIVE_REMOTE:
475 myfs_stats->typename = "Networked";
476 break;
477 case DRIVE_CDROM:
478 myfs_stats->typename = "CD-ROM";
479 break;
480 case DRIVE_RAMDISK:
481 myfs_stats->typename = "RAM disk";
482 break;
483 default:
484 myfs_stats->typename = "unknown";
485 break;
489 int gettimeofday (struct timeval* tvp, void *p)
491 if (p != NULL)
492 return 0;
494 /* Since MC only calls this func from get_random_hint we return
495 some value, not exactly the "correct" one */
496 tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows started*/
497 tvp->tv_usec = GetTickCount();
500 /* FAKE functions */
502 int
503 look_for_exe(const char* pathname)
505 int j;
506 char *p;
507 int lgh = strlen(pathname);
509 if (lgh < 4) {
510 return 0;
511 } else {
512 p = (char *) pathname;
513 for (j=0; j<lgh-4; j++) {
514 p++;
515 } /* endfor */
516 if (!stricmp(p, ".exe") ||
517 !stricmp(p, ".bat") ||
518 !stricmp(p, ".com") ||
519 !stricmp(p, ".cmd")) {
520 return 1;
523 return 0;
526 int
527 lstat (const char* pathname, struct stat *buffer)
529 int rc = stat (pathname, buffer);
530 #ifdef __BORLANDC__
531 if (rc == 0) {
532 if (!(buffer->st_mode & S_IFDIR)) {
533 if (!look_for_exe(pathname)) {
534 buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
538 #endif
539 return rc;
542 int getuid ()
544 /* SID sid;
545 LookupAccountName (NULL, &sid...
546 return 0;
548 return 0;
551 int getgid ()
553 return 0;
556 int readlink (char* path, char* buf, int size)
558 return -1;
560 int symlink (char *n1, char *n2)
562 return -1;
564 int link (char *p1, char *p2)
566 return -1;
568 int chown (char *path, int owner, int group)
570 return -1;
572 int mknod (char *path, int mode, int dev)
574 return -1;
577 void init_uid_gid_cache (void)
579 return;
582 /* INHANDLE is a result of some mc_open call to any vfs, this function
583 returns a normal handle (to be used with read) of a pipe for reading
584 of the output of COMMAND with arguments ... (must include argv[0] as
585 well) which gets as its input at most INLEN bytes from the INHANDLE
586 using mc_read. You have to call mc_doublepclose to close the returned
587 handle afterwards. If INLEN is -1, we read as much as we can :) */
588 int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
590 int pipe0 [2], pipe1 [2], std_sav [2];
591 #define MAXARGS 16
592 int argno;
593 char *args[MAXARGS];
594 char buffer [8192];
595 int i;
596 va_list ap;
598 pid_t pid;
600 // Create the pipes
601 if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
602 exit (1);
603 if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
604 exit (1);
605 // Duplicate stdin/stdout handles (next line will close original)
606 std_sav[0] = _dup(_fileno(stdin));
607 std_sav[1] = _dup(_fileno(stdout));
608 // Duplicate read end of pipe0 to stdin handle
609 if(_dup2(pipe0[0], _fileno(stdin)) != 0)
610 exit (1);
611 // Duplicate write end of pipe1 to stdout handle
612 if(_dup2(pipe1[1], _fileno(stdout)) != 0)
613 exit (1);
614 // Close original read end of pipe0
615 close(pipe0[0]);
616 // Close original write end of pipe1
617 close(pipe1[1]);
619 va_start (ap, command);
620 argno = 0;
621 while ((args[argno++] = va_arg(ap, char *)) != NULL)
622 if (argno == (MAXARGS - 1)) {
623 args[argno] = NULL;
624 break;
626 va_end (ap);
627 // Spawn process
628 pid = spawnvp(P_NOWAIT,command, args);// argv[1], (const char* const*)&argv[1]);
629 if(!pid)
630 exit (1);
631 // Duplicate copy of original stdin back into stdin
632 if(_dup2(std_sav[0], _fileno(stdin)) != 0)
633 exit (1);
634 // Duplicate copy of original stdout back into stdout
635 if(_dup2(std_sav[1], _fileno(stdout)) != 0)
636 exit (1);
637 // Close duplicate copy of original stdout and stdin
638 close(std_sav[0]);
639 close(std_sav[1]);
642 while ((i = _read (inhandle, buffer,
643 (inlen == -1 || inlen > 8192)
644 ? 8192 : inlen)) > 0) {
645 write (pipe0 [1], buffer, i);
646 if (inlen != -1) {
647 inlen -= i;
648 if (!inlen)
649 break;
652 close (pipe0 [1]);
653 *the_pid = pid;
654 return pipe1 [0];
658 int mc_doublepclose (int pipe, pid_t pid)
660 int status = 0;
662 close (pipe);
663 _cwait ( &status, pid, 0);
664 return status;
667 /*hacks to get it compile, remove these after vfs works */
669 /*hacks to get it compile, remove these after vfs works */
670 #ifndef USE_VFS
671 char *vfs_get_current_dir (void)
673 return NULL;
676 int vfs_current_is_extfs (void)
678 return 0;
681 int vfs_file_is_ftp (char *filename)
683 return 0;
686 int mc_utime (char *path, void *times)
688 return 0;
692 void extfs_run (char *file)
694 return;
696 #endif
698 char *
699 get_default_editor (void)
701 return "notepad.exe";
705 errno_dir_not_empty (int err)
707 if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
708 return 1;
709 return 0;
712 /* The MC library directory is by default the directory where mc.exe
713 is situated. It is possible to specify this directory via MCHOME
714 environment variable */
715 char *
716 get_mc_lib_dir ()
718 char *cur;
719 char *mchome = getenv("MCHOME");
721 if (mchome && *mchome)
722 return mchome;
723 mchome = malloc(MC_MAXPATHLEN);
724 GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
725 for (cur = mchome + strlen(mchome); \
726 (cur > mchome) && (*cur != PATH_SEP); cur--);
727 *cur = 0;
728 cur = strdup(mchome);
729 free(mchome);
730 if (!cur || !*cur) {
731 free(cur);
732 return "C:\\MC";
734 return cur;
736 int get_user_rights (struct stat *buf)
738 return 2;
740 void init_groups (void)
743 void delete_groups (void)