All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.commons.io.file.PathOperations Maven / Gradle / Ivy

There is a newer version: 11.1.10
Show newest version
/*
 * Copyright (C) 2014-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.commons.io.file;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.equals.EqualsHelper;

/**
 * Wraps file operations.
 *
 * @author Philip Helger
 */
@ThreadSafe
public final class PathOperations
{
  /**
   * The default value for warning if we're about to delete the root directory.
   */
  public static final boolean DEFAULT_EXCEPTION_ON_DELETE_ROOT = true;

  private static volatile boolean s_bExceptionOnDeleteRoot = DEFAULT_EXCEPTION_ON_DELETE_ROOT;

  @PresentForCodeCoverage
  private static final PathOperations INSTANCE = new PathOperations ();

  private PathOperations ()
  {}

  public static boolean isExceptionOnDeleteRoot ()
  {
    return s_bExceptionOnDeleteRoot;
  }

  public static void setExceptionOnDeleteRoot (final boolean bExceptionOnDeleteRoot)
  {
    s_bExceptionOnDeleteRoot = bExceptionOnDeleteRoot;
  }

  /**
   * Internal dummy interface for operations with one parameter.
   *
   * @author Philip Helger
   */
  @FunctionalInterface
  private interface IOpPath
  {
    void op (Path aPath) throws IOException;
  }

  /**
   * Internal dummy interface for operations with two parameters.
   *
   * @author Philip Helger
   */
  @FunctionalInterface
  private interface IOpPath2
  {
    void op (Path aPath1, Path aPath2) throws IOException;
  }

  @Nonnull
  private static FileIOError _perform (@Nonnull final EFileIOOperation eOperation,
                                       @Nonnull final IOpPath aRunnable,
                                       @Nonnull final Path aPath)
  {
    try
    {
      aRunnable.op (aPath);
      return EFileIOErrorCode.NO_ERROR.getAsIOError (eOperation, aPath);
    }
    catch (final SecurityException ex)
    {
      return EFileIOErrorCode.getSecurityAsIOError (eOperation, ex);
    }
    catch (final IOException ex)
    {
      return EFileIOErrorCode.getAsIOError (eOperation, ex);
    }
    catch (final UncheckedIOException ex)
    {
      return EFileIOErrorCode.getAsIOError (eOperation, ex);
    }
  }

  @Nonnull
  private static FileIOError _perform (@Nonnull final EFileIOOperation eOp,
                                       @Nonnull final IOpPath2 aRunnable,
                                       @Nonnull final Path aPath1,
                                       @Nonnull final Path aPath2)
  {
    try
    {
      aRunnable.op (aPath1, aPath2);
      return EFileIOErrorCode.NO_ERROR.getAsIOError (eOp, aPath1, aPath2);
    }
    catch (final SecurityException ex)
    {
      return EFileIOErrorCode.getSecurityAsIOError (eOp, ex);
    }
    catch (final IOException ex)
    {
      return EFileIOErrorCode.getAsIOError (eOp, ex);
    }
    catch (final UncheckedIOException ex)
    {
      return EFileIOErrorCode.getAsIOError (eOp, ex);
    }
  }

  @Nonnull
  private static Path _getUnifiedPath (final Path aPath)
  {
    return aPath.toAbsolutePath ().normalize ();
  }

