www.pudn.com > efs.rar > fs_ext_linux.c


/* Linux based external filesystem for EFS2.
 *
 * Copyright (C) 2004, 2005, 2006 Qualcomm, Inc.
 *
 * NOTE: Currently, this code is more of an example of how to use the EFS2
 * extfs functionality.  The only reason this is somewhat Linux specific is
 * that the values for the definitions are assumed to match between Linux
 * and EFS2.
 */

/* This is SAMPLE source code only. This file is not to be compiled
 * into any Qualcomm build. */
#if 0 /* EXAMPLE ONLY */

/*===========================================================================

                        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_ext_linux.c#5 $$ $$DateTime: 2006/05/08 11:49:02 $$ $$Author: davidb $$

when         who   what, where, why
----------   ---   ---------------------------------------------------------
2006-05-07   sh    Fixed hardalloc vs -1 compiler warning
2006-01-11   nrs   Fixed Copyright header
2005-12-22   dlb   Extensions to statvfs results.
2005-12-09   sh    Clarified status of Example Code
2005-06-06   dlb   Create

===========================================================================*/

#include "fs_extfs.h"
#include "fs_errno.h"
#include "fs_err.h"

/* Headers needed to get prototypes. */
#include 
#include 
#include 
#include 
#include 
#include 

/* This only works because these are defined with the same values. */
#include 

/* Can't bring in errno, since the definitions conflict with ours.  This is
 * very Linux specific. */
extern int *__errno_location (void) __attribute__ ((__const__));
#define errno (*__errno_location ())

/* These routines are all expected to return EFS2 error codes.  The return
 * result should either be 0 for success, or a negative error value. */

static int
e_linux_init (const char *name)
{
  (void) name;
  return 0;
}

/* base_stat:
 * Used to determine the fundamental type of the file.  For regular files,
 * it should also fill in the size of the file. */
static int
e_linux_base_stat (const char *name, fs_mode_t *mode, fs_size_t *size)
{
  struct stat sbuf;
  int result;

  result = lstat (name, &sbuf);
  if (result != 0)
    return -errno;              /* Remap... */

  *mode = sbuf.st_mode;
  *size = sbuf.st_size;

  return 0;
}

static int
e_linux_open (const char *name, int mode)
{
  int result;

  switch (mode) {
    case O_RDONLY:
    case O_RDWR:
      result = open (name, mode);
      break;

    case (O_CREAT | O_EXCL | O_RDWR):
      result = open (name, mode, 0644);
      break;

    default:
      FS_ERR_FATAL ("Invalid internal mode used", 0, 0, 0);
  }

  if (result < 0)
    result = -errno;

  return result;
}

static int
e_linux_lseek (int fd, fs_off_t pos)
{
  int result;

  result = lseek (fd, pos, SEEK_SET);
  if (result == (off_t) -1)
    result = -errno;
  return 0;
}

static int
e_linux_read (int fd, void *buf, fs_size_t count)
{
  int result;

  result = read (fd, buf, count);
  if (result < 0)
    result = -errno;
  return result;
}

static int
e_linux_write (int fd, const void *buf, fs_size_t count)
{
  int result;

  result = write (fd, buf, count);
  if (result < 0)
    result = -errno;
  return result;
}

static int
e_linux_close (int fd)
{
  int result;

  result = close (fd);
  if (result != 0)
    result = -errno;

  return result;
}

static int
e_linux_mkdir (const char *name)
{
  int result;

  result = mkdir (name, 0755);
  if (result != 0)
    result = -errno;
  return result;
}

static int
e_linux_rmdir (const char *name)
{
  int result;

  result = rmdir (name);
  if (result != 0)
    result = -errno;
  return result;
}

static int
e_linux_unlink (const char *name)
{
  int result;

  result = unlink (name);
  if (result != 0)
    result = -errno;
  return result;
}

