001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.internal.impl;
020
021import javax.inject.Named;
022import javax.inject.Singleton;
023
024import java.io.*;
025import java.nio.ByteBuffer;
026import java.nio.charset.StandardCharsets;
027import java.nio.file.Files;
028import java.nio.file.StandardCopyOption;
029
030import org.eclipse.aether.spi.io.FileProcessor;
031import org.eclipse.aether.util.FileUtils;
032
033/**
034 * A utility class helping with file-based operations.
035 *
036 * @deprecated
037 */
038@Deprecated
039@Singleton
040@Named
041public class DefaultFileProcessor implements FileProcessor {
042
043    /**
044     * Thread-safe variant of {@link File#mkdirs()}. Creates the directory named by the given abstract pathname,
045     * including any necessary but nonexistent parent directories. Note that if this operation fails it may have
046     * succeeded in creating some of the necessary parent directories.
047     *
048     * @param directory The directory to create, may be {@code null}.
049     * @return {@code true} if and only if the directory was created, along with all necessary parent directories;
050     * {@code false} otherwise
051     */
052    @Override
053    public boolean mkdirs(File directory) {
054        if (directory == null) {
055            return false;
056        }
057
058        if (directory.exists()) {
059            return false;
060        }
061        if (directory.mkdir()) {
062            return true;
063        }
064
065        File canonDir;
066        try {
067            canonDir = directory.getCanonicalFile();
068        } catch (IOException e) {
069            throw new UncheckedIOException(e);
070        }
071
072        File parentDir = canonDir.getParentFile();
073        return (parentDir != null && (mkdirs(parentDir) || parentDir.exists()) && canonDir.mkdir());
074    }
075
076    @Override
077    public void write(File target, String data) throws IOException {
078        FileUtils.writeFile(target.toPath(), p -> Files.write(p, data.getBytes(StandardCharsets.UTF_8)));
079    }
080
081    @Override
082    public void write(File target, InputStream source) throws IOException {
083        FileUtils.writeFile(target.toPath(), p -> Files.copy(source, p, StandardCopyOption.REPLACE_EXISTING));
084    }
085
086    @Override
087    public void copy(File source, File target) throws IOException {
088        copy(source, target, null);
089    }
090
091    @Override
092    public long copy(File source, File target, ProgressListener listener) throws IOException {
093        try (InputStream in = new BufferedInputStream(Files.newInputStream(source.toPath()));
094                FileUtils.CollocatedTempFile tempTarget = FileUtils.newTempFile(target.toPath());
095                OutputStream out = new BufferedOutputStream(Files.newOutputStream(tempTarget.getPath()))) {
096            long result = copy(out, in, listener);
097            tempTarget.move();
098            return result;
099        }
100    }
101
102    private long copy(OutputStream os, InputStream is, ProgressListener listener) throws IOException {
103        long total = 0L;
104        byte[] buffer = new byte[1024 * 32];
105        while (true) {
106            int bytes = is.read(buffer);
107            if (bytes < 0) {
108                break;
109            }
110
111            os.write(buffer, 0, bytes);
112
113            total += bytes;
114
115            if (listener != null && bytes > 0) {
116                try {
117                    listener.progressed(ByteBuffer.wrap(buffer, 0, bytes));
118                } catch (Exception e) {
119                    // too bad
120                }
121            }
122        }
123
124        return total;
125    }
126
127    @Override
128    public void move(File source, File target) throws IOException {
129        if (!source.renameTo(target)) {
130            copy(source, target);
131
132            target.setLastModified(source.lastModified());
133
134            source.delete();
135        }
136    }
137
138    @Override
139    public String readChecksum(final File checksumFile) throws IOException {
140        // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
141        String checksum = "";
142        try (BufferedReader br = new BufferedReader(
143                new InputStreamReader(Files.newInputStream(checksumFile.toPath()), StandardCharsets.UTF_8), 512)) {
144            while (true) {
145                String line = br.readLine();
146                if (line == null) {
147                    break;
148                }
149                line = line.trim();
150                if (!line.isEmpty()) {
151                    checksum = line;
152                    break;
153                }
154            }
155        }
156
157        if (checksum.matches(".+= [0-9A-Fa-f]+")) {
158            int lastSpacePos = checksum.lastIndexOf(' ');
159            checksum = checksum.substring(lastSpacePos + 1);
160        } else {
161            int spacePos = checksum.indexOf(' ');
162
163            if (spacePos != -1) {
164                checksum = checksum.substring(0, spacePos);
165            }
166        }
167
168        return checksum;
169    }
170
171    @Override
172    public void writeChecksum(final File checksumFile, final String checksum) throws IOException {
173        // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
174        write(checksumFile, checksum);
175    }
176}