lib: c: io: implement standard FILE and DIR interfaces
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#ifndef DIRENT_H_
|
#ifndef DIRENT_H_
|
||||||
#define DIRENT_H_
|
#define DIRENT_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define DT_UNKNOWN 0
|
#define DT_UNKNOWN 0
|
||||||
#define DT_BLK 1
|
#define DT_BLK 1
|
||||||
#define DT_CHR 2
|
#define DT_CHR 2
|
||||||
@@ -10,4 +12,22 @@
|
|||||||
#define DT_REG 6
|
#define DT_REG 6
|
||||||
#define DT_SOCK 7
|
#define DT_SOCK 7
|
||||||
|
|
||||||
|
struct dirent {
|
||||||
|
ino_t d_ino;
|
||||||
|
off_t d_off;
|
||||||
|
unsigned short d_reclen;
|
||||||
|
unsigned char d_type;
|
||||||
|
char d_name[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __opaque_dir;
|
||||||
|
typedef struct __opaque_dir DIR;
|
||||||
|
|
||||||
|
extern DIR *opendir(const char *name);
|
||||||
|
extern DIR *fdopendir(int fd);
|
||||||
|
|
||||||
|
extern int closedir(DIR *dirp);
|
||||||
|
|
||||||
|
extern struct dirent *readdir(DIR *dirp);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,10 +4,15 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define EOF -1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct __opaque_file;
|
||||||
|
typedef struct __opaque_file FILE;
|
||||||
|
|
||||||
extern int snprintf(char *buffer, size_t count, const char *format, ...);
|
extern int snprintf(char *buffer, size_t count, const char *format, ...);
|
||||||
extern int vsnprintf(
|
extern int vsnprintf(
|
||||||
char *buffer,
|
char *buffer,
|
||||||
@@ -15,6 +20,30 @@ extern int vsnprintf(
|
|||||||
const char *format,
|
const char *format,
|
||||||
va_list va);
|
va_list va);
|
||||||
|
|
||||||
|
extern FILE *fopen(const char *path, const char *mode);
|
||||||
|
extern int fclose(FILE *stream);
|
||||||
|
|
||||||
|
extern int feof(FILE *stream);
|
||||||
|
extern int ferr(FILE *stream);
|
||||||
|
|
||||||
|
extern size_t fread(void *buf, size_t size, size_t count, FILE *stream);
|
||||||
|
extern size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream);
|
||||||
|
|
||||||
|
extern int fgetc(FILE *stream);
|
||||||
|
static inline int getc(FILE *stream)
|
||||||
|
{
|
||||||
|
return fgetc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int fputc(int c, FILE *stream);
|
||||||
|
static inline int putc(int c, FILE *stream)
|
||||||
|
{
|
||||||
|
return fputc(c, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char *fgets(char *restrict str, int count, FILE *restrict stream);
|
||||||
|
extern int fputs(const char *restrict str, FILE *restrict stream);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#define SEEK_CUR 1
|
#define SEEK_CUR 1
|
||||||
#define SEEK_END 2
|
#define SEEK_END 2
|
||||||
|
|
||||||
|
typedef size_t ino_t;
|
||||||
|
|
||||||
struct dentry {
|
struct dentry {
|
||||||
unsigned long d_ino;
|
unsigned long d_ino;
|
||||||
unsigned short d_reclen;
|
unsigned short d_reclen;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include "dir.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int closedir(struct __opaque_dir *dirp)
|
||||||
|
{
|
||||||
|
close(dirp->d_fd);
|
||||||
|
|
||||||
|
if (dirp->d_buf) {
|
||||||
|
free(dirp->d_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dirp);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include "dir.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define DEFAULT_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
static void dirent_convert(const struct dentry *in, struct dirent *out)
|
||||||
|
{
|
||||||
|
out->d_ino = in->d_ino;
|
||||||
|
out->d_type = in->d_type;
|
||||||
|
out->d_reclen = in->d_reclen;
|
||||||
|
strncpy(out->d_name, in->d_name, sizeof out->d_name - 1);
|
||||||
|
out->d_name[sizeof out->d_name - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_dir_refill(struct __opaque_dir *d)
|
||||||
|
{
|
||||||
|
if (d->d_fd < 0) {
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->d_flags & DIR_ERR) {
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->d_flags & DIR_EOF) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->d_buf) {
|
||||||
|
d->d_buf_max = DEFAULT_BUFFER_SIZE;
|
||||||
|
d->d_buf = malloc(d->d_buf_max);
|
||||||
|
if (!d->d_buf) {
|
||||||
|
d->d_buf_max = 0;
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long r = getdents(d->d_fd, (struct dentry *)d->d_buf, d->d_buf_max);
|
||||||
|
if (r < 0) {
|
||||||
|
return -r;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->d_buf_datalen = r;
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
struct dentry *dent
|
||||||
|
= (struct dentry *)(d->d_buf + d->d_buf_readptr);
|
||||||
|
dirent_convert(dent, &d->d_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_dir_move_next(struct __opaque_dir *d)
|
||||||
|
{
|
||||||
|
if (d->d_fd < 0) {
|
||||||
|
return -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->d_flags & DIR_ERR) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->d_flags & DIR_EOF) {
|
||||||
|
return -SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->d_buf_readptr += d->d_current.d_reclen;
|
||||||
|
if (d->d_buf_readptr >= d->d_buf_datalen) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dentry *dent = (struct dentry *)(d->d_buf + d->d_buf_readptr);
|
||||||
|
dirent_convert(dent, &d->d_current);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _LIBC_IO_DIR_H_
|
||||||
|
#define _LIBC_IO_DIR_H_
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
enum dir_flags {
|
||||||
|
DIR_EOF = 0x01u,
|
||||||
|
DIR_ERR = 0x02u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __opaque_dir {
|
||||||
|
enum dir_flags d_flags;
|
||||||
|
int d_fd;
|
||||||
|
char *d_buf;
|
||||||
|
struct dirent d_current;
|
||||||
|
size_t d_buf_datalen, d_buf_max;
|
||||||
|
size_t d_buf_readptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int __libc_dir_refill(struct __opaque_dir *d);
|
||||||
|
extern int __libc_dir_move_next(struct __opaque_dir *d);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <mango/log.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int fclose(struct __opaque_file *stream)
|
||||||
|
{
|
||||||
|
if (stream->f_fd < 0) {
|
||||||
|
return __set_errno(EBADF);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(stream->f_fd);
|
||||||
|
|
||||||
|
if (stream->f_buf) {
|
||||||
|
free(stream->f_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stream);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
int feof(struct __opaque_file *stream)
|
||||||
|
{
|
||||||
|
return (stream->f_flags & FILE_EOF) != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
int ferr(struct __opaque_file *stream)
|
||||||
|
{
|
||||||
|
return (stream->f_flags & FILE_ERR) != 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int fgetc(struct __opaque_file *stream)
|
||||||
|
{
|
||||||
|
if (stream->f_flags & (FILE_EOF | FILE_ERR)) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t available = __libc_file_available(stream);
|
||||||
|
if (available == 0) {
|
||||||
|
int err = __libc_file_refill(stream);
|
||||||
|
if (err != SUCCESS) {
|
||||||
|
__set_errno(err);
|
||||||
|
stream->f_flags |= FILE_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
available = __libc_file_available(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available == 0) {
|
||||||
|
stream->f_flags |= FILE_EOF;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = stream->f_buf[stream->f_buf_readptr++];
|
||||||
|
return c;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
char *fgets(
|
||||||
|
char *restrict str,
|
||||||
|
int count,
|
||||||
|
struct __opaque_file *restrict stream)
|
||||||
|
{
|
||||||
|
if (stream->f_flags & (FILE_EOF | FILE_ERR)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
while (1) {
|
||||||
|
int c = fgetc(stream);
|
||||||
|
|
||||||
|
if (c == EOF) {
|
||||||
|
str[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = c;
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
str[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ferr(stream)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feof(stream) && i == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define DEFAULT_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
#define FILE_UNUSABLE(f) (((f)->f_flags & (FILE_EOF | FILE_ERR)) != 0)
|
||||||
|
|
||||||
|
int __libc_file_refill(struct __opaque_file *f)
|
||||||
|
{
|
||||||
|
f->f_buf_datalen = 0;
|
||||||
|
f->f_buf_readptr = 0;
|
||||||
|
|
||||||
|
if (f->f_fd < 0) {
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->f_flags & FILE_ERR) {
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->f_flags & FILE_EOF) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f->f_buf) {
|
||||||
|
f->f_buf_max = DEFAULT_BUFFER_SIZE;
|
||||||
|
f->f_buf = malloc(f->f_buf_max);
|
||||||
|
if (!f->f_buf) {
|
||||||
|
f->f_buf_max = 0;
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long r = read(f->f_fd, f->f_buf, f->f_buf_max);
|
||||||
|
if (r < 0) {
|
||||||
|
return -r;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->f_buf_datalen = r;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_file_read(struct __opaque_file *f, void *out, size_t count)
|
||||||
|
{
|
||||||
|
if (f->f_fd < 0) {
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->f_flags & FILE_ERR) {
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->f_flags & FILE_EOF) {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t available = f->f_buf_datalen - f->f_buf_readptr;
|
||||||
|
if (count > available) {
|
||||||
|
count = available;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, f->f_buf + f->f_buf_readptr, count);
|
||||||
|
|
||||||
|
f->f_buf_readptr += count;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t __libc_file_available(struct __opaque_file *f)
|
||||||
|
{
|
||||||
|
return f->f_buf_datalen - f->f_buf_readptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef _LIBC_IO_FILE_H_
|
||||||
|
#define _LIBC_IO_FILE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
enum file_flags {
|
||||||
|
FILE_EOF = 0x01u,
|
||||||
|
FILE_ERR = 0x02u,
|
||||||
|
FILE_BIN = 0x04u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __opaque_file {
|
||||||
|
enum file_flags f_flags;
|
||||||
|
int f_fd;
|
||||||
|
char f_unget;
|
||||||
|
char *f_buf;
|
||||||
|
size_t f_buf_datalen, f_buf_max;
|
||||||
|
size_t f_buf_readptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int __libc_file_refill(struct __opaque_file *f);
|
||||||
|
extern int __libc_file_read(struct __opaque_file *f, void *out, size_t count);
|
||||||
|
extern size_t __libc_file_available(struct __opaque_file *f);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#include "file.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
enum mode {
|
||||||
|
MODE_R = 0x01u,
|
||||||
|
MODE_W = 0x02u,
|
||||||
|
MODE_A = 0x04u,
|
||||||
|
MODE_B = 0x08u,
|
||||||
|
MODE_X = 0x10u,
|
||||||
|
MODE_PLUS = 0x20u,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int flags_from_mode(
|
||||||
|
const char *mode_string,
|
||||||
|
int *out_sysflags,
|
||||||
|
enum file_flags *out_fflags)
|
||||||
|
{
|
||||||
|
enum mode mode = 0;
|
||||||
|
int sysflags = 0;
|
||||||
|
enum file_flags fflags = 0;
|
||||||
|
|
||||||
|
for (int i = 0; mode_string[i]; i++) {
|
||||||
|
switch (mode_string[i]) {
|
||||||
|
case 'r':
|
||||||
|
if (mode & (MODE_R | MODE_W | MODE_A | MODE_X)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode |= MODE_R;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (mode & (MODE_R | MODE_W | MODE_A)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mode |= MODE_W;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
if (mode & (MODE_R | MODE_W | MODE_A | MODE_X)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
if (mode & MODE_PLUS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mode |= MODE_PLUS;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
if (mode & MODE_B) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mode |= MODE_B;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
if (mode & (MODE_R | MODE_A | MODE_X)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mode |= MODE_X;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((int)mode) {
|
||||||
|
case MODE_R | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_R:
|
||||||
|
sysflags = O_RDONLY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_W | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_W:
|
||||||
|
sysflags = O_WRONLY | O_TRUNC | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_A | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_A:
|
||||||
|
sysflags = O_WRONLY | O_APPEND | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_R | MODE_PLUS | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_R | MODE_PLUS:
|
||||||
|
sysflags = O_RDWR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_W | MODE_PLUS | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_W | MODE_PLUS:
|
||||||
|
sysflags = O_RDWR | O_TRUNC | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_W | MODE_PLUS | MODE_X | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_W | MODE_PLUS | MODE_X:
|
||||||
|
sysflags = O_RDWR | O_TRUNC | O_CREAT | O_EXCL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_A | MODE_PLUS | MODE_B:
|
||||||
|
fflags = FILE_BIN;
|
||||||
|
case MODE_A | MODE_PLUS:
|
||||||
|
sysflags = O_RDWR | O_APPEND | O_CREAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __opaque_file *fopen(const char *path, const char *mode)
|
||||||
|
{
|
||||||
|
int sysflags = 0;
|
||||||
|
enum file_flags fflags = 0;
|
||||||
|
if (flags_from_mode(mode, &sysflags, &fflags) != 0) {
|
||||||
|
__set_errno(EINVAL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __opaque_file *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
int fd = open(path, sysflags);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(out);
|
||||||
|
__set_errno(-fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->f_fd = fd;
|
||||||
|
out->f_flags = fflags;
|
||||||
|
__set_errno(SUCCESS);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#include "dir.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern struct __opaque_dir *opendir(const char *name)
|
||||||
|
{
|
||||||
|
struct __opaque_dir *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
int fd = open(name, O_RDONLY | O_DIRECTORY);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->d_flags = 0;
|
||||||
|
out->d_fd = fd;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "dir.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct dirent *readdir(struct __opaque_dir *dirp)
|
||||||
|
{
|
||||||
|
int result = __libc_dir_move_next(dirp);
|
||||||
|
if (result < 0) {
|
||||||
|
dirp->d_flags |= DIR_ERR;
|
||||||
|
__set_errno(-result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
return &dirp->d_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = __libc_dir_refill(dirp);
|
||||||
|
if (result < 0) {
|
||||||
|
dirp->d_flags |= DIR_ERR;
|
||||||
|
__set_errno(-result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dirp->d_buf_datalen) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dirp->d_current;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user