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

ENT-10961, CFE-1840: Added functions to get/update immutable file flag #235

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions libutils/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ libutils_la_SOURCES = \
version_comparison.c version_comparison.h \
writer.c writer.h \
xml_writer.c xml_writer.h \
fsattrs.c fsattrs.h \
glob_lib.c glob_lib.h

EXTRA_DIST = stack_base.c
Expand Down
143 changes: 143 additions & 0 deletions libutils/fsattrs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include <platform.h>
#include <fsattrs.h>
#include <logging.h>
#include <file_lib.h>

#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h> /* FS_* constants */
#endif /* HAVE_LINUX_FS_H */


FSAttrsResult FileGetImmutableFlag(const char *filename, bool *flag)
{
assert(filename != NULL);
assert(flag != NULL);

#if defined(HAVE_LINUX_FS_H)

int fd = safe_open(filename, O_RDONLY);
if (fd == -1)
{
return (errno == ENOENT) ? FS_ATTRS_NOENTRY : FS_ATTRS_FAILURE;
}

int attrs;
int ret = ioctl(fd, FS_IOC_GETFLAGS, &attrs);
close(fd); /* We don't need the file descriptor any more */
if (ret < 0)
{
return (errno == ENOTTY) ? FS_ATTRS_NOTSUPP : FS_ATTRS_FAILURE;
}

*flag = attrs & FS_IMMUTABLE_FL;
return FS_ATTRS_SUCCESS;

#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
|| defined(__NetBSD__)

struct stat sb;
int ret = lstat(filename, &sb);
if (ret == -1)
{
return (errno == ENOENT) ? FS_ATTRS_NOENTRY : FS_ATTRS_FAILURE;
}

*flag = sb.st_flags & SF_IMMUTABLE;
return FS_ATTRS_SUCCESS;

#else
/* Windows, AIX, HP-UX does not have file system flags as far as I can
tell */
(void) filename;
(void) flag;
return FS_ATTRS_NOTSUPP;
#endif
}

FSAttrsResult FileUpdateImmutableFlag(const char *filename, bool flag)
{
assert(filename != NULL);

#if defined(HAVE_LINUX_FS_H)

int fd = safe_open(filename, O_RDONLY);
if (fd == -1)
{
return (errno == ENOENT) ? FS_ATTRS_NOENTRY : FS_ATTRS_FAILURE;
}

int attrs;
int ret = ioctl(fd, FS_IOC_GETFLAGS, &attrs);
if (ret < 0)
{
close(fd);
return (errno == ENOTTY) ? FS_ATTRS_NOTSUPP : FS_ATTRS_FAILURE;
}

if (flag)
{
Log(LOG_LEVEL_DEBUG,
"Setting immutable bit in inode flags for file '%s'",
filename);
attrs |= FS_IMMUTABLE_FL;
}
else
{
Log(LOG_LEVEL_DEBUG,
"Clearing immutable bit in inode flags for file '%s'",
filename);
attrs &= ~FS_IMMUTABLE_FL;
}

ret = ioctl(fd, FS_IOC_SETFLAGS, &attrs);
if (ret < 0)
{
close(fd);
return (errno == ENOTTY) ? FS_ATTRS_NOTSUPP : FS_ATTRS_FAILURE;
}

close(fd);
return FS_ATTRS_SUCCESS;

#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
|| defined(__NetBSD__)

struct stat sb;
int ret = lstat(filename, &sb);
if (ret == -1)
{
return (errno == ENOENT) ? FS_ATTRS_NOENTRY : FS_ATTRS_FAILURE;
}


if (flag)
{
Log(LOG_LEVEL_DEBUG,
"Setting immutable bit in inode flags for file '%s'",
filename);
sb.st_flags |= SF_IMMUTABLE;
}
else
{
Log(LOG_LEVEL_DEBUG,
"Clearing immutable bit in inode flags for file '%s'",
filename);
sb.st_flags &= ~SF_IMMUTABLE;
}

ret = chflags(filename, sb.st_flags);
if (ret == -1)
{
return (errno == ENOTSUP) ? FS_ATTRS_NOTSUPP : FS_ATTRS_FAILURE;
}

return FS_ATTRS_SUCCESS;

#else
/* Windows, AIX, HP-UX does not have file system flags as far as I can
tell */
(void) filename;
(void) flag;
return FS_ATTRS_NOTSUPP;
#endif
}
53 changes: 53 additions & 0 deletions libutils/fsattrs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Copyright 2025 Northern.tech AS

This file is part of CFEngine 3 - written and maintained by Northern.tech AS.

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; version 3.

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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA

To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/

#ifndef CFENGINE_FSATTR_H
#define CFENGINE_FSATTR_H

#include <stdbool.h>

typedef enum {
FS_ATTRS_SUCCESS = 0,
FS_ATTRS_FAILURE,
FS_ATTRS_NOENTRY,
FS_ATTRS_NOTSUPP,
} FSAttrsResult;

/**
* @brief Get immutable flag of inode given the filename
* @param filename The filename
* @param flag The flag; true if flag is set, otherwise false
* @return Error code (see FSAttrsResult)
*/
FSAttrsResult FileGetImmutableFlag(const char *filename, bool *flag);

/**
* @brief Set/clear immutable flag of inode given the filename
* @param filename The filename
* @param flag The flag; true to set the flag, false to clear the flag
* @return Error code (see FSAttrsResult)
*/
FSAttrsResult FileUpdateImmutableFlag(const char *filename, bool flag);

#endif /* CFENGINE_FSATTR_H */
1 change: 1 addition & 0 deletions tests/unit/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ check_PROGRAMS = \
alloc_test \
string_writer_test \
file_writer_test \
fsattrs_test \
xml_writer_test \
sequence_test \
json_test \
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/fsattrs_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <test.h>
#include <cmockery.h>
#include <fsattrs.h>
#include <stdlib.h>


static void test_file_immutable_flag(void)
{
/* Get immutable flag from non existent file */
unlink("no_such_file_639123");
bool flag;
FSAttrsResult res = FileGetImmutableFlag("no_such_file_639123", &flag);
assert_int_not_equal(res, FS_ATTRS_SUCCESS);
assert_int_not_equal(res, FS_ATTRS_FAILURE);

/* Make temporary test file */
char filename[] = "test_file_immutable_flag_XXXXXX";
int fd = mkstemp(filename);
assert_int_not_equal(fd, -1);
close(fd);

/* There should not be any immutable flag on a newly created file */
res = FileGetImmutableFlag(filename, &flag);
unlink(filename);
if (res == FS_ATTRS_SUCCESS)
{
assert_false(flag);
}
assert_int_not_equal(res, FS_ATTRS_FAILURE);
assert_int_not_equal(res, FS_ATTRS_NOENTRY);

/* It would be nice to test updating inode flags, however this required
root permissions */
}

int main()
{
PRINT_TEST_BANNER();
const UnitTest tests[] =
{
unit_test(test_file_immutable_flag),
};

int ret = run_tests(tests);
return ret;
}
Loading