/* pfs-fs.c:
*
****************************************************************
* Copyright (C) 2002, 2003 Scott Parish
* Copyright (C) 2003 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "config-options.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/bugs/panic.h"
#include "hackerlab/machine/types.h"
#include "hackerlab/mem/alloc-limits.h"
#include "hackerlab/mem/mem.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/os/errno-to-string.h"
#include "hackerlab/vu/safe.h"
#include "libfsutils/dir-as-cwd.h"
#include "libfsutils/dir-listing.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/copy-file.h"
#include "libfsutils/file-contents.h"
#include "libarch/archives.h"
#include "libarch/exec.h"
#include "libarch/pfs-fs.h"
struct arch_pfs_fs_session
{
struct arch_pfs_session pfs;
t_uchar * cwd;
};
/* __STDC__ prototypes for static functions */
static t_uchar * fs_abs_path (t_uchar * cwd, t_uchar *path);
static void fs_disconnect (struct arch_pfs_session **pfs);
static int fs_get (struct arch_pfs_fs_session * p, int data_fd, t_uchar * path, int soft_errors);
static int pfs_get_file (struct arch_pfs_session * p, int out_fd, t_uchar * path, int soft_errors);
static t_uchar * pfs_file_contents (struct arch_pfs_session * p, t_uchar * path, int soft_errors);
static rel_table pfs_directory_files (struct arch_pfs_session * p, t_uchar * path, int soft_errors);
static int pfs_put_file (struct arch_pfs_session *p, t_uchar * path, mode_t perms, int data_fd, int soft_errors);
static int pfs_mkdir (struct arch_pfs_session * p, t_uchar * path, mode_t mode, int soft_errors);
static int pfs_file_exists (struct arch_pfs_session * p, t_uchar * path);
static int pfs_is_dir (struct arch_pfs_session * p, t_uchar * path);
static int pfs_rename (struct arch_pfs_session * p, t_uchar ** errstr, t_uchar * from_rel, t_uchar * to_rel, int soft_errors);
static int pfs_rmdir (struct arch_pfs_session * p, t_uchar * path, int soft_errors);
static int pfs_rm (struct arch_pfs_session * p, t_uchar * path, int soft_errors);
static t_uchar * dirfold (t_uchar *dir);
struct arch_pfs_vtable fs_pfs_fns =
{
fs_disconnect,
pfs_file_exists,
pfs_is_dir,
pfs_file_contents,
pfs_get_file,
pfs_directory_files,
pfs_put_file,
pfs_mkdir,
pfs_rename,
pfs_rmdir,
pfs_rm,
};
struct arch_pfs_session *
arch_pfs_fs_connect (t_uchar * uri, int safe_errors)
{
struct arch_pfs_fs_session * answer = NULL;
t_uchar *myuri;
if (str_length (uri) > 7 && !str_cmp_prefix("file:", uri))
myuri = unescape_location(uri+7);
else
myuri = unescape_location(uri);
invariant (!!myuri);
answer = (struct arch_pfs_fs_session *)lim_malloc (0, sizeof (*answer));
mem_set0 ((t_uchar *)answer, sizeof (*answer));
answer->pfs.vtable = &fs_pfs_fns;
if (directory_as_cwd_unsafe (&answer->cwd, myuri))
{
if (!safe_errors)
{
safe_printfmt (2, "arch_pfs_fs_connect: failed to get the dir for %s\n", myuri);
exit (1);
}
lim_free (0, answer);
lim_free (0, myuri);
return NULL;
}
lim_free (0, myuri);
return &answer->pfs;
}
static t_uchar *
fs_abs_path (t_uchar * cwd, t_uchar *path)
{
t_uchar * ap;
if (path[0] != '/')
ap = str_alloc_cat_many (0, cwd, "/", path, str_end);
else
ap = str_save (0, path);
return dirfold (ap);
}
void
fs_disconnect (struct arch_pfs_session **session)
{
/* FIXME: close stuff yadayadayada */
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)(*session);
lim_free (0, pfs->cwd);
lim_free (0, *session);
*session = NULL;
}
static int
fs_get (struct arch_pfs_fs_session * p, int data_fd, t_uchar * path, int soft_errors)
{
t_uchar * file = 0;
int errn;
int fd;
file = fs_abs_path (p->cwd, path);
fd = vu_open (&errn, file , O_RDONLY, 0444);
if (fd < 0)
{
if (soft_errors)
{
lim_free (0, file);
return -1;
}
safe_printfmt (2, "Failed to open files: %s\n", file);
exit (2);
}
safe_lseek (fd, (off_t)0, SEEK_SET);
copy_fd (fd, data_fd);
safe_close (fd);
lim_free (0, file);
return 0;
}
static int
pfs_get_file (struct arch_pfs_session * p, int out_fd, t_uchar * path, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
return fs_get (pfs, out_fd, path, soft_errors);
}
static t_uchar *
pfs_file_contents (struct arch_pfs_session * p, t_uchar * path, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
int errn;
int fd;
t_uchar * answer = 0;
t_uchar * file = 0;
file = fs_abs_path (pfs->cwd, path);
fd = vu_open (&errn, file , O_RDONLY, 0444);
if (fd == -1)
{
if (soft_errors)
{
lim_free (0, file);
return 0;
}
safe_printfmt (2, "Failed to open files: %s\n", fs_abs_path (pfs->cwd, path));
exit (2);
}
safe_lseek (fd, (off_t)0, SEEK_SET);
answer = fd_contents (fd);
safe_close (fd);
lim_free (0, file);
return answer;
}
static rel_table
pfs_directory_files (struct arch_pfs_session * p, t_uchar * path, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
rel_table answer = 0;
t_uchar * dir = 0;
dir = fs_abs_path (pfs->cwd, path);
if (!safe_file_is_directory_following (dir))
{
if (soft_errors)
return 0;
else
{
safe_printfmt (2, "not a directory (%s)\n", dir);
exit (2);
}
}
answer = directory_files (dir);
lim_free (0, dir);
return answer;
}
static int
pfs_put_file (struct arch_pfs_session *p, t_uchar * path, mode_t perms, int data_fd, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
t_uchar * file = 0;
int errn;
int fd;
file = fs_abs_path (pfs->cwd, path);
fd = vu_open (&errn, file , O_WRONLY | O_CREAT | O_EXCL, perms);
if (fd == -1)
{
if (soft_errors)
{
lim_free (0, file);
return -1;
}
safe_printfmt (2, "Failed to open files: %s\n", file);
exit (2);
}
copy_fd (data_fd, fd);
safe_close (fd);
lim_free (0, file);
return 0;
}
static int
pfs_mkdir (struct arch_pfs_session * p, t_uchar * path, mode_t mode, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
t_uchar * dir = 0;
int errn;
int answer;
dir = fs_abs_path (pfs->cwd, path);
answer = vu_mkdir (&errn, dir , mode);
if (answer && !soft_errors)
{
safe_printfmt (2, "Failed to create directory: %s\n", dir);
exit (2);
}
lim_free (0, dir);
return answer;
}
static int
pfs_file_exists (struct arch_pfs_session * p, t_uchar * path)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
t_uchar * abs_path = 0;
int answer;
abs_path = fs_abs_path (pfs->cwd, path);
answer = !safe_access (abs_path, F_OK);
lim_free (0, abs_path);
return answer;
}
static int
pfs_is_dir (struct arch_pfs_session * p, t_uchar * path)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
t_uchar * abs_path = 0;
struct stat stat_buf;
int errn;
int answer;
abs_path = fs_abs_path (pfs->cwd, path);
if (vu_stat (&errn, abs_path, &stat_buf))
answer = -1;
else
answer = !!S_ISDIR (stat_buf.st_mode);
lim_free (0, abs_path);
return answer;
}
static int
pfs_rename (struct arch_pfs_session * p, t_uchar ** errstr, t_uchar * from_rel, t_uchar * to_rel, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
int ret = 0;
int errn;
t_uchar * from = 0;
t_uchar * to = 0;
from = fs_abs_path (pfs->cwd, from_rel);
to = fs_abs_path (pfs->cwd, to_rel);
ret = vu_rename (&errn, from, to);
if (ret)
{
if (soft_errors)
{
if (errstr)
*errstr = str_save (0, "could not rename file.");
}
else
{
safe_printfmt (2, "Failed to rename file: %s => %s\n", from, to);
exit (2);
}
}
lim_free (0, from);
lim_free (0, to);
return ret;
}
static int
pfs_rmdir (struct arch_pfs_session * p, t_uchar * path, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
int errn;
int ret;
t_uchar * dir = 0;
dir = fs_abs_path (pfs->cwd, path);
ret = vu_rmdir (&errn, dir);
if (ret && !soft_errors)
{
safe_printfmt (2, "Failed to remove directory: %s\n", dir);
exit (2);
}
lim_free (0, dir);
return ret;
}
static int
pfs_rm (struct arch_pfs_session * p, t_uchar * path, int soft_errors)
{
struct arch_pfs_fs_session * pfs = (struct arch_pfs_fs_session *)p;
int errn;
int ret;
char * file = 0;
file = fs_abs_path (pfs->cwd, path);
ret = vu_unlink (&errn, file);
if (ret && !soft_errors)
{
safe_printfmt (2, "Failed to remove file: %s\n", file);
exit (2);
}
lim_free (0, file);
return ret;
}
static t_uchar *
dirfold (t_uchar *dir)
{
t_uchar * buf;
t_uchar * this;
t_uchar * next;
int dir_i = 0;
this = next = buf = str_save (0, dir);
while ((this = str_separate (&next, "/")) != NULL)
{
if (str_length (this) == 0 || (str_length (this) == 1 && this[0] == '.'))
continue;
else if (str_length (this) == 2 && *this == '.' && this[1] == '.')
{
if (dir_i > 0)
dir_i = (int)((char *)strrchr (dir, '/') - (char *)dir);
dir[dir_i] = 0;
}
else
{
dir[dir_i++] = '/';
strcpy (dir + dir_i, this);
dir_i += str_length (this);
}
}
lim_free (0, buf);
if (!str_length (dir))
str_cpy (dir, "/");
return dir;
}
/* tag: Tom Lord Thu Jun 5 15:23:06 2003 (pfs-fs.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1