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 = "CompressorFileUtil::copyFile input file is null."; 348 LOG.error(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 = "CompressorFileUtil::makeDir input file is null."; 376 LOG.error(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("Compressor::checkModuleTypeInHaps io exception: " + exception.getMessage()); 418 throw new BundleException("Compressor::checkModuleTypeInHaps failed."); 419 } finally { 420 Utility.closeStream(zipFile); 421 Utility.closeStream(zipInput); 422 Utility.closeStream(zin); 423 Utility.closeStream(inputStream); 424 Utility.closeStream(reader); 425 Utility.closeStream(br); 426 } 427 return jsonStr.toString(); 428 } 429 430 /** 431 * get all resource file in profile. 432 * 433 * @param zipFile is the hap file 434 * @throws BundleException when get profile json file failed 435 */ getProfileJson(ZipFile zipFile)436 static HashMap<String, String> getProfileJson(ZipFile zipFile) throws BundleException { 437 HashMap<String, String> resourceMap = new HashMap<>(); 438 try { 439 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 440 while (entries.hasMoreElements()) { 441 final ZipEntry entry = entries.nextElement(); 442 if (entry.getName().contains(RESOURCE_PATH)) { 443 String filePath = entry.getName(); 444 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 445 String fileContent = getFileStringFromZip(filePath, zipFile); 446 resourceMap.put(fileName, fileContent); 447 } 448 } 449 } catch (IOException e) { 450 LOG.error(PackingToolErrMsg.IO_EXCEPTION.toString("Get profile json exist IOExpection: " + e.getMessage())); 451 throw new BundleException("Get profile json failed."); 452 } 453 return resourceMap; 454 } 455 456 /** 457 * get file content in string from zip 458 * 459 * @param fileName is the file name we want to read 460 * @param zipFile is the zip file 461 */ getFileStringFromZip(String fileName, ZipFile zipFile)462 public static String getFileStringFromZip(String fileName, ZipFile zipFile) 463 throws IOException { 464 ZipEntry entry = zipFile.getEntry(fileName); 465 if (entry == null) { 466 LOG.debug("Uncompress::readStringFromFile " + fileName + " not found exception."); 467 return ""; 468 } 469 InputStream fileInputStream = null; 470 BufferedReader bufferedReader = null; 471 try { 472 fileInputStream = zipFile.getInputStream(entry); 473 bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8")); 474 String line; 475 StringBuilder sb = new StringBuilder(); 476 while ((line = bufferedReader.readLine()) != null) { 477 sb.append(line); 478 } 479 return sb.toString(); 480 } finally { 481 Utility.closeStream(bufferedReader); 482 Utility.closeStream(fileInputStream); 483 } 484 } 485 486 /** 487 * get sha-256 for file 488 * 489 * @param hapPath is the input path of file 490 */ getSha256(String hapPath)491 public static String getSha256(String hapPath) { 492 String sha256 = ""; 493 BufferedInputStream inputStream = null; 494 try { 495 File file = new File(hapPath); 496 inputStream = new BufferedInputStream(new FileInputStream(file)); 497 byte[] buffer = new byte[SHA256_BUFFER_SIZE]; 498 MessageDigest md5 = MessageDigest.getInstance(SHA256); 499 int size = -1; 500 while ((size = inputStream.read(buffer)) != -1) { 501 md5.update(buffer, 0, size); 502 } 503 sha256 = toHex(md5.digest()); 504 } catch (FileNotFoundException e) { 505 LOG.error("input hap file is not found: " + e.getMessage()); 506 } catch (NoSuchAlgorithmException e) { 507 LOG.error("can not provide sha-256 algorithm: " + e.getMessage()); 508 } catch (IOException e) { 509 LOG.error("input hap IO exception: " + e.getMessage()); 510 } finally { 511 Utility.closeStream(inputStream); 512 } 513 return sha256; 514 } 515 toHex(byte[] data)516 private static String toHex(byte[] data) { 517 StringBuilder hexString = new StringBuilder(); 518 for (byte item : data) { 519 hexString.append(Integer.toHexString(item & 0xFF)); 520 } 521 return hexString.toString(); 522 } 523 524 /** 525 * unzip file 526 * 527 * @param zipFilePath is the zipFilePath 528 * @param destDirPath is the output dest path 529 */ unzipFile(String zipFilePath, String destDirPath)530 public static boolean unzipFile(String zipFilePath, String destDirPath) { 531 boolean success = false; 532 File destDir = new File(destDirPath); 533 if (!destDir.exists()) { 534 destDir.mkdirs(); 535 } 536 ZipInputStream zipInputStream = null; 537 try { 538 zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath)); 539 ZipEntry entry = zipInputStream.getNextEntry(); 540 while (entry != null) { 541 String filePath = destDirPath + File.separator + entry.getName(); 542 if (!matchPattern(filePath)) { 543 LOG.error("Input invalid file " + filePath + "."); 544 return false; 545 } 546 if (!entry.isDirectory()) { 547 extractFile(zipInputStream, filePath); 548 } else { 549 File dir = new File(filePath); 550 dir.mkdirs(); 551 } 552 zipInputStream.closeEntry(); 553 entry = zipInputStream.getNextEntry(); 554 } 555 success = true; 556 } catch (IOException e) { 557 LOG.error("FileUtil::unzipFile failed, IOException is " + e.getMessage()); 558 } finally { 559 Utility.closeStream(zipInputStream); 560 } 561 return success; 562 } 563 extractFile(ZipInputStream zipInputStream, String filePath)564 private static void extractFile(ZipInputStream zipInputStream, String filePath) { 565 BufferedOutputStream bufferedOutputStream = null; 566 try { 567 if (!matchPattern(filePath)) { 568 LOG.error("input invalid file: " + filePath); 569 throw new BundleException("input invalid file " + filePath + "."); 570 } 571 bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath)); 572 byte[] bytes = new byte[BUFFER_SIZE]; 573 int readLength = 0; 574 while ((readLength = zipInputStream.read(bytes)) != -1) { 575 bufferedOutputStream.write(bytes, 0, readLength); 576 } 577 } catch (IOException | BundleException e) { 578 LOG.error("FileUtil::extractFile failed, Exception is " + e.getMessage()); 579 } finally { 580 Utility.closeStream(bufferedOutputStream); 581 } 582 } 583 matchPattern(String path)584 static boolean matchPattern(String path) { 585 if (!Pattern.matches(PATTERN, path)) { 586 LOG.error("input invalid file of " + path + "."); 587 return false; 588 } 589 return true; 590 } 591 592 /** 593 * getFileSize 594 * 595 * @param filePath is the input file path 596 * @return file length 597 */ getFileSize(String filePath)598 public static long getFileSize(String filePath) { 599 File file = new File(filePath); 600 if (file.exists() && file.isFile()) { 601 return file.length(); 602 } 603 String errMsg = "input " + filePath + " is not a valid file."; 604 LOG.error(PackingToolErrMsg.GET_FILE_SIZE_FAILED.toString(errMsg)); 605 return 0; 606 } 607 608 /** 609 * Create a parent directory for a file 610 * 611 * @param file file 612 */ createParentDir(File file)613 public static void createParentDir(File file) { 614 if (file != null && file.getParentFile() != null && !file.getParentFile().exists()) { 615 file.getParentFile().mkdirs(); 616 } 617 } 618 619 /** 620 * copy Stream 621 * 622 * @param inputStream input stream 623 * @param outputStream out stream 624 * @throws IOException IOException. 625 */ copyStream(InputStream inputStream, OutputStream outputStream)626 public static void copyStream(InputStream inputStream, OutputStream outputStream) throws IOException { 627 byte[] buffer = new byte[BUFFER_SIZE]; 628 int bytesRead = 0; 629 while ((bytesRead = inputStream.read(buffer)) != -1) { 630 outputStream.write(buffer, 0, bytesRead); 631 } 632 } 633 } 634