Ejemplo n.º 1
0
// static
void VFSNode::copyDirectory(const VFSNode& source, const VFSNode& dest, bool recursive) {
    if (recursive) {
        VString sourcePathWithTrailingSeparator = source.getPath() + (source.getPath().endsWith(PATH_SEPARATOR_CHAR) ? "" : PATH_SEPARATOR_CHARS);
        if (dest.getPath().startsWith(sourcePathWithTrailingSeparator)) {
            throw VException(VSTRING_FORMAT("Attempt to recursively copy '%s' into '%s'.", source.getPath().chars(), dest.getPath().chars()));
        }
    }

    if (!dest.exists()) {
        dest.mkdirs();
    }
    
    VFSNodeCopyDirectoryCallback copyDirectoryCallback(dest, recursive);
    source.iterate(copyDirectoryCallback);
}
Ejemplo n.º 2
0
// static
void VFSNode::safelyOverwriteFile(const VFSNode& target, Vs64 dataLength, VBinaryIOStream& dataStream, bool keepOld) {
    bool success = true;
    VString errorMessage;

    VString targetFileName = target.getName();

    VInstant now;
    VString temporaryFileName = now.getLocalString(VFSNODE_SAFE_FILE_NAME_INSTANT_FORMATTER) + "_tmp_" + targetFileName;
    VString keptFileName = now.getLocalString(VFSNODE_SAFE_FILE_NAME_INSTANT_FORMATTER) + "_ver_" + targetFileName;

    VFSNode directoryNode;
    target.getParentNode(directoryNode);
    VFSNode originalTargetNode(target);
    VFSNode temporaryFileNode(directoryNode, temporaryFileName);
    VFSNode keptFileNode(directoryNode, keptFileName);

    // Create and write to the temp file within a scope block to ensure file is closed when scope is exited.
    /* stream scope */ {
        VBufferedFileStream tempFileStream(temporaryFileNode);
        VBinaryIOStream tempOutputStream(tempFileStream);

        try {
            tempFileStream.openWrite();
        } catch (const VException& ex) {
            success = false;
            errorMessage = VSTRING_FORMAT("Unable to open temporary file '%s': %s", target.getPath().chars(), ex.what());
        }

        if (success) {
            try {
                VStream::streamCopy(dataStream, tempOutputStream, dataLength);
                tempOutputStream.flush();
            } catch (const VException& ex) {
                success = false;
                errorMessage = VSTRING_FORMAT("Unable to write to temporary file '%s': %s", target.getPath().chars(), ex.what());
            }
        }
    }

    /*
    If we succeeded, delete or rename the original file, and rename the temporary file to the original location.
    If we failed, delete the temporary file.
    Do this itself in separate phases, so that if the delete/rename fails, we still delete the temporary file.
    */
    // 1. Remove target. (It might not exist yet.)
    if (success && target.exists()) {
    
        if (keepOld) {
        
            try {
                target.renameToNode(keptFileNode);
            } catch (const VException& ex) {
                success = false;
                errorMessage = VSTRING_FORMAT("Failed renaming '%s' to '%s': %s", target.getPath().chars(), keptFileNode.getPath().chars(), ex.what());
            }

        } else {

            if (! target.rm()) {
                success = false;
                errorMessage = VSTRING_FORMAT("Unable to remove target file '%s'.", target.getPath().chars());
            }

        }
    
    }

    // 2. Rename temporary to (original) target.
    if (success) {
        try {
            temporaryFileNode.renameToNode(originalTargetNode);
        } catch (const VException& ex) {
            success = false;
            errorMessage = VSTRING_FORMAT("Failed renaming '%s' to '%s': %s", temporaryFileNode.getPath().chars(), originalTargetNode.getPath().chars(), ex.what());
        }
    }

    // 3. Remove temporary if unsuccessful.
    if (! success) {
        if (! temporaryFileNode.rm()) {
            errorMessage += VSTRING_FORMAT(" Removal of temporary file '%s' failed.", temporaryFileNode.getPath().chars());
        }
    }

    // If we failed, throw an exception with the error message we built wherever we encountered errors.
    if (! success) {
        throw VException(errorMessage);
    }
}