diff options
author | Ben Smith <binji@chromium.org> | 2014-09-24 17:15:21 -0700 |
---|---|---|
committer | Ben Smith <binji@chromium.org> | 2014-09-25 00:16:04 +0000 |
commit | a4ef3a9c60553b3bcc8708587ea7832fc7cac29e (patch) | |
tree | c3671a243eac0cf2ffb4b38253ba3b19aca3be40 /native_client_sdk | |
parent | 009b55e7f8532a4586fc4ab0a4df1532943f88fd (diff) | |
download | chromium_src-a4ef3a9c60553b3bcc8708587ea7832fc7cac29e.zip chromium_src-a4ef3a9c60553b3bcc8708587ea7832fc7cac29e.tar.gz chromium_src-a4ef3a9c60553b3bcc8708587ea7832fc7cac29e.tar.bz2 |
[NaCl SDK] nacl_io: Add chmod/fchmod
This change includes implementation for MemFs and FuseFs.
I've also reordered the fuse_operations struct to match the order used in the
real FUSE implementation.
BUG=414793
R=sbc@chromium.org
Review URL: https://codereview.chromium.org/604513002
Cr-Commit-Position: refs/heads/master@{#296588}
Diffstat (limited to 'native_client_sdk')
14 files changed, 208 insertions, 86 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/dir_node.cc b/native_client_sdk/src/libraries/nacl_io/dir_node.cc index e16c0c7..6cf0656 100644 --- a/native_client_sdk/src/libraries/nacl_io/dir_node.cc +++ b/native_client_sdk/src/libraries/nacl_io/dir_node.cc @@ -69,6 +69,12 @@ Error DirNode::GetDents(size_t offs, return cache_.GetDents(offs, pdir, size, out_bytes); } +Error DirNode::Fchmod(mode_t mode) { + AUTO_LOCK(node_lock_); + SetMode(mode); + return 0; +} + Error DirNode::AddChild(const std::string& name, const ScopedNode& node) { AUTO_LOCK(node_lock_); diff --git a/native_client_sdk/src/libraries/nacl_io/dir_node.h b/native_client_sdk/src/libraries/nacl_io/dir_node.h index 29d271f..3deaa33 100644 --- a/native_client_sdk/src/libraries/nacl_io/dir_node.h +++ b/native_client_sdk/src/libraries/nacl_io/dir_node.h @@ -43,6 +43,7 @@ class DirNode : public Node { const void* buf, size_t count, int* out_bytes); + virtual Error Fchmod(mode_t mode); // Adds a finds or adds a directory entry as an INO, updating the refcount virtual Error AddChild(const std::string& name, const ScopedNode& node); diff --git a/native_client_sdk/src/libraries/nacl_io/fuse.h b/native_client_sdk/src/libraries/nacl_io/fuse.h index 5f79786..cbc381f 100644 --- a/native_client_sdk/src/libraries/nacl_io/fuse.h +++ b/native_client_sdk/src/libraries/nacl_io/fuse.h @@ -87,35 +87,35 @@ struct fuse_operations { unsigned int flag_nopath : 1; unsigned int flag_reserved : 31; - // Called when a filesystem of this type is initialized. - void* (*init)(struct fuse_conn_info* conn); - // Called when a filesystem of this type is unmounted. - void (*destroy)(void*); - // Called by access() - int (*access)(const char* path, int mode); - // Called when O_CREAT is passed to open() - int (*create)(const char* path, mode_t mode, struct fuse_file_info*); - // Called by stat()/fstat(). If this function pointer is non-NULL, it is - // called, otherwise fuse_operations.getattr will be called. - int (*fgetattr)(const char* path, struct stat*, struct fuse_file_info*); - // Called by fsync(). The datasync paramater is not currently supported. - int (*fsync)(const char* path, int datasync, struct fuse_file_info*); - // Called by ftruncate() - int (*ftruncate)(const char* path, off_t, struct fuse_file_info*); // Called by stat()/fstat(), but only when fuse_operations.fgetattr is NULL. // Also called by open() to determine if the path is a directory or a regular // file. int (*getattr)(const char* path, struct stat*); - // Called by mkdir() - int (*mkdir)(const char* path, mode_t); + // Not called currently. + int (*readlink)(const char*, char*, size_t); // Called when O_CREAT is passed to open(), but only if fuse_operations.create // is non-NULL. int (*mknod)(const char* path, mode_t, dev_t); + // Called by mkdir() + int (*mkdir)(const char* path, mode_t); + // Called by unlink() + int (*unlink)(const char* path); + // Called by rmdir() + int (*rmdir)(const char* path); + // Not called currently. + int (*symlink)(const char*, const char*); + // Called by rename() + int (*rename)(const char* path, const char* new_path); + // Not called currently. + int (*link)(const char*, const char*); + // Called by chmod()/fchmod() + int (*chmod)(const char*, mode_t); + // Not called currently. + int (*chown)(const char*, uid_t, gid_t); + // Called by truncate(), as well as open() when O_TRUNC is passed. + int (*truncate)(const char* path, off_t); // Called by open() int (*open)(const char* path, struct fuse_file_info*); - // Called by getdents(), which is called by the more standard functions - // opendir()/readdir(). - int (*opendir)(const char* path, struct fuse_file_info*); // Called by read(). Note that FUSE specifies that all reads will fill the // entire requested buffer. If this function returns less than that, the // remainder of the buffer is zeroed. @@ -124,6 +124,34 @@ struct fuse_operations { size_t count, off_t, struct fuse_file_info*); + // Called by write(). Note that FUSE specifies that a write should always + // return the full count, unless an error occurs. + int (*write)(const char* path, + const char* buf, + size_t count, + off_t, + struct fuse_file_info*); + // Not called currently. + int (*statfs)(const char*, struct statvfs*); + // Not called currently. + int (*flush)(const char*, struct fuse_file_info*); + // Called when the last reference to this node is released. This is only + // called for regular files. For directories, fuse_operations.releasedir is + // called instead. + int (*release)(const char* path, struct fuse_file_info*); + // Called by fsync(). The datasync paramater is not currently supported. + int (*fsync)(const char* path, int datasync, struct fuse_file_info*); + // Not called currently. + int (*setxattr)(const char*, const char*, const char*, size_t, int); + // Not called currently. + int (*getxattr)(const char*, const char*, char*, size_t); + // Not called currently. + int (*listxattr)(const char*, char*, size_t); + // Not called currently. + int (*removexattr)(const char*, const char*); + // Called by getdents(), which is called by the more standard functions + // opendir()/readdir(). + int (*opendir)(const char* path, struct fuse_file_info*); // Called by getdents(), which is called by the more standard function // readdir(). // @@ -176,68 +204,57 @@ struct fuse_operations { off_t, struct fuse_file_info*); // Called when the last reference to this node is released. This is only - // called for regular files. For directories, fuse_operations.releasedir is - // called instead. - int (*release)(const char* path, struct fuse_file_info*); - // Called when the last reference to this node is released. This is only // called for directories. For regular files, fuse_operations.release is // called instead. int (*releasedir)(const char* path, struct fuse_file_info*); - // Called by rename() - int (*rename)(const char* path, const char* new_path); - // Called by rmdir() - int (*rmdir)(const char* path); - // Called by truncate(), as well as open() when O_TRUNC is passed. - int (*truncate)(const char* path, off_t); - // Called by unlink() - int (*unlink)(const char* path); - // Called by write(). Note that FUSE specifies that a write should always - // return the full count, unless an error occurs. - int (*write)(const char* path, - const char* buf, - size_t count, - off_t, - struct fuse_file_info*); + // Not called currently. + int (*fsyncdir)(const char*, int, struct fuse_file_info*); + // Called when a filesystem of this type is initialized. + void* (*init)(struct fuse_conn_info* conn); + // Called when a filesystem of this type is unmounted. + void (*destroy)(void*); + // Called by access() + int (*access)(const char* path, int mode); + // Called when O_CREAT is passed to open() + int (*create)(const char* path, mode_t mode, struct fuse_file_info*); + // Called by ftruncate() + int (*ftruncate)(const char* path, off_t, struct fuse_file_info*); + // Called by stat()/fstat(). If this function pointer is non-NULL, it is + // called, otherwise fuse_operations.getattr will be called. + int (*fgetattr)(const char* path, struct stat*, struct fuse_file_info*); + // Not called currently. + int (*lock)(const char*, struct fuse_file_info*, int cmd, struct flock*); // Called by utime()/utimes()/futimes()/futimens() etc. int (*utimens)(const char*, const struct timespec tv[2]); - - // The following functions are not currently called by the nacl_io - // implementation of FUSE. + // Not called currently. int (*bmap)(const char*, size_t blocksize, uint64_t* idx); - int (*chmod)(const char*, mode_t); - int (*chown)(const char*, uid_t, gid_t); - int (*fallocate)(const char*, int, off_t, off_t, struct fuse_file_info*); - int (*flock)(const char*, struct fuse_file_info*, int op); - int (*flush)(const char*, struct fuse_file_info*); - int (*fsyncdir)(const char*, int, struct fuse_file_info*); - int (*getxattr)(const char*, const char*, char*, size_t); + // Not called currently. int (*ioctl)(const char*, int cmd, void* arg, struct fuse_file_info*, unsigned int flags, void* data); - int (*link)(const char*, const char*); - int (*listxattr)(const char*, char*, size_t); - int (*lock)(const char*, struct fuse_file_info*, int cmd, struct flock*); + // Not called currently. int (*poll)(const char*, struct fuse_file_info*, struct fuse_pollhandle* ph, unsigned* reventsp); + // Not called currently. + int (*write_buf)(const char*, + struct fuse_bufvec* buf, + off_t off, + struct fuse_file_info*); + // Not called currently. int (*read_buf)(const char*, struct fuse_bufvec** bufp, size_t size, off_t off, struct fuse_file_info*); - int (*readlink)(const char*, char*, size_t); - int (*removexattr)(const char*, const char*); - int (*setxattr)(const char*, const char*, const char*, size_t, int); - int (*statfs)(const char*, struct statvfs*); - int (*symlink)(const char*, const char*); - int (*write_buf)(const char*, - struct fuse_bufvec* buf, - off_t off, - struct fuse_file_info*); + // Not called currently. + int (*flock)(const char*, struct fuse_file_info*, int op); + // Not called currently. + int (*fallocate)(const char*, int, off_t, off_t, struct fuse_file_info*); }; #endif // LIBRARIES_NACL_IO_FUSE_H_ diff --git a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc index 212f84f..d072392 100644 --- a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc +++ b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.cc @@ -261,6 +261,20 @@ Error FuseFsNode::Futimens(const struct timespec times[2]) { return result; } +Error FuseFsNode::Fchmod(mode_t mode) { + int result; + if (!fuse_ops_->chmod) { + LOG_TRACE("fuse_ops_->chmod is NULL."); + return ENOSYS; + } + + result = fuse_ops_->chmod(path_.c_str(), mode); + if (result < 0) + return -result; + + return result; +} + Error FuseFsNode::VIoctl(int request, va_list args) { LOG_ERROR("Ioctl not implemented for fusefs."); return ENOSYS; diff --git a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h index 5bd7bc1..6097143 100644 --- a/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h +++ b/native_client_sdk/src/libraries/nacl_io/fusefs/fuse_fs.h @@ -55,6 +55,7 @@ class FuseFsNode : public Node { const struct termios* termios_p); virtual Error GetSize(off_t* out_size); virtual Error Futimens(const struct timespec times[2]); + virtual Error Fchmod(mode_t mode); protected: struct fuse_operations* fuse_ops_; diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc index cf6cf07..b5cf443 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc @@ -799,8 +799,7 @@ int KernelProxy::remove(const char* path) { return 0; } -// TODO(noelallen): Needs implementation. -int KernelProxy::fchmod(int fd, int mode) { +int KernelProxy::fchmod(int fd, mode_t mode) { ScopedKernelHandle handle; Error error = AcquireHandle(fd, &handle); if (error) { @@ -808,6 +807,12 @@ int KernelProxy::fchmod(int fd, int mode) { return -1; } + error = handle->node()->Fchmod(mode); + if (error) { + errno = error; + return -1; + } + return 0; } diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h index fb11288..78a8cf8 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h @@ -107,7 +107,7 @@ class KernelProxy : protected KernelObject { virtual ssize_t read(int fd, void* buf, size_t nbyte); virtual ssize_t write(int fd, const void* buf, size_t nbyte); - virtual int fchmod(int fd, int prot); + virtual int fchmod(int fd, mode_t mode); virtual int fcntl(int fd, int request, va_list args); virtual int fstat(int fd, struct stat* buf); virtual int getdents(int fd, void* buf, unsigned int count); diff --git a/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.cc b/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.cc index 6eee9f0..507e5e2 100644 --- a/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.cc +++ b/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.cc @@ -122,4 +122,10 @@ Error MemFsNode::Resize(off_t new_length) { return 0; } +Error MemFsNode::Fchmod(mode_t mode) { + AUTO_LOCK(node_lock_); + SetMode(mode); + return 0; +} + } // namespace nacl_io diff --git a/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.h b/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.h index 77a327a..100b3ec 100644 --- a/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.h +++ b/native_client_sdk/src/libraries/nacl_io/memfs/mem_fs_node.h @@ -27,6 +27,7 @@ class MemFsNode : public Node { size_t count, int* out_bytes); virtual Error FTruncate(off_t size); + virtual Error Fchmod(mode_t mode); private: Error Resize(off_t size); diff --git a/native_client_sdk/src/libraries/nacl_io/node.cc b/native_client_sdk/src/libraries/nacl_io/node.cc index 6702dc8..b91726f 100644 --- a/native_client_sdk/src/libraries/nacl_io/node.cc +++ b/native_client_sdk/src/libraries/nacl_io/node.cc @@ -180,6 +180,10 @@ Error Node::Futimens(const struct timespec times[2]) { return 0; } +Error Node::Fchmod(mode_t mode) { + return EINVAL; +} + int Node::GetLinks() { return stat_.st_nlink; } diff --git a/native_client_sdk/src/libraries/nacl_io/node.h b/native_client_sdk/src/libraries/nacl_io/node.h index c30c796..8fb4ab9 100644 --- a/native_client_sdk/src/libraries/nacl_io/node.h +++ b/native_client_sdk/src/libraries/nacl_io/node.h @@ -90,6 +90,7 @@ class Node : public sdk_util::RefObject { virtual Error Tcsetattr(int optional_actions, const struct termios* termios_p); virtual Error Futimens(const struct timespec times[2]); + virtual Error Fchmod(mode_t mode); virtual int GetLinks(); virtual int GetMode(); diff --git a/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc b/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc index dffc1ba..e0833ce 100644 --- a/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/fuse_fs_test.cc @@ -31,18 +31,16 @@ class FuseFsForTesting : public FuseFs { // Implementation of a simple flat memory filesystem. struct File { - File() { - memset(×, 0, sizeof(times)); - } + File() : mode(0666) { memset(×, 0, sizeof(times)); } std::string name; std::vector<uint8_t> data; + mode_t mode; timespec times[2]; }; typedef std::vector<File> Files; Files g_files; -mode_t last_create_mode = 0666; bool IsValidPath(const char* path) { if (path == NULL) @@ -81,7 +79,7 @@ int testfs_getattr(const char* path, struct stat* stbuf) { if (file == NULL) return -ENOENT; - stbuf->st_mode = S_IFREG | last_create_mode; + stbuf->st_mode = S_IFREG | file->mode; stbuf->st_size = file->data.size(); stbuf->st_atime = file->times[0].tv_sec; stbuf->st_atimensec = file->times[0].tv_nsec; @@ -119,7 +117,7 @@ int testfs_create(const char* path, mode_t mode, struct fuse_file_info* fi) { file = &g_files.back(); file->name = &path[1]; // Skip initial / } - last_create_mode = mode; + file->mode = mode; return 0; } @@ -180,33 +178,62 @@ int testfs_utimens(const char* path, const struct timespec times[2]) { return 0; } +int testfs_chmod(const char* path, mode_t mode) { + File* file = FindFile(path); + if (file == NULL) + return -ENOENT; + + file->mode = mode; + return 0; +} + const char hello_world[] = "Hello, World!\n"; fuse_operations g_fuse_operations = { 0, // flag_nopath 0, // flag_reserved - NULL, // init - NULL, // destroy - NULL, // access - testfs_create, // create - NULL, // fgetattr - NULL, // fsync - NULL, // ftruncate testfs_getattr, // getattr - NULL, // mkdir + NULL, // readlink NULL, // mknod + NULL, // mkdir + NULL, // unlink + NULL, // rmdir + NULL, // symlink + NULL, // rename + NULL, // link + testfs_chmod, // chmod + NULL, // chown + NULL, // truncate testfs_open, // open - NULL, // opendir testfs_read, // read - testfs_readdir, // readdir + testfs_write, // write + NULL, // statfs + NULL, // flush NULL, // release + NULL, // fsync + NULL, // setxattr + NULL, // getxattr + NULL, // listxattr + NULL, // removexattr + NULL, // opendir + testfs_readdir, // readdir NULL, // releasedir - NULL, // rename - NULL, // rmdir - NULL, // truncate - NULL, // unlink - testfs_write, // write + NULL, // fsyncdir + NULL, // init + NULL, // destroy + NULL, // access + testfs_create, // create + NULL, // ftruncate + NULL, // fgetattr + NULL, // lock testfs_utimens, // utimens + NULL, // bmap + NULL, // ioctl + NULL, // poll + NULL, // write_buf + NULL, // read_buf + NULL, // flock + NULL, // fallocate }; class FuseFsTest : public ::testing::Test { @@ -361,6 +388,20 @@ TEST_F(FuseFsTest, Utimens) { EXPECT_EQ(times[1].tv_nsec, statbuf.st_mtimensec); } +TEST_F(FuseFsTest, Fchmod) { + struct stat statbuf; + ScopedNode node; + + ASSERT_EQ(0, fs_.Open(Path("/hello"), O_RDONLY, &node)); + ASSERT_EQ(0, node->GetStat(&statbuf)); + EXPECT_EQ(0666, statbuf.st_mode & ~S_IFMT); + + ASSERT_EQ(0, node->Fchmod(0777)); + + ASSERT_EQ(0, node->GetStat(&statbuf)); + EXPECT_EQ(0777, statbuf.st_mode & ~S_IFMT); +} + namespace { class KernelProxyFuseTest : public ::testing::Test { diff --git a/native_client_sdk/src/tests/nacl_io_test/mem_fs_node_test.cc b/native_client_sdk/src/tests/nacl_io_test/mem_fs_node_test.cc index f2259d7..9b6e347 100644 --- a/native_client_sdk/src/tests/nacl_io_test/mem_fs_node_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/mem_fs_node_test.cc @@ -127,6 +127,25 @@ TEST(MemFsNodeTest, File) { EXPECT_EQ(NULL_NODE, result_node.get()); } +TEST(MemFsNodeTest, Fchmod) { + MemFsNodeForTesting file; + + ASSERT_EQ(0, file.Init(0)); + EXPECT_EQ(S_IRALL | S_IWALL, file.GetMode()); + + struct stat s; + ASSERT_EQ(0, file.GetStat(&s)); + EXPECT_EQ(S_IFREG | S_IRALL | S_IWALL, s.st_mode); + + // Change to read-only. + EXPECT_EQ(0, file.Fchmod(S_IRALL)); + + EXPECT_EQ(S_IRALL, file.GetMode()); + + ASSERT_EQ(0, file.GetStat(&s)); + EXPECT_EQ(S_IFREG | S_IRALL, s.st_mode); +} + TEST(MemFsNodeTest, FTruncate) { MemFsNodeForTesting file; off_t result_size = 0; @@ -229,6 +248,12 @@ TEST(MemFsNodeTest, Directory) { EXPECT_EQ(EISDIR, root.Read(attr, buf1, sizeof(buf1), &result_bytes)); EXPECT_EQ(EISDIR, root.Write(attr, buf1, sizeof(buf1), &result_bytes)); + // Chmod test + EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL)); + EXPECT_EQ(S_IRALL | S_IWALL, root.GetMode()); + // Change it back. + EXPECT_EQ(0, root.Fchmod(S_IRALL | S_IWALL | S_IXALL)); + // Test directory operations MemFsNodeForTesting* raw_file = new MemFsNodeForTesting; EXPECT_EQ(0, raw_file->Init(0)); diff --git a/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h b/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h index b29fe6a..e121c6c 100644 --- a/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h +++ b/native_client_sdk/src/tests/nacl_io_test/mock_kernel_proxy.h @@ -26,7 +26,7 @@ class MockKernelProxy : public nacl_io::KernelProxy { MOCK_METHOD1(dup, int(int)); MOCK_METHOD2(dup2, int(int, int)); MOCK_METHOD1(fchdir, int(int)); - MOCK_METHOD2(fchmod, int(int, int)); + MOCK_METHOD2(fchmod, int(int, mode_t)); MOCK_METHOD3(fchown, int(int, uid_t, gid_t)); MOCK_METHOD3(fcntl, int(int, int, va_list)); MOCK_METHOD1(fdatasync, int(int)); |