static int
e_linux_rename (const char *oldname, const char *newname)
{
  int result;

  result = rename (oldname, newname);
  if (result != 0)
    result = -errno;
  return result;
}

static int
e_linux_statvfs (const char *name, struct fs_statvfs *buf)
{
  int result;
  struct statvfs pbuf;
  static uint32 avail_offset = 0;

  result = statvfs (name, &pbuf);

  if (result == 0) {
    /* Offset the size so that we don't try filling up the entire
     * filesystem. */
    if (avail_offset == 0) {
      avail_offset = pbuf.f_bavail - (120*1024*1024 / pbuf.f_bsize);
    }

    /* Copy the appropriate fields over. */
    buf->f_bsize = pbuf.f_bsize;
    buf->f_blocks = 128*1024*1024 / pbuf.f_bsize;
    buf->f_bfree = pbuf.f_bfree - avail_offset;
    buf->f_bavail = pbuf.f_bavail - avail_offset;
    buf->f_files = pbuf.f_files;
    buf->f_ffree = pbuf.f_ffree;
    buf->f_favail = pbuf.f_favail;
    buf->f_fsid = pbuf.f_fsid;
    buf->f_flag = pbuf.f_flag;
    buf->f_namemax = pbuf.f_namemax;
    buf->f_balloc = 0;
    buf->f_hardalloc = FS_INVALID_HARDALLOC;
  } else {
    /* Translate errno. */
    /* ... */
    result = -errno;
  }

  return result;
}

/* Directory operations. */
static void *
e_linux_opendir (const char *name)
{
  return opendir (name);
}

static int
e_linux_readdir (void *dir, char *name, int max_name)
{
  struct dirent *dent;

  dent = readdir (dir);
  if (dent != NULL) {
    if (strlen (dent->d_name) + 1 > (unsigned) max_name)
      /* Ideally, we want to be able to iterate past the name that is too
       * long. */
      return -ENAMETOOLONG;

    strcpy (name, dent->d_name);

    return 0;
  } else {
    return -EEOF;
  }
}

static int
e_linux_closedir (void *dir)
{
  int result;

  result = closedir (dir);
  if (result != 0)
    result = -errno;
  return result;
}

static int
e_linux_getstat (const char *name, struct fs_stat *buf)
{
  struct stat sbuf;
  int result;
  uint32 atime, ctime, mtime;

  result = lstat (name, &sbuf);
  if (result != 0) {
    return -errno;
  } else {
    /* Note that 'dev' and 'inum' aren't filled in.  They have already been
     * set to valid values, and can be left alone if they don't make sense.
     * Also, dev shouldn't be set, since we want the EFS2 internal value,
     * not the local filesystem's concept. */
    buf->st_mode = sbuf.st_mode;
    buf->st_nlink = sbuf.st_nlink;
    buf->st_size = sbuf.st_size;
    buf->st_blksize = sbuf.st_blksize;
    buf->st_blocks = sbuf.st_blocks;

    /* Ugh, the linux headers are annoying here. */
    atime = sbuf.st_atime;
    mtime = sbuf.st_mtime;
    ctime = sbuf.st_ctime;

#undef st_atime
#undef st_mtime
#undef st_ctime

    buf->st_atime = atime;
    buf->st_mtime = mtime;
    buf->st_ctime = ctime;

    return 0;
  }
}

struct fs_extfs_ops fs_linux_ops = {
  e_linux_init,
  e_linux_base_stat,
  e_linux_getstat,
  e_linux_open,
  e_linux_lseek,
  e_linux_read,
  e_linux_write,
  e_linux_close,
  e_linux_mkdir,
  e_linux_rmdir,
  e_linux_unlink,
  e_linux_rename,
  e_linux_statvfs,
  e_linux_opendir,
  e_linux_readdir,
  e_linux_closedir,
};

#else
extern int unused_filler_for_empty_file;
#endif /* EXAMPLE CODE ONLY */