/** * Lists all directories from root to directory of specified file, returns found directory. * * @param file * @param root * @return */ private FileInfo findParentInternal(FileInfo file, FileInfo root) { if (root == null || file == null || root.isRecentDir()) return null; if (!root.isRootDir() && !file.getPathName().startsWith(root.getPathName())) return null; // to list all directories starting root dir if (root.isDirectory && !root.isSpecialDir()) listDirectory(root); for (int i = 0; i < root.dirCount(); i++) { FileInfo found = findParentInternal(file, root.getDir(i)); if (found != null) return found; } for (int i = 0; i < root.fileCount(); i++) { if (root.getFile(i).getPathName().equals(file.getPathName())) return root; if (root.getFile(i).getPathName().startsWith(file.getPathName() + "@/")) return root; } return null; }
/** * Adds dir and file children to directory FileInfo item. * * @param baseDir is directory to list files and dirs for * @return true if successful. */ public boolean listDirectory(FileInfo baseDir) { Set<String> knownItems = null; if (baseDir.isListed) { knownItems = new HashSet<String>(); for (int i = baseDir.itemCount() - 1; i >= 0; i--) { FileInfo item = baseDir.getItem(i); if (!item.exists()) { // remove item from list baseDir.removeChild(item); } else { knownItems.add(item.getBasePath()); } } } try { File dir = new File(baseDir.pathname); File[] items = dir.listFiles(); // process normal files if (items != null) { for (File f : items) { // check whether file is a link if (Engine.isLink(f.getAbsolutePath()) != null) { log.w("skipping " + f + " because it's a link"); continue; } if (!f.isDirectory()) { // regular file if (f.getName().startsWith(".")) continue; // treat files beginning with '.' as hidden if (f.getName().equalsIgnoreCase("LOST.DIR")) continue; // system directory String pathName = f.getAbsolutePath(); if (knownItems != null && knownItems.contains(pathName)) continue; if (engine.isRootsMountPoint(pathName)) { // skip mount root continue; } boolean isZip = pathName.toLowerCase().endsWith(".zip"); FileInfo item = mFileList.get(pathName); boolean isNew = false; if (item == null) { item = new FileInfo(f); if (isZip) { item = scanZip(item); if (item == null) continue; if (item.isDirectory) { // many supported files in ZIP item.parent = baseDir; baseDir.addDir(item); for (int i = 0; i < item.fileCount(); i++) { FileInfo file = item.getFile(i); mFileList.put(file.getPathName(), file); } } else { item.parent = baseDir; baseDir.addFile(item); mFileList.put(pathName, item); } continue; } isNew = true; } if (item.format != null) { item.parent = baseDir; baseDir.addFile(item); if (isNew) mFileList.put(pathName, item); } } } // process directories for (File f : items) { if (f.isDirectory()) { if (f.getName().startsWith(".")) continue; // treat dirs beginning with '.' as hidden FileInfo item = new FileInfo(f); if (knownItems != null && knownItems.contains(item.getPathName())) continue; item.parent = baseDir; baseDir.addDir(item); } } } baseDir.isListed = true; return !baseDir.isEmpty(); } catch (Exception e) { L.e("Exception while listing directory " + baseDir.pathname, e); baseDir.isListed = true; return false; } }
/** * For all files in directory, retrieve metadata from DB or scan and save into DB. Call in GUI * thread only! * * @param baseDir is directory with files to lookup/scan; file items will be updated with info * from file metadata or DB * @param readyCallback is Runable to call when operation is finished or stopped (will be called * in GUI thread) * @param control allows to stop long operation */ private void scanDirectoryFiles( final CRDBService.LocalBinder db, final FileInfo baseDir, final ScanControl control, final Engine.ProgressControl progress, final Runnable readyCallback) { // GUI thread BackgroundThread.ensureGUI(); log.d("scanDirectoryFiles(" + baseDir.getPathName() + ") "); // store list of files to scan ArrayList<String> pathNames = new ArrayList<String>(); for (int i = 0; i < baseDir.fileCount(); i++) { pathNames.add(baseDir.getFile(i).getPathName()); } if (pathNames.size() == 0) { readyCallback.run(); return; } // list all subdirectories for (int i = 0; i < baseDir.dirCount(); i++) { if (control.isStopped()) break; listDirectory(baseDir.getDir(i)); } // load book infos for files db.loadFileInfos( pathNames, new CRDBService.FileInfoLoadingCallback() { @Override public void onFileInfoListLoaded(ArrayList<FileInfo> list) { log.v("onFileInfoListLoaded"); // GUI thread final ArrayList<FileInfo> filesForParsing = new ArrayList<FileInfo>(); ArrayList<FileInfo> filesForSave = new ArrayList<FileInfo>(); Map<String, FileInfo> mapOfFilesFoundInDb = new HashMap<String, FileInfo>(); for (FileInfo f : list) mapOfFilesFoundInDb.put(f.getPathName(), f); for (int i = 0; i < baseDir.fileCount(); i++) { FileInfo item = baseDir.getFile(i); FileInfo fromDB = mapOfFilesFoundInDb.get(item.getPathName()); if (fromDB != null) { // use DB value baseDir.setFile(i, fromDB); } else { // not found in DB if (item.format.canParseProperties()) { filesForParsing.add(new FileInfo(item)); } else { filesForSave.add(new FileInfo(item)); } } } if (filesForSave.size() > 0) { db.saveFileInfos(filesForSave); } if (filesForParsing.size() == 0 || control.isStopped()) { readyCallback.run(); return; } // scan files in Background thread BackgroundThread.instance() .postBackground( new Runnable() { @Override public void run() { // Background thread final ArrayList<FileInfo> filesForSave = new ArrayList<FileInfo>(); try { int count = filesForParsing.size(); for (int i = 0; i < count; i++) { if (control.isStopped()) break; progress.setProgress(i * 10000 / count); FileInfo item = filesForParsing.get(i); engine.scanBookProperties(item); filesForSave.add(item); } } catch (Exception e) { L.e("Exception while scanning", e); } progress.hide(); // jump to GUI thread BackgroundThread.instance() .postGUI( new Runnable() { @Override public void run() { // GUI thread try { if (filesForSave.size() > 0) { db.saveFileInfos(filesForSave); } for (FileInfo file : filesForSave) baseDir.setFile(file); } catch (Exception e) { L.e("Exception while scanning", e); } // call finish handler readyCallback.run(); } }); } }); } }); }