@Override
 public boolean rename(Path src, Path dst) throws IOException {
   Path absoluteSrc = makeAbsolute(src);
   INode srcINode = store.retrieveINode(absoluteSrc);
   if (srcINode == null) {
     // src path doesn't exist
     return false;
   }
   Path absoluteDst = makeAbsolute(dst);
   INode dstINode = store.retrieveINode(absoluteDst);
   if (dstINode != null && dstINode.isDirectory()) {
     absoluteDst = new Path(absoluteDst, absoluteSrc.getName());
     dstINode = store.retrieveINode(absoluteDst);
   }
   if (dstINode != null) {
     // dst path already exists - can't overwrite
     return false;
   }
   Path dstParent = absoluteDst.getParent();
   if (dstParent != null) {
     INode dstParentINode = store.retrieveINode(dstParent);
     if (dstParentINode == null || dstParentINode.isFile()) {
       // dst parent doesn't exist or is a file
       return false;
     }
   }
   return renameRecursive(absoluteSrc, absoluteDst);
 }
 public boolean delete(Path path, boolean recursive) throws IOException {
   Path absolutePath = makeAbsolute(path);
   INode inode = store.retrieveINode(absolutePath);
   if (inode == null) {
     return false;
   }
   if (inode.isFile()) {
     store.deleteINode(absolutePath);
     for (Block block : inode.getBlocks()) {
       store.deleteBlock(block);
     }
   } else {
     FileStatus[] contents = listStatus(absolutePath);
     if (contents == null) {
       return false;
     }
     if ((contents.length != 0) && (!recursive)) {
       throw new IOException("Directory " + path.toString() + " is not empty.");
     }
     for (FileStatus p : contents) {
       if (!delete(p.getPath(), recursive)) {
         return false;
       }
     }
     store.deleteINode(absolutePath);
   }
   return true;
 }
 @Override
 public boolean isFile(Path path) throws IOException {
   INode inode = store.retrieveINode(makeAbsolute(path));
   if (inode == null) {
     return false;
   }
   return inode.isFile();
 }
 private static long findLength(INode inode) {
   if (!inode.isDirectory()) {
     long length = 0L;
     for (Block block : inode.getBlocks()) {
       length += block.getLength();
     }
     return length;
   }
   return 0;
 }
 private INode checkFile(Path path) throws IOException {
   INode inode = store.retrieveINode(makeAbsolute(path));
   if (inode == null) {
     throw new IOException("No such file.");
   }
   if (inode.isDirectory()) {
     throw new IOException("Path " + path + " is a directory.");
   }
   return inode;
 }
 private boolean mkdir(Path path) throws IOException {
   Path absolutePath = makeAbsolute(path);
   INode inode = store.retrieveINode(absolutePath);
   if (inode == null) {
     store.storeINode(absolutePath, INode.DIRECTORY_INODE);
   } else if (inode.isFile()) {
     throw new IOException(
         String.format("Can't make directory for path %s since it is a file.", absolutePath));
   }
   return true;
 }
 @Override
 public FileStatus[] listStatus(Path f) throws IOException {
   Path absolutePath = makeAbsolute(f);
   INode inode = store.retrieveINode(absolutePath);
   if (inode == null) {
     return new FileStatus[0];
   }
   if (inode.isFile()) {
     return new FileStatus[] {new OssFileStatus(f.makeQualified(this), inode)};
   }
   ArrayList<FileStatus> ret = new ArrayList<FileStatus>();
   for (Path p : store.listSubPaths(absolutePath)) {
     // Here, we need to convert "file/path" to "/file/path".
     // Otherwise, Path.makeQualified will throw `URISyntaxException`.
     Path modifiedPath = new Path("/" + p.toString());
     ret.add(getFileStatus(modifiedPath.makeQualified(this)));
   }
   return ret.toArray(new FileStatus[0]);
 }
 private boolean renameRecursive(Path src, Path dst) throws IOException {
   INode srcINode = store.retrieveINode(src);
   store.storeINode(dst, srcINode);
   store.deleteINode(src);
   if (srcINode.isDirectory()) {
     for (Path oldSrc : store.listDeepSubPaths(src)) {
       INode inode = store.retrieveINode(oldSrc);
       if (inode == null) {
         return false;
       }
       String oldSrcPath = oldSrc.toUri().getPath();
       String srcPath = src.toUri().getPath();
       String dstPath = dst.toUri().getPath();
       Path newDst = new Path(oldSrcPath.replaceFirst(srcPath, dstPath));
       store.storeINode(newDst, inode);
       store.deleteINode(oldSrc);
     }
   }
   return true;
 }
 private static long findBlocksize(INode inode) {
   final Block[] ret = inode.getBlocks();
   return ret == null ? 0L : ret[0].getLength();
 }
 OssFileStatus(Path f, INode inode) throws IOException {
   super(findLength(inode), inode.isDirectory(), 1, findBlocksize(inode), 0, f);
 }