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:
Vreixo Formoso 2008-01-11 19:48:52 +01:00
parent 953da9ff8f
commit b29e2a7db2
1 changed files with 137 additions and 46 deletions

View File

@ -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