@Override
  public void close() throws IOException {
    boolean triedToClose = false, success = false;
    try {
      flush();
      ((FileOutputStream)out).getChannel().force(true);

      triedToClose = true;
      super.close();
      success = true;
    } finally {
      if (success) {
        boolean renamed = tmpFile.renameTo(origFile);
        if (!renamed) {
          // On windows, renameTo does not replace.
          if (origFile.exists()) {
            try {
              Files.delete(origFile.toPath());
            } catch (IOException e) {
              throw new IOException("Could not delete original file " + origFile, e);
            }
          }
          try {
            NativeIO.renameTo(tmpFile, origFile);
          } catch (NativeIOException e) {
            throw new IOException("Could not rename temporary file " + tmpFile
              + " to " + origFile + " due to failure in native rename. "
              + e.toString());
          }
        }
      } else {
        if (!triedToClose) {
          // If we failed when flushing, try to close it to not leak an FD
          IOUtils.closeStream(out);
        }
        // close wasn't successful, try to delete the tmp file
        if (!tmpFile.delete()) {
          LOG.warn("Unable to delete tmp file " + tmpFile);
        }
      }
    }
  }
@Test
  public void testFailToRename() throws IOException {
    assumeWindows();
    OutputStream fos = null;
    try {
      fos = new AtomicFileOutputStream(DST_FILE);
      fos.write(TEST_STRING.getBytes());
      FileUtil.setWritable(TEST_DIR, false);
      exception.expect(IOException.class);
      exception.expectMessage("failure in native rename");
      try {
        fos.close();
      } finally {
        fos = null;
      }
    } finally {
      IOUtils.cleanupWithLogger(null, fos);
      FileUtil.setWritable(TEST_DIR, true);
    }
  }