• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "file_fs_impl.h"
17 
18 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
19 #include <sys/xattr.h>
20 
21 #include "bundle_mgr_proxy.h"
22 #include "ipc_skeleton.h"
23 #include "iservice_registry.h"
24 #include "system_ability_definition.h"
25 #endif
26 
27 using namespace OHOS;
28 using namespace OHOS::FFI;
29 using namespace OHOS::FileManagement;
30 using namespace OHOS::CJSystemapi;
31 using namespace OHOS::CJSystemapi::FileFs;
32 
33 namespace {
34 
35 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
36 const std::string CLOUDDISK_FILE_PREFIX = "/data/storage/el2/cloud";
37 const std::string DISTRIBUTED_FILE_PREFIX = "/data/storage/el2/distributedfiles";
38 const std::string PACKAGE_NAME_FLAG = "<PackageName>";
39 const std::string USER_ID_FLAG = "<currentUserId>";
40 const std::string PHYSICAL_PATH_PREFIX = "/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>";
41 const std::string CLOUD_FILE_LOCATION = "user.cloud.location";
42 const char POSITION_LOCAL = '1';
43 const char POSITION_BOTH = '3';
44 const int BASE_USER_RANGE = 200000;
45 #endif
46 
ParseFile(int32_t file)47 std::tuple<int, FileInfo> ParseFile(int32_t file)
48 {
49     if (file < 0) {
50         LOGE("Invalid fd");
51         return { EINVAL, FileInfo { false, {}, {} } };
52     }
53     auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(file, false);
54     if (fdg == nullptr) {
55         LOGE("Failed to request heap memory.");
56         return { ENOMEM, FileInfo { false, {}, {} } };
57     }
58     return { SUCCESS_CODE, FileInfo { false, {}, move(fdg) } };
59 };
60 
ParseFile(std::string file)61 std::tuple<int, FileInfo> ParseFile(std::string file)
62 {
63     std::unique_ptr<char[]> filePath = std::make_unique<char[]>(file.length() + 1);
64     if (!filePath) {
65         return { ENOMEM, FileInfo { true, nullptr, {} } };
66     }
67     for (size_t i = 0; i < file.length(); i++) {
68         filePath[i] = file[i];
69     }
70 
71     return { SUCCESS_CODE, FileInfo { true, move(filePath), {} } };
72 };
73 
CheckFsStat(const FileInfo & fileInfo,uv_fs_t * req)74 int CheckFsStat(const FileInfo &fileInfo, uv_fs_t* req)
75 {
76     if (fileInfo.isPath) {
77         int ret = uv_fs_stat(nullptr, req, fileInfo.path.get(), nullptr);
78         if (ret < 0) {
79             LOGE("Failed to stat file with path");
80             return ret;
81         }
82     } else {
83         int ret = uv_fs_fstat(nullptr, req, fileInfo.fdg->GetFD(), nullptr);
84         if (ret < 0) {
85             LOGE("Failed to stat file with fd");
86             return ret;
87         }
88     }
89     return SUCCESS_CODE;
90 }
91 
GetUvStat(const FileInfo & fileInfo)92 std::tuple<int, uv_stat_t*> GetUvStat(const FileInfo& fileInfo)
93 {
94     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = {
95         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
96     if (!stat_req) {
97         LOGE("Failed to request heap memory.");
98         return {ENOMEM, nullptr};
99     }
100     auto state = CheckFsStat(fileInfo, stat_req.get());
101     if (state != SUCCESS_CODE) {
102         return { state, nullptr };
103     }
104     uv_stat_t* tempBuf = new (std::nothrow) uv_stat_t(stat_req->statbuf);
105     if (!tempBuf) {
106         return {ENOMEM, nullptr};
107     }
108     return {SUCCESS_CODE, tempBuf};
109 }
110 
ParseRandomFile(std::string file)111 std::tuple<bool, FileInfo, int> ParseRandomFile(std::string file)
112 {
113     LOGI("FS_TEST:: RandomAccessFileImpl::ParseRandomFile");
114     std::unique_ptr<char[]> filePath = std::make_unique<char[]>(file.length() + 1);
115     if (!filePath) {
116         return { false, FileInfo { true, nullptr, {} }, ENOMEM };
117     }
118     for (size_t i = 0; i < file.length(); i++) {
119         filePath[i] = file[i];
120     }
121     OHOS::DistributedFS::FDGuard sfd;
122     auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(sfd, false);
123     if (fdg == nullptr) {
124         return { false, FileInfo { false, nullptr, nullptr }, ENOMEM };
125     }
126     LOGI("FS_TEST:: RandomAccessFileImpl::ParseRandomFile success");
127     return { true, FileInfo { true, move(filePath), move(fdg) }, ERRNO_NOERR };
128 }
129 
UvAccess(const std::string & path,int mode)130 std::tuple<int32_t, bool> UvAccess(const std::string &path, int mode)
131 {
132     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = {
133         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
134     if (!stat_req) {
135         LOGE("Failed to request heap memory.");
136         return {GetErrorCode(ENOMEM), false};
137     }
138     bool isAccess = false;
139     int ret = uv_fs_access(nullptr, stat_req.get(), path.c_str(), mode, nullptr);
140     if (ret < 0 && (std::string_view(uv_err_name(ret)) != "ENOENT")) {
141         LOGE("Failed to access file by path");
142         return {GetErrorCode(ret), false};
143     }
144     if (ret == 0) {
145         isAccess = true;
146     }
147     return {SUCCESS_CODE, isAccess};
148 }
149 
150 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
IsCloudOrDistributedFilePath(const std::string & path)151 bool IsCloudOrDistributedFilePath(const std::string &path)
152 {
153     return path.find(CLOUDDISK_FILE_PREFIX) == 0 || path.find(DISTRIBUTED_FILE_PREFIX) == 0;
154 }
155 
GetCurrentUserId()156 int GetCurrentUserId()
157 {
158     int uid = IPCSkeleton::GetCallingUid();
159     int userId = uid / BASE_USER_RANGE;
160     return userId;
161 }
162 
GetBundleMgrProxy()163 sptr<OHOS::AppExecFwk::BundleMgrProxy> GetBundleMgrProxy()
164 {
165     sptr<OHOS::ISystemAbilityManager> systemAbilityManager =
166         OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
167     if (!systemAbilityManager) {
168         LOGE("Fail to get system ability mgr");
169         return nullptr;
170     }
171     sptr<OHOS::IRemoteObject> remoteObject =
172         systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
173     if (!remoteObject) {
174         LOGE("Fail to get bundle manager proxy");
175         return nullptr;
176     }
177     return iface_cast<OHOS::AppExecFwk::BundleMgrProxy>(remoteObject);
178 }
179 
GetSelfBundleName()180 std::string GetSelfBundleName()
181 {
182     sptr<OHOS::AppExecFwk::BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
183     if (!bundleMgrProxy) {
184         LOGE("BundleMgrProxy is nullptr");
185         return "";
186     }
187     OHOS::AppExecFwk::BundleInfo bundleInfo;
188     auto ret = bundleMgrProxy->GetBundleInfoForSelf(0, bundleInfo);
189     if (ret != 0) {
190         LOGE("BundleName get fail");
191         return "";
192     }
193     return bundleInfo.name;
194 }
195 
HandleLocalCheck(const std::string & path,int mode)196 std::tuple<int32_t, bool> HandleLocalCheck(const std::string &path, int mode)
197 {
198     // check if the file of /data/storage/el2/cloud is on the local
199     if (path.find(CLOUDDISK_FILE_PREFIX) == 0) {
200         char val[2] = {'\0'};
201         if (getxattr(path.c_str(), CLOUD_FILE_LOCATION.c_str(), val, sizeof(val)) < 0) {
202             LOGE("Get cloud file location fail, err: %{public}d", errno);
203             return {GetErrorCode(errno), false};
204         }
205         if (val[0] == POSITION_LOCAL || val[0] == POSITION_BOTH) {
206             return {SUCCESS_CODE, true};
207         }
208         return {GetErrorCode(ENOENT), false};
209     }
210     // check if the distributed file of /data/storage/el2/distributedfiles is on the local,
211     // convert into physical path(/mnt/hmdfs/<currentUserId>/account/device_view/local/data/<PackageName>) and check
212     if (path.find(DISTRIBUTED_FILE_PREFIX) == 0) {
213         int userId = GetCurrentUserId();
214         std::string bundleName = GetSelfBundleName();
215         std::string relativePath = path.substr(DISTRIBUTED_FILE_PREFIX.length());
216         std::string physicalPath = PHYSICAL_PATH_PREFIX + relativePath;
217         physicalPath.replace(physicalPath.find(USER_ID_FLAG), USER_ID_FLAG.length(), std::to_string(userId));
218         physicalPath.replace(physicalPath.find(PACKAGE_NAME_FLAG), PACKAGE_NAME_FLAG.length(), bundleName);
219         return UvAccess(physicalPath, mode);
220     }
221     return {GetErrorCode(ENOENT), false};
222 }
223 #endif
224 }
225 
226 namespace OHOS {
227 namespace CJSystemapi {
228 using namespace std;
Stat(int32_t file)229 std::tuple<int, sptr<StatImpl>> FileFsImpl::Stat(int32_t file)
230 {
231     auto [fileState, fileInfo] = ParseFile(file);
232 
233     if (fileState != SUCCESS_CODE) {
234         return {GetErrorCode(fileState), nullptr};
235     }
236     auto [statState, stat] = GetUvStat(fileInfo);
237     if (statState != SUCCESS_CODE) {
238         return {GetErrorCode(statState), nullptr};
239     }
240     auto nativeStat = FFIData::Create<StatImpl>(*stat);
241     delete(stat);
242     stat = nullptr;
243     if (!nativeStat) {
244         return {GetErrorCode(ENOMEM), nullptr};
245     }
246 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
247     auto fileInfoPtr = std::make_shared<FileInfo>(std::move(fileInfo));
248     nativeStat->SetFileInfo(fileInfoPtr);
249 #endif
250     return {SUCCESS_CODE, nativeStat};
251 }
252 
Stat(std::string file)253 std::tuple<int32_t, sptr<StatImpl>> FileFsImpl::Stat(std::string file)
254 {
255     auto [fileState, fileInfo] = ParseFile(file);
256 
257     if (fileState != SUCCESS_CODE) {
258         LOGE("ParseFile false, please check the file path!");
259         return {GetErrorCode(fileState), nullptr};
260     }
261     auto [statState, stat] = GetUvStat(fileInfo);
262     if (statState != SUCCESS_CODE) {
263         LOGE("Failed to getUvStat file by fileInfo");
264         return {GetErrorCode(statState), nullptr};
265     }
266     auto nativeStat = FFIData::Create<StatImpl>(*stat);
267     delete(stat);
268     stat = nullptr;
269     if (!nativeStat) {
270         return {GetErrorCode(ENOMEM), nullptr};
271     }
272 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
273     auto fileInfoPtr = std::make_shared<FileInfo>(std::move(fileInfo));
274     nativeStat->SetFileInfo(fileInfoPtr);
275 #endif
276     return {SUCCESS_CODE, nativeStat};
277 }
278 
CreateStream(std::string path,std::string mode)279 std::tuple<int32_t, sptr<StreamImpl>> FileFsImpl::CreateStream(std::string path, std::string mode)
280 {
281     std::unique_ptr<FILE, decltype(&fclose)> fp = { fopen(path.c_str(), mode.c_str()), fclose };
282     if (!fp) {
283         LOGE("Failed to fdopen file by path");
284         return {GetErrorCode(errno), nullptr};
285     }
286     auto nativeStream = FFIData::Create<StreamImpl>(std::move(fp));
287     if (!nativeStream) {
288         return {GetErrorCode(ENOMEM), nullptr};
289     }
290     return {SUCCESS_CODE, nativeStream};
291 }
292 
FdopenStream(int32_t fd,std::string mode)293 std::tuple<int32_t, sptr<StreamImpl>> FileFsImpl::FdopenStream(int32_t fd, std::string mode)
294 {
295     LOGI("FS_TEST::FileFsImpl::FdopenStream start");
296     if (fd < 0) {
297         LOGE("Invalid fd");
298         return {GetErrorCode(EINVAL), nullptr};
299     }
300     unique_ptr<FILE, decltype(&fclose)> fp = { fdopen(fd, mode.c_str()), fclose };
301     if (!fp) {
302         LOGE("Failed to fdopen file by fd:%{public}d", fd);
303         return {GetErrorCode(errno), nullptr};
304     }
305     auto nativeStream = FFIData::Create<StreamImpl>(std::move(fp));
306     if (!nativeStream) {
307         return {GetErrorCode(ENOMEM), nullptr};
308     }
309     return {SUCCESS_CODE, nativeStream};
310 }
311 
Lstat(std::string path)312 std::tuple<int32_t, sptr<StatImpl>> FileFsImpl::Lstat(std::string path)
313 {
314     LOGI("FS_TEST::FileFsImpl::Lstat start");
315 
316     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> lstat_req = {
317         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
318     if (!lstat_req) {
319         LOGE("Failed to request heap memory.");
320         return {GetErrorCode(ENOMEM), nullptr};
321     }
322     int ret = uv_fs_lstat(nullptr, lstat_req.get(), path.c_str(), nullptr);
323     if (ret < 0) {
324         LOGE("Failed to get stat of file, ret: %{public}d", ret);
325         return {GetErrorCode(ret), nullptr};
326     }
327     auto nativeStat = FFIData::Create<StatImpl>(lstat_req->statbuf);
328     if (!nativeStat) {
329         return {GetErrorCode(ENOMEM), nullptr};
330     }
331     return {SUCCESS_CODE, nativeStat};
332 }
333 
CreateRandomAccessFileSync(std::string file,unsigned int mode)334 std::tuple<int32_t, sptr<RandomAccessFileImpl>> FileFsImpl::CreateRandomAccessFileSync(std::string file,
335     unsigned int mode)
336 {
337     auto [succ, fileInfo, err] = ParseRandomFile(file);
338     if (!succ) {
339         LOGE("Error because %{public}d", err);
340         return {GetErrorCode(err), nullptr};
341     }
342 
343     if (fileInfo.isPath) {
344         if (mode < 0) {
345             LOGE("Invalid flags");
346             return {GetErrorCode(EINVAL), nullptr};
347         }
348         unsigned int flags = static_cast<unsigned int>(mode);
349         CommonFunc::ConvertCjFlags(flags);
350         std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> open_req = {
351         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
352         if (!open_req) {
353             LOGE("Failed to request heap memory.");
354             return {GetErrorCode(ENOMEM), nullptr};
355         }
356 
357         int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, S_IRUSR |
358             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
359         if (ret < 0) {
360             LOGE("Faile in fs_open %{public}d", ret);
361             return {GetErrorCode(ret), nullptr};
362         }
363         fileInfo.fdg->SetFD(open_req.get()->result, false);
364     }
365     std::shared_ptr<OHOS::FileManagement::ModuleFileIO::RandomAccessFileEntity> ptr =
366             std::make_shared<OHOS::FileManagement::ModuleFileIO::RandomAccessFileEntity>();
367     ptr->fd.swap(fileInfo.fdg);
368     ptr->filePointer = 0;
369     auto randomAccessFileImpl = FFIData::Create<RandomAccessFileImpl>(std::move(ptr));
370     if (!randomAccessFileImpl) {
371         return {GetErrorCode(ENOMEM), nullptr};
372     }
373     return {SUCCESS_CODE, randomAccessFileImpl};
374 }
375 
CreateRandomAccessFileSync(sptr<FileEntity> entity,unsigned int mode)376 std::tuple<int32_t, sptr<RandomAccessFileImpl>> FileFsImpl::CreateRandomAccessFileSync(sptr<FileEntity> entity,
377     unsigned int mode)
378 {
379     auto fd = entity->fd_.get()->GetFD();
380     FileInfo fileInfo;
381     if (fd < 0) {
382         HILOGE("Invalid fd");
383         return { GetErrorCode(EINVAL), nullptr };
384     }
385     auto dupFd = dup(fd);
386     if (dupFd < 0) {
387         HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd);
388         return { GetErrorCode(EINVAL), nullptr};
389     }
390     auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(dupFd, false);
391     if (fdg == nullptr) {
392         HILOGE("Failed to request heap memory.");
393         close(dupFd);
394         return { GetErrorCode(ENOMEM), nullptr};
395     }
396     fileInfo = FileInfo { false, nullptr, move(fdg) };
397     std::shared_ptr<OHOS::FileManagement::ModuleFileIO::RandomAccessFileEntity> ptr =
398         std::make_shared<OHOS::FileManagement::ModuleFileIO::RandomAccessFileEntity>();
399     ptr->fd.swap(fileInfo.fdg);
400     ptr->filePointer = 0;
401     auto randomAccessFileImpl = FFIData::Create<RandomAccessFileImpl>(std::move(ptr));
402     if (!randomAccessFileImpl) {
403         close(dupFd);
404         return {GetErrorCode(ENOMEM), nullptr};
405     }
406     return {SUCCESS_CODE, randomAccessFileImpl};
407 }
408 
Mkdir(std::string path,bool recursion,bool isTwoArgs)409 int FileFsImpl::Mkdir(std::string path, bool recursion, bool isTwoArgs)
410 {
411 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
412     if (isTwoArgs) {
413         MakeDirectionMode recursionMode = SINGLE;
414         recursionMode = static_cast<MakeDirectionMode>(recursion);
415         if (::Mkdirs(path.c_str(), recursionMode) < 0) {
416             HILOGE("Failed to create directories, error: %{public}d", errno);
417             return GetErrorCode(errno);
418         }
419         return SUCCESS_CODE;
420     }
421 #endif
422     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> mkdir_req = {
423         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
424     if (!mkdir_req) {
425         HILOGE("Failed to request heap memory.");
426         return GetErrorCode(ENOMEM);
427     }
428     int ret = uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr);
429     if (ret) {
430         HILOGE("Failed to create directory");
431         return GetErrorCode(ret);
432     }
433     return SUCCESS_CODE;
434 }
435 
Rmdir(std::string path)436 int FileFsImpl::Rmdir(std::string path)
437 {
438     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> scandir_req = {
439         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
440     if (!scandir_req) {
441         return GetErrorCode(ENOMEM);
442     }
443     int ret = 0;
444     ret = uv_fs_scandir(nullptr, scandir_req.get(), path.c_str(), 0, nullptr);
445     if (ret < 0) {
446         HILOGE("Failed to scandir, ret: %{public}d", ret);
447         return GetErrorCode(ret);
448     }
449     uv_dirent_t dent;
450     while (uv_fs_scandir_next(scandir_req.get(), &dent) != UV_EOF) {
451         string filePath = path + "/" + string(dent.name);
452         if (dent.type == UV_DIRENT_FILE) {
453             std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> unlink_req = {
454                 new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
455             if (!unlink_req) {
456                 HILOGE("Failed to request heap memory.");
457                 return GetErrorCode(ENOMEM);
458             }
459             ret = uv_fs_unlink(nullptr, unlink_req.get(), filePath.c_str(), nullptr);
460             if (ret < 0) {
461                 HILOGE("Failed to unlink file, ret: %{public}d", ret);
462                 return GetErrorCode(ret);
463             }
464         } else if (dent.type == UV_DIRENT_DIR) {
465             auto rmDirentRes = Rmdir(filePath);
466             if (rmDirentRes) {
467                 return rmDirentRes;
468             }
469         }
470     }
471     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> rmdir_req = {
472         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
473     if (!rmdir_req) {
474         LOGE("Failed to request heap memory.");
475         return GetErrorCode(ENOMEM);
476     }
477     ret = uv_fs_rmdir(nullptr, rmdir_req.get(), path.c_str(), nullptr);
478     if (ret < 0) {
479         LOGE("Failed to rmdir empty dir, ret: %{public}d", ret);
480         return GetErrorCode(ret);
481     }
482     return SUCCESS_CODE;
483 }
484 
Rename(std::string oldPath,std::string newPath)485 int FileFsImpl::Rename(std::string oldPath, std::string newPath)
486 {
487     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> rename_req = {
488         new uv_fs_t, CommonFunc::FsReqCleanup };
489     if (!rename_req) {
490         HILOGE("Failed to request heap memory.");
491         return GetErrorCode(ENOMEM);
492     }
493     int ret = uv_fs_rename(nullptr, rename_req.get(), oldPath.c_str(), newPath.c_str(), nullptr);
494     if (ret < 0) {
495         LOGE("Failed to rename file with path");
496         return GetErrorCode(ret);
497     }
498     return SUCCESS_CODE;
499 }
500 
Unlink(std::string path)501 int FileFsImpl::Unlink(std::string path)
502 {
503     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> unlink_req = {
504         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
505     if (!unlink_req) {
506         HILOGE("Failed to request heap memory.");
507         return GetErrorCode(ENOMEM);
508     }
509     int ret = uv_fs_unlink(nullptr, unlink_req.get(), path.c_str(), nullptr);
510     if (ret < 0) {
511         HILOGE("Failed to unlink with path");
512         return GetErrorCode(ret);
513     }
514     return SUCCESS_CODE;
515 }
516 
517 static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode,
518     deque<struct ConflictFiles> &errfiles);
519 
JudgeExistAndEmpty(const string & path)520 static tuple<bool, bool> JudgeExistAndEmpty(const string &path)
521 {
522     filesystem::path pathName(path);
523     if (filesystem::exists(pathName)) {
524         if (filesystem::is_empty(pathName)) {
525             return { true, true };
526         }
527         return { true, false };
528     }
529     return { false, false };
530 }
531 
RmDirectory(const string & path)532 static int RmDirectory(const string &path)
533 {
534     filesystem::path pathName(path);
535     if (filesystem::exists(pathName)) {
536         std::error_code errCode;
537         (void)filesystem::remove_all(pathName, errCode);
538         if (errCode.value() != 0) {
539             LOGE("Failed to remove directory, error code: %{public}d", errCode.value());
540             return errCode.value();
541         }
542     }
543     return ERRNO_NOERR;
544 }
545 
RestoreTime(const string & srcPath,const string & destPath)546 static int RestoreTime(const string &srcPath, const string &destPath)
547 {
548     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = {
549         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
550     if (!stat_req) {
551         HILOGE("Failed to request heap memory.");
552         return ENOMEM;
553     }
554     int ret = uv_fs_stat(nullptr, stat_req.get(), srcPath.c_str(), nullptr);
555     if (ret < 0) {
556         HILOGE("Failed to stat srcPath");
557         return ret;
558     }
559     double atime = static_cast<double>(stat_req->statbuf.st_atim.tv_sec) +
560         static_cast<double>(stat_req->statbuf.st_atim.tv_nsec) / NS;
561     double mtime = static_cast<double>(stat_req->statbuf.st_mtim.tv_sec) +
562         static_cast<double>(stat_req->statbuf.st_mtim.tv_nsec) / NS;
563     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> utime_req = {
564         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
565     if (!utime_req) {
566         HILOGE("Failed to request heap memory.");
567         return ENOMEM;
568     }
569     ret = uv_fs_utime(nullptr, utime_req.get(), destPath.c_str(), atime, mtime, nullptr);
570     if (ret < 0) {
571         HILOGE("Failed to utime %s, error code: %d", destPath.c_str(), ret);
572         return ret;
573     }
574     return ERRNO_NOERR;
575 }
576 
577 struct NameListArg {
578     struct dirent** namelist;
579     int num;
580 };
581 
Deleter(struct NameListArg * arg)582 static void Deleter(struct NameListArg *arg)
583 {
584     for (int i = 0; i < arg->num; i++) {
585         free((arg->namelist)[i]);
586         (arg->namelist)[i] = nullptr;
587     }
588     free(arg->namelist);
589     arg->namelist = nullptr;
590     delete arg;
591     arg = nullptr;
592 }
593 
FilterFunc(const struct dirent * filename)594 static int32_t FilterFunc(const struct dirent *filename)
595 {
596     if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") {
597         return FILE_DISMATCH;
598     }
599     return FILE_MATCH;
600 }
601 
RemovePath(const string & pathStr)602 static int RemovePath(const string& pathStr)
603 {
604     filesystem::path pathTarget(pathStr);
605     std::error_code errCode;
606     if (!filesystem::remove(pathTarget, errCode)) {
607         HILOGE("Failed to remove file or directory, error code: %{public}d", errCode.value());
608         return errCode.value();
609     }
610     return ERRNO_NOERR;
611 }
612 
613 
RenameDir(const string & src,const string & dest,const int mode,deque<struct ConflictFiles> & errfiles)614 static int RenameDir(const string &src, const string &dest, const int mode, deque<struct ConflictFiles> &errfiles)
615 {
616     filesystem::path destPath(dest);
617     if (filesystem::exists(destPath)) {
618         return RecurMoveDir(src, dest, mode, errfiles);
619     }
620     filesystem::path srcPath(src);
621     std::error_code errCode;
622     filesystem::rename(srcPath, destPath, errCode);
623     if (errCode.value() == EXDEV) {
624         HILOGE("Failed to rename file due to EXDEV");
625         if (!filesystem::create_directory(destPath, errCode)) {
626             HILOGE("Failed to create directory, error code: %{public}d", errCode.value());
627             return errCode.value();
628         }
629         int ret = RestoreTime(srcPath, destPath);
630         if (ret) {
631             HILOGE("Failed to utime dstPath");
632             return ret;
633         }
634         return RecurMoveDir(src, dest, mode, errfiles);
635     }
636     if (errCode.value() != 0) {
637         HILOGE("Failed to rename file, error code: %{public}d", errCode.value());
638         return errCode.value();
639     }
640     return ERRNO_NOERR;
641 }
642 
CopyAndDeleteFile(const string & src,const string & dest)643 static int CopyAndDeleteFile(const string &src, const string &dest)
644 {
645     filesystem::path dstPath(dest);
646     if (filesystem::exists(dstPath)) {
647         int removeRes = RemovePath(dest);
648         if (removeRes != 0) {
649             HILOGE("Failed to remove dest file");
650             return removeRes;
651         }
652     }
653     filesystem::path srcPath(src);
654     std::error_code errCode;
655     if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) {
656         HILOGE("Failed to copy file, error code: %{public}d", errCode.value());
657         return errCode.value();
658     }
659     int ret = RestoreTime(srcPath, dstPath);
660     if (ret) {
661         HILOGE("Failed to utime dstPath");
662         return ret;
663     }
664     return RemovePath(src);
665 }
666 
RenameFile(const string & src,const string & dest,const int mode,deque<struct ConflictFiles> & errfiles)667 static int RenameFile(const string &src, const string &dest, const int mode, deque<struct ConflictFiles> &errfiles)
668 {
669     filesystem::path dstPath(dest);
670     if (filesystem::exists(dstPath)) {
671         if (filesystem::is_directory(dstPath)) {
672             errfiles.emplace_front(src, dest);
673             return ERRNO_NOERR;
674         }
675         if (mode == DIRMODE_FILE_THROW_ERR) {
676             errfiles.emplace_back(src, dest);
677             return ERRNO_NOERR;
678         }
679     }
680     filesystem::path srcPath(src);
681     std::error_code errCode;
682     filesystem::rename(srcPath, dstPath, errCode);
683     if (errCode.value() == EXDEV) {
684         HILOGE("Failed to rename file due to EXDEV");
685         return CopyAndDeleteFile(src, dest);
686     }
687     return errCode.value();
688 }
689 
RecurMoveDir(const string & srcPath,const string & destPath,const int mode,deque<struct ConflictFiles> & errfiles)690 static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode,
691     deque<struct ConflictFiles> &errfiles)
692 {
693     filesystem::path dpath(destPath);
694     if (!filesystem::is_directory(dpath)) {
695         errfiles.emplace_front(srcPath, destPath);
696         return ERRNO_NOERR;
697     }
698 
699     unique_ptr<struct NameListArg, decltype(Deleter)*> ptr = {new struct NameListArg, Deleter};
700     if (!ptr) {
701         HILOGE("Failed to request heap memory.");
702         return ENOMEM;
703     }
704     int num = scandir(srcPath.c_str(), &(ptr->namelist), FilterFunc, alphasort);
705     ptr->num = num;
706 
707     for (int i = 0; i < num; i++) {
708         if ((ptr->namelist[i])->d_type == DT_DIR) {
709             string srcTemp = srcPath + '/' + string((ptr->namelist[i])->d_name);
710             string destTemp = destPath + '/' + string((ptr->namelist[i])->d_name);
711             size_t size = errfiles.size();
712             int res = RenameDir(srcTemp, destTemp, mode, errfiles);
713             if (res != ERRNO_NOERR) {
714                 return res;
715             }
716             if (size != errfiles.size()) {
717                 continue;
718             }
719             res = RemovePath(srcTemp);
720             if (res) {
721                 return res;
722             }
723         } else {
724             string src = srcPath + '/' + string((ptr->namelist[i])->d_name);
725             string dest = destPath + '/' + string((ptr->namelist[i])->d_name);
726             int res = RenameFile(src, dest, mode, errfiles);
727             if (res != ERRNO_NOERR) {
728                 HILOGE("Failed to rename file for error %{public}d", res);
729                 return res;
730             }
731         }
732     }
733     return ERRNO_NOERR;
734 }
735 
MoveDirFunc(const string & src,const string & dest,const int mode,std::deque<struct ConflictFiles> & errfiles)736 static int MoveDirFunc(const string &src, const string &dest, const int mode,
737     std::deque<struct ConflictFiles> &errfiles)
738 {
739     size_t found = string(src).rfind('/');
740     if (found == std::string::npos) {
741         return EINVAL;
742     }
743     if (access(src.c_str(), W_OK) != 0) {
744         LOGE("Failed to move src directory due to doesn't exist or hasn't write permission");
745         return errno;
746     }
747     string dirName = string(src).substr(found);
748     string destStr = dest + dirName;
749     auto [destStrExist, destStrEmpty] = JudgeExistAndEmpty(destStr);
750     if (destStrExist && !destStrEmpty) {
751         if (mode == DIRMODE_DIRECTORY_REPLACE) {
752             int removeRes = RmDirectory(destStr);
753             if (removeRes) {
754                 HILOGE("Failed to remove dest directory in DIRMODE_DIRECTORY_REPLACE");
755                 return removeRes;
756             }
757         }
758         if (mode == DIRMODE_DIRECTORY_THROW_ERR) {
759             HILOGE("Failed to move directory in DIRMODE_DIRECTORY_THROW_ERR");
760             return ENOTEMPTY;
761         }
762     }
763     int res = RenameDir(src, destStr, mode, errfiles);
764     if (res == ERRNO_NOERR) {
765         if (!errfiles.empty()) {
766             HILOGE("Failed to movedir with some conflicted files");
767             return EEXIST;
768         }
769         int removeRes = RmDirectory(src);
770         if (removeRes) {
771             HILOGE("Failed to remove src directory");
772             return removeRes;
773         }
774     }
775     return res;
776 }
777 
DequeToCConflict(std::deque<struct ConflictFiles> errfiles)778 static CConflictFiles* DequeToCConflict(std::deque<struct ConflictFiles> errfiles)
779 {
780     CConflictFiles* result = new(std::nothrow) CConflictFiles[errfiles.size()];
781     if (result == nullptr) {
782         return nullptr;
783     }
784     size_t temp = 0;
785     for (size_t i = 0; i < errfiles.size(); i++) {
786         size_t srcFilesLen = errfiles[i].srcFiles.length() + 1;
787         result[i].srcFiles = static_cast<char*>(malloc(srcFilesLen));
788         if (result[i].srcFiles == nullptr) {
789             break;
790         }
791         if (strcpy_s(result[i].srcFiles, srcFilesLen, errfiles[i].srcFiles.c_str()) != 0) {
792             free(result[i].srcFiles);
793             result[i].srcFiles = nullptr;
794             break;
795         }
796         size_t destFilesLen = errfiles[i].destFiles.length() + 1;
797         result[i].destFiles = static_cast<char*>(malloc(destFilesLen));
798         if (result[i].destFiles == nullptr) {
799             free(result[i].srcFiles);
800             result[i].srcFiles = nullptr;
801             break;
802         }
803         if (strcpy_s(result[i].destFiles, destFilesLen, errfiles[i].destFiles.c_str()) != 0) {
804             free(result[i].srcFiles);
805             free(result[i].destFiles);
806 
807             result[i].srcFiles = nullptr;
808             result[i].destFiles = nullptr;
809             break;
810         }
811         temp++;
812     }
813     if (temp != errfiles.size()) {
814         for (size_t j = temp; j > 0; j--) {
815             free(result[j - 1].srcFiles);
816             free(result[j - 1].destFiles);
817 
818             result[j - 1].srcFiles = nullptr;
819             result[j - 1].destFiles = nullptr;
820         }
821         delete[] result;
822         result = nullptr;
823         return nullptr;
824     }
825     return result;
826 }
827 
MoveDir(string src,string dest,int32_t mode)828 RetDataCArrConflictFiles FileFsImpl::MoveDir(string src, string dest, int32_t mode)
829 {
830     RetDataCArrConflictFiles ret = { .code = EINVAL, .data = { .head = nullptr, .size = 0 } };
831     if (!filesystem::is_directory(filesystem::status(src))) {
832         HILOGE("Invalid src");
833         ret.code = GetErrorCode(EINVAL);
834         return ret;
835     }
836     if (!filesystem::is_directory(filesystem::status(dest))) {
837         HILOGE("Invalid dest");
838         ret.code = GetErrorCode(EINVAL);
839         return ret;
840     }
841     if (mode < DIRMODE_MIN || mode > DIRMODE_MAX) {
842         HILOGE("Invalid mode");
843         ret.code = GetErrorCode(EINVAL);
844         return ret;
845     }
846     std::deque<struct ConflictFiles> errfiles = {};
847     int code = MoveDirFunc(src, dest, mode, errfiles);
848     if (code != SUCCESS_CODE) {
849         ret.code = GetErrorCode(code);
850     } else {
851         ret.code = SUCCESS_CODE;
852     }
853     ret.data.size = (int64_t)errfiles.size();
854     ret.data.head = DequeToCConflict(errfiles);
855     return ret;
856 }
857 
CheckReadArgs(int32_t fd,const char * buf,int64_t bufLen,size_t length,int64_t offset)858 static bool CheckReadArgs(int32_t fd, const char* buf, int64_t bufLen, size_t length, int64_t offset)
859 {
860     if (fd < 0) {
861         LOGE("Invalid fd");
862         return false;
863     }
864     if (buf == nullptr) {
865         LOGE("malloc fail");
866         return false;
867     }
868     if (bufLen > UINT_MAX) {
869         LOGE("Invalid arraybuffer");
870         return false;
871     }
872     if (length > UINT_MAX) {
873         LOGE("Invalid arraybuffer");
874         return false;
875     }
876     if (offset < 0) {
877         LOGE("option.offset shall be positive number");
878         return false;
879     }
880     return true;
881 }
882 
Read(int32_t fd,char * buf,int64_t bufLen,size_t length,int64_t offset)883 RetDataI64 FileFsImpl::Read(int32_t fd, char* buf, int64_t bufLen, size_t length, int64_t offset)
884 {
885     LOGI("FS_TEST::FileFsImpl::Read start");
886     RetDataI64 ret = { .code = EINVAL, .data = 0 };
887 
888     if (!CheckReadArgs(fd, buf, bufLen, length, offset)) {
889         return ret;
890     }
891 
892     auto [state, buff, len, offsetResult] = GetReadArg(static_cast<size_t>(bufLen), length, offset);
893     if (state != SUCCESS_CODE) {
894         LOGE("Failed to resolve buf and options");
895         return {GetErrorCode(state), 0};
896     }
897 
898     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
899 
900     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> read_req = {
901         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
902     if (!read_req) {
903         LOGE("Failed to request heap memory.");
904         ret.code = ENOMEM;
905         return ret;
906     }
907     int readCode = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, offset, nullptr);
908     if (readCode < 0) {
909         LOGE("Failed to read file for %{public}d", readCode);
910         ret.code = readCode;
911         return ret;
912     }
913     ret.code = SUCCESS_CODE;
914     ret.data = static_cast<int64_t>(readCode);
915     return ret;
916 }
917 
ReadCur(int32_t fd,char * buf,int64_t bufLen,size_t length)918 RetDataI64 FileFsImpl::ReadCur(int32_t fd, char* buf, int64_t bufLen, size_t length)
919 {
920     LOGI("FS_TEST::FileFsImpl::Read start");
921     RetDataI64 ret = { .code = EINVAL, .data = 0 };
922 
923     if (!CheckReadArgs(fd, buf, bufLen, length, 0)) {
924         return ret;
925     }
926 
927     auto [state, buff, len, offsetResult] = GetReadArg(static_cast<size_t>(bufLen), length, 0);
928     if (state != SUCCESS_CODE) {
929         LOGE("Failed to resolve buf and options");
930         return {GetErrorCode(state), 0};
931     }
932 
933     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
934 
935     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> read_req = {
936         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
937     if (!read_req) {
938         LOGE("Failed to request heap memory.");
939         ret.code = ENOMEM;
940         return ret;
941     }
942     int readCode = uv_fs_read(nullptr, read_req.get(), fd, &buffer, 1, -1, nullptr);
943     if (readCode < 0) {
944         LOGE("Failed to read file for %{public}d", readCode);
945         ret.code = readCode;
946         return ret;
947     }
948 
949     ret.code = SUCCESS_CODE;
950     ret.data = static_cast<int64_t>(readCode);
951     return ret;
952 }
953 
Write(int32_t fd,void * buf,size_t length,int64_t offset,std::string encode)954 RetDataI64 FileFsImpl::Write(int32_t fd, void* buf, size_t length, int64_t offset, std::string encode)
955 {
956     LOGI("FS_TEST::FileFsImpl::Write start");
957     RetDataI64 ret = { .code = EINVAL, .data = 0 };
958     if (fd < 0) {
959         LOGE("Invalid fd");
960         return ret;
961     }
962 
963     auto [state, buff, len, offsetResult] =
964         CommonFunc::GetWriteArg(buf, length, offset, encode);
965     if (state != SUCCESS_CODE) {
966         LOGE("Failed to resolve buf and options");
967         return {state, 0};
968     }
969 
970     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buff), static_cast<unsigned int>(len));
971     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> write_req = {
972         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
973     if (!write_req) {
974         LOGE("Failed to request heap memory.");
975         ret.code = ENOMEM;
976         return ret;
977     }
978     int writeCode = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr);
979     if (writeCode < 0) {
980         LOGE("Failed to write file for %{public}d", writeCode);
981         ret.code = writeCode;
982         return ret;
983     }
984     ret.code = SUCCESS_CODE;
985     ret.data = static_cast<int64_t>(writeCode);
986     return ret;
987 }
988 
WriteCur(int32_t fd,void * buf,size_t length,std::string encode)989 RetDataI64 FileFsImpl::WriteCur(int32_t fd, void* buf, size_t length, std::string encode)
990 {
991     LOGI("FS_TEST::FileFsImpl::Write start");
992     RetDataI64 ret = { .code = EINVAL, .data = 0 };
993     if (fd < 0) {
994         LOGE("Invalid fd");
995         return ret;
996     }
997 
998     auto [state, buff, len, offsetResult] =
999         CommonFunc::GetWriteArg(buf, length, 0, encode);
1000     if (state != SUCCESS_CODE) {
1001         LOGE("Failed to resolve buf and options");
1002         return {state, 0};
1003     }
1004 
1005     uv_buf_t buffer = uv_buf_init(static_cast<char *>(buff), static_cast<unsigned int>(len));
1006     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> write_req = {
1007         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1008     if (!write_req) {
1009         LOGE("Failed to request heap memory.");
1010         ret.code = ENOMEM;
1011         return ret;
1012     }
1013     int writeCode = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, -1, nullptr);
1014     if (writeCode < 0) {
1015         LOGE("Failed to write file for %{public}d", writeCode);
1016         ret.code = writeCode;
1017         return ret;
1018     }
1019     ret.code = SUCCESS_CODE;
1020     ret.data = static_cast<int64_t>(writeCode);
1021     return ret;
1022 }
1023 
Access(std::string path,int32_t mode,int32_t flag)1024 std::tuple<int32_t, bool> FileFsImpl::Access(std::string path, int32_t mode, int32_t flag)
1025 {
1026 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
1027     if (flag == LOCAL_FLAG && IsCloudOrDistributedFilePath(path)) {
1028         return HandleLocalCheck(path, mode);
1029     }
1030 #endif
1031     return UvAccess(path, mode);
1032 }
1033 
Truncate(std::string file,int64_t len)1034 int FileFsImpl::Truncate(std::string file, int64_t len)
1035 {
1036     auto [fileState, fileInfo] = ParseFile(file);
1037     if (fileState != SUCCESS_CODE) {
1038         return GetErrorCode(EINVAL);
1039     }
1040     if (len < 0) {
1041         return GetErrorCode(EINVAL);
1042     }
1043     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> open_req = {
1044         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1045     if (!open_req) {
1046         HILOGE("Failed to request heap memory.");
1047         return GetErrorCode(ENOMEM);
1048     }
1049     int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), O_RDWR,
1050         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
1051     if (ret < 0) {
1052         return GetErrorCode(ret);
1053     }
1054     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> ftruncate_req = {
1055         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1056     if (!ftruncate_req) {
1057         HILOGE("Failed to request heap memory.");
1058         return GetErrorCode(ENOMEM);
1059     }
1060     ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), ret, len, nullptr);
1061     if (ret < 0) {
1062         HILOGE("Failed to truncate file by path");
1063         return GetErrorCode(ret);
1064     }
1065     return SUCCESS_CODE;
1066 }
1067 
Truncate(int32_t fd,int64_t len)1068 int FileFsImpl::Truncate(int32_t fd, int64_t len)
1069 {
1070     auto [fileState, fileInfo] = ParseFile(fd);
1071     if (fileState != SUCCESS_CODE) {
1072         return GetErrorCode(fileState);
1073     }
1074     if (len < 0) {
1075         return GetErrorCode(EINVAL);
1076     }
1077     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> ftruncate_req = {
1078         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1079     if (!ftruncate_req) {
1080         HILOGE("Failed to request heap memory.");
1081         return GetErrorCode(ENOMEM);
1082     }
1083     int ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), fileInfo.fdg->GetFD(), len, nullptr);
1084     if (ret < 0) {
1085         HILOGE("Failed to truncate file by fd for libuv error %{public}d", ret);
1086         return GetErrorCode(ret);
1087     }
1088     return SUCCESS_CODE;
1089 }
1090 
CloseFd(int fd)1091 static int CloseFd(int fd)
1092 {
1093     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> close_req = {
1094         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1095     if (!close_req) {
1096         HILOGE("Failed to request heap memory.");
1097         return ENOMEM;
1098     }
1099     int ret = uv_fs_close(nullptr, close_req.get(), fd, nullptr);
1100     if (ret < 0) {
1101         HILOGE("Failed to close file with ret: %{public}d", ret);
1102         return ret;
1103     }
1104     return SUCCESS_CODE;
1105 }
1106 
CloseCore(FileStruct fileStruct)1107 static int CloseCore(FileStruct fileStruct)
1108 {
1109     if (fileStruct.isFd) {
1110         auto err = CloseFd(fileStruct.fd);
1111         if (err) {
1112             return GetErrorCode(err);
1113         }
1114     } else {
1115         auto err = CloseFd(fileStruct.fileEntity->fd_->GetFD());
1116         if (err) {
1117             return GetErrorCode(err);
1118         }
1119     }
1120     return SUCCESS_CODE;
1121 }
1122 
Close(int32_t file)1123 int FileFsImpl::Close(int32_t file)
1124 {
1125     FileStruct fileStruct;
1126     if (file >= 0) {
1127         fileStruct = FileStruct { true, file, nullptr };
1128     } else {
1129         return GetErrorCode(EINVAL);
1130     }
1131 
1132     return CloseCore(fileStruct);
1133 }
1134 
Close(sptr<OHOS::CJSystemapi::FileFs::FileEntity> file)1135 int FileFsImpl::Close(sptr<OHOS::CJSystemapi::FileFs::FileEntity> file)
1136 {
1137     FileStruct fileStruct = FileStruct { false, -1, file };
1138     return CloseCore(fileStruct);
1139 }
1140 
GetFileSize(const string & path,int64_t & offset)1141 static int GetFileSize(const string &path, int64_t &offset)
1142 {
1143     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = {
1144         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1145     if (!stat_req) {
1146         HILOGE("Failed to request heap memory.");
1147         return ENOMEM;
1148     }
1149 
1150     int ret = uv_fs_stat(nullptr, stat_req.get(), path.c_str(), nullptr);
1151     if (ret < 0) {
1152         HILOGE("Failed to get file stat by path");
1153         return ret;
1154     }
1155 
1156     offset = static_cast<int64_t>(stat_req->statbuf.st_size);
1157     return ERRNO_NOERR;
1158 }
1159 
ReadLines(char * file,std::string encoding)1160 std::tuple<int32_t, sptr<ReadIteratorImpl>> FileFsImpl::ReadLines(char* file, std::string encoding)
1161 {
1162     if (encoding != "utf-8") {
1163         return { GetErrorCode(EINVAL), nullptr};
1164     }
1165     auto iterator = ::ReaderIterator(file);
1166     if (iterator == nullptr) {
1167         HILOGE("Failed to read lines of the file, error: %{public}d", errno);
1168         return { GetErrorCode(errno), nullptr};
1169     }
1170     int64_t offset = 0;
1171     int ret = GetFileSize(file, offset);
1172     if (ret != 0) {
1173         HILOGE("Failed to get size of the file");
1174         return { GetErrorCode(ret), nullptr};
1175     }
1176     std::shared_ptr<OHOS::FileManagement::ModuleFileIO::ReaderIteratorEntity> ptr =
1177         std::make_shared<OHOS::FileManagement::ModuleFileIO::ReaderIteratorEntity>();
1178     ptr->iterator = iterator;
1179     ptr->offset = offset;
1180     auto readIteratorImpl = FFIData::Create<ReadIteratorImpl>(std::move(ptr));
1181     if (!readIteratorImpl) {
1182         return {GetErrorCode(ENOMEM), nullptr};
1183     }
1184     return {SUCCESS_CODE, readIteratorImpl};
1185 }
1186 
ReadTextCheckArgs(int64_t offset,int64_t len,char * encoding)1187 static int ReadTextCheckArgs(int64_t offset, int64_t len, char* encoding)
1188 {
1189     if (offset < 0) {
1190         HILOGE("Illegal option.offset parameter");
1191         return GetErrorCode(EINVAL);
1192     }
1193     if (len < 0 || len > UINT_MAX) {
1194         HILOGE("Illegal option.length parameter");
1195         return GetErrorCode(EINVAL);
1196     }
1197     if (string(encoding) != "utf-8") {
1198         HILOGE("Illegal option.encoding parameter");
1199         return GetErrorCode(EINVAL);
1200     }
1201     return SUCCESS_CODE;
1202 }
1203 
ReadTextOpenFile(const std::string & path)1204 static int ReadTextOpenFile(const std::string& path)
1205 {
1206     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> open_req = {
1207         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup
1208     };
1209     if (open_req == nullptr) {
1210         HILOGE("Failed to request heap memory.");
1211         return -ENOMEM;
1212     }
1213 
1214     return uv_fs_open(nullptr, open_req.get(), path.c_str(), O_RDONLY,
1215         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
1216 }
1217 
ReadFromFile(int fd,int64_t offset,string & buffer)1218 static int ReadFromFile(int fd, int64_t offset, string& buffer)
1219 {
1220     uv_buf_t readbuf = uv_buf_init(const_cast<char *>(buffer.c_str()), static_cast<unsigned int>(buffer.size()));
1221     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> read_req = {
1222         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1223     if (read_req == nullptr) {
1224         HILOGE("Failed to request heap memory.");
1225         return -ENOMEM;
1226     }
1227     return uv_fs_read(nullptr, read_req.get(), fd, &readbuf, 1, offset, nullptr);
1228 }
1229 
ReadText(char * path,int64_t offset,bool hasLen,int64_t len,char * encoding)1230 RetDataCString FileFsImpl::ReadText(char* path, int64_t offset, bool hasLen, int64_t len, char* encoding)
1231 {
1232     RetDataCString retData = { .code = ERR_INVALID_INSTANCE_CODE, .data = nullptr };
1233     int code = ReadTextCheckArgs(offset, len, encoding);
1234     if (code != SUCCESS_CODE) {
1235         retData.code = code;
1236         return retData;
1237     }
1238 
1239     DistributedFS::FDGuard sfd;
1240     int fd = ReadTextOpenFile(path);
1241     if (fd < 0) {
1242         HILOGE("Failed to open file by ret: %{public}d", fd);
1243         retData.code =  GetErrorCode(errno);
1244         return retData;
1245     }
1246     sfd.SetFD(fd);
1247     struct stat statbf;
1248     if ((!sfd) || (fstat(sfd.GetFD(), &statbf) < 0)) {
1249         HILOGE("Failed to get stat of file by fd: %{public}d", sfd.GetFD());
1250         retData.code =  GetErrorCode(errno);
1251         return retData;
1252     }
1253 
1254     if (offset > statbf.st_size) {
1255         HILOGE("Invalid offset: %{public}" PRIu64, offset);
1256         retData.code =  GetErrorCode(EINVAL);
1257         return retData;
1258     }
1259 
1260     len = (!hasLen || len > statbf.st_size) ? statbf.st_size : len;
1261     string buffer(len, '\0');
1262     int readRet = ReadFromFile(sfd.GetFD(), offset, buffer);
1263     if (readRet < 0) {
1264         HILOGE("Failed to read file by fd: %{public}d", sfd.GetFD());
1265         retData.code =  GetErrorCode(errno);
1266         return retData;
1267     }
1268     char *value = static_cast<char*>(malloc((len + 1) * sizeof(char)));
1269     if (value == nullptr) {
1270         return retData;
1271     }
1272     std::char_traits<char>::copy(value, buffer.c_str(), len + 1);
1273     retData.code = SUCCESS_CODE;
1274     retData.data = value;
1275     return retData;
1276 }
1277 
Utimes(std::string path,double mtime)1278 int FileFsImpl::Utimes(std::string path, double mtime)
1279 {
1280     if (mtime < 0) {
1281         HILOGE("Invalid mtime from JS second argument");
1282         return GetErrorCode(EINVAL);
1283     }
1284 
1285     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = {
1286         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1287     if (!stat_req) {
1288         HILOGE("Failed to request heap memory.");
1289         return GetErrorCode(ENOMEM);
1290     }
1291 
1292     int ret = uv_fs_stat(nullptr, stat_req.get(), path.c_str(), nullptr);
1293     if (ret < 0) {
1294         HILOGE("Failed to get stat of the file by path");
1295         return GetErrorCode(ret);
1296     }
1297 
1298     std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> utimes_req = {
1299         new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1300     if (!utimes_req) {
1301         HILOGE("Failed to request heap memory.");
1302         return GetErrorCode(ENOMEM);
1303     }
1304 
1305     double atime = static_cast<double>(stat_req->statbuf.st_atim.tv_sec) +
1306         static_cast<double>(stat_req->statbuf.st_atim.tv_nsec) / NS;
1307     ret = uv_fs_utime(nullptr, utimes_req.get(), path.c_str(), atime, mtime / MS, nullptr);
1308     if (ret < 0) {
1309         HILOGE("Failed to chang mtime of the file for %{public}d", ret);
1310         return GetErrorCode(ret);
1311     }
1312     return SUCCESS_CODE;
1313 }
1314 
CreateWatcher(std::string path,uint32_t events,void (* callback)(CWatchEvent))1315 std::tuple<int32_t, sptr<WatcherImpl>> FileFsImpl::CreateWatcher(std::string path, uint32_t events,
1316     void (*callback)(CWatchEvent))
1317 {
1318     std::shared_ptr<WatcherInfoArg> infoArg = std::make_shared<WatcherInfoArg>(callback);
1319     if (!FileWatcherManager::GetInstance().CheckEventValid(events)) {
1320         return { GetErrorCode(EINVAL), nullptr };
1321     }
1322     infoArg->events = events;
1323     infoArg->fileName = path;
1324 
1325     auto watcherImpl = FFIData::Create<WatcherImpl>();
1326     if (!watcherImpl) {
1327         return {GetErrorCode(ENOMEM), nullptr};
1328     }
1329     watcherImpl->data_ = infoArg;
1330 
1331     if (FileWatcherManager::GetInstance().GetNotifyId() < 0 &&
1332         !FileWatcherManager::GetInstance().InitNotify()) {
1333         HILOGE("Failed to get notifyId or initnotify fail");
1334         return { GetErrorCode(errno), nullptr };
1335     }
1336 
1337     bool ret = FileWatcherManager::GetInstance().AddWatcherInfo(infoArg->fileName, infoArg);
1338     if (!ret) {
1339         HILOGE("Failed to add watcher info.");
1340         return {GetErrorCode(EINVAL), nullptr};
1341     }
1342     return {SUCCESS_CODE, watcherImpl};
1343 }
1344 
1345 } // CJSystemapi
1346 } // namespace OHOS