<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.sshd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Vector;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import org.apache.sshd.client.SftpClient;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.util.BaseTest;
import org.apache.sshd.util.BogusPasswordAuthenticator;
import org.apache.sshd.util.EchoShellFactory;
import org.apache.sshd.util.JSchLogger;
import org.apache.sshd.util.SimpleUserInfo;
import org.apache.sshd.util.Utils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.*;

public class SftpTest extends BaseTest {

    private SshServer sshd;
    private int port;
    private com.jcraft.jsch.Session session;

    @Before
    public void setUp() throws Exception {
        sshd = SshServer.setUpDefaultServer();
        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
        sshd.setCommandFactory(new ScpCommandFactory());
        sshd.setShellFactory(new EchoShellFactory());
        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
        sshd.start();
        port = sshd.getPort();

        JSchLogger.init();
        JSch sch = new JSch();
        session = sch.getSession("sshd", "localhost", port);
        session.setUserInfo(new SimpleUserInfo("sshd"));
        session.connect();
    }

    @After
    public void tearDown() throws Exception {
        session.disconnect();
        sshd.stop(true);
    }

    @Test
    @Ignore
    public void testExternal() throws Exception {
        System.out.println("SFTP subsystem available on port " + port);
        Thread.sleep(5 * 60000);
    }

    @Test
    public void testOpen() throws Exception {
        SshClient client = SshClient.setUpDefaultClient();
        client.start();
        ClientSession session = client.connect("x", "localhost", port).await().getSession();
        session.addPasswordIdentity("x");
        session.auth().verify();

        String file = "target/sftp/client/test.txt";

        new File(file).getParentFile().mkdirs();
        new File(file).createNewFile();
        new File(file).setWritable(false, false);
        new File(file).setReadable(false, false);

        SftpClient sftp = session.createSftpClient();
        SftpClient.Handle h;

        try {
            sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
            fail("Should have failed");
        } catch (IOException e) {
            // ok
        }

        try {
            sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
            fail("Should have failed");
        } catch (IOException e) {
            // ok
        }

        try {
            sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
            fail("Should have failed");
        } catch (IOException e) {
            // ok
        }

        Assert.assertEquals(0, (sftp.stat(file).perms & (SftpClient.S_IWUSR | SftpClient.S_IRUSR)));

        new File(file).setWritable(true, false);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
        sftp.close(h);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        byte[] d = "0123456789\n".getBytes();
        sftp.write(h, 0, d, 0, d.length);
        sftp.write(h, d.length, d, 0, d.length);
        sftp.close(h);
        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        sftp.write(h, d.length * 2, d, 0, d.length);
        sftp.close(h);
        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        sftp.write(h, 3, "-".getBytes(), 0, 1);
        sftp.close(h);

        try {
            sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
            fail("Should have failed");
        } catch (IOException e) {
            // ok
        }

        new File(file).setReadable(true, false);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
        byte[] buf = new byte[3];
        int l = sftp.read(h, 2l, buf, 0, 3);
        assertEquals("2-4", new String(buf, 0, l));
        sftp.close(h);
    }

