File: [local] / prex / usr / server / fs / fatfs / fatfs_node.c (download)
Revision 1.1.1.1 (vendor branch), Tue Aug 19 12:47:01 2008 UTC (15 years, 10 months ago) by nbrk
Branch: MAIN, KOHSUKE
CVS Tags: PREX_0_8_BASE, HEAD Changes since 1.1: +0 -0 lines
Initial import of Prex, Portable Real-time Embedded POSIX microkernel system.
I have totally new directions in my development (more focused on real hardware, not virtual one).
Old hacks are available in prex-old module. They will be carefully re-designed and merged soon.
|
/*
* Copyright (c) 2005-2008, Kohsuke Ohtani
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <prex/prex.h>
#include <sys/buf.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include "fatfs.h"
/*
* Read directory entry to buffer, with cache.
*/
static int
fat_read_dirent(struct fatfsmount *fmp, u_long sec)
{
struct buf *bp;
int err;
if ((err = bread(fmp->dev, sec, &bp)) != 0)
return err;
memcpy(fmp->dir_buf, bp->b_data, SEC_SIZE);
brelse(bp);
return 0;
}
/*
* Write directory entry from buffer.
*/
static int
fat_write_dirent(struct fatfsmount *fmp, u_long sec)
{
struct buf *bp;
bp = getblk(fmp->dev, sec);
memcpy(bp->b_data, fmp->dir_buf, SEC_SIZE);
return bwrite(bp);
}
/*
* Find directory entry in specified sector.
* The fat vnode data is filled if success.
*
* @fmp: fatfs mount point
* @sec: sector#
* @name: file name
* @node: pointer to fat node
*/
static int
fat_lookup_dirent(struct fatfsmount *fmp, u_long sec, char *name,
struct fatfs_node *np)
{
struct fat_dirent *de;
int err, i;
err = fat_read_dirent(fmp, sec);
if (err)
return err;
de = (struct fat_dirent *)fmp->dir_buf;
for (i = 0; i < DIR_PER_SEC; i++) {
/* Find specific file or directory name */
if (IS_EMPTY(de))
return ENOENT;
if (!IS_VOL(de) &&
!fat_compare_name((char *)de->name, name)) {
/* Found. Fill the fat vnode data. */
*(&np->dirent) = *de;
np->sector = sec;
np->offset = sizeof(struct fat_dirent) * i;
DPRINTF(("fat_lookup_dirent: found sec=%d\n", sec));
return 0;
}
if (!IS_DELETED(de))
DPRINTF(("fat_lookup_dirent: %s\n", de->name));
de++;
}
return EAGAIN;
}
/*
* Find directory entry for specified name in directory.
* The fat vnode data is filled if success.
*
* @dvp: vnode for directory.
* @name: file name
* @np: pointer to fat node
*/
int
fatfs_lookup_node(vnode_t dvp, char *name, struct fatfs_node *np)
{
struct fatfsmount *fmp;
char fat_name[12];
u_long cl, sec;
int i, err;
if (name == NULL)
return ENOENT;
DPRINTF(("fat_lookup_denode: cl=%d name=%s\n", dvp->v_blkno, name));
fat_convert_name(name, fat_name);
*(fat_name + 11) = '\0';
fmp = (struct fatfsmount *)dvp->v_mount->m_data;
cl = dvp->v_blkno;
if (cl == CL_ROOT) {
/* Search entry in root directory */
for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
err = fat_lookup_dirent(fmp, sec, fat_name, np);
if (err != EAGAIN)
return err;
}
} else {
/* Search entry in sub directory */
while (!IS_EOFCL(fmp, cl)) {
sec = cl_to_sec(fmp, cl);
for (i = 0; i < fmp->sec_per_cl; i++) {
err = fat_lookup_dirent(fmp, sec, fat_name,
np);
if (err != EAGAIN)
return err;
sec++;
}
err = fat_next_cluster(fmp, cl, &cl);
if (err)
return err;
}
}
return ENOENT;
}
/*
* Get directory entry for specified index in sector.
* The directory entry is filled if success.
*
* @fmp: fatfs mount point
* @sec: sector#
* @target: target index
* @index: current index
* @np: pointer to fat node
*/
static int
fat_get_dirent(struct fatfsmount *fmp, u_long sec, int target, int *index,
struct fatfs_node *np)
{
struct fat_dirent *de;
int err, i;
err = fat_read_dirent(fmp, sec);
if (err)
return err;
de = (struct fat_dirent *)fmp->dir_buf;
for (i = 0; i < DIR_PER_SEC; i++) {
if (IS_EMPTY(de))
return ENOENT;
if (!IS_DELETED(de) && !IS_VOL(de)) {
/* valid file */
if (*index == target) {
*(&np->dirent) = *de;
np->sector = sec;
np->offset = sizeof(struct fat_dirent) * i;
DPRINTF(("fat_get_dirent: found index=%d\n", *index));
return 0;
}
(*index)++;
}
DPRINTF(("fat_get_dirent: %s\n", de->name));
de++;
}
return EAGAIN;
}
/*
* Get directory entry for specified index.
*
* @dvp: vnode for directory.
* @index: index of the entry
* @np: pointer to fat node
*/
int
fatfs_get_node(vnode_t dvp, int index, struct fatfs_node *np)
{
struct fatfsmount *fmp;
u_long cl, sec;
int i, cur_index, err;
fmp = (struct fatfsmount *)dvp->v_mount->m_data;
cl = dvp->v_blkno;
cur_index = 0;
DPRINTF(("fatfs_get_node: index=%d\n", index));
if (cl == CL_ROOT) {
/* Get entry from the root directory */
for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
err = fat_get_dirent(fmp, sec, index, &cur_index, np);
if (err != EAGAIN)
return err;
}
} else {
/* Get entry from the sub directory */
while (!IS_EOFCL(fmp, cl)) {
sec = cl_to_sec(fmp, cl);
for (i = 0; i < fmp->sec_per_cl; i++) {
err = fat_get_dirent(fmp, sec, index,
&cur_index, np);
if (err != EAGAIN)
return err;
sec++;
}
err = fat_next_cluster(fmp, cl, &cl);
if (err)
return err;
}
}
return ENOENT;
}
/*
* Find empty directory entry and put new entry on it.
*
* @fmp: fatfs mount point
* @sec: sector#
* @np: pointer to fat node
*/
static int
fat_add_dirent(struct fatfsmount *fmp, u_long sec, struct fatfs_node *np)
{
struct fat_dirent *de;
int err, i;
err = fat_read_dirent(fmp, sec);
if (err)
return err;
de = (struct fat_dirent *)fmp->dir_buf;
for (i = 0; i < DIR_PER_SEC; i++) {
if (IS_DELETED(de) || IS_EMPTY(de))
goto found;
DPRINTF(("fat_add_dirent: scan %s\n", de->name));
de++;
}
return ENOENT;
found:
DPRINTF(("fat_add_dirent: found. sec=%d\n", sec));
memcpy(de, &np->dirent, sizeof(struct fat_dirent));
err = fat_write_dirent(fmp, sec);
return err;
}
/*
* Find empty directory entry and put new entry on it.
* This search is done only in directory of specified cluster.
* @dvp: vnode for directory.
* @np: pointer to fat node
*/
int
fatfs_add_node(vnode_t dvp, struct fatfs_node *np)
{
struct fatfsmount *fmp;
u_long cl, sec;
int i, err;
u_long next;
fmp = (struct fatfsmount *)dvp->v_mount->m_data;
cl = dvp->v_blkno;
DPRINTF(("fatfs_add_node: cl=%d\n", cl));
if (cl == CL_ROOT) {
/* Add entry in root directory */
for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
err = fat_add_dirent(fmp, sec, np);
if (err != ENOENT)
return err;
}
} else {
/* Search entry in sub directory */
while (!IS_EOFCL(fmp, cl)) {
sec = cl_to_sec(fmp, cl);
for (i = 0; i < fmp->sec_per_cl; i++) {
err = fat_add_dirent(fmp, sec, np);
if (err != ENOENT)
return err;
sec++;
}
err = fat_next_cluster(fmp, cl, &next);
if (err)
return err;
cl = next;
}
/* No entry found, add one more free cluster for directory */
DPRINTF(("fatfs_add_node: expand dir\n"));
err = fat_expand_dir(fmp, cl, &next);
if (err)
return err;
/* Initialize free cluster. */
memset(fmp->dir_buf, 0, SEC_SIZE);
sec = cl_to_sec(fmp, next);
for (i = 0; i < fmp->sec_per_cl; i++) {
err = fat_write_dirent(fmp, sec);
if (err)
return err;
sec++;
}
/* Try again */
sec = cl_to_sec(fmp, next);
err = fat_add_dirent(fmp, sec, np);
return err;
}
return ENOENT;
}
/*
* Put directory entry.
* @fmp: fat mount data
* @np: pointer to fat node
*/
int
fatfs_put_node(struct fatfsmount *fmp, struct fatfs_node *np)
{
int err;
err = fat_read_dirent(fmp, np->sector);
if (err)
return err;
memcpy(fmp->dir_buf + np->offset, &np->dirent,
sizeof(struct fat_dirent));
err = fat_write_dirent(fmp, np->sector);
return err;
}