diff --git a/src/pack.c b/src/pack.c index 865e0e3..a8c6f1b 100644 --- a/src/pack.c +++ b/src/pack.c @@ -551,56 +551,49 @@ ssize_t pack_read(Packfile_t* file, void* buf, size_t count) { * @brief Seeks within a file inside a packfile. * * Behaves like lseek/fseek. - * - * @todo It's broken, needs fixing. * @param file File to seek. * @param offset Position to seek to. * @param whence Either SEEK_SET, SEEK_CUR or SEEK_END. * @return The position moved to. */ off_t pack_seek(Packfile_t* file, off_t offset, int whence) { - off_t ret; + off_t base, target, ret; DEBUG("Attempting to seek offset: %d, whence: %d", offset, whence); + /* Find where offset is relative to. */ switch(whence) { -#if HAS_POSIX case SEEK_SET: - if((file->start + offset) > file->end) return -1; - ret = lseek(file->fd, file->start + offset, SEEK_SET); - if(ret != ((off_t)file->start + offset)) return -1; + base = file->start; break; case SEEK_CUR: - if((file->start + offset) > file->end) return -1; - ret = lseek(file->fd, file->pos + offset, SEEK_SET); - if(ret != ((off_t)file->pos + offset)) return -1; + base = file->pos; break; case SEEK_END: - if((file->end + offset) < file->start) return -1; - ret = lseek(file->fd, file->end + offset, SEEK_SET); - if(ret != ((off_t)file->end - offset)) return -1; + base = file->end; break; -#else - case SEEK_SET: - if((file->start + offset) > file->end) return -1; - ret = fseek(file->fd, file->start + offset, SEEK_SET); - if(ret != (file->start + offset)) return -1; - break; - case SEEK_CUR: - if((file->start + offset) > file->end) return -1; - ret = fseek(file->fd, file->pos + offset -1, SEEK_SET); - if(ret != (file->pos + offset)) return -1; - break; - case SEEK_END: - if((file->end + offset) < file->start) return -1; - ret = fseek(file->fd, file->end + offset, SEEK_SET); - if(ret != (file->end - offset)) return -1; - break; -#endif /* HAS_POSIX */ default: ERR("Whence is not one of SEEK_SET, SEEK_CUR or SEEK_END"); return -1; } + + /* Get the target. */ + target = base + offset; + + /* Limit checks. */ + if((target < file->start) || (target >= file->end)) + return -1; + +#if HAS_POSIX + ret = lseek(file->fd, target, SEEK_SET); + if(ret != target) + return -1; +#else + ret = fseek(file->fp, target, SEEK_SET); + if(ret != 0) + return -1; +#endif + return ret - file->start; }