diff options
author | Adam Borowski <kilobyte@angband.pl> | 2010-10-07 00:13:20 +0200 |
---|---|---|
committer | Adam Borowski <kilobyte@angband.pl> | 2010-10-07 00:35:26 +0200 |
commit | 2d20a979dd95b082f58486da06bdb8340ceeb675 (patch) | |
tree | 5af71b437319a42ae6cfd2fb2b8dc1110d327861 /crawl-ref/source/package.cc | |
parent | 4ef016b9b477eb660c79c739442367c64ecdb377 (diff) | |
download | crawl-ref-2d20a979dd95b082f58486da06bdb8340ceeb675.tar.gz crawl-ref-2d20a979dd95b082f58486da06bdb8340ceeb675.zip |
Don't leak file descriptors when trying to open a save file fails.
The save browser is likely to open many, especially if you have a lot
of old saves after a compat break. Actually running out of descriptors
would require a bizarre case, but a bug is a bug...
Diffstat (limited to 'crawl-ref/source/package.cc')
-rw-r--r-- | crawl-ref/source/package.cc | 86 |
1 files changed, 52 insertions, 34 deletions
diff --git a/crawl-ref/source/package.cc b/crawl-ref/source/package.cc index 18f48b4dcb..be98d610ca 100644 --- a/crawl-ref/source/package.cc +++ b/crawl-ref/source/package.cc @@ -103,7 +103,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); @@ -114,46 +117,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; + } + } +} - for(directory_t::iterator ch = directory.begin(); - ch != directory.end(); ch++) - { - trace_chunk(ch->second); - } +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); + } #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 - } } } |