/* Seek to the specified position in the file. */ static void seek(MVMThreadContext *tc, MVMOSHandle *h, MVMint64 offset, MVMint64 whence) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; if (!data->seekable) MVM_exception_throw_adhoc(tc, "It is not possible to seek this kind of handle"); flush_output_buffer(tc, data); if (MVM_platform_lseek(data->fd, offset, whence) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); }
/* Seek to the specified position in the file. */ static void seek(MVMThreadContext *tc, MVMOSHandle *h, MVMint64 offset, MVMint64 whence) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; MVMint64 r; if (data->ds) { /* We'll start over from a new position. */ MVM_string_decodestream_destory(tc, data->ds); data->ds = NULL; } /* Seek, then get absolute position for new decodestream. */ if (MVM_platform_lseek(data->fd, offset, whence) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); if ((r = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); data->ds = MVM_string_decodestream_create(tc, data->encoding, r); }
/* 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; } }
/* Get curernt position in the file. */ static MVMint64 mvm_tell(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; MVMint64 r; if (data->ds) return MVM_string_decodestream_tell_bytes(tc, data->ds); if ((r = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to tell in filehandle: %d", errno); return r; }
/* Opens a file, returning a synchronous file handle. */ MVMObject * MVM_file_handle_from_fd(MVMThreadContext *tc, int fd) { MVMOSHandle * const result = (MVMOSHandle *)MVM_repr_alloc_init(tc, tc->instance->boot_types.BOOTIO); MVMIOFileData * const data = MVM_calloc(1, sizeof(MVMIOFileData)); data->fd = fd; data->seekable = MVM_platform_lseek(fd, 0, SEEK_CUR) != -1; result->body.ops = &op_table; result->body.data = data; #ifdef _WIN32 _setmode(fd, _O_BINARY); #endif return (MVMObject *)result; }
/* Checks if the end of file has been reached. */ static MVMint64 mvm_eof(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; MVMint64 seek_pos; uv_fs_t req; if (data->ds && !MVM_string_decodestream_is_empty(tc, data->ds)) return 0; if (uv_fs_fstat(tc->loop, &req, data->fd, NULL) == -1) { MVM_exception_throw_adhoc(tc, "Failed to stat file descriptor: %s", uv_strerror(req.result)); } if ((seek_pos = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); return req.statbuf.st_size == seek_pos; }
/* Get current position in the file. */ static MVMint64 mvm_tell(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; flush_output_buffer(tc, data); if (data->seekable) { MVMint64 r; if ((r = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to tell in filehandle: %d", errno); return r; } else { return data->byte_position; } }
/* Checks if the end of file has been reached. */ static MVMint64 mvm_eof(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; MVMint64 seek_pos; uv_fs_t req; if (data->ds && !MVM_string_decodestream_is_empty(tc, data->ds)) return 0; if (uv_fs_fstat(tc->loop, &req, data->fd, NULL) == -1) { MVM_exception_throw_adhoc(tc, "Failed to stat file descriptor: %s", uv_strerror(req.result)); } if ((seek_pos = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); /* Comparison with seek_pos for some special files, like those in /proc, * which file size is 0 can be false. In that case, we fall back to check * file size to detect EOF. */ return req.statbuf.st_size == seek_pos || req.statbuf.st_size == 0; }
/* Checks if the end of file has been reached. */ static MVMint64 mvm_eof(MVMThreadContext *tc, MVMOSHandle *h) { MVMIOFileData *data = (MVMIOFileData *)h->body.data; if (data->seekable) { MVMint64 seek_pos; STAT statbuf; if (fstat(data->fd, &statbuf) == -1) MVM_exception_throw_adhoc(tc, "Failed to stat file descriptor: %s", strerror(errno)); if ((seek_pos = MVM_platform_lseek(data->fd, 0, SEEK_CUR)) == -1) MVM_exception_throw_adhoc(tc, "Failed to seek in filehandle: %d", errno); /* Comparison with seek_pos for some special files, like those in /proc, * which file size is 0 can be false. In that case, we fall back to check * file size to detect EOF. */ return statbuf.st_size == seek_pos || statbuf.st_size == 0; } else { return data->eof_reported; } }