Improve filesystem implementation to deal with local files.
Instead of storing the path of each file, we store the name plus a ref to the parent. That way, we safe around 5-10% of memory.
This commit is contained in:
parent
953da9ff8f
commit
b29e2a7db2
183
src/fs_local.c
183
src/fs_local.c
@ -25,7 +25,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static
|
static
|
||||||
int iso_file_source_new_lfs(const char *path, IsoFileSource **src);
|
int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||||
|
IsoFileSource **src);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can share a local filesystem object, as it has no private atts.
|
* We can share a local filesystem object, as it has no private atts.
|
||||||
@ -34,7 +35,9 @@ IsoFilesystem *lfs= NULL;
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *path;
|
/** reference to the parent (if root it points to itself) */
|
||||||
|
IsoFileSource *parent;
|
||||||
|
char *name;
|
||||||
unsigned int openned :2; /* 0: not openned, 1: file, 2:dir */
|
unsigned int openned :2; /* 0: not openned, 1: file, 2:dir */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@ -48,32 +51,43 @@ char* lfs_get_path(IsoFileSource *src)
|
|||||||
{
|
{
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
data = src->data;
|
data = src->data;
|
||||||
return strdup(data->path);
|
|
||||||
|
if (data->parent == src) {
|
||||||
|
return strdup("/");
|
||||||
|
} else {
|
||||||
|
char *path = lfs_get_path(data->parent);
|
||||||
|
int pathlen = strlen(path);
|
||||||
|
path = realloc(path, pathlen + strlen(data->name) + 2);
|
||||||
|
if (pathlen != 1) {
|
||||||
|
/* pathlen can only be 1 for root */
|
||||||
|
path[pathlen] = '/';
|
||||||
|
path[pathlen + 1] = '\0';
|
||||||
|
}
|
||||||
|
return strcat(path, data->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
char* lfs_get_name(IsoFileSource *src)
|
char* lfs_get_name(IsoFileSource *src)
|
||||||
{
|
{
|
||||||
char *name, *p;
|
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
data = src->data;
|
data = src->data;
|
||||||
p = strdup(data->path); /* because basename() might modify its arg */
|
return strdup(data->name);
|
||||||
name = strdup(basename(p));
|
|
||||||
free(p);
|
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int lfs_lstat(IsoFileSource *src, struct stat *info)
|
int lfs_lstat(IsoFileSource *src, struct stat *info)
|
||||||
{
|
{
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
if (src == NULL || info == NULL) {
|
if (src == NULL || info == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
}
|
}
|
||||||
data = src->data;
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
if (lstat(data->path, info) != 0) {
|
if (lstat(path, info) != 0) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* error, choose an appropriate return code */
|
/* error, choose an appropriate return code */
|
||||||
@ -99,6 +113,7 @@ int lfs_lstat(IsoFileSource *src, struct stat *info)
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
return ISO_SUCCESS;
|
return ISO_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,13 +121,15 @@ static
|
|||||||
int lfs_stat(IsoFileSource *src, struct stat *info)
|
int lfs_stat(IsoFileSource *src, struct stat *info)
|
||||||
{
|
{
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
if (src == NULL || info == NULL) {
|
if (src == NULL || info == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
}
|
}
|
||||||
data = src->data;
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
if (stat(data->path, info) != 0) {
|
if (stat(path, info) != 0) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* error, choose an appropriate return code */
|
/* error, choose an appropriate return code */
|
||||||
@ -138,20 +155,26 @@ int lfs_stat(IsoFileSource *src, struct stat *info)
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
return ISO_SUCCESS;
|
return ISO_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int lfs_access(IsoFileSource *src)
|
int lfs_access(IsoFileSource *src)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
if (src == NULL) {
|
if (src == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
}
|
}
|
||||||
data = src->data;
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
return iso_eaccess(data->path);
|
ret = iso_eaccess(path);
|
||||||
|
free(path);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -160,6 +183,7 @@ int lfs_open(IsoFileSource *src)
|
|||||||
int err;
|
int err;
|
||||||
struct stat info;
|
struct stat info;
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
if (src == NULL) {
|
if (src == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
@ -176,13 +200,15 @@ int lfs_open(IsoFileSource *src)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path = lfs_get_path(src);
|
||||||
if (S_ISDIR(info.st_mode)) {
|
if (S_ISDIR(info.st_mode)) {
|
||||||
data->info.dir = opendir(data->path);
|
data->info.dir = opendir(path);
|
||||||
data->openned = data->info.dir ? 2 : 0;
|
data->openned = data->info.dir ? 2 : 0;
|
||||||
} else {
|
} else {
|
||||||
data->info.fd = open(data->path, O_RDONLY);
|
data->info.fd = open(path, O_RDONLY);
|
||||||
data->openned = data->info.fd != -1 ? 1 : 0;
|
data->openned = data->info.fd != -1 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
free(path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for possible errors, note that many of possible ones are
|
* check for possible errors, note that many of possible ones are
|
||||||
@ -294,9 +320,7 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
|||||||
return ISO_FILE_IS_NOT_DIR;
|
return ISO_FILE_IS_NOT_DIR;
|
||||||
case 2: /* directory */
|
case 2: /* directory */
|
||||||
{
|
{
|
||||||
char *path;
|
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
size_t a, b;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* while to skip "." and ".." dirs */
|
/* while to skip "." and ".." dirs */
|
||||||
@ -313,21 +337,8 @@ int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* constructs the new path */
|
|
||||||
a = strlen(data->path);
|
|
||||||
b = strlen(entry->d_name);
|
|
||||||
path = malloc(a + b + 2);
|
|
||||||
if (path == NULL) {
|
|
||||||
return ISO_MEM_ERROR;
|
|
||||||
}
|
|
||||||
strncpy(path, data->path, a);
|
|
||||||
path[a] = '/';
|
|
||||||
path[a + 1] = '\0';
|
|
||||||
strncat(path, entry->d_name, b);
|
|
||||||
|
|
||||||
/* create the new FileSrc */
|
/* create the new FileSrc */
|
||||||
ret = iso_file_source_new_lfs(path, child);
|
ret = iso_file_source_new_lfs(src, entry->d_name, child);
|
||||||
free(path);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -340,6 +351,7 @@ int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
|||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
if (src == NULL || buf == NULL) {
|
if (src == NULL || buf == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
@ -350,12 +362,14 @@ int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
data = src->data;
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* invoke readlink, with bufsiz -1 to reserve an space for
|
* invoke readlink, with bufsiz -1 to reserve an space for
|
||||||
* the NULL character
|
* the NULL character
|
||||||
*/
|
*/
|
||||||
size = readlink(data->path, buf, bufsiz - 1);
|
size = readlink(path, buf, bufsiz - 1);
|
||||||
|
free(path);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
/* error */
|
/* error */
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@ -399,8 +413,10 @@ void lfs_free(IsoFileSource *src)
|
|||||||
if (data->openned) {
|
if (data->openned) {
|
||||||
src->class->close(src);
|
src->class->close(src);
|
||||||
}
|
}
|
||||||
|
if (data->parent != src) {
|
||||||
free(data->path);
|
iso_file_source_unref(data->parent);
|
||||||
|
}
|
||||||
|
free(data->name);
|
||||||
free(data);
|
free(data);
|
||||||
iso_filesystem_unref(lfs);
|
iso_filesystem_unref(lfs);
|
||||||
}
|
}
|
||||||
@ -426,7 +442,8 @@ IsoFileSourceIface lfs_class = {
|
|||||||
* 1 success, < 0 error
|
* 1 success, < 0 error
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
int iso_file_source_new_lfs(const char *path, IsoFileSource **src)
|
int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||||
|
IsoFileSource **src)
|
||||||
{
|
{
|
||||||
IsoFileSource *lfs_src;
|
IsoFileSource *lfs_src;
|
||||||
_LocalFsFileSource *data;
|
_LocalFsFileSource *data;
|
||||||
@ -452,18 +469,14 @@ int iso_file_source_new_lfs(const char *path, IsoFileSource **src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fill struct */
|
/* fill struct */
|
||||||
data->path = strdup(path);
|
data->name = name ? strdup(name) : NULL;
|
||||||
{
|
|
||||||
/* remove trailing '/' */
|
|
||||||
int len = strlen(path);
|
|
||||||
if (len > 1) {
|
|
||||||
/* don't remove / for root! */
|
|
||||||
if (path[len-1] == '/') {
|
|
||||||
data->path[len-1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data->openned = 0;
|
data->openned = 0;
|
||||||
|
if (parent) {
|
||||||
|
data->parent = parent;
|
||||||
|
iso_file_source_ref(parent);
|
||||||
|
} else {
|
||||||
|
data->parent = lfs_src;
|
||||||
|
}
|
||||||
|
|
||||||
lfs_src->refcount = 1;
|
lfs_src->refcount = 1;
|
||||||
lfs_src->data = data;
|
lfs_src->data = data;
|
||||||
@ -483,16 +496,94 @@ int lfs_get_root(IsoFilesystem *fs, IsoFileSource **root)
|
|||||||
if (fs == NULL || root == NULL) {
|
if (fs == NULL || root == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
}
|
}
|
||||||
return iso_file_source_new_lfs("/", root);
|
return iso_file_source_new_lfs(NULL, NULL, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int lfs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
|
int lfs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSource *src;
|
||||||
|
struct stat info;
|
||||||
|
char *ptr, *brk_info, *component;
|
||||||
|
|
||||||
if (fs == NULL || path == NULL || file == NULL) {
|
if (fs == NULL || path == NULL || file == NULL) {
|
||||||
return ISO_NULL_POINTER;
|
return ISO_NULL_POINTER;
|
||||||
}
|
}
|
||||||
return iso_file_source_new_lfs(path, file);
|
|
||||||
|
/*
|
||||||
|
* first of all check that it is a valid path.
|
||||||
|
*/
|
||||||
|
if (lstat(path, &info) != 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* error, choose an appropriate return code */
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
err = ISO_FILE_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
case ENOTDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
err = ISO_FILE_BAD_PATH;
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
err = ISO_FILE_DOESNT_EXIST;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
err = ISO_MEM_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, path is valid. create the file source */
|
||||||
|
ret = lfs_get_root(fs, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!strcmp(path, "/")) {
|
||||||
|
/* we are looking for root */
|
||||||
|
*file = src;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strdup(path);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
return ISO_MEM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = strtok_r(ptr, "/", &brk_info);
|
||||||
|
while (component) {
|
||||||
|
IsoFileSource *child = NULL;
|
||||||
|
if (!strcmp(component, ".")) {
|
||||||
|
child = src;
|
||||||
|
} else if (!strcmp(component, "..")) {
|
||||||
|
child = ((_LocalFsFileSource*)src->data)->parent;
|
||||||
|
iso_file_source_ref(child);
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
} else {
|
||||||
|
ret = iso_file_source_new_lfs(src, component, &child);
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src = child;
|
||||||
|
component = strtok_r(NULL, "/", &brk_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
if (ret > 0) {
|
||||||
|
*file = src;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
Loading…
Reference in New Issue
Block a user