  /**
   * Create a new directory. The direct parent directory already needs to exist.
   *
   * @param aDir
   *        The directory to be created. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError createDir (@Nonnull final Path aDir)
  {
    ValueEnforcer.notNull (aDir, "Directory");

    final Path aRealDir = _getUnifiedPath (aDir);
    return FileOperations.createDir (aRealDir.toFile ());

    // // Does the directory already exist?
    // if (Files.exists (aRealDir))
    // return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError
    // (EFileIOOperation.CREATE_DIR, aRealDir);
    //
    // // Is the parent directory writable?
    // final Path aParentDir = aRealDir.getParent ();
    // if (aParentDir != null && Files.exists (aParentDir) && !Files.isWritable
    // (aParentDir))
    // return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError
    // (EFileIOOperation.CREATE_DIR, aRealDir);
    //
    // return _perform (EFileIOOperation.CREATE_DIR, Files::createDirectory,
    // aRealDir);
  }

  /**
   * Create a new directory if it does not exist. The direct parent directory
   * already needs to exist.
   *
   * @param aDir
   *        The directory to be created if it does not exist. May not be
   *        null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError createDirIfNotExisting (@Nonnull final Path aDir)
  {
    final FileIOError aError = createDir (aDir);
    if (aError.getErrorCode ().equals (EFileIOErrorCode.TARGET_ALREADY_EXISTS))
      return aError.withoutErrorCode ();
    return aError;
  }

  /**
   * Create a new directory. The parent directories are created if they are
   * missing.
   *
   * @param aDir
   *        The directory to be created. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError createDirRecursive (@Nonnull final Path aDir)
  {
    ValueEnforcer.notNull (aDir, "Directory");

    final Path aRealDir = _getUnifiedPath (aDir);
    return FileOperations.createDirRecursive (aRealDir.toFile ());

    // // Does the directory already exist?
    // if (Files.exists (aRealDir))
    // return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError
    // (EFileIOOperation.CREATE_DIR_RECURSIVE, aRealDir);
    //
    // // Is the parent directory writable?
    // final Path aParentDir = aRealDir.getParent ();
    // if (aParentDir != null && Files.exists (aParentDir) && !Files.isWritable
    // (aParentDir))
    // return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError
    // (EFileIOOperation.CREATE_DIR_RECURSIVE, aRealDir);
    //
    // return _perform (EFileIOOperation.CREATE_DIR_RECURSIVE,
    // Files::createDirectories, aRealDir);
  }

  /**
   * Create a new directory if it does not exist. The direct parent directory
   * already needs to exist.
   *
   * @param aDir
   *        The directory to be created if it does not exist. May not be
   *        null.
   * @return A non-null error code.
   * @see #createDirRecursive(Path)
   */
  @Nonnull
  public static FileIOError createDirRecursiveIfNotExisting (@Nonnull final Path aDir)
  {
    final FileIOError aError = createDirRecursive (aDir);
    if (aError.getErrorCode ().equals (EFileIOErrorCode.TARGET_ALREADY_EXISTS))
      return aError.withoutErrorCode ();
    return aError;
  }

  /**
   * Delete an existing directory. The directory needs to be empty before it can
   * be deleted.
   *
   * @param aDir
   *        The directory to be deleted. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError deleteDir (@Nonnull final Path aDir)
  {
    ValueEnforcer.notNull (aDir, "Directory");

    final Path aRealDir = _getUnifiedPath (aDir);

    // Does the directory not exist?
    if (!aRealDir.toFile ().isDirectory ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.DELETE_DIR, aRealDir);

    if (isExceptionOnDeleteRoot ())
    {
      // Check that we're not deleting the complete hard drive...
      if (aRealDir.getParent () == null || aRealDir.getNameCount () == 0)
        throw new IllegalArgumentException ("Aren't we deleting the full drive: '" + aRealDir + "'");
    }

    // Is the parent directory writable?
    final Path aParentDir = aRealDir.getParent ();
    if (aParentDir != null && !Files.isWritable (aParentDir))
      return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.DELETE_DIR, aRealDir);

    return _perform (EFileIOOperation.DELETE_DIR, Files::delete, aRealDir);
  }

  /**
   * Delete an existing directory if it is existing. The directory needs to be
   * empty before it can be deleted.
   *
   * @param aDir
   *        The directory to be deleted. May not be null.
   * @return A non-null error code.
   * @see #deleteDir(Path)
   */
  @Nonnull
  public static FileIOError deleteDirIfExisting (@Nonnull final Path aDir)
  {
    final FileIOError aError = deleteDir (aDir);
    if (aError.getErrorCode ().equals (EFileIOErrorCode.SOURCE_DOES_NOT_EXIST))
      return aError.withoutErrorCode ();
    return aError;
  }