    @Test
    public void testClient() throws Exception {
        SshClient client = SshClient.setUpDefaultClient();
        client.start();
        ClientSession session = client.connect("x", "localhost", port).await().getSession();
        session.addPasswordIdentity("x");
        session.auth().verify();

        Utils.deleteRecursive(new File("target/sftp"));
        new File("target/sftp").mkdirs();
        new File("target/sftp/client/test.txt").delete();
        new File("target/sftp/client").delete();

        SftpClient sftp = session.createSftpClient();

        sftp.mkdir("target/sftp/client");

        SftpClient.Handle h = sftp.open("target/sftp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
        byte[] d = "0123456789\n".getBytes();
        sftp.write(h, 0, d, 0, d.length);
        sftp.write(h, d.length, d, 0, d.length);
<commit_msg>[SSHD-396] Fixed SftpTest#testOpen to work correctly on Windows<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.sshd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Vector;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import org.apache.sshd.client.SftpClient;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.util.BaseTest;
import org.apache.sshd.util.BogusPasswordAuthenticator;
import org.apache.sshd.util.EchoShellFactory;
import org.apache.sshd.util.JSchLogger;
import org.apache.sshd.util.SimpleUserInfo;
import org.apache.sshd.util.Utils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.*;

public class SftpTest extends BaseTest {

    private SshServer sshd;
    private int port;
    private com.jcraft.jsch.Session session;

    @Before
    public void setUp() throws Exception {
        sshd = SshServer.setUpDefaultServer();
        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
        sshd.setCommandFactory(new ScpCommandFactory());
        sshd.setShellFactory(new EchoShellFactory());
        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
        sshd.start();
        port = sshd.getPort();

        JSchLogger.init();
        JSch sch = new JSch();
        session = sch.getSession("sshd", "localhost", port);
        session.setUserInfo(new SimpleUserInfo("sshd"));
        session.connect();
    }

    @After
    public void tearDown() throws Exception {
        session.disconnect();
        sshd.stop(true);
    }

    @Test
    @Ignore
    public void testExternal() throws Exception {
        System.out.println("SFTP subsystem available on port " + port);
        Thread.sleep(5 * 60000);
    }

    @Test
    public void testOpen() throws Exception {
        SshClient client = SshClient.setUpDefaultClient();
        client.start();
        ClientSession session = client.connect("x", "localhost", port).await().getSession();
        session.addPasswordIdentity("x");
        session.auth().verify();

        String file = "target/sftp/client/testOpen.txt";
        File javaFile = new File(file);

        javaFile.getParentFile().mkdirs();
        javaFile.createNewFile();
        javaFile.setWritable(false, false);
        javaFile.setReadable(false, false);

        SftpClient sftp = session.createSftpClient();
        SftpClient.Handle h;

        boolean	isWindows = OsUtils.isWin32();

        try {
            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
            // NOTE: on Windows files are always readable
            // see https://svn.apache.org/repos/asf/harmony/enhanced/java/branches/java6/classlib/modules/luni/src/test/api/windows/org/apache/harmony/luni/tests/java/io/WinFileTest.java
            Assert.assertTrue("Empty read should have failed", isWindows);
            sftp.close(h);
        } catch (IOException e) {
            if (isWindows) {
                throw e;
            }
        }

        try {
            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
            fail("Empty write should have failed");
        } catch (IOException e) {
            // ok
        }

        try {
            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate));
            fail("Empty truncate should have failed");
        } catch (IOException e) {
            // ok
        }

        // NOTE: on Windows files are always readable
        int	perms=sftp.stat(file).perms;
        int	permsMask=SftpClient.S_IWUSR | (isWindows ? 0 : SftpClient.S_IRUSR);
        Assert.assertEquals("Mismatched permissions - 0x" + Integer.toHexString(perms), 0, (perms & permsMask));

        javaFile.setWritable(true, false);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write));
        sftp.close(h);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        byte[] d = "0123456789\n".getBytes();
        sftp.write(h, 0, d, 0, d.length);
        sftp.write(h, d.length, d, 0, d.length);
        sftp.close(h);
        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        sftp.write(h, d.length * 2, d, 0, d.length);
        sftp.close(h);
        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write));
        sftp.write(h, 3, "-".getBytes(), 0, 1);
        sftp.close(h);

        try {
            h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
            // NOTE: on Windows files are always readable
            Assert.assertTrue("Data read should have failed", isWindows);
            sftp.close(h);
        } catch (IOException e) {
            if (isWindows) {
                throw e;
            }
        }

        javaFile.setReadable(true, false);

        h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Read));
        byte[] buf = new byte[3];
        int l = sftp.read(h, 2l, buf, 0, 3);
        assertEquals("Mismatched read data", "2-4", new String(buf, 0, l));
        sftp.close(h);
    }

    @Test
    public void testClient() throws Exception {
        SshClient client = SshClient.setUpDefaultClient();
        client.start();
        ClientSession session = client.connect("x", "localhost", port).await().getSession();
        session.addPasswordIdentity("x");
        session.auth().verify();

        Utils.deleteRecursive(new File("target/sftp"));
        new File("target/sftp").mkdirs();
        new File("target/sftp/client/test.txt").delete();
        new File("target/sftp/client").delete();

        SftpClient sftp = session.createSftpClient();

        sftp.mkdir("target/sftp/client");

        SftpClient.Handle h = sftp.open("target/sftp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create));
        byte[] d = "0123456789\n".getBytes();
        sftp.write(h, 0, d, 0, d.length);
        sftp.write(h, d.length, d, 0, d.length);

{'fraction_non_alphanumeric': 0.12454500035686246, 'fraction_numerical': 0.007565484262365285, 'mean_word_length': 2.847336628226249, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1688064', 'n_tokens_mistral': 4519, 'n_tokens_neox': 4216, 'n_words': 962}