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

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

kash: Removed the SH_PURE_STUB_MODE code.

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