Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

control rpm verification flags #6

Merged
merged 6 commits into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion rpm/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>

<!-- show log output during tests using logback as the slfj backend. -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
65 changes: 65 additions & 0 deletions rpm/src/main/java/org/eclipse/packager/rpm/VerifyFlags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.packager.rpm;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sorry I overlooked this before, but this file is missing a license header.


/**
* Constants to identify the RPM verification flags.
* See https://github.com/ctron/rpm-builder/issues/41
* The name of this enum is questionable.
* It should rather be "VerifyFlag" (singular), but I leave it this way, cf. {@link FileFlags}.
* The constants and their value are from http://ftp.rpm.org/api/4.14.0/group__rpmvf.html
* @since 0.15.2
*/
public enum VerifyFlags
{
// The following constants control the verify flags.
// Each bit corresponds to an upper case character in the output of "rpm -V ..."
MD5( 1 << 0), // '5'
SIZE( 1 << 1), // 'S'
LINKTO(1 << 2), // 'L'
USER( 1 << 3), // 'U'
GROUP( 1 << 4), // 'G'
MTIME( 1 << 5), // 'T'
MODE( 1 << 6), // 'M'
RDEV( 1 << 7), // 'D'
CAPS( 1 << 8), // 'P'

// The purpose of the following constants is not clear to me.
// Do they refer to the same bitmask? Oliver Matz
// see discussion in https://github.com/eclipse/packager/pull/6
VERIFY_CONTEXTS (1 << 15),
VERIFY_FILES (1 << 16),
VERIFY_DEPS (1 << 17),
VERIFY_SCRIPT (1 << 18),
VERIFY_DIGEST (1 << 19),
VERIFY_SIGNATURE (1 << 20),
VERIFY_PATCHES (1 << 21),
VERIFY_HDRCHK (1 << 22),
VERIFY_FOR_LIST (1 << 23),
VERIFY_FOR_STATE (1 << 24),
VERIFY_FOR_DOCS (1 << 25),
VERIFY_FOR_CONFIG (1 << 26),
VERIFY_FOR_DUMPFILES (1 << 27);

private final int value;

VerifyFlags( final int value)
{
this.value = value;
}

public int getValue()
{
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Set;

import org.eclipse.packager.rpm.FileFlags;
import org.eclipse.packager.rpm.VerifyFlags;

public class FileInformation
{
Expand All @@ -29,6 +30,12 @@ public class FileInformation

private Set<FileFlags> fileFlags = EnumSet.noneOf ( FileFlags.class );

// https://github.com/ctron/rpm-builder/issues/41
/**
* If null (default), this will result in a bitmask with value -1.
*/
private Set<VerifyFlags> verifyFlags;

private short mode = 0644;

public void setTimestamp ( final Instant timestamp )
Expand Down Expand Up @@ -77,6 +84,43 @@ public Set<FileFlags> getFileFlags ()
return this.fileFlags;
}

/**
* verify flags control the verify behaviour, i.e. <code>rpm -V ...</code>.
* See https://github.com/ctron/rpm-builder/issues/41
* <br>
* The value null restores the default.
* This will result in a bitmask with value -1, so the RPM tool will then verify everything it knows of,
* not only what this library knows of.
* Thus there is a subtle difference between passing <code>null</code> and passing <code>EnumSet.allOf(VerifyFlags.class)</code>
* @param verifyFlags set of VerifyFlags, maybe null.
* @since 0.15.2
*/
public void setVerifyFlags ( final Set<VerifyFlags> verifyFlags )
{
if (verifyFlags == null)
{
this.verifyFlags = null;
}
else if ( verifyFlags.isEmpty () )
{
this.verifyFlags = EnumSet.noneOf ( VerifyFlags.class );
}
else
{
this.verifyFlags = EnumSet.copyOf ( verifyFlags );
}
}

/**
* If non-null, specifies the verification flags.
* Null (default) means: verify everything (old behaviour).
* @return maybe null
*/
public Set<VerifyFlags> getVerifyFlags ()
{
return this.verifyFlags;
}

public void setUser ( final String user )
{
this.user = user;
Expand Down
20 changes: 20 additions & 0 deletions rpm/src/main/java/org/eclipse/packager/rpm/build/RpmBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.eclipse.packager.rpm.RpmTag;
import org.eclipse.packager.rpm.RpmVersion;
import org.eclipse.packager.rpm.Rpms;
import org.eclipse.packager.rpm.VerifyFlags;
import org.eclipse.packager.rpm.build.PayloadRecorder.Result;
import org.eclipse.packager.rpm.deps.Dependencies;
import org.eclipse.packager.rpm.deps.Dependency;
Expand Down Expand Up @@ -659,6 +660,25 @@ protected void customizeFile ( final FileEntry entry, final FileInformation info
entry.setFlags ( entry.getFlags () | fileFlag.getValue () );
}
}
customizeVerificationFlags(entry, information);
}

/**
* see https://github.com/ctron/rpm-builder/issues/41
* @since 0.15.2
*/
private void customizeVerificationFlags(FileEntry entry, FileInformation information) {
final Collection<VerifyFlags> informationVerifyFlags = information.getVerifyFlags();
if ( informationVerifyFlags == null )
{
return; // bail out - entry's verification flag bitmask will remain -1 (meaning: verify everthing)
}
int bitmask = 0;
for (final VerifyFlags verifyFlag : informationVerifyFlags)
{
bitmask |= verifyFlag.getValue();
}
entry.setVerifyFlags(bitmask);
}

protected void customizeSymbolicLink ( final FileEntry entry, final FileInformation information )
Expand Down
113 changes: 113 additions & 0 deletions rpm/src/test/java/org/eclipse/packager/rpm/SetVerifyFlagsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.packager.rpm;
OliverMatz marked this conversation as resolved.
Show resolved Hide resolved

import org.eclipse.packager.rpm.app.Dumper;
import org.eclipse.packager.rpm.build.FileInformation;
import org.eclipse.packager.rpm.build.RpmBuilder;
import org.eclipse.packager.rpm.parse.InputHeader;
import org.eclipse.packager.rpm.parse.RpmInputStream;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

/**
* see https://github.com/ctron/rpm-builder/issues/41
*/
class SetVerifyFlagsTest
{
private final static Logger LOGGER = LoggerFactory.getLogger ( SetVerifyFlagsTest.class );

private static final Path OUT_BASE = Paths.get ( "target", "data", "out" );

@BeforeAll
static void setup () throws IOException
{
Files.createDirectories ( OUT_BASE );
}

private static final String DIRNAME = "/opt/testing/";
private static final String NAME_myconf = "my.conf";
private static final String NAME_myreadme = "readme.txt";

/**
* Firstly, writes a RPM file with two file entries having different type flags and different verification flags;
* Secondly, read that RPM file and verify the flags.
*/
@Test
void writeRpmWithVerifyFlags () throws IOException
{
final Path outFile;
try ( RpmBuilder builder = new RpmBuilder ( "vflag0-test", "1.0.0", "1", "noarch", OUT_BASE ) )
{
final String content_myconf = "Hallo, myconf!";
builder.newContext().addFile(DIRNAME + NAME_myconf, content_myconf.getBytes(), (targetName, object, type) -> {
if ((DIRNAME + NAME_myconf).equals(targetName)) {
final FileInformation ret = new FileInformation();
final Set<FileFlags> fileFlags = new HashSet<>(
Arrays.asList(FileFlags.CONFIGURATION, FileFlags.NOREPLACE));
ret.setFileFlags(fileFlags);
ret.setUser("conf_user");
ret.setGroup("conf_group");
final Set<VerifyFlags> verifyFlags = new HashSet<>(
Arrays.asList(VerifyFlags.USER, VerifyFlags.GROUP));
ret.setVerifyFlags(verifyFlags);
LOGGER.info("file info for {}: {}", targetName, ret);
return ret;
}
throw new IllegalArgumentException("unexpected target name: " + targetName);
});
final String content_readme = "Hallo, readme!";
builder.newContext().addFile(DIRNAME + NAME_myreadme, content_readme.getBytes(), (targetName, object, type) -> {
if ((DIRNAME + NAME_myreadme).equals(targetName)) {
final FileInformation ret = new FileInformation();
final Set<FileFlags> fileFlags = new HashSet<>(Collections.singletonList(FileFlags.README));
ret.setFileFlags(fileFlags);
LOGGER.info("file info for {}: {}", targetName, ret);
return ret;
}
throw new IllegalArgumentException("unexpected target name: " + targetName);
});
outFile = builder.getTargetFile ();
builder.build ();
LOGGER.info("Written: {}", outFile);
}

try ( final RpmInputStream in = new RpmInputStream ( new BufferedInputStream ( Files.newInputStream ( outFile ) ) ) )
{
Dumper.dumpAll ( in );
final InputHeader<RpmTag> header = in.getPayloadHeader ();
final String[] dirNames = (String[])header.getTag(RpmTag.DIRNAMES);
assertArrayEquals(new String[] {DIRNAME}, dirNames);
final String[] baseNames = (String[])header.getTag(RpmTag.BASENAMES);
assertArrayEquals(new String[] {NAME_myconf, NAME_myreadme}, baseNames);
final Integer[] fileFlags = (Integer[])header.getTag(RpmTag.FILE_FLAGS);
assertArrayEquals(new Integer[] {17, 256}, fileFlags); // 17: CONFIGURATION|NOREPLACE, 256: README
final Integer[] fileVerifyFlags = (Integer[])header.getTag(RpmTag.FILE_VERIFYFLAGS);
assertArrayEquals(new Integer[] {24, -1}, fileVerifyFlags); // 24: USER|GROUP, -1: <default>
}
}
}