#include "node.h"
#include <current.h>
#include <verify_area.h>
#include <segment.h>
#include <errno.h>
#include <config.h>
static unsigned int get_len(const char *fs_basename)
{
unsigned int len;
char c;
len = 0;
while ((c = get_fs_byte(fs_basename)) && c != '/')
len++, fs_basename++;
return len;
}
static int resolve_internal(const char *fs_path, struct file_struct **file, struct file_struct **dir, const char **fs_basename)
{
int retval;
char c;
unsigned int len;
if (!verify_str(fs_path, PATH_MAX, &len))
return -EFAULT;
if (len == PATH_MAX)
return -ENAMETOOLONG;
if (!get_fs_byte(fs_path))
return -ENOENT;
*dir = *file = get_fs_byte(fs_path) == '/' ? root : get_wd();
node_hold(*dir);
node_hold(*file);
*fs_basename = fs_path;
while (1) {
while ((c = get_fs_byte(fs_path)) == '/')
fs_path++;
if (!c)
return 0;
node_release(*dir);
if (!(*dir = *file)) {
retval = -ENOENT;
goto error;
}
*fs_basename = fs_path;
if ((len = get_len(fs_path)) > NAME_MAX) {
retval = -ENAMETOOLONG;
goto error_release_dir;
}
if ((retval = find_node(*dir, fs_path, file)) < 0)
goto error_release_dir;
if (*file)
node_hold(*file);
fs_path += len;
if (*file && get_fs_byte(fs_path) == '/' && !node_is_dir(*file)) {
retval = -ENOTDIR;
goto error_release_file;
}
}
error_release_file:
node_release(*file);
error_release_dir:
node_release(*dir);
error:
return retval;
}
int resolve(const char *fs_path, struct file_struct **file)
{
struct file_struct *dir;
const char *fs_basename;
int rv;
if ((rv = resolve_internal(fs_path, file, &dir, &fs_basename)) < 0)
return rv;
if (dir)
node_release(dir);
if (!*file)
return -ENOENT;
return 0;
}
int resolve_dir(const char *fs_path, struct file_struct **dir, const char **fs_basename)
{
struct file_struct *file;
int rv;
if ((rv = resolve_internal(fs_path, &file, dir, fs_basename)) < 0)
return rv;
if (file)
node_release(file);
if (!*dir)
return -ENOENT;
return 0;
}
int file_exists(const char *fs_path)
{
struct file_struct *file;
struct file_struct *dir;
const char *fs_basename;
int rv;
if ((rv = resolve_internal(fs_path, &file, &dir, &fs_basename)) < 0)
return rv;
if (dir)
node_release(dir);
if (file)
node_release(file);
return file ? 1 : 0;
}