Use GList to store directory content in vfs_s_inode.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru> Signed-off-by: Slava Zanko <slavazanko@gmail.com>
Этот коммит содержится в:
родитель
401aaa5014
Коммит
519246eccd
@ -61,7 +61,7 @@
|
||||
|
||||
struct dirhandle
|
||||
{
|
||||
struct vfs_s_entry *cur;
|
||||
GList *cur;
|
||||
struct vfs_s_inode *dir;
|
||||
};
|
||||
|
||||
@ -72,33 +72,43 @@ static volatile int total_inodes = 0, total_entries = 0;
|
||||
/*** file scope functions ************************************************************************/
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
vfs_s_entry_compare (const void *a, const void *b)
|
||||
{
|
||||
const struct vfs_s_entry *e = (const struct vfs_s_entry *) a;
|
||||
const char *name = (const char *) b;
|
||||
|
||||
return strcmp (e->name, name);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
vfs_s_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
|
||||
{
|
||||
if (!ino)
|
||||
if (ino == NULL)
|
||||
vfs_die ("Don't pass NULL to me");
|
||||
|
||||
/* ==0 can happen if freshly created entry is deleted */
|
||||
if (ino->st.st_nlink <= 1)
|
||||
if (ino->st.st_nlink > 1)
|
||||
{
|
||||
while (ino->subdir)
|
||||
{
|
||||
vfs_s_free_entry (me, ino->subdir);
|
||||
}
|
||||
|
||||
CALL (free_inode) (me, ino);
|
||||
g_free (ino->linkname);
|
||||
if (ino->localname)
|
||||
{
|
||||
unlink (ino->localname);
|
||||
g_free (ino->localname);
|
||||
}
|
||||
total_inodes--;
|
||||
ino->super->ino_usage--;
|
||||
g_free (ino);
|
||||
}
|
||||
else
|
||||
ino->st.st_nlink--;
|
||||
return;
|
||||
}
|
||||
|
||||
while (ino->subdir != NULL)
|
||||
vfs_s_free_entry (me, (struct vfs_s_entry *) ino->subdir->data);
|
||||
|
||||
CALL (free_inode) (me, ino);
|
||||
g_free (ino->linkname);
|
||||
if (ino->localname != NULL)
|
||||
{
|
||||
unlink (ino->localname);
|
||||
g_free (ino->localname);
|
||||
}
|
||||
total_inodes--;
|
||||
ino->super->ino_usage--;
|
||||
g_free (ino);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
@ -108,14 +118,16 @@ static struct vfs_s_entry *
|
||||
vfs_s_automake (struct vfs_class *me, struct vfs_s_inode *dir, char *path, int flags)
|
||||
{
|
||||
struct vfs_s_entry *res;
|
||||
char *sep = strchr (path, PATH_SEP);
|
||||
char *sep;
|
||||
|
||||
sep = strchr (path, PATH_SEP);
|
||||
if (sep != NULL)
|
||||
*sep = '\0';
|
||||
|
||||
if (sep)
|
||||
*sep = 0;
|
||||
res = vfs_s_generate_entry (me, path, dir, flags & FL_MKDIR ? (0777 | S_IFDIR) : 0777);
|
||||
vfs_s_insert_entry (me, dir, res);
|
||||
|
||||
if (sep)
|
||||
if (sep != NULL)
|
||||
*sep = PATH_SEP;
|
||||
|
||||
return res;
|
||||
@ -179,36 +191,46 @@ vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
/* canonicalize as well, but don't remove '../' from path */
|
||||
custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
|
||||
|
||||
while (root)
|
||||
while (root != NULL)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
while (*path == PATH_SEP) /* Strip leading '/' */
|
||||
path++;
|
||||
|
||||
if (!path[0])
|
||||
if (path[0] == '\0')
|
||||
{
|
||||
g_free (pathref);
|
||||
return ent;
|
||||
}
|
||||
|
||||
for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++);
|
||||
for (pseg = 0; path[pseg] != '\0' && path[pseg] != PATH_SEP; pseg++)
|
||||
;
|
||||
|
||||
for (ent = root->subdir; ent != NULL; ent = ent->next)
|
||||
if (strlen (ent->name) == pseg && (!strncmp (ent->name, path, pseg)))
|
||||
for (iter = root->subdir; iter != NULL; iter = g_list_next (iter))
|
||||
{
|
||||
ent = (struct vfs_s_entry *) iter->data;
|
||||
if (strlen (ent->name) == pseg && strncmp (ent->name, path, pseg) == 0)
|
||||
/* FOUND! */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ent && (flags & (FL_MKFILE | FL_MKDIR)))
|
||||
ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
|
||||
|
||||
if (ent == NULL && (flags & (FL_MKFILE | FL_MKDIR)) != 0)
|
||||
ent = vfs_s_automake (me, root, path, flags);
|
||||
if (!ent)
|
||||
if (ent == NULL)
|
||||
{
|
||||
me->verrno = ENOENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
path += pseg;
|
||||
/* here we must follow leading directories always;
|
||||
only the actual file is optional */
|
||||
ent = vfs_s_resolve_symlink (me, ent, strchr (path, PATH_SEP) ? LINK_FOLLOW : follow);
|
||||
if (!ent)
|
||||
ent = vfs_s_resolve_symlink (me, ent,
|
||||
strchr (path, PATH_SEP) != NULL ? LINK_FOLLOW : follow);
|
||||
if (ent == NULL)
|
||||
goto cleanup;
|
||||
root = ent->ino;
|
||||
}
|
||||
@ -251,6 +273,7 @@ vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
struct vfs_s_entry *ent = NULL;
|
||||
char *const path = g_strdup (a_path);
|
||||
struct vfs_s_entry *retval = NULL;
|
||||
GList *iter;
|
||||
|
||||
if (root->super->root != root)
|
||||
vfs_die ("We have to use _real_ root. Always. Sorry.");
|
||||
@ -258,24 +281,23 @@ vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
/* canonicalize as well, but don't remove '../' from path */
|
||||
custom_canonicalize_pathname (path, CANON_PATH_ALL & (~CANON_PATH_REMDOUBLEDOTS));
|
||||
|
||||
if (!(flags & FL_DIR))
|
||||
if ((flags & FL_DIR) == 0)
|
||||
{
|
||||
char *dirname, *name, *save;
|
||||
struct vfs_s_inode *ino;
|
||||
split_dir_name (me, path, &dirname, &name, &save);
|
||||
ino = vfs_s_find_inode (me, root->super, dirname, follow, flags | FL_DIR);
|
||||
if (save)
|
||||
if (save != NULL)
|
||||
*save = PATH_SEP;
|
||||
retval = vfs_s_find_entry_tree (me, ino, name, follow, flags);
|
||||
g_free (path);
|
||||
return retval;
|
||||
}
|
||||
|
||||
for (ent = root->subdir; ent != NULL; ent = ent->next)
|
||||
if (!strcmp (ent->name, path))
|
||||
break;
|
||||
iter = g_list_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
|
||||
ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
|
||||
|
||||
if (ent && (!(MEDATA->dir_uptodate) (me, ent->ino)))
|
||||
if (ent != NULL && !MEDATA->dir_uptodate (me, ent->ino))
|
||||
{
|
||||
#if 1
|
||||
vfs_print_message (_("Directory cache expired for %s"), path);
|
||||
@ -284,25 +306,25 @@ vfs_s_find_entry_linear (struct vfs_class *me, struct vfs_s_inode *root,
|
||||
ent = NULL;
|
||||
}
|
||||
|
||||
if (!ent)
|
||||
if (ent == NULL)
|
||||
{
|
||||
struct vfs_s_inode *ino;
|
||||
|
||||
ino = vfs_s_new_inode (me, root->super, vfs_s_default_stat (me, S_IFDIR | 0755));
|
||||
ent = vfs_s_new_entry (me, path, ino);
|
||||
if ((MEDATA->dir_load) (me, ino, path) == -1)
|
||||
if (MEDATA->dir_load (me, ino, path) == -1)
|
||||
{
|
||||
vfs_s_free_entry (me, ent);
|
||||
g_free (path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vfs_s_insert_entry (me, root, ent);
|
||||
|
||||
for (ent = root->subdir; ent != NULL; ent = ent->next)
|
||||
if (!strcmp (ent->name, path))
|
||||
break;
|
||||
iter = g_list_find_custom (root->subdir, path, (GCompareFunc) vfs_s_entry_compare);
|
||||
ent = iter != NULL ? (struct vfs_s_entry *) iter->data : NULL;
|
||||
}
|
||||
if (!ent)
|
||||
if (ent == NULL)
|
||||
vfs_die ("find_linear: success but directory is not there\n");
|
||||
|
||||
#if 0
|
||||
@ -343,7 +365,7 @@ vfs_s_insert_super (struct vfs_class *me, struct vfs_s_super *super)
|
||||
static void
|
||||
vfs_s_free_super (struct vfs_class *me, struct vfs_s_super *super)
|
||||
{
|
||||
if (super->root)
|
||||
if (super->root != NULL)
|
||||
{
|
||||
vfs_s_free_inode (me, super->root);
|
||||
super->root = NULL;
|
||||
@ -419,14 +441,14 @@ vfs_s_opendir (struct vfs_class *me, const char *dirname)
|
||||
struct dirhandle *info;
|
||||
|
||||
dir = vfs_s_inode_from_path (me, dirname, FL_DIR | FL_FOLLOW);
|
||||
if (!dir)
|
||||
if (dir == NULL)
|
||||
return NULL;
|
||||
if (!S_ISDIR (dir->st.st_mode))
|
||||
ERRNOR (ENOTDIR, NULL);
|
||||
|
||||
dir->st.st_nlink++;
|
||||
#if 0
|
||||
if (!dir->subdir) /* This can actually happen if we allow empty directories */
|
||||
if (dir->subdir == NULL) /* This can actually happen if we allow empty directories */
|
||||
ERRNOR (EAGAIN, NULL);
|
||||
#endif
|
||||
info = g_new (struct dirhandle, 1);
|
||||
@ -443,21 +465,19 @@ vfs_s_readdir (void *data)
|
||||
{
|
||||
static union vfs_dirent dir;
|
||||
struct dirhandle *info = (struct dirhandle *) data;
|
||||
const char *name;
|
||||
|
||||
if (!(info->cur))
|
||||
if (info->cur == NULL || info->cur->data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (info->cur->name)
|
||||
{
|
||||
g_strlcpy (dir.dent.d_name, info->cur->name, MC_MAXPATHLEN);
|
||||
}
|
||||
name = ((struct vfs_s_entry *) info->cur->data)->name;
|
||||
if (name != NULL)
|
||||
g_strlcpy (dir.dent.d_name, name, MC_MAXPATHLEN);
|
||||
else
|
||||
{
|
||||
vfs_die ("Null in structure-cannot happen");
|
||||
}
|
||||
|
||||
compute_namelen (&dir.dent);
|
||||
info->cur = info->cur->next;
|
||||
info->cur = g_list_next (info->cur);
|
||||
|
||||
return (void *) &dir;
|
||||
}
|
||||
@ -898,9 +918,7 @@ vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *ino
|
||||
entry = g_new0 (struct vfs_s_entry, 1);
|
||||
total_entries++;
|
||||
|
||||
if (name)
|
||||
entry->name = g_strdup (name);
|
||||
|
||||
entry->name = g_strdup (name);
|
||||
entry->ino = inode;
|
||||
entry->ino->ent = entry;
|
||||
CALL (init_entry) (me, entry);
|
||||
@ -914,22 +932,16 @@ vfs_s_new_entry (struct vfs_class *me, const char *name, struct vfs_s_inode *ino
|
||||
void
|
||||
vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
|
||||
{
|
||||
if (ent->prevp)
|
||||
{
|
||||
/* It is possible that we are deleting freshly created entry */
|
||||
*ent->prevp = ent->next;
|
||||
if (ent->next)
|
||||
ent->next->prevp = ent->prevp;
|
||||
}
|
||||
if (ent->dir != NULL)
|
||||
ent->dir->subdir = g_list_remove (ent->dir->subdir, ent);
|
||||
|
||||
g_free (ent->name);
|
||||
ent->name = NULL;
|
||||
/* ent->name = NULL; */
|
||||
|
||||
if (ent->ino)
|
||||
if (ent->ino != NULL)
|
||||
{
|
||||
ent->ino->ent = NULL;
|
||||
vfs_s_free_inode (me, ent->ino);
|
||||
ent->ino = NULL;
|
||||
}
|
||||
|
||||
total_entries--;
|
||||
@ -941,18 +953,12 @@ vfs_s_free_entry (struct vfs_class *me, struct vfs_s_entry *ent)
|
||||
void
|
||||
vfs_s_insert_entry (struct vfs_class *me, struct vfs_s_inode *dir, struct vfs_s_entry *ent)
|
||||
{
|
||||
struct vfs_s_entry **ep;
|
||||
|
||||
(void) me;
|
||||
|
||||
for (ep = &dir->subdir; *ep != NULL; ep = &((*ep)->next))
|
||||
;
|
||||
ent->prevp = ep;
|
||||
ent->next = NULL;
|
||||
ent->dir = dir;
|
||||
*ep = ent;
|
||||
|
||||
ent->ino->st.st_nlink++;
|
||||
dir->subdir = g_list_append (dir->subdir, ent);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -130,7 +130,6 @@ struct vfs_s_super
|
||||
*/
|
||||
struct vfs_s_entry
|
||||
{
|
||||
struct vfs_s_entry **prevp, *next; /* Pointers in the entry list */
|
||||
struct vfs_s_inode *dir; /* Directory we are in, i.e. our parent */
|
||||
char *name; /* Name of this entry */
|
||||
struct vfs_s_inode *ino; /* ... and its inode */
|
||||
@ -143,7 +142,7 @@ struct vfs_s_inode
|
||||
struct vfs_s_entry *ent; /* Our entry in the parent directory -
|
||||
use only for directories because they
|
||||
cannot be hardlinked */
|
||||
struct vfs_s_entry *subdir; /* If this is a directory, its entry */
|
||||
GList *subdir; /* If this is a directory, its entry. List of vfs_s_entry */
|
||||
struct stat st; /* Parameters of this inode */
|
||||
char *linkname; /* Symlink's contents */
|
||||
char *localname; /* Filename of local file, if we have one */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user