Commit 40b895fd authored by noelallen's avatar noelallen Committed by Commit bot

Replace allocated ino with hash of path.

HTML5FS (PPAPI) does not provide an INO so it is impossible to determine
a files uniqueness.  In addition, node information does not persist in
memory since nodes could be transparently destroyed from JavaScript, thus
creating leaks.  Because of this the current stack based INO allocation
causes sequentially accesed file handles to report the same INO.

HTML5FS (including media galleries) does not traverse links.  This implies
that all paths normalized to the mount are unique.  We use this property
to generate a 64 bit hash.

R=binji@chromium.org
BUG=414938

Review URL: https://codereview.chromium.org/605513002

Cr-Commit-Position: refs/heads/master@{#296840}
parent 70d0d490
......@@ -95,10 +95,10 @@ class Filesystem : public sdk_util::RefObject {
Error Filesystem_Ioctl(int request, ...);
// Assumes that |node| is non-NULL.
void OnNodeCreated(Node* node);
virtual void OnNodeCreated(Node* node);
// Assumes that |node| is non-NULL.
void OnNodeDestroyed(Node* node);
virtual void OnNodeDestroyed(Node* node);
protected:
// Device number for the filesystem.
......
......@@ -29,6 +29,41 @@ int64_t strtoull(const char* nptr, char** endptr, int base) {
} // namespace
// Continuing DJB2a hash
ino_t Html5Fs::HashPathSegment(ino_t hash, const char *str, size_t len) {
// First add the path seperator
hash = (hash * static_cast<ino_t>(33)) ^ '/';
while (len--) {
hash = (hash * static_cast<ino_t>(33)) ^ *str++;
}
return hash;
}
ino_t Html5Fs::HashPath(const Path& path) {
// Prime the DJB2a hash
ino_t hash = 5381;
// Apply a running DJB2a to each part of the path
for (size_t segment = 0; segment < path.Size(); segment++) {
const char *ptr = path.Part(segment).c_str();
size_t len = path.Part(segment).length();
hash = HashPathSegment(hash, ptr, len);
}
return hash;
}
// For HTML5, the INO should be the one used by the system, however PPAPI
// does not provide access to the real INO. Instead, since HTML5 does not
// suport links, we assume that files are unique based on path to the base
// of the mount.
void Html5Fs::OnNodeCreated(Node* node) {
node->stat_.st_dev = dev_;
}
void Html5Fs::OnNodeDestroyed(Node* node) {}
Error Html5Fs::OpenWithMode(const Path& path, int open_flags, mode_t mode,
ScopedNode* out_node) {
out_node->reset(NULL);
......@@ -43,6 +78,10 @@ Error Html5Fs::OpenWithMode(const Path& path, int open_flags, mode_t mode,
ScopedNode node(new Html5FsNode(this, fileref));
error = node->Init(open_flags);
// Set the INO based on the path
node->stat_.st_ino = HashPath(path);
if (error)
return error;
......
......@@ -28,6 +28,12 @@ class Html5Fs : public Filesystem {
PP_Resource filesystem_resource() { return filesystem_resource_; }
virtual void OnNodeCreated(Node* node);
virtual void OnNodeDestroyed(Node* node);
static ino_t HashPathSegment(ino_t hash, const char *str, size_t len);
static ino_t HashPath(const Path& path);
protected:
static const int REMOVE_DIR = 1;
static const int REMOVE_FILE = 2;
......
......@@ -16,6 +16,7 @@
#include "nacl_io/filesystem.h"
#include "nacl_io/getdents_helper.h"
#include "nacl_io/html5fs/html5_fs.h"
#include "nacl_io/kernel_handle.h"
#include "nacl_io/osdirent.h"
#include "nacl_io/pepper_interface.h"
......@@ -125,8 +126,13 @@ Error Html5FsNode::GetDents(size_t offs,
std::min(static_cast<size_t>(file_name_length),
MEMBER_SIZE(dirent, d_name) - 1); // -1 for NULL.
// TODO(binji): Better handling of ino numbers.
helper.AddDirent(1, file_name, file_name_length);
// The INO is based on the running hash of fully qualified path, so
// a childs INO must be the parent directories hash, plus '/', plus
// the filename.
ino_t child_ino = Html5Fs::HashPathSegment(stat_.st_ino, file_name,
file_name_length);
helper.AddDirent(child_ino, file_name, file_name_length);
}
var_iface_->Release(file_name_var);
......
......@@ -470,6 +470,10 @@ TEST_F(Html5FsTest, GetDents) {
ScopedNode node;
ASSERT_EQ(0, fs->Open(Path("/file"), O_RDWR, &node));
struct stat stat;
ASSERT_EQ(0, node->GetStat(&stat));
ino_t file1_ino = stat.st_ino;
// Should fail for regular files.
const size_t kMaxDirents = 5;
dirent dirents[kMaxDirents];
......@@ -506,6 +510,11 @@ TEST_F(Html5FsTest, GetDents) {
// Add another file...
ASSERT_EQ(0, fs->Open(Path("/file2"), O_CREAT, &node));
ASSERT_EQ(0, node->GetStat(&stat));
ino_t file2_ino = stat.st_ino;
// These files SHOULD not hash to the same value but COULD.
EXPECT_NE(file1_ino, file2_ino);
// Read the root directory again.
memset(&dirents[0], 0, sizeof(dirents));
......@@ -521,6 +530,13 @@ TEST_F(Html5FsTest, GetDents) {
EXPECT_EQ(sizeof(dirent), dirents[i].d_off);
EXPECT_EQ(sizeof(dirent), dirents[i].d_reclen);
dirnames.insert(dirents[i].d_name);
if (!strcmp(dirents[i].d_name, "file")) {
EXPECT_EQ(dirents[i].d_ino, file1_ino);
}
if (!strcmp(dirents[i].d_name, "file2")) {
EXPECT_EQ(dirents[i].d_ino, file2_ino);
}
}
EXPECT_EQ(1, dirnames.count("file"));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment