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

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

kash: no return indicators that works for both gcc and msc (not pretty, but wtf).

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