/* vu-virtual-null.c - the virtual-null file system
*
****************************************************************
* Copyright (C) 1999, 2000 Thomas Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/os/errno.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/mem/talloc.h"
#include "hackerlab/vu/reserv.h"
#include "hackerlab/vu/vu-virtual-null.h"
/* __STDC__ prototypes for static functions */
static void * vu_virtual_null_make_closure (void * closure);
static void vu_virtual_null_free_closure (void * closure);
static int vu_virtual_null_access (int * errn, char * path, int mode, void * closure);
static int vu_virtual_null_chdir (int * errn, char * path, void * closure);
static int vu_virtual_null_chmod (int * errn, char * path, int mode, void * closure);
static int vu_virtual_null_chown (int * errn, char * path, int owner, int group, void * closure);
static int vu_virtual_null_chroot (int * errn, char * path, void * closure);
static int vu_virtual_null_closedir (int * errn, DIR * dir, void * closure);
static int vu_virtual_null_close (int * errn, int fd, void * closure);
static int vu_virtual_null_fchdir (int * errn, int fd, void * closure);
static int vu_virtual_null_fchmod (int * errn, int fd, int mode, void * closure);
static int vu_virtual_null_fchown (int * errn, int fd, int owner, int group, void * closure);
static int vu_virtual_null_fstat (int * errn, int fd, struct stat * buf, void * closure);
static int vu_virtual_null_fsync (int * errn, int fd, void * closure);
static int vu_virtual_null_ftruncate (int * errn, int fd, off_t where, void * closure);
static int vu_virtual_null_link (int * errn, char * from, char * to, void * closure);
static off_t vu_virtual_null_lseek (int * errn, int fd, off_t offset, int whence, void * closure);
static int vu_virtual_null_lstat (int * errn, char * path, struct stat * buf, void * closure);
static int vu_virtual_null_mkdir (int * errn, char * path, int mode, void * closure);
static int vu_virtual_null_open (int * errn, char * path, int flags, int mode, void * closure);
static int vu_virtual_null_opendir (int * errn, DIR ** retv, char * path, void * closure);
static ssize_t vu_virtual_null_read (int * errn, int fd, char * buf, size_t count, void * closure);
static int vu_virtual_null_readdir (int * errn, struct alloc_limits * limits, char ** file_ret, DIR * dir, void * closure);
static int vu_virtual_null_readlink (int * errn,
char * path,
char * buf,
int bufsize,
void * closure);
static int vu_virtual_null_rename (int * errn, char * from, char * to, void * closure);
static int vu_virtual_null_rmdir (int * errn, char * path, void * closure);
static int vu_virtual_null_stat (int * errn, char * path, struct stat * buf, void * closure);
static int vu_virtual_null_symlink (int * errn, char * from, char * to, void * closure);
static int vu_virtual_null_truncate (int * errn, char * path, off_t where, void * closure);
static int vu_virtual_null_unlink (int * errn, char * path, void * closure);
static int vu_virtual_null_utime (int * errn, char * path, struct utimbuf * times, void * closure);
static ssize_t vu_virtual_null_write (int * errn, int fd, char const * buf, size_t count, void * closure);
static int vu_virtual_null_fcntl (int * errn, int fd, int cmd, long arg, void * closure);
static int vu_virtual_null_dup (int * errn, int fd, void * closure);
static int vu_virtual_null_dup2 (int * errn, int fd, int newfd, void * closure);
static int vu_virtual_null_move_state (int * errn, int fd, int newfd, void * closure);
static struct vu_fs_discipline vu_virtual_null_vtable
= { VU_FS_DISCIPLINE_INITIALIZERS (vu_virtual_null_) };
/************************************************************************
*(h0 "Virtual Null File Descriptors")
*
* These VU functions define a trivial file system implementation in
* which all functions act like the file is /dev/null but no actual
* system calls are performed.
*
* Virtual /dev/null is considered a universally readable/writable,
* permanently 0-length file whose permissions bits and ownerships can
* not be changed by anyone (including root). It's access,
* modification and change times are permanently 0.
*
* The closure for opened files is the access flags cast to
* (void *).
*/
static off_t * fd_offset = NULL;
/* wrap ar_ref ensuring caches will be freed on exit */
static off_t *
fd_ref_off_t (ar_off_t * array, int fd)
{
if (!fd_offset)
{
off_t * result = ar_ref_off_t (array, fd);
talloc_steal (talloc_autofree_context(), ar_base (*array));
return result;
}
else
return ar_ref_off_t (array, fd);
}
/*(c vu_make_virtual_null_fd)
* int vu_make_virtual_null_fd (int * errn, int flags);
*
* Return a new (pseudo) descriptor opened for
* "virtual /dev/null".
*/
int
vu_make_virtual_null_fd (int * errn, int flags)
{
int fd;
fd = reserv_pseudo (errn, flags);
if (fd >= 0)
{
off_t * offset;
offset = fd_ref_off_t (&fd_offset, fd);
*offset = 0;
vu_set_fd_handler (fd, &vu_virtual_null_vtable, (void *)(unsigned long)flags);
}
return fd;
}
/*(c vu_make_virtual_null_fd_ge_n)
* int vu_make_virtual_null_fd_ge_n (int * errn, int n, int flags);
*
* Return a new (pseudo) descriptor opened for
* "virtual /dev/null".
*
* The new descriptor is greater than or equal to `n'.
*/
int
vu_make_virtual_null_fd_ge_n (int * errn, int n, int flags)
{
int fd;
fd = reserv_pseudo_ge_n (errn, n, flags);
if (fd >= 0)
{
off_t * offset;
offset = fd_ref_off_t (&fd_offset, fd);
*offset = 0;
vu_set_fd_handler (fd, &vu_virtual_null_vtable, (void *)(unsigned long)flags);
}
return fd;
}
static void *
vu_virtual_null_make_closure (void * closure)
{
return closure;
}
static void
vu_virtual_null_free_closure (void * closure)
{}
static int
vu_virtual_null_access (int * errn, char * path, int mode, void * closure)
{
if (mode & X_OK)
{
*errn = EACCES;
return -1;
}
return 0;
}
static int
vu_virtual_null_chdir (int * errn, char * path, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_chmod (int * errn, char * path, int mode, void * closure)
{
*errn = EPERM;
return -1;
}
static int
vu_virtual_null_chown (int * errn, char * path, int owner, int group, void * closure)
{
*errn = EPERM;
return -1;
}
static int
vu_virtual_null_chroot (int * errn, char * path, void * closure)
{
*errn = EPERM;
return -1;
}
static int
vu_virtual_null_closedir (int * errn, DIR * dir, void * closure)
{
*errn = ENOTDIR;
return -1;
}
static int
vu_virtual_null_close (int * errn, int fd, void * closure)
{
fd_offset[fd] = 0;
unreserv_pseudo (fd);
return 0;
}
static int
vu_virtual_null_fchdir (int * errn, int fd, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_fchmod (int * errn, int fd, int mode, void * closure)
{
*errn = EPERM;
return -1;
}
static int
vu_virtual_null_fchown (int * errn, int fd, int owner, int group, void * closure)
{
*errn = EPERM;
return -1;
}
static int
vu_virtual_null_fstat (int * errn, int fd, struct stat * buf, void * closure)
{
buf->st_dev = 0;
buf->st_ino = 0;
buf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
buf->st_nlink = 1;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_rdev = 0;
buf->st_size = 0;
buf->st_blksize = 4096;
buf->st_blocks = 0;
buf->st_atime = 0;
buf->st_mtime = 0;
buf->st_ctime = 0;
return 0;
}
static int
vu_virtual_null_fsync (int * errn, int fd, void * closure)
{
return 0;
}
static int
vu_virtual_null_ftruncate (int * errn, int fd, off_t where, void * closure)
{
if (((int)(unsigned long)closure == O_RDONLY) || (where != 0))
{
*errn = EIO;
return -1;
}
return 0;
}
static int
vu_virtual_null_link (int * errn, char * from, char * to, void * closure)
{
*errn = ENOSYS;
return -1;
}
static off_t
vu_virtual_null_lseek (int * errn, int fd, off_t offset, int whence, void * closure)
{
switch (whence)
{
case SEEK_END:
case SEEK_SET:
if (offset < 0)
{
offset_error:
*errn = EINVAL;
return -1;
}
fd_offset[fd] = offset;
return offset;
case SEEK_CUR:
if ((fd_offset[fd] + offset) < 0)
goto offset_error;
fd_offset[fd] = fd_offset[fd] + offset;
return fd_offset[fd];
default:
*errn = EINVAL;
return -1;
}
}
static int
vu_virtual_null_lstat (int * errn, char * path, struct stat * buf, void * closure)
{
return vu_virtual_null_fstat (errn, 0, buf, closure);
}
static int
vu_virtual_null_mkdir (int * errn, char * path, int mode, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_open (int * errn, char * path, int flags, int mode, void * closure)
{
return vu_make_virtual_null_fd (errn, flags);
}
static int
vu_virtual_null_opendir (int * errn, DIR ** retv, char * path, void * closure)
{
*errn = ENOTDIR;
return -1;
}
static ssize_t
vu_virtual_null_read (int * errn, int fd, char * buf, size_t count, void * closure)
{
if ((int)(unsigned long)closure == O_WRONLY)
{
*errn = EBADF;
return -1;
}
return 0;
}
static int
vu_virtual_null_readdir (int * errn, struct alloc_limits * limits, char ** file_ret, DIR * dir, void * closure)
{
*errn = ENOTDIR;
return -1;
}
static int
vu_virtual_null_readlink (int * errn,
char * path,
char * buf,
int bufsize,
void * closure)
{
*errn = EINVAL;
return -1;
}
static int
vu_virtual_null_rename (int * errn, char * from, char * to, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_rmdir (int * errn, char * path, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_stat (int * errn, char * path, struct stat * buf, void * closure)
{
return vu_virtual_null_fstat (errn, 0, buf, closure);
}
static int
vu_virtual_null_symlink (int * errn, char * from, char * to, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_truncate (int * errn, char * path, off_t where, void * closure)
{
if (where != 0)
{
*errn = EIO;
return -1;
}
return 0;
}
static int
vu_virtual_null_unlink (int * errn, char * path, void * closure)
{
*errn = ENOSYS;
return -1;
}
static int
vu_virtual_null_utime (int * errn, char * path, struct utimbuf * times, void * closure)
{
*errn = EPERM;
return -1;
}
static ssize_t
vu_virtual_null_write (int * errn, int fd, char const * buf, size_t count, void * closure)
{
if ((int)(unsigned long)closure == O_RDONLY)
{
*errn = EBADF;
return -1;
}
fd_offset[fd] += count;
return count;
}
static int
vu_virtual_null_fcntl (int * errn, int fd, int cmd, long arg, void * closure)
{
switch (cmd)
{
default:
*errn = ENOSYS;
return -1;
case F_DUPFD:
return vu_make_virtual_null_fd_ge_n (errn, arg, (int)(unsigned long)closure);
case F_GETFD:
return FD_CLOEXEC;
case F_SETFD:
if (arg != FD_CLOEXEC)
{
*errn = EINVAL;
return -1;
}
return 0;
case F_GETFL:
return O_NONBLOCK | (int)(unsigned long)closure;
case F_SETFL:
if (arg != O_NONBLOCK)
{
*errn = EINVAL;
return -1;
}
return 0;
case F_GETOWN:
case F_SETOWN:
*errn = EINVAL;
return -1;
}
}
static int
vu_virtual_null_dup (int * errn, int fd, void * closure)
{
return vu_virtual_null_fcntl (errn, fd, F_DUPFD, 0, closure);
}
static int
vu_virtual_null_dup2 (int * errn, int fd, int newfd, void * closure)
{
return vu_virtual_null_fcntl (errn, fd, F_DUPFD, newfd, closure);
}
static int
vu_virtual_null_move_state (int * errn, int fd, int newfd, void * closure)
{
off_t * offset_fd;
off_t * offset_newfd;
if (fd == newfd)
return fd;
offset_fd = fd_ref_off_t (&fd_offset, fd);
offset_newfd = fd_ref_off_t (&fd_offset, newfd);
*offset_newfd = *offset_fd;
vu_set_fd_handler (newfd, &vu_virtual_null_vtable, closure);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1