Beispiel #1
0
static INLINE bool
SI_close_win_handles(FSFileHandle *self) {
    FSFileHandleIVARS *ivars = FSFH_IVARS(self);
    // Close both standard handle and mapping handle.
    if (ivars->win_maphandle) {
        if (!CloseHandle(ivars->win_maphandle)) {
            char *win_error = Err_win_error();
            Err_set_error(Err_new(CB_newf("Failed to close file mapping handle: %s",
                                          win_error)));
            FREEMEM(win_error);
            return false;
        }
        ivars->win_maphandle = NULL;
    }
    if (ivars->win_fhandle) {
        if (!CloseHandle(ivars->win_fhandle)) {
            char *win_error = Err_win_error();
            Err_set_error(Err_new(CB_newf("Failed to close file handle: %s",
                                          win_error)));
            FREEMEM(win_error);
            return false;
        }
        ivars->win_fhandle = NULL;
    }

    return true;
}
Beispiel #2
0
bool
FSFH_read(FSFileHandle *self, char *dest, int64_t offset, size_t len) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);
    int64_t check_val;

    // Sanity check.
    if (offset < 0) {
        Err_set_error(Err_new(CB_newf("Can't read from an offset less than 0 (%i64)",
                                      offset)));
        return false;
    }

    // Read.
    check_val = pread64(ivars->fd, dest, len, offset);
    if (check_val != (int64_t)len) {
        if (check_val == -1) {
            Err_set_error(Err_new(CB_newf("Tried to read %u64 bytes, got %i64: %s",
                                          (uint64_t)len, check_val, strerror(errno))));
        }
        else {
            Err_set_error(Err_new(CB_newf("Tried to read %u64 bytes, got %i64",
                                          (uint64_t)len, check_val)));
        }
        return false;
    }

    return true;
}
Beispiel #3
0
bool
FSFH_close(FSFileHandle *self) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);

    // On 64-bit systems, cancel the whole-file mapping.
    if (IS_64_BIT && (ivars->flags & FH_READ_ONLY) && ivars->buf != NULL) {
        if (!SI_unmap(self, ivars->buf, ivars->len)) { return false; }
        ivars->buf = NULL;
    }

    // Close system-specific handles.
    if (ivars->fd) {
        if (close(ivars->fd)) {
            Err_set_error(Err_new(CB_newf("Failed to close file: %s",
                                          strerror(errno))));
            return false;
        }
        ivars->fd  = 0;
    }
    #if (defined(CHY_HAS_WINDOWS_H) && !defined(CHY_HAS_SYS_MMAN_H))
    if (ivars->win_fhandle) {
        if (!SI_close_win_handles(self)) { return false; }
    }
    #endif

    return true;
}
Beispiel #4
0
static INLINE bool
SI_unmap(FSFileHandle *self, char *buf, int64_t len) {
    if (buf != NULL) {
        if (munmap(buf, len)) {
            Err_set_error(Err_new(CB_newf("Failed to munmap '%o': %s",
                                          FSFH_IVARS(self)->path,
                                          strerror(errno))));
            return false;
        }
    }
    return true;
}
Beispiel #5
0
static INLINE bool
SI_unmap(FSFileHandle *self, char *ptr, int64_t len) {
    if (buf != NULL) {
        if (!UnmapViewOfFile(buf)) {
            char *win_error = Err_win_error();
            Err_set_error(Err_new(CB_newf("Failed to unmap '%o': %s",
                                          FSFH_IVARS(self)->path,
                                          win_error)));
            FREEMEM(win_error);
            return false;
        }
    }
    return true;
}
Beispiel #6
0
static void
test_Close(TestBatchRunner *runner) {
    String *test_filename = (String*)SSTR_WRAP_UTF8("_fstest", 7);
    FSFileHandle *fh;

    remove(Str_Get_Ptr8(test_filename));
    fh = FSFH_open(test_filename,
                   FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
    TEST_TRUE(runner, FSFH_Close(fh), "Close returns true for write-only");
    DECREF(fh);

    // Simulate an OS error when closing the file descriptor.  This
    // approximates what would happen if, say, we run out of disk space.
    remove(Str_Get_Ptr8(test_filename));
    fh = FSFH_open(test_filename,
                   FH_CREATE | FH_WRITE_ONLY | FH_EXCLUSIVE);
#ifdef _MSC_VER
    SKIP(runner, "LUCY-155");
    SKIP(runner, "LUCY-155");
#else
    int saved_fd = FSFH_IVARS(fh)->fd;
    FSFH_IVARS(fh)->fd = -1;
    Err_set_error(NULL);
    bool result = FSFH_Close(fh);
    TEST_FALSE(runner, result, "Failed Close() returns false");
    TEST_TRUE(runner, Err_get_error() != NULL,
              "Failed Close() sets Err_error");
    FSFH_IVARS(fh)->fd = saved_fd;
#endif /* _MSC_VER */
    DECREF(fh);

    fh = FSFH_open(test_filename, FH_READ_ONLY);
    TEST_TRUE(runner, FSFH_Close(fh), "Close returns true for read-only");

    DECREF(fh);
    remove(Str_Get_Ptr8(test_filename));
}
Beispiel #7
0
bool
FSFH_read(FSFileHandle *self, char *dest, int64_t offset, size_t len) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);
    BOOL check_val;
    DWORD got;
    OVERLAPPED read_op_state;
    uint64_t offs = (uint64_t)offset;

    read_op_state.hEvent     = NULL;
    read_op_state.OffsetHigh = offs >> 32;
    read_op_state.Offset     = offs & 0xFFFFFFFF;

    // Sanity check.
    if (offset < 0) {
        Err_set_error(Err_new(CB_newf("Can't read from an offset less than 0 (%i64)",
                                      offset)));
        return false;
    }

    // ReadFile() takes a DWORD (unsigned 32-bit integer) as a length
    // argument, so throw a sensible error rather than wrap around.
    if (len > UINT32_MAX) {
        Err_set_error(Err_new(CB_newf("Can't read more than 4 GB (%u64)",
                                      (uint64_t)len)));
        return false;
    }

    // Read.
    check_val = ReadFile(ivars->win_fhandle, dest, len, &got, &read_op_state);
    if (!check_val && GetLastError() == ERROR_IO_PENDING) {
        // Read has been queued by the OS and will soon complete.  Wait for
        // it, since this is a blocking IO call from the point of the rest of
        // the library.
        check_val = GetOverlappedResult(ivars->win_fhandle, &read_op_state,
                                        &got, TRUE);
    }

    // Verify that the read has succeeded by now.
    if (!check_val) {
        char *win_error = Err_win_error();
        Err_set_error(Err_new(CB_newf("Failed to read %u64 bytes: %s",
                                      (uint64_t)len, win_error)));
        FREEMEM(win_error);
        return false;
    }

    return true;
}
Beispiel #8
0
bool
FSFH_read(FSFileHandle *self, char *dest, int64_t offset, size_t len) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);
    const int64_t end = offset + len;

    if (ivars->flags & FH_WRITE_ONLY) {
        Err_set_error(Err_new(CB_newf("Can't read from write-only filehandle")));
        return false;
    }
    if (offset < 0) {
        Err_set_error(Err_new(CB_newf("Can't read from an offset less than 0 (%i64)",
                                      offset)));
        return false;
    }
    else if (end > ivars->len) {
        Err_set_error(Err_new(CB_newf("Tried to read past EOF: offset %i64 + request %u64 > len %i64",
                                      offset, (uint64_t)len, ivars->len)));
        return false;
    }
    memcpy(dest, ivars->buf + offset, len);
    return true;
}
Beispiel #9
0
bool
FSFH_window(FSFileHandle *self, FileWindow *window, int64_t offset,
            int64_t len) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);
    const int64_t end = offset + len;
    if (!(ivars->flags & FH_READ_ONLY)) {
        Err_set_error(Err_new(CB_newf("Can't read from write-only handle")));
        return false;
    }
    else if (offset < 0) {
        Err_set_error(Err_new(CB_newf("Can't read from negative offset %i64",
                                      offset)));
        return false;
    }
    else if (end > ivars->len) {
        Err_set_error(Err_new(CB_newf("Tried to read past EOF: offset %i64 + request %i64 > len %i64",
                                      offset, len, ivars->len)));
        return false;
    }
    else {
        return SI_window(self, ivars, window, offset, len);
    }
}
Beispiel #10
0
bool
FSFH_write(FSFileHandle *self, const void *data, size_t len) {
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);

    if (len) {
        // Write data, track file length, check for errors.
        int64_t check_val = write(ivars->fd, data, len);
        ivars->len += check_val;
        if ((size_t)check_val != len) {
            if (check_val == -1) {
                Err_set_error(Err_new(CB_newf("Error when writing %u64 bytes: %s",
                                              (uint64_t)len, strerror(errno))));
            }
            else {
                Err_set_error(Err_new(CB_newf("Attempted to write %u64 bytes, but wrote %i64",
                                              (uint64_t)len, check_val)));
            }
            return false;
        }
    }

    return true;
}
Beispiel #11
0
FSFileHandle*
FSFH_do_open(FSFileHandle *self, const CharBuf *path, uint32_t flags) {
    FH_do_open((FileHandle*)self, path, flags);
    FSFileHandleIVARS *const ivars = FSFH_IVARS(self);
    if (!path || !CB_Get_Size(path)) {
        Err_set_error(Err_new(CB_newf("Missing required param 'path'")));
        CFISH_DECREF(self);
        return NULL;
    }

    // Attempt to open file.
    if (flags & FH_WRITE_ONLY) {
        ivars->fd = open((char*)CB_Get_Ptr8(path), SI_posix_flags(flags), 0666);
        if (ivars->fd == -1) {
            ivars->fd = 0;
            Err_set_error(Err_new(CB_newf("Attempt to open '%o' failed: %s",
                                          path, strerror(errno))));
            CFISH_DECREF(self);
            return NULL;
        }
        if (flags & FH_EXCLUSIVE) {
            ivars->len = 0;
        }
        else {
            // Derive length.
            ivars->len = lseek64(ivars->fd, INT64_C(0), SEEK_END);
            if (ivars->len == -1) {
                Err_set_error(Err_new(CB_newf("lseek64 on %o failed: %s",
                                              ivars->path, strerror(errno))));
                CFISH_DECREF(self);
                return NULL;
            }
            else {
                int64_t check_val = lseek64(ivars->fd, INT64_C(0), SEEK_SET);
                if (check_val == -1) {
                    Err_set_error(Err_new(CB_newf("lseek64 on %o failed: %s",
                                                  ivars->path, strerror(errno))));
                    CFISH_DECREF(self);
                    return NULL;
                }
            }
        }
    }
    else if (flags & FH_READ_ONLY) {
        if (SI_init_read_only(self, ivars)) {
            // On 64-bit systems, map the whole file up-front.
            if (IS_64_BIT && ivars->len) {
                ivars->buf = (char*)SI_map(self, ivars, 0, ivars->len);
                if (!ivars->buf) {
                    // An error occurred during SI_map, which has set
                    // Err_error for us already.
                    CFISH_DECREF(self);
                    return NULL;
                }
            }
        }
        else {
            CFISH_DECREF(self);
            return NULL;
        }
    }
    else {
        Err_set_error(Err_new(CB_newf("Must specify FH_READ_ONLY or FH_WRITE_ONLY to open '%o'",
                                      path)));
        CFISH_DECREF(self);
        return NULL;
    }

    return self;
}
Beispiel #12
0
int64_t
FSFH_length(FSFileHandle *self) {
    return FSFH_IVARS(self)->len;
}