35 |
|
|
36 |
static volatile int total_inodes = 0, total_entries = 0; |
static volatile int total_inodes = 0, total_entries = 0; |
37 |
|
|
|
static struct vfs_s_entry *vfs_s_resolve_symlink (struct vfs_class * me, struct vfs_s_entry * entry, |
|
|
char *path, int follow); |
|
|
|
|
38 |
struct vfs_s_inode * |
struct vfs_s_inode * |
39 |
vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat) |
vfs_s_new_inode (struct vfs_class *me, struct vfs_s_super *super, struct stat *initstat) |
40 |
{ |
{ |
211 |
return res; |
return res; |
212 |
} |
} |
213 |
|
|
214 |
|
/* If the entry is a symlink, find the entry for its target */ |
215 |
|
static struct vfs_s_entry * |
216 |
|
vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, |
217 |
|
char *path, int follow) |
218 |
|
{ |
219 |
|
char *linkname; |
220 |
|
char *fullname = NULL; |
221 |
|
struct vfs_s_entry *target; |
222 |
|
|
223 |
|
if (follow == LINK_NO_FOLLOW) |
224 |
|
return entry; |
225 |
|
if (follow == 0) |
226 |
|
ERRNOR (ELOOP, NULL); |
227 |
|
if (!entry) |
228 |
|
ERRNOR (ENOENT, NULL); |
229 |
|
if (!S_ISLNK (entry->ino->st.st_mode)) |
230 |
|
return entry; |
231 |
|
|
232 |
|
linkname = entry->ino->linkname; |
233 |
|
if (linkname == NULL) |
234 |
|
ERRNOR (EFAULT, NULL); |
235 |
|
|
236 |
|
/* make full path from relative */ |
237 |
|
if (*linkname != PATH_SEP) { |
238 |
|
char *fullpath = vfs_s_fullpath (me, entry->dir); |
239 |
|
fullname = g_strdup_printf ("%s/%s", fullpath, linkname); |
240 |
|
linkname = fullname; |
241 |
|
g_free (fullpath); |
242 |
|
} |
243 |
|
|
244 |
|
target = |
245 |
|
(MEDATA->find_entry) (me, entry->dir->super->root, linkname, |
246 |
|
follow - 1, 0); |
247 |
|
g_free (fullname); |
248 |
|
return target; |
249 |
|
} |
250 |
|
|
251 |
/* |
/* |
252 |
* Follow > 0: follow links, serves as loop protect, |
* Follow > 0: follow links, serves as loop protect, |
253 |
* == -1: do not follow links |
* == -1: do not follow links |
254 |
*/ |
*/ |
255 |
struct vfs_s_entry * |
struct vfs_s_entry * |
256 |
vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root, char *path, int follow, int flags) |
vfs_s_find_entry_tree (struct vfs_class *me, struct vfs_s_inode *root, |
257 |
|
char *path, int follow, int flags) |
258 |
{ |
{ |
259 |
unsigned int pseg; |
unsigned int pseg; |
260 |
struct vfs_s_entry *ent = NULL; |
struct vfs_s_entry *ent = NULL; |
261 |
char p[MC_MAXPATHLEN] = ""; |
char p[MC_MAXPATHLEN] = ""; |
262 |
|
|
263 |
while (root){ |
if (strlen(path) >= MC_MAXPATHLEN) |
264 |
|
return NULL; |
265 |
|
|
266 |
|
while (root) { |
267 |
int t; |
int t; |
268 |
|
|
269 |
while (*path == PATH_SEP) /* Strip leading '/' */ |
while (*path == PATH_SEP) /* Strip leading '/' */ |
270 |
path++; |
path++; |
271 |
|
|
272 |
if (!path [0]) |
if (!path[0]) |
273 |
return ent; |
return ent; |
274 |
|
|
275 |
for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++) |
for (pseg = 0; path[pseg] && path[pseg] != PATH_SEP; pseg++); |
|
; |
|
276 |
|
|
277 |
strcat (p, PATH_SEP_STR); |
strcat (p, PATH_SEP_STR); |
278 |
strncpy (p + (t = strlen (p)), path, pseg); |
strncpy (p + (t = strlen (p)), path, pseg); |
279 |
p[t + pseg] = '\0'; |
p[t + pseg] = '\0'; |
280 |
|
|
281 |
for (ent = root->subdir; ent != NULL; ent = ent->next) |
for (ent = root->subdir; ent != NULL; ent = ent->next) |
282 |
if (strlen (ent->name) == pseg && (!strncmp (ent->name, path, pseg))) |
if (strlen (ent->name) == pseg |
283 |
|
&& (!strncmp (ent->name, path, pseg))) |
284 |
/* FOUND! */ |
/* FOUND! */ |
285 |
break; |
break; |
286 |
|
|
287 |
if (!ent && (flags & (FL_MKFILE | FL_MKDIR))) |
if (!ent && (flags & (FL_MKFILE | FL_MKDIR))) |
288 |
ent = vfs_s_automake (me, root, path, flags); |
ent = vfs_s_automake (me, root, path, flags); |
289 |
if (!ent) ERRNOR (ENOENT, NULL); |
if (!ent) |
290 |
|
ERRNOR (ENOENT, NULL); |
291 |
path += pseg; |
path += pseg; |
292 |
/* here we must follow leading directories always; only the actual file is optional */ |
/* here we must follow leading directories always; |
293 |
if (!(ent = vfs_s_resolve_symlink (me, ent, p, strchr (path, PATH_SEP) ? LINK_FOLLOW : follow))) |
only the actual file is optional */ |
294 |
|
ent = |
295 |
|
vfs_s_resolve_symlink (me, ent, p, |
296 |
|
strchr (path, |
297 |
|
PATH_SEP) ? LINK_FOLLOW : |
298 |
|
follow); |
299 |
|
if (!ent) |
300 |
return NULL; |
return NULL; |
301 |
root = ent->ino; |
root = ent->ino; |
302 |
} |
} |
389 |
return ent->ino; |
return ent->ino; |
390 |
} |
} |
391 |
|
|
|
static struct vfs_s_entry * |
|
|
vfs_s_resolve_symlink (struct vfs_class *me, struct vfs_s_entry *entry, char *path, int follow) |
|
|
{ |
|
|
char buf[MC_MAXPATHLEN], *linkname; |
|
|
|
|
|
if (follow == LINK_NO_FOLLOW) |
|
|
return entry; |
|
|
if (follow == 0) |
|
|
ERRNOR (ELOOP, NULL); |
|
|
if (!entry) |
|
|
ERRNOR (ENOENT, NULL); |
|
|
if (!S_ISLNK (entry->ino->st.st_mode)) |
|
|
return entry; |
|
|
|
|
|
linkname = entry->ino->linkname; |
|
|
|
|
|
if (linkname == NULL) |
|
|
ERRNOR (EFAULT, NULL); |
|
|
|
|
|
if (MEDATA->find_entry == vfs_s_find_entry_linear) { |
|
|
if (*linkname == PATH_SEP) |
|
|
return (MEDATA->find_entry) (me, entry->dir->super->root, |
|
|
linkname, follow - 1, 0); |
|
|
else { |
|
|
char *fullpath = vfs_s_fullpath (me, entry->dir); |
|
|
|
|
|
g_snprintf (buf, sizeof (buf), "%s/%s", fullpath, linkname); |
|
|
g_free (fullpath); |
|
|
return (MEDATA->find_entry) (me, entry->dir->super->root, buf, |
|
|
follow - 1, 0); |
|
|
} |
|
|
} |
|
|
|
|
|
/* Convert absolute paths to relative ones */ |
|
|
if (*linkname == PATH_SEP) { |
|
|
char *p, *q; |
|
|
|
|
|
for (p = path, q = entry->ino->linkname; *p == *q; p++, q++); |
|
|
while (*(--q) != PATH_SEP); |
|
|
q++; |
|
|
for (;; p++) { |
|
|
p = strchr (p, PATH_SEP); |
|
|
if (!p) { |
|
|
strcat (buf, q); |
|
|
break; |
|
|
} |
|
|
strcat (buf, ".."); |
|
|
strcat (buf, PATH_SEP_STR); |
|
|
} |
|
|
linkname = buf; |
|
|
} |
|
|
|
|
|
return (MEDATA->find_entry) (me, entry->dir, linkname, follow - 1, 0); |
|
|
} |
|
|
|
|
392 |
/* Ook, these were functions around directory entries / inodes */ |
/* Ook, these were functions around directory entries / inodes */ |
393 |
/* -------------------------------- superblock games -------------------------- */ |
/* -------------------------------- superblock games -------------------------- */ |
394 |
|
|
534 |
char * |
char * |
535 |
vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino) |
vfs_s_fullpath (struct vfs_class *me, struct vfs_s_inode *ino) |
536 |
{ |
{ |
537 |
/* For now, usable only on filesystems with _linear structure */ |
if (!ino->ent) |
|
if (MEDATA->find_entry != vfs_s_find_entry_linear) |
|
|
vfs_die ("Implement me!"); |
|
|
if (!ino->ent) /* That must be directory... */ |
|
538 |
ERRNOR (EAGAIN, NULL); |
ERRNOR (EAGAIN, NULL); |
539 |
|
|
540 |
if ((!ino->ent->dir) || (!ino->ent->dir->ent)) /* It must be directory */ |
if (MEDATA->find_entry != vfs_s_find_entry_linear) { |
541 |
return g_strdup (ino->ent->name); |
char *newpath; |
542 |
|
char *path = g_strdup (ino->ent->name); |
543 |
|
while (1) { |
544 |
|
ino = ino->ent->dir; |
545 |
|
if (ino == ino->super->root) |
546 |
|
break; |
547 |
|
newpath = g_strdup_printf ("%s/%s", ino->ent->name, path); |
548 |
|
g_free (path); |
549 |
|
path = newpath; |
550 |
|
} |
551 |
|
return path; |
552 |
|
} |
553 |
|
|
554 |
|
/* It must be directory */ |
555 |
|
if ((!ino->ent->dir) || (!ino->ent->dir->ent)) |
556 |
|
return g_strdup (ino->ent->name); |
557 |
|
|
558 |
return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, |
return g_strconcat (ino->ent->dir->ent->name, PATH_SEP_STR, |
559 |
ino->ent->name, NULL); |
ino->ent->name, NULL); |
560 |
} |
} |
561 |
|
|
562 |
/* Support of archives */ |
/* Support of archives */ |