diff options
author | Adam Borowski <kilobyte@angband.pl> | 2010-10-15 02:12:34 +0200 |
---|---|---|
committer | Adam Borowski <kilobyte@angband.pl> | 2010-10-15 02:12:34 +0200 |
commit | e7572d74b30900124d9a896843f42b1c957d20c2 (patch) | |
tree | 4498d0d55dd643ae021e93e38d74dafce960bfd9 /crawl-ref/source/package.cc | |
parent | 634ab294f302c98be55389a97e94cd7205860310 (diff) | |
parent | acf5187334f2cfb983a1a8de07d1e77f73e4283a (diff) | |
download | crawl-ref-e7572d74b30900124d9a896843f42b1c957d20c2.tar.gz crawl-ref-e7572d74b30900124d9a896843f42b1c957d20c2.zip |
Merge branch 'master' into unicode
Diffstat (limited to 'crawl-ref/source/package.cc')
-rw-r--r-- | crawl-ref/source/package.cc | 120 |
1 files changed, 80 insertions, 40 deletions
diff --git a/crawl-ref/source/package.cc b/crawl-ref/source/package.cc index ce941d1666..4ec55fc4eb 100644 --- a/crawl-ref/source/package.cc +++ b/crawl-ref/source/package.cc @@ -10,8 +10,6 @@ Guarantees: the exact state it had at the last commit(). Caveats/issues: -* Before the first commit, the save is "not a valid DCSS save file", - how should we handle this? * Benchmarked on random chunks of size 2^random2(X) * frandom(1), naive reusing of the first slab of free space produces less waste than best fit. I don't fully understand why, but for now, let's use that. @@ -93,6 +91,7 @@ package::package(const char* file, bool writeable, bool empty) { dprintf("package: initializing file=\"%s\" rw=%d\n", file, writeable); ASSERT(writeable || !empty); + filename = file; rw = writeable; if (empty) @@ -102,7 +101,10 @@ package::package(const char* file, bool writeable, bool empty) sysfail("can't create save file (%s)", file); if (!lock_file(fd, true)) + { + close(fd); sysfail("failed to lock newly created save (%s)", file); + } dirty = true; file_len = sizeof(file_header); @@ -113,46 +115,61 @@ package::package(const char* file, bool writeable, bool empty) if (fd == -1) sysfail("can't open save file (%s)", file); - if (!lock_file(fd, writeable)) - fail("Another game is already in progress using this save!"); - - file_header head; - ssize_t res = ::read(fd, &head, sizeof(file_header)); - if (res < 0) - sysfail("error reading the save file (%s)", file); - if (!res || !(head.magic || head.version || head.padding[0] - || head.padding[1] || head.padding[2] || head.start)) + try { - fail("The save file (%s) is empty!", file); + if (!lock_file(fd, writeable)) + fail("Another game is already in progress using this save!"); + + load(); } - if (res != sizeof(file_header)) - fail("save file (%s) corrupted -- header truncated", file); - - if (htole(head.magic) != PACKAGE_MAGIC) - fail("save file (%s) corrupted -- not a DCSS save file", file); - if (head.version != PACKAGE_VERSION) - fail("save file (%s) uses an unknown format %u", file, head.version); - off_t len = lseek(fd, 0, SEEK_END); - if (len == -1) - sysfail("save file (%s) is not seekable", file); - file_len = len; - read_directory(htole(head.start)); - - if (writeable) + catch (std::exception &e) { - free_blocks[sizeof(file_header)] = file_len - sizeof(file_header); + close(fd); + throw; + } + } +} + +void package::load() +{ + file_header head; + ssize_t res = ::read(fd, &head, sizeof(file_header)); + if (res < 0) + sysfail("error reading the save file (%s)", filename.c_str()); + if (!res || !(head.magic || head.version || head.padding[0] + || head.padding[1] || head.padding[2] || head.start)) + { + fail("The save file (%s) is empty!", filename.c_str()); + } + if (res != sizeof(file_header)) + fail("save file (%s) corrupted -- header truncated", filename.c_str()); + + if (htole(head.magic) != PACKAGE_MAGIC) + fail("save file (%s) corrupted -- not a DCSS save file", + filename.c_str()); + if (head.version != PACKAGE_VERSION) + fail("save file (%s) uses an unknown format %u", filename.c_str(), + head.version); + off_t len = lseek(fd, 0, SEEK_END); + if (len == -1) + sysfail("save file (%s) is not seekable", filename.c_str()); + file_len = len; + read_directory(htole(head.start)); + + if (rw) + { + free_blocks[sizeof(file_header)] = file_len - sizeof(file_header); - for(directory_t::iterator ch = directory.begin(); - ch != directory.end(); ch++) - { - trace_chunk(ch->second); - } + for(directory_t::iterator ch = directory.begin(); + ch != directory.end(); ch++) + { + trace_chunk(ch->second); + } #ifdef COSTLY_ASSERTS - // any inconsitency in the save is guaranteed to be already found - // by this time -- this checks only for internal bugs - fsck(); + // any inconsitency in the save is guaranteed to be already found + // by this time -- this checks only for internal bugs + fsck(); #endif - } } } @@ -173,9 +190,10 @@ package::~package() } // all errors here should be cached write errors - if (close(fd) && !aborted) - sysfail(rw ? "write error while saving" - : "can't close the save I've just read???"); + if (fd != -1) + if (close(fd) && !aborted) + sysfail(rw ? "write error while saving" + : "can't close the save I've just read???"); dprintf("package: closed\n"); } @@ -194,7 +212,7 @@ void package::commit() head.magic = htole(PACKAGE_MAGIC); head.version = PACKAGE_VERSION; memset(&head.padding, 0, sizeof(head.padding)); - head.start = write_directory(); + head.start = htole(write_directory()); #ifdef DO_FSYNC // We need a barrier before updating the link to point at the new directory. if (fdatasync(fd)) @@ -519,12 +537,28 @@ void package::abort() aborted = true; } +void package::unlink() +{ + abort(); + close(fd); + fd = -1; + ::unlink_u(filename.c_str()); +} + chunk_writer::chunk_writer(package *parent, const std::string _name) : first_block(0), cur_block(0), block_len(0) { ASSERT(parent); ASSERT(!parent->aborted); + + /* + The save format is currently limited to 4 character names for simplicity + (we use 3 max). If you want to extend this, please implement marshalling + of arbitrary strings in {read,write}_directory(). + */ + ASSERT(_name.size() <= 4); + dprintf("chunk_writer(%s): starting\n", _name.c_str()); pkg = parent; pkg->n_users++; @@ -550,7 +584,13 @@ chunk_writer::~chunk_writer() ASSERT(pkg->n_users > 0); pkg->n_users--; if (pkg->aborted) + { +#ifdef USE_ZLIB + // ignore errors, they're not relevant anymore + deflateEnd(&zs); +#endif return; + } #ifdef USE_ZLIB zs.avail_in = 0; |