// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.config.model.application.provider; import com.fasterxml.jackson.databind.ObjectMapper; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.io.IOUtils; import com.yahoo.path.Path; import com.yahoo.vespa.config.util.ConfigUtils; import com.yahoo.yolean.Exceptions; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * @author Ulf Lilleengen * @author Vegard Havdal */ public class FilesApplicationFile extends ApplicationFile { private static final Logger log = Logger.getLogger("FilesApplicationFile"); private final File file; private final ObjectMapper mapper = new ObjectMapper(); public FilesApplicationFile(Path path, File file) { super(path); this.file = file; } @Override public boolean isDirectory() { return file.isDirectory(); } @Override public boolean exists() { return file.exists(); } @Override public ApplicationFile delete() { log.log(Level.FINE, () -> "Delete " + file); if (file.isDirectory() && !listFiles().isEmpty()) { throw new RuntimeException("files. Can't delete, directory not empty: " + this + "(" + listFiles() + ")." + listFiles().size()); } if (file.isDirectory() && file.listFiles() != null && file.listFiles().length > 0) { for (File f : file.listFiles()) { deleteFile(f); } } if (!file.delete()) { throw new IllegalStateException("Unable to delete: "+this); } try { writeMetaFile("", ApplicationFile.ContentStatusDeleted); } catch (IOException e) { throw new RuntimeException(e); } return this; } public static boolean deleteFile(File path) { if( path.exists() ) { if (path.isDirectory()) { File[] files = path.listFiles(); for(int i=0; i listFiles(final PathFilter filter) { List files = new ArrayList<>(); if (!file.isDirectory()) { return files; } FileFilter fileFilter = pathname -> filter.accept(path.append(pathname.getName())); for (File child : file.listFiles(fileFilter)) { // Ignore dot-files. if (!child.getName().startsWith(".")) { files.add(new FilesApplicationFile(path.append(child.getName()), child)); } } return files; } private void writeMetaFile(String data, String status) throws IOException { File metaDir = createMetaDir(); log.log(Level.FINE, () -> "meta dir=" + metaDir); File metaFile = new File(metaDir + "/" + getPath().getName()); if (status == null) { status = ApplicationFile.ContentStatusNew; if (metaFile.exists()) { status = ApplicationFile.ContentStatusChanged; } } String hash; if (file.isDirectory() || status.equals(ApplicationFile.ContentStatusDeleted)) { hash = ""; } else { hash = ConfigUtils.getMd5(data); } mapper.writeValue(metaFile, new MetaData(status, hash)); } private File createMetaDir() { File metaDir = getMetaDir(); if (!metaDir.exists()) { log.log(Level.FINE, () -> "Creating meta dir " + metaDir); metaDir.mkdirs(); } return metaDir; } private File getMetaDir() { String substring = file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf("/") + 1); return new File(substring + Path.fromString(".meta/")); } public MetaData getMetaData() { File metaDir = getMetaDir(); File metaFile = new File(metaDir + "/" + getPath().getName()); log.log(Level.FINE, () -> "Getting metadata for " + metaFile); if (metaFile.exists()) { try { return mapper.readValue(metaFile, MetaData.class); } catch (IOException e) { System.out.println("whot:" + Exceptions.toMessageString(e)); // return below } } try { if (file.isDirectory()) { return new MetaData(ApplicationFile.ContentStatusNew, ""); } else { return new MetaData(ApplicationFile.ContentStatusNew, ConfigUtils.getMd5(IOUtils.readAll(createReader()))); } } catch (IOException | IllegalArgumentException e) { return null; } } @Override public long getSize() { return file.length(); } @Override public int compareTo(ApplicationFile other) { if (other == this) return 0; return this.getPath().getName().compareTo((other).getPath().getName()); } }