minix/lib/libsffs/write.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

160 lines
3.4 KiB
C

/* This file contains file writing system call handlers.
*
* The entry points into this file are:
* do_write perform the WRITE file system call
* do_ftrunc perform the FTRUNC file system call
*
* Created:
* April 2009 (D.C. van Moolenbroek)
*/
#include "inc.h"
static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
cp_grant_id_t *grantp);
/*===========================================================================*
* write_file *
*===========================================================================*/
static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
cp_grant_id_t *grantp)
{
/* Write data or zeroes to a file, depending on whether a valid pointer to
* a data grant was provided.
*/
u64_t pos;
size_t count, size;
vir_bytes off;
char *ptr;
int r, chunk;
assert(!IS_DIR(ino));
if ((r = get_handle(ino)) != OK)
return r;
pos = *posp;
count = *countp;
assert(count > 0);
/* Use the buffer from below to eliminate extra copying. */
size = sffs_table->t_writebuf(&ptr);
off = 0;
while (count > 0) {
chunk = MIN(count, size);
if (grantp != NULL) {
r = sys_safecopyfrom(m_in.m_source, *grantp,
off, (vir_bytes) ptr, chunk);
if (r != OK)
break;
} else {
/* Do this every time. We don't know what happens below. */
memset(ptr, 0, chunk);
}
if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0)
break;
count -= r;
off += r;
pos += r;
}
if (r < 0)
return r;
*posp = pos;
*countp = off;
return OK;
}
/*===========================================================================*
* do_write *
*===========================================================================*/
int do_write(void)
{
/* Write data to a file.
*/
struct inode *ino;
off_t pos;
size_t count;
cp_grant_id_t grant;
int r;
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_readwrite.inode)) == NULL)
return EINVAL;
if (IS_DIR(ino)) return EISDIR;
pos = m_in.m_vfs_fs_readwrite.seek_pos;
count = m_in.m_vfs_fs_readwrite.nbytes;
grant = m_in.m_vfs_fs_readwrite.grant;
if (count == 0) return EINVAL;
if ((r = write_file(ino, &pos, &count, &grant)) != OK)
return r;
m_out.m_fs_vfs_readwrite.seek_pos = pos;
m_out.m_fs_vfs_readwrite.nbytes = count;
return OK;
}
/*===========================================================================*
* do_ftrunc *
*===========================================================================*/
int do_ftrunc(void)
{
/* Change file size or create file holes.
*/
char path[PATH_MAX];
struct inode *ino;
struct sffs_attr attr;
u64_t start, end, delta;
size_t count;
int r;
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_ftrunc.inode)) == NULL)
return EINVAL;
if (IS_DIR(ino)) return EISDIR;
start = m_in.m_vfs_fs_ftrunc.trc_start;
end = m_in.m_vfs_fs_ftrunc.trc_end;
if (end == 0) {
/* Truncate or expand the file. */
if ((r = verify_inode(ino, path, NULL)) != OK)
return r;
attr.a_mask = SFFS_ATTR_SIZE;
attr.a_size = start;
r = sffs_table->t_setattr(path, &attr);
} else {
/* Write zeroes to the file. We can't create holes. */
if (end <= start) return EINVAL;
delta = end - start;
if (ex64hi(delta) != 0) return EINVAL;
count = ex64lo(delta);
r = write_file(ino, &start, &count, NULL);
}
return r;
}