#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/posix_types.h>
#include <linux/errno.h>
#include <linux/cleanup.h>
#include <linux/err.h>
struct file;
extern void fput(struct file *);
struct file_operations;
struct task_struct;
struct vfsmount;
struct dentry;
struct inode;
struct path;
extern struct file *alloc_file_pseudo(struct inode *, struct vfsmount *,
const char *, int flags, const struct file_operations *);
extern struct file *alloc_file_pseudo_noaccount(struct inode *, struct vfsmount *,
const char *, int flags, const struct file_operations *);
extern struct file *alloc_file_clone(struct file *, int flags,
const struct file_operations *);
struct fd {
unsigned long word;
};
#define FDPUT_FPUT 1
#define FDPUT_POS_UNLOCK 2
#define fd_file(f) ((struct file *)((f).word & ~(FDPUT_FPUT|FDPUT_POS_UNLOCK)))
static inline bool fd_empty(struct fd f)
{
return unlikely(!f.word);
}
#define EMPTY_FD (struct fd){0}
static inline struct fd BORROWED_FD(struct file *f)
{
return (struct fd){(unsigned long)f};
}
static inline struct fd CLONED_FD(struct file *f)
{
return (struct fd){(unsigned long)f | FDPUT_FPUT};
}
static inline void fdput(struct fd fd)
{
if (unlikely(fd.word & FDPUT_FPUT))
fput(fd_file(fd));
}
extern struct file *fget(unsigned int fd);
extern struct file *fget_raw(unsigned int fd);
extern struct file *fget_task(struct task_struct *task, unsigned int fd);
extern struct file *fget_task_next(struct task_struct *task, unsigned int *fd);
extern void __f_unlock_pos(struct file *);
struct fd fdget(unsigned int fd);
struct fd fdget_raw(unsigned int fd);
struct fd fdget_pos(unsigned int fd);
static inline void fdput_pos(struct fd f)
{
if (f.word & FDPUT_POS_UNLOCK)
__f_unlock_pos(fd_file(f));
fdput(f);
}
DEFINE_CLASS(fd, struct fd, fdput(_T), fdget(fd), int fd)
DEFINE_CLASS(fd_raw, struct fd, fdput(_T), fdget_raw(fd), int fd)
DEFINE_CLASS(fd_pos, struct fd, fdput_pos(_T), fdget_pos(fd), int fd)
extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
extern void set_close_on_exec(unsigned int fd, int flag);
extern bool get_close_on_exec(unsigned int fd);
extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
extern int get_unused_fd_flags(unsigned flags);
extern void put_unused_fd(unsigned int fd);
DEFINE_CLASS(get_unused_fd, int, if (_T >= 0) put_unused_fd(_T),
get_unused_fd_flags(flags), unsigned flags)
DEFINE_FREE(fput, struct file *, if (!IS_ERR_OR_NULL(_T)) fput(_T))
#define take_fd(fd) __get_and_null(fd, -EBADF)
extern void fd_install(unsigned int fd, struct file *file);
int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags);
int receive_fd_replace(int new_fd, struct file *file, unsigned int o_flags);
extern void flush_delayed_fput(void);
extern void __fput_sync(struct file *);
extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max;
struct fd_prepare {
s32 err;
s32 __fd;
struct file *__file;
};
typedef struct fd_prepare class_fd_prepare_t;
#define fd_prepare_fd(_fdf) \
(_Generic((_fdf), struct fd_prepare: (_fdf).__fd))
#define fd_prepare_file(_fdf) \
(_Generic((_fdf), struct fd_prepare: (_fdf).__file))
static inline void class_fd_prepare_destructor(const struct fd_prepare *fdf)
{
if (unlikely(fdf->__fd >= 0))
put_unused_fd(fdf->__fd);
if (unlikely(!IS_ERR_OR_NULL(fdf->__file)))
fput(fdf->__file);
}
static inline int class_fd_prepare_lock_err(const struct fd_prepare *fdf)
{
if (unlikely(fdf->err))
return fdf->err;
if (unlikely(fdf->__fd < 0))
return fdf->__fd;
if (unlikely(IS_ERR(fdf->__file)))
return PTR_ERR(fdf->__file);
if (unlikely(!fdf->__file))
return -ENOMEM;
return 0;
}
#define __FD_PREPARE_INIT(_fd_flags, _file_owned) \
({ \
struct fd_prepare fdf = { \
.__fd = get_unused_fd_flags((_fd_flags)), \
}; \
if (likely(fdf.__fd >= 0)) \
fdf.__file = (_file_owned); \
fdf.err = ACQUIRE_ERR(fd_prepare, &fdf); \
fdf; \
})
#define FD_PREPARE(_fdf, _fd_flags, _file_owned) \
CLASS_INIT(fd_prepare, _fdf, __FD_PREPARE_INIT(_fd_flags, _file_owned))
#define fd_publish(_fdf) \
({ \
struct fd_prepare *fdp = &(_fdf); \
VFS_WARN_ON_ONCE(fdp->err); \
VFS_WARN_ON_ONCE(fdp->__fd < 0); \
VFS_WARN_ON_ONCE(IS_ERR_OR_NULL(fdp->__file)); \
fd_install(fdp->__fd, fdp->__file); \
retain_and_null_ptr(fdp->__file); \
take_fd(fdp->__fd); \
})
#define __FD_ADD(_fdf, _fd_flags, _file_owned) \
({ \
FD_PREPARE(_fdf, _fd_flags, _file_owned); \
s32 ret = _fdf.err; \
if (likely(!ret)) \
ret = fd_publish(_fdf); \
ret; \
})
#define FD_ADD(_fd_flags, _file_owned) \
__FD_ADD(__UNIQUE_ID(fd_prepare), _fd_flags, _file_owned)
#endif