<commit_before>/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2013, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.as.patching.runner;

import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

import org.jboss.as.patching.logging.PatchLogger;
import org.wildfly.security.manager.WildFlySecurityManager;

import static org.jboss.as.patching.runner.PatchUtils.BACKUP_EXT;
import static org.jboss.as.patching.runner.PatchUtils.JAR_EXT;

/**
 * Cripple a JAR or other zip file by flipping a bit in the end of central directory record
 * This process can be reversed by flipping the bit back. Useful for rendering JARs non-executable.
 *
 * based on the org.jboss.as.server.deployment.scanner.ZipCompletionScanner
 *
 * @author <NAME>
 * @author <NAME>enhuber
 */
class PatchModuleInvalidationUtils {

    private static final boolean ENABLE_INVALIDATION = Boolean.parseBoolean(WildFlySecurityManager.getPropertyPrivileged("org.wildfly.patching.jar.invalidation", "false"));

    /**
     * Local file header marker
     */
    public static final long LOCSIG = 0x04034b50L;
    /**
     * Extra data descriptor marker
     */
    public static final long EXTSIG = 0x08074b50L;
    /**
     * Central directory file header marker
     */
    public static final long CENSIG = 0x02014b50L;

    /**
     * End of central directory record marker
     */
    public static final int GOOD_ENDSIG = 0x06054b50; // Good signature
    public static final int CRIPPLED_ENDSIG = 0x07054b50; // Crippled signature

    /**
     * Length of the fixed portion of a local file header
     */
    public static final int LOCLEN = 30;
    /**
     * Length of the fixed portion of a central directory file header
     */
    public static final int CENLEN = 46;
    /**
     * Length of the fixed portion of an End of central directory record
     */
    public static final int ENDLEN = 22;

    /**
     * Position of the filename length in a local file header
     */
    public static final int LOC_FILENAMELEN = 26;
    /**
     * Position of the extra field length in a local file header
     */
    public static final int LOC_EXTFLDLEN = 28;

    /**
     * Position of the associated local file's compressed size in the central directory file header
     */
    public static final int CENSIZ = 20;
    /**
     * Position of the associated local file's offset in the central directory file header
     */
    public static final int CEN_LOC_OFFSET = 32;

    /**
     * Position of the 'start of central directory' field in an end of central directory record
     */
    public static final int END_CENSTART = 16;
    /**
     * END_CENSTART value that indicates the zip is in ZIP 64 format
     */
    public static final long ZIP64_MARKER = 0xFFFFFFFFL;
    /**
     * Position of the comment length in an end of central directory record
     */
    public static final int END_COMMENTLEN = 20;

    private static final int MAX_REVERSE_SCAN = (1 << 16) + ENDLEN;
    private static final int CHUNK_SIZE = 4096;
    private static final int ALPHABET_SIZE = 256;

    private static final byte[] GOOD_ENDSIG_PATTERN = new byte[]{0x06, 0x05, 0x4b, 0x50}; // good signature
    private static final byte[] CRIPPLED_ENDSIG_PATTERN = new byte[]{0x07, 0x05, 0x4b, 0x50}; // crippled signature
    private static final int SIG_PATTERN_LENGTH = 4;

    private static final int[] BAD_BYTE_SKIP = new int[ALPHABET_SIZE];

    private static final byte[] LOCSIG_PATTERN = new byte[]{0x50, 0x4b, 0x03, 0x04};
    private static final int[] LOC_BAD_BYTE_SKIP = new int[ALPHABET_SIZE];

    static {
        // Set up the Boyer Moore "bad character arrays" for our 3 patterns
//        computeBadByteSkipArray(GOOD_ENDSIG_PATTERN, GOOD_END_BAD_BYTE_SKIP);
//        computeBadByteSkipArray(CRIPPLED_ENDSIG_PATTERN, CRIPPLED_BAD_BYTE_SKIP);
        computeBadByteSkipArray(GOOD_ENDSIG_PATTERN, CRIPPLED_ENDSIG_PATTERN, BAD_BYTE_SKIP);
        computeBadByteSkipArray(LOCSIG_PATTERN, LOC_BAD_BYTE_SKIP);
    }

    /**
     * Prevent instantiation
     */
    private PatchModuleInvalidationUtils() {
    }

    /**
     * Process a file.
     *
     * @param file the file to be processed
     * @param mode the patching mode
     * @throws IOException
     */
    static void processFile(final IdentityPatchContext context, final File file, final PatchingTaskContext.Mode mode) throws IOException {
        if (mode == PatchingTaskContext.Mode.APPLY) {
            if (ENABLE_INVALIDATION) {
                updateJar(file, GOOD_ENDSIG_PATTERN, BAD_BYTE_SKIP, CRIPPLED_ENDSIG, GOOD_ENDSIG);
                backup(context, file);
            }
        } else if (mode == PatchingTaskContext.Mode.ROLLBACK) {
            updateJar(file, CRIPPLED_ENDSIG_PATTERN, BAD_BYTE_SKIP, GOOD_ENDSIG, CRIPPLED_ENDSIG);
            restore(context, file);
        } else {
            throw new IllegalStateException();
        }
    }

    /**
     * Update the central directory signature of a .jar.
     *
     * @param file          the file to process
     * @param searchPattern the search patter to use
     * @param badSkipBytes  the bad bytes skip table
     * @param newSig        the new signature
     * @param endSig        the expected signature
     * @throws IOException
     */
    private static void updateJar(final File file, final byte[] searchPattern, final int[] badSkipBytes, final int newSig, final int endSig) throws IOException {
        final RandomAccessFile raf = new RandomAccessFile(file, "rw");
        try {
            final FileChannel channel = raf.getChannel();
            try {
                long pos = channel.size() - ENDLEN;
                final ScanContext context;
                if (newSig == CRIPPLED_ENDSIG) {
                    context = new ScanContext(GOOD_ENDSIG_PATTERN, CRIPPLED_ENDSIG_PATTERN);
                } else if (newSig == GOOD_ENDSIG) {
                    context = new ScanContext(CRIPPLED_ENDSIG_PATTERN, GOOD_ENDSIG_PATTERN);
                } else {
                    context = null;
                }

                if (!validateEndRecord(file, channel, pos, endSig)) {
                    pos = scanForEndSig(file, channel, context);
                }
                if (pos == -1) {<commit_msg>[WFCORE-5520] Avoid Nullpointer (Patching)<commit_after>/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2013, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.as.patching.runner;

import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

import org.jboss.as.patching.logging.PatchLogger;
import org.wildfly.security.manager.WildFlySecurityManager;

import static org.jboss.as.patching.runner.PatchUtils.BACKUP_EXT;
import static org.jboss.as.patching.runner.PatchUtils.JAR_EXT;

/**
 * Cripple a JAR or other zip file by flipping a bit in the end of central directory record
 * This process can be reversed by flipping the bit back. Useful for rendering JARs non-executable.
 *
 * based on the org.jboss.as.server.deployment.scanner.ZipCompletionScanner
 *
 * @author <NAME>
 * @author <NAME>
 */
class PatchModuleInvalidationUtils {

    private static final boolean ENABLE_INVALIDATION = Boolean.parseBoolean(WildFlySecurityManager.getPropertyPrivileged("org.wildfly.patching.jar.invalidation", "false"));

    /**
     * Local file header marker
     */
    public static final long LOCSIG = 0x04034b50L;
    /**
     * Extra data descriptor marker
     */
    public static final long EXTSIG = 0x08074b50L;
    /**
     * Central directory file header marker
     */
    public static final long CENSIG = 0x02014b50L;

    /**
     * End of central directory record marker
     */
    public static final int GOOD_ENDSIG = 0x06054b50; // Good signature
    public static final boolean FLAG_GOOD_ENDSIG = false;
    public static final int CRIPPLED_ENDSIG = 0x07054b50; // Crippled signature
    public static final boolean FLAG_CRIPPLED_ENDSIG = true;

    /**
     * Length of the fixed portion of a local file header
     */
    public static final int LOCLEN = 30;
    /**
     * Length of the fixed portion of a central directory file header
     */
    public static final int CENLEN = 46;
    /**
     * Length of the fixed portion of an End of central directory record
     */
    public static final int ENDLEN = 22;

    /**
     * Position of the filename length in a local file header
     */
    public static final int LOC_FILENAMELEN = 26;
    /**
     * Position of the extra field length in a local file header
     */
    public static final int LOC_EXTFLDLEN = 28;

    /**
     * Position of the associated local file's compressed size in the central directory file header
     */
    public static final int CENSIZ = 20;
    /**
     * Position of the associated local file's offset in the central directory file header
     */
    public static final int CEN_LOC_OFFSET = 32;

    /**
     * Position of the 'start of central directory' field in an end of central directory record
     */
    public static final int END_CENSTART = 16;
    /**
     * END_CENSTART value that indicates the zip is in ZIP 64 format
     */
    public static final long ZIP64_MARKER = 0xFFFFFFFFL;
    /**
     * Position of the comment length in an end of central directory record
     */
    public static final int END_COMMENTLEN = 20;

    private static final int MAX_REVERSE_SCAN = (1 << 16) + ENDLEN;
    private static final int CHUNK_SIZE = 4096;
    private static final int ALPHABET_SIZE = 256;

    private static final byte[] GOOD_ENDSIG_PATTERN = new byte[]{0x06, 0x05, 0x4b, 0x50}; // good signature
    private static final byte[] CRIPPLED_ENDSIG_PATTERN = new byte[]{0x07, 0x05, 0x4b, 0x50}; // crippled signature
    private static final int SIG_PATTERN_LENGTH = 4;

    private static final int[] BAD_BYTE_SKIP = new int[ALPHABET_SIZE];

    private static final byte[] LOCSIG_PATTERN = new byte[]{0x50, 0x4b, 0x03, 0x04};
    private static final int[] LOC_BAD_BYTE_SKIP = new int[ALPHABET_SIZE];

    static {
        // Set up the Boyer Moore "bad character arrays" for our 3 patterns
//        computeBadByteSkipArray(GOOD_ENDSIG_PATTERN, GOOD_END_BAD_BYTE_SKIP);
//        computeBadByteSkipArray(CRIPPLED_ENDSIG_PATTERN, CRIPPLED_BAD_BYTE_SKIP);
        computeBadByteSkipArray(GOOD_ENDSIG_PATTERN, CRIPPLED_ENDSIG_PATTERN, BAD_BYTE_SKIP);
        computeBadByteSkipArray(LOCSIG_PATTERN, LOC_BAD_BYTE_SKIP);
    }

    /**
     * Prevent instantiation
     */
    private PatchModuleInvalidationUtils() {
    }

    /**
     * Process a file.
     *
     * @param file the file to be processed
     * @param mode the patching mode
     * @throws IOException
     */
    static void processFile(final IdentityPatchContext context, final File file, final PatchingTaskContext.Mode mode) throws IOException {
        if (mode == PatchingTaskContext.Mode.APPLY) {
            if (ENABLE_INVALIDATION) {
                updateJar(file, GOOD_ENDSIG_PATTERN, BAD_BYTE_SKIP, FLAG_CRIPPLED_ENDSIG, GOOD_ENDSIG);
                backup(context, file);
            }
        } else if (mode == PatchingTaskContext.Mode.ROLLBACK) {
            updateJar(file, CRIPPLED_ENDSIG_PATTERN, BAD_BYTE_SKIP, FLAG_GOOD_ENDSIG, CRIPPLED_ENDSIG);
            restore(context, file);
        } else {
            throw new IllegalStateException();
        }
    }

    /**
     * Update the central directory signature of a .jar.
     *
     * @param file          the file to process
     * @param searchPattern the search patter to use
     * @param badSkipBytes  the bad bytes skip table
     * @param flagNewSig    true for CRIPPLED_ENDSIG, false for a GOOD_ENDSIG as newSig
     * @param endSig        the expected signature
     * @throws IOException
     */
    private static void updateJar(final File file, final byte[] searchPattern, final int[] badSkipBytes, final boolean flagNewSig, final int endSig) throws IOException {
        final RandomAccessFile raf = new RandomAccessFile(file, "rw");
        try {
            final FileChannel channel = raf.getChannel();
            try {
                long pos = channel.size() - ENDLEN;
                final ScanContext context;
                final int newSig;
                if (flagNewSig) {
                    context = new ScanContext(GOOD_ENDSIG_PATTERN, CRIPPLED_ENDSIG_PATTERN);
                    newSig = CRIPPLED_ENDSIG;
                } else  {
                    context = new ScanContext(CRIPPLED_ENDSIG_PATTERN, GOOD_ENDSIG_PATTERN);
                    newSig = GOOD_ENDSIG;
                }

                if (!validateEndRecord(file, channel, pos, endSig)) {
                    pos = scanForEndSig(file, channel, context);
                }
                if (pos == -1) {
{'fraction_non_alphanumeric': 0.07463685654996988, 'fraction_numerical': 0.017136354508333892, 'mean_word_length': 2.7774968394437423, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, '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': '4944311', 'n_tokens_mistral': 4538, 'n_tokens_neox': 4221, 'n_words': 1485}