oskit/oskit-20020317/com/sfs_peropen.c

638 lines
13 KiB
C
Executable File

/*
* Copyright (c) 1999 The University of Utah and the Flux Group.
* All rights reserved.
*
* Contributed by the Computer Security Research division,
* INFOSEC Research and Technology Office, NSA.
*
* This file is part of the Flux OSKit. The OSKit is free software, also known
* as "open source;" you can redistribute it and/or modify it under the terms
* of the GNU General Public License (GPL), version 2, as published by the Free
* Software Foundation (FSF). To explore alternate licensing terms, contact
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
*
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
* received a copy of the GPL along with the OSKit; see the file COPYING. If
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
*/
#include <oskit/c/string.h>
#include "sfs.h"
static struct oskit_openfile_ops ofile_ops;
static struct oskit_absio_ops ofile_absio_ops;
static struct oskit_comsid_ops sid_ops;
static inline struct sopenfile *
add_openfile(struct sopenfile * list,
struct sopenfile * item)
{
if (list == NULL) {
item->prev = item->next = item;
} else {
item->prev = list->prev;
item->next = list;
list->prev->next = item;
list->prev = item;
}
return (item);
}
static inline struct sopenfile *
remove_openfile(struct sopenfile * list,
struct sopenfile * item)
{
if (item->next == item->prev) {
return (NULL);
} else {
item->prev->next = item->next;
item->next->prev = item->prev;
return (item->next);
}
}
oskit_error_t
sopenfile_create(struct sfiledir * sfile,
oskit_openfile_t * ofile,
oskit_oflags_t flags,
oskit_security_id_t sid,
struct sopenfile ** out_sofile)
{
struct sopenfile *sofile;
oskit_error_t rc;
sofile =
oskit_osenv_mem_alloc(sfile->sfs->mem,sizeof(struct sopenfile),0,0);
if (!sofile)
return OSKIT_ENOMEM;
sofile->ofilei.ops = &ofile_ops;
sofile->absioi.ops = &ofile_absio_ops;
sofile->sidi.ops = &sid_ops;
sofile->count = 1;
sofile->flags = flags;
sofile->sid = sid;
sofile->sfile = sfile;
oskit_file_addref(&sfile->filei);
sofile->ofile = ofile;
oskit_openfile_addref(ofile);
rc = oskit_openfile_query(ofile, &oskit_absio_iid, (void **) &sofile->absio);
if (rc)
sofile->absio = NULL;
sfile->sopenfile_list = add_openfile(sfile->sopenfile_list, sofile);
OSKIT_AVC_ENTRY_REF_INIT(&sofile->avcr);
OSKIT_AVC_ENTRY_REF_CPY(&sofile->file_avcr, &sfile->avcr);
*out_sofile = sofile;
return 0;
}
/*
* oskit_openfile methods
*/
static OSKIT_COMDECL
ofile_query(oskit_openfile_t * f,
const struct oskit_guid * iid,
void **out_ihandle)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) f;
if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_stream_iid, sizeof(*iid)) == 0 ||
memcmp(iid, &oskit_openfile_iid, sizeof(*iid)) == 0) {
*out_ihandle = &sofile->ofilei;
++sofile->count;
return 0;
}
if (memcmp(iid, &oskit_comsid_iid, sizeof(*iid)) == 0) {
*out_ihandle = &sofile->sidi;
++sofile->count;
return 0;
}
if (sofile->absio && memcmp(iid, &oskit_absio_iid, sizeof(*iid)) == 0) {
*out_ihandle = &sofile->absioi;
++sofile->count;
return 0;
}
*out_ihandle = NULL;
return OSKIT_E_NOINTERFACE;
}
static OSKIT_COMDECL_U
ofile_addref(oskit_openfile_t * f)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) f;
return ++sofile->count;
}
static OSKIT_COMDECL_U
ofile_release(oskit_openfile_t * f)
{
struct sopenfile *sofile;
struct sopenfile *openfile_list;
unsigned newcount;
sofile = (struct sopenfile *) f;
newcount = --sofile->count;
if (newcount == 0) {
openfile_list = sofile->sfile->sopenfile_list;
sofile->sfile->sopenfile_list = remove_openfile(openfile_list, sofile);
oskit_file_release(&sofile->sfile->filei);
oskit_openfile_release(sofile->ofile);
if (sofile->absio)
oskit_absio_release(sofile->absio);
oskit_osenv_mem_free(sofile->sfile->sfs->mem, sofile, 0,
sizeof(struct sopenfile));
}
return newcount;
}
static inline oskit_error_t
ofile_read_checks(struct sopenfile * sofile)
{
oskit_security_id_t csid;
oskit_error_t rc;
if (!(sofile->flags & OSKIT_O_RDONLY))
return OSKIT_EBADF;
CSID(&csid);
if (csid != sofile->sid) {
rc = SFS_FD_HAS_PERM(csid, sofile, SETATTR);
if (rc)
return rc;
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, READ);
if (rc)
return rc;
}
return 0;
}
static OSKIT_COMDECL
ofile_read(oskit_openfile_t * f, void *buf, oskit_u32_t len,
oskit_u32_t * out_actual)
{
struct sopenfile *sofile;
oskit_error_t rc;
sofile = (struct sopenfile *) f;
if (!sofile || !sofile->count)
return OSKIT_E_INVALIDARG;
rc = ofile_read_checks(sofile);
if (rc)
return rc;
return oskit_openfile_read(sofile->ofile, buf, len, out_actual);
}
static inline oskit_error_t
ofile_write_checks(struct sopenfile * sofile)
{
oskit_security_id_t csid;
oskit_error_t rc;
if (!(sofile->flags & OSKIT_O_WRONLY))
return OSKIT_EBADF;
CSID(&csid);
if (csid != sofile->sid) {
rc = SFS_FD_HAS_PERM(csid, sofile, SETATTR);
if (rc)
return rc;
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, WRITE);
if (rc) {
if (sofile->flags & OSKIT_O_APPEND) {
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, APPEND);
}
}
if (rc)
return rc;
}
return 0;
}
static OSKIT_COMDECL
ofile_write(oskit_openfile_t * f, const void *buf,
oskit_u32_t len, oskit_u32_t * out_actual)
{
struct sopenfile *sofile;
oskit_error_t rc;
sofile = (struct sopenfile *) f;
if (!sofile || !sofile->count)
return OSKIT_E_INVALIDARG;
rc = ofile_write_checks(sofile);
if (rc)
return rc;
return oskit_openfile_write(sofile->ofile, buf, len, out_actual);
}
static OSKIT_COMDECL
ofile_seek(oskit_openfile_t * f, oskit_s64_t ofs,
oskit_seek_t whence, oskit_u64_t * out_newpos)
{
oskit_security_id_t csid;
struct sopenfile *sofile;
oskit_error_t rc;
sofile = (struct sopenfile *) f;
if (!sofile || !sofile->count)
return OSKIT_E_INVALIDARG;
CSID(&csid);
if (csid != sofile->sid) {
rc = SFS_FD_HAS_PERM(csid, sofile, SETATTR);
if (rc)
return rc;
}
return oskit_openfile_seek(sofile->ofile, ofs, whence, out_newpos);
}
static OSKIT_COMDECL
ofile_setsize(oskit_openfile_t * f, oskit_u64_t new_size)
{
struct sopenfile *sofile;
oskit_security_id_t csid;
oskit_error_t rc;
sofile = (struct sopenfile *) f;
if (!sofile || !sofile->count)
return OSKIT_E_INVALIDARG;
CSID(&csid);
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, SETATTR);
if (rc)
return rc;
return oskit_openfile_setsize(sofile->ofile, new_size);
}
static OSKIT_COMDECL
ofile_copy_to(oskit_openfile_t * f,
oskit_stream_t * dst,
oskit_u64_t size,
oskit_u64_t * out_read,
oskit_u64_t * out_written)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_commit(oskit_openfile_t * f, oskit_u32_t commit_flags)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_revert(oskit_openfile_t * f)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_lock_region(oskit_openfile_t * f,
oskit_u64_t offset, oskit_u64_t size,
oskit_u32_t lock_type)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_unlock_region(oskit_openfile_t * f,
oskit_u64_t offset, oskit_u64_t size,
oskit_u32_t lock_type)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_stat(oskit_openfile_t * f, oskit_stream_stat_t * out_stat,
oskit_u32_t stat_flags)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_clone(oskit_openfile_t * f, oskit_openfile_t ** out_stream)
{
return OSKIT_E_NOTIMPL;
}
static OSKIT_COMDECL
ofile_getfile(oskit_openfile_t * f,
struct oskit_file ** out_file)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) f;
if (!sofile || !sofile->count)
return OSKIT_E_INVALIDARG;
oskit_file_addref(&sofile->sfile->filei);
*out_file = &sofile->sfile->filei;
return 0;
}
static struct oskit_openfile_ops ofile_ops = {
ofile_query,
ofile_addref,
ofile_release,
ofile_read,
ofile_write,
ofile_seek,
ofile_setsize,
ofile_copy_to,
ofile_commit,
ofile_revert,
ofile_lock_region,
ofile_unlock_region,
ofile_stat,
ofile_clone,
ofile_getfile
};
/*
* oskit_openfile absolute I/O methods
*/
static OSKIT_COMDECL
afile_query(oskit_absio_t * io,
const struct oskit_guid * iid,
void **out_ihandle)
{
struct sopenfile *ofile;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
ofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
return oskit_openfile_query(&ofile->ofilei, iid, out_ihandle);
}
static OSKIT_COMDECL_U
afile_addref(oskit_absio_t * io)
{
struct sopenfile *ofile;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
ofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
return oskit_openfile_addref(&ofile->ofilei);
}
static OSKIT_COMDECL_U
afile_release(oskit_absio_t * io)
{
struct sopenfile *ofile;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
ofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
return oskit_openfile_release(&ofile->ofilei);
}
static OSKIT_COMDECL
afile_read(oskit_absio_t * io, void *buf,
oskit_off_t offset, oskit_size_t amount,
oskit_size_t * out_actual)
{
struct sopenfile *sofile;
oskit_error_t rc;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
sofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
if (!sofile->count)
return OSKIT_E_INVALIDARG;
rc = ofile_read_checks(sofile);
if (rc)
return rc;
return oskit_absio_read(sofile->absio, buf, offset, amount, out_actual);
}
static OSKIT_COMDECL
afile_write(oskit_absio_t * io, const void *buf,
oskit_off_t offset, oskit_size_t amount,
oskit_size_t * out_actual)
{
struct sopenfile *sofile;
oskit_error_t rc;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
sofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
if (!sofile->count)
return OSKIT_E_INVALIDARG;
rc = ofile_write_checks(sofile);
if (rc)
return rc;
return oskit_absio_write(sofile->absio, buf, offset, amount, out_actual);
}
static OSKIT_COMDECL
afile_get_size(oskit_absio_t * io, oskit_off_t * out_size)
{
struct sopenfile *sofile;
oskit_security_id_t csid;
oskit_error_t rc;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
sofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
if (!sofile->count)
return OSKIT_E_INVALIDARG;
CSID(&csid);
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, GETATTR);
if (rc)
return rc;
return oskit_absio_getsize(sofile->absio, out_size);
}
static OSKIT_COMDECL
afile_set_size(oskit_absio_t * io, oskit_off_t new_size)
{
struct sopenfile *sofile;
oskit_security_id_t csid;
oskit_error_t rc;
if (!io || io->ops != &ofile_absio_ops)
return OSKIT_E_INVALIDARG;
sofile = (struct sopenfile *) ((char *) io -
offsetof(struct sopenfile, absioi));
if (!sofile->count)
return OSKIT_E_INVALIDARG;
CSID(&csid);
rc = SFS_FD_FILE_HAS_PERM(csid, sofile, SETATTR);
if (rc)
return rc;
return oskit_absio_setsize(sofile->absio, new_size);
}
static struct oskit_absio_ops ofile_absio_ops = {
afile_query,
afile_addref,
afile_release,
(void *) 0,
afile_read,
afile_write,
afile_get_size,
afile_set_size
};
/*
* oskit_comsid methods
*/
static OSKIT_COMDECL
sid_query(oskit_comsid_t * s,
const struct oskit_guid * iid,
void **out_ihandle)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) ((char *) s -
offsetof(struct sopenfile, sidi));
return oskit_openfile_query(&sofile->ofilei, iid, out_ihandle);
}
static OSKIT_COMDECL_U
sid_addref(oskit_comsid_t * s)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) ((char *) s -
offsetof(struct sopenfile, sidi));
return oskit_openfile_addref(&sofile->ofilei);
}
static OSKIT_COMDECL_U
sid_release(oskit_comsid_t * s)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) ((char *) s -
offsetof(struct sopenfile, sidi));
return oskit_openfile_release(&sofile->ofilei);
}
static OSKIT_COMDECL
sid_get(oskit_comsid_t * s,
oskit_security_class_t * outclass,
oskit_security_id_t * outsid)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) ((char *) s -
offsetof(struct sopenfile, sidi));
*outclass = OSKIT_SECCLASS_FD;
*outsid = sofile->sid;
return 0;
}
static OSKIT_COMDECL
sid_set(oskit_comsid_t * s,
oskit_security_id_t newsid)
{
struct sopenfile *sofile;
sofile = (struct sopenfile *) ((char *) s -
offsetof(struct sopenfile, sidi));
return OSKIT_E_NOTIMPL;
}
static struct oskit_comsid_ops sid_ops = {
sid_query,
sid_addref,
sid_release,
sid_get,
sid_set
};