www.pudn.com > efs.rar > fs_public.c
/***********************************************************************
* fs_public.c
*
* Public interface for EFS2
* Copyright (C) 2002--2006 Qualcomm, Inc.
*
* This file contains POSIX interface functions using which EFS2
* can be utilized.
***********************************************************************/
/*===========================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header: //depot/asic/MSMSHARED/services/efs/MSM_EFS.01.02/fs_public.c#42 $ $DateTime: 2006/11/13 09:30:29 $ $Author: davidb $
when who what, where, why
-------- --- ------------------------------------------------------
2006-11-10 s h Add support for efs_chmod().
2006-11-02 rp Added efs_stdio_init() in efs_initialize().
2006-10-26 s h Removed all references to obsolete fs_testapp
2006-10-05 umr Added call to initialize deltree lock in efs_initialize
2006-09-20 dlb Lint cleanup.
2006-08-15 dlb Initialize upgrade system.
2006-07-19 dlb Move transaction limits down to each FS.
2006-07-06 dlb Remove 'size' field from vnode.
2006-07-05 dlb Move read-end check down to VFS code.
2006-06-27 dlb Pass stat through readdir.
2006-06-23 sh Removed conditional FEATURE_FS_BENCHMARK.. stubs now.
2006-06-19 dlb Enable diag in off-target test.
2006-06-19 nrs Allow renames on different size items
2006-06-07 sh Featurized hotplug_init()
2006-06-02 sh Removed FTL layer initialization. (moved to hotplug)
2006-05-23 yg Added FTL layer initialization.
2006-05-11 sh Renamed efs_hotplug_... to hotplug_...
2006-05-09 dlb Add nodevfs.
2006-03-31 sh Lint cleanup
2006-03-29 sh Hotplug init is no longer optional.
2006-01-31 dlb Correct errno of access call.
2006-01-26 sh Added TIMETEST2 messages for public API
2006-01-26 sh Added TIMETEST2 message support
2006-01-11 nrs Fixed Copyright header
2005-12-20 dlb Initialize descriptor table.
2005-11-28 nrs Merge 7500 orphans
2005-11-12 sh Use rex tcb err_num instead of global efs_errno
2005-11-10 nrs Merge Fix
2005-11-09 sh Renamed FS_FEATURE_EXTFS to FEATURE_EFS_EXTFS
2005-10-28 nrs Changed raw_put and raw_get length from int to fs_size_t
2005-10-26 sh Lint cleanup
2005-10-20 sh Initialize fs_benchmark task and cpu_hog task
2005-10-05 nrs Clean and fix quotas and reservations
2005-09-02 dlb Don't follow last symlink on symlink creation.
2005-09-02 dlb Add sfat mounting feature on /mmc1.
2005-08-26 sh Don't ERR_FATAL on efs_chmod, even unimplemented
2005-08-23 sh Add support for mknod, device files
2005-08-10 dlb Umount of opened dirs.
2005-08-10 dlb Nodev root of mpoint properly.
2005-08-09 dlb Add nodev support, for cleanup on umount.
2005-08-08 sh Enforce identical item size for put
2005-08-03 dlb Add umount support.
2005-07-22 nrs Added implementation for quotas & reservations
2005-07-15 nrs Added implementation for efs_chown
2005-07-13 dlb Mountpoint cleanup.
2005-06-06 dlb Extensions for SFAT.
2005-05-26 sd Compilation fixes for L4.
2005-05-10 sh Lock filesystem before starting superblock reset
2005-04-26 dlb Add 2K page support.
2005-04-13 dlb Fix testapp build for remote.
2005-04-06 nrs Removed fs_diag dependencies from Unit Test
2005-03-28 dlb Move unref of mkdir vp up one level.
2005-02-17 dlb Remove transaction mention from mkdir.
2005-01-27 dlb Allow standalone builds.
2004-11-02 dlb Remove all mention of transactions here.
2004-10-21 nrs Modified fs_public_desc_write() to not use transactions
2004-10-13 dlb Fixed flush outside of xact on unlink.
2004-10-12 dlb Add remote EFS client support.
2004-10-11 nrs Modified rename to work with files that currently exist
2004-10-11 nrs Modified unlink to remove transaction calls
2004-10-07 nrs Changed efs_put, efs_get to efs_raw_put, efs_raw_get
2004-10-07 dlb Whitespace cleanup.
2004-07-26 dlb Support extfs.
2004-07-19 dlb Restructure vnode interface.
2004-02-20 dlb Disallow renames of symlinks.
2003-11-18 gr Restored call to FS_GLOBAL_UNLOCK in efs_rename.
2003-10-22 dlb Fix error code on write of 0 bytes.
2003-09-09 dlb Factory image works with bitmap and tree.
2003-08-20 dlb Remove delayed truncate code.
2003-07-26 gr Modified efs_lseek to return an error if an attempt to
seek before the beginning of the file is made.
2003-07-23 gr Added check in ftruncate to return an error if the input
file was opened in read-only mode.
2003-06-17 jkl Clean up code.
2003-06-13 gr Modified efs_unlink and efs_rmdir to return an error if
the file or directory being deleted is open.
2003-06-12 adm Add support for factory start.
2003-06-12 cr Featurize testapp init.
2003-05-30 gr Fixed a bug in efs_open. Modified efs_rename to return
failure if called on a directory.
2003-05-23 cr Add initialization of on target test application.
The init won't happen unless one takes a breakpoint in
debugger and changes state on static variables.
2003-05-16 gr Fixed a bug in efs_rename.
2003-05-02 gr Added master reset functionality.
2003-04-15 cr Moved global lock to fs_efs2.h as part of delayed
truncation implementation to fix CR#28410.
2003-03-24 gr Code modifications to ensure that all writes to flash
have transaction wrappers.
2003-03-12 gr Implemented efs_rename.
2003-03-06 bgc Moved vnode flush to inside the transaction in
fs_public_desc_write().
2003-03-04 gr Renamed the parameters to efs_rename so that the C++
reserved word "new" is not used.
2002-08-20 adm Created.
===========================================================================*/
#include
#include
#include
#include "fs_sys_types.h"
#include "fs_err.h"
#include "fs_fcntl.h"
#include "fs_errno.h"
#include "fs_public.h"
#include "fs_desc.h"
#include "fs_vnode.h"
#include "fs_namei.h"
#include "fs_mount.h"
#include "fs_efs2.h"
#include "fs_romfs.h"
#include "fs_nodev.h"
#include "fs_db.h"
#include "fs_timetest2.h"
#include "fs_hotplug.h"
#include "fs_benchmark.h"
#include "fs_upgrade.h"
#include "fs_pathbuff.h"
#include "fs_stdio.h"
#include "fs_privatedir.h"
#include "jzap.h"
#ifdef FEATURE_EFS_EXTFS
#include "fs_extfs.h"
#endif
#ifdef FS_FEATURE_RMTEFS_CLIENT
#include "fs_rmtefs.h"
#endif
#ifndef FS_STANDALONE
/* FS_GLOBAL_LOCK critical section definition memory allocation */
rex_crit_sect_type fs_crit_sect;
#endif /*FS_STANDALONE*/
#ifdef FS_STANDALONE
int efs_errno = 0;
#endif
struct nameidata nameidata_buffer;
struct nameidata nameidata_buf2;
/* Vops. */
static int fs_public_desc_close (struct fs_descriptor *file);
static fs_ssize_t fs_public_desc_write (struct fs_descriptor *file,
const void *buf, fs_size_t count);
static fs_ssize_t fs_public_desc_read (struct fs_descriptor *file,
void *buf, fs_size_t count);
static struct desc_ops public_desc_ops = {
fs_public_desc_close,
fs_public_desc_write,
fs_public_desc_read,
};
/**********************************************************************
* Iterators.
*
* All iterators are allocated and deallocated from a common pool. We make
* the assumption that there will not be many iterators in use.
*/
struct fs_dir_data {
int busy;
void *iter;
struct fs_dirent dirent;
struct fs_mount *mp;
struct fs_vnode *vp;
};
static struct fs_dir_data all_iters[FS_MAX_ITERATORS];
#ifdef FEATURE_EFS_COMPATIBILITY
extern void fs_compat_init (void);
#endif /* FEATURE_EFS_COMPATIBILITY */
#ifndef FEATURE_IG_EFS_EXT_SERVER
extern void fs_diag_init (void);
#endif
/* Data for exceptions. */
struct efs_catch_block *_fs_catch = NULL;
struct efs_catch_block _fs_static_catch;
/***********************************************************************
FUNCTION efs_initialize
DESCRIPTION This function should be called to mount the
root file system. It calls the start function specified
in the fs_mount_ops structure to do the actual initialization
where both the file system and the dbtree are initialized.
DEPENDENCIES
RETURN VALUE If the mount was successful 0, else the error no.
SIDE EFFECTS
**********************************************************************/
int
efs_initialize ()
{
int result;
int i;
FS_GLOBAL_LOCK_INIT();
FS_PATH_BUFF_LOCK_INIT();
EFS_TT_API (EFS_TT_INITIALIZE);
_fs_catch = NULL;
#ifdef FEATURE_JZAP
zap_init();
#endif
fs_upgrade_init ();
fs_desc_init ();
fs_vnode_init ();
fs_mount_init ();
fs_efs2_init ();
fs_romfs_init ();
fs_nodevfs_init ();
#ifdef FS_FEATURE_RMTEFS_CLIENT
fs_rmtefs_init ();
#endif
#ifdef FEATURE_EFS_EXTFS
fs_extfs_init ();
#endif
/* Mount the root filesystem. */
result = fs_mount_root ("EFS2", "");
if (result != 0)
FS_ERR_FATAL ("No flash device found", 0, 0, 0);
/* All of the iterators are available. */
for (i = 0; i < FS_MAX_ITERATORS; i++)
all_iters[i].busy = 0;
#ifdef FEATURE_EFS_COMPATIBILITY
fs_compat_init ();
#endif /* FEATURE_EFS_COMPATIBILITY */
#ifndef FEATURE_IG_EFS_EXT_SERVER
fs_diag_init ();
#endif
fs_benchmark_init();
fs_cpu_hog_init();
#ifdef FEATURE_L4
efs_mkdir ("/export", 0755);
#endif /* FEATURE_L4 */
#if defined FEATURE_EFS_HOTPLUG || defined FEATURE_EFS_COLDPLUG
hotplug_init ();
#endif
#if defined(FS_FEATURE_RMTEFS_CLIENT) && defined(FEATURE_EXTERNAL_APPS_MOUNT)
efs_mkdir ("/apps", 0755);
efs_mount ("0", "/apps", "rmtefs", 0, "/");
#endif
/* create the efs's private meta-data folder */
efs_privatedir_init ();
/* Initialize stdio related functions */
efs_stdio_init ();
return result;
}
/***********************************************************************
FUNCTION efs_power_down
DESCRIPTION This function calls the file system finalize function to
make sure the shut down is handled correctly and normally.
DEPENDENCIES None
RETURN VALUE If the shut down was successful 0.
SIDE EFFECTS None
**********************************************************************/
int
efs_power_down ()
{
EFS_TT_API (EFS_TT_POWER_DOWN);
/* XXX: Should unmount everything. */
return fs_root_mpoint->ops->stop (fs_root_mpoint);
}
/* Open/create a file. */
int
efs_open (const char *path, int oflag, ...)
{
fs_mode_t mode = 0;
struct nameidata *ndp = &nameidata_buffer;
int result = 0;
struct fs_descriptor *file = 0;
/* Posix requires the optional third argument for the mode. Extract this
* if we are creating a file.
* Lint is so very very confused by va_arg. Suppress everything it finds. */
/*lint -save -e746 -e10 -e64 -e718 -e529 */
if ((oflag & O_CREAT) != 0)
{
va_list arg;
va_start (arg, oflag);
mode = va_arg (arg, int);
va_end (arg);
}
/*lint -restore */
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_OPEN, path);
EFS_TT_VALUE (EFS_TT_OPEN, (uint32) oflag, FALSE, FALSE, TRUE);
/* Allocate a descriptor. */
file = fs_desc_alloc ();
if (file == NULL) {
efs_errno = EMFILE;
goto error_case;
}
result = fs_namei (ndp, path, oflag);
if (result != 0) {
goto error_case;
}
/* Don't allow open on device special files */
if (ndp->vp && (S_ISBLK(ndp->vp->mode) || S_ISCHR(ndp->vp->mode))) {
efs_errno = EEXIST;
fs_vnode_unref (ndp->dvp);
fs_vnode_unref (ndp->vp);
goto error_case;
}
/* If the name lookup succeeds, return an error if the user is attempting
* to open a directory with O_WRONLY or O_RDWR specified.
*/
if ((ndp->vp != NULL) && S_ISDIR (ndp->vp->mode) &&
((oflag & O_RDWR) || (oflag & O_WRONLY))) {
efs_errno = EISDIR;
fs_vnode_unref (ndp->dvp);
fs_vnode_unref (ndp->vp);
goto error_case;
}
/* fs_namei already checked the open flags for O_CREAT and O_EXCL, so, if
* we get this far, we can either create, or open the file. */
if (ndp->vp == NULL) {
result = ndp->dvp->vops->create (ndp, mode);
if (result < 0) {
fs_vnode_unref (ndp->dvp);
goto error_case;
}
}
/* Now, ndp->vp points to our file. We don't need the directory any
* more, so unreference that. */
fs_vnode_unref (ndp->dvp);
ndp->dvp = 0;
/* If the file should be truncated (and was opened for writing). */
if ((oflag & O_TRUNC) &&
(((oflag & O_ACCMODE) + 1 ) & 2) != 0)
{
result = ndp->vp->vops->truncate (ndp->vp, 0);
/* XXX: What do we do if there was a problem truncating the file? */
}
/* XXX: Handle different operation types. */
/* Fill in the descriptor */
file->state = FS_DESC_STATE_FILE;
/* Move the referenced vnode into the descriptor. */
file->vp = ndp->vp;
ndp->vp = 0;
file->mode = oflag;
file->file_pos = 0;
file->dops = &public_desc_ops;
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (file->fd);
return file->fd;
error_case:
if (file != NULL)
fs_desc_free (file);
if (result < 0)
efs_errno = -result;
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (-result);
return -1;
}
static fs_ssize_t
_efs_read_core (int filedes, void *buf, fs_size_t nbyte)
{
struct fs_descriptor *desc_ptr;
int result;
FS_GLOBAL_LOCK ();
if ((desc_ptr = fs_desc_lookup (filedes)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
return -1;
}
result = desc_ptr->dops->read (desc_ptr, buf, nbyte);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return result;
}
fs_ssize_t
efs_read (int filedes, void *buf, fs_size_t nbyte)
{
fs_ssize_t result;
EFS_TT_API (EFS_TT_READ);
EFS_TT_VALUE (EFS_TT_READ, (uint16)filedes, TRUE, TRUE, FALSE);
EFS_TT_VALUE (EFS_TT_READ, (uint32)nbyte, TRUE, TRUE, TRUE);
result = _efs_read_core (filedes, buf, nbyte);
EFS_TT_RETURN (result);
return result;
}
static fs_ssize_t
fs_public_desc_read (struct fs_descriptor *file,
void *buf, fs_size_t count)
{
fs_ssize_t result;
/* Check permissions, use the same trick described in
* fs_public_desc_write. */
if ((((file->mode & O_ACCMODE) + 1) & 1) == 0) {
return -EBADF;
}
/* Do the actual read. */
if (count > 0)
result = file->vp->vops->read (file->vp, file->file_pos, buf, count);
else
result = 0;
/* Adjust the file pointer. */
if (result > 0) {
file->file_pos += result;
}
return result;
}
static fs_ssize_t
_efs_write_core (int filedes, const void *buf, fs_size_t nbyte)
{
struct fs_descriptor *desc_ptr;
int result;
/* Just return if asked to write zero bytes.
*/
if (nbyte == 0)
return 0;
FS_GLOBAL_LOCK ();
if ((desc_ptr = fs_desc_lookup (filedes)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
return -1;
}
result = desc_ptr->dops->write (desc_ptr, buf, nbyte);
FS_GLOBAL_UNLOCK ();
/* It is not an error to write fewer bytes than requested. However, we
* consider it an error if not even one byte could be written.
*/
if (result <= 0) {
if (result == 0)
result = -ENOSPC;
efs_errno = -result;
return -1;
} else
return result;
}
fs_ssize_t
efs_write (int filedes, const void *buf, fs_size_t nbyte)
{
fs_ssize_t result;
EFS_TT_API (EFS_TT_WRITE);
EFS_TT_VALUE (EFS_TT_WRITE, (uint16)filedes, TRUE, TRUE, FALSE);
EFS_TT_VALUE (EFS_TT_WRITE, (uint32)nbyte, TRUE, TRUE, TRUE);
result = _efs_write_core (filedes, buf, nbyte);
EFS_TT_RETURN (result);
return result;
}
static fs_ssize_t
fs_public_desc_write (struct fs_descriptor *file,
const void *buf, fs_size_t count)
{
fs_ssize_t result;
/* Check that we have permissions to write this file. This depends on
* the specific values of O_RDONLY=0, O_WRONLY=1, and O_RDWR=2 that posix
* use. By adding 1, the value is just a pair of bits with the lowest
* bit indicating read, the the next bit indicating write. Neat, isn't
* it. */
if ((((file->mode & O_ACCMODE) + 1) & 2) == 0) {
return -EBADF;
}
/* Check for the append case. In append, all writes always seek to the
* end of the file. */
if ((file->mode & O_APPEND) != 0) {
file->file_pos = FS_OFFSET_APPEND;
}
/* Do the actual write. */
if (count > 0) {
result = file->vp->vops->write (file->vp, file->file_pos, buf, count);
/* Adjust the file pointer appropriately. */
/* XXX: This won't have the correct value if the file is opened in
* append mode. */
if (result > 0) {
file->file_pos += result;
}
}
else
result = 0;
return result;
}
/* efs_mkdir */
int
efs_mkdir (const char *path, fs_mode_t mode)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_MKDIR, path);
result = fs_namei (ndp, path, O_EXCL | O_CREAT);
if (result < 0)
{
goto clean_up;
}
result = ndp->dvp->vops->mkdir (ndp, mode);
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
clean_up:
EFS_TT_RETURN (-result);
FS_GLOBAL_UNLOCK ();
if (result == 0)
return 0;
else {
efs_errno = -result;
return -1;
}
}
int
efs_creat (const char *path, fs_mode_t mode)
{
EFS_TT_API (EFS_TT_CREAT);
return efs_open (path, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
int
efs_close (int filedes)
{
struct fs_descriptor *desc_ptr;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_VALUE (EFS_TT_CLOSE, (uint16)filedes, TRUE, TRUE, FALSE);
/* Check if file descriptor is valid */
if ((desc_ptr = fs_desc_lookup (filedes)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
return -1;
}
result = desc_ptr->dops->close (desc_ptr);
fs_desc_free (desc_ptr);
FS_GLOBAL_UNLOCK ();
return result;
}
/* Close handler for filesystem (through vnode) operations. */
static int
fs_public_desc_close (struct fs_descriptor *file)
{
/* Dereference the vnode. There should be no need to flush. */
file->state = 0;
fs_vnode_unref (file->vp);
file->vp = 0;
return 0;
}
fs_off_t
efs_lseek (int filedes, fs_off_t offset, int whence)
{
struct fs_descriptor *desc_ptr;
fs_off_t base;
static struct fs_stat sbuf;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_VALUE (EFS_TT_LSEEK, (uint16)filedes, TRUE, TRUE, FALSE);
EFS_TT_VALUE (EFS_TT_LSEEK, (uint32)offset, TRUE, TRUE, TRUE);
/* Check if file descriptor is valid */
if ((desc_ptr = fs_desc_lookup (filedes)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (-EBADF);
return -1;
}
/* This is only valid with files. */
if (desc_ptr->state != FS_DESC_STATE_FILE) {
efs_errno = ESPIPE;
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (-ESPIPE);
return -1;
}
switch (whence) {
case SEEK_SET:
base = 0;
break;
case SEEK_CUR:
base = desc_ptr->file_pos;
break;
case SEEK_END:
// base = desc_ptr->vp->size;
result = desc_ptr->vp->vops->getstat (desc_ptr->vp, &sbuf);
if (result != 0) {
efs_errno = -result;
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (-efs_errno);
return -1;
}
base = sbuf.st_size;
break;
default:
EFS_TT_RETURN (-EINVAL);
FS_GLOBAL_UNLOCK ();
efs_errno = EINVAL;
return -1;
}
if (base + offset >= 0) {
desc_ptr->file_pos = base + offset;
base = desc_ptr->file_pos;
}
else {
efs_errno = EINVAL;
base = -1;
}
FS_GLOBAL_UNLOCK ();
EFS_TT_RETURN (base);
return base;
}
fs_off_t
efs_truncate (const char *path, fs_off_t length)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_API (EFS_TT_TRUNCATE);
result = fs_namei (ndp, path, 0);
if (result != 0)
goto error_case;
result = ndp->vp->vops->truncate (ndp->vp, length);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
}
fs_off_t
efs_ftruncate (int fd, fs_off_t length)
{
struct fs_descriptor *desc;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_API (EFS_TT_FTRUNCATE);
desc = fs_desc_lookup (fd);
if (desc == NULL) {
result = -EBADF;
goto clean_up;
}
/* Check that we have permissions to write this file. Use the trick
* described in fs_public_desc_write.
*/
if ((((desc->mode & O_ACCMODE) + 1) & 2) == 0) {
result = -EINVAL;
goto clean_up;
}
result = desc->vp->vops->truncate (desc->vp, length);
clean_up:
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return result;
}
int
efs_stat (const char *path, struct fs_stat *buf)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
struct fs_vnode *vp;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_STAT, path);
result = fs_namei (ndp, path, 0);
if (result != 0)
goto error_case;
vp = ndp->vp;
result = vp->vops->getstat (vp, buf);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
EFS_TT_RETURN(-result);
efs_errno = -result;
return -1;
} else
return 0;
}
int
efs_fstat (int fd, struct fs_stat *buf)
{
struct fs_descriptor *desc_ptr;
struct fs_vnode *vp;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_VALUE (EFS_TT_FSTAT, (uint16)fd, TRUE, TRUE, FALSE);
/* Check if file descriptor is valid */
if ((desc_ptr = fs_desc_lookup (fd)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
return -1;
}
/* This is only valid with files. */
if (desc_ptr->state != FS_DESC_STATE_FILE) {
efs_errno = ESPIPE;
FS_GLOBAL_UNLOCK ();
return -1;
}
vp = desc_ptr->vp;
result = vp->vops->getstat (vp, buf);
FS_GLOBAL_UNLOCK ();
if (result == 0)
return 0;
else {
efs_errno = -result;
return -1;
}
}
int
efs_lstat (const char *path, struct fs_stat *buf)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
struct fs_vnode *vp;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_LSTAT, path);
result = fs_namei (ndp, path, O_NOFOLLOW);
if (result != 0)
goto error_case;
vp = ndp->vp;
result = vp->vops->getstat (vp, buf);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
EFS_TT_RETURN (-result);
efs_errno = -result;
return -1;
} else
return 0;
} /* efs_lstat */
int
efs_statvfs (const char *path, struct fs_statvfs *buf)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
struct fs_vnode *vp;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_STATVFS, path);
result = fs_namei (ndp, path, 0);
if (result != 0)
goto error_case;
vp = ndp->vp;
result = vp->vops->getstatvfs (vp, buf);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
EFS_TT_RETURN (-result);
efs_errno = -result;
return -1;
}
return 0;
} /* END efs_statvfs */
int
efs_fstatvfs(int fd, struct fs_statvfs *buf)
{
struct fs_descriptor * desc_ptr;
struct fs_vnode * vp;
int result;
FS_GLOBAL_LOCK();
EFS_TT_API (EFS_TT_FSTATVFS);
/*Check if file descriptor is valid*/
if ((desc_ptr = fs_desc_lookup (fd)) == NULL)
{
efs_errno = EBADF;
FS_GLOBAL_UNLOCK ();
return -1;
}
/* This is only valid with files. */
if (desc_ptr->state != FS_DESC_STATE_FILE) {
efs_errno = ESPIPE;
FS_GLOBAL_UNLOCK ();
return -1;
}
vp = desc_ptr->vp;
result = vp->vops->getstatvfs (vp, buf);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
}
return 0;
}
int
efs_unlink (const char *path)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_UNLINK, path);
result = fs_namei (ndp, path, O_NOFOLLOW);
if (result != 0) {
goto error_case;
}
if (!S_ISREG (ndp->vp->mode) && !S_ISLNK (ndp->vp->mode) &&
!S_ISBLK (ndp->vp->mode) && !S_ISCHR (ndp->vp->mode) &&
!S_ISITM (ndp->vp->mode)) {
/* Posix actually says to return EPERM for this case. EISDIR seems to
* make more sense, but we'll comply with Posix. */
result = -EPERM;
fs_vnode_unref (ndp->vp);
goto error_case;
}
if (S_ISREG (ndp->vp->mode)) {
/* If the file is already open, return an error.
* XXX: This is not ideal behavior. At some point, we should handle
* unlinking open files.
*/
if (fs_vnode_getref (ndp->vp) > 1) {
result = -ETXTBSY;
fs_vnode_unref (ndp->vp);
goto error_case;
}
}
result = ndp->dvp->vops->unlink (ndp);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
/* The entry vnode was unreferenced by the unlink operation itself. */
FS_GLOBAL_UNLOCK ();
if (result < 0) {
EFS_TT_RETURN(-result);
efs_errno = -result;
return -1;
} else
return 0;
} /* END efs_unlink */
EFSDIR *
efs_opendir (const char *dirname)
{
int i;
EFSDIR *iter;
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_OPENDIR, dirname);
for (i = 0; i < FS_MAX_ITERATORS; i++) {
if (!all_iters[i].busy)
break;
}
if (i == FS_MAX_ITERATORS) {
efs_errno = EMFILE;
EFS_TT_RETURN (-EMFILE);
FS_GLOBAL_UNLOCK ();
return NULL;
}
iter = &all_iters[i];
result = fs_namei (ndp, dirname, 0);
if (result != 0) {
iter->iter = NULL;
goto error_case;
}
iter->iter = ndp->vp->vops->opendir (ndp->vp);
if (iter->iter == NULL) {
fs_vnode_unref (ndp->vp);
result = -ENOTDIR;
} else {
iter->busy = 1;
/* Copy the reference in, so don't unref it until close. */
iter->vp = ndp->vp;
iter->mp = ndp->vp->mp;
}
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
EFS_TT_RETURN (-result);
return NULL;
} else
return iter;
}
struct fs_dirent *
efs_readdir (EFSDIR *dirp)
{
int result;
FS_GLOBAL_LOCK ();
EFS_TT_API (EFS_TT_READDIR);
if (dirp == NULL || !dirp->busy) {
FS_GLOBAL_UNLOCK ();
efs_errno = EINVAL;
EFS_TT_RETURN (-EINVAL);
return 0;
}
result = dirp->vp->vops->readdir (dirp->vp, dirp->iter,
&dirp->dirent);
FS_GLOBAL_UNLOCK ();
if (result == -EEOF) {
dirp->dirent.d_name[0] = '\0';
EFS_TT_RETURN (-EEOF);
return 0;
}
else if (result < 0) {
EFS_TT_RETURN (-result);
efs_errno = -result;
return 0;
} else {
return &dirp->dirent;
}
}
int
efs_closedir (EFSDIR *dirp)
{
int result;
FS_GLOBAL_LOCK ();
EFS_TT_API (EFS_TT_CLOSEDIR);
if (dirp == NULL || !dirp->busy) {
FS_GLOBAL_UNLOCK ();
efs_errno = EINVAL;
return -1;
}
result = dirp->vp->vops->closedir (dirp->vp, dirp->iter);
dirp->busy = 0;
fs_vnode_unref (dirp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
}
int
efs_rename (const char *oldpath, const char *newpath)
{
struct nameidata *ndp1 = &nameidata_buffer;
struct nameidata *ndp2 = &nameidata_buf2;
int result;
struct fs_stat sbuf;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_RENAME, oldpath);
EFS_TT_PRINT (EFS_TT_RENAME, newpath);
ndp1->dvp = ndp1->vp = NULL;
ndp2->dvp = ndp2->vp = NULL;
result = fs_namei (ndp1, oldpath, O_NOFOLLOW);
if (result == 0) {
result = ndp1->vp->vops->getstat (ndp1->vp, &sbuf);
if (result == 0 && (sbuf.st_mode & S_IFMT) != S_IFREG) {
EFS_TT_RETURN (-EISDIR);
result = -EISDIR;
}
}
if (result == 0) {
result = fs_namei (ndp2, newpath, O_CREAT);
}
if (result == 0) {
result = ndp1->dvp->vops->rename (ndp1, ndp2);
}
/* rename call unrefs on error. */
if (ndp1->dvp != NULL) {
fs_vnode_unref (ndp1->dvp);
}
if (ndp1->vp != NULL) {
fs_vnode_unref (ndp1->vp);
}
if (ndp2->dvp != NULL) {
fs_vnode_unref (ndp2->dvp);
}
if (ndp2->vp != NULL) {
fs_vnode_unref (ndp2->vp);
}
if (result != 0) {
EFS_TT_RETURN (-result);
efs_errno = -result;
result = -1;
}
FS_GLOBAL_UNLOCK ();
return result;
}
int
efs_rmdir (const char *path)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_RMDIR, path);
result = fs_namei (ndp, path, 0);
if (result != 0)
goto error_case;
/* If they try to delete '.', or '..', or trailing slash. */
if (ndp->vp == ndp->dvp ||
(ndp->length == 2 && ndp->next[0] == '.' && ndp->next[1] == '.'))
{
result = -EINVAL;
goto error_case;
}
result = ndp->dvp->vops->rmdir (ndp);
if (result != 0)
fs_vnode_unref (ndp->vp);
ndp->vp = NULL;
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
} /* END efs_rmdir */
int
efs_chmod (const char *path, fs_mode_t mode)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
EFS_TT_API (EFS_TT_CHMOD);
FS_GLOBAL_LOCK ();
/* Check to see if the path is valid */
result = fs_namei (ndp, path, 0);
/* If file exists, change the mode on this vp */
if (result == 0)
result = ndp->vp->vops->chmod (ndp->vp, mode);
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
efs_errno = -result;
return -1;
}
else
return 0;
} /* END efs_chmod */
/**********************************************************************
* Mountpoints.
*/
int
efs_mount (const char *special, const char *dir,
const char *fstype, int flags, const void *data)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
(void) flags;
(void) special;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_MOUNT, dir);
result = fs_namei (ndp, dir, 0);
if (result == 0 && !S_ISDIR (ndp->vp->mode)) {
result = -ENOTDIR;
}
if (result == 0) {
result = fs_mount_mount (ndp->vp, fstype, data);
}
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
}
int
efs_umount (const char *target)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
struct fs_mount *mp = NULL;
int i;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_UMOUNT, target);
result = fs_namei (ndp, target, 0);
if (result == 0) {
result = fs_mount_umount (ndp->vp);
mp = ndp->vp->mp;
}
if (result == 0 && mp != NULL) {
fs_desc_make_nodev (mp);
/* printf ("umount ref = %d\n", ndp->vp->ref); */
fs_vnode_make_nodev (ndp->vp);
/* Cleanup any iterators. */
for (i = 0; i < FS_MAX_ITERATORS; i++) {
if (all_iters[i].busy &&
all_iters[i].vp != NULL &&
all_iters[i].mp == mp)
{
/* If this vnode hasn't been obliterated already, clean it up. */
if (all_iters[i].vp->mp == mp)
fs_vnode_make_nodev (all_iters[i].vp);
}
}
}
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
#ifdef FS_UNIT_TEST
#error code not present
#endif
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
}
int
efs_remount (const char *oldtarget, const char *newtarget)
{
int result;
struct nameidata *ndp1 = &nameidata_buffer;
struct nameidata *ndp2 = &nameidata_buf2;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_REMOUNT, oldtarget);
EFS_TT_PRINT (EFS_TT_REMOUNT, newtarget);
ndp1->dvp = ndp1->vp = NULL;
ndp2->dvp = ndp2->vp = NULL;
result = fs_namei (ndp1, oldtarget, 0);
if (result == 0 && !S_ISDIR (ndp1->vp->mode)) {
result = -EINVAL;
}
if (result == 0) {
result = fs_namei (ndp2, newtarget, 0);
}
if (result == 0 && !S_ISDIR (ndp2->vp->mode)) {
result = -ENOTDIR;
}
if (result == 0) {
result = fs_mount_remount (ndp1->vp, ndp2->vp);
}
if (ndp1->dvp != NULL) {
fs_vnode_unref (ndp1->dvp);
}
if (ndp1->vp != NULL) {
fs_vnode_unref (ndp1->vp);
}
if (ndp2->dvp != NULL) {
fs_vnode_unref (ndp2->dvp);
}
if (ndp2->vp != NULL) {
fs_vnode_unref (ndp2->vp);
}
if (result != 0) {
efs_errno = -result;
result = -1;
}
FS_GLOBAL_UNLOCK ();
return result;
}
int
efs_symlink (const char *oldpath, const char *newpath)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_SYMLINK, oldpath);
EFS_TT_PRINT (EFS_TT_SYMLINK, newpath);
result = fs_namei (ndp, newpath, O_EXCL | O_CREAT | O_NOFOLLOW);
if (result < 0) {
goto error_case;
}
result = ndp->dvp->vops->symlink (ndp, oldpath);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return 0;
}
int
efs_readlink (const char *path, char *buf, fs_size_t bufsiz)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_READLINK, path);
result = fs_namei (ndp, path, O_NOFOLLOW);
if (result < 0) {
goto error_case;
}
result = ndp->vp->vops->readlink (ndp->vp, buf, bufsiz);
error_case:
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return result;
}
int
efs_access (const char *path, int amode)
{
(void) path;
(void) amode;
/* efs_access is not implemented in EFS2. At this point, there is no
* intent on doing so. It is part of a security model not well suited to
* mobile devices. */
EFS_TT_API (EFS_TT_ACCESS);
efs_errno = EINVAL;
return -1;
}
int
efs_mknod (const char *path, int mode, fs_devspecial_t dev)
{
struct nameidata *ndp = &nameidata_buffer;
int result = 0;
FS_GLOBAL_LOCK();
EFS_TT_PRINT (EFS_TT_MKNOD, path);
result = fs_namei (ndp, path, O_EXCL | O_CREAT);
/* If the name lookup succeeds, the file already exists */
if (ndp->vp != NULL)
result = -EEXIST;
/* Just attempt to create the device file (XXX ndp->dvp safe???)*/
if (result == 0)
result = ndp->dvp->vops->mknod (ndp, mode, dev);
/* Done. */
if (ndp->dvp)
fs_vnode_unref (ndp->dvp);
if (ndp->vp)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result != 0) {
efs_errno = -result;
result = -1;
}
return result;
}
/**********************************************************************
* FUNCTION efs_raw_put
*
* Store a value in a special item file.
*/
int
efs_raw_put (const char *path, void *data, fs_size_t length,
int oflag, int mode)
{
struct nameidata *ndp = &nameidata_buffer;
int result = 0;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_RAW_PUT, path);
if (result == 0)
result = fs_namei (ndp, path, oflag);
if (result == 0 && ndp->vp) {
/* Verify that if we did recover a 'node' that it is really an item
* type. */
if (!S_ISITM (ndp->vp->mode))
result = -EEXIST;
}
if (result == 0) {
result = ndp->dvp->vops->put_item (ndp, data, length, mode);
}
if (ndp->dvp) {
fs_vnode_unref (ndp->dvp);
}
if (ndp->vp)
fs_vnode_unref (ndp->vp);
if (result != 0) {
efs_errno = -result;
result = -1;
}
FS_GLOBAL_UNLOCK ();
return result;
}
/* Read contents of item. */
int
efs_raw_get (const char *path, void *data, fs_size_t length)
{
struct nameidata *ndp = &nameidata_buffer;
int result;
struct fs_vnode *vp;
FS_GLOBAL_LOCK ();
EFS_TT_PRINT (EFS_TT_RAW_GET, path);
result = fs_namei (ndp, path, 0);
if (result == 0) {
vp = ndp->vp;
result = vp->vops->get_item (vp, data, length);
}
if (ndp->dvp != NULL)
fs_vnode_unref (ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref (ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else
return result;
}
/***********************************************************************
* FUNCTION efs_wait_for_xact
*
* DESCRIPTION This function waits for a transaction to finish.
*
************************************************************************/
void
efs_wait_for_xact (void)
{
EFS_TT_API (EFS_TT_WAIT_FOR_XACT);
FS_GLOBAL_LOCK();
} /* efs_wait_for_xact */
/**********************************************************************
* FUNCTION efs_reset
*
* DESCRIPTION
* Resets the filesystem and stops the system. The mobile must be
* rebooted before it can be used again.
************************************************************************/
void
efs_reset (void)
{
/* Invalidate all superblocks and halt the system. This will force a
* fresh start on the next reboot.
*
* Make sure we prevent all filesystem operations until we reboot, so we
* don't trip on the inconsistent state while the erase is running.
*/
FS_GLOBAL_LOCK();
EFS_TT_API (EFS_TT_RESET);
fs_pm_super_invalidate_superblocks ();
#if defined(FEATURE_FS_REMOTE_APPS_PROC) && defined(FEATURE_REMOTE_EFS_RESET)
/* For dual proc targets, also reset efs on the modem processor */
remote_efs_reset ();
#endif
FS_ERR_FATAL ("filesystem reset. reboot needed", 0, 0, 0);
} /* efs_reset */
/***********************************************************************
* FUNCTION efs_reset_nostop (void)
*
* DESCRIPTION
* Same as efs_reset, except that it returns. Should only be used from
* within the FS_ERR_FATAL handler.
*/
void
efs_reset_nostop (void)
{
EFS_TT_API (EFS_TT_RESET_NOSTOP);
fs_pm_super_invalidate_superblocks ();
}
/***********************************************************************
FUNCTION efs_get_fs_data
DESCRIPTION
DEPENDENCIES None
RETURN VALUE If successful, returns 0.
Otherwise, returns -1, and sets errno to indicate the error.
SIDE EFFECTS None
**********************************************************************/
extern int fs_get_fs_data(struct fs_factimage_read_info * read_info_ptr,
byte * page_buffer);
int
efs_get_fs_data (struct fs_factimage_read_info * image_info_ptr,
byte* page_buffer)
{
int result;
EFS_TT_API (EFS_TT_GET_FS_DATA);
if (image_info_ptr == NULL) {
efs_errno = EINVAL;
return -1;
}
if (image_info_ptr->stream_state < 0) {
efs_errno=EINVAL;
return -1;
}
FS_GLOBAL_LOCK ();
result = fs_get_fs_data(image_info_ptr, page_buffer);
FS_GLOBAL_UNLOCK ();
if (result < 0) {
efs_errno = -result;
return -1;
} else {
return 0;
}
} /* end of efs_get_fs_data */
/***********************************************************************
* FUNCTION efs_get_device_info
*
* DESCRIPTION This function will get the attributes of the flash device
*
* DEPENDENCIES None
*
* RETURN VALUE If successful efs_access will return zero else -1.
*
* SIDE EFFECTS None
***********************************************************************/
extern int fs_get_device_attr(struct fs_device_attr * dev_attr);
int
efs_get_device_info (struct fs_device_attr * dev_attr)
{
int result;
EFS_TT_API (EFS_TT_GET_DEVICE_INFO);
result = fs_get_device_attr(dev_attr);
return result;
} /* efs_get_device_info */
/***********************************************************************
* FUNCTION
* efs_image_prepare
*
* DESCRIPTION
* Make progress toward preparing this image for a factory dump. This
* does a small amount of work, of whatever kind is needed to prepare to
* make an exportable image of this filesystem. This function should be
* called repeatedly until it returns that there is no work left to do.
*
* RETURN VALUE
* Returns a count indicating any additional work. This number should
* only be compared against zero. Positive indicates that there is work
* to do, and negative indicates an error has occured.
***********************************************************************/
/* XXX: To support multiple filesystems, this function needs to take an
* argument to indicate which FS to use. */
int
efs_image_prepare (void)
{
extern int fs_efs2_image_prepare (void);
EFS_TT_API (EFS_TT_IMAGE_PREPARE);
return fs_efs2_image_prepare ();
}
/*************************************************************************
*
* efs_chown
*
* change the owner and/or group id
*
*/
int
efs_chown (const char *path, int uid_val, int gid_val)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
result = 0;
FS_GLOBAL_LOCK ();
/* Check to see if the path is valid */
result = fs_namei (ndp, path, 0);
if (result != 0)
goto cleanup;
/* Everything checks out so let us change the group id */
result = ndp->vp->vops->chown(ndp->vp, uid_val, gid_val);
cleanup:
if (ndp->dvp != NULL)
fs_vnode_unref(ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref(ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
efs_errno = -result;
return -1;
}
else
return 0;
}
/*************************************************************************
*
* efs_set_reservation
*
* sets the amount of space for a reservation
*
*/
int
efs_set_reservation(const char *path, uint32 groupid, uint32 size)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
result = 0;
FS_GLOBAL_LOCK ();
result = fs_namei (ndp, path, 0);
if (result != 0)
goto cleanup;
/* Everything checks out so let us set the reservation
*/
result = ndp->vp->vops->set_reservation(ndp->vp, groupid, size);
cleanup:
if (ndp->dvp != NULL)
fs_vnode_unref(ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref(ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
efs_errno = -result;
return -1;
}
else
return 0;
}
/*************************************************************************
*
* efs_set_quota
*
* sets the quota limit
*
*/
int
efs_set_quota(const char *path, uint32 groupid, uint32 size)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
result = 0;
FS_GLOBAL_LOCK ();
/* We need a buffer to pass in updated values to the superblock so just
* get a buffer for where we are
*/
result = fs_namei (ndp, path, 0);
if (result != 0)
goto cleanup;
/* Everything checks out so let us set the quota
*/
result = ndp->vp->vops->set_quota(ndp->vp, groupid, size);
cleanup:
if (ndp->dvp != NULL)
fs_vnode_unref(ndp->dvp);
if (ndp->vp != NULL)
fs_vnode_unref(ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
efs_errno = -result;
return -1;
}
else
return 0;
}
/*************************************************************************
*
* efs_get_group_info
*
* gets the information for quotas and reservations for a specific group
* id
*
*/
int
efs_get_group_info(const char *path, uint32 groupid,
struct fs_group_info * ginfo)
{
int result;
struct nameidata *ndp = &nameidata_buffer;
result = 0;
FS_GLOBAL_LOCK ();
result = fs_namei (ndp, path, 0);
if (result != 0)
goto cleanup;
/* Everything checks out so let us get the reservation
*/
result = ndp->vp->vops->get_group_info(ndp->vp, groupid, ginfo);
cleanup:
if (ndp->vp != NULL)
fs_vnode_unref(ndp->vp);
FS_GLOBAL_UNLOCK ();
if (result < 0)
{
efs_errno = -result;
return -1;
}
else
return 0;
}