int dfs_chmod(const char *path, mode_t mode) { TRACE1("chmod", path) #if PERMS // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(path); assert(dfs); assert('/' == *path); hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { ERROR("Could not connect to HDFS"); return -EIO; } if (hdfsChmod(userFS, path, (short)mode)) { ERROR("Could not chmod %s to %d", path, (int)mode); return -EIO; } #endif return 0; }
/** * For now implement truncate here and only for size == 0. * Weak implementation in that we just delete the file and * then re-create it, but don't set the user, group, and times to the old * file's metadata. */ int dfs_truncate(const char *path, off_t size) { TRACE1("truncate", path) dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; assert(path); assert('/' == *path); assert(dfs); if (size != 0) { return -ENOTSUP; } int ret = dfs_unlink(path); if (ret != 0) { return ret; } hdfsFS userFS = doConnectAsUser(dfs->nn_hostname, dfs->nn_port); if (userFS == NULL) { ERROR("Could not connect"); ret = -EIO; goto cleanup; } int flags = O_WRONLY | O_CREAT; hdfsFile file; if ((file = (hdfsFile)hdfsOpenFile(userFS, path, flags, 0, 0, 0)) == NULL) { ERROR("Could not connect open file %s", path); ret = -EIO; goto cleanup; } if (hdfsCloseFile(userFS, file) != 0) { ERROR("Could not close file %s", path); ret = -EIO; goto cleanup; } cleanup: if (doDisconnect(userFS)) { ret = -EIO; } return ret; }
int dfs_mkdir(const char *path, mode_t mode) { TRACE1("mkdir", path) // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(path); assert(dfs); assert('/' == *path); if (is_protected(path)) { syslog(LOG_ERR,"ERROR: hdfs trying to create the directory: %s", path); return -EACCES; } if (dfs->read_only) { syslog(LOG_ERR,"ERROR: hdfs is configured as read-only, cannot create the directory %s\n",path); return -EACCES; } hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { syslog(LOG_ERR, "ERROR: could not connect to dfs %s:%d\n", __FILE__, __LINE__); return -EIO; } // In theory the create and chmod should be atomic. if (hdfsCreateDirectory(userFS, path)) { syslog(LOG_ERR,"ERROR: hdfs trying to create directory %s",path); return -EIO; } #if PERMS if (hdfsChmod(userFS, path, (short)mode)) { syslog(LOG_ERR,"ERROR: hdfs trying to chmod %s to %d",path, (int)mode); return -EIO; } #endif return 0; }
int dfs_access(const char *path, int mask) { TRACE1("access", path) // bugbug - I think we need the FileSystemAPI/libhdfs to expose this! // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(dfs); assert(path); hdfsFS userFS; if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port)) == NULL) { ERROR("Could not connect to HDFS"); return -EIO; } // return hdfsAccess(userFS, path, mask); return 0; }
int dfs_statfs(const char *path, struct statvfs *st) { TRACE1("statfs",path) dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; assert(path); assert(st); assert(dfs); memset(st,0,sizeof(struct statvfs)); hdfsFS userFS = doConnectAsUser(dfs->nn_hostname, dfs->nn_port); if (userFS == NULL) { ERROR("Could not connect"); return -EIO; } const tOffset cap = hdfsGetCapacity(userFS); const tOffset used = hdfsGetUsed(userFS); const tOffset bsize = hdfsGetDefaultBlockSize(userFS); if (doDisconnect(userFS)) { return -EIO; } st->f_bsize = bsize; st->f_frsize = bsize; st->f_blocks = cap/bsize; st->f_bfree = (cap-used)/bsize; st->f_bavail = (cap-used)/bsize; st->f_files = 1000; st->f_ffree = 500; st->f_favail = 500; st->f_fsid = 1023; st->f_flag = ST_RDONLY | ST_NOSUID; st->f_namemax = 1023; return 0; }
int dfs_rename(const char *from, const char *to) { TRACE1("rename", from) // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(from); assert(to); assert(dfs); assert('/' == *from); assert('/' == *to); if (is_protected(from) || is_protected(to)) { syslog(LOG_ERR,"ERROR: hdfs trying to rename: %s %s", from, to); return -EACCES; } if (dfs->read_only) { syslog(LOG_ERR,"ERROR: hdfs is configured as read-only, cannot rename the directory %s\n",from); return -EACCES; } hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { syslog(LOG_ERR, "ERROR: could not connect to dfs %s:%d\n", __FILE__, __LINE__); return -EIO; } if (hdfsRename(userFS, from, to)) { syslog(LOG_ERR,"ERROR: hdfs trying to rename %s to %s",from, to); return -EIO; } return 0; }
int dfs_unlink(const char *path) { TRACE1("unlink", path) // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(path); assert(dfs); assert('/' == *path); if (is_protected(path)) { syslog(LOG_ERR,"ERROR: hdfs trying to delete a protected directory: %s ",path); return -EACCES; } if (dfs->read_only) { syslog(LOG_ERR,"ERROR: hdfs is configured as read-only, cannot create the directory %s\n",path); return -EACCES; } hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { syslog(LOG_ERR, "ERROR: could not connect to dfs %s:%d\n", __FILE__, __LINE__); return -EIO; } if (hdfsDeleteWithTrash(userFS, path, dfs->usetrash)) { syslog(LOG_ERR,"ERROR: hdfs trying to delete the file %s",path); return -EIO; } return 0; }
int dfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { TRACE1("readdir",path) (void) offset; (void) fi; // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(dfs); assert(path); assert(buf); int path_len = strlen(path); hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { syslog(LOG_ERR, "ERROR: could not connect to dfs %s:%d\n", __FILE__, __LINE__); return -EIO; } // call dfs to read the dir int numEntries = 0; hdfsFileInfo *info = hdfsListDirectory(userFS,path,&numEntries); userFS = NULL; // NULL means either the directory doesn't exist or maybe IO error. if (NULL == info) { return -ENOENT; } int i ; for (i = 0; i < numEntries; i++) { // check the info[i] struct if (NULL == info[i].mName) { syslog(LOG_ERR,"ERROR: for <%s> info[%d].mName==NULL %s:%d", path, i, __FILE__,__LINE__); continue; } struct stat st; fill_stat_structure(&info[i], &st); // hack city: todo fix the below to something nicer and more maintainable but // with good performance // strip off the path but be careful if the path is solely '/' // NOTE - this API started returning filenames as full dfs uris const char *const str = info[i].mName + dfs->dfs_uri_len + path_len + ((path_len == 1 && *path == '/') ? 0 : 1); // pack this entry into the fuse buffer int res = 0; if ((res = filler(buf,str,&st,0)) != 0) { syslog(LOG_ERR, "ERROR: readdir filling the buffer %d %s:%d\n",res, __FILE__, __LINE__); } } // insert '.' and '..' const char *const dots [] = { ".",".."}; for (i = 0 ; i < 2 ; i++) { struct stat st; memset(&st, 0, sizeof(struct stat)); // set to 0 to indicate not supported for directory because we cannot (efficiently) get this info for every subdirectory st.st_nlink = 0; // setup stat size and acl meta data st.st_size = 512; st.st_blksize = 512; st.st_blocks = 1; st.st_mode = (S_IFDIR | 0777); st.st_uid = default_id; st.st_gid = default_id; // todo fix below times st.st_atime = 0; st.st_mtime = 0; st.st_ctime = 0; const char *const str = dots[i]; // flatten the info using fuse's function into a buffer int res = 0; if ((res = filler(buf,str,&st,0)) != 0) { syslog(LOG_ERR, "ERROR: readdir filling the buffer %d %s:%d", res, __FILE__, __LINE__); } } // free the info pointers hdfsFreeFileInfo(info,numEntries); return 0; }
int dfs_open(const char *path, struct fuse_file_info *fi) { TRACE1("open", path) dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(path); assert('/' == *path); assert(dfs); int ret = 0; // 0x8000 is always passed in and hadoop doesn't like it, so killing it here // bugbug figure out what this flag is and report problem to Hadoop JIRA int flags = (fi->flags & 0x7FFF); // retrieve dfs specific data dfs_fh *fh = (dfs_fh*)calloc(1, sizeof (dfs_fh)); if (fh == NULL) { ERROR("Malloc of new file handle failed"); return -EIO; } fh->fs = doConnectAsUser(dfs->nn_hostname, dfs->nn_port); if (fh->fs == NULL) { ERROR("Could not connect to dfs"); return -EIO; } if (flags & O_RDWR) { hdfsFileInfo *info = hdfsGetPathInfo(fh->fs,path); if (info == NULL) { // File does not exist (maybe?); interpret it as a O_WRONLY // If the actual error was something else, we'll get it again when // we try to open the file. flags ^= O_RDWR; flags |= O_WRONLY; } else { // File exists; open this as read only. flags ^= O_RDWR; flags |= O_RDONLY; } } if ((fh->hdfsFH = hdfsOpenFile(fh->fs, path, flags, 0, 0, 0)) == NULL) { ERROR("Could not open file %s (errno=%d)", path, errno); if (errno == 0 || errno == EINTERNAL) { return -EIO; } return -errno; } pthread_mutex_init(&fh->mutex, NULL); if (fi->flags & O_WRONLY || fi->flags & O_CREAT) { fh->buf = NULL; } else { assert(dfs->rdbuffer_size > 0); fh->buf = (char*)malloc(dfs->rdbuffer_size * sizeof(char)); if (NULL == fh->buf) { ERROR("Could not allocate memory for a read for file %s\n", path); ret = -EIO; } fh->buffersStartOffset = 0; fh->bufferSize = 0; } fi->fh = (uint64_t)fh; return ret; }
int dfs_statfs(const char *path, struct statvfs *st) { TRACE1("statfs",path) // retrieve dfs specific data dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data; // check params and the context var assert(path); assert(st); assert(dfs); // init the stat structure memset(st,0,sizeof(struct statvfs)); hdfsFS userFS; // if not connected, try to connect and fail out if we can't. if ((userFS = doConnectAsUser(dfs->nn_hostname,dfs->nn_port))== NULL) { ERROR("Could not connect"); return -EIO; } const tOffset cap = hdfsGetCapacity(userFS); const tOffset used = hdfsGetUsed(userFS); const tOffset bsize = hdfsGetDefaultBlockSize(userFS); // fill in the statvfs structure /* FOR REFERENCE: struct statvfs { unsigned long f_bsize; // file system block size unsigned long f_frsize; // fragment size fsblkcnt_t f_blocks; // size of fs in f_frsize units fsblkcnt_t f_bfree; // # free blocks fsblkcnt_t f_bavail; // # free blocks for non-root fsfilcnt_t f_files; // # inodes fsfilcnt_t f_ffree; // # free inodes fsfilcnt_t f_favail; // # free inodes for non-root unsigned long f_fsid; // file system id unsigned long f_flag; / mount flags unsigned long f_namemax; // maximum filename length }; */ st->f_bsize = bsize; st->f_frsize = bsize; st->f_blocks = cap/bsize; st->f_bfree = (cap-used)/bsize; st->f_bavail = (cap-used)/bsize; st->f_files = 1000; st->f_ffree = 500; st->f_favail = 500; st->f_fsid = 1023; st->f_flag = ST_RDONLY | ST_NOSUID; st->f_namemax = 1023; return 0; }