/** * Combine the status stored in the index and the underlying status. * * @param h status stored in the index * @param cache caching the underlying file statuses * @return the combined file status * @throws IOException */ private FileStatus toFileStatus(HarStatus h, Map<String, FileStatus> cache) throws IOException { FileStatus underlying = null; if (cache != null) { underlying = cache.get(h.partName); } if (underlying == null) { final Path p = h.isDir ? archivePath : new Path(archivePath, h.partName); underlying = fs.getFileStatus(p); if (cache != null) { cache.put(h.partName, underlying); } } long modTime = 0; int version = metadata.getVersion(); if (version < 3) { modTime = underlying.getModificationTime(); } else if (version == 3) { modTime = h.getModificationTime(); } return new FileStatus( h.isDir() ? 0L : h.getLength(), h.isDir(), underlying.getReplication(), underlying.getBlockSize(), modTime, underlying.getAccessTime(), underlying.getPermission(), underlying.getOwner(), underlying.getGroup(), makeRelative(this.uri.getPath(), new Path(h.name))); }
/** * Get block locations from the underlying fs and fix their offsets and lengths. * * @param file the input file status to get block locations * @param start the start of the desired range in the contained file * @param len the length of the desired range * @return block locations for this segment of file * @throws IOException */ @Override public BlockLocation[] getFileBlockLocations(FileStatus file, long start, long len) throws IOException { HarStatus hstatus = getFileHarStatus(file.getPath()); Path partPath = new Path(archivePath, hstatus.getPartName()); FileStatus partStatus = metadata.getPartFileStatus(partPath); // get all part blocks that overlap with the desired file blocks BlockLocation[] locations = fs.getFileBlockLocations(partStatus, hstatus.getStartIndex() + start, len); return fixBlockLocations(locations, start, len, hstatus.getStartIndex()); }
/** * Returns a har input stream which fakes end of file. It reads the index files to get the part * file name and the size and start of the file. */ @Override public FSDataInputStream open(Path f, int bufferSize) throws IOException { // get the fs DataInputStream for the underlying file HarStatus hstatus = getFileHarStatus(f); if (hstatus.isDir()) { throw new FileNotFoundException(f + " : not a file in " + archivePath); } return new HarFSDataInputStream( fs, new Path(archivePath, hstatus.getPartName()), hstatus.getStartIndex(), hstatus.getLength(), bufferSize); }
/** * Get filestatuses of all the children of a given directory. This just reads through index file * and reads line by line to get all statuses for children of a directory. Its a brute force way * of getting all such filestatuses * * @param parent the parent path directory * @param statuses the list to add the children filestatuses to */ private void fileStatusesInIndex(HarStatus parent, List<FileStatus> statuses) throws IOException { String parentString = parent.getName(); if (!parentString.endsWith(Path.SEPARATOR)) { parentString += Path.SEPARATOR; } Path harPath = new Path(parentString); int harlen = harPath.depth(); final Map<String, FileStatus> cache = new TreeMap<String, FileStatus>(); for (HarStatus hstatus : metadata.archive.values()) { String child = hstatus.getName(); if ((child.startsWith(parentString))) { Path thisPath = new Path(child); if (thisPath.depth() == harlen + 1) { statuses.add(toFileStatus(hstatus, cache)); } } } }
/** liststatus returns the children of a directory after looking up the index files. */ @Override public FileStatus[] listStatus(Path f) throws IOException { // need to see if the file is an index in file // get the filestatus of the archive directory // we will create fake filestatuses to return // to the client List<FileStatus> statuses = new ArrayList<FileStatus>(); Path tmpPath = makeQualified(f); Path harPath = getPathInHar(tmpPath); HarStatus hstatus = metadata.archive.get(harPath); if (hstatus == null) { throw new FileNotFoundException("File " + f + " not found in " + archivePath); } if (hstatus.isDir()) { fileStatusesInIndex(hstatus, statuses); } else { statuses.add(toFileStatus(hstatus, null)); } return statuses.toArray(new FileStatus[statuses.size()]); }