Mainly standardisation of makefiles, now support make install rules and use ros heade...
[reactos.git] / rosapps / mc / pc / util_nt.c
1 /* Various utilities - NT versions
2 Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
3
4 Written 1994, 1995, 1996 by:
5 Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
6 Jakub Jelinek, Mauricio Plaza.
7
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.
12
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.
17
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. */
21
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 #if defined(_MSC_VER)
33 #include <sys/time.h___> /* select: timeout */
34 #else
35 #include <sys/time.h> /* select: timeout */
36 #endif
37 #include <sys/param.h>
38 #include <sys/stat.h>
39 #include <stdarg.h>
40 #include <process.h>
41 #include "../src/fs.h"
42 #include "../src/util.h"
43 #include "util_win32.h"
44
45 #ifdef __BORLANDC__
46 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
47 #endif
48
49 char *get_owner (int uid)
50 {
51 return "none";
52 }
53
54 char *get_group (int gid)
55 {
56 return "none";
57 }
58
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
62
63 static int error_pipe[2]; /* File descriptors of error pipe */
64 static int old_error; /* File descriptor of old standard error */
65
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)
70 {
71 if (pipe (error_pipe) < 0){
72 message (0, _(" Warning "), _(" Pipe failed ") );
73 }
74 old_error = dup (2);
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]);
79 }
80 close (error_pipe[1]);
81 }
82
83 void close_error_pipe (int error, char *text)
84 {
85 char *title;
86 char msg[MAX_PIPE_SIZE];
87 int len = 0;
88
89 if (error)
90 title = _(" Error ");
91 else
92 title = _(" Warning ");
93 if (old_error >= 0){
94 close (2);
95 dup (old_error);
96 close (old_error);
97 len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
98
99 if (len >= 0)
100 msg[len] = 0;
101 close (error_pipe[0]);
102 }
103 if (error < 0)
104 return; /* Just ignore error message */
105 if (text == NULL){
106 if (len == 0) return; /* Nothing to show */
107
108 /* Show message from pipe */
109 message (error, title, msg);
110 } else {
111 /* Show given text and possible message from pipe */
112 message (error, title, " %s \n %s ", text, msg);
113 }
114 }
115
116 void check_error_pipe (void)
117 {
118 char error[MAX_PIPE_SIZE];
119 int len = 0;
120 if (old_error >= 0){
121 while (len < MAX_PIPE_SIZE)
122 {
123 int rvalue;
124
125 rvalue = -1; // read (error_pipe[0], error + len, 1);
126 if (rvalue <= 0)
127 break;
128 len ++;
129 }
130 error[len] = 0;
131 close (error_pipe[0]);
132 }
133 if (len > 0)
134 message (0, _(" Warning "), error);
135 }
136
137 int my_system (int as_shell_command, const char *shell, const char *command)
138 {
139 int status = 0;
140
141 #if 0
142 /* .ado: temp. turn out */
143 if (as_shell_command) {
144 /* It is only the shell, /c will not work */
145 if (command)
146 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
147 else
148 spawnlp (P_WAIT, shell, (char *) 0);
149 } else
150 spawnl (P_WAIT, shell, shell, command, (char *) 0);
151
152 if (win32_GetPlatform() == OS_Win95) {
153 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
154 }
155 #endif
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 */
162 break;
163 case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
164 case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
165 case EXE_Unknown:
166 default:
167 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
168 break;
169 }
170 }
171 else
172 spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
173 }
174 else
175 spawnl (P_WAIT, shell, shell, command, (char *) 0);
176
177 if (win32_GetPlatform() == OS_Win95) {
178 SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
179 }
180
181 return status;
182 }
183
184 /* get_default_shell
185 Get the default shell for the current hardware platform
186 */
187 char* get_default_shell()
188 {
189 if (win32_GetPlatform() == OS_WinNT)
190 return "cmd.exe";
191 else
192 return "command.com";
193 }
194
195 char *tilde_expand (char *directory)
196 {
197 return strdup (directory);
198 }
199
200 /* sleep: Call Windows API.
201 Can't do simple define. That would need <windows.h> in every source
202 */
203 #ifndef __EMX__
204 void sleep(unsigned long dwMiliSecs)
205 {
206 Sleep(dwMiliSecs);
207 }
208 #endif
209
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)
218 {
219 int i, start;
220 char stub_char;
221
222 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
223
224 /* Walk along path looking for things to compact. */
225 i = 0;
226 for (;;) {
227 if (!path[i])
228 break;
229
230 while (path[i] && path[i] != PATH_SEP)
231 i++;
232
233 start = i++;
234
235 /* If we didn't find any slashes, then there is nothing left to do. */
236 if (!path[start])
237 break;
238
239 /* Handle multiple `/'s in a row. */
240 while (path[i] == PATH_SEP)
241 i++;
242
243 if ((start + 1) != i) {
244 strcpy (path + start + 1, path + i);
245 i = start + 1;
246 }
247
248 /* Handle backquoted `/'. */
249 if (start > 0 && path[start - 1] == '\\')
250 continue;
251
252 /* Check for trailing `/'. */
253 if (start && !path[i]) {
254 zero_last:
255 path[--i] = '\0';
256 break;
257 }
258
259 /* Check for `../', `./' or trailing `.' by itself. */
260 if (path[i] == '.') {
261 /* Handle trailing `.' by itself. */
262 if (!path[i + 1])
263 goto zero_last;
264
265 /* Handle `./'. */
266 if (path[i + 1] == PATH_SEP) {
267 strcpy (path + i, path + i + 1);
268 i = start;
269 continue;
270 }
271
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))
278 continue;
279 strcpy (path + start + 1, path + i + 2);
280 i = start;
281 continue;
282 }
283 }
284 }
285
286 if (!*path) {
287 *path = stub_char;
288 path[1] = '\0';
289 }
290 return path;
291 }
292
293 #ifndef USE_VFS
294 /*
295 int mc_rmdir (char *path);
296 Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
297 of ENOTEMPTY.
298 */
299 int mc_rmdir (char *path)
300 {
301 if (win32_GetPlatform() == OS_Win95) {
302 if (rmdir(path)) {
303 SetLastError (ERROR_DIR_NOT_EMPTY);
304 #ifndef __EMX__
305 /* FIXME: We are always saying the same thing! */
306 _doserrno = ERROR_DIR_NOT_EMPTY;
307 #endif
308 errno = ENOTEMPTY;
309 return -1;
310 } else
311 return 0;
312 }
313 else
314 return rmdir(path); /* No trouble in Windows NT */
315 }
316
317 static int conv_nt_unx_rc(int rc)
318 {
319 int errCode;
320 switch (rc) {
321 case ERROR_FILE_NOT_FOUND:
322 case ERROR_PATH_NOT_FOUND:
323 case ERROR_TOO_MANY_OPEN_FILES:
324 errCode = ENOENT;
325 break;
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:
334 errCode = EACCES;
335 break;
336 case ERROR_NOT_ENOUGH_MEMORY:
337 errCode = ENOMEM;
338 break;
339 case ERROR_INVALID_BLOCK:
340 case ERROR_INVALID_FUNCTION:
341 case ERROR_INVALID_DRIVE:
342 errCode = ENODEV;
343 break;
344 case ERROR_CURRENT_DIRECTORY:
345 errCode = ENOTDIR;
346 break;
347 case ERROR_NOT_READY:
348 errCode = EINVAL;
349 break;
350 default:
351 errCode = EINVAL;
352 break;
353 } /* endswitch */
354 return errCode;
355 }
356
357 /*
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
362 */
363 int mc_unlink (char *pathName)
364 {
365 char *fileName;
366 char *trunced_name;
367 static int erase_all = 0;
368 BOOL rc;
369 DWORD returnError;
370
371 rc = DeleteFile(pathName);
372 returnError = GetLastError();
373 if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
374 int result;
375 if (!erase_all) {
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!"));
383 free(fileName);
384
385 switch (result) {
386 case 0:
387 do_refresh ();
388 return -1;
389 case 1:
390 do_refresh ();
391 break;
392 case 2:
393 do_refresh ();
394 erase_all = 1;
395 break;
396 default:
397 do_refresh ();
398 return -1;
399 break;
400 }
401 }
402
403 chmod(pathName, S_IWRITE); /* make it writable */
404 rc = DeleteFile(pathName);
405 returnError = GetLastError();
406 if (rc == FALSE) {
407 errno = conv_nt_unx_rc(returnError);
408 return -1;
409 }
410 }
411 if (rc == TRUE) return 0;
412 else
413 return -1;
414 }
415 #endif /*USE_VFS*/
416
417 void my_statfs (struct my_statfs *myfs_stats, char *path)
418 {
419 int len = 0;
420 DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
421 DWORD lpMaximumComponentLength, lpFileSystemFlags;
422 static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
423
424 GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
425 &lpFreeClusters, &lpClusters);
426
427 /* KBytes available */
428 myfs_stats->avail = (unsigned int)( ((double)lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters) / 1024 );
429
430 /* KBytes total */
431 myfs_stats->total = (unsigned int)( ((double)lpSectorsPerCluster * lpBytesPerSector * lpClusters) / 1024 );
432 myfs_stats->nfree = lpFreeClusters;
433 myfs_stats->nodes = lpClusters;
434
435 GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
436 &lpMaximumComponentLength, &lpFileSystemFlags,
437 lpFileSystemNameBuffer, 30);
438
439 myfs_stats->mpoint = lpFileSystemNameBuffer;
440 myfs_stats->device = lpVolumeNameBuffer;
441
442
443 myfs_stats->type = GetDriveType(NULL);
444 switch (myfs_stats->type) {
445 /*
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:
470 * Format is unknown
471 */
472 case DRIVE_REMOVABLE:
473 myfs_stats->typename = _("Removable");
474 break;
475 case DRIVE_FIXED:
476 myfs_stats->typename = _("Hard Disk");
477 break;
478 case DRIVE_REMOTE:
479 myfs_stats->typename = _("Networked");
480 break;
481 case DRIVE_CDROM:
482 myfs_stats->typename = _("CD-ROM");
483 break;
484 case DRIVE_RAMDISK:
485 myfs_stats->typename = _("RAM disk");
486 break;
487 default:
488 myfs_stats->typename = _("unknown");
489 break;
490 };
491 }
492
493 int gettimeofday (struct timeval* tvp, void *p)
494 {
495 if (p != NULL)
496 return 0;
497
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();
502 }
503
504 /* FAKE functions */
505
506 int
507 look_for_exe(const char* pathname)
508 {
509 int j;
510 char *p;
511 int lgh = strlen(pathname);
512
513 if (lgh < 4) {
514 return 0;
515 } else {
516 p = (char *) pathname;
517 for (j=0; j<lgh-4; j++) {
518 p++;
519 } /* endfor */
520 if (!stricmp(p, ".exe") ||
521 !stricmp(p, ".bat") ||
522 !stricmp(p, ".com") ||
523 !stricmp(p, ".cmd")) {
524 return 1;
525 }
526 }
527 return 0;
528 }
529
530 int
531 lstat (const char* pathname, struct stat *buffer)
532 {
533 int rc = stat (pathname, buffer);
534 #ifdef __BORLANDC__
535 if (rc == 0) {
536 if (!(buffer->st_mode & S_IFDIR)) {
537 if (!look_for_exe(pathname)) {
538 buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
539 }
540 }
541 }
542 #endif
543 return rc;
544 }
545
546 int getuid ()
547 {
548 /* SID sid;
549 LookupAccountName (NULL, &sid...
550 return 0;
551 */
552 return 0;
553 }
554
555 int getgid ()
556 {
557 return 0;
558 }
559
560 int readlink (char* path, char* buf, int size)
561 {
562 return -1;
563 }
564 int symlink (char *n1, char *n2)
565 {
566 return -1;
567 }
568 int link (char *p1, char *p2)
569 {
570 return -1;
571 }
572 int chown (char *path, int owner, int group)
573 {
574 return -1;
575 }
576 int mknod (char *path, int mode, int dev)
577 {
578 return -1;
579 }
580
581 void init_uid_gid_cache (void)
582 {
583 return;
584 }
585
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, ...)
593 {
594 int pipe0 [2], pipe1 [2], std_sav [2];
595 #define MAXARGS 16
596 int argno;
597 char *args[MAXARGS];
598 char buffer [8192];
599 int i;
600 va_list ap;
601
602 pid_t pid;
603
604 // Create the pipes
605 if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
606 exit (1);
607 if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
608 exit (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)
614 exit (1);
615 // Duplicate write end of pipe1 to stdout handle
616 if(_dup2(pipe1[1], _fileno(stdout)) != 0)
617 exit (1);
618 // Close original read end of pipe0
619 close(pipe0[0]);
620 // Close original write end of pipe1
621 close(pipe1[1]);
622
623 va_start (ap, command);
624 argno = 0;
625 while ((args[argno++] = va_arg(ap, char *)) != NULL)
626 if (argno == (MAXARGS - 1)) {
627 args[argno] = NULL;
628 break;
629 }
630 va_end (ap);
631 // Spawn process
632 pid = spawnvp(P_NOWAIT,command, args);// argv[1], (const char* const*)&argv[1]);
633 if(!pid)
634 exit (1);
635 // Duplicate copy of original stdin back into stdin
636 if(_dup2(std_sav[0], _fileno(stdin)) != 0)
637 exit (1);
638 // Duplicate copy of original stdout back into stdout
639 if(_dup2(std_sav[1], _fileno(stdout)) != 0)
640 exit (1);
641 // Close duplicate copy of original stdout and stdin
642 close(std_sav[0]);
643 close(std_sav[1]);
644
645
646 while ((i = _read (inhandle, buffer,
647 (inlen == -1 || inlen > 8192)
648 ? 8192 : inlen)) > 0) {
649 write (pipe0 [1], buffer, i);
650 if (inlen != -1) {
651 inlen -= i;
652 if (!inlen)
653 break;
654 }
655 }
656 close (pipe0 [1]);
657 *the_pid = pid;
658 return pipe1 [0];
659
660 }
661
662 int mc_doublepclose (int pipe, pid_t pid)
663 {
664 int status = 0;
665
666 close (pipe);
667 _cwait ( &status, pid, 0);
668 return status;
669 }
670
671 /*hacks to get it compile, remove these after vfs works */
672
673 /*hacks to get it compile, remove these after vfs works */
674 #ifndef USE_VFS
675 char *vfs_get_current_dir (void)
676 {
677 return NULL;
678 }
679
680 int vfs_current_is_extfs (void)
681 {
682 return 0;
683 }
684
685 int vfs_file_is_ftp (char *filename)
686 {
687 return 0;
688 }
689
690 int mc_utime (char *path, void *times)
691 {
692 return 0;
693 }
694
695
696 void extfs_run (char *file)
697 {
698 return;
699 }
700 #endif
701
702 char *
703 get_default_editor (void)
704 {
705 return "notepad.exe";
706 }
707
708 int
709 errno_dir_not_empty (int err)
710 {
711 if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
712 return 1;
713 return 0;
714 }
715
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 */
719 char *
720 get_mc_lib_dir ()
721 {
722 char *cur;
723 char *mchome = getenv("MCHOME");
724
725 if (mchome && *mchome)
726 return 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--);
731 *cur = 0;
732 cur = strdup(mchome);
733 free(mchome);
734 if (!cur || !*cur) {
735 free(cur);
736 return "C:\\MC";
737 }
738 return cur;
739 }
740 int get_user_rights (struct stat *buf)
741 {
742 return 2;
743 }
744 void init_groups (void)
745 {
746 }
747 void delete_groups (void)
748 {
749 }