Skip to content

Commit

Permalink
Implement chmod, chown, and utimens.
Browse files Browse the repository at this point in the history
Store uid, gid, and mode in LocalGridFile. These get stored in the "owner", "group" (both names, not uid/gid), and "mode" keys.
It's a shame that mongo::GridFS/GridFile don't provide a way to add/access your own keys in the file object.
Modified the LGF setters and getters, sorry.
  • Loading branch information
Imroy committed Nov 25, 2013
1 parent c92c036 commit b53000a
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 77 deletions.
103 changes: 49 additions & 54 deletions local_gridfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,59 @@

using namespace std;

int LocalGridFile::write(const char *buf, size_t nbyte, off_t offset)
{
size_t last_chunk = (offset + nbyte) / _chunkSize;
size_t written = 0;

while(last_chunk > _chunks.size() - 1) {
char *new_buf = new char[_chunkSize];
memset(new_buf, 0, _chunkSize);
_chunks.push_back(new_buf);
}

int chunk_num = offset / _chunkSize;
char* dest_buf = _chunks[chunk_num];

int buf_offset = offset % _chunkSize;
if(buf_offset) {
dest_buf += offset % _chunkSize;
int to_write = min<size_t>(nbyte - written,
(long unsigned int)(_chunkSize - buf_offset));
memcpy(dest_buf, buf, to_write);
written += to_write;
chunk_num++;
}

while(written < nbyte) {
dest_buf = _chunks[chunk_num];
int to_write = min<size_t>(nbyte - written,
(long unsigned int)_chunkSize);
memcpy(dest_buf, buf, to_write);
written += to_write;
chunk_num++;
}

_length = max(_length, offset + written);
_dirty = true;

return written;
int LocalGridFile::write(const char *buf, size_t nbyte, off_t offset) {
size_t last_chunk = (offset + nbyte) / _chunkSize;
size_t written = 0;

while(last_chunk > _chunks.size() - 1) {
char *new_buf = new char[_chunkSize];
memset(new_buf, 0, _chunkSize);
_chunks.push_back(new_buf);
}

off_t chunk_num = offset / _chunkSize;
off_t buf_offset = offset % _chunkSize;

char* dest_buf = _chunks[chunk_num];
if (buf_offset) {
dest_buf += offset % _chunkSize;
size_t to_write = min<size_t>(nbyte - written, _chunkSize - buf_offset);
memcpy(dest_buf, buf, to_write);
written += to_write;
chunk_num++;
}

while(written < nbyte) {
dest_buf = _chunks[chunk_num];
size_t to_write = min<size_t>(nbyte - written, _chunkSize);
memcpy(dest_buf, buf, to_write);
written += to_write;
chunk_num++;
}

_length = max(_length, offset + written);
_dirty = true;

return written;
}

int LocalGridFile::read(char* buf, size_t size, off_t offset)
{
size_t len = 0;
size_t chunk_num = offset / _chunkSize;
int LocalGridFile::read(char* buf, size_t size, off_t offset) {
size_t len = 0;
size_t chunk_num = offset / _chunkSize;

while(len < size && chunk_num < _chunks.size()) {
const char* chunk = _chunks[chunk_num];
size_t to_read = min<size_t>((size_t)_chunkSize, size - len);
while (len < size && chunk_num < _chunks.size()) {
const char* chunk = _chunks[chunk_num];
size_t to_read = min<size_t>((size_t)_chunkSize, size - len);

if(!len && offset) {
chunk += offset % _chunkSize;
to_read = min<size_t>(to_read,
(size_t)(_chunkSize - (offset % _chunkSize)));
}

memcpy(buf + len, chunk, to_read);
len += to_read;
chunk_num++;
if (!len && offset) {
chunk += offset % _chunkSize;
to_read = min<size_t>(to_read, (size_t)(_chunkSize - (offset % _chunkSize)));
}

return len;
memcpy(buf + len, chunk, to_read);
len += to_read;
chunk_num++;
}

return len;
}
45 changes: 35 additions & 10 deletions local_gridfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@
#include <memory>

#ifdef __linux__
#include "sys/types.h"
#include "sys/types.h"
#endif

const unsigned int DEFAULT_CHUNK_SIZE = 256 * 1024;

class LocalGridFile {
public:
LocalGridFile(int chunkSize = DEFAULT_CHUNK_SIZE) :
_length(0), _chunkSize(chunkSize), _dirty(true) {
public:
LocalGridFile(uid_t u, gid_t g, mode_t m, int chunkSize = DEFAULT_CHUNK_SIZE) :
_length(0),
_chunkSize(chunkSize),
_uid(u),
_gid(g),
_mode(m),
_dirty(true)
{
_chunks.push_back(new char[_chunkSize]);
}

Expand All @@ -25,12 +31,27 @@ class LocalGridFile {
}
}

int getChunkSize() { return _chunkSize; }
int getNumChunks() { return _chunks.size(); }
int getLength() { return _length; }
char* getChunk(int n) { return _chunks[n]; }
bool dirty() { return _dirty; }
void flushed() { _dirty = false; }
int Length() const { return _length; }

int ChunkSize() const { return _chunkSize; }

int NumChunks() const { return _chunks.size(); }

char* Chunk(int n) const { return _chunks[n]; }

uid_t Uid() const { return _uid; }
void setUid(uid_t u) { _uid = u; }

gid_t Gid() const { return _gid; }
void setGid(gid_t g) { _gid = g; }

mode_t Mode() const { return _mode; }
void setMode(mode_t m) { _mode = m; }

bool is_dirty() const { return _dirty; }
bool is_clean() const { return !_dirty; }

void set_flushed() { _dirty = false; }

int write(const char* buf, size_t nbyte, off_t offset);
int read(char* buf, size_t size, off_t offset);
Expand All @@ -39,6 +60,10 @@ class LocalGridFile {

private:
size_t _length, _chunkSize;
uid_t _uid;
gid_t _gid;
mode_t _mode;

bool _dirty;
std::vector<char*> _chunks;
};
Expand Down
3 changes: 3 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ int main(int argc, char *argv[])
static struct fuse_operations gridfs_oper;
gridfs_oper.getattr = gridfs_getattr;
gridfs_oper.readdir = gridfs_readdir;
gridfs_oper.chmod = gridfs_chmod;
gridfs_oper.chown = gridfs_chown;
gridfs_oper.utimens = gridfs_utimens;
gridfs_oper.open = gridfs_open;
gridfs_oper.create = gridfs_create;
gridfs_oper.release = gridfs_release;
Expand Down
130 changes: 117 additions & 13 deletions operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
#include <cerrno>
#include <fcntl.h>
#include <memory>
#include <pwd.h>
#include <grp.h>

#include <mongo/bson/bson.h>
#include <mongo/client/gridfs.h>
#include <mongo/client/connpool.h>
#include <mongo/client/dbclient.h>
Expand Down Expand Up @@ -74,11 +77,14 @@ int gridfs_getattr(const char *path, struct stat *stbuf) {
auto file_iter = open_files.find(path);

if (file_iter != open_files.end()) {
stbuf->st_mode = S_IFREG | 0555;
LocalGridFile::ptr lgf = file_iter->second;
stbuf->st_mode = S_IFREG | (lgf->Mode() & (0xffff ^ S_IFMT));
stbuf->st_nlink = 1;
stbuf->st_uid = lgf->Uid();
stbuf->st_gid = lgf->Gid();
stbuf->st_ctime = time(NULL);
stbuf->st_mtime = time(NULL);
stbuf->st_size = file_iter->second->getLength();
stbuf->st_size = lgf->Length();
return 0;
}

Expand All @@ -95,17 +101,28 @@ int gridfs_getattr(const char *path, struct stat *stbuf) {
}*/

auto sdc = make_ScopedDbConnection();
GridFS gf(sdc->conn(), gridfs_options.db, gridfs_options.prefix);
GridFile file = gf.findFile(path);
string db_name = string(gridfs_options.db) + "." + gridfs_options.prefix;
BSONObj file_obj = sdc->conn().findOne(db_name + ".files",
BSON("filename" << path));

if (!file.exists())
if (file_obj.isEmpty())
return -ENOENT;

stbuf->st_mode = S_IFREG | 0555;
stbuf->st_mode = S_IFREG | (file_obj["mode"].Int() & (0xffff ^ S_IFMT));
stbuf->st_nlink = 1;
stbuf->st_size = file.getContentLength();
if (!file_obj["owner"].eoo()) {
passwd *pw = getpwnam(file_obj["owner"].str().c_str());
if (pw)
stbuf->st_uid = pw->pw_uid;
}
if (!file_obj["group"].eoo()) {
group *gr = getgrnam(file_obj["group"].str().c_str());
if (gr)
stbuf->st_gid = gr->gr_gid;
}
stbuf->st_size = file_obj["length"].Int();

time_t upload_time = mongo_time_to_unix_time(file.getUploadDate());
time_t upload_time = mongo_time_to_unix_time(file_obj["uploadDate"].date());
stbuf->st_ctime = upload_time;
stbuf->st_mtime = upload_time;

Expand Down Expand Up @@ -146,6 +163,74 @@ int gridfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t of
return 0;
}

int gridfs_chmod(const char* path, mode_t mode) {
path = fuse_to_mongo_path(path);
auto file_iter = open_files.find(path);

if (file_iter != open_files.end()) {
LocalGridFile::ptr lgf = file_iter->second;
lgf->setMode(mode);
}

auto sdc = make_ScopedDbConnection();
string db_name = string(gridfs_options.db) + "." + gridfs_options.prefix;
sdc->conn().update(db_name + ".files",
BSON("filename" << path),
BSON("$set" << BSON("mode" << mode)));

return 0;
}

int gridfs_chown(const char* path, uid_t uid, gid_t gid) {
path = fuse_to_mongo_path(path);
auto file_iter = open_files.find(path);

if (file_iter != open_files.end()) {
LocalGridFile::ptr lgf = file_iter->second;
lgf->setUid(uid);
lgf->setGid(gid);
}

mongo::BSONObjBuilder b;

{
passwd *pw = getpwuid(uid);
if (pw)
b.append("owner", pw->pw_name);
}
{
group *gr = getgrgid(gid);
if (gr)
b.append("group", gr->gr_name);
}

if (b.hasField("owner") || b.hasField("group")) {
auto sdc = make_ScopedDbConnection();
string db_name = string(gridfs_options.db) + "." + gridfs_options.prefix;
sdc->conn().update(db_name + ".files",
BSON("filename" << path),
BSON("$set" << b.obj()));
}

return 0;
}

int gridfs_utimens(const char* path, const struct timespec tv[2]) {
path = fuse_to_mongo_path(path);

unsigned long long millis = ((unsigned long long)tv[1].tv_sec * 1000) + (tv[1].tv_nsec / 1e+6);

auto sdc = make_ScopedDbConnection();
string db_name = string(gridfs_options.db) + "." + gridfs_options.prefix;
sdc->conn().update(db_name + ".files",
BSON("filename" << path),
BSON("$set" <<
BSON("uploadDate" << Date_t(millis))
));

return 0;
}

int gridfs_open(const char *path, struct fuse_file_info *fi) {
if ((fi->flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
Expand All @@ -166,8 +251,9 @@ int gridfs_open(const char *path, struct fuse_file_info *fi) {
}

int gridfs_create(const char* path, mode_t mode, struct fuse_file_info* ffi) {
fuse_context *context = fuse_get_context();
path = fuse_to_mongo_path(path);
open_files[path] = std::make_shared<LocalGridFile>();
open_files[path] = std::make_shared<LocalGridFile>(context->uid, context->gid, mode);

ffi->fh = FH++;

Expand Down Expand Up @@ -396,7 +482,7 @@ int gridfs_flush(const char* path, struct fuse_file_info *ffi) {

LocalGridFile::ptr lgf = file_iter->second;

if (!lgf->dirty())
if (lgf->is_clean())
return 0;

auto sdc = make_ScopedDbConnection();
Expand All @@ -405,13 +491,31 @@ int gridfs_flush(const char* path, struct fuse_file_info *ffi) {
if (gf.findFile(path).exists())
gf.removeFile(path);

size_t len = lgf->getLength();
size_t len = lgf->Length();
char *buf = new char[len];
lgf->read(buf, len, 0);

gf.storeFile(buf, len, path);
BSONObj file_obj = gf.storeFile(buf, len, path);

mongo::BSONObjBuilder b;
{
passwd *pw = getpwuid(lgf->Uid());
if (pw)
b.append("owner", pw->pw_name);
}
{
group *gr = getgrgid(lgf->Gid());
if (gr)
b.append("group", gr->gr_name);
}
b.append("mode", lgf->Mode());

string db_name = string(gridfs_options.db) + "." + gridfs_options.prefix;
sdc->conn().update(db_name + ".files",
BSON("filename" << path),
BSON("$set" << b.obj()));

lgf->flushed();
lgf->set_flushed();

return 0;
}
Expand Down
Loading

0 comments on commit b53000a

Please sign in to comment.