1 #pragma prototyped noticed
2
3 /*
4 * workarounds to bring the native interface close to posix and x/open
5 */
6
7 #if defined(__STDPP__directive) && defined(__STDPP__hide)
8 __STDPP__directive pragma pp:hide utime utimes
9 #else
10 #define utime ______utime
11 #define utimes ______utimes
12 #endif
13
14 #include <ast.h>
15 #include <error.h>
16 #include <tm.h>
17
18 #include "FEATURE/omitted"
19
20 #undef OMITTED
21
22 #if _win32_botch
23
24 #define OMITTED 1
25
26 #include <ls.h>
27 #include <utime.h>
28
29 #if __CYGWIN__
30 #include <ast_windows.h>
31 #if _win32_botch_execve || _lib_spawn_mode
32 #define CONVERT 1
33 #endif
34 #endif
35
36 #if defined(__STDPP__directive) && defined(__STDPP__hide)
37 __STDPP__directive pragma pp:nohide utime utimes
38 #else
39 #undef utime
40 #undef utimes
41 #endif
42
43 #ifndef MAX_PATH
44 #define MAX_PATH PATH_MAX
45 #endif
46
47 /*
48 * these workarounds assume each system call foo() has a _foo() entry
49 * which is true for __CYGWIN__ and __EMX__ (both gnu based)
50 *
51 * the workarounds handle:
52 *
53 * (1) .exe suffix inconsistencies
54 * (2) /bin/sh reference in execve() and spawnve()
55 * (3) bogus getpagesize() return values
56 * (4) a fork() bug that screws up shell fork()+script
57 *
58 * NOTE: Not all workarounds can be handled by unix syscall intercepts.
59 * In particular, { ksh nmake } have workarounds for case-ignorant
60 * filesystems and { libast } has workarounds for win32 locale info.
61 */
62
63 #undef _pathconf
64 #undef pathconf
65 #undef stat
66
67 extern int _access(const char*, int);
68 extern unsigned int _alarm(unsigned int);
69 extern int _chmod(const char*, mode_t);
70 extern int _close(int);
71 extern pid_t _execve(const char*, char* const*, char* const*);
72 extern uid_t _getuid(void);
73 extern int _link(const char*, const char*);
74 extern int _open(const char*, int, ...);
75 extern long _pathconf(const char*, int);
76 extern ssize_t _read(int, void*, size_t);
77 extern int _rename(const char*, const char*);
78 extern pid_t _spawnve(int, const char*, char* const*, char* const*);
79 extern int _stat(const char*, struct stat*);
80 extern int _unlink(const char*);
81 extern int _utime(const char*, const struct utimbuf*);
82 extern int _utimes(const char*, const struct timeval*);
83 extern ssize_t _write(int, const void*, size_t);
84
85 #if defined(__EXPORT__)
86 #define extern __EXPORT__
87 #endif
88
89 #if _win32_botch_access
90 #define sysaccess _access
91 #else
92 #define sysaccess access
93 #endif
94 #if _win32_botch_alarm
95 #define sysalarm _alarm
96 #else
97 #define sysalarm alarm
98 #endif
99 #if _win32_botch_chmod
100 #define syschmod _chmod
101 #else
102 #define syschmod chmod
103 #endif
104 #if _win32_botch_copy
105 #define sysclose _close
106 #else
107 #define sysclose close
108 #endif
109 #if _win32_botch_execve || _lib_spawn_mode
110 #define sysexecve _execve
111 #else
112 #define sysexecve execve
113 #endif
114 #if CONVERT
115 #define sysgetuid _getuid
116 #else
117 #define sysgetuid getuid
118 #endif
119 #if _win32_botch_link
120 #define syslink _link
121 #else
122 #define syslink link
123 #endif
124 #if _win32_botch_open || _win32_botch_copy
125 #define sysopen _open
126 #else
127 #define sysopen open
128 #endif
129 #if _win32_botch_pathconf
130 #define syspathconf _pathconf
131 #else
132 #define syspathconf pathconf
133 #endif
134 #define sysread _read
135 #if _win32_botch_rename
136 #define sysrename _rename
137 #else
138 #define sysrename rename
139 #endif
140 #if _lib_spawn_mode
141 #define sysspawnve _spawnve
142 #else
143 #define sysspawnve spawnve
144 #endif
145 #if _win32_botch_stat
146 #define sysstat _stat
147 #else
148 #define sysstat stat
149 #endif
150 #if _win32_botch_truncate
151 #define systruncate _truncate
152 #else
153 #define systruncate truncate
154 #endif
155 #if _win32_botch_unlink
156 #define sysunlink _unlink
157 #else
158 #define sysunlink unlink
159 #endif
160 #if _win32_botch_utime
161 #define sysutime _utime
162 #define sysutimes _utimes
163 #else
164 #define sysutime utime
165 #define sysutimes utimes
166 #endif
167 #if _win32_botch_copy
168 #define syswrite _write
169 #else
170 #define syswrite write
171 #endif
172
173 static char*
suffix(register const char * path)174 suffix(register const char* path)
175 {
176 register const char* s = path + strlen(path);
177 register int c;
178
179 while (s > path)
180 if ((c = *--s) == '.')
181 return (char*)s + 1;
182 else if (c == '/' || c == '\\')
183 break;
184 return 0;
185 }
186
187 static int
execrate(const char * path,char * buf,int size,int physical)188 execrate(const char* path, char* buf, int size, int physical)
189 {
190 char* s;
191 int n;
192 int oerrno;
193
194 if (suffix(path))
195 return 0;
196 oerrno = errno;
197 if (physical || strlen(path) >= size || !(s = pathcanon(strcpy(buf, path), size, PATH_PHYSICAL|PATH_DOTDOT|PATH_EXISTS)))
198 snprintf(buf, size, "%s.exe", path);
199 else if (!suffix(buf) && ((buf + size) - s) >= 4)
200 strcpy(s, ".exe");
201 errno = oerrno;
202 return 1;
203 }
204
205 /*
206 * return 0 if path is magic, -1 otherwise
207 * ux!=0 set to 1 if path is unix executable
208 * ux!=0 also retains errno for -1 return
209 */
210
211 static int
magic(const char * path,int * ux)212 magic(const char* path, int* ux)
213 {
214 int fd;
215 int r;
216 int n;
217 int m;
218 int oerrno;
219 #if CONVERT
220 unsigned char buf[512];
221 #else
222 unsigned char buf[2];
223 #endif
224
225 oerrno = errno;
226 if ((fd = sysopen(path, O_RDONLY, 0)) >= 0)
227 {
228 #if CONVERT
229 if (ux)
230 n = sizeof(buf);
231 else
232 #endif
233 n = 2;
234 r = (m = sysread(fd, buf, n)) >= 2 && (buf[1] == 0x5a && (buf[0] == 0x4c || buf[0] == 0x4d) || ux && buf[0] == '#' && buf[1] == '!' && (*ux = 1) && !(ux = 0)) ? 0 : -1;
235 sysclose(fd);
236 if (ux)
237 {
238 if (r)
239 oerrno = ENOEXEC;
240 else if (m > 61 && (n = buf[60] | (buf[61]<<8) + 92) < (m - 1))
241 *ux = (buf[n] | (buf[n+1]<<8)) == 3;
242 else
243 *ux = 0;
244 }
245 }
246 else if (!ux)
247 r = -1;
248 else if (errno == ENOENT)
249 {
250 oerrno = errno;
251 r = -1;
252 }
253 else
254 {
255 r = 0;
256 *ux = 0;
257 }
258 errno = oerrno;
259 return r;
260 }
261
262 #if _win32_botch_access
263
264 extern int
access(const char * path,int op)265 access(const char* path, int op)
266 {
267 int r;
268 int oerrno;
269 char buf[PATH_MAX];
270
271 oerrno = errno;
272 if ((r = sysaccess(path, op)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
273 {
274 errno = oerrno;
275 r = sysaccess(buf, op);
276 }
277 return r;
278 }
279
280 #endif
281
282 #if _win32_botch_alarm
283
284 extern unsigned int
alarm(unsigned int s)285 alarm(unsigned int s)
286 {
287 unsigned int n;
288 unsigned int r;
289
290 static unsigned int a;
291
292 n = (unsigned int)time(NiL);
293 if (a <= n)
294 r = 0;
295 else
296 r = a - n;
297 a = n + s - 1;
298 (void)sysalarm(s);
299 return r;
300 }
301
302 #endif
303
304 #if _win32_botch_chmod
305
306 extern int
chmod(const char * path,mode_t mode)307 chmod(const char* path, mode_t mode)
308 {
309 int r;
310 int oerrno;
311 char buf[PATH_MAX];
312
313 if ((r = syschmod(path, mode)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
314 {
315 errno = oerrno;
316 return syschmod(buf, mode);
317 }
318 if (!(r = syschmod(path, mode)) &&
319 (mode & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
320 !suffix(path) &&
321 (strlen(path) + 4) < sizeof(buf))
322 {
323 oerrno = errno;
324 if (!magic(path, NiL))
325 {
326 snprintf(buf, sizeof(buf), "%s.exe", path);
327 sysrename(path, buf);
328 }
329 errno = oerrno;
330 }
331 return r;
332 }
333
334 #endif
335
336 #if _win32_botch_execve || _lib_spawn_mode
337
338 #if _lib_spawn_mode
339
340 /*
341 * can anyone get const prototype args straight?
342 */
343
344 #define execve ______execve
345 #define spawnve ______spawnve
346
347 #include <process.h>
348
349 #undef execve
350 #undef spawnve
351
352 #endif
353
354 #if CONVERT
355
356 /*
357 * this intercept converts dos env vars to unix
358 * we'd rather intercept main but can't twist cc to do it
359 * getuid() gets ksh to do the right thing and
360 * that's our main concern
361 *
362 * DOSPATHVARS='a b c' convert { a b c }
363 */
364
365 static int convertinit;
366
367 /*
368 * convertvars[0] names the list of env var names
369 * convertvars[i] are not converted
370 */
371
372 static const char* convertvars[] = { "DOSPATHVARS", "PATH" };
373
374 static int
convert(register const char * d,const char * s)375 convert(register const char* d, const char* s)
376 {
377 register const char* t;
378 register const char* v;
379 int i;
380
381 for (i = 0; i < elementsof(convertvars); i++)
382 {
383 for (v = convertvars[i], t = s; *t && *t == *v; t++, v++);
384 if (*t == '=' && *v == 0)
385 return 0;
386 }
387 for (;;)
388 {
389 while (*d == ' ' || *d == '\t')
390 d++;
391 if (!*d)
392 break;
393 for (t = s; *t && *t == *d; d++, t++);
394 if (*t == '=' && (*d == ' ' || *d == '\t' || *d == 0))
395 return t - s + 1;
396 while (*d && *d != ' ' && *d != '\t')
397 d++;
398 }
399 return 0;
400 }
401
402 uid_t
getuid(void)403 getuid(void)
404 {
405 register char* d;
406 register char* s;
407 register char* t;
408 register char** e;
409 int n;
410 int m;
411
412 if (!convertinit++ && (d = getenv(convertvars[0])))
413 for (e = environ; s = *e; e++)
414 if ((n = convert(d, s)) && (m = cygwin_win32_to_posix_path_list_buf_size(s + n)) > 0)
415 {
416 if (!(t = malloc(n + m + 1)))
417 break;
418 *e = t;
419 memcpy(t, s, n);
420 cygwin_win32_to_posix_path_list(s + n, t + n);
421 }
422 return sysgetuid();
423 }
424
425 #endif
426
427 #ifndef _P_OVERLAY
428 #define _P_OVERLAY (-1)
429 #endif
430
431 #define DEBUG 1
432
433 static pid_t
runve(int mode,const char * path,char * const * argv,char * const * envv)434 runve(int mode, const char* path, char* const* argv, char* const* envv)
435 {
436 register char* s;
437 register char** p;
438 register char** v;
439
440 void* m1;
441 void* m2;
442 pid_t pid;
443 int oerrno;
444 int ux;
445 int n;
446 #if defined(_P_DETACH) && defined(_P_NOWAIT)
447 int pgrp;
448 #endif
449 #if CONVERT
450 char* d;
451 char* t;
452 int m;
453 #endif
454 struct stat st;
455 char buf[PATH_MAX];
456 char tmp[PATH_MAX];
457
458 #if DEBUG
459 static int trace;
460 #endif
461
462 #if defined(_P_DETACH) && defined(_P_NOWAIT)
463 if (mode == _P_DETACH)
464 {
465 /*
466 * 2004-02-29 cygwin _P_DETACH is useless:
467 * spawn*() returns 0 instead of the spawned pid
468 * spawned { pgid sid } are the same as the parent
469 */
470
471 mode = _P_NOWAIT;
472 pgrp = 1;
473 }
474 else
475 pgrp = 0;
476 #endif
477 if (!envv)
478 envv = (char* const*)environ;
479 m1 = m2 = 0;
480 oerrno = errno;
481 #if DEBUG
482 if (!trace)
483 trace = (s = getenv("_AST_exec_trace")) ? *s : 'n';
484 #endif
485 if (execrate(path, buf, sizeof(buf), 0))
486 {
487 if (!sysstat(buf, &st))
488 path = (const char*)buf;
489 else
490 errno = oerrno;
491 }
492 if (path != (const char*)buf && sysstat(path, &st))
493 return -1;
494 if (!S_ISREG(st.st_mode) || !(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
495 {
496 errno = EACCES;
497 return -1;
498 }
499 if (magic(path, &ux))
500 {
501 #if _CYGWIN_fork_works
502 errno = ENOEXEC;
503 return -1;
504 #else
505 ux = 1;
506 p = (char**)argv;
507 while (*p++);
508 if (!(v = (char**)malloc((p - (char**)argv + 2) * sizeof(char*))))
509 {
510 errno = EAGAIN;
511 return -1;
512 }
513 m1 = v;
514 p = v;
515 *p++ = (char*)path;
516 *p++ = (char*)path;
517 path = (const char*)pathshell();
518 if (*argv)
519 argv++;
520 while (*p++ = (char*)*argv++);
521 argv = (char* const*)v;
522 #endif
523 }
524
525 /*
526 * the win32 dll search order is
527 * (1) the directory of path
528 * (2) .
529 * (3) /c/(WINNT|WINDOWS)/system32 /c/(WINNT|WINDOWS)
530 * (4) the directories on $PATH
531 * there are no cygwin dlls in (3), so if (1) and (2) fail
532 * to produce the required dlls its up to (4)
533 *
534 * the standard allows PATH to be anything once the path
535 * to an executable is determined; this code ensures that PATH
536 * contains /bin so that at least the cygwin dll, required
537 * by all cygwin executables, will be found
538 */
539
540 if (p = (char**)envv)
541 {
542 n = 1;
543 while (s = *p++)
544 if (strneq(s, "PATH=", 5))
545 {
546 s += 5;
547 do
548 {
549 s = pathcat(s, ':', NiL, "", tmp, sizeof(tmp));
550 if (streq(tmp, "/usr/bin/") || streq(tmp, "/bin/"))
551 {
552 n = 0;
553 break;
554 }
555 } while (s);
556 if (n)
557 {
558 n = 0;
559 snprintf(tmp, sizeof(tmp), "%s:/bin", *(p - 1));
560 *(p - 1) = tmp;
561 }
562 break;
563 }
564 if (n)
565 {
566 n = p - (char**)envv + 1;
567 p = (char**)envv;
568 if (v = (char**)malloc(n * sizeof(char*)))
569 {
570 m2 = v;
571 envv = (char* const*)v;
572 *v++ = strcpy(tmp, "PATH=/bin");
573 while (*v++ = *p++);
574 }
575 }
576 #if CONVERT
577 if (!ux && (d = getenv(convertvars[0])))
578 for (p = (char**)envv; s = *p; p++)
579 if ((n = convert(d, s)) && (m = cygwin_posix_to_win32_path_list_buf_size(s + n)) > 0)
580 {
581 if (!(t = malloc(n + m + 1)))
582 break;
583 *p = t;
584 memcpy(t, s, n);
585 cygwin_posix_to_win32_path_list(s + n, t + n);
586 }
587 #endif
588 }
589
590 #if DEBUG
591 if (trace == 'a' || trace == 'e')
592 {
593 sfprintf(sfstderr, "%s %s [", mode == _P_OVERLAY ? "_execve" : "_spawnve", path);
594 for (n = 0; argv[n]; n++)
595 sfprintf(sfstderr, " '%s'", argv[n]);
596 if (trace == 'e')
597 {
598 sfprintf(sfstderr, " ] [");
599 for (n = 0; envv[n]; n++)
600 sfprintf(sfstderr, " '%s'", envv[n]);
601 }
602 sfprintf(sfstderr, " ]\n");
603 sfsync(sfstderr);
604 }
605 #endif
606 #if _lib_spawn_mode
607 if (mode != _P_OVERLAY)
608 {
609 pid = sysspawnve(mode, path, argv, envv);
610 #if defined(_P_DETACH) && defined(_P_NOWAIT)
611 if (pid > 0 && pgrp)
612 setpgid(pid, 0);
613 #endif
614 }
615 else
616 #endif
617 {
618 #if defined(_P_DETACH) && defined(_P_NOWAIT)
619 if (pgrp)
620 setpgid(0, 0);
621 #endif
622 pid = sysexecve(path, argv, envv);
623 }
624 if (m1)
625 free(m1);
626 if (m2)
627 free(m2);
628 return pid;
629 }
630
631 #if _win32_botch_execve
632
633 extern pid_t
execve(const char * path,char * const * argv,char * const * envv)634 execve(const char* path, char* const* argv, char* const* envv)
635 {
636 return runve(_P_OVERLAY, path, argv, envv);
637 }
638
639 #endif
640
641 #if _lib_spawn_mode
642
643 extern pid_t
spawnve(int mode,const char * path,char * const * argv,char * const * envv)644 spawnve(int mode, const char* path, char* const* argv, char* const* envv)
645 {
646 return runve(mode, path, argv, envv);
647 }
648
649 #endif
650
651 #endif
652
653 #if _win32_botch_getpagesize
654
655 extern size_t
getpagesize(void)656 getpagesize(void)
657 {
658 return 64 * 1024;
659 }
660
661 #endif
662
663 #if _win32_botch_link
664
665 extern int
link(const char * fp,const char * tp)666 link(const char* fp, const char* tp)
667 {
668 int r;
669 int oerrno;
670 char fb[PATH_MAX];
671 char tb[PATH_MAX];
672
673 oerrno = errno;
674 if ((r = syslink(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
675 {
676 if (execrate(tp, tb, sizeof(tb), 1))
677 tp = tb;
678 errno = oerrno;
679 r = syslink(fb, tp);
680 }
681 return r;
682 }
683
684 #endif
685
686 #if _win32_botch_open || _win32_botch_copy
687
688 #if _win32_botch_copy
689
690 /*
691 * this should intercept the important cases
692 * dup*() and exec*() fd's will not be intercepted
693 */
694
695 typedef struct Exe_test_s
696 {
697 int test;
698 ino_t ino;
699 char path[PATH_MAX];
700 } Exe_test_t;
701
702 static Exe_test_t* exe[16];
703
704 extern int
close(int fd)705 close(int fd)
706 {
707 int r;
708 int oerrno;
709 struct stat st;
710 char buf[PATH_MAX];
711
712 if (fd >= 0 && fd < elementsof(exe) && exe[fd])
713 {
714 r = exe[fd]->test;
715 exe[fd]->test = 0;
716 if (r > 0 && !fstat(fd, &st) && st.st_ino == exe[fd]->ino)
717 {
718 if (r = sysclose(fd))
719 return r;
720 oerrno = errno;
721 if (!stat(exe[fd]->path, &st) && st.st_ino == exe[fd]->ino)
722 {
723 snprintf(buf, sizeof(buf), "%s.exe", exe[fd]->path);
724 sysrename(exe[fd]->path, buf);
725 }
726 errno = oerrno;
727 return 0;
728 }
729 }
730 return sysclose(fd);
731 }
732
733 extern ssize_t
write(int fd,const void * buf,size_t n)734 write(int fd, const void* buf, size_t n)
735 {
736 if (fd >= 0 && fd < elementsof(exe) && exe[fd] && exe[fd]->test < 0)
737 exe[fd]->test = n >= 2 && ((unsigned char*)buf)[1] == 0x5a && (((unsigned char*)buf)[0] == 0x4c || ((unsigned char*)buf)[0] == 0x4d) && !lseek(fd, (off_t)0, SEEK_CUR);
738 return syswrite(fd, buf, n);
739 }
740
741 #endif
742
743 extern int
open(const char * path,int flags,...)744 open(const char* path, int flags, ...)
745 {
746 int fd;
747 int mode;
748 int oerrno;
749 char buf[PATH_MAX];
750 #if _win32_botch_copy
751 struct stat st;
752 #endif
753 va_list ap;
754
755 va_start(ap, flags);
756 mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
757 oerrno = errno;
758 fd = sysopen(path, flags, mode);
759 #if _win32_botch_open
760 if (fd < 0 && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
761 {
762 errno = oerrno;
763 fd = sysopen(buf, flags, mode);
764 }
765 #endif
766 #if _win32_botch_copy
767 if (fd >= 0 && fd < elementsof(exe) && strlen(path) < PATH_MAX &&
768 (flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC) && (mode & 0111))
769 {
770 if (!suffix(path) && !fstat(fd, &st) && (exe[fd] || (exe[fd] = (Exe_test_t*)malloc(sizeof(Exe_test_t)))))
771 {
772 exe[fd]->test = -1;
773 exe[fd]->ino = st.st_ino;
774 strcpy(exe[fd]->path, path);
775 }
776 errno = oerrno;
777 }
778 #endif
779 va_end(ap);
780 return fd;
781 }
782
783 #endif
784
785 #if _win32_botch_pathconf
786
787 extern long
pathconf(const char * path,int op)788 pathconf(const char* path, int op)
789 {
790 if (sysaccess(path, F_OK))
791 return -1;
792 return syspathconf(path, op);
793 }
794
795 #endif
796
797 #if _win32_botch_rename
798
799 extern int
rename(const char * fp,const char * tp)800 rename(const char* fp, const char* tp)
801 {
802 int r;
803 int oerrno;
804 char fb[PATH_MAX];
805 char tb[PATH_MAX];
806
807 oerrno = errno;
808 if ((r = sysrename(fp, tp)) && errno == ENOENT && execrate(fp, fb, sizeof(fb), 1))
809 {
810 if (execrate(tp, tb, sizeof(tb), 1))
811 tp = tb;
812 errno = oerrno;
813 r = sysrename(fb, tp);
814 }
815 return r;
816 }
817
818 #endif
819
820 #if _win32_botch_stat
821
822 extern int
stat(const char * path,struct stat * st)823 stat(const char* path, struct stat* st)
824 {
825 int r;
826 int oerrno;
827 char buf[PATH_MAX];
828
829 oerrno = errno;
830 if ((r = sysstat(path, st)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
831 {
832 errno = oerrno;
833 r = sysstat(buf, st);
834 }
835 return r;
836 }
837
838 #endif
839
840 #if _win32_botch_truncate
841
842 extern int
truncate(const char * path,off_t offset)843 truncate(const char* path, off_t offset)
844 {
845 int r;
846 int oerrno;
847 char buf[PATH_MAX];
848
849 oerrno = errno;
850 if ((r = systruncate(path, offset)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
851 {
852 errno = oerrno;
853 r = systruncate(buf, offset);
854 }
855 return r;
856 }
857
858 #endif
859
860 #if _win32_botch_unlink
861
862 extern int
unlink(const char * path)863 unlink(const char* path)
864 {
865 int r;
866 int drive;
867 int mask;
868 int suffix;
869 int stop;
870 int oerrno;
871 unsigned long base;
872 char buf[PATH_MAX];
873 char tmp[MAX_PATH];
874
875 #define DELETED_DIR_1 7
876 #define DELETED_DIR_2 16
877
878 static char deleted[] = "%c:\\temp\\.deleted\\%08x.%03x";
879
880 static int count = 0;
881
882 #if __CYGWIN__
883
884 DWORD fattr = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE;
885 DWORD share = FILE_SHARE_DELETE;
886 HANDLE hp;
887 struct stat st;
888 char nat[MAX_PATH];
889
890 oerrno = errno;
891 if (lstat(path, &st) || !S_ISREG(st.st_mode))
892 goto try_unlink;
893 cygwin_conv_to_full_win32_path(path, nat);
894 if (!strncasecmp(nat + 1, ":\\temp\\", 7))
895 goto try_unlink;
896 drive = nat[0];
897 path = (const char*)nat;
898 for (;;)
899 {
900 hp = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
901 if (hp != INVALID_HANDLE_VALUE)
902 {
903 CloseHandle(hp);
904 errno = oerrno;
905 return 0;
906 }
907 if (GetLastError() != ERROR_FILE_NOT_FOUND)
908 break;
909 if (path == (const char*)buf || !execrate(path, buf, sizeof(buf), 1))
910 {
911 errno = ENOENT;
912 return -1;
913 }
914 path = (const char*)buf;
915 }
916 #else
917 if (sysaccess(path, 0))
918 #if _win32_botch_access
919 {
920 if (errno != ENOENT || !execrate(path, buf, sizeof(buf), 1) || sysaccess(buf, 0))
921 return -1;
922 path = (const char*)buf;
923 }
924 #else
925 return -1;
926 #endif
927 drive = 'C':
928 #endif
929
930 /*
931 * rename to a `deleted' path just in case the file is open
932 * otherwise directory readers may choke on phantom entries
933 */
934
935 base = ((getuid() & 0xffff) << 16) | (time(NiL) & 0xffff);
936 suffix = (getpid() & 0xfff) + count++;
937 snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
938 if (!sysrename(path, tmp))
939 {
940 path = (const char*)tmp;
941 goto try_delete;
942 }
943 if (errno != ENOTDIR && errno != ENOENT)
944 goto try_unlink;
945 tmp[DELETED_DIR_2] = 0;
946 if (sysaccess(tmp, 0))
947 {
948 mask = umask(0);
949 tmp[DELETED_DIR_1] = 0;
950 if (sysaccess(tmp, 0) && mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO))
951 {
952 umask(mask);
953 goto try_unlink;
954 }
955 tmp[DELETED_DIR_1] = '\\';
956 r = mkdir(tmp, S_IRWXU|S_IRWXG|S_IRWXO);
957 umask(mask);
958 if (r)
959 goto try_unlink;
960 errno = 0;
961 }
962 tmp[DELETED_DIR_2] = '\\';
963 if (!errno && !sysrename(path, tmp))
964 {
965 path = (const char*)tmp;
966 goto try_delete;
967 }
968 #if !__CYGWIN__
969 if (errno == ENOENT)
970 {
971 #if !_win32_botch_access
972 if (execrate(path, buf, sizeof(buf), 1) && !sysrename(buf, tmp))
973 path = (const char*)tmp;
974 #endif
975 goto try_unlink;
976 }
977 #endif
978 stop = suffix;
979 do
980 {
981 snprintf(tmp, sizeof(tmp), deleted, drive, base, suffix);
982 if (!sysrename(path, tmp))
983 {
984 path = (const char*)tmp;
985 goto try_delete;
986 }
987 if (++suffix > 0xfff)
988 suffix = 0;
989 } while (suffix != stop);
990 try_delete:
991 #if __CYGWIN__
992 hp = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_DELETE_ON_CLOSE, NULL);
993 if (hp != INVALID_HANDLE_VALUE)
994 {
995 CloseHandle(hp);
996 errno = oerrno;
997 return 0;
998 }
999 #endif
1000 try_unlink:
1001 errno = oerrno;
1002 return sysunlink(path);
1003 }
1004
1005 #endif
1006
1007 #if _win32_botch_utime
1008
1009 #if __CYGWIN__
1010
1011 /*
1012 * cygwin refuses to set st_ctime for some operations
1013 * this rejects that refusal
1014 */
1015
1016 static void
ctime_now(const char * path)1017 ctime_now(const char* path)
1018 {
1019 HANDLE hp;
1020 SYSTEMTIME st;
1021 FILETIME ct;
1022 WIN32_FIND_DATA ff;
1023 struct stat fs;
1024 int oerrno;
1025 char tmp[MAX_PATH];
1026
1027 if (sysstat(path, &fs) || (fs.st_mode & S_IWUSR) || syschmod(path, (fs.st_mode | S_IWUSR) & S_IPERM))
1028 fs.st_mode = 0;
1029 cygwin_conv_to_win32_path(path, tmp);
1030 hp = CreateFile(tmp, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1031 if (hp && hp != INVALID_HANDLE_VALUE)
1032 {
1033 GetSystemTime(&st);
1034 SystemTimeToFileTime(&st, &ct);
1035 SetFileTime(hp, &ct, 0, 0);
1036 CloseHandle(hp);
1037 }
1038 if (fs.st_mode)
1039 syschmod(path, fs.st_mode & S_IPERM);
1040 errno = oerrno;
1041 }
1042
1043 #else
1044
1045 #define ctime_now(p)
1046
1047 #endif
1048
1049 extern int
utimes(const char * path,const struct timeval * ut)1050 utimes(const char* path, const struct timeval* ut)
1051 {
1052 int r;
1053 int oerrno;
1054 char buf[PATH_MAX];
1055
1056 oerrno = errno;
1057 if ((r = sysutimes(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
1058 {
1059 errno = oerrno;
1060 r = sysutimes(path = buf, ut);
1061 }
1062 if (!r)
1063 ctime_now(path);
1064 return r;
1065 }
1066
1067 extern int
utime(const char * path,const struct utimbuf * ut)1068 utime(const char* path, const struct utimbuf* ut)
1069 {
1070 int r;
1071 int oerrno;
1072 char buf[PATH_MAX];
1073
1074 oerrno = errno;
1075 if ((r = sysutime(path, ut)) && errno == ENOENT && execrate(path, buf, sizeof(buf), 0))
1076 {
1077 errno = oerrno;
1078 r = sysutime(path = buf, ut);
1079 }
1080 if (!r)
1081 ctime_now(path);
1082 return r;
1083 }
1084
1085 #endif
1086
1087 #endif
1088
1089 /*
1090 * some systems (sun) miss a few functions required by their
1091 * own bsd-like macros
1092 */
1093
1094 #if !_lib_bzero || defined(bzero)
1095
1096 #undef bzero
1097
1098 void
bzero(void * b,size_t n)1099 bzero(void* b, size_t n)
1100 {
1101 memset(b, 0, n);
1102 }
1103
1104 #endif
1105
1106 #if !_lib_getpagesize || defined(getpagesize)
1107
1108 #ifndef OMITTED
1109 #define OMITTED 1
1110 #endif
1111
1112 #undef getpagesize
1113
1114 #ifdef _SC_PAGESIZE
1115 #undef _AST_PAGESIZE
1116 #define _AST_PAGESIZE (int)sysconf(_SC_PAGESIZE)
1117 #else
1118 #ifndef _AST_PAGESIZE
1119 #define _AST_PAGESIZE 4096
1120 #endif
1121 #endif
1122
1123 int
getpagesize()1124 getpagesize()
1125 {
1126 return _AST_PAGESIZE;
1127 }
1128
1129 #endif
1130
1131 #if __CYGWIN__ && defined(__IMPORT__) && defined(__EXPORT__)
1132
1133 #ifndef OMITTED
1134 #define OMITTED 1
1135 #endif
1136
1137 /*
1138 * a few _imp__FUNCTION symbols are needed to avoid
1139 * static link multiple definitions
1140 */
1141
1142 #ifndef strtod
1143 __EXPORT__ double (*_imp__strtod)(const char*, char**) = strtod;
1144 #endif
1145
1146 #endif
1147
1148 #ifndef OMITTED
1149
1150 NoN(omitted)
1151
1152 #endif
1153