chunk_reader::pointer chunk_reader::get(slice_reader & base, const chunk & chunk) { if(!base.seek(chunk.first_slice, chunk.offset)) { throw chunk_error("error seeking"); } char magic[ARRAY_SIZE(chunk_id)]; if(base.read(magic, 4) != 4 || memcmp(magic, chunk_id, ARRAY_SIZE(chunk_id))) { throw chunk_error("bad chunk magic"); } pointer result = boost::make_shared<type>(); switch(chunk.compression) { case Stored: break; case Zlib: result->push(io::zlib_decompressor(), 8192); break; case BZip2: result->push(io::bzip2_decompressor(), 8192); break; #ifdef HAVE_LZMA case LZMA1: result->push(inno_lzma1_decompressor(), 8192); break; case LZMA2: result->push(inno_lzma2_decompressor(), 8192); break; #else case LZMA1: case LZMA2: throw chunk_error("LZMA decompression not supported by this Inno Extract build"); #endif default: throw chunk_error("unknown compression"); } result->push(io::restrict(boost::ref(base), 0, int64_t(chunk.size))); return result; }
/* Insert word into chunk */ void chunk_insert_word(chunk_ptr cp, word_t wd, size_t offset) { if (cp == NULL && chunk_check_level >= 2) { chunk_error("Null Pointer", cp); return; } if (chunk_check_level >= 2 && offset >= cp->length) { chunk_error("Out of bounds insertion", cp); return; } cp->words[offset] = wd; }
static int check_err(int code, char *source) { char ebuf[100]; if (code != 0) { sprintf(ebuf, "Error in %s. Number %d\n", source, code); chunk_error(ebuf, NULL); } return code; }
/* Create a new chunk */ chunk_ptr chunk_new(size_t len) { size_t more_bytes = len == 0 ? 0 : WORD_BYTES * (len - 1); chunk_ptr cp = (chunk_ptr) malloc_or_fail(sizeof(chunk_t) + more_bytes, "chunk_new"); if (cp == NULL && chunk_check_level >= 1) { chunk_error("Could not allocate chunk", cp); } cp->length = len; return cp; }
/* Read chunk from file. Return null pointer if fail. */ chunk_ptr chunk_read_legacy(int fd, bool *eofp) { unsigned char buf[CHUNK_MAX_SIZE]; /* Must get enough bytes to read chunk length */ size_t cnt = 0; size_t need_cnt = sizeof(chunk_t); while (cnt < need_cnt) { ssize_t n = read(fd, &buf[cnt], need_cnt-cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } if (n == 0) { if (eofp) *eofp = true; else chunk_error("Unexpected EOF", NULL); return NULL; } cnt += n; } chunk_ptr creadp = (chunk_ptr) buf; size_t len = creadp->length; if (len > 1) { need_cnt += WORD_BYTES * (len - 1); while (cnt < need_cnt) { ssize_t n = read(fd, &buf[cnt], need_cnt-cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } cnt += n; } } if (eofp) *eofp = false; return chunk_clone(creadp); }
/* Get word from chunk */ word_t chunk_get_word(chunk_ptr cp, size_t offset) { if (cp == NULL && chunk_check_level >= 2) { chunk_error("Null Pointer", cp); } if (chunk_check_level >= 2 && offset >= cp->length) { err(false, "Out of bounds retrieval. Length %lu, offset %lu", cp->length, offset); } return cp->words[offset]; }
/* Insert words from source chunk into destination chunk with designated offset */ void chunk_insert_chunk(chunk_ptr cdestp, chunk_ptr csrcp, size_t offset) { if (csrcp == NULL && chunk_check_level >= 2) { chunk_error("Null Source Pointer", csrcp); return; } size_t i; size_t len = (size_t) csrcp->length; for(i = 0; i < len; i++) { chunk_insert_word(cdestp, csrcp->words[i], i + offset); } }
/* Get double word from chunk. Offset indicates position of first word */ dword_t chunk_get_dword(chunk_ptr cp, size_t offset) { if (cp == NULL && chunk_check_level >= 2) { chunk_error("Null Pointer", cp); } if (chunk_check_level >= 2 && offset+1 >= cp->length) { err(false, "Out of bounds retrieval. Length %lu, offset %lu", cp->length, offset+1); } dword_t result; result.w0 = cp->words[offset]; result.w1 = cp->words[offset+1]; return result; }
/* Replicate a chunk */ chunk_ptr chunk_clone(chunk_ptr cp) { if (cp == NULL && chunk_check_level >= 2) { chunk_error("Null Pointer", cp); return NULL; } chunk_ptr ncp = chunk_new(cp->length); ncp->length = cp->length; size_t i; for (i = 0; i < cp->length; i++) { ncp->words[i] = cp->words[i]; } return ncp; }
void chunk_deinit() { buf_node* temp_node = buf_list_head; //create new head while (temp_node != NULL) { buf_list_head = temp_node; temp_node = temp_node->next; if (buf_list_head->buf != NULL) free_block(buf_list_head->buf, 2*CHUNK_MAX_SIZE*sizeof(char)); else chunk_error("Chunk buffer was null in a buffer list node", NULL); free_block(buf_list_head, sizeof(buf_node)); } }
/* Return 1 if successful, 0 if failed */ bool chunk_write(int fd, chunk_ptr cp) { unsigned char *bytes = (unsigned char *) cp; size_t len = cp->length; size_t more_bytes = len == 0 ? 0 : WORD_BYTES * (len - 1); size_t cnt = sizeof(chunk_t) + more_bytes; size_t save_cnt = cnt; while (cnt > 0) { ssize_t n = write(fd, bytes, cnt); if (n < 0) { chunk_error("Failed write", cp); return false; } bytes += n; cnt -= n; } chunks_sent ++; chunk_bytes_sent += save_cnt; return true; }
chunk_ptr chunk_read(int fd, bool* eofp) { if (fd > maxfd) { // on first call, we zero the buffer set if (maxfd == 0) { FD_ZERO(&buf_set); FD_ZERO(&in_set); } maxfd = fd; } buf_node* curr_node = NULL; buf_node* temp_node = NULL; //create new head if (buf_list_head == NULL) { buf_list_head = calloc_or_fail(sizeof(buf_node), 1, "chunk_read create head"); buf_list_head->fd = fd; #if RPT >= 5 report(5, "created a node for fd %d as head\n", fd); #endif buf_list_head->length = 0; buf_list_head->location = 0; buf_list_head->buf = calloc_or_fail(CHUNK_MAX_SIZE, 2, "chunk_read create head buf"); curr_node = buf_list_head; } // search for the fd in the buffer list, if it exists else { temp_node = buf_list_head; while (temp_node != NULL && curr_node == NULL) { if (fd == temp_node->fd) { curr_node = temp_node; #if RPT >= 5 report(5, "found node for fd %d\n", fd); #endif } temp_node = temp_node->next; } } // if it doesn't exist, create the new fd buffer at the head of the list if (curr_node == NULL) { curr_node = calloc_or_fail(sizeof(buf_node), 1, "chunk_read create node"); curr_node->fd = fd; curr_node->length = 0; curr_node->location = 0; curr_node->next = buf_list_head; curr_node->buf = calloc_or_fail(CHUNK_MAX_SIZE, 2, "chunk_read create head buf"); #if RPT >= 5 report(5, "created a node for fd %d at head\n", fd); #endif buf_list_head = curr_node; } // if we can copy to the beginning, then we copy to the beginning // (if the read point is past the beginning, and if the end of // the buffered data is past the midway point of the buffer) if (curr_node->length + curr_node->location >= CHUNK_MAX_SIZE && curr_node->location > 0) { memmove(curr_node->buf, (char *)(curr_node->buf + curr_node->location), curr_node->length); curr_node->location = 0; } // read if possible - if there is space, if the inset contains it, and if we // want to use buffering (otherwise we don't want random buffer refills) if (((curr_node->length + curr_node->location) < CHUNK_MAX_SIZE) && bufferReadBool && !(!(FD_ISSET(fd, &in_set))) ) { #if RPT >= 5 report(5, "reading for %d\n", curr_node->fd); #endif ssize_t n = read(curr_node->fd, curr_node->buf + curr_node->location + curr_node->length, CHUNK_MAX_SIZE); curr_node->length += n; } #if RPT >= 5 report(5, "about to get header for %d\n", fd); #endif // get header of chunk size_t need_cnt = sizeof(chunk_t); unsigned char buf[CHUNK_MAX_SIZE]; unsigned char* buf_ptr = (unsigned char*)buf; ssize_t n = buf_read(curr_node, eofp, buf_ptr, need_cnt); //ssize_t n = read(curr_node->fd, buf, need_cnt); if (n <= 0) { return NULL; } #if RPT >= 5 report(5, "about to get rest of chunk for fd %d\n", fd); #endif // get rest of chunk chunk_ptr creadp = (chunk_ptr) buf_ptr; size_t len = creadp->length; #if RPT >= 5 report(5, "len needed: %d", len); #endif if (len > 1) { need_cnt = WORD_BYTES * (len - 1); #if RPT >= 5 report(5, "head buf pointer at %p", buf_ptr); #endif buf_ptr = (unsigned char *)(buf_ptr + n); #if RPT >= 5 report(5, "moved pointer to %p for rest", buf_ptr); #endif ssize_t n = buf_read(curr_node, eofp, buf_ptr, need_cnt); //ssize_t n = read(curr_node->fd, buf_ptr, need_cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } } #if RPT >= 5 report(5, "exiting chunk_read_buffered_builtin!\n"); #endif if (eofp) *eofp = false; return chunk_clone(creadp); }
static ssize_t buf_read(buf_node* curr_node, bool* eofp, unsigned char* buf, int len) { int cnt = 0; int copyLen = 0; while (cnt < len) { #if RPT >= 5 report(5, "waiting for %d bytes", (len - cnt)); #endif //if there's stuff in the buffer, copy it over if (curr_node->length > 0) { copyLen = ((len - cnt) < curr_node->length ? (len - cnt) : curr_node->length); #if RPT >= 5 report(5, "copying a buffer of length %d from total length %d, to the return buffer", copyLen, curr_node->length); report(5, "old length = %d, new length = %d", curr_node->length, curr_node->length - copyLen); #endif memcpy(buf + cnt, curr_node->buf + curr_node->location, copyLen); cnt = cnt + copyLen; curr_node->length = curr_node->length - copyLen; if (curr_node->length == 0) { curr_node->location = 0; } else { curr_node->location = curr_node->location + copyLen; } #if RPT >= 5 report(5, "new location: %d\n", curr_node->location); #endif } //otherwise, we refill the buffer else { #if RPT >= 5 report(5, "fill the saved buffer!"); #endif ssize_t n = read(curr_node->fd, curr_node->buf + curr_node->location + curr_node->length, CHUNK_MAX_SIZE); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; toggle_buffered_in_set(curr_node); return n; } if (n == 0) { if (eofp) *eofp = true; else chunk_error("Unexpected EOF", NULL); toggle_buffered_in_set(curr_node); return n; } curr_node->length = curr_node->length + n; #if RPT >= 5 report(5, "added %d bytes to the saved buffer; length is now %d at location %d\n", n, curr_node->length, curr_node->location); #endif } } toggle_buffered_in_set(curr_node); return (ssize_t)cnt; }