Merge branch 'permissions'

FIXES #997
main
Adriaan de Groot 6 years ago
commit d507425128

@ -10,6 +10,7 @@ This release contains contributions from (alphabetically by first name):
- Caio Carvalho
- Kevin Kofler
- Philip Mueller
- Scott Harvey
## Core ##
@ -25,6 +26,8 @@ There are no core changes in this version.
size is close to the required installation size).
* The *keyboard* module now handles the (bogus) Austrian keymap for
the system console properly.
* The *preservefiles* module now has a mechanism for setting the permissions
(and ownership) of preserved files.
* New module *fsresizer* can be used to resize filesystems. It is intended
for use in OEM installs where an image of fixed size is created,
and then sized to the actual SD card the user has used.

@ -4,6 +4,7 @@ calamares_add_plugin( preservefiles
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
permissions.cpp
PreserveFiles.cpp
LINK_PRIVATE_LIBRARIES
calamares

@ -18,6 +18,8 @@
#include "PreserveFiles.h"
#include "permissions.h"
#include "CalamaresVersion.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
@ -83,6 +85,38 @@ PreserveFiles::prettyName() const
return tr( "Saving files for later ..." );
}
static bool
copy_file( const QString& source, const QString& dest )
{
QFile sourcef( source );
if ( !sourcef.open( QFile::ReadOnly ) )
{
cWarning() << "Could not read" << source;
return false;
}
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
return false;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
return true;
}
Calamares::JobResult PreserveFiles::exec()
{
if ( m_items.isEmpty() )
@ -96,7 +130,8 @@ Calamares::JobResult PreserveFiles::exec()
for ( const auto& it : m_items )
{
QString source = it.source;
QString dest = prefix + atReplacements( it.dest );
QString bare_dest = atReplacements( it.dest );
QString dest = prefix + bare_dest;
if ( it.type == ItemType::Log )
source = Logger::logFile();
@ -111,32 +146,29 @@ Calamares::JobResult PreserveFiles::exec()
cWarning() << "Skipping unnamed source file for" << dest;
else
{
QFile sourcef( source );
if ( !sourcef.open( QFile::ReadOnly ) )
{
cWarning() << "Could not read" << source;
continue;
}
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
if ( copy_file( source, dest ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
continue;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
if ( it.perm.isValid() )
{
auto s_p = CalamaresUtils::System::instance();
int r;
r = s_p->targetEnvCall( QStringList{ "chown", it.perm.username(), bare_dest } );
if ( r )
cWarning() << "Could not chown target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chgrp", it.perm.group(), bare_dest } );
if ( r )
cWarning() << "Could not chgrp target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chmod", it.perm.octal(), bare_dest } );
if ( r )
cWarning() << "Could not chmod target" << bare_dest;
}
++count;
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
++count;
}
}
@ -160,6 +192,10 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
return;
}
QString defaultPermissions = configurationMap[ "perm" ].toString();
if ( defaultPermissions.isEmpty() )
defaultPermissions = QStringLiteral( "root:root:0400" );
QVariantList l = files.toList();
unsigned int c = 0;
for ( const auto& li : l )
@ -168,7 +204,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
{
QString filename = li.toString();
if ( !filename.isEmpty() )
m_items.append( Item{ filename, filename, ItemType::Path } );
m_items.append( Item{ filename, filename, Permissions( defaultPermissions ), ItemType::Path } );
else
cDebug() << "Empty filename for preservefiles, item" << c;
}
@ -181,6 +217,9 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
( from == "log" ) ? ItemType::Log :
( from == "config" ) ? ItemType::Config :
ItemType::None;
QString perm = map[ "perm" ].toString();
if ( perm.isEmpty() )
perm = defaultPermissions;
if ( dest.isEmpty() )
{
@ -192,7 +231,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
}
else
{
m_items.append( Item{ QString(), dest, t } );
m_items.append( Item{ QString(), dest, Permissions( perm ), t } );
}
}
else

@ -24,11 +24,11 @@
#include <QVariantMap>
#include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h"
#include "PluginDllMacro.h"
#include "permissions.h"
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
@ -46,6 +46,7 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
QString source;
QString dest;
Permissions perm;
ItemType type;
} ;

@ -0,0 +1,75 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QString>
#include <QStringList>
#include "permissions.h"
Permissions::Permissions() :
m_username(),
m_group(),
m_valid(false),
m_value(0)
{
}
Permissions::Permissions(QString p) : Permissions()
{
parsePermissions(p);
}
void Permissions::parsePermissions(const QString& p) {
QStringList segments = p.split(":");
if (segments.length() != 3) {
m_valid = false;
return;
}
if (segments[0].isEmpty() || segments[1].isEmpty()) {
m_valid = false;
return;
}
bool ok;
int octal = segments[2].toInt(&ok, 8);
if (!ok || octal == 0) {
m_valid = false;
return;
} else {
m_value = octal;
}
// We have exactly three segments and the third is valid octal,
// so we can declare the string valid and set the user and group names
m_valid = true;
m_username = segments[0];
m_group = segments[1];
return;
}

@ -0,0 +1,62 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PERMISSIONS_H
#define PERMISSIONS_H
#include <QString>
/**
* @brief The Permissions class takes a QString @p in the form of
* <user>:<group>:<permissions>, checks it for validity, and makes the three
* components available indivdually.
*/
class Permissions
{
public:
/** @brief Constructor
*
* Splits the string @p at the colon (":") into separate elements for
* <user>, <group>, and <value> (permissions), where <value> is returned as
* an **octal** integer.
*/
Permissions(QString p);
/** @brief Default constructor of an invalid Permissions. */
Permissions();
bool isValid() const { return m_valid; }
QString username() const { return m_username; }
QString group() const { return m_group; }
int value() const { return m_value; }
QString octal() const { return QString::number( m_value, 8 ); }
private:
void parsePermissions(QString const &p);
QString m_username;
QString m_group;
bool m_valid;
int m_value;
};
#endif // PERMISSIONS_H

@ -9,13 +9,18 @@
# as the source).
# - a map with a *dest* key. The *dest* value is a path interpreted in the
# target system (if dontChroot is true, in the host system). Relative paths
# are not recommended. There are two possible other keys in the map:
# are not recommended. There are three possible other keys in the map:
# - *from*, which must have one of the values, below; it is used to
# preserve files whose pathname is known to Calamares internally.
# - *src*, to refer to a path interpreted in the host system. Relative
# paths are not recommended, and are interpreted relative to where
# Calamares is being run.
# Only one of the two other keys (either *from* or *src*) may be set.
# - *perm*, is a colon-separated tuple of <user>:<group>:<mode>
# where <mode> is in octal (e.g. 4777 for wide-open, 0400 for read-only
# by owner). If set, the file's ownership and permissions are set to
# those values within the target system; if not set, no permissions
# are changed.
# Only one of the two source keys (either *from* or *src*) may be set.
#
# The target filename is modified as follows:
# - `@@ROOT@@` is replaced by the path to the target root (may be /)
@ -32,5 +37,13 @@ files:
- /etc/oem-information
- from: log
dest: /root/install.log
perm: root:wheel:644
- from: config
dest: /root/install.cfg
perm: root:wheel:400
# The *perm* key contains a default value to apply to all files listed
# above that do not have a *perm* key of their own. If not set,
# root:root:0400 (highly restrictive) is used.
#
# perm: "root:root:0400"

Loading…
Cancel
Save