hpkg format: Add attributes for declaring users and groups

This commit is contained in:
Ingo Weinhold 2013-05-24 03:11:18 +02:00
parent c82776b2fa
commit 0f4e11e75c
18 changed files with 771 additions and 21 deletions

View File

@ -0,0 +1 @@
#include <../os/package/User.h>

View File

@ -18,6 +18,7 @@
#include <package/PackageResolvable.h>
#include <package/PackageResolvableExpression.h>
#include <package/PackageVersion.h>
#include <package/User.h>
#include <package/UserSettingsFileInfo.h>
@ -86,6 +87,9 @@ public:
const BObjectList<BUserSettingsFileInfo>&
UserSettingsFileInfos() const;
const BObjectList<BUser>& Users() const;
const BStringList& Groups() const;
const BObjectList<BPackageResolvable>& ProvidesList() const;
const BObjectList<BPackageResolvableExpression>&
RequiresList() const;
@ -135,6 +139,12 @@ public:
status_t AddUserSettingsFileInfo(
const BUserSettingsFileInfo& info);
void ClearUsers();
status_t AddUser(const BUser& user);
void ClearGroups();
status_t AddGroup(const BString& group);
void ClearProvidesList();
status_t AddProvides(const BPackageResolvable& provides);
@ -196,6 +206,8 @@ private:
typedef BObjectList<BUserSettingsFileInfo>
UserSettingsFileInfoList;
typedef BObjectList<BUser> UserList;
private:
status_t _ReadFromPackageFile(
const PackageFileLocation& fileLocation);
@ -218,6 +230,8 @@ private:
const char* field,
const UserSettingsFileInfoList&
infos);
static status_t _AddUsers(BMessage* archive, const char* field,
const UserList& users);
static status_t _ExtractVersion(BMessage* archive,
const char* field, int32 index,
@ -236,6 +250,8 @@ private:
static status_t _ExtractUserSettingsFileInfos(
BMessage* archive, const char* field,
UserSettingsFileInfoList& _infos);
static status_t _ExtractUsers(BMessage* archive,
const char* field, UserList& _users);
private:
BString fName;
@ -259,6 +275,9 @@ private:
BObjectList<BGlobalSettingsFileInfo> fGlobalSettingsFileInfos;
BObjectList<BUserSettingsFileInfo> fUserSettingsFileInfos;
UserList fUsers;
BStringList fGroups;
ResolvableList fProvidesList;
ResolvableExpressionList fRequiresList;

View File

@ -45,6 +45,10 @@ enum BPackageInfoAttributeID {
// list of global settings file infos
B_PACKAGE_INFO_USER_SETTINGS_FILES,
// list of user settings file infos
B_PACKAGE_INFO_USERS,
// list of (Unix) users defined/needed
B_PACKAGE_INFO_GROUPS,
// list of (Unix) groups defined/needed
//
B_PACKAGE_INFO_ENUM_COUNT,
};

52
headers/os/package/User.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright 2013, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _PACKAGE__USER_H_
#define _PACKAGE__USER_H_
#include <String.h>
#include <StringList.h>
namespace BPackageKit {
class BUser {
public:
BUser();
BUser(const BString& name,
const BString& realName,
const BString& home, const BString& shell,
const BStringList& groups);
~BUser();
status_t InitCheck() const;
const BString& Name() const;
const BString& RealName() const;
const BString& Home() const;
const BString& Shell() const;
const BStringList& Groups() const;
status_t SetTo(const BString& name,
const BString& realName,
const BString& home, const BString& shell,
const BStringList& groups);
static bool IsValidUserName(const char* name);
private:
BString fName;
BString fRealName;
BString fHome;
BString fShell;
BStringList fGroups;
};
} // namespace BPackageKit
#endif // _PACKAGE__USER_H_

View File

@ -70,3 +70,10 @@ B_DEFINE_HPKG_ATTRIBUTE(44, UINT, "package:settings-file-update-type",
PACKAGE_SETTINGS_FILE_UPDATE_TYPE)
B_DEFINE_HPKG_ATTRIBUTE(45, STRING, "package:settings-file-template",
PACKAGE_SETTINGS_FILE_TEMPLATE)
B_DEFINE_HPKG_ATTRIBUTE(46, STRING, "package:user", PACKAGE_USER)
B_DEFINE_HPKG_ATTRIBUTE(47, STRING, "package:user.real-name",
PACKAGE_USER_REAL_NAME)
B_DEFINE_HPKG_ATTRIBUTE(48, STRING, "package:user.home", PACKAGE_USER_HOME)
B_DEFINE_HPKG_ATTRIBUTE(49, STRING, "package:user.shell", PACKAGE_USER_SHELL)
B_DEFINE_HPKG_ATTRIBUTE(50, STRING, "package:user.group", PACKAGE_USER_GROUP)
B_DEFINE_HPKG_ATTRIBUTE(51, STRING, "package:group", PACKAGE_GROUP)

View File

@ -59,6 +59,16 @@ struct BUserSettingsFileInfoData {
};
struct BUserData {
const char* name;
const char* realName;
const char* home;
const char* shell;
const char* const* groups;
size_t groupCount;
};
struct BPackageInfoAttributeValue {
union {
uint64 unsignedInt;
@ -68,6 +78,7 @@ struct BPackageInfoAttributeValue {
BPackageResolvableExpressionData resolvableExpression;
BGlobalSettingsFileInfoData globalSettingsFileInfo;
BUserSettingsFileInfoData userSettingsFileInfo;
BUserData user;
};
BPackageInfoAttributeID attributeID;

View File

@ -13,6 +13,7 @@
#include <ByteOrder.h>
#include <SupportDefs.h>
#include <Array.h>
#include <util/SinglyLinkedList.h>
#include <package/hpkg/ErrorOutput.h>
@ -103,6 +104,7 @@ protected:
class PackageResolvableExpressionAttributeHandler;
class GlobalSettingsFileInfoAttributeHandler;
class UserSettingsFileInfoAttributeHandler;
class UserAttributeHandler;
class PackageAttributeHandler;
class LowLevelAttributeHandler;
@ -344,6 +346,25 @@ public:
};
class ReaderImplBase::UserAttributeHandler
: public PackageInfoAttributeHandlerBase {
public:
UserAttributeHandler(
BPackageInfoAttributeValue&
packageInfoValue);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
Array<const char*> fGroups;
};
class ReaderImplBase::PackageAttributeHandler : public AttributeHandler {
public:
virtual status_t HandleAttribute(

View File

@ -163,6 +163,12 @@ private:
= B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR;
private:
PackageAttribute* _AddStringAttribute(BHPKGAttributeID id,
const BString& value,
DoublyLinkedList<PackageAttribute>& list);
inline PackageAttribute* _AddStringAttributeIfNotEmpty(
BHPKGAttributeID id, const BString& value,
DoublyLinkedList<PackageAttribute>& list);
void _WritePackageAttributes(
const PackageAttributeList& attributes);
@ -252,6 +258,16 @@ WriterImplBase::SetFinished(bool finished)
}
inline WriterImplBase::PackageAttribute*
WriterImplBase::_AddStringAttributeIfNotEmpty(BHPKGAttributeID id,
const BString& value, DoublyLinkedList<PackageAttribute>& list)
{
if (value.IsEmpty())
return NULL;
return _AddStringAttribute(id, value, list);
}
} // namespace BPrivate
} // namespace BHPKG

View File

@ -310,6 +310,22 @@ struct PackageContentListHandler : VersionPolicy::PackageContentHandler {
printf("\n");
break;
case B_PACKAGE_INFO_USERS:
printf("\tuser: %s\n", value.user.name);
if (value.user.realName != NULL)
printf("\t\treal name: %s\n", value.user.realName);
if (value.user.home != NULL)
printf("\t\thome: %s\n", value.user.home);
if (value.user.shell != NULL)
printf("\t\tshell: %s\n", value.user.shell);
for (size_t i = 0; i < value.user.groupCount; i++)
printf("\t\tgroup: %s\n", value.user.groups[i]);
break;
case B_PACKAGE_INFO_GROUPS:
printf("\tgroup: %s\n", value.string);
break;
case B_PACKAGE_INFO_INSTALL_PATH:
printf("\tinstall path: %s\n", value.string);
break;

View File

@ -105,6 +105,7 @@ BuildPlatformSharedLibrary libpackage_build.so
RepositoryInfo.cpp
Request.cpp
TempfileManager.cpp
User.cpp
ValidateChecksumJob.cpp
$(HPKG_SOURCES)

View File

@ -97,6 +97,7 @@ SharedLibrary libpackage.so
RepositoryInfo.cpp
Request.cpp
TempfileManager.cpp
User.cpp
ValidateChecksumJob.cpp
$(HPKG_SOURCES)

View File

@ -1,5 +1,6 @@
/*
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -52,6 +53,8 @@ const char* const BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
"base-package",
"global-settings-files",
"user-settings-files",
"users",
"groups"
};
@ -160,18 +163,20 @@ BPackageInfo::BPackageInfo()
BArchivable(),
fFlags(0),
fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
fCopyrightList(5),
fLicenseList(5),
fURLList(5),
fSourceURLList(5),
fGlobalSettingsFileInfos(5, true),
fUserSettingsFileInfos(5, true),
fCopyrightList(4),
fLicenseList(4),
fURLList(4),
fSourceURLList(4),
fGlobalSettingsFileInfos(4, true),
fUserSettingsFileInfos(4, true),
fUsers(4, true),
fGroups(4),
fProvidesList(20, true),
fRequiresList(20, true),
fSupplementsList(20, true),
fConflictsList(5, true),
fFreshensList(5, true),
fReplacesList(5)
fConflictsList(4, true),
fFreshensList(4, true),
fReplacesList(4)
{
}
@ -181,18 +186,20 @@ BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
BArchivable(archive),
fFlags(0),
fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
fCopyrightList(5),
fLicenseList(5),
fURLList(5),
fSourceURLList(5),
fGlobalSettingsFileInfos(5, true),
fUserSettingsFileInfos(5, true),
fCopyrightList(4),
fLicenseList(4),
fURLList(4),
fSourceURLList(4),
fGlobalSettingsFileInfos(4, true),
fUserSettingsFileInfos(4, true),
fUsers(4, true),
fGroups(4),
fProvidesList(20, true),
fRequiresList(20, true),
fSupplementsList(20, true),
fConflictsList(5, true),
fFreshensList(5, true),
fReplacesList(5)
fConflictsList(4, true),
fFreshensList(4, true),
fReplacesList(4)
{
status_t error;
int32 architecture;
@ -216,6 +223,8 @@ BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
"global-settings-files", fGlobalSettingsFileInfos)) == B_OK
&& (error = _ExtractUserSettingsFileInfos(archive, "user-settings-files",
fUserSettingsFileInfos)) == B_OK
&& (error = _ExtractUsers(archive, "users", fUsers)) == B_OK
&& (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
== B_OK
&& (error = _ExtractResolvableExpressions(archive, "requires",
@ -326,6 +335,50 @@ BPackageInfo::InitCheck() const
|| fProvidesList.IsEmpty())
return B_NO_INIT;
// check global settings files
int32 globalSettingsFileCount = fGlobalSettingsFileInfos.CountItems();
for (int32 i = 0; i < globalSettingsFileCount; i++) {
const BGlobalSettingsFileInfo* info
= fGlobalSettingsFileInfos.ItemAt(i);
status_t error = info->InitCheck();
if (error != B_OK)
return error;
}
// check user settings files
int32 userSettingsFileCount = fUserSettingsFileInfos.CountItems();
for (int32 i = 0; i < userSettingsFileCount; i++) {
const BUserSettingsFileInfo* info = fUserSettingsFileInfos.ItemAt(i);
status_t error = info->InitCheck();
if (error != B_OK)
return error;
}
// check users
int32 userCount = fUsers.CountItems();
for (int32 i = 0; i < userCount; i++) {
const BUser* user = fUsers.ItemAt(i);
status_t error = user->InitCheck();
if (error != B_OK)
return B_NO_INIT;
// make sure the user's groups are specified as groups
const BStringList& userGroups = user->Groups();
int32 groupCount = userGroups.CountStrings();
for (int32 k = 0; k < groupCount; k++) {
const BString& group = userGroups.StringAt(k);
if (!fGroups.HasString(group))
return B_BAD_VALUE;
}
}
// check groups
int32 groupCount = fGroups.CountStrings();
for (int32 i = 0; i< groupCount; i++) {
if (!BUser::IsValidUserName(fGroups.StringAt(i)))
return B_BAD_VALUE;
}
return B_OK;
}
@ -449,6 +502,20 @@ BPackageInfo::UserSettingsFileInfos() const
}
const BObjectList<BUser>&
BPackageInfo::Users() const
{
return fUsers;
}
const BStringList&
BPackageInfo::Groups() const
{
return fGroups;
}
const BObjectList<BPackageResolvable>&
BPackageInfo::ProvidesList() const
{
@ -629,6 +696,13 @@ BPackageInfo::ClearSourceURLList()
}
status_t
BPackageInfo::AddSourceURL(const BString& url)
{
return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
}
void
BPackageInfo::ClearGlobalSettingsFileInfos()
{
@ -671,10 +745,37 @@ BPackageInfo::AddUserSettingsFileInfo(const BUserSettingsFileInfo& info)
}
status_t
BPackageInfo::AddSourceURL(const BString& url)
void
BPackageInfo::ClearUsers()
{
return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
fUsers.MakeEmpty();
}
status_t
BPackageInfo::AddUser(const BUser& user)
{
BUser* newUser = new (std::nothrow) BUser(user);
if (newUser == NULL || !fUsers.AddItem(newUser)) {
delete newUser;
return B_NO_MEMORY;
}
return B_OK;
}
void
BPackageInfo::ClearGroups()
{
fGroups.MakeEmpty();
}
status_t
BPackageInfo::AddGroup(const BString& group)
{
return fGroups.Add(group) ? B_OK : B_NO_MEMORY;
}
@ -807,6 +908,8 @@ BPackageInfo::Clear()
fSourceURLList.MakeEmpty();
fGlobalSettingsFileInfos.MakeEmpty();
fUserSettingsFileInfos.MakeEmpty();
fUsers.MakeEmpty();
fGroups.MakeEmpty();
fRequiresList.MakeEmpty();
fProvidesList.MakeEmpty();
fSupplementsList.MakeEmpty();
@ -842,6 +945,8 @@ BPackageInfo::Archive(BMessage* archive, bool deep) const
"global-settings-files", fGlobalSettingsFileInfos)) != B_OK
|| (error = _AddUserSettingsFileInfos(archive,
"user-settings-files", fUserSettingsFileInfos)) != B_OK
|| (error = _AddUsers(archive, "users", fUsers)) != B_OK
|| (error = archive->AddStrings("groups", fGroups)) != B_OK
|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
|| (error = _AddResolvableExpressions(archive, "requires",
fRequiresList)) != B_OK
@ -887,6 +992,8 @@ BPackageInfo::GetConfigString(BString& _string) const
.Write("source-urls", fSourceURLList)
.Write("global-settings-files", fGlobalSettingsFileInfos)
.Write("user-settings-files", fUserSettingsFileInfos)
.Write("users", fUsers)
.Write("groups", fGroups)
.Write("provides", fProvidesList)
.BeginRequires(fBasePackage)
.Write("requires", fRequiresList)
@ -1135,6 +1242,44 @@ BPackageInfo::_AddUserSettingsFileInfos(BMessage* archive, const char* field,
}
/*static*/ status_t
BPackageInfo::_AddUsers(BMessage* archive, const char* field,
const UserList& users)
{
// construct the field names we need
FieldName nameField(field, ":name");
FieldName realNameField(field, ":realName");
FieldName homeField(field, ":home");
FieldName shellField(field, ":shell");
FieldName groupsField(field, ":groups");
if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
|| !shellField.IsValid() || !groupsField.IsValid())
return B_BAD_VALUE;
// add fields
int32 count = users.CountItems();
for (int32 i = 0; i < count; i++) {
const BUser* user = users.ItemAt(i);
BString groups = user->Groups().Join(" ");
if (groups.IsEmpty() && !user->Groups().IsEmpty())
return B_NO_MEMORY;
status_t error;
if ((error = archive->AddString(nameField, user->Name())) != B_OK
|| (error = archive->AddString(realNameField, user->RealName()))
!= B_OK
|| (error = archive->AddString(homeField, user->Home())) != B_OK
|| (error = archive->AddString(shellField, user->Shell())) != B_OK
|| (error = archive->AddString(groupsField, groups)) != B_OK) {
return error;
}
}
return B_OK;
}
/*static*/ status_t
BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
BPackageVersion& _version)
@ -1401,4 +1546,70 @@ BPackageInfo::_ExtractUserSettingsFileInfos(BMessage* archive,
}
/*static*/ status_t
BPackageInfo::_ExtractUsers(BMessage* archive, const char* field,
UserList& _users)
{
// construct the field names we need
FieldName nameField(field, ":name");
FieldName realNameField(field, ":realName");
FieldName homeField(field, ":home");
FieldName shellField(field, ":shell");
FieldName groupsField(field, ":groups");
if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
|| !shellField.IsValid() || !groupsField.IsValid())
return B_BAD_VALUE;
// get the number of items
type_code type;
int32 count;
if (archive->GetInfo(nameField, &type, &count) != B_OK) {
// the field is missing
return B_OK;
}
// extract fields
for (int32 i = 0; i < count; i++) {
BString name;
status_t error = archive->FindString(nameField, i, &name);
if (error != B_OK)
return error;
BString realName;
error = archive->FindString(realNameField, i, &realName);
if (error != B_OK)
return error;
BString home;
error = archive->FindString(homeField, i, &home);
if (error != B_OK)
return error;
BString shell;
error = archive->FindString(shellField, i, &shell);
if (error != B_OK)
return error;
BString groupsString;
error = archive->FindString(groupsField, i, &groupsString);
if (error != B_OK)
return error;
BStringList groups;
if (!groupsString.Split(" ", false, groups))
return B_NO_MEMORY;
BUser* user = new(std::nothrow) BUser(name, realName, home, shell,
groups);
if (user == NULL || !_users.AddItem(user)) {
delete user;
return B_NO_MEMORY;
}
}
return B_OK;
}
} // namespace BPackageKit

