• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 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 */
15import hilog from '@ohos.hilog';
16import fs from '@ohos.file.fs';
17import type { Filter } from '@ohos.file.fs';
18import fileExtensionInfo from '@ohos.file.fileExtensionInfo';
19import type { Fileinfo } from './Common';
20import { getPath, uriReturnObject, encodePathOfUri, DOMAIN_CODE, TAG, infosReturnObject } from './Common';
21
22const documentFlag = fileExtensionInfo.DocumentFlag;
23const ERR_OK = 0;
24const E_GETRESULT = 14300004;
25const APP_DATA = 'appdata';
26const BACKUP_DIR = '.backup';
27const CURRENT_USER_PATH = '/storage/Users/currentUser';
28
29function hasFilter(filter: Filter) : boolean {
30  if (filter === null) {
31    return false;
32  }
33  let displayNameArray = filter.displayName;
34  if (displayNameArray !== null && displayNameArray.length > 0) {
35    return true;
36  }
37  let suffixArray = filter.suffix;
38  if (suffixArray !== null && suffixArray.length > 0) {
39    return true;
40  }
41  let lastModifiedAfter = filter.lastModifiedAfter;
42  if (lastModifiedAfter !== null && lastModifiedAfter >= 0) {
43    return true;
44  }
45  let fileSizeOver = filter.fileSizeOver;
46  if (fileSizeOver !== null && fileSizeOver >= 0) {
47    return true;
48  }
49  return false;
50}
51
52function buildDisplayName(displayNameArray: string[]) : string[] {
53  let displayNames : string[] = [];
54  for (let i = 0; i < displayNameArray.length; i++) {
55    if (displayNameArray[i].lastIndexOf('*') === -1) {
56      let name = '*' + displayNameArray[i];
57      displayNames.push(name);
58    } else {
59      displayNames.push(displayNameArray[i]);
60    }
61  }
62  return displayNames;
63}
64
65function buildFilterOptions(filter: Filter, listNum: number, recursion: boolean) :
66{recursion: boolean, listNum: number, filter: Filter} {
67  let optionFilter: Filter = {};
68  if (filter !== null) {
69    let suffixArray = filter.suffix;
70    if (suffixArray !== null && suffixArray.length > 0) {
71      optionFilter.suffix = suffixArray;
72    }
73    let displayNameArray = filter.displayName;
74    if (displayNameArray !== null && displayNameArray.length > 0) {
75      optionFilter.displayName = buildDisplayName(displayNameArray);
76    }
77    let fileSizeOver = filter.fileSizeOver;
78    if (fileSizeOver !== null && fileSizeOver >= 0) {
79      optionFilter.fileSizeOver = fileSizeOver;
80    }
81    let lastModifiedAfter = filter.lastModifiedAfter;
82    if (lastModifiedAfter !== null && lastModifiedAfter >= 0) {
83      optionFilter.lastModifiedAfter = lastModifiedAfter;
84    }
85    let mimeType = filter.mimeType;
86    if (mimeType !== null && mimeType.length > 0) {
87      hilog.error(DOMAIN_CODE, TAG, 'mimeType is not supported as a filter condition');
88    }
89    let excludeMedia = filter.excludeMedia;
90    if (excludeMedia !== null && excludeMedia === true) {
91      hilog.error(DOMAIN_CODE, TAG, 'excludeMedia is not supported as a filter condition');
92    }
93  }
94  let options = {
95    'recursion': recursion,
96    'listNum': listNum,
97    'filter': optionFilter,
98  };
99  return options;
100}
101
102function buildNoFilterOptions(listNum: number, recursion: boolean) : {recursion: boolean, listNum: number} {
103  let options = {
104    'recursion': recursion,
105    'listNum': listNum,
106  };
107  return options;
108}
109
110function getNewPathOrUri(prefixSection: string, filename: string) : string {
111  let completeResult = prefixSection;
112  if (completeResult.endsWith('/')) {
113    if (filename.startsWith('/')) {
114      filename = filename.substring(1, filename.length);
115    }
116    completeResult += filename;
117  } else {
118    if (!filename.startsWith('/')) {
119      completeResult += '/';
120    }
121    completeResult += filename;
122  }
123  return completeResult;
124}
125
126function genNewFileName(filename: string): string {
127  let newFilename = filename;
128  let index = newFilename.lastIndexOf('/');
129  if (index !== -1) {
130    newFilename = newFilename.substring(index + 1, newFilename.length);
131  }
132  return newFilename;
133}
134
135function getListFileInfos(sourceFileUri: string, offset: number, count: number, filter: Filter, recursion: boolean) :
136{infos: Fileinfo[], code: number} {
137  let infos : Fileinfo[] = [];
138  let path = getPath(sourceFileUri);
139  try {
140    let statPath = fs.statSync(path);
141    if (!statPath.isDirectory()) {
142      return infosReturnObject([], E_GETRESULT);
143    }
144    let options;
145    let listNum = offset + count;
146    if (hasFilter(filter)) {
147      options = buildFilterOptions(filter, listNum, recursion);
148    } else {
149      options = buildNoFilterOptions(listNum, recursion);
150    }
151    let fileNameList = fs.listFileSync(path, options);
152    for (let i = offset; i < fileNameList.length; i++) {
153      if (i === listNum) {
154        break;
155      }
156      if (path === CURRENT_USER_PATH && (fileNameList[i] === APP_DATA || fileNameList[i] === BACKUP_DIR)) {
157        hilog.info(DOMAIN_CODE, TAG, `filter appdata doc or backup dir`);
158        continue;
159      }
160      let mode = documentFlag.SUPPORTS_READ | documentFlag.SUPPORTS_WRITE;
161      let filePath = getNewPathOrUri(path, fileNameList[i]);
162      let stat = fs.statSync(filePath);
163      if (stat.isDirectory()) {
164        mode |= documentFlag.REPRESENTS_DIR;
165      } else {
166        mode |= documentFlag.REPRESENTS_FILE;
167      }
168      let newFileUri = getNewPathOrUri(sourceFileUri, fileNameList[i]);
169      newFileUri = encodePathOfUri(newFileUri);
170      infos.push({ uri: newFileUri, relativePath: filePath, fileName: genNewFileName(fileNameList[i]),
171        mode: mode, size: stat.size, mtime: stat.mtime, mimeType: '' });
172    }
173  } catch (e) {
174    hilog.error(DOMAIN_CODE, TAG, `getFileInfos error: ${e.message},code: ${e.code}`);
175    return infosReturnObject([], E_GETRESULT);
176  }
177  return infosReturnObject(infos, ERR_OK);
178}
179
180function getSubUriList(path: string, listNum: number, filter: Filter) : string[]
181{
182  let dirOptions = {
183    'recursion': false
184  };
185  let fileOption = hasFilter(filter) ?
186      buildFilterOptions(filter, listNum, false) : buildNoFilterOptions(listNum, false);
187  let dirTmpResult = fs.listFileSync(path, dirOptions).filter(item => item !== APP_DATA).map(function(item) {
188    return CURRENT_USER_PATH + '/' + item;
189  });
190  let fileResult = fs.listFileSync(path, fileOption).filter(item => item !== APP_DATA).map(function(item) {
191    return CURRENT_USER_PATH + '/' + item;
192  });
193  let dirResult : string[] = [];
194  for (let i = 0; i < dirTmpResult.length; ++i) {
195    if (fs.statSync(dirTmpResult[i]).isDirectory()) {
196      dirResult.push(dirTmpResult[i]);
197    }
198  }
199  return Array.from(new Set(fileResult.concat(dirResult)));
200}
201
202function getSubFileInfos(
203  changeData: {
204    options: {recursion: boolean, listNum: number, filter?: Filter},
205    tempOffset: number,
206    listNumCnt: number
207  }, needInfo: {subPath: string, count: number, isRootPath: boolean, sourceFileUri: string}): Fileinfo[] {
208  let infos: Fileinfo[] = [];
209  let tmpStat = fs.statSync(needInfo.subPath);
210  let bIsDct = tmpStat.isDirectory();
211  let fileNameList = bIsDct ? fs.listFileSync(needInfo.subPath, changeData.options) :
212      [needInfo.subPath.substring(CURRENT_USER_PATH.length)];
213  let subPath = needInfo.subPath;
214  if (needInfo.isRootPath) {
215    subPath = bIsDct ? subPath.substring(CURRENT_USER_PATH.length) : '';
216  }
217  let listLen = fileNameList.length;
218  if (changeData.tempOffset >= listLen) {
219    changeData.tempOffset -= listLen;
220    return infos;
221  }
222  for (let j = changeData.tempOffset; j < fileNameList.length; ++j, ++changeData.listNumCnt) {
223    if (changeData.listNumCnt === needInfo.count) {
224      break;
225    }
226    let mode = documentFlag.SUPPORTS_READ | documentFlag.SUPPORTS_WRITE;
227    let filePath = getNewPathOrUri(needInfo.subPath, fileNameList[j]);
228    let stat = bIsDct ? fs.statSync(filePath) : tmpStat;
229    mode |= (bIsDct | stat.isDirectory()) ? documentFlag.REPRESENTS_DIR : documentFlag.REPRESENTS_FILE;
230    let newFileUri = getNewPathOrUri(
231      needInfo.isRootPath ? needInfo.sourceFileUri + subPath : needInfo.sourceFileUri, fileNameList[j]);
232    newFileUri = encodePathOfUri(newFileUri);
233    infos.push({ uri: newFileUri, relativePath: filePath, fileName: genNewFileName(fileNameList[j]),
234      mode: mode, size: stat.size, mtime: stat.mtime, mimeType: '' });
235  }
236  changeData.tempOffset = 0;
237  changeData.options.listNum = needInfo.count - changeData.listNumCnt;
238  return infos;
239}
240
241function getScanFileInfos(sourceFileUri: string, offset: number, count: number, filter: Filter, recursion: boolean) :
242{infos: Fileinfo[], code: number} {
243  let infos : Fileinfo[] = [];
244  let path = getPath(sourceFileUri);
245  try {
246    let statPath = fs.statSync(path);
247    if (!statPath.isDirectory()) {
248      return infosReturnObject([], E_GETRESULT);
249    }
250    let listNum = offset + count;
251    let isRootPath = (path === CURRENT_USER_PATH);
252    let listInfo = (isRootPath) ? getSubUriList(path, listNum, filter) : [path];
253    let changeData = {
254      options: hasFilter(filter) ?
255        buildFilterOptions(filter, listNum, recursion) : buildNoFilterOptions(listNum, recursion),
256      tempOffset: offset,
257      listNumCnt: 0
258    };
259    for (let i = 0; i < listInfo.length; ++i) {
260      const needInfo = {
261        subPath: listInfo[i],
262        count: count,
263        isRootPath: isRootPath,
264        sourceFileUri: sourceFileUri
265      };
266      let subFileRes = getSubFileInfos(changeData, needInfo);
267      infos.push(...subFileRes);
268      if (changeData.options.listNum <= 0) {
269        break;
270      }
271    }
272  } catch (e) {
273    hilog.error(DOMAIN_CODE, TAG, `getFileInfos error: ${e.message},code: ${e.code}`);
274    return infosReturnObject([], E_GETRESULT);
275  }
276  return infosReturnObject(infos, ERR_OK);
277}
278export { getListFileInfos, getScanFileInfos, buildFilterOptions, buildNoFilterOptions, hasFilter };
279