source: trunk/src/kash/shfile.c@ 2294

Last change on this file since 2294 was 2294, checked in by bird, 16 years ago

kash: more fixes + pipe.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 31.7 KB
Line 
1/* $Id: shfile.c 2294 2009-02-28 08:33:26Z bird $ */
2/** @file
3 *
4 * File management.
5 *
6 * Copyright (c) 2007-2009 knut st. osmundsen <bird-kBuild-spamix@anduin.net>
7 *
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include "shfile.h"
28#include "shinstance.h" /* TRACE2 */
29#include <stdlib.h>
30#include <stdio.h>
31#include <assert.h>
32
33#if K_OS == K_OS_WINDOWS
34# include <limits.h>
35# ifndef PIPE_BUF
36# define PIPE_BUF 512
37# endif
38# include <Windows.h>
39#else
40# include <unistd.h>
41# include <fcntl.h>
42# include <dirent.h>
43#endif
44
45#ifdef DEBUG
46extern FILE *tracefile;
47#endif
48
49
50/*******************************************************************************
51* Defined Constants And Macros *
52*******************************************************************************/
53/** @def SHFILE_IN_USE
54 * Whether the file descriptor table stuff is actually in use or not.
55 */
56#if !defined(SH_PURE_STUB_MODE) \
57 && ( K_OS == K_OS_WINDOWS \
58 || ( !defined(SH_STUB_MODE) \
59 && !defined(SH_FORKED_MODE)) \
60 )
61# define SHFILE_IN_USE
62#endif
63/** The max file table size. */
64#define SHFILE_MAX 1024
65/** The file table growth rate. */
66#define SHFILE_GROW 64
67/** The min native unix file descriptor. */
68#define SHFILE_UNIX_MIN_FD 32
69/** The path buffer size we use. */
70#define SHFILE_MAX_PATH 4096
71
72/** Set errno and return. Doing a trace in debug build. */
73#define RETURN_ERROR(rc, err, msg) \
74 do { \
75 TRACE2((NULL, "%s: " ## msg ## " - returning %d / %d\n", __FUNCTION__, (rc), (err))); \
76 errno = (err); \
77 return (rc); \
78 } while (0)
79
80
81#ifdef SHFILE_IN_USE
82
83/**
84 * Close the specified native handle.
85 *
86 * @param native The native file handle.
87 * @param flags The flags in case they might come in handy later.
88 */
89static void shfile_native_close(intptr_t native, unsigned flags)
90{
91#if K_OS == K_OS_WINDOWS
92 BOOL fRc = CloseHandle((HANDLE)native);
93 assert(fRc); (void)fRc;
94#else
95 int s = errno;
96 close(native);
97 errno = s;
98#endif
99 (void)flags;
100}
101
102/**
103 * Inserts the file into the descriptor table.
104 *
105 * If we're out of memory and cannot extend the table, we'll close the
106 * file, set errno to EMFILE and return -1.
107 *
108 * @returns The file descriptor number. -1 and errno on failure.
109 * @param pfdtab The file descriptor table.
110 * @param native The native file handle.
111 * @param flags The flags the it was created with.
112 * @param fdMin The minimum file descriptor number, pass -1 if any is ok.
113 * @param who Who we're doing this for (for logging purposes).
114 */
115static int shfile_insert(shfdtab *pfdtab, intptr_t native, unsigned flags, int fdMin, const char *who)
116{
117 shmtxtmp tmp;
118 int fd;
119 int i;
120
121 /*
122 * Fend of bad stuff.
123 */
124 if (fdMin >= SHFILE_MAX)
125 {
126 errno = EMFILE;
127 return -1;
128 }
129
130 shmtx_enter(&pfdtab->mtx, &tmp);
131
132 /*
133 * Search for a fitting unused location.
134 */
135 fd = -1;
136 for (i = 0; (unsigned)i < pfdtab->size; i++)
137 if ( i >= fdMin
138 && pfdtab->tab[i].fd == -1)
139 {
140 fd = i;
141 break;
142 }
143 if (fd == -1)
144 {
145 /*
146 * Grow the descriptor table.
147 */
148 shfile *new_tab;
149 int new_size = pfdtab->size + SHFILE_GROW;
150 while (new_size < fdMin)
151 new_size += SHFILE_GROW;
152 new_tab = sh_realloc(NULL, pfdtab->tab, new_size * sizeof(shfile));
153 if (new_tab)
154 {
155 fd = i = pfdtab->size;
156 if (fd < fdMin)
157 fd = fdMin;
158 for (i = pfdtab->size; i < new_size; i++)
159 {
160 new_tab[i].fd = -1;
161 new_tab[i].flags = 0;
162 new_tab[i].native = -1;
163 }
164
165 pfdtab->tab = new_tab;
166 pfdtab->size = new_size;
167 }
168 }
169
170 /*
171 * Fill in the entry if we've found one.
172 */
173 if (fd != -1)
174 {
175 pfdtab->tab[fd].fd = fd;
176 pfdtab->tab[fd].flags = flags;
177 pfdtab->tab[fd].cloexec = 0;
178 pfdtab->tab[fd].native = native;
179 }
180 else
181 shfile_native_close(native, flags);
182
183 shmtx_leave(&pfdtab->mtx, &tmp);
184
185 if (fd == -1)
186 errno = EMFILE;
187 (void)who;
188 return fd;
189}
190
191/**
192 * Gets a file descriptor and lock the file descriptor table.
193 *
194 * @returns Pointer to the file and table ownership on success,
195 * NULL and errno set to EBADF on failure.
196 * @param pfdtab The file descriptor table.
197 * @param fd The file descriptor number.
198 * @param ptmp See shmtx_enter.
199 */
200static shfile *shfile_get(shfdtab *pfdtab, int fd, shmtxtmp *ptmp)
201{
202 shfile *file = NULL;
203 if ( fd >= 0
204 && (unsigned)fd < pfdtab->size)
205 {
206 shmtx_enter(&pfdtab->mtx, ptmp);
207 if ((unsigned)fd < pfdtab->size
208 && pfdtab->tab[fd].fd != -1)
209 file = &pfdtab->tab[fd];
210 else
211 shmtx_leave(&pfdtab->mtx, ptmp);
212 }
213 if (!file)
214 errno = EBADF;
215 return file;
216}
217
218/**
219 * Puts back a file descriptor and releases the table ownership.
220 *
221 * @param pfdtab The file descriptor table.
222 * @param file The file.
223 * @param ptmp See shmtx_leave.
224 */
225static void shfile_put(shfdtab *pfdtab, shfile *file, shmtxtmp *ptmp)
226{
227 shmtx_leave(&pfdtab->mtx, ptmp);
228 assert(file);
229 (void)file;
230}
231
232/**
233 * Constructs a path from the current directory and the passed in path.
234 *
235 * @returns 0 on success, -1 and errno set to ENAMETOOLONG or EINVAL on failure.
236 *
237 * @param pfdtab The file descriptor table
238 * @param path The path the caller supplied.
239 * @param buf Where to put the path. This is assumed to be SHFILE_MAX_PATH
240 * chars in size.
241 */
242int shfile_make_path(shfdtab *pfdtab, const char *path, char *buf)
243{
244 size_t path_len = strlen(path);
245 if (path_len == 0)
246 {
247 errno = EINVAL;
248 return -1;
249 }
250 if (path_len >= SHFILE_MAX_PATH)
251 {
252 errno = ENAMETOOLONG;
253 return -1;
254 }
255 if ( *path == '/'
256#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
257 || *path == '\\'
258 || ( *path
259 && path[1] == ':'
260 && ( (*path >= 'A' && *path <= 'Z')
261 || (*path >= 'a' && *path <= 'z')))
262#endif
263 )
264 {
265 memcpy(buf, path, path_len + 1);
266 }
267 else
268 {
269 size_t cwd_len;
270 shmtxtmp tmp;
271
272 shmtx_enter(&pfdtab->mtx, &tmp);
273
274 cwd_len = strlen(pfdtab->cwd);
275 memcpy(buf, pfdtab->cwd, cwd_len);
276
277 shmtx_leave(&pfdtab->mtx, &tmp);
278
279 if (cwd_len + path_len + 1 >= SHFILE_MAX_PATH)
280 {
281 errno = ENAMETOOLONG;
282 return -1;
283 }
284 if ( !cwd_len
285 || buf[cwd_len - 1] != '/')
286 buf[cwd_len++] = '/';
287 memcpy(buf + cwd_len, path, path_len + 1);
288 }
289
290#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
291 if (!strcmp(buf, "/dev/null"))
292 strcpy(buf, "NUL");
293#endif
294 return 0;
295}
296
297# if K_OS == K_OS_WINDOWS
298/**
299 * Converts a DOS(/Windows) error code to errno,
300 * assigning it to errno.
301 *
302 * @returns -1
303 * @param err The DOS error.
304 */
305static int shfile_dos2errno(int err)
306{
307 switch (err)
308 {
309 case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break;
310 case ERROR_ACCESS_DENIED: errno = EACCES; break;
311 case ERROR_CURRENT_DIRECTORY: errno = EACCES; break;
312 case ERROR_LOCK_VIOLATION: errno = EACCES; break;
313 case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break;
314 case ERROR_CANNOT_MAKE: errno = EACCES; break;
315 case ERROR_FAIL_I24: errno = EACCES; break;
316 case ERROR_DRIVE_LOCKED: errno = EACCES; break;
317 case ERROR_SEEK_ON_DEVICE: errno = EACCES; break;
318 case ERROR_NOT_LOCKED: errno = EACCES; break;
319 case ERROR_LOCK_FAILED: errno = EACCES; break;
320 case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break;
321 case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break;
322 case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break;
323 case ERROR_INVALID_HANDLE: errno = EBADF; break;
324 case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break;
325 case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break;
326 case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break;
327 case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break;
328 case ERROR_FILE_EXISTS: errno = EEXIST; break;
329 case ERROR_ALREADY_EXISTS: errno = EEXIST; break;
330 case ERROR_INVALID_FUNCTION: errno = EINVAL; break;
331 case ERROR_INVALID_ACCESS: errno = EINVAL; break;
332 case ERROR_INVALID_DATA: errno = EINVAL; break;
333 case ERROR_INVALID_PARAMETER: errno = EINVAL; break;
334 case ERROR_NEGATIVE_SEEK: errno = EINVAL; break;
335 case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break;
336 case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
337 case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
338 case ERROR_INVALID_DRIVE: errno = ENOENT; break;
339 case ERROR_NO_MORE_FILES: errno = ENOENT; break;
340 case ERROR_BAD_NETPATH: errno = ENOENT; break;
341 case ERROR_BAD_NET_NAME: errno = ENOENT; break;
342 case ERROR_BAD_PATHNAME: errno = ENOENT; break;
343 case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break;
344 case ERROR_BAD_FORMAT: errno = ENOEXEC; break;
345 case ERROR_ARENA_TRASHED: errno = ENOMEM; break;
346 case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break;
347 case ERROR_INVALID_BLOCK: errno = ENOMEM; break;
348 case ERROR_NOT_ENOUGH_QUOTA: errno = ENOMEM; break;
349 case ERROR_DISK_FULL: errno = ENOSPC; break;
350 case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break;
351 case ERROR_BROKEN_PIPE: errno = EPIPE; break;
352 case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break;
353 default: errno = EINVAL; break;
354 }
355 return -1;
356}
357# endif /* K_OS == K_OS_WINDOWS */
358
359#endif /* SHFILE_IN_USE */
360
361/**
362 * Initializes a file descriptor table.
363 *
364 * @returns 0 on success, -1 and errno on failure.
365 * @param pfdtab The table to initialize.
366 * @param inherit File descriptor table to inherit from. If not specified
367 * we will inherit from the current process as it were.
368 */
369int shfile_init(shfdtab *pfdtab, shfdtab *inherit)
370{
371 int rc;
372
373 pfdtab->cwd = NULL;
374 pfdtab->size = 0;
375 pfdtab->tab = NULL;
376 rc = shmtx_init(&pfdtab->mtx);
377 if (!rc)
378 {
379#ifdef SHFILE_IN_USE
380 char buf[SHFILE_MAX_PATH];
381 if (getcwd(buf, sizeof(buf)))
382 {
383 pfdtab->cwd = sh_strdup(NULL, buf);
384 if (!inherit)
385 {
386# if K_OS == K_OS_WINDOWS
387 static const struct
388 {
389 DWORD dwStdHandle;
390 unsigned flags;
391 } aStdHandles[3] =
392 {
393 { STD_INPUT_HANDLE, _O_RDONLY },
394 { STD_OUTPUT_HANDLE, _O_WRONLY },
395 { STD_ERROR_HANDLE, _O_WRONLY }
396 };
397 unsigned i;
398 STARTUPINFO Info;
399
400 rc = 0;
401
402 /* Try pick up the Visual C++ CRT file descriptor info. */
403 __try {
404 GetStartupInfo(&Info);
405 } __except (EXCEPTION_EXECUTE_HANDLER) {
406 memset(&Info, 0, sizeof(Info));
407 }
408 if ( Info.cbReserved2 <= sizeof(int)
409 && (uintptr_t)Info.lpReserved2 >= 0x1000
410 && *(int *)Info.lpReserved2 * (sizeof(int) + sizeof(intptr_t)) + 4 <= Info.cbReserved2
411 && *(int *)Info.lpReserved2 <= 2048
412 && *(int *)Info.lpReserved2 >= 1)
413 {
414 unsigned c = *(int *)Info.lpReserved2;
415 char *aosfile = (char *)Info.lpReserved2 + sizeof(int);
416 intptr_t *aosfhnd = (intptr_t *)(aosfile + c);
417
418 /** @todo process */
419
420 }
421
422 /* Check the three standard handles. */
423 for (i = 0; i < 3; i++)
424 {
425 HANDLE hFile = GetStdHandle(aStdHandles[i].dwStdHandle);
426 if ( hFile != INVALID_HANDLE_VALUE
427 && ( (unsigned)i >= pfdtab->size
428 || pfdtab->tab[i].fd == -1))
429 {
430 int fd2 = shfile_insert(pfdtab, (intptr_t)hFile, aStdHandles[i].flags, i, "shtab_init");
431 assert(fd2 == i); (void)fd2;
432 if (fd2 != i)
433 rc = -1;
434 }
435 }
436# else
437# endif
438 }
439 else
440 {
441 /** @todo */
442 errno = ENOSYS;
443 rc = -1;
444 }
445 }
446 else
447 rc = -1;
448#endif
449 }
450 return rc;
451}
452
453#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE) //&& defined(SH_FORKED_MODE)
454/**
455 * Helper for shfork.
456 *
457 * @param pfdtab The file descriptor table.
458 * @param set Whether to make all handles inheritable (1) or
459 * to restore them to the rigth state (0).
460 * @param hndls Where to store the three standard handles.
461 */
462void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls)
463{
464 shmtxtmp tmp;
465 unsigned i;
466
467 shmtx_enter(&pfdtab->mtx, &tmp);
468 TRACE2((NULL, "shfile_fork_win:\n"));
469
470 i = pfdtab->size;
471 while (i-- > 0)
472 {
473 if (pfdtab->tab[i].fd == i)
474 {
475 HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
476 DWORD fFlag = (set || !pfdtab->tab[i].cloexec)
477 ? HANDLE_FLAG_INHERIT : 0;
478 if (set)
479 TRACE2((NULL, " #%d: native=%#x flags=%#x cloexec=%d fFlag=%#x\n",
480 i, pfdtab->tab[i].flags, hFile, pfdtab->tab[i].cloexec, fFlag));
481
482 if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, fFlag))
483 {
484 DWORD err = GetLastError();
485 assert(0);
486 }
487 }
488 }
489
490 if (hndls)
491 {
492 for (i = 0; i < 3; i++)
493 {
494 if ( pfdtab->size > i
495 && pfdtab->tab[i].fd == 0)
496 hndls[i] = pfdtab->tab[i].native;
497 else
498 hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
499 }
500 }
501
502 shmtx_leave(&pfdtab->mtx, &tmp);
503}
504#endif
505
506
507/**
508 * open().
509 */
510int shfile_open(shfdtab *pfdtab, const char *name, unsigned flags, mode_t mode)
511{
512 int fd;
513#ifdef SHFILE_IN_USE
514 char absname[SHFILE_MAX_PATH];
515# if K_OS == K_OS_WINDOWS
516 HANDLE hFile;
517 DWORD dwDesiredAccess;
518 DWORD dwShareMode;
519 DWORD dwCreationDisposition;
520 DWORD dwFlagsAndAttributes;
521 SECURITY_ATTRIBUTES SecurityAttributes;
522
523# ifndef _O_ACCMODE
524# define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
525# endif
526 switch (flags & (_O_ACCMODE | _O_APPEND))
527 {
528 case _O_RDONLY: dwDesiredAccess = GENERIC_READ; break;
529 case _O_RDONLY | _O_APPEND: dwDesiredAccess = GENERIC_READ; break;
530 case _O_WRONLY: dwDesiredAccess = GENERIC_WRITE; break;
531 case _O_WRONLY | _O_APPEND: dwDesiredAccess = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break;
532 case _O_RDWR: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; break;
533 case _O_RDWR | _O_APPEND: dwDesiredAccess = GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break;
534
535 default:
536 RETURN_ERROR(-1, EINVAL, "invalid mode");
537 }
538
539 dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
540
541 SecurityAttributes.nLength = sizeof(SecurityAttributes);
542 SecurityAttributes.lpSecurityDescriptor = NULL;
543 SecurityAttributes.bInheritHandle = (flags & _O_NOINHERIT) == 0;
544
545 if (flags & _O_CREAT)
546 {
547 if ((flags & (_O_EXCL | _O_TRUNC)) == (_O_EXCL | _O_TRUNC))
548 RETURN_ERROR(-1, EINVAL, "_O_EXCL | _O_TRUNC");
549
550 if (flags & _O_TRUNC)
551 dwCreationDisposition = CREATE_ALWAYS; /* not 100%, but close enough */
552 else if (flags & _O_EXCL)
553 dwCreationDisposition = CREATE_NEW;
554 else
555 dwCreationDisposition = OPEN_ALWAYS;
556 }
557 else if (flags & _O_TRUNC)
558 dwCreationDisposition = TRUNCATE_EXISTING;
559 else
560 dwCreationDisposition = OPEN_EXISTING;
561
562 if (!(flags & _O_CREAT) || (mode & 0222))
563 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
564 else
565 dwFlagsAndAttributes = FILE_ATTRIBUTE_READONLY;
566
567 fd = shfile_make_path(pfdtab, name, &absname[0]);
568 if (!fd)
569 {
570 SetLastError(0);
571 hFile = CreateFileA(absname,
572 dwDesiredAccess,
573 dwShareMode,
574 &SecurityAttributes,
575 dwCreationDisposition,
576 dwFlagsAndAttributes,
577 NULL /* hTemplateFile */);
578 if (hFile != INVALID_HANDLE_VALUE)
579 fd = shfile_insert(pfdtab, (intptr_t)hFile, flags, -1, "shfile_open");
580 else
581 fd = shfile_dos2errno(GetLastError());
582 }
583
584# else /* K_OS != K_OS_WINDOWS */
585 fd = shfile_make_path(pfdtab, name, &absname[0]);
586 if (!fd)
587 {
588 fd = open(absname, flag, mode);
589 if (fd != -1)
590 {
591 int native = fcntl(fd, F_DUPFD, SHFILE_UNIX_MIN_FD);
592 int s = errno;
593 close(fd);
594 errno = s;
595 if (native != -1)
596 fd = shfile_insert(pfdtab, native, flags, -1, "shfile_open");
597 else
598 fd = -1;
599 }
600 }
601
602# endif /* K_OS != K_OS_WINDOWS */
603
604#elif defined(SH_PURE_STUB_MODE)
605 fd = -1;
606 errno = ENOSYS;
607
608#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
609 fd = open(name, flags, mode);
610#endif
611
612#ifdef DEBUG
613 if (tracefile)
614 TRACE2((NULL, "shfile_open(%p:{%s}, %#x, 0%o) -> %d [%d]\n", name, name, flags, mode, fd, errno));
615#endif
616 return fd;
617}
618
619int shfile_pipe(shfdtab *pfdtab, int fds[2])
620{
621 int rc;
622 int s;
623#ifdef SHFILE_IN_USE
624# if K_OS == K_OS_WINDOWS
625 HANDLE hRead = INVALID_HANDLE_VALUE;
626 HANDLE hWrite = INVALID_HANDLE_VALUE;
627 SECURITY_ATTRIBUTES SecurityAttributes;
628
629 SecurityAttributes.nLength = sizeof(SecurityAttributes);
630 SecurityAttributes.lpSecurityDescriptor = NULL;
631 SecurityAttributes.bInheritHandle = TRUE;
632
633 if (!CreatePipe(&hRead, &hWrite, &SecurityAttributes, 4096))
634 {
635 fds[0] = shfile_insert(pfdtab, (intptr_t)hRead, O_RDONLY, -1, "shfile_pipe");
636 if (fds[0] != -1)
637 {
638 fds[1] = shfile_insert(pfdtab, (intptr_t)hWrite, O_WRONLY, -1, "shfile_pipe");
639 if (fds[1] != -1)
640 rc = 0;
641 }
642
643# else
644 int native_fds[2];
645 if (!pipe(native_fds))
646 {
647 fds[1] = -1;
648 fds[0] = shfile_insert(pfdtab, native_fds[0], O_RDONLY, -1, "shfile_pipe");
649 if (fds[0] != -1)
650 {
651 fds[1] = shfile_insert(pfdtab, native_fds[1], O_WRONLY, -1, "shfile_pipe");
652 if (fds[1] != -1)
653 rc = 0;
654 }
655# endif
656 s = errno;
657 if (fds[1] == -1)
658 {
659 if (fds[0] != -1)
660 {
661 shmtxtmp tmp;
662 shmtx_enter(&pfdtab->mtx, &tmp);
663 rc = fds[0];
664 pfdtab->tab[rc].fd = -1;
665 pfdtab->tab[rc].flags = 0;
666 pfdtab->tab[rc].native = -1;
667 shmtx_leave(&pfdtab->mtx, &tmp);
668 }
669
670# if K_OS == K_OS_WINDOWS
671 CloseHandle(hRead);
672 CloseHandle(hWrite);
673# else
674 close(native_fds[0]);
675 close(native_fds[1]);
676# endif
677 fds[0] = fds[1] = -1;
678 errno = s;
679 rc = -1;
680 }
681 }
682
683#elif defined(SH_PURE_STUB_MODE)
684 rc = -1;
685 errno = ENOSYS;
686
687#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
688# ifdef _MSC_VER
689 rc = _pipe(fds, PIPE_BUF, O_BINARY);
690# else
691 rc = pipe(fds);
692# endif
693#endif
694
695 TRACE2((NULL, "shfile_pipe() -> %d{%d,%d} [%d]\n", rc, fds[0], fds[1], errno));
696 return rc;
697}
698
699int shfile_dup(shfdtab *pfdtab, int fd)
700{
701 int rc;
702#ifdef SH_PURE_STUB_MODE
703 rc = -1;
704
705#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
706 rc = dup(fd);
707
708#else
709#endif
710
711 TRACE2((NULL, "shfile_dup(%d) -> %d [%d]\n", fd, rc, errno));
712 return rc;
713}
714
715/**
716 * close().
717 */
718int shfile_close(shfdtab *pfdtab, unsigned fd)
719{
720 int rc;
721#ifdef SHFILE_IN_USE
722 shmtxtmp tmp;
723 shfile *file = shfile_get(pfdtab, fd, &tmp);
724 if (file)
725 {
726 shfile_native_close(file->native, file->flags);
727
728 file->fd = -1;
729 file->flags = 0;
730 file->native = -1;
731
732 shfile_put(pfdtab, file, &tmp);
733 rc = 0;
734 }
735 else
736 rc = -1;
737
738#elif defined(SH_PURE_STUB_MODE)
739 rc = -1;
740
741#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
742 rc = close(fd);
743#endif
744
745 TRACE2((NULL, "shfile_close(%d) -> %d [%d]\n", fd, rc, errno));
746 return rc;
747}
748
749/**
750 * read().
751 */
752long shfile_read(shfdtab *pfdtab, int fd, void *buf, size_t len)
753{
754 long rc;
755#ifdef SHFILE_IN_USE
756 shmtxtmp tmp;
757 shfile *file = shfile_get(pfdtab, fd, &tmp);
758 if (file)
759 {
760# if K_OS == K_OS_WINDOWS
761 DWORD dwRead = 0;
762 if (ReadFile((HANDLE)file->native, buf, (DWORD)len, &dwRead, NULL))
763 rc = dwRead;
764 else
765 rc = shfile_dos2errno(GetLastError());
766# else
767 rc = read(file->native, buf, len);
768# endif
769
770 shfile_put(pfdtab, file, &tmp);
771 }
772 else
773 rc = -1;
774
775#elif defined(SH_PURE_STUB_MODE)
776 rc = -1;
777
778#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
779# ifdef _MSC_VER
780 rc = read(fd, buf, (unsigned)len);
781# else
782 rc = read(fd, buf, len);
783# endif
784#endif
785 return rc;
786}
787
788/**
789 * write().
790 */
791long shfile_write(shfdtab *pfdtab, int fd, const void *buf, size_t len)
792{
793 long rc;
794#ifdef SHFILE_IN_USE
795 shmtxtmp tmp;
796 shfile *file = shfile_get(pfdtab, fd, &tmp);
797 if (file)
798 {
799# if K_OS == K_OS_WINDOWS
800 DWORD dwWritten = 0;
801 if (WriteFile((HANDLE)file->native, buf, (DWORD)len, &dwWritten, NULL))
802 rc = dwWritten;
803 else
804 rc = shfile_dos2errno(GetLastError());
805# else
806 rc = write(file->native, buf, len);
807# endif
808
809 shfile_put(pfdtab, file, &tmp);
810 }
811 else
812 rc = -1;
813
814#elif defined(SH_PURE_STUB_MODE)
815 rc = -1;
816
817#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
818# ifdef _MSC_VER
819 rc = write(fd, buf, (unsigned)len);
820# else
821 rc = write(fd, buf, len);
822# endif
823#endif
824 return rc;
825}
826
827/**
828 * lseek().
829 */
830long shfile_lseek(shfdtab *pfdtab, int fd, long off, int whench)
831{
832 long rc;
833#ifdef SHFILE_IN_USE
834 shmtxtmp tmp;
835 shfile *file = shfile_get(pfdtab, fd, &tmp);
836 if (file)
837 {
838# if K_OS == K_OS_WINDOWS
839 assert(SEEK_SET == FILE_BEGIN);
840 assert(SEEK_CUR == FILE_CURRENT);
841 assert(SEEK_END == FILE_END);
842 rc = SetFilePointer((HANDLE)file->native, off, NULL, whench);
843 if (rc == INVALID_SET_FILE_POINTER)
844 rc = shfile_dos2errno(GetLastError());
845# else
846 rc = lseek(file->native, off, whench);
847# endif
848
849 shfile_put(pfdtab, file, &tmp);
850 }
851 else
852 rc = -1;
853
854#elif defined(SH_PURE_STUB_MODE)
855 rc = -1;
856
857#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
858 rc = lseek(fd, off, whench);
859#endif
860
861 return rc;
862}
863
864int shfile_fcntl(shfdtab *pfdtab, int fd, int cmd, int arg)
865{
866 int rc;
867#ifdef SHFILE_IN_USE
868 shmtxtmp tmp;
869 shfile *file = shfile_get(pfdtab, fd, &tmp);
870 if (file)
871 {
872 switch (cmd)
873 {
874 case F_GETFL:
875 rc = file->flags;
876 break;
877
878 case F_SETFL:
879 {
880 unsigned mask = O_NONBLOCK | O_APPEND | O_BINARY | O_TEXT;
881# ifdef O_DIRECT
882 mask |= O_DIRECT;
883# endif
884# ifdef O_ASYNC
885 mask |= O_ASYNC;
886# endif
887# ifdef O_SYNC
888 mask |= O_SYNC;
889# endif
890 if ((file->flags & mask) == (arg & mask))
891 rc = 0;
892 else
893 {
894# if K_OS == K_OS_WINDOWS
895 assert(0);
896 errno = EINVAL;
897 rc = -1;
898# else
899 rc = fcntl(file->native, F_SETFL, arg);
900 if (rc != -1)
901 file->flags = (file->flags & ~mask) | (arg & mask);
902# endif
903 }
904 break;
905 }
906
907 case F_DUPFD:
908 {
909# if K_OS == K_OS_WINDOWS
910 HANDLE hNew = INVALID_HANDLE_VALUE;
911 if (DuplicateHandle(GetCurrentProcess(),
912 (HANDLE)file->native,
913 GetCurrentProcess(),
914 &hNew,
915 0,
916 TRUE /* bInheritHandle */,
917 DUPLICATE_SAME_ACCESS))
918 rc = shfile_insert(pfdtab, (intptr_t)hNew, file->flags, arg, "shfile_fcntl");
919 else
920 rc = shfile_dos2errno(GetLastError());
921# else
922 int nativeNew = fcntl(file->native F_DUPFD, SHFILE_UNIX_MIN_FD);
923 if (nativeNew != -1)
924 rc = shfile_insert(pfdtab, nativeNew, file->flags, arg, "shfile_fcntl");
925# endif
926 break;
927 }
928
929 default:
930 errno = -EINVAL;
931 rc = -1;
932 break;
933 }
934
935 shfile_put(pfdtab, file, &tmp);
936 }
937 else
938 rc = -1;
939
940#elif defined(SH_PURE_STUB_MODE)
941 rc = -1;
942
943#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
944# ifdef _MSC_VER
945 switch (cmd)
946 {
947 /* Just enough F_GETFL/F_SETFL to get along with. */
948 case F_GETFL:
949 errno = 0;
950 rc = _isatty(fd);
951 if (errno == EBADF)
952 rc = -1;
953 break;
954
955 case F_SETFL:
956 errno = 0;
957 rc = _isatty(fd);
958 if (errno != EBADF)
959 {
960 if (!arg)
961 rc = 0;
962 else
963 {
964 errno = EINVAL;
965 rc = -1;
966 }
967 }
968 else
969 rc = -1;
970 break;
971
972 case F_DUPFD:
973 {
974 /* the brute force approach. */
975 int i = 0;
976 int fds[256];
977 for (i = 0; i < 256; i++)
978 {
979 fds[i] = -1;
980 rc = _dup(fd);
981 if (rc >= arg)
982 break;
983 fds[i] = rc;
984 }
985 while (i-- > 0)
986 close(fds[i]);
987 if (rc < arg)
988 {
989 errno = EMFILE;
990 rc = -1;
991 }
992 break;
993 }
994 }
995# else
996 rc = fcntl(fd, cmd, arg);
997# endif
998#endif
999
1000#ifdef DEBUG
1001 if (tracefile)
1002 switch (cmd)
1003 {
1004 case F_GETFL:
1005 TRACE2((NULL, "shfile_fcntl(%d,F_GETFL,ignored=%d) -> %d [%d]\n", fd, arg, rc, errno));
1006 break;
1007 case F_SETFL:
1008 TRACE2((NULL, "shfile_fcntl(%d,F_SETFL,newflags=%#x) -> %d [%d]\n", fd, arg, rc, errno));
1009 break;
1010 case F_DUPFD:
1011 TRACE2((NULL, "shfile_fcntl(%d,F_DUPFS,minfd=%d) -> %d [%d]\n", fd, arg, rc, errno));
1012 break;
1013 default:
1014 TRACE2((NULL, "shfile_fcntl(%d,%d,%d) -> %d [%d]\n", fd, cmd, arg, rc, errno));
1015 break;
1016 }
1017#endif
1018 return rc;
1019}
1020
1021int shfile_stat(shfdtab *pfdtab, const char *path, struct stat *pst)
1022{
1023#ifdef SH_PURE_STUB_MODE
1024 return -1;
1025
1026#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1027 return stat(path, pst);
1028
1029#else
1030#endif
1031}
1032
1033int shfile_lstat(shfdtab *pfdtab, const char *link, struct stat *pst)
1034{
1035#ifdef SH_PURE_STUB_MODE
1036 return -1;
1037
1038#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1039# ifdef _MSC_VER
1040 return stat(link, pst);
1041# else
1042 return lstat(link, pst);
1043# endif
1044
1045#else
1046#endif
1047}
1048
1049int shfile_chdir(shfdtab *pfdtab, const char *path)
1050{
1051#ifdef SH_PURE_STUB_MODE
1052 return -1;
1053
1054#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1055# ifdef _MSC_VER //???
1056 return chdir(path);
1057# else
1058 return chdir(path);
1059# endif
1060
1061#else
1062#endif
1063}
1064
1065char *shfile_getcwd(shfdtab *pfdtab, char *buf, int len)
1066{
1067#ifdef SH_PURE_STUB_MODE
1068 return NULL;
1069
1070#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1071 return getcwd(buf, len);
1072
1073#else
1074#endif
1075}
1076
1077int shfile_access(shfdtab *pfdtab, const char *path, int type)
1078{
1079#ifdef SH_PURE_STUB_MODE
1080 return -1;
1081
1082#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1083# ifdef _MSC_VER
1084 type &= ~X_OK;
1085 return access(path, type);
1086# else
1087 return access(path, type);
1088# endif
1089
1090#else
1091#endif
1092}
1093
1094int shfile_isatty(shfdtab *pfdtab, int fd)
1095{
1096 int rc;
1097
1098#ifdef SH_PURE_STUB_MODE
1099 rc = 0;
1100#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1101 rc = isatty(fd);
1102#else
1103#endif
1104
1105 TRACE2((NULL, "isatty(%d) -> %d [%d]\n", fd, rc, errno));
1106 return rc;
1107}
1108
1109
1110int shfile_cloexec(shfdtab *pfdtab, int fd, int closeit)
1111{
1112 int rc;
1113
1114#ifdef SH_PURE_STUB_MODE
1115 rc = -1;
1116
1117#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1118# ifdef _MSC_VER
1119 errno = ENOSYS;
1120 rc = -1;
1121# else
1122 rc = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0)
1123 | (closeit ? FD_CLOEXEC : 0));
1124# endif
1125
1126#else
1127#endif
1128
1129 TRACE2((NULL, "shfile_cloexec(%d, %d) -> %d [%d]\n", fd, closeit, rc, errno));
1130 return rc;
1131}
1132
1133
1134int shfile_ioctl(shfdtab *pfdtab, int fd, unsigned long request, void *buf)
1135{
1136 int rc;
1137
1138#ifdef SH_PURE_STUB_MODE
1139 rc = -1;
1140
1141#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1142# ifdef _MSC_VER
1143 errno = ENOSYS;
1144 rc = -1;
1145# else
1146 rc = ioctl(fd, request, buf);
1147# endif
1148
1149#else
1150#endif
1151
1152 TRACE2((NULL, "ioctl(%d, %#x, %p) -> %d\n", fd, request, buf, rc));
1153 return rc;
1154}
1155
1156
1157mode_t shfile_get_umask(shfdtab *pfdtab)
1158{
1159#ifdef SH_PURE_STUB_MODE
1160 return 022;
1161
1162#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1163 return 022;
1164
1165#else
1166#endif
1167}
1168
1169void shfile_set_umask(shfdtab *pfdtab, mode_t mask)
1170{
1171 (void)mask;
1172}
1173
1174
1175shdir *shfile_opendir(shfdtab *pfdtab, const char *dir)
1176{
1177#ifdef SH_PURE_STUB_MODE
1178 return NULL;
1179
1180#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1181# ifdef _MSC_VER
1182 errno = ENOSYS;
1183 return NULL;
1184# else
1185 return (shdir *)opendir(dir);
1186# endif
1187
1188#else
1189#endif
1190}
1191
1192shdirent *shfile_readdir(struct shdir *pdir)
1193{
1194#ifdef SH_PURE_STUB_MODE
1195 return NULL;
1196
1197#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1198# ifdef _MSC_VER
1199 errno = ENOSYS;
1200 return NULL;
1201# else
1202 struct dirent *pde = readdir((DIR *)pdir);
1203 return pde ? (shdirent *)&pde->d_name[0] : NULL;
1204# endif
1205
1206#else
1207#endif
1208}
1209
1210void shfile_closedir(struct shdir *pdir)
1211{
1212#ifdef SH_PURE_STUB_MODE
1213 return NULL;
1214
1215#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
1216# ifdef _MSC_VER
1217 errno = ENOSYS;
1218# else
1219 closedir((DIR *)pdir);
1220# endif
1221
1222#else
1223#endif
1224}
Note: See TracBrowser for help on using the repository browser.