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

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

kash: eliminating warnings (gcc/darwin).

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 40.4 KB
Line 
1/* $Id: shfile.c 2312 2009-03-02 01:14:43Z 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_FORKED_MODE)
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#if K_OS == K_OS_WINDOWS
77 /* See msdos.h for description. */
78# define FOPEN 0x01
79# define FEOFLAG 0x02
80# define FCRLF 0x04
81# define FPIPE 0x08
82# define FNOINHERIT 0x10
83# define FAPPEND 0x20
84# define FDEV 0x40
85# define FTEXT 0x80
86
87# define MY_ObjectBasicInformation 0
88typedef LONG (NTAPI * PFN_NtQueryObject)(HANDLE, int, void *, size_t, size_t *);
89
90typedef struct MY_OBJECT_BASIC_INFORMATION
91{
92 ULONG Attributes;
93 ACCESS_MASK GrantedAccess;
94 ULONG HandleCount;
95 ULONG PointerCount;
96 ULONG PagedPoolUsage;
97 ULONG NonPagedPoolUsage;
98 ULONG Reserved[3];
99 ULONG NameInformationLength;
100 ULONG TypeInformationLength;
101 ULONG SecurityDescriptorLength;
102 LARGE_INTEGER CreateTime;
103} MY_OBJECT_BASIC_INFORMATION;
104
105#endif /* K_OS_WINDOWS */
106
107
108#ifdef SHFILE_IN_USE
109
110/**
111 * Close the specified native handle.
112 *
113 * @param native The native file handle.
114 * @param flags The flags in case they might come in handy later.
115 */
116static void shfile_native_close(intptr_t native, unsigned flags)
117{
118#if K_OS == K_OS_WINDOWS
119 BOOL fRc = CloseHandle((HANDLE)native);
120 assert(fRc); (void)fRc;
121#else
122 int s = errno;
123 close(native);
124 errno = s;
125#endif
126 (void)flags;
127}
128
129/**
130 * Inserts the file into the descriptor table.
131 *
132 * If we're out of memory and cannot extend the table, we'll close the
133 * file, set errno to EMFILE and return -1.
134 *
135 * @returns The file descriptor number. -1 and errno on failure.
136 * @param pfdtab The file descriptor table.
137 * @param native The native file handle.
138 * @param oflags The flags the it was opened/created with.
139 * @param shflags The shell file flags.
140 * @param fdMin The minimum file descriptor number, pass -1 if any is ok.
141 * @param who Who we're doing this for (for logging purposes).
142 */
143static int shfile_insert(shfdtab *pfdtab, intptr_t native, unsigned oflags, unsigned shflags, int fdMin, const char *who)
144{
145 shmtxtmp tmp;
146 int fd;
147 int i;
148
149 /*
150 * Fend of bad stuff.
151 */
152 if (fdMin >= SHFILE_MAX)
153 {
154 errno = EMFILE;
155 return -1;
156 }
157
158 shmtx_enter(&pfdtab->mtx, &tmp);
159
160 /*
161 * Search for a fitting unused location.
162 */
163 fd = -1;
164 for (i = 0; (unsigned)i < pfdtab->size; i++)
165 if ( i >= fdMin
166 && pfdtab->tab[i].fd == -1)
167 {
168 fd = i;
169 break;
170 }
171 if (fd == -1)
172 {
173 /*
174 * Grow the descriptor table.
175 */
176 shfile *new_tab;
177 int new_size = pfdtab->size + SHFILE_GROW;
178 while (new_size < fdMin)
179 new_size += SHFILE_GROW;
180 new_tab = sh_realloc(shthread_get_shell(), pfdtab->tab, new_size * sizeof(shfile));
181 if (new_tab)
182 {
183 for (i = pfdtab->size; i < new_size; i++)
184 {
185 new_tab[i].fd = -1;
186 new_tab[i].oflags = 0;
187 new_tab[i].shflags = 0;
188 new_tab[i].native = -1;
189 }
190
191 fd = pfdtab->size;
192 if (fd < fdMin)
193 fd = fdMin;
194
195 pfdtab->tab = new_tab;
196 pfdtab->size = new_size;
197 }
198 }
199
200 /*
201 * Fill in the entry if we've found one.
202 */
203 if (fd != -1)
204 {
205 pfdtab->tab[fd].fd = fd;
206 pfdtab->tab[fd].oflags = oflags;
207 pfdtab->tab[fd].shflags = shflags;
208 pfdtab->tab[fd].native = native;
209 }
210 else
211 shfile_native_close(native, oflags);
212
213 shmtx_leave(&pfdtab->mtx, &tmp);
214
215 if (fd == -1)
216 errno = EMFILE;
217 (void)who;
218 return fd;
219}
220
221/**
222 * Gets a file descriptor and lock the file descriptor table.
223 *
224 * @returns Pointer to the file and table ownership on success,
225 * NULL and errno set to EBADF on failure.
226 * @param pfdtab The file descriptor table.
227 * @param fd The file descriptor number.
228 * @param ptmp See shmtx_enter.
229 */
230static shfile *shfile_get(shfdtab *pfdtab, int fd, shmtxtmp *ptmp)
231{
232 shfile *file = NULL;
233 if ( fd >= 0
234 && (unsigned)fd < pfdtab->size)
235 {
236 shmtx_enter(&pfdtab->mtx, ptmp);
237 if ((unsigned)fd < pfdtab->size
238 && pfdtab->tab[fd].fd != -1)
239 file = &pfdtab->tab[fd];
240 else
241 shmtx_leave(&pfdtab->mtx, ptmp);
242 }
243 if (!file)
244 errno = EBADF;
245 return file;
246}
247
248/**
249 * Puts back a file descriptor and releases the table ownership.
250 *
251 * @param pfdtab The file descriptor table.
252 * @param file The file.
253 * @param ptmp See shmtx_leave.
254 */
255static void shfile_put(shfdtab *pfdtab, shfile *file, shmtxtmp *ptmp)
256{
257 shmtx_leave(&pfdtab->mtx, ptmp);
258 assert(file);
259 (void)file;
260}
261
262/**
263 * Constructs a path from the current directory and the passed in path.
264 *
265 * @returns 0 on success, -1 and errno set to ENAMETOOLONG or EINVAL on failure.
266 *
267 * @param pfdtab The file descriptor table
268 * @param path The path the caller supplied.
269 * @param buf Where to put the path. This is assumed to be SHFILE_MAX_PATH
270 * chars in size.
271 */
272int shfile_make_path(shfdtab *pfdtab, const char *path, char *buf)
273{
274 size_t path_len = strlen(path);
275 if (path_len == 0)
276 {
277 errno = EINVAL;
278 return -1;
279 }
280 if (path_len >= SHFILE_MAX_PATH)
281 {
282 errno = ENAMETOOLONG;
283 return -1;
284 }
285 if ( *path == '/'
286#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
287 || *path == '\\'
288 || ( *path
289 && path[1] == ':'
290 && ( (*path >= 'A' && *path <= 'Z')
291 || (*path >= 'a' && *path <= 'z')))
292#endif
293 )
294 {
295 memcpy(buf, path, path_len + 1);
296 }
297 else
298 {
299 size_t cwd_len;
300 shmtxtmp tmp;
301
302 shmtx_enter(&pfdtab->mtx, &tmp);
303
304 cwd_len = strlen(pfdtab->cwd);
305 memcpy(buf, pfdtab->cwd, cwd_len);
306
307 shmtx_leave(&pfdtab->mtx, &tmp);
308
309 if (cwd_len + path_len + 1 >= SHFILE_MAX_PATH)
310 {
311 errno = ENAMETOOLONG;
312 return -1;
313 }
314 if ( !cwd_len
315 || buf[cwd_len - 1] != '/')
316 buf[cwd_len++] = '/';
317 memcpy(buf + cwd_len, path, path_len + 1);
318 }
319
320#if K_OS == K_OS_WINDOWS || K_OS == K_OS_OS2
321 if (!strcmp(buf, "/dev/null"))
322 strcpy(buf, "NUL");
323#endif
324 return 0;
325}
326
327# if K_OS == K_OS_WINDOWS
328
329/**
330 * Converts a DOS(/Windows) error code to errno,
331 * assigning it to errno.
332 *
333 * @returns -1
334 * @param err The DOS error.
335 */
336static int shfile_dos2errno(int err)
337{
338 switch (err)
339 {
340 case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break;
341 case ERROR_ACCESS_DENIED: errno = EACCES; break;
342 case ERROR_CURRENT_DIRECTORY: errno = EACCES; break;
343 case ERROR_LOCK_VIOLATION: errno = EACCES; break;
344 case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break;
345 case ERROR_CANNOT_MAKE: errno = EACCES; break;
346 case ERROR_FAIL_I24: errno = EACCES; break;
347 case ERROR_DRIVE_LOCKED: errno = EACCES; break;
348 case ERROR_SEEK_ON_DEVICE: errno = EACCES; break;
349 case ERROR_NOT_LOCKED: errno = EACCES; break;
350 case ERROR_LOCK_FAILED: errno = EACCES; break;
351 case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break;
352 case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break;
353 case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break;
354 case ERROR_INVALID_HANDLE: errno = EBADF; break;
355 case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break;
356 case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break;
357 case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break;
358 case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break;
359 case ERROR_FILE_EXISTS: errno = EEXIST; break;
360 case ERROR_ALREADY_EXISTS: errno = EEXIST; break;
361 case ERROR_INVALID_FUNCTION: errno = EINVAL; break;
362 case ERROR_INVALID_ACCESS: errno = EINVAL; break;
363 case ERROR_INVALID_DATA: errno = EINVAL; break;
364 case ERROR_INVALID_PARAMETER: errno = EINVAL; break;
365 case ERROR_NEGATIVE_SEEK: errno = EINVAL; break;
366 case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break;
367 case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
368 case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
369 case ERROR_INVALID_DRIVE: errno = ENOENT; break;
370 case ERROR_NO_MORE_FILES: errno = ENOENT; break;
371 case ERROR_BAD_NETPATH: errno = ENOENT; break;
372 case ERROR_BAD_NET_NAME: errno = ENOENT; break;
373 case ERROR_BAD_PATHNAME: errno = ENOENT; break;
374 case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break;
375 case ERROR_BAD_FORMAT: errno = ENOEXEC; break;
376 case ERROR_ARENA_TRASHED: errno = ENOMEM; break;
377 case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break;
378 case ERROR_INVALID_BLOCK: errno = ENOMEM; break;
379 case ERROR_NOT_ENOUGH_QUOTA: errno = ENOMEM; break;
380 case ERROR_DISK_FULL: errno = ENOSPC; break;
381 case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break;
382 case ERROR_BROKEN_PIPE: errno = EPIPE; break;
383 case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break;
384 default: errno = EINVAL; break;
385 }
386 return -1;
387}
388
389DWORD shfile_query_handle_access_mask(HANDLE h, PACCESS_MASK pMask)
390{
391 static PFN_NtQueryObject s_pfnNtQueryObject = NULL;
392 MY_OBJECT_BASIC_INFORMATION BasicInfo;
393 LONG Status;
394
395 if (!s_pfnNtQueryObject)
396 {
397 s_pfnNtQueryObject = (PFN_NtQueryObject)GetProcAddress(GetModuleHandle("NTDLL"), "NtQueryObject");
398 if (!s_pfnNtQueryObject)
399 return ERROR_NOT_SUPPORTED;
400 }
401
402 Status = s_pfnNtQueryObject(h, MY_ObjectBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
403 if (Status >= 0)
404 {
405 *pMask = BasicInfo.GrantedAccess;
406 return NO_ERROR;
407 }
408 if (Status != STATUS_INVALID_HANDLE)
409 return ERROR_GEN_FAILURE;
410 return ERROR_INVALID_HANDLE;
411}
412
413# endif /* K_OS == K_OS_WINDOWS */
414
415#endif /* SHFILE_IN_USE */
416
417/**
418 * Initializes a file descriptor table.
419 *
420 * @returns 0 on success, -1 and errno on failure.
421 * @param pfdtab The table to initialize.
422 * @param inherit File descriptor table to inherit from. If not specified
423 * we will inherit from the current process as it were.
424 */
425int shfile_init(shfdtab *pfdtab, shfdtab *inherit)
426{
427 int rc;
428
429 pfdtab->cwd = NULL;
430 pfdtab->size = 0;
431 pfdtab->tab = NULL;
432 rc = shmtx_init(&pfdtab->mtx);
433 if (!rc)
434 {
435#ifdef SHFILE_IN_USE
436 char buf[SHFILE_MAX_PATH];
437 if (getcwd(buf, sizeof(buf)))
438 {
439 pfdtab->cwd = sh_strdup(NULL, buf);
440 if (!inherit)
441 {
442# if K_OS == K_OS_WINDOWS
443 static const struct
444 {
445 DWORD dwStdHandle;
446 unsigned fFlags;
447 } aStdHandles[3] =
448 {
449 { STD_INPUT_HANDLE, _O_RDONLY },
450 { STD_OUTPUT_HANDLE, _O_WRONLY },
451 { STD_ERROR_HANDLE, _O_WRONLY }
452 };
453 int i;
454 STARTUPINFO Info;
455 ACCESS_MASK Mask;
456 DWORD dwErr;
457
458 rc = 0;
459
460 /* Try pick up the Visual C++ CRT file descriptor info. */
461 __try {
462 GetStartupInfo(&Info);
463 } __except (EXCEPTION_EXECUTE_HANDLER) {
464 memset(&Info, 0, sizeof(Info));
465 }
466
467 if ( Info.cbReserved2 > sizeof(int)
468 && (uintptr_t)Info.lpReserved2 >= 0x1000
469 && (i = *(int *)Info.lpReserved2) >= 1
470 && i <= 2048
471 && ( Info.cbReserved2 == i * 5 + 4
472 //|| Info.cbReserved2 == i * 5 + 1 - check the cygwin sources.
473 || Info.cbReserved2 == i * 9 + 4))
474 {
475 uint8_t *paf = (uint8_t *)Info.lpReserved2 + sizeof(int);
476 int dwPerH = 1 + (Info.cbReserved2 == i * 9 + 4);
477 DWORD *ph = (DWORD *)(paf + i) + dwPerH * i;
478 HANDLE aStdHandles2[3];
479 int j;
480
481 //if (Info.cbReserved2 == i * 5 + 1) - check the cygwin sources.
482 // i--;
483
484 for (j = 0; j < 3; j++)
485 aStdHandles2[j] = GetStdHandle(aStdHandles[j].dwStdHandle);
486
487 while (i-- > 0)
488 {
489 ph -= dwPerH;
490
491 if ( (paf[i] & (FOPEN | FNOINHERIT)) == FOPEN
492 && *ph != (uint32_t)INVALID_HANDLE_VALUE)
493 {
494 HANDLE h = (HANDLE)(intptr_t)*ph;
495 int fd2;
496 int fFlags;
497 int fFlags2;
498
499 if ( h == aStdHandles2[j = 0]
500 || h == aStdHandles2[j = 1]
501 || h == aStdHandles2[j = 2])
502 fFlags = aStdHandles[j].fFlags;
503 else
504 {
505 dwErr = shfile_query_handle_access_mask(h, &Mask);
506 if (dwErr == ERROR_INVALID_HANDLE)
507 continue;
508 else if (dwErr == NO_ERROR)
509 {
510 fFlags = 0;
511 if ( (Mask & (GENERIC_READ | FILE_READ_DATA))
512 && (Mask & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)))
513 fFlags |= O_RDWR;
514 else if (Mask & (GENERIC_READ | FILE_READ_DATA))
515 fFlags |= O_RDONLY;
516 else if (Mask & (GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA))
517 fFlags |= O_WRONLY;
518 else
519 fFlags |= O_RDWR;
520 if ((Mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) == FILE_APPEND_DATA)
521 fFlags |= O_APPEND;
522 }
523 else
524 fFlags = O_RDWR;
525 }
526
527 if (paf[i] & FPIPE)
528 fFlags2 = SHFILE_FLAGS_PIPE;
529 else if (paf[i] & FDEV)
530 fFlags2 = SHFILE_FLAGS_TTY;
531 else
532 fFlags2 = 0;
533
534 fd2 = shfile_insert(pfdtab, (intptr_t)h, fFlags, fFlags2, i, "shtab_init");
535 assert(fd2 == i); (void)fd2;
536 if (fd2 != i)
537 rc = -1;
538 }
539 }
540 }
541
542 /* Check the three standard handles. */
543 for (i = 0; i < 3; i++)
544 if ( (unsigned)i >= pfdtab->size
545 || pfdtab->tab[i].fd == -1)
546 {
547 HANDLE hFile = GetStdHandle(aStdHandles[i].dwStdHandle);
548 if (hFile != INVALID_HANDLE_VALUE)
549 {
550 int fd2 = shfile_insert(pfdtab, (intptr_t)hFile, aStdHandles[i].fFlags, 0, i, "shtab_init");
551 assert(fd2 == i); (void)fd2;
552 if (fd2 != i)
553 rc = -1;
554 }
555 }
556# else
557# endif
558 }
559 else
560 {
561 /** @todo */
562 errno = ENOSYS;
563 rc = -1;
564 }
565 }
566 else
567 rc = -1;
568#endif
569 }
570 return rc;
571}
572
573#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE)
574
575/**
576 * Helper for shfork.
577 *
578 * @param pfdtab The file descriptor table.
579 * @param set Whether to make all handles inheritable (1) or
580 * to restore them to the rigth state (0).
581 * @param hndls Where to store the three standard handles.
582 */
583void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls)
584{
585 shmtxtmp tmp;
586 unsigned i;
587 DWORD fFlag = set ? HANDLE_FLAG_INHERIT : 0;
588
589 shmtx_enter(&pfdtab->mtx, &tmp);
590 TRACE2((NULL, "shfile_fork_win:\n"));
591
592 i = pfdtab->size;
593 while (i-- > 0)
594 {
595 if (pfdtab->tab[i].fd == i)
596 {
597 HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
598 if (set)
599 TRACE2((NULL, " #%d: native=%#x oflags=%#x shflags=%#x\n",
600 i, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags, hFile));
601 if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, fFlag))
602 {
603 DWORD err = GetLastError();
604 assert(0);
605 }
606 }
607 }
608
609 if (hndls)
610 {
611 for (i = 0; i < 3; i++)
612 {
613 if ( pfdtab->size > i
614 && pfdtab->tab[i].fd == 0)
615 hndls[i] = pfdtab->tab[i].native;
616 else
617 hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
618 }
619 }
620
621 shmtx_leave(&pfdtab->mtx, &tmp);
622}
623
624/**
625 * Helper for sh_execve.
626 *
627 * This is called before and after CreateProcess. On the first call it
628 * will mark the non-close-on-exec handles as inheritable and produce
629 * the startup info for the CRT. On the second call, after CreateProcess,
630 * it will restore the handle inheritability properties.
631 *
632 * @returns Pointer to CRT data if prepare is 1, NULL if prepare is 0.
633 * @param pfdtab The file descriptor table.
634 * @param prepare Which call, 1 if before and 0 if after.
635 * @param sizep Where to store the size of the returned data.
636 * @param hndls Where to store the three standard handles.
637 */
638void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls)
639{
640 void *pvRet;
641 shmtxtmp tmp;
642 unsigned count;
643 unsigned i;
644
645 shmtx_enter(&pfdtab->mtx, &tmp);
646 TRACE2((NULL, "shfile_fork_win:\n"));
647
648 count = pfdtab->size < (0x10000-4) / (1 + sizeof(HANDLE))
649 ? pfdtab->size
650 : (0x10000-4) / (1 + sizeof(HANDLE));
651 while (count > 3 && pfdtab->tab[count].fd == -1)
652 count--;
653
654 if (prepare)
655 {
656 size_t cbData = sizeof(int) + count * (1 + sizeof(HANDLE));
657 uint8_t *pbData = sh_malloc(shthread_get_shell(), cbData);
658 uint8_t *paf = pbData + sizeof(int);
659 HANDLE *pah = (HANDLE *)(paf + count);
660
661 *(int *)pbData = count;
662
663 i = count;
664 while (i-- > 0)
665 {
666 if ( pfdtab->tab[i].fd == i
667 && !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC))
668 {
669 HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
670 TRACE2((NULL, " #%d: native=%#x oflags=%#x shflags=%#x\n",
671 i, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags, hFile));
672
673 if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
674 {
675 DWORD err = GetLastError();
676 assert(0);
677 }
678 paf[i] = FOPEN;
679 if (pfdtab->tab[i].oflags & _O_APPEND)
680 paf[i] |= FAPPEND;
681 if (pfdtab->tab[i].oflags & _O_TEXT)
682 paf[i] |= FTEXT;
683 switch (pfdtab->tab[i].shflags & SHFILE_FLAGS_TYPE_MASK)
684 {
685 case SHFILE_FLAGS_TTY: paf[i] |= FDEV; break;
686 case SHFILE_FLAGS_PIPE: paf[i] |= FPIPE; break;
687 }
688 pah[i] = hFile;
689 }
690 else
691 {
692 paf[i] = 0;
693 pah[i] = INVALID_HANDLE_VALUE;
694 }
695 }
696
697 for (i = 0; i < 3; i++)
698 {
699 if ( count > i
700 && pfdtab->tab[i].fd == 0)
701 hndls[i] = pfdtab->tab[i].native;
702 else
703 hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
704 }
705
706 *sizep = (unsigned short)cbData;
707 pvRet = pbData;
708 }
709 else
710 {
711 assert(!hndls);
712 assert(!sizep);
713 i = count;
714 while (i-- > 0)
715 {
716 if ( pfdtab->tab[i].fd == i
717 && !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC))
718 {
719 HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
720 if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, 0))
721 {
722 DWORD err = GetLastError();
723 assert(0);
724 }
725 }
726 }
727 pvRet = NULL;
728 }
729
730 shmtx_leave(&pfdtab->mtx, &tmp);
731 return pvRet;
732}
733
734#endif /* K_OS_WINDOWS */
735
736
737/**
738 * open().
739 */
740int shfile_open(shfdtab *pfdtab, const char *name, unsigned flags, mode_t mode)
741{
742 int fd;
743#ifdef SHFILE_IN_USE
744 char absname[SHFILE_MAX_PATH];
745# if K_OS == K_OS_WINDOWS
746 HANDLE hFile;
747 DWORD dwDesiredAccess;
748 DWORD dwShareMode;
749 DWORD dwCreationDisposition;
750 DWORD dwFlagsAndAttributes;
751 SECURITY_ATTRIBUTES SecurityAttributes;
752
753# ifndef _O_ACCMODE
754# define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR)
755# endif
756 switch (flags & (_O_ACCMODE | _O_APPEND))
757 {
758 case _O_RDONLY: dwDesiredAccess = GENERIC_READ; break;
759 case _O_RDONLY | _O_APPEND: dwDesiredAccess = GENERIC_READ; break;
760 case _O_WRONLY: dwDesiredAccess = GENERIC_WRITE; break;
761 case _O_WRONLY | _O_APPEND: dwDesiredAccess = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break;
762 case _O_RDWR: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; break;
763 case _O_RDWR | _O_APPEND: dwDesiredAccess = GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); break;
764
765 default:
766 RETURN_ERROR(-1, EINVAL, "invalid mode");
767 }
768
769 dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
770
771 SecurityAttributes.nLength = sizeof(SecurityAttributes);
772 SecurityAttributes.lpSecurityDescriptor = NULL;
773 SecurityAttributes.bInheritHandle = FALSE;
774
775 if (flags & _O_CREAT)
776 {
777 if ((flags & (_O_EXCL | _O_TRUNC)) == (_O_EXCL | _O_TRUNC))
778 RETURN_ERROR(-1, EINVAL, "_O_EXCL | _O_TRUNC");
779
780 if (flags & _O_TRUNC)
781 dwCreationDisposition = CREATE_ALWAYS; /* not 100%, but close enough */
782 else if (flags & _O_EXCL)
783 dwCreationDisposition = CREATE_NEW;
784 else
785 dwCreationDisposition = OPEN_ALWAYS;
786 }
787 else if (flags & _O_TRUNC)
788 dwCreationDisposition = TRUNCATE_EXISTING;
789 else
790 dwCreationDisposition = OPEN_EXISTING;
791
792 if (!(flags & _O_CREAT) || (mode & 0222))
793 dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
794 else
795 dwFlagsAndAttributes = FILE_ATTRIBUTE_READONLY;
796
797 fd = shfile_make_path(pfdtab, name, &absname[0]);
798 if (!fd)
799 {
800 SetLastError(0);
801 hFile = CreateFileA(absname,
802 dwDesiredAccess,
803 dwShareMode,
804 &SecurityAttributes,
805 dwCreationDisposition,
806 dwFlagsAndAttributes,
807 NULL /* hTemplateFile */);
808 if (hFile != INVALID_HANDLE_VALUE)
809 fd = shfile_insert(pfdtab, (intptr_t)hFile, flags, 0, -1, "shfile_open");
810 else
811 fd = shfile_dos2errno(GetLastError());
812 }
813
814# else /* K_OS != K_OS_WINDOWS */
815 fd = shfile_make_path(pfdtab, name, &absname[0]);
816 if (!fd)
817 {
818 fd = open(absname, flag, mode);
819 if (fd != -1)
820 {
821 int native = fcntl(fd, F_DUPFD, SHFILE_UNIX_MIN_FD);
822 int s = errno;
823 close(fd);
824 errno = s;
825 if (native != -1)
826 fd = shfile_insert(pfdtab, native, flags, 0, -1, "shfile_open");
827 else
828 fd = -1;
829 }
830 }
831
832# endif /* K_OS != K_OS_WINDOWS */
833
834#else
835 fd = open(name, flags, mode);
836#endif
837
838 TRACE2((NULL, "shfile_open(%p:{%s}, %#x, 0%o) -> %d [%d]\n", name, name, flags, mode, fd, errno));
839 return fd;
840}
841
842int shfile_pipe(shfdtab *pfdtab, int fds[2])
843{
844 int rc;
845#ifdef SHFILE_IN_USE
846# if K_OS == K_OS_WINDOWS
847 HANDLE hRead = INVALID_HANDLE_VALUE;
848 HANDLE hWrite = INVALID_HANDLE_VALUE;
849 SECURITY_ATTRIBUTES SecurityAttributes;
850
851 SecurityAttributes.nLength = sizeof(SecurityAttributes);
852 SecurityAttributes.lpSecurityDescriptor = NULL;
853 SecurityAttributes.bInheritHandle = FALSE;
854
855 fds[1] = fds[0] = -1;
856 if (CreatePipe(&hRead, &hWrite, &SecurityAttributes, 4096))
857 {
858 fds[0] = shfile_insert(pfdtab, (intptr_t)hRead, O_RDONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe");
859 if (fds[0] != -1)
860 {
861 fds[1] = shfile_insert(pfdtab, (intptr_t)hWrite, O_WRONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe");
862 if (fds[1] != -1)
863 rc = 0;
864 }
865
866# else
867 int native_fds[2];
868
869 fds[1] = fds[0] = -1;
870 if (!pipe(native_fds))
871 {
872 fds[0] = shfile_insert(pfdtab, native_fds[0], O_RDONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe");
873 if (fds[0] != -1)
874 {
875 fds[1] = shfile_insert(pfdtab, native_fds[1], O_WRONLY, SHFILE_FLAGS_PIPE, -1, "shfile_pipe");
876 if (fds[1] != -1)
877 rc = 0;
878 }
879# endif
880 if (fds[1] == -1)
881 {
882 int s = errno;
883 if (fds[0] != -1)
884 {
885 shmtxtmp tmp;
886 shmtx_enter(&pfdtab->mtx, &tmp);
887 rc = fds[0];
888 pfdtab->tab[rc].fd = -1;
889 pfdtab->tab[rc].oflags = 0;
890 pfdtab->tab[rc].shflags = 0;
891 pfdtab->tab[rc].native = -1;
892 shmtx_leave(&pfdtab->mtx, &tmp);
893 }
894
895# if K_OS == K_OS_WINDOWS
896 CloseHandle(hRead);
897 CloseHandle(hWrite);
898# else
899 close(native_fds[0]);
900 close(native_fds[1]);
901# endif
902 fds[0] = fds[1] = -1;
903 errno = s;
904 rc = -1;
905 }
906 }
907 else
908 {
909# if K_OS == K_OS_WINDOWS
910 errno = shfile_dos2errno(GetLastError());
911# endif
912 rc = -1;
913 }
914
915#else
916 rc = pipe(fds);
917#endif
918
919 TRACE2((NULL, "shfile_pipe() -> %d{%d,%d} [%d]\n", rc, fds[0], fds[1], errno));
920 return rc;
921}
922
923/**
924 * dup().
925 */
926int shfile_dup(shfdtab *pfdtab, int fd)
927{
928 return shfile_fcntl(pfdtab,fd, F_DUPFD, 0);
929}
930
931/**
932 * close().
933 */
934int shfile_close(shfdtab *pfdtab, unsigned fd)
935{
936 int rc;
937#ifdef SHFILE_IN_USE
938 shmtxtmp tmp;
939 shfile *file = shfile_get(pfdtab, fd, &tmp);
940 if (file)
941 {
942 shfile_native_close(file->native, file->oflags);
943
944 file->fd = -1;
945 file->oflags = 0;
946 file->shflags = 0;
947 file->native = -1;
948
949 shfile_put(pfdtab, file, &tmp);
950 rc = 0;
951 }
952 else
953 rc = -1;
954
955#else
956 rc = close(fd);
957#endif
958
959 TRACE2((NULL, "shfile_close(%d) -> %d [%d]\n", fd, rc, errno));
960 return rc;
961}
962
963/**
964 * read().
965 */
966long shfile_read(shfdtab *pfdtab, int fd, void *buf, size_t len)
967{
968 long rc;
969#ifdef SHFILE_IN_USE
970 shmtxtmp tmp;
971 shfile *file = shfile_get(pfdtab, fd, &tmp);
972 if (file)
973 {
974# if K_OS == K_OS_WINDOWS
975 DWORD dwRead = 0;
976 if (ReadFile((HANDLE)file->native, buf, (DWORD)len, &dwRead, NULL))
977 rc = dwRead;
978 else
979 rc = shfile_dos2errno(GetLastError());
980# else
981 rc = read(file->native, buf, len);
982# endif
983
984 shfile_put(pfdtab, file, &tmp);
985 }
986 else
987 rc = -1;
988
989#else
990 rc = read(fd, buf, len);
991#endif
992 return rc;
993}
994
995/**
996 * write().
997 */
998long shfile_write(shfdtab *pfdtab, int fd, const void *buf, size_t len)
999{
1000 long rc;
1001#ifdef SHFILE_IN_USE
1002 shmtxtmp tmp;
1003 shfile *file = shfile_get(pfdtab, fd, &tmp);
1004 if (file)
1005 {
1006# if K_OS == K_OS_WINDOWS
1007 DWORD dwWritten = 0;
1008 if (WriteFile((HANDLE)file->native, buf, (DWORD)len, &dwWritten, NULL))
1009 rc = dwWritten;
1010 else
1011 rc = shfile_dos2errno(GetLastError());
1012# else
1013 rc = write(file->native, buf, len);
1014# endif
1015
1016 shfile_put(pfdtab, file, &tmp);
1017 }
1018 else
1019 rc = -1;
1020
1021#else
1022 rc = write(fd, buf, len);
1023#endif
1024 return rc;
1025}
1026
1027/**
1028 * lseek().
1029 */
1030long shfile_lseek(shfdtab *pfdtab, int fd, long off, int whench)
1031{
1032 long rc;
1033#ifdef SHFILE_IN_USE
1034 shmtxtmp tmp;
1035 shfile *file = shfile_get(pfdtab, fd, &tmp);
1036 if (file)
1037 {
1038# if K_OS == K_OS_WINDOWS
1039 assert(SEEK_SET == FILE_BEGIN);
1040 assert(SEEK_CUR == FILE_CURRENT);
1041 assert(SEEK_END == FILE_END);
1042 rc = SetFilePointer((HANDLE)file->native, off, NULL, whench);
1043 if (rc == INVALID_SET_FILE_POINTER)
1044 rc = shfile_dos2errno(GetLastError());
1045# else
1046 rc = lseek(file->native, off, whench);
1047# endif
1048
1049 shfile_put(pfdtab, file, &tmp);
1050 }
1051 else
1052 rc = -1;
1053
1054#else
1055 rc = lseek(fd, off, whench);
1056#endif
1057
1058 return rc;
1059}
1060
1061int shfile_fcntl(shfdtab *pfdtab, int fd, int cmd, int arg)
1062{
1063 int rc;
1064#ifdef SHFILE_IN_USE
1065 shmtxtmp tmp;
1066 shfile *file = shfile_get(pfdtab, fd, &tmp);
1067 if (file)
1068 {
1069 switch (cmd)
1070 {
1071 case F_GETFL:
1072 rc = file->oflags;
1073 break;
1074
1075 case F_SETFL:
1076 {
1077 unsigned mask = O_NONBLOCK | O_APPEND | O_BINARY | O_TEXT;
1078# ifdef O_DIRECT
1079 mask |= O_DIRECT;
1080# endif
1081# ifdef O_ASYNC
1082 mask |= O_ASYNC;
1083# endif
1084# ifdef O_SYNC
1085 mask |= O_SYNC;
1086# endif
1087 if ((file->oflags & mask) == (arg & mask))
1088 rc = 0;
1089 else
1090 {
1091# if K_OS == K_OS_WINDOWS
1092 assert(0);
1093 errno = EINVAL;
1094 rc = -1;
1095# else
1096 rc = fcntl(file->native, F_SETFL, arg);
1097 if (rc != -1)
1098 file->flags = (file->flags & ~mask) | (arg & mask);
1099# endif
1100 }
1101 break;
1102 }
1103
1104 case F_DUPFD:
1105 {
1106# if K_OS == K_OS_WINDOWS
1107 HANDLE hNew = INVALID_HANDLE_VALUE;
1108 if (DuplicateHandle(GetCurrentProcess(),
1109 (HANDLE)file->native,
1110 GetCurrentProcess(),
1111 &hNew,
1112 0,
1113 FALSE /* bInheritHandle */,
1114 DUPLICATE_SAME_ACCESS))
1115 rc = shfile_insert(pfdtab, (intptr_t)hNew, file->oflags, file->shflags, arg, "shfile_fcntl");
1116 else
1117 rc = shfile_dos2errno(GetLastError());
1118# else
1119 int nativeNew = fcntl(file->native F_DUPFD, SHFILE_UNIX_MIN_FD);
1120 if (nativeNew != -1)
1121 rc = shfile_insert(pfdtab, nativeNew, file->oflags, file->shflags, arg, "shfile_fcntl");
1122# endif
1123 break;
1124 }
1125
1126 default:
1127 errno = -EINVAL;
1128 rc = -1;
1129 break;
1130 }
1131
1132 shfile_put(pfdtab, file, &tmp);
1133 }
1134 else
1135 rc = -1;
1136
1137#else
1138 rc = fcntl(fd, cmd, arg);
1139#endif
1140
1141 switch (cmd)
1142 {
1143 case F_GETFL: TRACE2((NULL, "shfile_fcntl(%d,F_GETFL,ignored=%d) -> %d [%d]\n", fd, arg, rc, errno)); break;
1144 case F_SETFL: TRACE2((NULL, "shfile_fcntl(%d,F_SETFL,newflags=%#x) -> %d [%d]\n", fd, arg, rc, errno)); break;
1145 case F_DUPFD: TRACE2((NULL, "shfile_fcntl(%d,F_DUPFS,minfd=%d) -> %d [%d]\n", fd, arg, rc, errno)); break;
1146 default: TRACE2((NULL, "shfile_fcntl(%d,%d,%d) -> %d [%d]\n", fd, cmd, arg, rc, errno)); break;
1147 }
1148 return rc;
1149}
1150
1151int shfile_stat(shfdtab *pfdtab, const char *path, struct stat *pst)
1152{
1153#ifdef SHFILE_IN_USE
1154 char abspath[SHFILE_MAX_PATH];
1155 int rc;
1156 rc = shfile_make_path(pfdtab, path, &abspath[0]);
1157 if (!rc)
1158 {
1159# if K_OS == K_OS_WINDOWS
1160 rc = stat(abspath, pst); /** @todo re-implement stat. */
1161# else
1162 rc = stat(abspath, pst);
1163# endif
1164 }
1165 TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno));
1166 return rc;
1167#else
1168 return stat(path, pst);
1169#endif
1170}
1171
1172int shfile_lstat(shfdtab *pfdtab, const char *path, struct stat *pst)
1173{
1174 int rc;
1175#ifdef SHFILE_IN_USE
1176 char abspath[SHFILE_MAX_PATH];
1177
1178 rc = shfile_make_path(pfdtab, path, &abspath[0]);
1179 if (!rc)
1180 {
1181# if K_OS == K_OS_WINDOWS
1182 rc = stat(abspath, pst); /** @todo implement lstat. */
1183# else
1184 rc = lstat(abspath, pst);
1185# endif
1186 }
1187#else
1188 rc = stat(path, pst);
1189#endif
1190 TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno));
1191 return rc;
1192}
1193
1194/**
1195 * chdir().
1196 */
1197int shfile_chdir(shfdtab *pfdtab, const char *path)
1198{
1199 shinstance *psh = shthread_get_shell();
1200 int rc;
1201#ifdef SHFILE_IN_USE
1202 char abspath[SHFILE_MAX_PATH];
1203
1204 rc = shfile_make_path(pfdtab, path, &abspath[0]);
1205 if (!rc)
1206 {
1207 char *abspath_copy = sh_strdup(psh, abspath);
1208 char *free_me = abspath_copy;
1209 rc = chdir(path);
1210 if (!rc)
1211 {
1212 shmtxtmp tmp;
1213 shmtx_enter(&pfdtab->mtx, &tmp);
1214
1215 free_me = pfdtab->cwd;
1216 pfdtab->cwd = abspath_copy;
1217
1218 shmtx_leave(&pfdtab->mtx, &tmp);
1219 }
1220 sh_free(psh, free_me);
1221 }
1222 else
1223 rc = -1;
1224#else
1225 rc = chdir(path);
1226#endif
1227
1228 TRACE2((psh, "shfile_chdir(,%s) -> %d [%d]\n", path, rc, errno));
1229 return rc;
1230}
1231
1232/**
1233 * getcwd().
1234 */
1235char *shfile_getcwd(shfdtab *pfdtab, char *buf, int size)
1236{
1237 char *ret;
1238#ifdef SHFILE_IN_USE
1239
1240 ret = NULL;
1241 if (buf && !size)
1242 errno = -EINVAL;
1243 else
1244 {
1245 size_t cwd_size;
1246 shmtxtmp tmp;
1247 shmtx_enter(&pfdtab->mtx, &tmp);
1248
1249 cwd_size = strlen(pfdtab->cwd) + 1;
1250 if (buf)
1251 {
1252 if (cwd_size <= (size_t)size)
1253 ret = memcpy(buf, pfdtab->cwd, cwd_size);
1254 else
1255 errno = ERANGE;
1256 }
1257 else
1258 {
1259 if (size < cwd_size)
1260 size = (int)cwd_size;
1261 ret = sh_malloc(shthread_get_shell(), size);
1262 if (ret)
1263 ret = memcpy(ret, pfdtab->cwd, cwd_size);
1264 else
1265 errno = ENOMEM;
1266 }
1267
1268 shmtx_leave(&pfdtab->mtx, &tmp);
1269 }
1270#else
1271 ret = getcwd(buf, size);
1272#endif
1273
1274 TRACE2((NULL, "shfile_getcwd(,%p,%d) -> %s [%d]\n", buf, size, ret, errno));
1275 return ret;
1276}
1277
1278/**
1279 * access().
1280 */
1281int shfile_access(shfdtab *pfdtab, const char *path, int type)
1282{
1283 int rc;
1284#ifdef SHFILE_IN_USE
1285 char abspath[SHFILE_MAX_PATH];
1286
1287 rc = shfile_make_path(pfdtab, path, &abspath[0]);
1288 if (!rc)
1289 {
1290# ifdef _MSC_VER
1291 if (type & X_OK)
1292 type = (type & ~X_OK) | R_OK;
1293# endif
1294 rc = access(abspath, type);
1295 }
1296#else
1297# ifdef _MSC_VER
1298 if (type & X_OK)
1299 type = (type & ~X_OK) | R_OK;
1300# endif
1301 rc = access(path, type);
1302#endif
1303
1304 TRACE2((NULL, "shfile_access(,%s,%#x) -> %d [%d]\n", path, type, rc, errno));
1305 return rc;
1306}
1307
1308/**
1309 * isatty()
1310 */
1311int shfile_isatty(shfdtab *pfdtab, int fd)
1312{
1313 int rc;
1314#ifdef SHFILE_IN_USE
1315 shmtxtmp tmp;
1316 shfile *file = shfile_get(pfdtab, fd, &tmp);
1317 if (file)
1318 {
1319# if K_OS == K_OS_WINDOWS
1320 rc = (file->shflags & SHFILE_FLAGS_TYPE_MASK) == SHFILE_FLAGS_TTY;
1321# else
1322 rc = isatty(file->native);
1323# endif
1324 shfile_put(pfdtab, file, &tmp);
1325 }
1326 else
1327 rc = 0;
1328#else
1329 rc = isatty(fd);
1330#endif
1331
1332 TRACE2((NULL, "isatty(%d) -> %d [%d]\n", fd, rc, errno));
1333 return rc;
1334}
1335
1336/**
1337 * fcntl F_SETFD / FD_CLOEXEC.
1338 */
1339int shfile_cloexec(shfdtab *pfdtab, int fd, int closeit)
1340{
1341 int rc;
1342#ifdef SHFILE_IN_USE
1343 shmtxtmp tmp;
1344 shfile *file = shfile_get(pfdtab, fd, &tmp);
1345 if (file)
1346 {
1347 if (closeit)
1348 file->shflags |= SHFILE_FLAGS_CLOSE_ON_EXEC;
1349 else
1350 file->shflags &= ~SHFILE_FLAGS_CLOSE_ON_EXEC;
1351 shfile_put(pfdtab, file, &tmp);
1352 }
1353 else
1354 rc = -1;
1355#else
1356 rc = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0)
1357 | (closeit ? FD_CLOEXEC : 0));
1358#endif
1359
1360 TRACE2((NULL, "shfile_cloexec(%d, %d) -> %d [%d]\n", fd, closeit, rc, errno));
1361 return rc;
1362}
1363
1364
1365int shfile_ioctl(shfdtab *pfdtab, int fd, unsigned long request, void *buf)
1366{
1367 int rc;
1368#ifdef SHFILE_IN_USE
1369 shmtxtmp tmp;
1370 shfile *file = shfile_get(pfdtab, fd, &tmp);
1371 if (file)
1372 {
1373# if K_OS == K_OS_WINDOWS
1374 rc = -1;
1375 errno = ENOSYS;
1376# else
1377 rc = ioctl(file->native, request, buf);
1378# endif
1379 shfile_put(pfdtab, file, &tmp);
1380 }
1381 else
1382 rc = -1;
1383#else
1384 rc = ioctl(fd, request, buf);
1385#endif
1386
1387 TRACE2((NULL, "ioctl(%d, %#x, %p) -> %d\n", fd, request, buf, rc));
1388 return rc;
1389}
1390
1391
1392mode_t shfile_get_umask(shfdtab *pfdtab)
1393{
1394 /** @todo */
1395 return 022;
1396}
1397
1398void shfile_set_umask(shfdtab *pfdtab, mode_t mask)
1399{
1400 /** @todo */
1401 (void)mask;
1402}
1403
1404
1405shdir *shfile_opendir(shfdtab *pfdtab, const char *dir)
1406{
1407#ifdef SHFILE_IN_USE
1408 errno = ENOSYS;
1409 return NULL;
1410#else
1411 return (shdir *)opendir(dir);
1412#endif
1413}
1414
1415shdirent *shfile_readdir(struct shdir *pdir)
1416{
1417#ifdef SHFILE_IN_USE
1418 errno = ENOSYS;
1419 return NULL;
1420#else
1421 struct dirent *pde = readdir((DIR *)pdir);
1422 return pde ? (shdirent *)&pde->d_name[0] : NULL;
1423#endif
1424}
1425
1426void shfile_closedir(struct shdir *pdir)
1427{
1428#ifdef SHFILE_IN_USE
1429 errno = ENOSYS;
1430#else
1431 closedir((DIR *)pdir);
1432#endif
1433}
1434
Note: See TracBrowser for help on using the repository browser.