📄 yaffsfs.c
字号:
/* * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning <charles@aleph1.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include "yaffsfs.h"#include "yaffs_guts.h"#include "yaffscfg.h"#include <string.h> // for memset#include "yportenv.h"#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5#ifndef NULL#define NULL ((void *)0)#endifconst char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.25 2009/03/05 01:47:17 charles Exp $";// configurationList is the list of devices that are supportedstatic yaffsfs_DeviceConfiguration *yaffsfs_configurationList;/* Some forward references */static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path, int symDepth);static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);// Handle management.//unsigned int yaffs_wr_attempts;typedef struct{ __u8 inUse:1; // this handle is in use __u8 readOnly:1; // this handle is read only __u8 append:1; // append only __u8 exclusive:1; // exclusive __u32 position; // current position in file yaffs_Object *obj; // the object}yaffsfs_Handle;static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];// yaffsfs_InitHandle/// Inilitalise handles on start-up.//static int yaffsfs_InitHandles(void){ int i; for(i = 0; i < YAFFSFS_N_HANDLES; i++) { yaffsfs_handle[i].inUse = 0; yaffsfs_handle[i].obj = NULL; } return 0;}yaffsfs_Handle *yaffsfs_GetHandlePointer(int h){ if(h < 0 || h >= YAFFSFS_N_HANDLES) { return NULL; } return &yaffsfs_handle[h];}yaffs_Object *yaffsfs_GetHandleObject(int handle){ yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); if(h && h->inUse) { return h->obj; } return NULL;}//yaffsfs_GetHandle// Grab a handle (when opening a file)//static int yaffsfs_GetHandle(void){ int i; yaffsfs_Handle *h; for(i = 0; i < YAFFSFS_N_HANDLES; i++) { h = yaffsfs_GetHandlePointer(i); if(!h) { // todo bug: should never happen } if(!h->inUse) { memset(h,0,sizeof(yaffsfs_Handle)); h->inUse=1; return i; } } return -1;}// yaffs_PutHandle// Let go of a handle (when closing a file)//static int yaffsfs_PutHandle(int handle){ yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle); if(h) { h->inUse = 0; h->obj = NULL; } return 0;}// Stuff to search for a directory from a pathint yaffsfs_Match(YCHAR a, YCHAR b){ // case sensitive return (a == b);}int yaffsfs_IsPathDivider(YCHAR ch){ YCHAR *str = YAFFS_PATH_DIVIDERS; while(*str){ if(*str == ch) return 1; str++; } return 0;}// yaffsfs_FindDevice// yaffsfs_FindRoot// Scan the configuration list to find the root.// Curveballs: Should match paths that end in '/' too// Curveball2 Might have "/x/ and "/x/y". Need to return the longest matchstatic yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath){ yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; const YCHAR *leftOver; const YCHAR *p; yaffs_Device *retval = NULL; int thisMatchLength; int longestMatch = -1; int matching; // Check all configs, choose the one that: // 1) Actually matches a prefix (ie /a amd /abc will not match // 2) Matches the longest. while(cfg && cfg->prefix && cfg->dev) { leftOver = path; p = cfg->prefix; thisMatchLength = 0; matching = 1; while(matching && *p && *leftOver){ // Skip over any /s while(yaffsfs_IsPathDivider(*p)) p++; // Skip over any /s while(yaffsfs_IsPathDivider(*leftOver)) leftOver++; // Now match the text part while(matching && *p && !yaffsfs_IsPathDivider(*p) && *leftOver && !yaffsfs_IsPathDivider(*leftOver)){ if(yaffsfs_Match(*p,*leftOver)){ p++; leftOver++; thisMatchLength++; } else { matching = 0; } } } // Skip over any /s in leftOver while(yaffsfs_IsPathDivider(*leftOver)) leftOver++; if( matching && (thisMatchLength > longestMatch)) { // Matched prefix *restOfPath = (YCHAR *)leftOver; retval = cfg->dev; longestMatch = thisMatchLength; } cfg++; } return retval;}#if 0static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath){ yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList; const YCHAR *leftOver; const YCHAR *p; yaffs_Device *retval = NULL; int thisMatchLength; int longestMatch = -1; // Check all configs, choose the one that: // 1) Actually matches a prefix (ie /a amd /abc will not match // 2) Matches the longest. while(cfg && cfg->prefix && cfg->dev) { leftOver = path; p = cfg->prefix; thisMatchLength = 0; while(*p && //unmatched part of prefix !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) && // the rest of the prefix is not / (to catch / at end) *leftOver && yaffsfs_Match(*p,*leftOver)) { p++; leftOver++; thisMatchLength++; } if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) && // end of prefix (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && // no more in this path name part (thisMatchLength > longestMatch)) { // Matched prefix *restOfPath = (YCHAR *)leftOver; retval = cfg->dev; longestMatch = thisMatchLength; } cfg++; } return retval;}#endifstatic yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath){ yaffs_Device *dev; dev= yaffsfs_FindDevice(path,restOfPath); if(dev && dev->isMounted) { return dev->rootDir; } return NULL;}static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth){ while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { YCHAR *alias = obj->variant.symLinkVariant.alias; if(yaffsfs_IsPathDivider(*alias)) { // Starts with a /, need to scan from root up obj = yaffsfs_FindObject(NULL,alias,symDepth++); } else { // Relative to here, so use the parent of the symlink as a start obj = yaffsfs_FindObject(obj->parent,alias,symDepth++); } } return obj;}// yaffsfs_FindDirectory// Parse a path to determine the directory and the name within the directory.//// eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const YCHAR *path,YCHAR **name,int symDepth){ yaffs_Object *dir; YCHAR *restOfPath; YCHAR str[YAFFS_MAX_NAME_LENGTH+1]; int i; if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) { return NULL; } if(startDir) { dir = startDir; restOfPath = (YCHAR *)path; } else { dir = yaffsfs_FindRoot(path,&restOfPath); } while(dir) { // parse off /. // curve ball: also throw away surplus '/' // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" while(yaffsfs_IsPathDivider(*restOfPath)) { restOfPath++; // get rid of '/' } *name = restOfPath; i = 0; while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) { if (i < YAFFS_MAX_NAME_LENGTH) { str[i] = *restOfPath; str[i+1] = '\0'; i++; } restOfPath++; } if(!*restOfPath) { // got to the end of the string return dir; } else { if(yaffs_strcmp(str,_Y(".")) == 0) { // Do nothing } else if(yaffs_strcmp(str,_Y("..")) == 0) { dir = dir->parent; } else { dir = yaffs_FindObjectByName(dir,str); while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { dir = yaffsfs_FollowLink(dir,symDepth); } if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { dir = NULL; } } } } // directory did not exist. return NULL;}static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const YCHAR *path,YCHAR **name,int symDepth){ return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);}// yaffsfs_FindObject turns a path for an existing object into the object//static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path,int symDepth){ yaffs_Object *dir; YCHAR *name; dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth); if(dir && *name) { return yaffs_FindObjectByName(dir,name); } return dir;}int yaffs_dup(int fd){ int newHandle = -1; yaffsfs_Handle *oldPtr = NULL; yaffsfs_Handle *newPtr = NULL; yaffsfs_Lock(); oldPtr = yaffsfs_GetHandlePointer(fd); if(oldPtr && oldPtr->inUse) newHandle = yaffsfs_GetHandle(); if(newHandle >= 0) newPtr = yaffsfs_GetHandlePointer(newHandle); if(newPtr){ *newPtr = *oldPtr; return newHandle; } if(!oldPtr) yaffsfs_SetError(-EBADF); else yaffsfs_SetError(-ENOMEM); return -1;}int yaffs_open(const YCHAR *path, int oflag, int mode){ yaffs_Object *obj = NULL; yaffs_Object *dir = NULL; YCHAR *name; int handle = -1; yaffsfs_Handle *h = NULL; int alreadyOpen = 0; int alreadyExclusive = 0; int openDenied = 0; int symDepth = 0; int errorReported = 0; int i; // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR yaffsfs_Lock(); handle = yaffsfs_GetHandle(); if(handle >= 0) { h = yaffsfs_GetHandlePointer(handle); // try to find the exisiting object obj = yaffsfs_FindObject(NULL,path,0); if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { obj = yaffsfs_FollowLink(obj,symDepth++); } if(obj && obj->variantType != YAFFS_OBJECT_TYPE_FILE) { obj = NULL; } if(obj) { // Check if the object is already in use alreadyOpen = alreadyExclusive = 0; for(i = 0; i < YAFFSFS_N_HANDLES; i++) { if(i != handle && yaffsfs_handle[i].inUse && obj == yaffsfs_handle[i].obj) { alreadyOpen = 1; if(yaffsfs_handle[i].exclusive) { alreadyExclusive = 1; } } } if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive) { openDenied = 1; } // Open should fail if O_CREAT and O_EXCL are specified if((oflag & O_EXCL) && (oflag & O_CREAT)) { openDenied = 1; yaffsfs_SetError(-EEXIST); errorReported = 1; } // Check file permissions if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY !(obj->yst_mode & S_IREAD)) { openDenied = 1; } if( (oflag & O_RDWR) && !(obj->yst_mode & S_IREAD)) { openDenied = 1; } if( (oflag & (O_RDWR | O_WRONLY)) && !(obj->yst_mode & S_IWRITE)) { openDenied = 1; } } else if((oflag & O_CREAT)) { // Let's see if we can create this file dir = yaffsfs_FindDirectory(NULL,path,&name,0); if(dir) { obj = yaffs_MknodFile(dir,name,mode,0,0); } else { yaffsfs_SetError(-ENOTDIR); errorReported = 1; } } if(obj && !openDenied) { h->obj = obj; h->inUse = 1; h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1; h->append = (oflag & O_APPEND) ? 1 : 0; h->exclusive = (oflag & O_EXCL) ? 1 : 0; h->position = 0; obj->inUse++; if((oflag & O_TRUNC) && !h->readOnly) { yaffs_ResizeFile(obj,0); } } else { yaffsfs_PutHandle(handle); if(!errorReported) { yaffsfs_SetError(-EACCES); errorReported = 1; } handle = -1; } } yaffsfs_Unlock(); return handle;}int yaffs_flush(int fd){ yaffsfs_Handle *h = NULL; int retVal = 0; yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); if(h && h->inUse) { // flush the file yaffs_FlushFile(h->obj,1); } else { // bad handle yaffsfs_SetError(-EBADF); retVal = -1; } yaffsfs_Unlock(); return retVal;}int yaffs_close(int fd){ yaffsfs_Handle *h = NULL; int retVal = 0; yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); if(h && h->inUse) { // clean up yaffs_FlushFile(h->obj,1); h->obj->inUse--; if(h->obj->inUse <= 0 && h->obj->unlinked) { yaffs_DeleteObject(h->obj); } yaffsfs_PutHandle(fd); retVal = 0; } else { // bad handle yaffsfs_SetError(-EBADF); retVal = -1; } yaffsfs_Unlock(); return retVal;}int yaffs_read(int fd, void *buf, unsigned int nbyte){ yaffsfs_Handle *h = NULL; yaffs_Object *obj = NULL; int pos = 0; int nRead = -1; unsigned int maxRead; yaffsfs_Lock(); h = yaffsfs_GetHandlePointer(fd); obj = yaffsfs_GetHandleObject(fd); if(!h || !obj) { // bad handle yaffsfs_SetError(-EBADF); } else if( h && obj)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -