Exemple #1
0
/* rename one file to another. */
void MVM_file_rename(MVMThreadContext *tc, MVMString *src, MVMString *dest) {
    char * const a = MVM_string_utf8_c8_encode_C_string(tc, src);
    char * const b = MVM_string_utf8_c8_encode_C_string(tc, dest);
    uv_fs_t req;

    if(uv_fs_rename(tc->loop, &req, a, b, NULL) < 0 ) {
        MVM_free(a);
        MVM_free(b);
        MVM_exception_throw_adhoc(tc, "Failed to rename file: %s", uv_strerror(req.result));
    }

    MVM_free(a);
    MVM_free(b);
}
Exemple #2
0
/* Opens a file, returning a synchronous file handle. */
MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) {
    char          * const fname  = MVM_string_utf8_c8_encode_C_string(tc, filename);
    char          * const fmode  = MVM_string_utf8_encode_C_string(tc, mode);
    MVMOSHandle   * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO);
    MVMIOFileData * const data   = MVM_calloc(1, sizeof(MVMIOFileData));
    uv_fs_t req;
    uv_file fd;

    /* Resolve mode description to flags. */
    int flag;
    if (!resolve_open_mode(&flag, fmode)) {
        char *waste[] = { fmode, NULL };
        MVM_free(fname);
        MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode: %s", fmode);
    }
    MVM_free(fmode);

    /* Try to open the file. */
    if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) {
        char *waste[] = { fname, NULL };
        MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, uv_strerror(req.result));
    }

    /* Set up handle. */
    data->fd          = fd;
    data->filename    = fname;
    data->encoding    = MVM_encoding_type_utf8;
    MVM_string_decode_stream_sep_default(tc, &(data->sep_spec));
    result->body.ops  = &op_table;
    result->body.data = data;

    return (MVMObject *)result;
}
Exemple #3
0
MVMint64 MVM_file_isexecutable(MVMThreadContext *tc, MVMString *filename, MVMint32 use_lstat) {
    if (!MVM_file_exists(tc, filename, use_lstat))
        return 0;
    else {
        MVMint64 r = 0;
        uv_stat_t statbuf = file_info(tc, filename, use_lstat);
        if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
            return 1;
        else {
            // true if fileext is in PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
            MVMString *dot = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, ".");
            MVMROOT(tc, dot, {
                MVMint64 n = MVM_string_index_from_end(tc, filename, dot, 0);
                if (n >= 0) {
                    MVMString *fileext = MVM_string_substring(tc, filename, n, -1);
                    char *ext  = MVM_string_utf8_c8_encode_C_string(tc, fileext);
                    char *pext = getenv("PATHEXT");
                    int plen   = strlen(pext);
                    int i;
                    for (i = 0; i < plen; i++) {
                        if (0 == stricmp(ext, pext++)) {
                             r = 1;
                             break;
                        }
                    }
                    MVM_free(ext);
                    MVM_free(pext);
                }
            });
        }
        return r;
    }
Exemple #4
0
/* Change directory. */
void MVM_dir_chdir(MVMThreadContext *tc, MVMString *dir) {
    char * const dirstring = MVM_string_utf8_c8_encode_C_string(tc, dir);

    if (uv_chdir((const char *)dirstring) != 0) {
        MVM_free(dirstring);
        MVM_exception_throw_adhoc(tc, "chdir failed: %s", uv_strerror(errno));
    }

    MVM_free(dirstring);
}
Exemple #5
0
/* Remove a directory recursively. */
void MVM_dir_rmdir(MVMThreadContext *tc, MVMString *path) {
    char * const pathname = MVM_string_utf8_c8_encode_C_string(tc, path);
    uv_fs_t req;

    if(uv_fs_rmdir(tc->loop, &req, pathname, NULL) < 0 ) {
        MVM_free(pathname);
        MVM_exception_throw_adhoc(tc, "Failed to rmdir: %s", uv_strerror(req.result));
    }

    MVM_free(pathname);
}
Exemple #6
0
void MVM_file_chmod(MVMThreadContext *tc, MVMString *f, MVMint64 flag) {
    char * const a = MVM_string_utf8_c8_encode_C_string(tc, f);
    uv_fs_t req;

    if(uv_fs_chmod(tc->loop, &req, a, flag, NULL) < 0 ) {
        MVM_free(a);
        MVM_exception_throw_adhoc(tc, "Failed to set permissions on path: %s", uv_strerror(req.result));
    }

    MVM_free(a);
}
Exemple #7
0
/* Opens a file, returning a synchronous file handle. */
MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) {
    char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename);
    int fd;
    int flag;
    STAT statbuf;

    /* Resolve mode description to flags. */
    char * const fmode  = MVM_string_utf8_encode_C_string(tc, mode);
    if (!resolve_open_mode(&flag, fmode)) {
        char *waste[] = { fname, fmode, NULL };
        MVM_exception_throw_adhoc_free(tc, waste,
            "Invalid open mode for file %s: %s", fname, fmode);
    }
    MVM_free(fmode);

    /* Try to open the file. */
#ifdef _WIN32
    flag |= _O_BINARY;
#endif
    if ((fd = open((const char *)fname, flag, DEFAULT_MODE)) == -1) {
        char *waste[] = { fname, NULL };
        const char *err = strerror(errno);
        MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err);
    }

    /*  Check that we didn't open a directory by accident.
        If fstat fails, just move on: Most of the documented error cases should
        already have triggered when opening the file, and we can't do anything
        about the others; a failure also does not necessarily imply that the
        file descriptor cannot be used for reading/writing. */
    if (fstat(fd, &statbuf) == 0 && (statbuf.st_mode & S_IFMT) == S_IFDIR) {
        char *waste[] = { fname, NULL };
        if (close(fd) == -1) {
            const char *err = strerror(errno);
            MVM_exception_throw_adhoc_free(tc, waste,
                "Tried to open directory %s, which we failed to close: %s",
                fname, err);
        }
        MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname);
    }

    /* Set up handle. */
    MVM_free(fname);
    {
        MVMIOFileData * const data   = MVM_calloc(1, sizeof(MVMIOFileData));
        MVMOSHandle   * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc,
            tc->instance->boot_types.BOOTIO);
        data->fd          = fd;
        data->seekable    = MVM_platform_lseek(fd, 0, SEEK_CUR) != -1;
        result->body.ops  = &op_table;
        result->body.data = data;
        return (MVMObject *)result;
    }
}
Exemple #8
0
MVMint64 MVM_file_exists(MVMThreadContext *tc, MVMString *f, MVMint32 use_lstat) {
    uv_fs_t req;
    char * const a = MVM_string_utf8_c8_encode_C_string(tc, f);
    const MVMint64 result = (use_lstat
      ? uv_fs_lstat(tc->loop, &req, a, NULL)
      :  uv_fs_stat(tc->loop, &req, a, NULL)
    ) < 0 ? 0 : 1;

    MVM_free(a);

    return result;
}
Exemple #9
0
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env,
        MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) {
    MVMint64 result = 0, spawn_result;
    uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i, process_still_running;

    char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd);
    char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd);
    const MVMuint64 size = MVM_repr_elems(tc, env);
    char **_env = MVM_malloc((size + 1) * sizeof(char *));
    MVMIter *iter;

#ifdef _WIN32
    const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */
    char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec"));
    char *args[3];
    args[0] = "/c";
    args[1] = cmdin;
    args[2] = NULL;
#else
    char * const _cmd = "/bin/sh";
    char *args[4];
    args[0] = "/bin/sh";
    args[1] = "-c";
    args[2] = cmdin;
    args[3] = NULL;
