diff --git a/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp b/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp index 2332ae06431b3db63b71bce13dd7673ef050004e..7e3fd5fd9032db0d78304007411b4c3f75df0d27 100644 --- a/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp +++ b/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp @@ -15,12 +15,33 @@ #include "file_operations_cloud.h" #include +#include +#include +#include "cloud_disk_inode.h" +#include "cloud_file_utils.h" +#include "database_manager.h" +#include "dk_database.h" +#include "drive_kit.h" +#include "file_operations_helper.h" #include "utils_log.h" namespace OHOS { namespace FileManagement { namespace CloudDisk { +using namespace std; +using namespace DriveKit; +namespace { + static const uint32_t STAT_MODE_REG = 0770; + static const uint32_t STAT_MODE_DIR = 0771; +} + +static int32_t DoCloudLookup(fuse_req_t req, fuse_ino_t parent, const char *name, + struct fuse_entry_param *e) +{ + return 0; +} + void FileOperationsCloud::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { LOGE("Lookup operation is not supported!"); @@ -35,26 +56,159 @@ void FileOperationsCloud::Access(fuse_req_t req, fuse_ino_t ino, int mask) void FileOperationsCloud::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - LOGE("GetAttr operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + fuse_reply_attr(req, &inoPtr->stat, 0); } void FileOperationsCloud::Open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - LOGE("Open operation is not supported!"); - fuse_reply_err(req, ENOSYS); + int32_t fd = -1; + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + + string path = CloudFileUtils::GetLocalFilePath( + inoPtr->cloudId, inoPtr->bundleName, data->userId); + fd = open(path.c_str(), fi->flags & O_NOFOLLOW); + if (fd < 0) { + LOGE("open file failed path:%{public}s errno:%{public}d", path.c_str(), errno); + return (void) fuse_reply_err(req, errno); + } + fi->fh = fd; + fuse_reply_open(req, fi); } void FileOperationsCloud::Forget(fuse_req_t req, fuse_ino_t ino, uint64_t nLookup) { - LOGE("Forget operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct CloudDiskFuseData *data = reinterpret_cast(fuse_req_userdata(req)); + if (ino == FUSE_ROOT_ID) { + LOGD("Cloud file operation should not get a root inode"); + return (void) fuse_reply_none(req); + } + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + shared_ptr node = FileOperationsHelper::FindCloudDiskInode(data, inoPtr->cloudId); + fuse_reply_none(req); } void FileOperationsCloud::ForgetMulti(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { - LOGE("ForgetMulti operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct CloudDiskFuseData *data = reinterpret_cast(fuse_req_userdata(req)); + for (size_t i = 0; i < count; i++) { + if (forgets[i].ino == FUSE_ROOT_ID) { + LOGD("Cloud file operation should not get a root inode"); + return (void) fuse_reply_none(req); + } + struct CloudDiskInode *inoPtr = reinterpret_cast(forgets[i].ino); + shared_ptr node = FileOperationsHelper::FindCloudDiskInode(data, inoPtr->cloudId); + FileOperationsHelper::PutCloudDiskInode(data, node, forgets[i].nlookup); + } + fuse_reply_none(req); +} + +static shared_ptr GetDatabase(int32_t userId, string bundleName) +{ + auto driveKit = DriveKit::DriveKitNative::GetInstance(userId); + if (driveKit == nullptr) { + LOGE("sdk helper get drive kit instance fail"); + return nullptr; + } + + auto container = driveKit->GetDefaultContainer(bundleName); + if (container == nullptr) { + LOGE("sdk helper get drive kit container fail"); + return nullptr; + } + + shared_ptr database = container->GetPrivateDatabase(); + if (database == nullptr) { + LOGE("sdk helper get drive kit database fail"); + return nullptr; + } + return database; +} + +static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, int32_t userId, mode_t mode) +{ + string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId); + string path = CloudFileUtils::GetLocalFilePath(cloudId, bundleName, userId); + if (access(bucketPath.c_str(), F_OK) != 0) { + if (mkdir(bucketPath.c_str(), STAT_MODE_DIR) != 0) { + LOGE("mkdir bucketpath failed :%{public}s err:%{public}d", bucketPath.c_str(), errno); + return -errno; + } + } + int32_t fd = open(path.c_str(), (mode & O_NOFOLLOW) | O_CREAT, STAT_MODE_REG); + if (fd < 0) { + LOGE("create file failed :%{public}s err:%{public}d", path.c_str(), errno); + return -errno; + } + return fd; +} + +void RemoveLocalFile(const string &path) +{ + int32_t err = remove(path.c_str()); + if (err != 0) { + LOGE("remove file %{public}s failed, error:%{public}d", path.c_str(), errno); + } +} + +int32_t GenerateCloudId(int32_t userId, const string &bundleName, string &cloudId) +{ + shared_ptr dkDatabasePtr = GetDatabase(userId, bundleName); + if (dkDatabasePtr == nullptr) { + LOGE("Failed to get database"); + return ENOSYS; + } + + vector ids; + DKError dkErr = dkDatabasePtr->GenerateIds(1, ids); + if (dkErr.dkErrorCode != DKLocalErrorCode::NO_ERROR || ids.size() != 1) { + return ENOSYS; + } + cloudId = ids[0]; + return 0; +} + +int32_t DoCreatFile(fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_entry_param &e) +{ + int32_t err = 0; + string cloudId; + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + struct CloudDiskInode *parentInode = reinterpret_cast(parent); + + err = GenerateCloudId(data->userId, parentInode->bundleName, cloudId); + if (err != 0) { + LOGE("Failed to generate cloud id"); + return -err; + } + + int32_t fd = CreateLocalFile(cloudId, parentInode->bundleName, data->userId, mode); + if (fd < 0) { + LOGD("Create local file failed error:%{public}d", fd); + return fd; + } + + DatabaseManager &databaseManager = DatabaseManager::GetInstance(); + string path = CloudFileUtils::GetLocalFilePath(cloudId, parentInode->bundleName, data->userId); + shared_ptr rdbStore = + databaseManager.GetRdbStore(parentInode->bundleName, data->userId); + err = rdbStore->Create(cloudId, parentInode->cloudId, name); + if (err != 0) { + close(fd); + RemoveLocalFile(path); + return -err; + } + + err = DoCloudLookup(req, parent, name, &e); + if (err != 0) { + close(fd); + RemoveLocalFile(path); + return -err; + } + return fd; } void FileOperationsCloud::MkNod(fuse_req_t req, fuse_ino_t parent, const char *name, @@ -67,8 +221,16 @@ void FileOperationsCloud::MkNod(fuse_req_t req, fuse_ino_t parent, const char *n void FileOperationsCloud::Create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { - LOGE("Create operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct fuse_entry_param e; + int32_t err = 0; + + err = DoCreatFile(req, parent, name, mode, e); + if (err < 0) { + fuse_reply_err(req, -err); + return; + } + fi->fh = err; + fuse_reply_create(req, &e, fi); } void FileOperationsCloud::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, diff --git a/services/cloudfiledaemon/src/cloud_disk/file_operations_local.cpp b/services/cloudfiledaemon/src/cloud_disk/file_operations_local.cpp index ae166e7a80669076b7e2384142513e08612f03fa..c1027bec2292242a1792674bcc70d45019f243a4 100644 --- a/services/cloudfiledaemon/src/cloud_disk/file_operations_local.cpp +++ b/services/cloudfiledaemon/src/cloud_disk/file_operations_local.cpp @@ -15,41 +15,160 @@ #include "file_operations_local.h" #include +#include +#include "file_operations_cloud.h" +#include "file_operations_helper.h" #include "utils_log.h" namespace OHOS { namespace FileManagement { namespace CloudDisk { +using namespace std; + +static int32_t DoLocalLookup(fuse_req_t req, fuse_ino_t parent, const char *name, + struct fuse_entry_param *e) +{ + int32_t err = 0; + bool createFlag = false; + shared_ptr child; + struct CloudDiskFuseData *data = reinterpret_cast(fuse_req_userdata(req)); + string path = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, name); + std::unique_lock wLock(data->cacheLock, std::defer_lock); + + child = FileOperationsHelper::FindCloudDiskInode(data, path); + if (child == nullptr) { + child = make_shared(); + createFlag = true; + LOGD("new child %{public}s", name); + } + + err = stat(path.c_str(), &child->stat); + if (err != 0) { + LOGE("lookup %{public}s error, err: %{public}d", path.c_str(), errno); + return errno; + } + + child->refCount++; + if (createFlag) { + child->parent = parent; + child->path = path; + child->layer = FileOperationsHelper::GetNextLayer(parent); + child->stat.st_ino = reinterpret_cast(child.get()); + child->ops = make_shared(); + wLock.lock(); + data->inodeCache[path] = child; + wLock.unlock(); + } + if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) { + child->bundleName = name; + child->ops = make_shared(); + } + e->ino = reinterpret_cast(child.get()); + FileOperationsHelper::GetInodeAttr(child, &e->attr); + return 0; +} + void FileOperationsLocal::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - LOGE("Lookup operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct fuse_entry_param e; + int32_t err; + + err = DoLocalLookup(req, parent, name, &e); + if (err) { + fuse_reply_err(req, err); + } else { + fuse_reply_entry(req, &e); + } } void FileOperationsLocal::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - LOGE("GetAttr operation is not supported!"); - fuse_reply_err(req, ENOSYS); + if (ino == FUSE_ROOT_ID) { + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + string path = FileOperationsHelper::GetCloudDiskRootPath(data->userId); + + struct stat statBuf; + int err = stat(path.c_str(), &statBuf); + if (err != 0) { + LOGE("lookup %{public}s error, err: %{public}d", path.c_str(), err); + fuse_reply_err(req, err); + return; + } + fuse_reply_attr(req, &statBuf, 0); + return; + } + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + fuse_reply_attr(req, &inoPtr->stat, 0); } void FileOperationsLocal::Forget(fuse_req_t req, fuse_ino_t ino, uint64_t nLookup) { - LOGE("Forget operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + shared_ptr node = FileOperationsHelper::FindCloudDiskInode(data, inoPtr->path); + FileOperationsHelper::PutCloudDiskInode(data, node, nLookup); + fuse_reply_none(req); } void FileOperationsLocal::ForgetMulti(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { - LOGE("ForgetMulti operation is not supported!"); - fuse_reply_err(req, ENOSYS); + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + for (size_t i = 0; i < count; i++) { + struct CloudDiskInode *inoPtr = + reinterpret_cast(forgets[i].ino); + shared_ptr node = FileOperationsHelper::FindCloudDiskInode(data, inoPtr->path); + FileOperationsHelper::PutCloudDiskInode(data, node, forgets[i].nlookup); + } + fuse_reply_none(req); } void FileOperationsLocal::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - LOGE("ReadDir operation is not supported!"); - fuse_reply_err(req, ENOSYS); + (void) fi; + string path; + struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + struct CloudDiskFuseData *data = + reinterpret_cast(fuse_req_userdata(req)); + shared_ptr child; + if (ino == FUSE_ROOT_ID) { + path = FileOperationsHelper::GetCloudDiskRootPath(data->userId); + } else { + path = inoPtr->path; + } + DIR* dir = opendir(path.c_str()); + if (dir == NULL) { + LOGE("opendir error %{public}d, path:%{public}s", errno, path.c_str()); + return; + } + + struct dirent *entry; + string entryData; + size_t len = 0; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + string childPath = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, entry->d_name); + shared_ptr childPtr = FileOperationsHelper::FindCloudDiskInode( + data, childPath.c_str()); + if (childPtr == nullptr) { + childPtr = FileOperationsHelper::GenerateCloudDiskInode(data, inoPtr, + entry->d_name, childPath.c_str()); + } + if (childPtr == nullptr) { + continue; + } + FileOperationsHelper::AddDirEntry(req, entryData, len, entry->d_name, childPtr); + } + FileOperationsHelper::FuseReplyLimited(req, entryData.c_str(), len, off, size); + closedir(dir); + return; } } // namespace CloudDisk } // namespace FileManagement diff --git a/services/cloudfiledaemon/src/cloud_disk/fuse_operations.cpp b/services/cloudfiledaemon/src/cloud_disk/fuse_operations.cpp index dff914bf19792d8656bc8836960fbad593ed800f..4abab1588b4bfebe85f2d9f88008339247af6273 100644 --- a/services/cloudfiledaemon/src/cloud_disk/fuse_operations.cpp +++ b/services/cloudfiledaemon/src/cloud_disk/fuse_operations.cpp @@ -15,13 +15,22 @@ #include "fuse_operations.h" #include "cloud_disk_inode.h" +#include "file_operations_local.h" +#include "utils_log.h" namespace OHOS { namespace FileManagement { namespace CloudDisk { +using namespace std; void FuseOperations::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { - struct CloudDiskInode *inoPtr = reinterpret_cast(parent); + struct CloudDiskInode *inoPtr = nullptr; + if (parent == FUSE_ROOT_ID) { + shared_ptr opsPtr = make_shared(); + opsPtr->Lookup(req, parent, name); + return; + } + inoPtr= reinterpret_cast(parent); inoPtr->ops->Lookup(req, parent, name); } @@ -33,7 +42,13 @@ void FuseOperations::Access(fuse_req_t req, fuse_ino_t ino, int mask) void FuseOperations::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + struct CloudDiskInode *inoPtr = nullptr; + if (ino == FUSE_ROOT_ID) { + shared_ptr opsPtr = make_shared(); + opsPtr->GetAttr(req, ino, fi); + return; + } + inoPtr = reinterpret_cast(ino); inoPtr->ops->GetAttr(req, ino, fi); } @@ -75,7 +90,14 @@ void FuseOperations::Create(fuse_req_t req, fuse_ino_t parent, const char *name, void FuseOperations::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { - struct CloudDiskInode *inoPtr = reinterpret_cast(ino); + struct CloudDiskInode *inoPtr = nullptr; + (void) fi; + if (ino == FUSE_ROOT_ID) { + shared_ptr opsPtr = make_shared(); + opsPtr->ReadDir(req, ino, size, off, fi); + return; + } + inoPtr = reinterpret_cast(ino); inoPtr->ops->ReadDir(req, ino, size, off, fi); } @@ -94,4 +116,4 @@ void FuseOperations::GetXattr(fuse_req_t req, fuse_ino_t ino, const char *name, } } // namespace CloudDisk } // namespace FileManagement -} // namespace OHOS \ No newline at end of file +} // namespace OHOS