minix/lib/libpuffs/read.c
Lionel Sambuc 56350a991b Message types for VFS read, write & peek
All of these requests share the same message type as at least one server
manages those requests in the same handler, just by checking the actual
type of the request, and then acting upon it.

Change-Id: I17337b4c67ae209523574c22ccc108cf5f1e65e9
2014-07-28 17:05:29 +02:00

179 lines
4.6 KiB
C

/* Created (MFS based):
* February 2010 (Evgeniy Ivanov)
*/
#include "fs.h"
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <minix/com.h>
#include <minix/u64.h>
#include <minix/vfsif.h>
#include <assert.h>
#include <sys/param.h>
#include "puffs.h"
#include "puffs_priv.h"
#define GETDENTS_BUFSIZ 4096
static char getdents_buf[GETDENTS_BUFSIZ];
#define RW_BUFSIZ (128 << 10)
static char rw_buf[RW_BUFSIZ];
/*===========================================================================*
* fs_readwrite *
*===========================================================================*/
int fs_readwrite(void)
{
int r = OK, rw_flag;
cp_grant_id_t gid;
off_t pos;
size_t nrbytes, bytes_left, bytes_done = 0;
struct puffs_node *pn;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_readwrite.inode)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
/* Get the values from the request message */
rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
gid = fs_m_in.m_vfs_fs_readwrite.grant;
pos = fs_m_in.m_vfs_fs_readwrite.seek_pos;
nrbytes = bytes_left = fs_m_in.m_vfs_fs_readwrite.nbytes;
if (nrbytes > RW_BUFSIZ)
nrbytes = bytes_left = RW_BUFSIZ;
memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
if (rw_flag == READING) {
if (global_pu->pu_ops.puffs_node_read == NULL)
return(EINVAL);
r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf,
pos, &bytes_left, pcr, 0);
if (r) {
lpuffs_debug("puffs_node_read failed\n");
return(EINVAL);
}
bytes_done = nrbytes - bytes_left;
if (bytes_done) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0,
(vir_bytes) rw_buf, bytes_done);
update_timens(pn, ATIME, NULL);
}
} else if (rw_flag == WRITING) {
/* At first try to change vattr */
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
puffs_vattr_null(&va);
if ((u_quad_t)(pos + bytes_left) > pn->pn_va.va_size)
va.va_size = bytes_left + pos;
va.va_ctime = va.va_mtime = clock_timespec();
va.va_atime = pn->pn_va.va_atime;
r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr);
if (r) return(EINVAL);
r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0,
(vir_bytes) rw_buf, nrbytes);
if (r != OK) return(EINVAL);
if (global_pu->pu_ops.puffs_node_write == NULL)
return(EINVAL);
r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf,
pos, &bytes_left, pcr, 0);
bytes_done = nrbytes - bytes_left;
}
if (r != OK) return(EINVAL);
fs_m_out.m_fs_vfs_readwrite.seek_pos = pos + bytes_done;
fs_m_out.m_fs_vfs_readwrite.nbytes = bytes_done;
return(r);
}
/*===========================================================================*
* fs_breadwrite *
*===========================================================================*/
int fs_breadwrite(void)
{
/* We do not support breads/writes */
panic("bread write requested, but FS doesn't support it!\n");
return(OK);
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
int fs_getdents(void)
{
int r;
register struct puffs_node *pn;
ino_t ino;
cp_grant_id_t gid;
size_t size, buf_left;
off_t pos;
struct dirent *dent;
int eofflag = 0;
size_t written;
PUFFS_MAKECRED(pcr, &global_kcred);
ino = fs_m_in.m_vfs_fs_getdents.inode;
gid = fs_m_in.m_vfs_fs_getdents.grant;
size = buf_left = fs_m_in.m_vfs_fs_getdents.mem_size;
pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
if (GETDENTS_BUFSIZ < size)
size = buf_left = GETDENTS_BUFSIZ;
memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
dent = (struct dirent*) getdents_buf;
r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, &pos,
&buf_left, pcr, &eofflag, 0, 0);
if (r) {
lpuffs_debug("puffs_node_readdir returned error\n");
return(EINVAL);
}
assert(buf_left <= size);
written = size - buf_left;
if (written == 0 && !eofflag) {
lpuffs_debug("The user's buffer is too small\n");
return(EINVAL);
}
if (written) {
r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0,
(vir_bytes) getdents_buf, written);
if (r != OK) return(r);
}
update_timens(pn, ATIME, NULL);
fs_m_out.m_fs_vfs_getdents.nbytes = written;
fs_m_out.m_fs_vfs_getdents.seek_pos = pos;
return(OK);
}