int OssFS::getattr(const char *path, struct stat *statbuf) { log_debug("path:%s", path); int res = 0; OssObject *obj = this->find_file(path); log_debug("immediate sync:%zd, obj:%p", AliConf::IMMEDIATE_SYNC, obj); if (obj != NULL) { memset(statbuf, 0, sizeof(struct stat)); if (obj->get_stats()->type == OSS_DIR) statbuf->st_mode = S_IFDIR | obj->get_stats()->mode; else if (obj->get_stats()->type == OSS_REGULAR) statbuf->st_mode = S_IFREG | obj->get_stats()->mode; else if (obj->get_stats()->type == OSS_LINK) statbuf->st_mode = S_IFLNK | obj->get_stats()->mode; statbuf->st_nlink = 2; statbuf->st_size = obj->get_stats()->size; statbuf->st_atim.tv_sec = obj->get_stats()->mtime; statbuf->st_atim.tv_nsec = 0; statbuf->st_mtim.tv_sec = obj->get_stats()->mtime; statbuf->st_mtim.tv_nsec = 0; statbuf->st_ctim.tv_sec = obj->get_stats()->mtime; statbuf->st_ctim.tv_nsec = 0; statbuf->st_uid = getuid(); statbuf->st_gid = getgid(); } else res = -ENOENT; return res; }
int OssFS::mkdir(const char *path, mode_t mode) { log_debug("path:%s", path); std::vector<OssStats *> dir_stats; string tmp_str = path; if (tmp_str.at(tmp_str.length() - 1) != '/') { tmp_str.append("/"); } OssDirObject* parentObj = (OssDirObject *)get_parent(path); if (NULL == parentObj) { log_error("path [%s]", path); return -ENOENT; } OssObject *obj = this->add_file(tmp_str.c_str(), dir_stats, OSS_DIR); if (NULL == obj) { return -ENOENT; } OSS_FILE_META meta; obj->get_stats()->to_meta(meta); m_oss->put_object_data(AliConf::BUCKET.c_str(), obj->get_path_name(), meta); return 0; }
int OssFS::readlink(const char *path, char *link, size_t size) { log_debug("path:%s, link:%s", path, link); OssObject *obj = find_certain_path(path); if (obj == NULL || obj->get_stats()->type != OSS_LINK) { return -ENOENT; } OssSymObject *sym = (OssSymObject *) obj; sym->get_link_obj(link, size); return 0; }
int OssFS::truncate(const char *path, off_t newSize) { log_debug("path:%s", path); OssObject *obj = this->find_certain_path(path); if (obj == NULL) { return -ENOENT; } //我们在这里先判断这个文件类型, cloudfs目前只支持普通文件的truncate if (obj->get_stats()->type != OSS_REGULAR) { log_debug("Error Truncate type"); return -1; } OssGroupObject *pTmpObj = (OssGroupObject *)obj; return pTmpObj->truncate(newSize); }
// 下面做的工作就是为每个文件实例化一个相应的类 // 目录文件实例化为 OssDirObject int OssFS::load_files(vector<oss_object_desc_t>& objects, bool initial_load, size_t sync_flag) { std::vector<OssStats *> group_stats; vector<oss_object_desc_t>::iterator iter; OSS_FILE_META meta; OssObject *tmpObj = NULL; for (iter = objects.begin(); iter != objects.end(); iter++) { meta.clear(); convert_object_to_meta(&(*iter), meta); //先检查本该文件是否已经存在, 如果已经存在则不需要加载 //第一次的全量加载不进行本步骤的检查, 提高加载速度 if (!initial_load) { tmpObj = get_file(iter->name.c_str()); if (tmpObj != NULL) { //先判断该文件是否已经被打开读写, 如果已经被打开, 则保持该文件状态不变化 if (tmpObj->is_open()) { log_error("file [%s] is opened, ignore it", iter->name.c_str()); if (sync_flag != 0) { tmpObj->set_sync_flag(sync_flag); } continue; } /* obj可能是目录, 普通文件, 链接文件的任意一种 目录: 设置同步标识, 直接跳过 普通文件与链接文件: 如果文件文件大小不一致, 直接删除cloudfs中的对象, 重新创建一个新的对象 */ OssStats *pTmpStat = const_cast<OssStats *>(tmpObj->get_stats()); if (pTmpStat->type == OSS_DIR) { if (sync_flag != 0) { tmpObj->set_sync_flag(sync_flag); } continue; } else if ((pTmpStat->type == OSS_REGULAR) || (pTmpStat->type == OSS_LINK)) { //后台文件与前台文件一致, 直接continue if (pTmpStat->get_size() == iter->size) { if (sync_flag != 0) { tmpObj->set_sync_flag(sync_flag); } continue; } log_error("file [%s] in OSS size[%zd] is different from cloudfs size[%zd], updating ...", iter->name.c_str(), iter->size, pTmpStat->get_size()); //后台文件与前台文件不一致, 删除前台对象, 后面会重新创建该对象 //删除上层目录表中该对象的信息 OssDirObject * parent_dir = (OssDirObject *)get_parent(iter->name.c_str()); if (parent_dir != NULL) { parent_dir->remove_record(tmpObj->get_file_name()); } else { log_error("file [%s] get parent directory failed", iter->name.c_str()); } } else { log_error("file [%s] invalid object type %zd", iter->name.c_str(), pTmpStat->type); continue; } } } log_debug("file:[%s] need online sync", iter->name.c_str()); group_stats.clear(); OssStats stats = OssStats(meta); if (stats.type == OSS_REGULAR) { log_debug("stats.size:[%d]", stats.size); create_group_stats(stats.size, 0, group_stats); tmpObj = this->add_file(iter->name.c_str(), group_stats, stats.type); //subobject不再需要保存stats, 此处循环释放所有的stat delete_group_stats(group_stats); } //增加对LINK文件的初始化处理 else if (stats.type == OSS_DIR) { tmpObj = this->add_file(iter->name.c_str(), group_stats, stats.type); } else if (stats.type == OSS_LINK) { OssStats *pTmpStat = new OssStats(meta); group_stats.push_back(pTmpStat); tmpObj = this->add_file(iter->name.c_str(), group_stats, stats.type); } else { log_error("invalid stats.type %d", stats.type); } /* 检查add_file的结果, 并设置对应的sync_flag */ if (tmpObj != NULL) { if (sync_flag != 0) tmpObj->set_sync_flag(sync_flag); } } return 0; }
int OssFS::readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fileInfo) { log_debug("path:%s", path); (void) offset; (void) fileInfo; //先准备两个子目录, 当前子目录和上级目录 filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); OssObject *pTargetDir = NULL; OSS_OBJS_MAP *target_dir = NULL; string Prefix; const char *pDelimiter = "/"; if (strcmp(path, "/") == 0) { //根目录不需要设置Prefix Prefix = ""; } else { //非根目录, prefix组装形式为fun/模式 Prefix = (path+1); Prefix = Prefix + "/"; } pTargetDir = get_file(path); target_dir = pTargetDir->get_subs(); int is_syncd = 0; //检查同步时间配置, 如果时间间隔不为0, 则按照配置进行文件夹访问时间刷新 if (AliConf::ONLINE_SYNC_CYCLE != 0) { //pTargetDir是当前要读取的目录对象, 判断当前操作与上一次操作的时间间隔 OssStats *pStat = (OssStats *)pTargetDir->get_stats(); time_t current_time = time(0); vector<oss_object_desc_t> object_list; if ((size_t)(current_time - pStat->mtime) > AliConf::ONLINE_SYNC_CYCLE) { size_t sync_flag = pTargetDir->get_sync_flag() + 1; pTargetDir->set_sync_flag(sync_flag); int ret_code = m_oss->get_bucket(AliConf::BUCKET.c_str(), Prefix.c_str(), pDelimiter, object_list); if (ret_code != 0) { //如果向OSS请求更新目录子文件与子目录失败, 记录error日志, 按照已有的缓存数据继续处理 log_error("get_bucket failed"); } else { //更新对象的访问时间 pStat->mtime = current_time; //更新load过来的文件 load_files(object_list, false, pTargetDir->get_sync_flag()); //用于下面函数判断是否进行了一次同步 is_syncd = 1; } } } OssObject* tmpObj; map<const char *, OssObject *>::iterator it; vector<const char *> vecDel; vector<const char *>::iterator vec_iter; //遍历目录的map结构, 启用目录的读锁 ((OssDirObject *)pTargetDir)->rdlock(); for (it = target_dir->begin(); it != target_dir->end(); it++) { tmpObj = it->second; if (1 == is_syncd) { // 本次readdir进行过数据同步 if (tmpObj->get_sync_flag() == pTargetDir->get_sync_flag()) { filler(buf, it->first, NULL, 0); } else { log_debug("file:[%s] need delete.", it->first); vecDel.push_back(it->first); } } else { // 本次readdir没有进行过数据同步, 不需要比较同步flag filler(buf, it->first, NULL, 0); } } //遍历结束, 关闭锁 ((OssDirObject *)pTargetDir)->unlock(); for (vec_iter = vecDel.begin(); vec_iter != vecDel.end(); vec_iter++) { del_file(*vec_iter); } return 0; }