• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-2023 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// @ts-nocheck
16import Extension from '@ohos.application.FileAccessExtensionAbility';
17import fs from '@ohos.file.fs';
18import type { Filter } from '@ohos.file.fs';
19import fileAccess from '@ohos.file.fileAccess';
20import fileExtensionInfo from '@ohos.file.fileExtensionInfo';
21import hilog from '@ohos.hilog';
22import { getListFileInfos, getScanFileInfos, buildFilterOptions, buildNoFilterOptions, hasFilter } from './ListScanFileInfo';
23import type { Fileinfo } from './Common';
24import { getPath, checkUri, uriReturnObject, encodePathOfUri, decodeUri, BUNDLE_NAME, DOMAIN_CODE, fileinfoReturnObject } from './Common';
25import { FILE_PREFIX_NAME, TAG, fdReturnObject, boolReturnObject, rootsReturnObject } from './Common';
26import { infosReturnObject, resultsResultObject } from './Common';
27
28
29const deviceFlag = fileExtensionInfo.DeviceFlag;
30const documentFlag = fileExtensionInfo.DocumentFlag;
31const deviceType = fileExtensionInfo.DeviceType;
32const MOVEFILEOVERWRITE = 2;
33const FILEOVERWRITE = 1;
34const THROWEXCEPTION = 0;
35
36const ERR_OK = 0;
37const ERR_ERROR = -1;
38const EXCEPTION = -1;
39const NOEXCEPTION = -2;
40const E_PERM = 13900001;
41const E_NOEXIST = 13900002;
42const E_FAULT = 13900013;
43const E_EXIST = 13900015;
44const E_NOT_DIR = 13900018;
45const E_IS_DIR = 13900019;
46const E_INVAL = 13900020;
47const E_URIS = 14300002;
48const E_GETRESULT = 14300004;
49const CREATE_EVENT_CODE = 0x00000100;
50const IN_DELETE_EVENT_CODE = 0x00000200;
51const DELETE_SELF_EVENT_CODE = 0x00000400;
52const MOVE_TO_CODE = 0x00000080;
53const MOVED_FROM_CODE = 0x00000040;
54const MOVE_SELF_CODE = 0x00000800;
55const MOVE_MODLE_CODE = 3;
56const CREATE_EVENT = 0;
57const DELETE_EVENT = 1;
58const MOVED_TO = 2;
59const MOVED_FROM = 3;
60const MOVED_SELF = 4;
61const DEVICE_ONLINE = 5;
62const DEVICE_OFFLINE = 6;
63const CURRENT_USER_PATH_LEN = 4;
64const CURRENT_USER_PATH = '/storage/Users/currentUser';
65const USER_PATH = '/storage/Users/';
66const TRASH_SUB_FODER = '/oh_trash_content';
67const EXTERNAL_PATH = '/storage/External';
68let observerMap = new Map();
69let eventMap = new Map([
70  [CREATE_EVENT_CODE, CREATE_EVENT],
71  [IN_DELETE_EVENT_CODE, DELETE_EVENT],
72  [DELETE_SELF_EVENT_CODE, DELETE_EVENT],
73  [MOVE_TO_CODE, MOVED_TO],
74  [MOVED_FROM_CODE, MOVED_FROM],
75  [MOVE_SELF_CODE, MOVED_SELF]
76]);
77
78let deviceOnlineMap = new Map([
79  [CREATE_EVENT_CODE, DEVICE_ONLINE],
80  [IN_DELETE_EVENT_CODE, DEVICE_OFFLINE]
81]);
82
83// ['IN_ACCESS', 0x00000001],
84// ['IN_MODIFY', 0x00000002],
85// ['IN_ATTRIB', 0x00000004],
86// ['IN_CLOSE_WRITE', 0x00000008],
87// ['IN_CLOSE_NOWRITE', 0x00000010],
88// ['IN_OPE', 0x00000020],
89// ['IN_MOVED_FROM', 0x00000040],
90// ['IN_MOVED_TO', 0x00000080],
91// ['IN_CREATE', 0x00000100],
92// ['IN_DELETE', 0x00000200],
93// ['IN_DELETE_SELF', 0x00000400],
94// ['IN_MOVE_SELF', 0x00000800]
95
96export default class FileExtAbility extends Extension {
97  onCreate(want): void {
98    hilog.info(DOMAIN_CODE, TAG, 'Extension init process');
99  }
100
101
102  genNewFileUri(uri, displayName) {
103    let newFileUri = uri;
104    if (uri.charAt(uri.length - 1) === '/') {
105      newFileUri += displayName;
106    } else {
107      newFileUri += '/' + displayName;
108    }
109    return newFileUri;
110  }
111
112  getFileName(uri): string {
113    let arr = uri.split('/');
114    let name = arr.pop();
115    if (name === '') {
116      name = arr.pop();
117    }
118    return name;
119  }
120
121  renameUri(uri, displayName): string {
122    let arr = uri.split('/');
123    let newFileUri = '';
124    if (arr.pop() === '') {
125      arr.pop();
126      arr.push(displayName);
127      arr.push('');
128    } else {
129      arr.push(displayName);
130    }
131    for (let index = 0; index < arr.length; index++) {
132      if (arr[index] === '') {
133        newFileUri += '/';
134      } else if (index === arr.length - 1) {
135        newFileUri += arr[index];
136      } else {
137        newFileUri += arr[index] + '/';
138      }
139    }
140    return newFileUri;
141  }
142
143  recurseDir(path, cb): void {
144    try {
145      let stat = fs.statSync(path);
146      if (stat.isDirectory()) {
147        let fileName = fs.listFileSync(path);
148        for (let fileLen = 0; fileLen < fileName.length; fileLen++) {
149          stat = fs.statSync(path + '/' + fileName[fileLen]);
150          if (stat.isDirectory()) {
151            this.recurseDir(path + '/' + fileName[fileLen], cb);
152          } else {
153            cb(path + '/' + fileName[fileLen], false);
154          }
155        }
156      } else {
157        cb(path, false);
158      }
159    } catch (e) {
160      hilog.error(DOMAIN_CODE, TAG, 'recurseDir error ' + e.message);
161      cb(path, true);
162    }
163  }
164
165  openFile(sourceFileUri, flags): {number, number} {
166    sourceFileUri = decodeUri(sourceFileUri);
167    if (!checkUri(sourceFileUri)) {
168      return fdReturnObject(ERR_ERROR, E_URIS);
169    }
170    try {
171      let path = getPath(sourceFileUri);
172      let file = fs.openSync(path, flags);
173      return fdReturnObject(file.fd, ERR_OK);
174    } catch (e) {
175      hilog.error(DOMAIN_CODE, TAG, 'openFile error ' + e.message);
176      return fdReturnObject(ERR_ERROR, e.code);
177    }
178  }
179
180  createFile(parentUri, displayName): {string, number} {
181    parentUri = decodeUri(parentUri);
182    if (!checkUri(parentUri)) {
183      return uriReturnObject('', E_URIS);
184    }
185    try {
186      hilog.info(DOMAIN_CODE, TAG, 'createFile, uri is ' + parentUri);
187      let newFileUri = this.genNewFileUri(parentUri, displayName);
188      let path = getPath(newFileUri);
189      if (fs.accessSync(path)) {
190        return uriReturnObject('', E_EXIST);
191      }
192      let file = fs.openSync(path, fs.OpenMode.CREATE);
193      fs.closeSync(file);
194      newFileUri = encodePathOfUri(newFileUri);
195      return uriReturnObject(newFileUri, ERR_OK);
196    } catch (e) {
197      hilog.error(DOMAIN_CODE, TAG, 'createFile error ' + e.message);
198      return uriReturnObject('', e.code);
199    }
200  }
201
202  mkdir(parentUri, displayName): {string, number} {
203    parentUri = decodeUri(parentUri);
204    if (!checkUri(parentUri)) {
205      return uriReturnObject('', E_URIS);
206    }
207    try {
208      let newFileUri = this.genNewFileUri(parentUri, displayName);
209      let path = getPath(newFileUri);
210      fs.mkdirSync(path);
211      newFileUri = encodePathOfUri(newFileUri);
212      return uriReturnObject(newFileUri, ERR_OK);
213    } catch (e) {
214      hilog.error(DOMAIN_CODE, TAG, 'mkdir error ' + e.message);
215      return uriReturnObject('', e.code);
216    }
217  }
218
219  mkdirs(path): void {
220    if (path.length > 0) {
221      // argument uri is dir, add '/'
222      path = path + '/';
223      for (let i = 1; i < path.length; ++i) {
224        if (path.charAt(i) === '/') {
225          let subDir = path.substring(0, i);
226          hilog.info(DOMAIN_CODE, TAG, 'mkdirs: subDir path = ' + subDir);
227          try {
228            let isAccess = fs.accessSync(subDir);
229            if (!isAccess) {
230              fs.mkdirSync(subDir);
231            }
232          } catch (e) {
233            hilog.error(DOMAIN_CODE, TAG, 'mkdirs error ' + e.message);
234          }
235        }
236      }
237    }
238  }
239
240  getUserPath(path): string {
241    let i;
242    let num = 0;
243    if (path.indexOf(USER_PATH) !== 0) {
244      return CURRENT_USER_PATH;
245    }
246    for (i = 0; i < path.length; i++) {
247      if (path[i] === '/') {
248        num ++;
249        if (num === CURRENT_USER_PATH_LEN) {
250          return path.substring(0, i);
251        }
252      }
253    }
254    return path;
255  }
256
257  deleteToTrash(path): number {
258    let code = ERR_OK;
259    let pathLen = path.length;
260    if (path.charAt(pathLen - 1) === '/') {
261      path = path.substring(0, pathLen - 1);
262    }
263    // 取最后一级和前一层目录
264    let posLastSlash = path.lastIndexOf('/');
265    if (posLastSlash === -1) {
266      hilog.error(DOMAIN_CODE, TAG, 'Mkdirs: invalid uri');
267      return E_URIS;
268    }
269
270    let selectPathOnly = path.substring(0, posLastSlash);
271    // 获取时间戳
272    let curTime = new Date().getTime();
273    try {
274      // 拼接新路径
275      let currentTrashParentPath = this.getUserPath(path) + '/.Trash/' + curTime + selectPathOnly + TRASH_SUB_FODER + curTime;
276      // 创建回收站目录
277      this.mkdirs(currentTrashParentPath);
278      let stat = fs.statSync(path);
279      if (!stat.isDirectory()) {
280        let selectFileOnly = path.substring(posLastSlash);
281        hilog.info(DOMAIN_CODE, TAG, 'deleteToTrash: selectFileOnly:' + selectFileOnly);
282        let newFileName = currentTrashParentPath + selectFileOnly;
283        // 移动文件
284        fs.moveFileSync(path, newFileName, 0);
285      } else {
286        // 待删除文件夹
287        let toDeleteDir = path.substring(posLastSlash);
288        // 移动待删除文件夹
289        fs.moveDirSync(selectPathOnly + toDeleteDir, currentTrashParentPath, MOVE_MODLE_CODE);
290        if (fs.accessSync(path)) {
291          fs.rmdirSync(path);
292        }
293      }
294    } catch (e) {
295      hilog.error(DOMAIN_CODE, TAG, 'deleteToTrash error ' + e.message);
296      return e.code;
297    }
298    return code;
299  }
300
301  delete(selectFileUri): number {
302    selectFileUri = decodeUri(selectFileUri);
303    if (!checkUri(selectFileUri)) {
304      return E_URIS;
305    }
306    let path = getPath(selectFileUri);
307
308    if (!path.startsWith(EXTERNAL_PATH)) {
309      return this.deleteToTrash(path);
310    }
311
312    let code = ERR_OK;
313    try {
314      let stat = fs.statSync(path);
315      if (stat.isDirectory()) {
316        fs.rmdirSync(path);
317      } else {
318        fs.unlinkSync(path);
319      }
320    } catch (e) {
321      hilog.error(DOMAIN_CODE, TAG, 'deleteFile error ' + e.message);
322      return e.code;
323    }
324    return code;
325  }
326
327  move(sourceFileUri, targetParentUri): {string, number} {
328    sourceFileUri = decodeUri(sourceFileUri);
329    targetParentUri = decodeUri(targetParentUri);
330    if (!checkUri(sourceFileUri) || !checkUri(targetParentUri)) {
331      return uriReturnObject('', E_URIS);
332    }
333    let displayName = this.getFileName(sourceFileUri);
334    let newFileUri = this.genNewFileUri(targetParentUri, displayName);
335    let oldPath = getPath(sourceFileUri);
336    let newPath = getPath(newFileUri);
337    newFileUri = encodePathOfUri(newFileUri);
338    if (newFileUri === '') {
339      return uriReturnObject('', E_URIS);
340    }
341    if (oldPath === newPath) {
342      // move to the same directory
343      return {
344        uri: newFileUri,
345        code: ERR_OK,
346      };
347    } else if (newPath.indexOf(oldPath) === 0 && newPath.charAt(oldPath.length) === '/') {
348      // move to a subdirectory of the source directory
349      return uriReturnObject('', E_GETRESULT);
350    }
351    try {
352      // The source file does not exist or the destination is not a directory
353      let isAccess = fs.accessSync(oldPath);
354      let stat = fs.statSync(getPath(targetParentUri));
355      let statOld = fs.statSync(oldPath);
356      if (!isAccess || !stat || !stat.isDirectory() || !statOld) {
357        return uriReturnObject('', E_GETRESULT);
358      }
359      // isDir
360      if (statOld.isDirectory()) {
361        fs.moveDirSync(oldPath, getPath(targetParentUri), MOVE_MODLE_CODE);
362        return uriReturnObject(newFileUri, ERR_OK);
363      }
364      // when targetFile is exist, delete it
365      let isAccessNewPath = fs.accessSync(newPath);
366      if (isAccessNewPath) {
367        fs.unlinkSync(newPath);
368      }
369      fs.moveFileSync(oldPath, newPath, 0);
370      return uriReturnObject(newFileUri, ERR_OK);
371    } catch (e) {
372      hilog.error(DOMAIN_CODE, TAG, 'move error ' + e.message);
373      return uriReturnObject('', e.code);
374    }
375  }
376
377  rename(sourceFileUri, displayName): {string, number} {
378    sourceFileUri = decodeUri(sourceFileUri);
379    if (!checkUri(sourceFileUri)) {
380      return uriReturnObject('', E_URIS);
381    }
382    try {
383      let newFileUri = this.renameUri(sourceFileUri, displayName);
384      let oldPath = getPath(sourceFileUri);
385      let newPath = getPath(newFileUri);
386      let isAccess = fs.accessSync(newPath);
387      if (isAccess) {
388        return uriReturnObject('', E_EXIST);
389      }
390      fs.renameSync(oldPath, newPath);
391      newFileUri = encodePathOfUri(newFileUri);
392      return uriReturnObject(newFileUri, ERR_OK);
393    } catch (e) {
394      hilog.error(DOMAIN_CODE, TAG, 'rename error ' + e.message);
395      return uriReturnObject('', e.code);
396    }
397  }
398
399  getReturnValue(sourceUri, destUri, errCode, errMsg, ret): {[], number} {
400    let copyResult = [
401      {
402        sourceUri: sourceUri,
403        destUri: destUri,
404        errCode: errCode,
405        errMsg: errMsg,
406      },
407    ];
408    return resultsResultObject(copyResult, ret);
409  }
410
411  checkCopyArguments(sourceFileUri, targetParentUri): {[], number} {
412    if (!checkUri(sourceFileUri) || !checkUri(targetParentUri)) {
413      hilog.error(DOMAIN_CODE, TAG, 'check arguments error, invalid arguments');
414      return this.getReturnValue(sourceFileUri, targetParentUri, E_URIS, '', EXCEPTION);
415    }
416
417    let displayName = this.getFileName(sourceFileUri);
418    let newFileOrDirUri = this.genNewFileUri(targetParentUri, displayName);
419    let oldPath = getPath(sourceFileUri);
420    let newPath = getPath(newFileOrDirUri);
421    if (oldPath === newPath) {
422      hilog.error(DOMAIN_CODE, TAG, 'the source and target files are the same file');
423      return this.getReturnValue(sourceFileUri, targetParentUri, E_INVAL, '', NOEXCEPTION);
424    } else if (newPath.indexOf(oldPath) === 0 && newPath.charAt(oldPath.length) === '/') {
425      hilog.error(DOMAIN_CODE, TAG, 'copy to a subdirectory of the source directory');
426      return this.getReturnValue(sourceFileUri, targetParentUri, E_FAULT, '', EXCEPTION);
427    }
428
429    try {
430      let isExist = fs.accessSync(oldPath);
431      if (!isExist) {
432        hilog.error(DOMAIN_CODE, TAG, 'source uri is not exist, invalid arguments');
433        return this.getReturnValue(sourceFileUri, '', E_INVAL, '', NOEXCEPTION);
434      }
435
436      let stat = fs.statSync(getPath(targetParentUri));
437      if (!stat || !stat.isDirectory()) {
438        hilog.error(DOMAIN_CODE, TAG, 'target is not directory, invalid arguments');
439        return this.getReturnValue('', targetParentUri, E_INVAL, '', NOEXCEPTION);
440      }
441    } catch (e) {
442      hilog.error(DOMAIN_CODE, TAG, 'copy error ' + e.message);
443      return this.getReturnValue(sourceFileUri, targetParentUri, e.code, '', EXCEPTION);
444    }
445    return resultsResultObject([], ERR_OK);
446  }
447
448  processReturnValue(ret, copyRet): void {
449    if (ret.code === EXCEPTION) {
450      copyRet = ret;
451    }
452    if (ret.code === NOEXCEPTION) {
453      for (let index in ret.results) {
454        copyRet.results.push(ret.results[index]);
455      }
456      copyRet.code = ret.code;
457    }
458  }
459
460  copyFile(sourceFilePath, newFilePath): {[], number} {
461    let copyRet = {
462      results: [],
463      code: ERR_OK,
464    };
465
466    try {
467      let isExist = fs.accessSync(newFilePath);
468      if (isExist) {
469        fs.unlinkSync(newFilePath);
470      }
471      fs.copyFileSync(sourceFilePath, newFilePath);
472    } catch (err) {
473      hilog.error(DOMAIN_CODE, TAG,
474        'copyFileSync failed with error message: ' + err.message + ', error code: ' + err.code);
475      return this.getReturnValue(encodePathOfUri(this.relativePath2uri(sourceFilePath)), '', err.code, err.message, EXCEPTION);
476    }
477    return copyRet;
478  }
479
480  copyDirectory(sourceFilePath, targetFilePath, mode): {[], number} {
481    let copyRet = {
482      results: [],
483      code: ERR_OK,
484    };
485    try {
486      fs.copyDirSync(sourceFilePath, targetFilePath, mode);
487    } catch (err) {
488      if (err.code === E_EXIST) {
489        for (let i = 0; i < err.data.length; i++) {
490          hilog.error(DOMAIN_CODE, TAG,
491            'copy directory failed with conflicting files: ' + err.data[i].srcFile + ' ' + err.data[i].destFile);
492          let ret = this.getReturnValue(
493            encodePathOfUri(this.relativePath2uri(err.data[i].srcFile)),
494            encodePathOfUri(this.relativePath2uri(err.data[i].destFile)),
495            err.code, err.message, NOEXCEPTION);
496          this.processReturnValue(ret, copyRet);
497        }
498        return copyRet;
499      }
500      hilog.error(DOMAIN_CODE, TAG,
501        'copy directory failed with error message: ' + err.message + ', error code: ' + err.code);
502      return this.getReturnValue(
503        this.relativePath2uri(sourceFilePath), this.relativePath2uri(targetFilePath),
504        err.code, err.message, EXCEPTION);
505    }
506    return copyRet;
507  }
508
509  copy(sourceFileUri, targetParentUri, force): {[], number} {
510    sourceFileUri = decodeUri(sourceFileUri);
511    targetParentUri = decodeUri(targetParentUri);
512    let checkRet = this.checkCopyArguments(sourceFileUri, targetParentUri);
513    if (checkRet.code !== ERR_OK) {
514      return checkRet;
515    }
516
517    let sourceFilePath = getPath(sourceFileUri);
518    let targetFilePath = getPath(targetParentUri);
519    let displayName = this.getFileName(sourceFileUri);
520    let newFileOrDirUri = this.genNewFileUri(targetParentUri, displayName);
521    let newFilePath = getPath(newFileOrDirUri);
522
523    let stat = fs.statSync(sourceFilePath);
524    if (stat.isFile()) {
525      let isExist = fs.accessSync(newFilePath);
526      if (isExist && force === false) {
527        return this.getReturnValue(encodePathOfUri(sourceFileUri), encodePathOfUri(newFileOrDirUri), E_EXIST, '', NOEXCEPTION);
528      }
529      return this.copyFile(sourceFilePath, newFilePath);
530    } else if (stat.isDirectory()) {
531      let mode = force ? FILEOVERWRITE : THROWEXCEPTION;
532      let copyRet = this.copyDirectory(sourceFilePath, targetFilePath, mode);
533      return copyRet;
534    } else {
535      hilog.error(DOMAIN_CODE, TAG, 'the copy operation is not permitted');
536      return this.getReturnValue(sourceFileUri, targetParentUri, E_PERM, '', EXCEPTION);
537    }
538  }
539
540  copyFileByFileName(sourceFileUri, targetParentUri, fileName): {string, number } {
541    sourceFileUri = decodeUri(sourceFileUri);
542    targetParentUri = decodeUri(targetParentUri);
543    if (!checkUri(sourceFileUri) || !checkUri(targetParentUri)) {
544      return uriReturnObject('', E_URIS);
545    }
546
547    let displayName = this.getFileName(sourceFileUri);
548    let newFileUri = this.genNewFileUri(targetParentUri, displayName);
549    let newFilePath = getPath(newFileUri);
550    newFileUri = encodePathOfUri(newFileUri);
551
552    if (newFileUri === '') {
553      return uriReturnObject('', E_URIS);
554    }
555
556    try {
557      let sourceFilePath = getPath(sourceFileUri);
558      let isAccess = fs.accessSync(sourceFilePath);
559      if (!isAccess) {
560        hilog.error(DOMAIN_CODE, TAG, 'sourceFilePath is not exist');
561        return uriReturnObject('', E_GETRESULT);
562      }
563      let stat = fs.statSync(sourceFilePath);
564      if (!stat || stat.isDirectory()) {
565        hilog.error(DOMAIN_CODE, TAG, 'sourceFilePath is not file');
566        return uriReturnObject('', E_URIS);
567      }
568      let statNew = fs.statSync(getPath(targetParentUri));
569      if (!statNew || !statNew.isDirectory()) {
570        hilog.error(DOMAIN_CODE, TAG, 'targetParentUri is not directory');
571        return uriReturnObject('', E_GETRESULT);
572      }
573
574      let isAccessNewFilePath = fs.accessSync(newFilePath);
575      if (isAccessNewFilePath) {
576        newFileUri = this.genNewFileUri(targetParentUri, fileName);
577        newFilePath = getPath(newFileUri);
578        if (fs.accessSync(newFilePath)) {
579          hilog.error(DOMAIN_CODE, TAG, 'fileName is exist');
580          return uriReturnObject('', E_EXIST);
581        }
582      }
583      newFileUri = encodePathOfUri(newFileUri);
584      fs.copyFileSync(sourceFilePath, newFilePath);
585      return uriReturnObject(newFileUri, ERR_OK);
586    } catch (e) {
587      hilog.error(DOMAIN_CODE, TAG, 'copyFile error :' + e.message);
588      return uriReturnObject('', e.code);
589    }
590  }
591
592  access(sourceFileUri): {boolean, number} {
593    sourceFileUri = decodeUri(sourceFileUri);
594    if (sourceFileUri === '') {
595      return uriReturnObject('', E_URIS);
596    }
597    if (!checkUri(sourceFileUri)) {
598      hilog.error(DOMAIN_CODE, TAG, 'access checkUri fail');
599      return boolReturnObject(false, E_URIS);
600    }
601    let isAccess = false;
602    try {
603      let path = getPath(sourceFileUri);
604      isAccess = fs.accessSync(path);
605      if (!isAccess) {
606        return boolReturnObject(false, ERR_OK);
607      }
608    } catch (e) {
609      hilog.error(DOMAIN_CODE, TAG, 'access error ' + e.message);
610      return boolReturnObject(false, e.code);
611    }
612    return boolReturnObject(true, ERR_OK);
613  }
614
615  getFileInfoNum(sourceFileUri: string, filter: Filter, recursion: boolean) : {boolean, number} {
616    let path = getPath(sourceFileUri);
617    try {
618      let statPath = fs.statSync(path);
619      if (!statPath.isDirectory()) {
620        return {success: false, counts: 0};
621      }
622      let options;
623      if (hasFilter(filter)) {
624        options = buildFilterOptions(filter, 0, recursion);
625      } else {
626        options = buildNoFilterOptions(0, recursion);
627      }
628      let fileNameList = fs.listFileSync(path, options);
629      return {success: true, counts: fileNameList.length};
630    } catch (e) {
631      hilog.error(DOMAIN_CODE, TAG, `getFileInfoNum error: ${e.message},code: ${e.code}`);
632      return {success: false, counts: 0};
633    }
634  }
635
636  listFile(sourceFileUri: string, offset: number, count: number, filter: Filter) :
637  {infos: Fileinfo[], code: number} {
638    let infos : Fileinfo[] = [];
639    sourceFileUri = decodeUri(sourceFileUri);
640    if (!checkUri(sourceFileUri)) {
641      return infosReturnObject([], E_URIS);
642    }
643    return getListFileInfos(sourceFileUri, offset, count, filter, false);
644  }
645
646  scanFile(sourceFileUri: string, offset: number, count: number, filter: Filter) :
647  {infos: Fileinfo[], code: number} {
648    let infos : Fileinfo[] = [];
649    sourceFileUri = decodeUri(sourceFileUri);
650    if (!checkUri(sourceFileUri)) {
651      return infosReturnObject([], E_URIS);
652    }
653
654    return getScanFileInfos(sourceFileUri, offset, count, filter, true);
655  }
656
657  getFileInfoFromUri(selectFileUri) {
658    selectFileUri = decodeUri(selectFileUri);
659    if (selectFileUri === '') {
660      return uriReturnObject('', E_URIS);
661    }
662
663    if (!checkUri(selectFileUri)) {
664      return fileinfoReturnObject({}, E_URIS);
665    }
666    let fileInfo = {};
667    try {
668      let path = getPath(selectFileUri);
669      let fileName = this.getFileName(path);
670      let stat = fs.statSync(path);
671      let mode = documentFlag.SUPPORTS_READ | documentFlag.SUPPORTS_WRITE;
672      if (stat.isDirectory()) {
673        mode |= documentFlag.REPRESENTS_DIR;
674      } else {
675        mode |= documentFlag.REPRESENTS_FILE;
676      }
677      selectFileUri = encodePathOfUri(selectFileUri);
678      fileInfo = {
679        uri: selectFileUri,
680        relativePath: path,
681        fileName: fileName,
682        mode: mode,
683        size: stat.size,
684        mtime: stat.mtime,
685        mimeType: '',
686      };
687    } catch (e) {
688      hilog.error(DOMAIN_CODE, TAG, 'getFileInfoFromUri error ' + e.message);
689      return fileinfoReturnObject({}, e.code);
690    }
691    return fileinfoReturnObject(fileInfo, ERR_OK);
692  }
693
694  checkRelativePath(selectFileRelativePath): boolean {
695    try {
696      // Processing format: The first character is '/'
697      if (selectFileRelativePath !== undefined && selectFileRelativePath.indexOf('/') === 0) {
698        hilog.info(DOMAIN_CODE, TAG, 'checkRelativePath-path is ' + selectFileRelativePath);
699        return true;
700      } else {
701        hilog.error(DOMAIN_CODE, TAG, 'checkRelativePath error, path is ' + selectFileRelativePath);
702        return false;
703      }
704    } catch (error) {
705      hilog.error(DOMAIN_CODE, TAG, 'checkRelativePath error, path is ' + selectFileRelativePath);
706      return false;
707    }
708  }
709
710  /*
711   * selectFileRelativePath formate: /storage/Users/currentUser/filename
712   */
713  getFileInfoFromRelativePath(selectFileRelativePath): {fileInfo:object, code:number} {
714    let fileInfo = {};
715    if (!this.checkRelativePath(selectFileRelativePath)) {
716      return fileinfoReturnObject({}, E_INVAL);
717    }
718    try {
719      // Processing format: Delete the last '/'
720      if (selectFileRelativePath.charAt(selectFileRelativePath.length - 1) === '/') {
721        selectFileRelativePath = selectFileRelativePath.substr(0, selectFileRelativePath.length - 1);
722      }
723      let fileName = this.getFileName(selectFileRelativePath);
724      let stat = fs.statSync(selectFileRelativePath);
725      let mode = documentFlag.SUPPORTS_READ | documentFlag.SUPPORTS_WRITE;
726      if (stat.isDirectory()) {
727        mode |= documentFlag.REPRESENTS_DIR;
728      } else {
729        mode |= documentFlag.REPRESENTS_FILE;
730      }
731      let selectFileUri = encodePathOfUri(this.relativePath2uri(selectFileRelativePath));
732      fileInfo = {
733        uri: selectFileUri,
734        relativePath: selectFileRelativePath,
735        fileName: fileName,
736        mode: mode,
737        size: stat.size,
738        mtime: stat.mtime,
739        mimeType: '',
740      };
741    } catch (e) {
742      hilog.error(DOMAIN_CODE, TAG, 'getFileInfoFromRelativePath error ' + e.message);
743      return fileinfoReturnObject({}, e.code);
744    }
745    return fileinfoReturnObject(fileInfo, ERR_OK);
746  }
747
748  relativePath2uri(path): string {
749    return `file://docs${path}`;
750  }
751
752  volumePath2uri(path): string {
753    return `file://docs/storage/External/${path}`;
754  }
755
756  hmdfsPath2uri(path): string {
757    return `file://docs/storage/hmdfs/${path}`;
758  }
759
760  getHmdfsPath(): {}[] {
761    let rootPathHmdfs = '/storage/hmdfs';
762    let hmdfsInfoList = [];
763    let hmdfsName = fs.listFileSync(rootPathHmdfs);
764    for (let i = 0; i < hmdfsName.length; i++) {
765      let hmdfsInfo = {
766        uri: this.hmdfsPath2uri(hmdfsName[i]),
767        displayName: hmdfsName[i],
768        relativePath: '/storage/hmdfs/' + hmdfsName[i],
769        deviceType: deviceType.DEVICE_SHARED_TERMINAL,
770        deviceFlags: deviceFlag.SUPPORTS_READ | deviceFlag.SUPPORTS_WRITE,
771      };
772      hilog.info(DOMAIN_CODE, TAG, `df count: ${hmdfsInfo.length}`);
773      hmdfsInfoList.push(hmdfsInfo);
774    }
775    return hmdfsInfoList;
776  }
777
778  getRoots() {
779    let roots = [
780      {
781        uri: 'file://docs/storage/Users/currentUser',
782        displayName: 'currentUser',
783        relativePath: '/storage/Users/currentUser',
784        deviceType: deviceType.DEVICE_LOCAL_DISK,
785        deviceFlags: deviceFlag.SUPPORTS_READ | deviceFlag.SUPPORTS_WRITE,
786      },
787      {
788        uri: 'file://docs/storage/Share',
789        displayName: 'shared_disk',
790        relativePath: '/storage/Share',
791        deviceType: deviceType.DEVICE_SHARED_DISK,
792        deviceFlags: deviceFlag.SUPPORTS_READ | deviceFlag.SUPPORTS_WRITE,
793      }
794    ];
795    try {
796      let rootPath = '/storage/External';
797      let volumeInfoList = [];
798      let volumeName = fs.listFileSync(rootPath);
799      for (let i = 0; i < volumeName.length; i++) {
800        let volumeInfo = {
801          uri: this.volumePath2uri(volumeName[i]),
802          displayName: volumeName[i],
803          relativePath: '/storage/External/' + volumeName[i],
804          deviceType: deviceType.DEVICE_EXTERNAL_USB,
805          deviceFlags: deviceFlag.SUPPORTS_READ | deviceFlag.SUPPORTS_WRITE,
806        };
807        volumeInfoList.push(volumeInfo);
808      }
809      roots = roots.concat(volumeInfoList);
810      hilog.info(DOMAIN_CODE, TAG, `External file count: ${volumeInfoList.length}`);
811      try {
812        roots = roots.concat(getHmdfsPath());
813      } catch (e) {
814        hilog.info(DOMAIN_CODE, TAG, 'getRoots errorcode: ' + e.code, ' message: ' + e.message);
815      }
816
817      return rootsReturnObject(roots, ERR_OK);
818    } catch (e) {
819      hilog.error(DOMAIN_CODE, TAG, 'getRoots errorcode: ' + e.code, ' message: ' + e.message);
820      return rootsReturnObject([], e.code);
821    }
822  }
823
824  getNormalResult(dirPath, column, queryResults): void {
825    if (column === 'display_name') {
826      let index = dirPath.lastIndexOf('/');
827      let target = dirPath.substring(index + 1, );
828      queryResults.push(String(target));
829    } else if (column === 'relative_path') {
830      queryResults.push(dirPath);
831    } else {
832      queryResults.push('');
833    }
834  }
835
836  getResultFromStat(dirPath, column, stat, queryResults): void {
837    if (column === 'size' && stat.isDirectory()) {
838      let size = 0;
839      this.recurseDir(dirPath, function (filePath, isDirectory) {
840        if (!isDirectory) {
841          let fileStat = fs.statSync(filePath);
842          size += fileStat.size;
843        }
844      });
845      queryResults.push(String(size));
846    } else {
847      queryResults.push(String(stat[column]));
848    }
849  }
850
851  query(uri, columns): {[], number} {
852    uri = decodeUri(uri);
853    if (uri === '') {
854      return uriReturnObject('', E_URIS);
855    }
856
857    if (!checkUri(uri)) {
858      return resultsResultObject([], E_URIS);
859    }
860
861    fs.access(uri, (err, res) => {
862      if (err) {
863        return {
864          results: [],
865          code: E_NOEXIST,
866        };
867      } else {
868        if (res) {
869          console.info('file exists');
870        }
871      }
872    });
873
874    let queryResults = [];
875    try {
876      let dirPath = getPath(uri);
877      let stat = fs.statSync(dirPath);
878      for (let index in columns) {
879        let column = columns[index];
880        if (column in stat) {
881          this.getResultFromStat(dirPath, column, stat, queryResults);
882        } else {
883          this.getNormalResult(dirPath, column, queryResults);
884        }
885      }
886    } catch (e) {
887      hilog.error(DOMAIN_CODE, TAG, 'query error ' + e.message);
888      return resultsResultObject([], E_GETRESULT);
889    }
890    return resultsResultObject(queryResults, ERR_OK);
891  }
892
893  isDeviceUri(uri): boolean {
894    let tempUri = uri.slice(0, uri.lastIndexOf('/'));
895    let deviceUris = fileAccess.DeviceRoots;
896    if (deviceUris.indexOf(tempUri) !== -1) {
897      return true;
898    }
899    return false;
900  }
901
902  startWatcher(uri, callback): number {
903    uri = decodeUri(uri);
904    if (!checkUri(uri)) {
905      return E_URIS;
906    }
907    let watchPath = getPath(uri);
908    try {
909      if (!observerMap.has(uri)) {
910        let watcher = fs.createWatcher(watchPath, CREATE_EVENT_CODE | IN_DELETE_EVENT_CODE | DELETE_SELF_EVENT_CODE |
911          MOVE_TO_CODE | MOVED_FROM_CODE | MOVE_SELF_CODE, (data) => {
912          try {
913            let eventCode = -1;
914            let targetUri = FILE_PREFIX_NAME + BUNDLE_NAME + data.fileName;
915            let tempMap = eventMap;
916            if (this.isDeviceUri(targetUri)) {
917              tempMap = deviceOnlineMap;
918            }
919            tempMap.forEach((value, key) => {
920              if (data.event & key) {
921                eventCode = value;
922              }
923            });
924            targetUri = encodePathOfUri(targetUri);
925            if (eventCode >= 0) {
926              callback(targetUri, eventCode);
927            }
928          } catch (error) {
929            hilog.error(DOMAIN_CODE, TAG, 'onchange error ' + error.message);
930          }
931        });
932        watcher.start();
933        observerMap.set(uri, watcher);
934      } else {
935        hilog.warn(DOMAIN_CODE, TAG, 'uri already exists');
936      }
937    } catch (e) {
938      hilog.error(DOMAIN_CODE, TAG, 'startWatcher error ' + e.message);
939      return E_GETRESULT;
940    }
941    return ERR_OK;
942  }
943
944  stopWatcher(uri): number {
945    uri = decodeUri(uri);
946    if (!checkUri(uri)) {
947      return E_URIS;
948    }
949    try {
950      if (!observerMap.has(uri)) {
951        return E_GETRESULT;
952      }
953      let watcher = observerMap.get(uri);
954      if (typeof watcher !== undefined) {
955        watcher.stop();
956        observerMap.delete(uri);
957      }
958    } catch (e) {
959      hilog.error(DOMAIN_CODE, TAG, 'stopWatcher error ' + e.message);
960      return E_GETRESULT;
961    }
962    return ERR_OK;
963  }
964
965  moveForFile(sourceFilePath, newFilePath): { [], number } {
966    let copyRet = {
967      results: [],
968      code: ERR_OK,
969    };
970
971    try {
972      let isExist = fs.accessSync(newFilePath);
973      if (isExist) {
974        fs.unlinkSync(newFilePath);
975      }
976      fs.moveFileSync(sourceFilePath, newFilePath, 1);
977    } catch (err) {
978      hilog.error(DOMAIN_CODE, TAG, 'moveFileSync failed with error message: ' + err.message + ', error code: ' + err.code);
979      return this.getReturnValue(encodePathOfUri(this.relativePath2uri(sourceFilePath)), '', err.code, err.message, NOEXCEPTION);
980    }
981    return copyRet;
982  }
983
984  moveDirectory(sourceFilePath, targetFilePath, force): { [], number } {
985    let copyRet = {
986      results: [],
987      code: ERR_OK,
988    };
989    let mode = force ? MOVEFILEOVERWRITE : FILEOVERWRITE;
990    try {
991      fs.moveDirSync(sourceFilePath, targetFilePath, mode);
992    } catch (err) {
993      if (err.code === E_EXIST) {
994        for (let i = 0; i < err.data.length; i++) {
995          hilog.error(DOMAIN_CODE, TAG,
996            'move directory failed with conflicting files: ' + err.data[i].srcFile + ' ' + err.data[i].destFile);
997          let srcStat = fs.statSync(err.data[i].srcFile);
998          let dstStat = fs.statSync(err.data[i].destFile);
999          let errCode = undefined;
1000          if (srcStat.isDirectory() && dstStat.isFile()) {
1001            errCode = E_NOT_DIR;
1002          } else if (srcStat.isFile() && dstStat.isDirectory()) {
1003            errCode = E_IS_DIR;
1004          } else {
1005            errCode = err.code;
1006          }
1007          let ret = this.getReturnValue(
1008            encodePathOfUri(this.relativePath2uri(err.data[i].srcFile)),
1009            encodePathOfUri(this.relativePath2uri(err.data[i].destFile)),
1010            errCode, err.message, NOEXCEPTION);
1011          this.processReturnValue(ret, copyRet);
1012        }
1013        return copyRet;
1014      }
1015      return this.getReturnValue(
1016        this.relativePath2uri(sourceFilePath), this.relativePath2uri(targetFilePath),
1017        err.code, err.message, EXCEPTION);
1018    }
1019    return copyRet;
1020  }
1021
1022  moveItem(sourceFileUri, targetParentUri, force): { [], number } {
1023    sourceFileUri = decodeUri(sourceFileUri);
1024    targetParentUri = decodeUri(targetParentUri);
1025    if (!checkUri(sourceFileUri) || !checkUri(targetParentUri)) {
1026      hilog.error(DOMAIN_CODE, TAG, 'check arguments error, invalid arguments');
1027      return this.getReturnValue(sourceFileUri, targetParentUri, E_URIS, EXCEPTION);
1028    }
1029    let displayName = this.getFileName(sourceFileUri);
1030    let newFileUri = this.genNewFileUri(targetParentUri, displayName);
1031    let newPathDir = getPath(targetParentUri);
1032    let oldPath = getPath(sourceFileUri);
1033    let newPath = getPath(newFileUri);
1034    newFileUri = encodePathOfUri(newFileUri);
1035    if (newFileUri === '') {
1036      return this.getReturnValue(sourceFileUri, targetParentUri, E_URIS, EXCEPTION);
1037    }
1038    if (oldPath === newPath) {
1039      return this.getReturnValue(sourceFileUri, newFileOrDirUri, ERR_OK, '', EXCEPTION);
1040    } else if (newPath.indexOf(oldPath) === 0 && newPath.charAt(oldPath.length) === '/') {
1041      return this.getReturnValue(sourceFileUri, targetParentUri, E_GETRESULT, '', NOEXCEPTION);
1042    }
1043    try {
1044      let stat = fs.statSync(getPath(targetParentUri));
1045      let statOld = fs.statSync(oldPath);
1046      if (!fs.accessSync(oldPath) || !stat || !stat.isDirectory() || !statOld) {
1047        hilog.error(DOMAIN_CODE, TAG, 'operate illegal');
1048        return this.getReturnValue(sourceFileUri, targetParentUri, E_GETRESULT, '', EXCEPTION);
1049      }
1050      if (statOld.isFile()) {
1051        hilog.info(DOMAIN_CODE, TAG, 'sourceUri is file');
1052        let isExist = fs.accessSync(newPath);
1053        if (isExist && fs.statSync(newPath).isDirectory()) {
1054          return this.getReturnValue(sourceFileUri, newFileUri, E_IS_DIR, '', NOEXCEPTION);
1055        }
1056        if (isExist && force === false) {
1057          return this.getReturnValue(sourceFileUri, newFileUri, E_EXIST, '', NOEXCEPTION);
1058        } else {
1059          return this.moveForFile(oldPath, newPath);
1060        }
1061      } else if (statOld.isDirectory()) {
1062        hilog.info(DOMAIN_CODE, TAG, 'sourceUri is dir');
1063        return this.moveDirectory(oldPath, newPathDir, force);
1064      } else {
1065        hilog.error(DOMAIN_CODE, TAG, 'the move operation is not permitted');
1066        return this.getReturnValue(sourceFileUri, targetParentUri, E_PERM, '', EXCEPTION);
1067      }
1068    } catch (err) {
1069      hilog.error(DOMAIN_CODE, TAG, 'error message: ' + err.message + ', error code: ' + err.code);
1070      return this.getReturnValue(sourceFileUri, targetParentUri, err.code, err.message, EXCEPTION);
1071    }
1072  }
1073
1074  moveFile(sourceFileUri, targetParentUri, fileName): { string, number } {
1075    sourceFileUri = decodeUri(sourceFileUri);
1076    targetParentUri = decodeUri(targetParentUri);
1077    if (!checkUri(sourceFileUri) || !checkUri(targetParentUri)) {
1078      return uriReturnObject('', E_URIS);
1079    }
1080    let displayName = this.getFileName(sourceFileUri);
1081    let newFileUri = this.genNewFileUri(targetParentUri, displayName);
1082    let fixedUri = this.genNewFileUri(targetParentUri, fileName);
1083    let oldPath = getPath(sourceFileUri);
1084    let newPath = getPath(newFileUri);
1085    let fixedPath = getPath(fixedUri);
1086    fixedUri = encodePathOfUri(fixedUri);
1087    newFileUri = encodePathOfUri(newFileUri);
1088    if (newFileUri === '') {
1089      return uriReturnObject('', E_URIS);
1090    }
1091    if (oldPath === newPath) {
1092      // move to the same directory
1093      return {
1094        uri: newFileUri,
1095        code: ERR_OK,
1096      };
1097    }
1098    try {
1099      // The source file does not exist or the destination is not a directory
1100      let isAccess = fs.accessSync(oldPath);
1101      let stat = fs.statSync(getPath(targetParentUri));
1102      let statOld = fs.statSync(oldPath);
1103      if (!isAccess || !stat || !stat.isDirectory() || !statOld) {
1104        return uriReturnObject('', E_GETRESULT);
1105      }
1106      // isDir
1107      if (statOld.isDirectory()) {
1108        return uriReturnObject('', E_URIS);
1109      }
1110
1111      let isAccessNewPath = fs.accessSync(newPath);
1112      if (isAccessNewPath) {
1113        if (fs.accessSync(fixedPath)) {
1114          hilog.error(DOMAIN_CODE, TAG, 'fileName is exist');
1115          return uriReturnObject('', E_EXIST);
1116        }
1117        fs.moveFileSync(oldPath, fixedPath, 0);
1118        return uriReturnObject(fixedUri, ERR_OK);
1119      }
1120      fs.moveFileSync(oldPath, newPath, 0);
1121      return uriReturnObject(newFileUri, ERR_OK);
1122    } catch (e) {
1123      hilog.error(DOMAIN_CODE, TAG, 'move error ' + e.message);
1124      return uriReturnObject('', e.code);
1125    }
1126  }
1127};
1128