  /**
   * Delete an existing directory including all child objects.
   *
   * @param aDir
   *        The directory to be deleted. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError deleteDirRecursive (@Nonnull final Path aDir)
  {
    ValueEnforcer.notNull (aDir, "Directory");

    final Path aRealDir = _getUnifiedPath (aDir);

    // Non-existing directory?
    if (!aRealDir.toFile ().isDirectory ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.DELETE_DIR_RECURSIVE, aRealDir);

    if (isExceptionOnDeleteRoot ())
    {
      // Check that we're not deleting the complete hard drive...
      if (aRealDir.getParent () == null || aRealDir.getNameCount () == 0)
        throw new IllegalArgumentException ("Aren't we deleting the full drive: '" + aRealDir + "'");
    }

    // Is the parent directory writable?
    final Path aParentDir = aRealDir.getParent ();
    if (aParentDir != null && !Files.isWritable (aParentDir))
      return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.DELETE_DIR_RECURSIVE, aRealDir);

    // iterate directory
    for (final Path aChild : PathHelper.getDirectoryContent (aRealDir))
    {
      final File aChildFile = aChild.toFile ();

      // is it a file or a directory or ...
      if (aChildFile.isDirectory ())
      {
        // Ignore "." and ".." directory
        if (FilenameHelper.isSystemInternalDirectory (aChild))
          continue;

        // recursive call
        final FileIOError eCode = deleteDirRecursive (aChild);
        if (eCode.isFailure ())
          return eCode;
      }
      else
        if (aChildFile.isFile ())
        {
          // delete file
          final FileIOError eCode = deleteFile (aChild);
          if (eCode.isFailure ())
            return eCode;
        }
        else
        {
          // Neither directory no file - don't know how to handle
          return EFileIOErrorCode.OBJECT_CANNOT_BE_HANDLED.getAsIOError (EFileIOOperation.DELETE_DIR_RECURSIVE, aChild);
        }
    }

    // Now this directory should be empty -> delete as if empty
    return deleteDir (aRealDir);
  }

  /**
   * Delete an existing directory including all child objects if it is existing.
   *
   * @param aDir
   *        The directory to be deleted. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError deleteDirRecursiveIfExisting (@Nonnull final Path aDir)
  {
    final FileIOError aError = deleteDirRecursive (aDir);
    if (aError.getErrorCode ().equals (EFileIOErrorCode.SOURCE_DOES_NOT_EXIST))
      return aError.withoutErrorCode ();
    return aError;
  }

  /**
   * Delete an existing file.
   *
   * @param aFile
   *        The file to be deleted. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError deleteFile (@Nonnull final Path aFile)
  {
    ValueEnforcer.notNull (aFile, "Path");

    final Path aRealFile = _getUnifiedPath (aFile);

    if (!aRealFile.toFile ().isFile ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.DELETE_FILE, aRealFile);

    // Is the parent directory writable?
    final Path aParentDir = aRealFile.getParent ();
    if (aParentDir != null && !Files.isWritable (aParentDir))
      return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.DELETE_FILE, aRealFile);

    return _perform (EFileIOOperation.DELETE_FILE, Files::delete, aRealFile);
  }

  /**
   * Delete a file if it is existing.
   *
   * @param aFile
   *        The file to be deleted. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError deleteFileIfExisting (@Nonnull final Path aFile)
  {
    final FileIOError aError = deleteFile (aFile);
    if (aError.getErrorCode ().equals (EFileIOErrorCode.SOURCE_DOES_NOT_EXIST))
      return aError.withoutErrorCode ();
    return aError;
  }

  private static void _atomicMove (@Nonnull final Path aSourcePath, @Nonnull final Path aTargetPath) throws IOException
  {
    Files.move (aSourcePath, aTargetPath, StandardCopyOption.ATOMIC_MOVE);
  }

  /**
   * Rename a file.
   *
   * @param aSourceFile
   *        The original file name. May not be null.
   * @param aTargetFile
   *        The destination file name. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError renameFile (@Nonnull final Path aSourceFile, @Nonnull final Path aTargetFile)
  {
    ValueEnforcer.notNull (aSourceFile, "SourceFile");
    ValueEnforcer.notNull (aTargetFile, "TargetFile");

    final Path aRealSourceFile = _getUnifiedPath (aSourceFile);
    final Path aRealTargetFile = _getUnifiedPath (aTargetFile);

    // Does the source file exist?
    if (!aRealSourceFile.toFile ().isFile ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.RENAME_FILE, aRealSourceFile);

    // Are source and target different?
    if (EqualsHelper.equals (aRealSourceFile, aRealTargetFile))
      return EFileIOErrorCode.SOURCE_EQUALS_TARGET.getAsIOError (EFileIOOperation.RENAME_FILE, aRealSourceFile);

    // Does the target file already exist?
    if (aRealTargetFile.toFile ().exists ())
      return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError (EFileIOOperation.RENAME_FILE, aRealTargetFile);

    // Is the source parent directory writable?
    final Path aSourceParentDir = aRealSourceFile.getParent ();
    if (aSourceParentDir != null && !Files.isWritable (aSourceParentDir))
      return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.RENAME_FILE, aRealSourceFile);

    // Is the target parent directory writable?
    final Path aTargetParentDir = aRealTargetFile.getParent ();
    if (aTargetParentDir != null && aTargetParentDir.toFile ().exists () && !Files.isWritable (aTargetParentDir))
      return EFileIOErrorCode.TARGET_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.RENAME_FILE, aRealTargetFile);

    // Ensure parent of target directory is present
    PathHelper.ensureParentDirectoryIsPresent (aRealTargetFile);

    return _perform (EFileIOOperation.RENAME_FILE, PathOperations::_atomicMove, aRealSourceFile, aRealTargetFile);
  }

  /**
   * Rename a directory.
   *
   * @param aSourceDir
   *        The original directory name. May not be null.
   * @param aTargetDir
   *        The destination directory name. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError renameDir (@Nonnull final Path aSourceDir, @Nonnull final Path aTargetDir)
  {
    ValueEnforcer.notNull (aSourceDir, "SourceDirectory");
    ValueEnforcer.notNull (aTargetDir, "TargetDirectory");

    final Path aRealSourceDir = _getUnifiedPath (aSourceDir);
    final Path aRealTargetDir = _getUnifiedPath (aTargetDir);

    // Does the source directory exist?
    if (!aRealSourceDir.toFile ().isDirectory ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.RENAME_DIR, aRealSourceDir);

    // Are source and target different?
    if (EqualsHelper.equals (aRealSourceDir, aRealTargetDir))
      return EFileIOErrorCode.SOURCE_EQUALS_TARGET.getAsIOError (EFileIOOperation.RENAME_DIR, aRealSourceDir);

    // Does the target directory already exist?
    if (aRealTargetDir.toFile ().exists ())
      return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError (EFileIOOperation.RENAME_DIR, aRealTargetDir);

    // Is the source a parent of target?
    if (PathHelper.isParentDirectory (aRealSourceDir, aRealTargetDir))
      return EFileIOErrorCode.TARGET_IS_CHILD_OF_SOURCE.getAsIOError (EFileIOOperation.RENAME_DIR, aRealSourceDir, aRealTargetDir);

    // Is the source parent directory writable?
    final Path aSourceParentDir = aRealSourceDir.getParent ();
    if (aSourceParentDir != null && !Files.isWritable (aSourceParentDir))
      return EFileIOErrorCode.SOURCE_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.RENAME_DIR, aRealSourceDir);

    // Is the target parent directory writable?
    final Path aTargetParentDir = aRealTargetDir.getParent ();
    if (aTargetParentDir != null && aTargetParentDir.toFile ().exists () && !Files.isWritable (aTargetParentDir))
      return EFileIOErrorCode.TARGET_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.RENAME_DIR, aRealTargetDir);

    // Ensure parent of target directory is present
    PathHelper.ensureParentDirectoryIsPresent (aRealTargetDir);

    return _perform (EFileIOOperation.RENAME_DIR, PathOperations::_atomicMove, aRealSourceDir, aRealTargetDir);
  }

  /**
   * Copies the source file to the target file.
   *
   * @param aSourceFile
   *        The source file to use. May not be null. Needs to be an
   *        existing file.
   * @param aTargetFile
   *        The destination files. May not be null and may not be
   *        an existing file.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError copyFile (@Nonnull final Path aSourceFile, @Nonnull final Path aTargetFile)
  {
    ValueEnforcer.notNull (aSourceFile, "SourceFile");
    ValueEnforcer.notNull (aTargetFile, "TargetFile");

    final Path aRealSourceFile = _getUnifiedPath (aSourceFile);
    final Path aRealTargetFile = _getUnifiedPath (aTargetFile);

    // Does the source file exist?
    if (!aRealSourceFile.toFile ().isFile ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.COPY_FILE, aRealSourceFile);

    // Are source and target different?
    if (EqualsHelper.equals (aRealSourceFile, aRealTargetFile))
      return EFileIOErrorCode.SOURCE_EQUALS_TARGET.getAsIOError (EFileIOOperation.COPY_FILE, aRealSourceFile);

    // Does the target file already exist?
    if (aRealTargetFile.toFile ().exists ())
      return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError (EFileIOOperation.COPY_FILE, aRealTargetFile);

    // Is the source file readable?
    if (!Files.isReadable (aRealSourceFile))
      return EFileIOErrorCode.SOURCE_NOT_READABLE.getAsIOError (EFileIOOperation.COPY_FILE, aRealSourceFile);

    // Is the target parent directory writable?
    final Path aTargetParentDir = aRealTargetFile.getParent ();
    if (aTargetParentDir != null && aTargetParentDir.toFile ().exists () && !Files.isWritable (aTargetParentDir))
      return EFileIOErrorCode.TARGET_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.COPY_FILE, aRealTargetFile);

    // Ensure the targets parent directory is present
    PathHelper.ensureParentDirectoryIsPresent (aRealTargetFile);

    return _perform (EFileIOOperation.COPY_FILE, Files::copy, aRealSourceFile, aRealTargetFile);
  }

  /**
   * Copy a directory including all child objects.
   *
   * @param aSourceDir
   *        The source directory to be copied. May not be null.
   * @param aTargetDir
   *        The destination directory where to be copied. This directory may not
   *        be existing. May not be null.
   * @return A non-null error code.
   */
  @Nonnull
  public static FileIOError copyDirRecursive (@Nonnull final Path aSourceDir, @Nonnull final Path aTargetDir)
  {
    ValueEnforcer.notNull (aSourceDir, "SourceDirectory");
    ValueEnforcer.notNull (aTargetDir, "TargetDirectory");

    final Path aRealSourceDir = _getUnifiedPath (aSourceDir);
    final Path aRealTargetDir = _getUnifiedPath (aTargetDir);

    // Does the source directory exist?
    if (!aRealSourceDir.toFile ().isDirectory ())
      return EFileIOErrorCode.SOURCE_DOES_NOT_EXIST.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealSourceDir);

