/* 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 #include #include #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) */