View File

@ -703,6 +703,118 @@ BPackageInfo::Parser::_ParseUserSettingsFileInfos(
}
void
BPackageInfo::Parser::_ParseUsers(UserList* users)
{
struct UserParser : public ListElementParser {
Parser& parser;
UserList* users;
UserParser(Parser& parser, UserList* users)
:
parser(parser),
users(users)
{
}
virtual void operator()(const Token& token)
{
if (token.type != TOKEN_WORD) {
throw ParseError("expected a user name",
token.pos);
}
BString realName;
BString home;
BString shell;
BStringList groups;
for (;;) {
Token nextToken = parser._NextToken();
if (nextToken.type != TOKEN_WORD) {
parser._RewindTo(nextToken);
break;
}
if (nextToken.text == "real-name") {
nextToken = parser._NextToken();
if (nextToken.type != TOKEN_WORD
&& nextToken.type != TOKEN_QUOTED_STRING) {
throw ParseError("expected string (a user real name)",
nextToken.pos);
}
realName = nextToken.text;
} else if (nextToken.text == "home") {
nextToken = parser._NextToken();
if (nextToken.type != TOKEN_WORD
&& nextToken.type != TOKEN_QUOTED_STRING) {
throw ParseError("expected string (a home path)",
nextToken.pos);
}
home = nextToken.text;
} else if (nextToken.text == "shell") {
nextToken = parser._NextToken();
if (nextToken.type != TOKEN_WORD
&& nextToken.type != TOKEN_QUOTED_STRING) {
throw ParseError("expected string (a shell path)",
nextToken.pos);
}
shell = nextToken.text;
} else if (nextToken.text == "groups") {
for (;;) {
nextToken = parser._NextToken();
if (nextToken.type == TOKEN_WORD) {
if (!groups.Add(nextToken.text))
throw std::bad_alloc();
} else if (nextToken.type == TOKEN_ITEM_SEPARATOR
|| nextToken.type == TOKEN_CLOSE_BRACE) {
parser._RewindTo(nextToken);
break;
} else {
throw ParseError("expected a group name",
nextToken.pos);
}
}
break;
} else {
throw ParseError(
"expected 'real-name', 'home', 'shell', or 'groups'",
nextToken.pos);
}
}
BString templatePath;
Token nextToken = parser._NextToken();
if (nextToken.type == TOKEN_WORD && nextToken.text == "template") {
nextToken = parser._NextToken();
if (nextToken.type != TOKEN_WORD
&& nextToken.type != TOKEN_QUOTED_STRING) {
throw ParseError(
"expected string (a settings template file path)",
nextToken.pos);
}
templatePath = nextToken.text;
} else if (nextToken.type == TOKEN_ITEM_SEPARATOR
|| nextToken.type == TOKEN_CLOSE_BRACE) {
parser._RewindTo(nextToken);
} else {
throw ParseError(
"expected 'template', semicolon, new line or '}'",
nextToken.pos);
}
if (!users->AddItem(new BUser(token.text, realName, home, shell,
groups))) {
throw std::bad_alloc();
}
}
} resolvableExpressionParser(*this, users);
_ParseList(resolvableExpressionParser, false);
}
void
BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
{
@ -814,6 +926,14 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
&packageInfo->fUserSettingsFileInfos);
break;
case B_PACKAGE_INFO_USERS:
_ParseUsers(&packageInfo->fUsers);
break;
case B_PACKAGE_INFO_GROUPS:
_ParseStringList(&packageInfo->fGroups);
break;
case B_PACKAGE_INFO_PROVIDES:
_ParseResolvableList(&packageInfo->fProvidesList);
break;

View File

@ -79,6 +79,7 @@ private:
GlobalSettingsFileInfoList* infos);
void _ParseUserSettingsFileInfos(
UserSettingsFileInfoList* infos);
void _ParseUsers(UserList* users);
void _Parse(BPackageInfo* packageInfo);

View File

@ -175,6 +175,37 @@ private:
}
}
void _WriteListElement(const BUser* value)
{
_WriteMaybeQuoted(value->Name());
if (!value->RealName().IsEmpty()) {
_Write(" real-name ");
_WriteMaybeQuoted(value->RealName());
}
if (!value->Home().IsEmpty()) {
_Write(" home ");
_WriteMaybeQuoted(value->Home());
}
if (!value->Shell().IsEmpty()) {
_Write(" shell ");
_WriteMaybeQuoted(value->Shell());
}
if (!value->Groups().IsEmpty()) {
_Write(" groups ");
BString groups = value->Groups().Join(" ");
if (groups.IsEmpty()) {
if (fError == B_OK)
fError = B_NO_MEMORY;
return;
}
_Write(groups);
}
}
static inline bool _IsValueEmpty(const char* value)
{
return value[0] == '\0';

118
src/kits/package/User.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include <package/User.h>
#include <ctype.h>
namespace BPackageKit {
BUser::BUser()
:
fName(),
fRealName(),
fHome(),
fShell(),
fGroups()
{
}
BUser::BUser(const BString& name, const BString& realName, const BString& home,
const BString& shell, const BStringList& groups)
:
fName(name),
fRealName(realName),
fHome(home),
fShell(shell),
fGroups(groups)
{
}
BUser::~BUser()
{
}
status_t
BUser::InitCheck() const
{
if (fName.IsEmpty())
return B_NO_INIT;
if (!IsValidUserName(fName))
return B_BAD_VALUE;
return B_OK;
}
const BString&
BUser::Name() const
{
return fName;
}
const BString&
BUser::RealName() const
{
return fRealName;
}
const BString&
BUser::Home() const
{
return fHome;
}
const BString&
BUser::Shell() const
{
return fShell;
}
const BStringList&
BUser::Groups() const
{
return fGroups;
}
status_t
BUser::SetTo(const BString& name, const BString& realName, const BString& home,
const BString& shell, const BStringList& groups)
{
fName = name;
fRealName = realName;
fHome = home;
fShell = shell;
fGroups = groups;
return fGroups.CountStrings() == groups.CountStrings() ? B_OK : B_NO_MEMORY;
}
/*static*/ bool
BUser::IsValidUserName(const char* name)
{
if (name[0] == '\0')
return false;
for (; name[0] != '\0'; name++) {
if (!isalnum(name[0]) && name[0] != '_')
return false;
}
return true;
}
} // namespace BPackageKit

View File

@ -402,6 +402,69 @@ ReaderImplBase::UserSettingsFileInfoAttributeHandler::HandleAttribute(
return B_OK;
}
// #pragma mark - UserAttributeHandler
ReaderImplBase::UserAttributeHandler::UserAttributeHandler(
BPackageInfoAttributeValue& packageInfoValue)
:
PackageInfoAttributeHandlerBase(packageInfoValue),
fGroups()
{
}
status_t
ReaderImplBase::UserAttributeHandler::HandleAttribute(
AttributeHandlerContext* context, uint8 id, const AttributeValue& value,
AttributeHandler** _handler)
{
switch (id) {
case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_REAL_NAME:
fPackageInfoValue.user.realName = value.string;
break;
case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_HOME:
fPackageInfoValue.user.home = value.string;
break;
case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SHELL:
fPackageInfoValue.user.shell = value.string;
break;
case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_GROUP:
if (!fGroups.Add(value.string))
return B_NO_MEMORY;
break;
default:
if (context->ignoreUnknownAttributes)
break;
context->errorOutput->PrintError("Error: Invalid package "
"attribute section: unexpected package attribute id %d "
"encountered when parsing user settings file info\n",
id);
return B_BAD_DATA;
}
return B_OK;
}
status_t
ReaderImplBase::UserAttributeHandler::Delete(AttributeHandlerContext* context)
{
if (!fGroups.IsEmpty()) {
fPackageInfoValue.user.groups = fGroups.Elements();
fPackageInfoValue.user.groupCount = fGroups.Count();
}
return PackageInfoAttributeHandlerBase::Delete(context);
}
// #pragma mark - PackageAttributeHandler
@ -569,6 +632,21 @@ ReaderImplBase::PackageAttributeHandler::HandleAttribute(
}
break;
case B_HPKG_ATTRIBUTE_ID_PACKAGE_USER:
fPackageInfoValue.user.name = value.string;
fPackageInfoValue.attributeID = B_PACKAGE_INFO_USERS;
if (_handler != NULL) {
*_handler = new(std::nothrow) UserAttributeHandler(
fPackageInfoValue);
if (*_handler == NULL)
return B_NO_MEMORY;
}
break;
case B_HPKG_ATTRIBUTE_ID_PACKAGE_GROUP:
fPackageInfoValue.SetTo(B_PACKAGE_INFO_GROUPS, value.string);
break;
default:
if (context->ignoreUnknownAttributes)
break;

View File

@ -480,6 +480,36 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
}
}
// user list
const BObjectList<BUser>& users = packageInfo.Users();
for (int32 i = 0; i < users.CountItems(); ++i) {
const BUser* user = users.ItemAt(i);
PackageAttribute* attribute = _AddStringAttribute(
B_HPKG_ATTRIBUTE_ID_PACKAGE_USER, user->Name(), attributeList);
_AddStringAttributeIfNotEmpty(
B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_REAL_NAME, user->RealName(),
attribute->children);
_AddStringAttributeIfNotEmpty(
B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_HOME, user->Home(),
attribute->children);
_AddStringAttributeIfNotEmpty(
B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_SHELL, user->Shell(),
attribute->children);
for (int32 k = 0; k < user->Groups().CountStrings(); k++) {
_AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_USER_GROUP,
user->Groups().StringAt(k), attribute->children);
}
}
// group list
const BStringList& groups = packageInfo.Groups();
for (int32 i = 0; i < groups.CountStrings(); i++) {
_AddStringAttribute(B_HPKG_ATTRIBUTE_ID_PACKAGE_GROUP,
groups.StringAt(i), attributeList);
}
// checksum (optional, only exists in repositories)
if (packageInfo.Checksum().Length() > 0) {
PackageAttribute* checksum = new PackageAttribute(
@ -740,6 +770,18 @@ WriterImplBase::RawWriteBuffer(const void* buffer, size_t size, off_t offset)
}
WriterImplBase::PackageAttribute*
WriterImplBase::_AddStringAttribute(BHPKGAttributeID id, const BString& value,
DoublyLinkedList<PackageAttribute>& list)
{
PackageAttribute* attribute = new PackageAttribute(id,
B_HPKG_ATTRIBUTE_TYPE_STRING, B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
attribute->string = fPackageStringCache.Get(value);
list.Add(attribute);
return attribute;
}
void
WriterImplBase::_WritePackageAttributes(
const PackageAttributeList& packageAttributes)