#endif

    MVMROOT(tc, in, {
    MVMROOT(tc, out, {
    MVMROOT(tc, err, {
        iter = (MVMIter *)MVM_iter(tc, env);
        INIT_ENV();
    });
    });
Exemple #10
0
static uv_stat_t file_info(MVMThreadContext *tc, MVMString *filename, MVMint32 use_lstat) {
    char * const a = MVM_string_utf8_c8_encode_C_string(tc, filename);
    uv_fs_t req;

    if ((use_lstat
      ? uv_fs_lstat(tc->loop, &req, a, NULL)
      :  uv_fs_stat(tc->loop, &req, a, NULL)
    ) < 0) {
        MVM_free(a);
        MVM_exception_throw_adhoc(tc, "Failed to stat file: %s", uv_strerror(req.result));
    }

    MVM_free(a);
    return req.statbuf;
}
Exemple #11
0
void MVM_load_bytecode(MVMThreadContext *tc, MVMString *filename) {
    MVMCompUnit *cu;
    MVMLoadedCompUnitName *loaded_name;

    /* Work out actual filename to use, taking --libpath into account. */
    filename = MVM_file_in_libpath(tc, filename);

    /* See if we already loaded this. */
    uv_mutex_lock(&tc->instance->mutex_loaded_compunits);
    MVM_string_flatten(tc, filename);
    MVM_HASH_GET(tc, tc->instance->loaded_compunits, filename, loaded_name);
    if (loaded_name) {
        /* already loaded */
        uv_mutex_unlock(&tc->instance->mutex_loaded_compunits);
        return;
    }

    /* Otherwise, load from disk. */
    MVMROOT(tc, filename, {
        char *c_filename = MVM_string_utf8_c8_encode_C_string(tc, filename);
        /* XXX any exception from MVM_cu_map_from_file needs to be handled
         *     and c_filename needs to be freed */
        cu = MVM_cu_map_from_file(tc, c_filename);
        MVM_free(c_filename);
        cu->body.filename = filename;

        /* If there's a deserialization frame, need to run that. */
        if (cu->body.deserialize_frame) {
            /* Set up special return to delegate to running the load frame,
             * if any. */
            tc->cur_frame->return_value             = NULL;
            tc->cur_frame->return_type              = MVM_RETURN_VOID;
            tc->cur_frame->special_return           = run_load;
            tc->cur_frame->special_return_data      = cu;
            tc->cur_frame->mark_special_return_data = mark_sr_data;

            /* Invoke the deserialization frame and return to the runloop. */
            MVM_frame_invoke(tc, cu->body.deserialize_frame, MVM_callsite_get_common(tc, MVM_CALLSITE_ID_NULL_ARGS),
                NULL, NULL, NULL, -1);
        }
        else {
            /* No deserialize frame, so do load frame instead. */
            run_load(tc, cu);
        }
        loaded_name = MVM_calloc(1, sizeof(MVMLoadedCompUnitName));
        loaded_name->filename = filename;
        MVM_HASH_BIND(tc, tc->instance->loaded_compunits, filename, loaded_name);
    });
Exemple #12
0
/* Create a directory recursively. */
void MVM_dir_mkdir(MVMThreadContext *tc, MVMString *path, MVMint64 mode) {
    char * const pathname = MVM_string_utf8_c8_encode_C_string(tc, path);

#ifdef _WIN32
    /* Must using UTF8ToUnicode for supporting CJK Windows file name. */
    wchar_t *wpathname = UTF8ToUnicode(pathname);
    int str_len = wcslen(wpathname);

    if (str_len > MAX_PATH) {
        wchar_t  abs_dirname[4096]; /* 4096 should be enough for absolute path */
        wchar_t *lpp_part;

        /* You cannot use the "\\?\" prefix with a relative path,
         * relative paths are always limited to a total of MAX_PATH characters.
         * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx */
        if (!GetFullPathNameW(wpathname, 4096, abs_dirname, &lpp_part)) {
            MVM_exception_throw_adhoc(tc, "Directory path is wrong: %d", GetLastError());
        }

        MVM_free(wpathname);

        str_len  = wcslen(abs_dirname);
        wpathname = (wchar_t *)MVM_malloc((str_len + 4) * sizeof(wchar_t));
        wcscpy(wpathname, L"\\\\?\\");
        wcscat(wpathname, abs_dirname);
    }

    if (!mkdir_p(wpathname, mode)) {
        DWORD error = GetLastError();
        if (error != ERROR_ALREADY_EXISTS) {
            MVM_free(pathname);
            MVM_free(wpathname);
            MVM_exception_throw_adhoc(tc, "Failed to mkdir: %d", error);
        }
    }
    MVM_free(wpathname);
#else

    if (mkdir_p(pathname, mode) == -1 && errno != EEXIST) {
        MVM_free(pathname);
        MVM_exception_throw_adhoc(tc, "Failed to mkdir: %d", errno);
    }

#endif
    MVM_free(pathname);
}
Exemple #13
0
void MVM_file_delete(MVMThreadContext *tc, MVMString *f) {
    uv_fs_t req;
    char * const a = MVM_string_utf8_c8_encode_C_string(tc, f);

#ifdef _WIN32
    const int r = MVM_platform_unlink(a);

    if( r < 0 && r != ENOENT) {
        MVM_free(a);
        MVM_exception_throw_adhoc(tc, "Failed to delete file: %d", errno);
    }

#else
    const int r = uv_fs_unlink(tc->loop, &req, a, NULL);

    if( r < 0 && r != UV_ENOENT) {
        MVM_free(a);
        MVM_exception_throw_adhoc(tc, "Failed to delete file: %s", uv_strerror(req.result));
    }

#endif
    MVM_free(a);
}
Exemple #14
0
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env,
        MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) {
    MVMint64 result = 0, spawn_result;
    uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i;

    char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd);
    char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd);
    const MVMuint64 size = MVM_repr_elems(tc, env);
    MVMIter * const iter = (MVMIter *)MVM_iter(tc, env);
    char **_env = MVM_malloc((size + 1) * sizeof(char *));

#ifdef _WIN32
    const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */
    char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec"));
    char *args[3];
    args[0] = "/c";
    args[1] = cmdin;
    args[2] = NULL;
#else
    char * const _cmd = "/bin/sh";
    char *args[4];
    args[0] = "/bin/sh";
    args[1] = "-c";
    args[2] = cmdin;
    args[3] = NULL;
#endif

    INIT_ENV();
    setup_process_stdio(tc, in,  process, &process_stdio[0], 0, flags,      "shell");
    setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "shell");
    setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "shell");

    process_options.stdio       = process_stdio;
    process_options.file        = _cmd;
    process_options.args        = args;
    process_options.cwd         = _cwd;
    process_options.flags       = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE;
    process_options.env         = _env;
    process_options.stdio_count = 3;
    process_options.exit_cb     = spawn_on_exit;
    if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) {
        process->data = MVM_calloc(1, sizeof(MVMint64));
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
    }
    else {
        process->data = &result;
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
        else
            uv_run(tc->loop, UV_RUN_DEFAULT);
    }

    FREE_ENV();
    MVM_free(_cwd);
#ifdef _WIN32
    MVM_free(_cmd);
#endif
    MVM_free(cmdin);
    uv_unref((uv_handle_t *)process);

    return result;
}
Exemple #15
0
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMObject *argv, MVMString *cwd, MVMObject *env,
        MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) {
    MVMint64 result = 0, spawn_result;
    uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t));
    uv_process_options_t process_options = {0};
    uv_stdio_container_t process_stdio[3];
    int i;

    char   * const      _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd);
    const MVMuint64     size = MVM_repr_elems(tc, env);
    MVMIter * const     iter = (MVMIter *)MVM_iter(tc, env);
    char              **_env = MVM_malloc((size + 1) * sizeof(char *));
    const MVMuint64  arg_size = MVM_repr_elems(tc, argv);
    char             **args = MVM_malloc((arg_size + 1) * sizeof(char *));
    MVMRegister        reg;

    i = 0;
    while(i < arg_size) {
        REPR(argv)->pos_funcs.at_pos(tc, STABLE(argv), argv, OBJECT_BODY(argv), i, &reg, MVM_reg_obj);
        args[i++] = MVM_string_utf8_c8_encode_C_string(tc, MVM_repr_get_str(tc, reg.o));
    }
    args[arg_size] = NULL;

    INIT_ENV();
    setup_process_stdio(tc, in,  process, &process_stdio[0], 0, flags,      "spawn");
    setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "spawn");
    setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "spawn");

    process_options.stdio       = process_stdio;
    process_options.file        = arg_size ? args[0] : NULL;
    process_options.args        = args;
    process_options.cwd         = _cwd;
    process_options.flags       = UV_PROCESS_WINDOWS_HIDE;
    process_options.env         = _env;
    process_options.stdio_count = 3;
    process_options.exit_cb     = spawn_on_exit;
    if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) {
        process->data = MVM_calloc(1, sizeof(MVMint64));
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
    }
    else {
        process->data = &result;
        uv_ref((uv_handle_t *)process);
        spawn_result = uv_spawn(tc->loop, process, &process_options);
        if (spawn_result)
            result = spawn_result;
        else
            uv_run(tc->loop, UV_RUN_DEFAULT);
    }

    FREE_ENV();
    MVM_free(_cwd);
    uv_unref((uv_handle_t *)process);

    i = 0;
    while(args[i])
        MVM_free(args[i++]);

    MVM_free(args);

    return result;
}
Exemple #16
0
/* Open a filehandle, returning a handle. */
MVMObject * MVM_dir_open(MVMThreadContext *tc, MVMString *dirname) {
    MVMOSHandle  * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO);
    MVMIODirIter * const data   = MVM_calloc(1, sizeof(MVMIODirIter));
#ifdef _WIN32
    char *name;
    int str_len;
    wchar_t *wname;
    wchar_t *dir_name;

    name  = MVM_string_utf8_c8_encode_C_string(tc, dirname);
    wname = UTF8ToUnicode(name);
    MVM_free(name);

    str_len = wcslen(wname);

    if (str_len > MAX_PATH - 2) { // the length of later appended '\*' is 2
        wchar_t  abs_dirname[4096]; /* 4096 should be enough for absolute path */
        wchar_t *lpp_part;

        /* You cannot use the "\\?\" prefix with a relative path,
         * relative paths are always limited to a total of MAX_PATH characters.
         * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx */
        if (!GetFullPathNameW(wname, 4096, abs_dirname, &lpp_part)) {
            MVM_free(wname);
            MVM_exception_throw_adhoc(tc, "Directory path is wrong: %d", GetLastError());
        }
        MVM_free(wname);

        str_len  = wcslen(abs_dirname);
        dir_name = (wchar_t *)MVM_malloc((str_len + 7) * sizeof(wchar_t));
        wcscpy(dir_name, L"\\\\?\\");
        wcscat(dir_name, abs_dirname);
    } else {
        dir_name = (wchar_t *)MVM_malloc((str_len + 3) * sizeof(wchar_t));
        wcscpy(dir_name, wname);
        MVM_free(wname);
    }

    wcscat(dir_name, L"\\*");     /* Three characters are for the "\*" plus NULL appended.
                                   * see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200%28v=vs.85%29.aspx */

    data->dir_name   = dir_name;
    data->dir_handle = INVALID_HANDLE_VALUE;

#else
    char * const dir_name = MVM_string_utf8_c8_encode_C_string(tc, dirname);
    DIR * const dir_handle = opendir(dir_name);
    MVM_free(dir_name);

    if (!dir_handle)
        MVM_exception_throw_adhoc(tc, "Failed to open dir: %d", errno);

    data->dir_handle = dir_handle;
#endif

    data->encoding = MVM_encoding_type_utf8;
    result->body.ops  = &op_table;
    result->body.data = data;

    return (MVMObject *)result;
}
Exemple #17
0
/* copy a file from one to another */
void MVM_file_copy(MVMThreadContext *tc, MVMString *src, MVMString * dest) {
    /* TODO: on Windows we can use the CopyFile API, which is probaly
       more efficient, not to mention easier to use. */
    uv_fs_t req;
    char * a, * b;
    uv_file in_fd = -1, out_fd = -1;
    MVMuint64 size, offset;

    a = MVM_string_utf8_c8_encode_C_string(tc, src);
    b = MVM_string_utf8_c8_encode_C_string(tc, dest);

    /* If the file cannot be stat(), there is little point in going any further. */
    if (uv_fs_stat(tc->loop, &req, a, NULL) < 0)
        goto failure;
    size = req.statbuf.st_size;

    in_fd = uv_fs_open(tc->loop, &req, (const char *)a, O_RDONLY, 0, NULL);
    if (in_fd < 0) {
        goto failure;
    }

    out_fd = uv_fs_open(tc->loop, &req, (const char *)b, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_MODE, NULL);
    if (out_fd < 0) {
        goto failure;
    }

    offset = 0;
    do {
        /* sendfile() traditionally takes offset as a pointer argument
         * used a both input and output. libuv deviates by making
         * offset an integer and returning the number of bytes
         * sent. So it is necessary to add these explicitly. */
        MVMint64 sent = uv_fs_sendfile(tc->loop, &req, out_fd, in_fd, offset, size - offset, NULL);
        if (sent < 0) {
            goto failure;
        }
        offset += sent;
    } while (offset < size);

    /* Cleanup */
    if(uv_fs_close(tc->loop, &req, in_fd, NULL) < 0) {
        goto failure;
    }
    in_fd = -1;

    if (uv_fs_close(tc->loop, &req, out_fd, NULL) < 0) {
        goto failure;
    }

    MVM_free(b);
    MVM_free(a);
    return;

 failure: {
        /* First get the error, since it may be overwritten further on. */
        const char * error = uv_strerror(req.result);
        /* Basic premise: dealing with all failure cases is hard.
         * So to simplify, a and b are allocated in all conditions.
         * Also to simplify, in_fd are nonnegative if open, negative
         * otherwise. */
        MVM_free(b);
        MVM_free(a);
        /* If any of these fail there is nothing
         * further to do, since we're already failing */
        if (in_fd >= 0)
            uv_fs_close(tc->loop, &req, in_fd, NULL);
        if (out_fd >= 0)
            uv_fs_close(tc->loop, &req, out_fd, NULL);
        /* This function only throws adhoc errors, so the message is for
         * progammer eyes only */
        MVM_exception_throw_adhoc(tc, "Failed to copy file: %s", error);
    }
}
Exemple #18
0
MVMint64 MVM_file_stat(MVMThreadContext *tc, MVMString *filename, MVMint64 status, MVMint32 use_lstat) {
    MVMint64 r = -1;

    switch (status) {

        case MVM_STAT_EXISTS:             r = MVM_file_exists(tc, filename, use_lstat); break;

        case MVM_STAT_FILESIZE: {
                char * const a = MVM_string_utf8_c8_encode_C_string(tc, filename);
                uv_fs_t req;

                if ((use_lstat
                  ? uv_fs_lstat(tc->loop, &req, a, NULL)
                  :  uv_fs_stat(tc->loop, &req, a, NULL)
                ) < 0) {
                    MVM_free(a);
                    MVM_exception_throw_adhoc(tc, "Failed to stat file: %s", uv_strerror(req.result));
                }
                MVM_free(a);

                r = req.statbuf.st_size;
                break;
            }

        case MVM_STAT_ISDIR:              r = (file_info(tc, filename, use_lstat).st_mode & S_IFMT) == S_IFDIR; break;

        case MVM_STAT_ISREG:              r = (file_info(tc, filename, use_lstat).st_mode & S_IFMT) == S_IFREG; break;

        case MVM_STAT_ISDEV: {
            const int mode = file_info(tc, filename, use_lstat).st_mode;
#ifdef _WIN32
            r = mode & S_IFMT == S_IFCHR;
#else
            r = (mode & S_IFMT) == S_IFCHR || (mode & S_IFMT) == S_IFBLK;
#endif
            break;
        }

        case MVM_STAT_CREATETIME:         r = file_info(tc, filename, use_lstat).st_ctim.tv_sec; break;

        case MVM_STAT_ACCESSTIME:         r = file_info(tc, filename, use_lstat).st_atim.tv_sec; break;

        case MVM_STAT_MODIFYTIME:         r = file_info(tc, filename, use_lstat).st_mtim.tv_sec; break;

        case MVM_STAT_CHANGETIME:         r = file_info(tc, filename, use_lstat).st_ctim.tv_sec; break;

/*        case MVM_STAT_BACKUPTIME:         r = -1; break;  */

        case MVM_STAT_UID:                r = file_info(tc, filename, use_lstat).st_uid; break;

        case MVM_STAT_GID:                r = file_info(tc, filename, use_lstat).st_gid; break;

        case MVM_STAT_ISLNK:              r = (file_info(tc, filename, 1).st_mode & S_IFMT) == S_IFLNK; break;

        case MVM_STAT_PLATFORM_DEV:       r = file_info(tc, filename, use_lstat).st_dev; break;

        case MVM_STAT_PLATFORM_INODE:     r = file_info(tc, filename, use_lstat).st_ino; break;

        case MVM_STAT_PLATFORM_MODE:      r = file_info(tc, filename, use_lstat).st_mode; break;

        case MVM_STAT_PLATFORM_NLINKS:    r = file_info(tc, filename, use_lstat).st_nlink; break;

        case MVM_STAT_PLATFORM_DEVTYPE:   r = file_info(tc, filename, use_lstat).st_rdev; break;

        case MVM_STAT_PLATFORM_BLOCKSIZE: r = file_info(tc, filename, use_lstat).st_blksize; break;

        case MVM_STAT_PLATFORM_BLOCKS:    r = file_info(tc, filename, use_lstat).st_blocks; break;

        default: break;
    }

    return r;
}
Exemple #19
0
/* Opens a file, returning a synchronous file handle. */
MVMObject * MVM_file_open_fh(MVMThreadContext *tc, MVMString *filename, MVMString *mode) {
    char * const fname = MVM_string_utf8_c8_encode_C_string(tc, filename);
    uv_fs_t req;
    uv_file fd;
    int flag;

    /* Resolve mode description to flags. */
    {
        char * const fmode  = MVM_string_utf8_encode_C_string(tc, mode);

        if (!resolve_open_mode(&flag, fmode)) {
            char *waste[] = { fname, fmode, NULL };
            MVM_exception_throw_adhoc_free(tc, waste, "Invalid open mode for file %s: %s", fname, fmode);
        }
        MVM_free(fmode);
    }

    /* Try to open the file. */
    if ((fd = uv_fs_open(tc->loop, &req, (const char *)fname, flag, DEFAULT_MODE, NULL)) < 0) {
        char *waste[] = { fname, NULL };
        const char *err = uv_strerror(req.result);

        uv_fs_req_cleanup(&req);
        MVM_exception_throw_adhoc_free(tc, waste, "Failed to open file %s: %s", fname, err);
    }
    uv_fs_req_cleanup(&req);

    /*  Check that we didn't open a directory by accident.
        If fstat fails, just move on: Most of the documented error cases should
        already have triggered when opening the file, and we can't do anything
        about the others; a failure also does not necessarily imply that the
        file descriptor cannot be used for reading/writing. */
    if (uv_fs_fstat(tc->loop, &req, fd, NULL) == 0 && (req.statbuf.st_mode & S_IFMT) == S_IFDIR) {
        char *waste[] = { fname, NULL };

        uv_fs_req_cleanup(&req);

        if (uv_fs_close(tc->loop, &req, fd, NULL) < 0) {
            const char *err = uv_strerror(req.result);

            uv_fs_req_cleanup(&req);
            MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s, which we failed to close: %s",
                fname, err);
        }
        uv_fs_req_cleanup(&req);

        MVM_exception_throw_adhoc_free(tc, waste, "Tried to open directory %s", fname);
    }
    uv_fs_req_cleanup(&req);

    /* Set up handle. */
    {
        MVMIOFileData * const data   = MVM_calloc(1, sizeof(MVMIOFileData));
        MVMOSHandle   * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO);

        data->fd          = fd;
        data->filename    = fname;
        data->encoding    = MVM_encoding_type_utf8;
        MVM_string_decode_stream_sep_default(tc, &(data->sep_spec));
        result->body.ops  = &op_table;
        result->body.data = data;

        return (MVMObject *)result;
    }
}
Exemple #20
0
MVM_NO_RETURN static void parse_error(MVMThreadContext *tc, MVMString *s, const char* reason) {
    char* got = MVM_string_utf8_c8_encode_C_string(tc, s);
    char *waste[] = { got, NULL };
    MVM_exception_throw_adhoc_free(tc, waste, "Can't convert '%s' to num: %s", got, reason);
}