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