mirror of
https://github.com/ish-app/ish.git
synced 2026-01-25 14:06:40 +00:00
pread and pwrite have been fixed to return the correct (unchanged) offset. In addition, both functions have been added to fd_ops and sys_read and sys_write will use these if they are available; making them (fd_ops's read/write) effectively optional if there is an implementation of pread and pwrite available. lseek is no longer optional.
192 lines
5.6 KiB
C
192 lines
5.6 KiB
C
#ifndef FD_H
|
|
#define FD_H
|
|
#include <dirent.h>
|
|
#include "emu/memory.h"
|
|
#include "util/list.h"
|
|
#include "util/sync.h"
|
|
#include "util/bits.h"
|
|
#include "fs/stat.h"
|
|
#include "fs/proc.h"
|
|
#include "fs/sockrestart.h"
|
|
|
|
// FIXME almost everything that uses the structs in this file does so without any kind of sane locking
|
|
|
|
struct fd {
|
|
atomic_uint refcount;
|
|
unsigned flags;
|
|
mode_t_ type; // just the S_IFMT part, it can't change
|
|
const struct fd_ops *ops;
|
|
struct list poll_fds;
|
|
lock_t poll_lock;
|
|
unsigned long offset;
|
|
|
|
// fd data
|
|
union {
|
|
// tty
|
|
struct {
|
|
struct tty *tty;
|
|
// links together fds pointing to the same tty
|
|
// locked by the tty
|
|
struct list tty_other_fds;
|
|
};
|
|
struct {
|
|
struct poll *poll;
|
|
} epollfd;
|
|
struct {
|
|
uint64_t val;
|
|
} eventfd;
|
|
struct {
|
|
struct timer *timer;
|
|
uint64_t expirations;
|
|
} timerfd;
|
|
struct {
|
|
int domain;
|
|
int type;
|
|
int protocol;
|
|
|
|
// These are only used as strong references, to keep the inode
|
|
// alive while there is a listener.
|
|
struct inode_data *unix_name_inode;
|
|
struct unix_abstract *unix_name_abstract;
|
|
// TODO add a field for unix socket name
|
|
struct fd *unix_peer; // locked by peer_lock, for simplicity
|
|
cond_t unix_got_peer;
|
|
// Queue of struct scm for sending file descriptors
|
|
// locked by fd->lock
|
|
struct list unix_scm;
|
|
struct ucred_ {
|
|
pid_t_ pid;
|
|
uid_t_ uid;
|
|
uid_t_ gid;
|
|
} unix_cred;
|
|
} socket;
|
|
|
|
// See app/Pasteboard.m
|
|
struct {
|
|
// UIPasteboard.changeCount
|
|
uint64_t generation;
|
|
// Buffer for written data
|
|
void* buffer;
|
|
// its capacity
|
|
size_t buffer_cap;
|
|
// length of actual data stored in the buffer
|
|
size_t buffer_len;
|
|
} clipboard;
|
|
|
|
// can fit anything in here
|
|
void *data;
|
|
};
|
|
// fs data
|
|
union {
|
|
struct {
|
|
struct proc_entry entry;
|
|
unsigned dir_index;
|
|
struct proc_data data;
|
|
} proc;
|
|
struct {
|
|
int num;
|
|
} devpts;
|
|
struct {
|
|
struct tmp_dirent *dirent;
|
|
struct tmp_dirent *dir_pos;
|
|
} tmpfs;
|
|
void *fs_data;
|
|
};
|
|
|
|
// fs/inode data
|
|
struct mount *mount;
|
|
int real_fd; // seeks on this fd require the lock TODO think about making a special lock just for that
|
|
DIR *dir;
|
|
struct inode_data *inode;
|
|
ino_t fake_inode;
|
|
struct statbuf stat; // for adhoc fs
|
|
struct fd_sockrestart sockrestart; // argh
|
|
|
|
// these are used for a variety of things related to the fd
|
|
lock_t lock;
|
|
cond_t cond;
|
|
};
|
|
|
|
typedef sdword_t fd_t;
|
|
#define AT_FDCWD_ -100
|
|
|
|
struct fd *fd_create(const struct fd_ops *ops);
|
|
struct fd *fd_retain(struct fd *fd);
|
|
int fd_close(struct fd *fd);
|
|
|
|
int fd_getflags(struct fd *fd);
|
|
int fd_setflags(struct fd *fd, int flags);
|
|
|
|
#define NAME_MAX 255
|
|
struct dir_entry {
|
|
qword_t inode;
|
|
char name[NAME_MAX + 1];
|
|
};
|
|
|
|
#define LSEEK_SET 0
|
|
#define LSEEK_CUR 1
|
|
#define LSEEK_END 2
|
|
|
|
struct fd_ops {
|
|
// required for files
|
|
// TODO make optional for non-files
|
|
ssize_t (*read)(struct fd *fd, void *buf, size_t bufsize);
|
|
ssize_t (*write)(struct fd *fd, const void *buf, size_t bufsize);
|
|
ssize_t (*pread)(struct fd *fd, void *buf, size_t bufsize, off_t off);
|
|
ssize_t (*pwrite)(struct fd *fd, const void *buf, size_t bufsize, off_t off);
|
|
off_t_ (*lseek)(struct fd *fd, off_t_ off, int whence);
|
|
|
|
// Reads a directory entry from the stream
|
|
// required for directories
|
|
int (*readdir)(struct fd *fd, struct dir_entry *entry);
|
|
// Return an opaque value representing the current point in the directory stream
|
|
// optional, fd->offset will be used instead
|
|
unsigned long (*telldir)(struct fd *fd);
|
|
// Seek to the location represented by a pointer returned from telldir
|
|
// optional, fd->offset will be used instead
|
|
void (*seekdir)(struct fd *fd, unsigned long ptr);
|
|
|
|
// map the file
|
|
int (*mmap)(struct fd *fd, struct mem *mem, page_t start, pages_t pages, off_t offset, int prot, int flags);
|
|
|
|
// returns a bitmask of operations that won't block
|
|
int (*poll)(struct fd *fd);
|
|
|
|
// returns the size needed for the output of ioctl, 0 if the arg is not a
|
|
// pointer, -1 for invalid command
|
|
ssize_t (*ioctl_size)(int cmd);
|
|
// if ioctl_size returns non-zero, arg must point to ioctl_size valid bytes
|
|
int (*ioctl)(struct fd *fd, int cmd, void *arg);
|
|
|
|
int (*fsync)(struct fd *fd);
|
|
int (*close)(struct fd *fd);
|
|
|
|
// handle F_GETFL, i.e. return open flags for this fd
|
|
int (*getflags)(struct fd *fd);
|
|
// handle F_SETFL, i.e. set O_NONBLOCK
|
|
int (*setflags)(struct fd *fd, dword_t arg);
|
|
};
|
|
|
|
struct fdtable {
|
|
atomic_uint refcount;
|
|
unsigned size;
|
|
struct fd **files;
|
|
bits_t *cloexec;
|
|
lock_t lock;
|
|
};
|
|
|
|
struct fdtable *fdtable_new(int size);
|
|
void fdtable_release(struct fdtable *table);
|
|
struct fdtable *fdtable_copy(struct fdtable *table);
|
|
void fdtable_free(struct fdtable *table);
|
|
void fdtable_do_cloexec(struct fdtable *table);
|
|
struct fd *fdtable_get(struct fdtable *table, fd_t f);
|
|
|
|
struct fd *f_get(fd_t f);
|
|
// steals a reference to the fd, gives it to the table on success and destroys it on error
|
|
// flags is checked for O_CLOEXEC and O_NONBLOCK
|
|
fd_t f_install(struct fd *fd, int flags);
|
|
int f_close(fd_t f);
|
|
|
|
#endif
|