/*
 * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* @test
 * @summary Ensure touching folder ACLs does not affect contained file
 * @requires (os.family == "windows")
 */

import java.io.InputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.AclFileAttributeView;
import java.util.Arrays;
import java.util.List;

import static java.nio.file.StandardOpenOption.READ;

public class TouchAcls {

    private static final String CMD = "C:\\windows\\system32\\icacls";
    private static final String FILE = ".md.truc";
    private static final byte[] BUF = new byte[1024];

    private static void execCmd(String[] cmdarray) throws Throwable {
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(cmdarray);
        try (InputStream input = proc.getInputStream()) {
            int n;
            while ((n = input.read(BUF)) != -1) {
                String s = new String(BUF, 0, n, "US-ASCII");
                System.out.printf("%s", s);
            }
        }
        proc.waitFor();
    }

    private static void touchAcl(Path p) throws IOException {
        System.out.println("Touching Acl at: " + p);
        AclFileAttributeView aclFileAttributes =
            Files.getFileAttributeView(p, AclFileAttributeView.class);
        aclFileAttributes.setAcl(aclFileAttributes.getAcl());
    }

    public static void main(String[] args) throws Throwable {
        // 1. create dir
        Path dir = Paths.get(System.getProperty("test.dir", "."));
        Path folder = Files.createTempDirectory(dir, "acltest");
        if (Files.exists(folder))
            System.out.printf("Directory created: %s%n", folder);
        folder.toFile().deleteOnExit();

        String[] cmdarray = new String[] {
            CMD, folder.toString()
        };
        execCmd(cmdarray);

        // 2. touch acl of the folder
        // note: if this is done AFTER file creation, then no issue
        touchAcl(folder);
        execCmd(cmdarray);

        // 3. create file
        Path fpath = folder.resolve(Paths.get(FILE));
        List<String> lines = Arrays.asList("Line one", "Line two");
        Files.write(fpath, lines, Charset.forName("UTF-8"));
        if (Files.exists(fpath))
            System.out.printf("File written: %s%n", fpath);
        fpath.toFile().deleteOnExit();

        // 4. read
        if (!Files.isReadable(folder))
            throw new RuntimeException(folder + " is unreadable");
        if (!Files.isReadable(fpath))
            throw new RuntimeException(fpath + " is unreadable");

        try (FileChannel fc = FileChannel.open(fpath, READ)) {
            System.out.println("Success opening file");
        }
    }
}