    // Are source and target different?
    if (EqualsHelper.equals (aRealSourceDir, aRealTargetDir))
      return EFileIOErrorCode.SOURCE_EQUALS_TARGET.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealSourceDir);

    // Is the source a parent of target?
    if (PathHelper.isParentDirectory (aRealSourceDir, aRealTargetDir))
      return EFileIOErrorCode.TARGET_IS_CHILD_OF_SOURCE.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealSourceDir, aRealTargetDir);

    // Does the target directory already exist?
    if (aRealTargetDir.toFile ().exists ())
      return EFileIOErrorCode.TARGET_ALREADY_EXISTS.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealTargetDir);

    // Is the source directory readable?
    if (!Files.isReadable (aRealSourceDir))
      return EFileIOErrorCode.SOURCE_NOT_READABLE.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealSourceDir);

    // Is the target parent directory writable?
    final Path aTargetParentDir = aRealTargetDir.getParent ();
    if (aTargetParentDir != null && aTargetParentDir.toFile ().exists () && !Files.isWritable (aTargetParentDir))
      return EFileIOErrorCode.TARGET_PARENT_NOT_WRITABLE.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealTargetDir);

    FileIOError eCode;

    // Ensure the targets parent directory is present
    eCode = createDirRecursive (aRealTargetDir);
    if (eCode.isFailure ())
      return eCode;

    for (final Path aChild : PathHelper.getDirectoryContent (aRealSourceDir))
    {
      final File aChildFile = aChild.toFile ();
      if (aChildFile.isDirectory ())
      {
        // Skip "." and ".."
        if (FilenameHelper.isSystemInternalDirectory (aChild))
          continue;

        // Copy directory
        eCode = copyDirRecursive (aChild, aRealTargetDir.resolve (aChild.getFileName ()));
        if (eCode.isFailure ())
          return eCode;
      }
      else
        if (aChildFile.isFile ())
        {
          // Copy a file
          eCode = copyFile (aChild, aRealTargetDir.resolve (aChild.getFileName ()));
          if (eCode.isFailure ())
            return eCode;
        }
        else
        {
          // Neither directory not file - don't know how to handle
          return EFileIOErrorCode.OBJECT_CANNOT_BE_HANDLED.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aChild);
        }
    }

    // Done
    return EFileIOErrorCode.NO_ERROR.getAsIOError (EFileIOOperation.COPY_DIR_RECURSIVE, aRealSourceDir, aRealTargetDir);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy