Merge pull request #1642 from atom/archive-update-header

Keep asar archive's file opened in the archive's whole life time
This commit is contained in:
Cheng Zhao 2015-05-11 12:07:16 +08:00
commit e5380fd671
6 changed files with 59 additions and 30 deletions

View file

@ -88,6 +88,13 @@ class Archive : public mate::Wrappable {
return mate::ConvertToV8(isolate, new_path); return mate::ConvertToV8(isolate, new_path);
} }
// Return the file descriptor.
int GetFD() const {
if (!archive_)
return -1;
return archive_->GetFD();
}
// Free the resources used by archive. // Free the resources used by archive.
void Destroy() { void Destroy() {
archive_.reset(); archive_.reset();
@ -102,6 +109,7 @@ class Archive : public mate::Wrappable {
.SetMethod("readdir", &Archive::Readdir) .SetMethod("readdir", &Archive::Readdir)
.SetMethod("realpath", &Archive::Realpath) .SetMethod("realpath", &Archive::Realpath)
.SetMethod("copyFileOut", &Archive::CopyFileOut) .SetMethod("copyFileOut", &Archive::CopyFileOut)
.SetMethod("getFd", &Archive::GetFD)
.SetMethod("destroy", &Archive::Destroy); .SetMethod("destroy", &Archive::Destroy);
} }

View file

@ -4,6 +4,10 @@
#include "atom/common/asar/archive.h" #include "atom/common/asar/archive.h"
#if defined(OS_WIN)
#include <io.h>
#endif
#include <string> #include <string>
#include <vector> #include <vector>
@ -104,6 +108,7 @@ bool FillFileInfoWithNode(Archive::FileInfo* info,
Archive::Archive(const base::FilePath& path) Archive::Archive(const base::FilePath& path)
: path_(path), : path_(path),
file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ),
header_size_(0) { header_size_(0) {
} }
@ -111,15 +116,14 @@ Archive::~Archive() {
} }
bool Archive::Init() { bool Archive::Init() {
base::File file(path_, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!file_.IsValid())
if (!file.IsValid())
return false; return false;
std::vector<char> buf; std::vector<char> buf;
int len; int len;
buf.resize(8); buf.resize(8);
len = file.ReadAtCurrentPos(buf.data(), buf.size()); len = file_.ReadAtCurrentPos(buf.data(), buf.size());
if (len != static_cast<int>(buf.size())) { if (len != static_cast<int>(buf.size())) {
PLOG(ERROR) << "Failed to read header size from " << path_.value(); PLOG(ERROR) << "Failed to read header size from " << path_.value();
return false; return false;
@ -132,7 +136,7 @@ bool Archive::Init() {
} }
buf.resize(size); buf.resize(size);
len = file.ReadAtCurrentPos(buf.data(), buf.size()); len = file_.ReadAtCurrentPos(buf.data(), buf.size());
if (len != static_cast<int>(buf.size())) { if (len != static_cast<int>(buf.size())) {
PLOG(ERROR) << "Failed to read header from " << path_.value(); PLOG(ERROR) << "Failed to read header from " << path_.value();
return false; return false;
@ -250,7 +254,7 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
} }
scoped_ptr<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile); scoped_ptr<ScopedTemporaryFile> temp_file(new ScopedTemporaryFile);
if (!temp_file->InitFromFile(path_, info.offset, info.size)) if (!temp_file->InitFromFile(&file_, info.offset, info.size))
return false; return false;
*out = temp_file->path(); *out = temp_file->path();
@ -258,4 +262,18 @@ bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) {
return true; return true;
} }
int Archive::GetFD() const {
if (!file_.IsValid())
return -1;
#if defined(OS_WIN)
return
_open_osfhandle(reinterpret_cast<intptr_t>(file_.GetPlatformFile()), 0);
#elif defined(OS_POSIX)
return file_.GetPlatformFile();
#else
return -1;
#endif
}
} // namespace asar } // namespace asar

View file

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include "base/containers/scoped_ptr_hash_map.h" #include "base/containers/scoped_ptr_hash_map.h"
#include "base/files/file.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
@ -59,11 +60,15 @@ class Archive {
// For unpacked file, this method will return its real path. // For unpacked file, this method will return its real path.
bool CopyFileOut(const base::FilePath& path, base::FilePath* out); bool CopyFileOut(const base::FilePath& path, base::FilePath* out);
// Returns the file's fd.
int GetFD() const;
base::FilePath path() const { return path_; } base::FilePath path() const { return path_; }
base::DictionaryValue* header() const { return header_.get(); } base::DictionaryValue* header() const { return header_.get(); }
private: private:
base::FilePath path_; base::FilePath path_;
base::File file_;
uint32 header_size_; uint32 header_size_;
scoped_ptr<base::DictionaryValue> header_; scoped_ptr<base::DictionaryValue> header_;

View file

@ -36,17 +36,16 @@ bool ScopedTemporaryFile::Init() {
return base::CreateTemporaryFile(&path_); return base::CreateTemporaryFile(&path_);
} }
bool ScopedTemporaryFile::InitFromFile(const base::FilePath& path, bool ScopedTemporaryFile::InitFromFile(base::File* src,
uint64 offset, uint64 size) { uint64 offset, uint64 size) {
if (!src->IsValid())
return false;
if (!Init()) if (!Init())
return false; return false;
base::File src(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!src.IsValid())
return false;
std::vector<char> buf(size); std::vector<char> buf(size);
int len = src.Read(offset, buf.data(), buf.size()); int len = src->Read(offset, buf.data(), buf.size());
if (len != static_cast<int>(size)) if (len != static_cast<int>(size))
return false; return false;

View file

@ -7,6 +7,10 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
namespace base {
class File;
}
namespace asar { namespace asar {
// An object representing a temporary file that should be cleaned up when this // An object representing a temporary file that should be cleaned up when this
@ -22,7 +26,7 @@ class ScopedTemporaryFile {
bool Init(); bool Init();
// Init an temporary file and fill it with content of |path|. // Init an temporary file and fill it with content of |path|.
bool InitFromFile(const base::FilePath& path, uint64 offset, uint64 size); bool InitFromFile(base::File* src, uint64 offset, uint64 size);
base::FilePath path() const { return path_; } base::FilePath path() const { return path_; }

View file

@ -236,21 +236,20 @@ exports.wrapFsWithAsar = (fs) ->
return fs.readFile realPath, options, callback return fs.readFile realPath, options, callback
if not options if not options
options = encoding: null, flag: 'r' options = encoding: null
else if util.isString options else if util.isString options
options = encoding: options, flag: 'r' options = encoding: options
else if not util.isObject options else if not util.isObject options
throw new TypeError('Bad arguments') throw new TypeError('Bad arguments')
flag = options.flag || 'r'
encoding = options.encoding encoding = options.encoding
buffer = new Buffer(info.size) buffer = new Buffer(info.size)
open archive.path, flag, (error, fd) -> fd = archive.getFd()
return callback error if error return notFoundError asarPath, filePath, callback unless fd >= 0
fs.read fd, buffer, 0, info.size, info.offset, (error) ->
fs.close fd, -> fs.read fd, buffer, 0, info.size, info.offset, (error) ->
callback error, if encoding then buffer.toString encoding else buffer callback error, if encoding then buffer.toString encoding else buffer
openSync = fs.openSync openSync = fs.openSync
readFileSync = fs.readFileSync readFileSync = fs.readFileSync
@ -270,23 +269,19 @@ exports.wrapFsWithAsar = (fs) ->
return fs.readFileSync realPath, options return fs.readFileSync realPath, options
if not options if not options
options = encoding: null, flag: 'r' options = encoding: null
else if util.isString options else if util.isString options
options = encoding: options, flag: 'r' options = encoding: options
else if not util.isObject options else if not util.isObject options
throw new TypeError('Bad arguments') throw new TypeError('Bad arguments')
flag = options.flag || 'r'
encoding = options.encoding encoding = options.encoding
buffer = new Buffer(info.size) buffer = new Buffer(info.size)
fd = openSync archive.path, flag fd = archive.getFd()
try notFoundError asarPath, filePath unless fd >= 0
fs.readSync fd, buffer, 0, info.size, info.offset
catch e fs.readSync fd, buffer, 0, info.size, info.offset
throw e
finally
fs.closeSync fd
if encoding then buffer.toString encoding else buffer if encoding then buffer.toString encoding else buffer
readdir = fs.readdir readdir = fs.readdir