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

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

kash: avoid file steams in the trace code.

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