1 /* 2 * Copyright (c) 2021 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 package ohos; 17 18 import java.io.BufferedInputStream; 19 import java.io.BufferedOutputStream; 20 import java.io.BufferedReader; 21 import java.io.Closeable; 22 import java.io.File; 23 import java.io.FileInputStream; 24 import java.io.FileOutputStream; 25 import java.io.FileNotFoundException; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.security.NoSuchAlgorithmException; 31 import java.util.ArrayList; 32 import java.util.Enumeration; 33 import java.util.HashMap; 34 import java.util.Optional; 35 import java.util.regex.Pattern; 36 import java.util.zip.ZipEntry; 37 import java.util.zip.ZipFile; 38 import java.util.zip.ZipInputStream; 39 import java.security.MessageDigest; 40 41 /** 42 * file tools 43 * 44 */ 45 class FileUtils { 46 private static final int BUFFER_SIZE = 1024; 47 private static final int SHA256_BUFFER_SIZE = 10240; 48 private static final Log LOG = new Log(FileUtils.class.toString()); 49 private static final String RESOURCE_PATH = "resources/base/profile/"; 50 private static final String SHA256 = "SHA-256"; 51 private static final String PATTERN = "[0-9A-Za-z/].{0,4095}"; 52 53 /** 54 * generate fileData byte stream 55 * 56 * @param filePath file path 57 * @return byte array 58 */ getFileData(final String filePath)59 public static byte[] getFileData(final String filePath) { 60 File file = new File(filePath); 61 long fileSize = file.length(); 62 byte[] buffer = new byte[(int) fileSize]; 63 if (fileSize > Integer.MAX_VALUE) { 64 LOG.error("file too big."); 65 return buffer; 66 } 67 FileInputStream fi = null; 68 try { 69 fi = new FileInputStream(file); 70 int offset = 0; 71 int numRead = 0; 72 while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) { 73 offset += numRead; 74 } 75 } catch (IOException exception) { 76 LOG.error("getFileData IOException error: " + exception.getMessage()); 77 return new byte[(int) fileSize]; 78 } finally { 79 closeStream(fi); 80 } 81 return buffer; 82 } 83 84 /** 85 * search filePath for special fileName 86 * 87 * @param fileName file name 88 * @param directory dir path 89 * @return filePath 90 */ searchFile(final String fileName, final String directory)91 public static Optional<String> searchFile(final String fileName, final String directory) { 92 ArrayList<String> fileList = new ArrayList<>(); 93 getFileList(directory, fileList); 94 for (String fileItem : fileList) { 95 if (fileItem.endsWith(fileName)) { 96 return Optional.ofNullable(fileItem); 97 } 98 } 99 return Optional.empty(); 100 } 101 102 /** 103 * get file list in filePath 104 * 105 * @param filePath file path 106 * @param fileList file path in arrayList 107 */ getFileList(final String filePath, ArrayList<String> fileList)108 public static void getFileList(final String filePath, ArrayList<String> fileList) { 109 File file = new File(filePath); 110 if (!file.exists()) { 111 LOG.error("getFileList: file is not exists."); 112 return; 113 } 114 File[] files = file.listFiles(); 115 if (files == null) { 116 LOG.error("getFileList: no file in this file path."); 117 return; 118 } 119 for (File f : files) { 120 try { 121 if (f.isFile()) { 122 fileList.add(f.getCanonicalPath()); 123 } else if (f.isDirectory()) { 124 getFileList(f.getCanonicalPath(), fileList); 125 } else { 126 LOG.error("It's not file or directory."); 127 } 128 } catch (IOException msg) { 129 LOG.error("IOException error: " + msg.getMessage()); 130 return; 131 } 132 } 133 } 134 135 /** 136 * get string from file 137 * 138 * @param filePath file path 139 * @return String for file 140 */ getFileContent(final String filePath)141 public static Optional<String> getFileContent(final String filePath) { 142 if (filePath.isEmpty()) { 143 return Optional.empty(); 144 } 145 BufferedReader reader = null; 146 FileInputStream fileInputStream = null; 147 InputStreamReader inputStreamReader = null; 148 StringBuilder content = new StringBuilder(); 149 try { 150 fileInputStream = new FileInputStream(filePath); 151 inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); 152 reader = new BufferedReader(inputStreamReader); 153 String tempString; 154 while ((tempString = reader.readLine()) != null) { 155 content.append(tempString); 156 } 157 } catch (IOException msg) { 158 LOG.error(PackingToolErrMsg.GET_FILE_CONTENT_FAILED.toString( 159 "IOException: " + msg.getMessage())); 160 return Optional.empty(); 161 } finally { 162 closeStream(reader); 163 closeStream(inputStreamReader); 164 closeStream(fileInputStream); 165 } 166 return Optional.ofNullable(content.toString()); 167 } 168 169 /** 170 * close file stream 171 * 172 * @param fileStream file stream 173 */ closeStream(Closeable fileStream)174 public static void closeStream(Closeable fileStream) { 175 try { 176 if (fileStream != null) { 177 fileStream.close(); 178 } 179 } catch (IOException msg) { 180 LOG.error(PackingToolErrMsg.CLOSE_STREAM_EXCEPTION.toString( 181 "Close stream exist IOException: " + msg.getMessage())); 182 } 183 } 184 185 /** 186 * delete file 187 * 188 * @param path file path which will be deleted 189 */ deleteFile(final String path)190 public static void deleteFile(final String path) { 191 File file = new File(path); 192 if (file.exists()) { 193 file.delete(); 194 } 195 } 196 197 /** 198 * unzip hap package to path 199 * 200 * @param hapPath zip file 201 * @param destDir path after unzip file 202 */ unzip(final String hapPath, final String destDir)203 public static void unzip(final String hapPath, final String destDir) { 204 File file = new File(destDir); 205 if (!file.exists()) { 206 file.mkdirs(); 207 } 208 209 ZipFile zipFile = null; 210 BufferedInputStream bis = null; 211 BufferedOutputStream bos = null; 212 FileOutputStream fos = null; 213 try { 214 zipFile = new ZipFile(hapPath); 215 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 216 int entriesNum = 0; 217 while (entries.hasMoreElements()) { 218 entriesNum++; 219 ZipEntry entry = entries.nextElement(); 220 if (entry == null) { 221 continue; 222 } 223 String filePath = destDir + File.separator + entry.getName(); 224 if (!matchPattern(filePath)) { 225 LOG.error("Input invalid file: " + filePath); 226 throw new BundleException("Input invalid file " + filePath); 227 } 228 if (entry.isDirectory()) { 229 new File(filePath).mkdirs(); 230 continue; 231 } 232 233 bis = new BufferedInputStream(zipFile.getInputStream(entry)); 234 File newFile = new File(filePath); 235 File parent = newFile.getParentFile(); 236 if (parent != null && (!parent.exists())) { 237 parent.mkdirs(); 238 } 239 240 fos = new FileOutputStream(newFile); 241 bos = new BufferedOutputStream(fos, BUFFER_SIZE); 242 243 int count; 244 int total = 0; 245 byte[] data = new byte[BUFFER_SIZE]; 246 while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1) { 247 bos.write(data, 0, count); 248 total += count; 249 } 250 251 bos.flush(); 252 bos.close(); 253 fos.close(); 254 bis.close(); 255 } 256 } catch (IOException | BundleException exception) { 257 LOG.error("unzip file failed " + exception.getMessage()); 258 } finally { 259 closeStream(bos); 260 closeStream(fos); 261 closeStream(bis); 262 closeStream(zipFile); 263 } 264 } 265 266 /** 267 * delete directory 268 * 269 * @param directory dir path which will be deleted 270 */ deleteDirectory(final String directory)271 public static void deleteDirectory(final String directory) { 272 File dir = new File(directory); 273 if (!dir.exists()) { 274 return; 275 } 276 277 File[] fileList = dir.listFiles(); 278 if (fileList == null) { 279 return; 280 } 281 for (File file : fileList) { 282 try { 283 if (file.isFile()) { 284 file.delete(); 285 } else if (file.isDirectory()) { 286 deleteDirectory(file.getCanonicalPath()); 287 } else { 288 LOG.error("It's not file or directory."); 289 } 290 } catch (IOException msg) { 291 LOG.error("deleteDirectory IOException : " + msg.getMessage()); 292 } 293 } 294 dir.delete(); 295 } 296 297 /** 298 * format filepath 299 * 300 * @param filePath file path which is need to format 301 * @return canonicalPath for filePath 302 */ getFormatedPath(final String filePath)303 public static Optional<String> getFormatedPath(final String filePath) { 304 String absPath; 305 try { 306 File file = new File(filePath); 307 absPath = file.getCanonicalPath(); 308 } catch (IOException msg) { 309 LOG.error("format path IOException : " + msg.getMessage()); 310 return Optional.empty(); 311 } 312 return Optional.of(absPath); 313 } 314 315 /** 316 * check file whether is exist or not 317 * 318 * @param filePath bin file path 319 * @return true: file is exist, false: file is not exist 320 */ checkFileIsExists(final String filePath)321 public static boolean checkFileIsExists(final String filePath) { 322 if (filePath.isEmpty()) { 323 return false; 324 } 325 326 Optional<String> absFilePath = getFormatedPath(filePath); 327 if (!absFilePath.isPresent()) { 328 return false; 329 } 330 331 File file = new File(absFilePath.get()); 332 if (!file.exists()) { 333 return false; 334 } 335 return true; 336 } 337 338 /** 339 * copy a file to another place. 340 * 341 * @param sourceFile is the source file 342 * @param destFile is the destination file 343 * @throws IOException FileNotFoundException|IOException. 344 */ copyFile(File sourceFile, File destFile)345 public static void copyFile(File sourceFile, File destFile) throws IOException, BundleException { 346 if (sourceFile == null || destFile == null) { 347 String errMsg = "Source file or destination file is null."; 348 LOG.error(PackingToolErrMsg.COPY_FILE_FAILED.toString(errMsg)); 349 throw new BundleException(errMsg); 350 } 351 InputStream inputStream = null; 352 OutputStream outputStream = null; 353 try { 354 inputStream = new FileInputStream(sourceFile); 355 outputStream = new FileOutputStream(destFile); 356 byte[] buffer = new byte[BUFFER_SIZE]; 357 int length; 358 while ((length = inputStream.read(buffer)) > 0) { 359 outputStream.write(buffer, 0, length); 360 } 361 } finally { 362 Utility.closeStream(inputStream); 363 Utility.closeStream(outputStream); 364 } 365 } 366 367 /** 368 * make a directory if not exist. 369 * 370 * @param dirFile is the directory file 371 * @throws IOException FileNotFoundException|IOException. 372 */ makeDir(File dirFile)373 public static void makeDir(File dirFile) throws IOException, BundleException { 374 if (dirFile == null) { 375 String errMsg = "Input file is null."; 376 LOG.error(PackingToolErrMsg.MAKE_DIR_FAILED.toString(errMsg)); 377 throw new BundleException(errMsg); 378 } 379 dirFile.mkdirs(); 380 } 381 382 /** 383 * check json type code in haps. 384 * 385 * @param srcFile source file to zip 386 * @return true is for successful and false is for failed 387 * @throws BundleException FileNotFoundException|IOException. 388 */ getJsonInZips(File srcFile, String jsonName)389 public static String getJsonInZips(File srcFile, String jsonName) throws BundleException { 390 String fileStr = srcFile.getPath(); 391 ZipFile zipFile = null; 392 FileInputStream zipInput = null; 393 ZipInputStream zin = null; 394 InputStream inputStream = null; 395 InputStreamReader reader = null; 396 BufferedReader br = null; 397 ZipEntry entry = null; 398 StringBuilder jsonStr = new StringBuilder(); 399 try { 400 zipFile = new ZipFile(srcFile); 401 zipInput = new FileInputStream(fileStr); 402 zin = new ZipInputStream(zipInput); 403 while ((entry = zin.getNextEntry()) != null) { 404 if (entry.getName().toLowerCase().equals(jsonName)) { 405 inputStream = zipFile.getInputStream(entry); 406 reader = new InputStreamReader(inputStream); 407 br = new BufferedReader(reader); 408 String line; 409 while ((line = br.readLine()) != null) { 410 jsonStr.append(line); 411 } 412 inputStream.close(); 413 } 414 } 415 jsonStr = new StringBuilder(jsonStr.toString().replaceAll("\r|\n|\t", "")); 416 } catch (IOException exception) { 417 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 418 "Get Json in zips exist IOException: " + exception.getMessage())); 419 throw new BundleException("Compressor::checkModuleTypeInHaps failed."); 420 } finally { 421 Utility.closeStream(zipFile); 422 Utility.closeStream(zipInput); 423 Utility.closeStream(zin); 424 Utility.closeStream(inputStream); 425 Utility.closeStream(reader); 426 Utility.closeStream(br); 427 } 428 return jsonStr.toString(); 429 } 430 431 /** 432 * get all resource file in profile. 433 * 434 * @param zipFile is the hap file 435 * @throws BundleException when get profile json file failed 436 */ getProfileJson(ZipFile zipFile)437 static HashMap<String, String> getProfileJson(ZipFile zipFile) throws BundleException { 438 HashMap<String, String> resourceMap = new HashMap<>(); 439 try { 440 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 441 while (entries.hasMoreElements()) { 442 final ZipEntry entry = entries.nextElement(); 443 if (entry.getName().contains(RESOURCE_PATH)) { 444 String filePath = entry.getName(); 445 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 446 String fileContent = getFileStringFromZip(filePath, zipFile); 447 resourceMap.put(fileName, fileContent); 448 } 449 } 450 } catch (IOException e) { 451 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString( 452 "Get profile json exist IOException: " + e.getMessage())); 453 throw new BundleException("Get profile json failed."); 454 } 455 return resourceMap; 456 } 457 458 /** 459 * get file content in string from zip 460 * 461 * @param fileName is the file name we want to read 462 * @param zipFile is the zip file 463 */ getFileStringFromZip(String fileName, ZipFile zipFile)464 public static String getFileStringFromZip(String fileName, ZipFile zipFile) 465 throws IOException { 466 ZipEntry entry = zipFile.getEntry(fileName); 467 if (entry == null) { 468 LOG.debug("Uncompress::readStringFromFile " + fileName + " not found exception."); 469 return ""; 470 } 471 InputStream fileInputStream = null; 472 BufferedReader bufferedReader = null; 473 try { 474 fileInputStream = zipFile.getInputStream(entry); 475 bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8")); 476 String line; 477 StringBuilder sb = new StringBuilder(); 478 while ((line = bufferedReader.readLine()) != null) { 479 sb.append(line); 480 } 481 return sb.toString(); 482 } finally { 483 Utility.closeStream(bufferedReader); 484 Utility.closeStream(fileInputStream); 485 } 486 } 487 488 /** 489 * get sha-256 for file 490 * 491 * @param hapPath is the input path of file 492 */ getSha256(String hapPath)493 public static String getSha256(String hapPath) { 494 String sha256 = ""; 495 BufferedInputStream inputStream = null; 496 try { 497 File file = new File(hapPath); 498 inputStream = new BufferedInputStream(new FileInputStream(file)); 499 byte[] buffer = new byte[SHA256_BUFFER_SIZE]; 500 MessageDigest md5 = MessageDigest.getInstance(SHA256); 501 int size = -1; 502 while ((size = inputStream.read(buffer)) != -1) { 503 md5.update(buffer, 0, size); 504 } 505 sha256 = toHex(md5.digest()); 506 } catch (FileNotFoundException e) { 507 LOG.error("input hap file is not found: " + e.getMessage()); 508 } catch (NoSuchAlgorithmException e) { 509 LOG.error("can not provide sha-256 algorithm: " + e.getMessage()); 510 } catch (IOException e) { 511 LOG.error("input hap IO exception: " + e.getMessage()); 512 } finally { 513 Utility.closeStream(inputStream); 514 } 515 return sha256; 516 } 517 toHex(byte[] data)518 private static String toHex(byte[] data) { 519 StringBuilder hexString = new StringBuilder(); 520 for (byte item : data) { 521 hexString.append(Integer.toHexString(item & 0xFF)); 522 } 523 return hexString.toString(); 524 } 525 526 /** 527 * unzip file 528 * 529 * @param zipFilePath is the zipFilePath 530 * @param destDirPath is the output dest path 531 */ unzipFile(String zipFilePath, String destDirPath)532 public static boolean unzipFile(String zipFilePath, String destDirPath) { 533 boolean success = false; 534 File destDir = new File(destDirPath); 535 if (!destDir.exists()) { 536 destDir.mkdirs(); 537 } 538 ZipInputStream zipInputStream = null; 539 try { 540 zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath)); 541 ZipEntry entry = zipInputStream.getNextEntry(); 542 while (entry != null) { 543 String filePath = destDirPath + File.separator + entry.getName(); 544 if (!matchPattern(filePath)) { 545 LOG.error("Input invalid file " + filePath + "."); 546 return false; 547 } 548 if (!entry.isDirectory()) { 549 extractFile(zipInputStream, filePath); 550 } else { 551 File dir = new File(filePath); 552 dir.mkdirs(); 553 } 554 zipInputStream.closeEntry(); 555 entry = zipInputStream.getNextEntry(); 556 } 557 success = true; 558 } catch (IOException e) { 559 LOG.error("FileUtil::unzipFile failed, IOException is " + e.getMessage()); 560 } finally { 561 Utility.closeStream(zipInputStream); 562 } 563 return success; 564 } 565 extractFile(ZipInputStream zipInputStream, String filePath)566 private static void extractFile(ZipInputStream zipInputStream, String filePath) { 567 BufferedOutputStream bufferedOutputStream = null; 568 try { 569 if (!matchPattern(filePath)) { 570 LOG.error("input invalid file: " + filePath); 571 throw new BundleException("input invalid file " + filePath + "."); 572 } 573 bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath)); 574 byte[] bytes = new byte[BUFFER_SIZE]; 575 int readLength = 0; 576 while ((readLength = zipInputStream.read(bytes)) != -1) { 577 bufferedOutputStream.write(bytes, 0, readLength); 578 } 579 } catch (IOException | BundleException e) { 580 LOG.error("FileUtil::extractFile failed, Exception is " + e.getMessage()); 581 } finally { 582 Utility.closeStream(bufferedOutputStream); 583 } 584 } 585 matchPattern(String path)586 static boolean matchPattern(String path) { 587 if (!Pattern.matches(PATTERN, path)) { 588 LOG.error("input invalid file of " + path + "."); 589 return false; 590 } 591 return true; 592 } 593 594 /** 595 * getFileSize 596 * 597 * @param filePath is the input file path 598 * @return file length 599 */ getFileSize(String filePath)600 public static long getFileSize(String filePath) { 601 File file = new File(filePath); 602 if (file.exists() && file.isFile()) { 603 return file.length(); 604 } 605 String errMsg = "input " + filePath + " is not a valid file."; 606 LOG.error(PackingToolErrMsg.GET_FILE_SIZE_FAILED.toString(errMsg)); 607 return 0; 608 } 609 610 /** 611 * Create a parent directory for a file 612 * 613 * @param file file 614 */ createParentDir(File file)615 public static void createParentDir(File file) { 616 if (file != null && file.getParentFile() != null && !file.getParentFile().exists()) { 617 file.getParentFile().mkdirs(); 618 } 619 } 620 621 /** 622 * copy Stream 623 * 624 * @param inputStream input stream 625 * @param outputStream out stream 626 * @throws IOException IOException. 627 */ copyStream(InputStream inputStream, OutputStream outputStream)628 public static void copyStream(InputStream inputStream, OutputStream outputStream) throws IOException { 629 byte[] buffer = new byte[BUFFER_SIZE]; 630 int bytesRead = 0; 631 while ((bytesRead = inputStream.read(buffer)) != -1) { 632 outputStream.write(buffer, 0, bytesRead); 633 } 634 } 635 } 636