|
|
4b6aa8 |
From 12f813825e09e16f0c9b4f7ef4fe89ca73baf886 Mon Sep 17 00:00:00 2001
|
|
|
4b6aa8 |
From: Martin Kutlak <mkutlak@redhat.com>
|
|
|
4b6aa8 |
Date: Wed, 26 Sep 2018 14:45:57 +0200
|
|
|
4b6aa8 |
Subject: [PATCH] dd: add functions for opening dd item
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
In cases where libreport users don't want to build contents of a dump
|
|
|
4b6aa8 |
dir element in memory and save to disk using dd_save_* functions, they
|
|
|
4b6aa8 |
had to guess file name and take care of file attributes. Forcing users
|
|
|
4b6aa8 |
to take of this is a security risk.
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
This commit introduces new functions that will create a file inside of
|
|
|
4b6aa8 |
a dump directory with correct name and file attributes.
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
For simplicity, only read only mode and read-write mode are allowed.
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
The read-write mode cause removal of the original item element as we
|
|
|
4b6aa8 |
must never use truncate mode because of hard link threat (libreport
|
|
|
4b6aa8 |
code runs under privileged user, so libreport must avoid rewriting
|
|
|
4b6aa8 |
files - the correct approach is to remove the old one and create the new
|
|
|
4b6aa8 |
one).
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
Sometimes we need to be able write some data and immediately read them.
|
|
|
4b6aa8 |
This can be done by opening the file, writing the contents, closing the
|
|
|
4b6aa8 |
file and re-opening it for reading. However, if we need to split the
|
|
|
4b6aa8 |
work into chunks, than this approach becomes quite expensive.
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
Signed-off-by: Martin Kutlak <mkutlak@redhat.com>
|
|
|
4b6aa8 |
---
|
|
|
4b6aa8 |
src/include/dump_dir.h | 44 +++++++++
|
|
|
4b6aa8 |
src/lib/dump_dir.c | 86 +++++++++++++----
|
|
|
4b6aa8 |
tests/dump_dir.at | 205 +++++++++++++++++++++++++++++++++++++++++
|
|
|
4b6aa8 |
3 files changed, 318 insertions(+), 17 deletions(-)
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
diff --git a/src/include/dump_dir.h b/src/include/dump_dir.h
|
|
|
4b6aa8 |
index 690695a0..badef179 100644
|
|
|
4b6aa8 |
--- a/src/include/dump_dir.h
|
|
|
4b6aa8 |
+++ b/src/include/dump_dir.h
|
|
|
4b6aa8 |
@@ -24,6 +24,9 @@
|
|
|
4b6aa8 |
/* For const_string_vector_const_ptr_t */
|
|
|
4b6aa8 |
#include "libreport_types.h"
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
+#include <stdint.h>
|
|
|
4b6aa8 |
+#include <stdio.h>
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
/* For DIR */
|
|
|
4b6aa8 |
#include <sys/types.h>
|
|
|
4b6aa8 |
#include <dirent.h>
|
|
|
4b6aa8 |
@@ -75,10 +78,24 @@ void dd_close(struct dump_dir *dd);
|
|
|
4b6aa8 |
/* Opens the given path and returns the resulting file descriptor.
|
|
|
4b6aa8 |
*/
|
|
|
4b6aa8 |
int dd_openfd(const char *dir);
|
|
|
4b6aa8 |
+/* Opens the given path
|
|
|
4b6aa8 |
+ */
|
|
|
4b6aa8 |
struct dump_dir *dd_opendir(const char *dir, int flags);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+/* Re-opens a dump_dir opened with DD_OPEN_FD_ONLY.
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * The passed dump_dir must not be used any more and the return value must be
|
|
|
4b6aa8 |
+ * used instead.
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * The passed flags must not contain DD_OPEN_FD_ONLY.
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * The passed dump_dir must not be already locked.
|
|
|
4b6aa8 |
+ */
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
/* Skips dd_openfd(dir) and uses the given file descriptor instead
|
|
|
4b6aa8 |
*/
|
|
|
4b6aa8 |
struct dump_dir *dd_fdopendir(int dir_fd, const char *dir, int flags);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
struct dump_dir *dd_create_skeleton(const char *dir, uid_t uid, mode_t mode, int flags);
|
|
|
4b6aa8 |
int dd_reset_ownership(struct dump_dir *dd);
|
|
|
4b6aa8 |
/* Pass uid = (uid_t)-1L to disable chown'ing of newly created files
|
|
|
4b6aa8 |
@@ -108,6 +125,33 @@ long dd_get_item_size(struct dump_dir *dd, const char *name);
|
|
|
4b6aa8 |
* For more about errno see unlink documentation
|
|
|
4b6aa8 |
*/
|
|
|
4b6aa8 |
int dd_delete_item(struct dump_dir *dd, const char *name);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+/* Returns a file descriptor for the given name. The function is limited to open
|
|
|
4b6aa8 |
+ * an element read only, write only or create new.
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * O_RDONLY - opens an existing item for reading
|
|
|
4b6aa8 |
+ * O_RDWR - removes an item, creates its file and opens the file for reading and writing
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * @param dd Dump directory
|
|
|
4b6aa8 |
+ * @param name The name of the item
|
|
|
4b6aa8 |
+ * @param flags One of these : O_RDONLY, O_RDWR
|
|
|
4b6aa8 |
+ * @return Negative number on error
|
|
|
4b6aa8 |
+ */
|
|
|
4b6aa8 |
+int dd_open_item(struct dump_dir *dd, const char *name, int flags);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+/* Returns a FILE for the given name. The function is limited to open
|
|
|
4b6aa8 |
+ * an element read only, write only or create new.
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * O_RDONLY - opens an existing file for reading
|
|
|
4b6aa8 |
+ * O_RDWR - removes an item, creates its file and opens the file for reading and writing
|
|
|
4b6aa8 |
+ *
|
|
|
4b6aa8 |
+ * @param dd Dump directory
|
|
|
4b6aa8 |
+ * @param name The name of the item
|
|
|
4b6aa8 |
+ * @param flags One of these : O_RDONLY, O_RDWR
|
|
|
4b6aa8 |
+ * @return NULL on error
|
|
|
4b6aa8 |
+ */
|
|
|
4b6aa8 |
+FILE *dd_open_item_file(struct dump_dir *dd, const char *name, int flags);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
/* Returns 0 if directory is deleted or not found */
|
|
|
4b6aa8 |
int dd_delete(struct dump_dir *dd);
|
|
|
4b6aa8 |
int dd_rename(struct dump_dir *dd, const char *new_path);
|
|
|
4b6aa8 |
diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c
|
|
|
4b6aa8 |
index c0117380..7e8ee017 100644
|
|
|
4b6aa8 |
--- a/src/lib/dump_dir.c
|
|
|
4b6aa8 |
+++ b/src/lib/dump_dir.c
|
|
|
4b6aa8 |
@@ -84,6 +84,12 @@
|
|
|
4b6aa8 |
#define RMDIR_FAIL_USLEEP (10*1000)
|
|
|
4b6aa8 |
#define RMDIR_FAIL_COUNT 50
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
+// A sub-directory of a dump directory where the meta-data such as owner are
|
|
|
4b6aa8 |
+// stored. The meta-data directory must have same owner, group and mode as its
|
|
|
4b6aa8 |
+// parent dump directory. It is not a fatal error, if the meta-data directory
|
|
|
4b6aa8 |
+// does not exist (backward compatibility).
|
|
|
4b6aa8 |
+#define META_DATA_DIR_NAME ".libreport"
|
|
|
4b6aa8 |
+#define META_DATA_FILE_OWNER "owner"
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
static char *load_text_file(const char *path, unsigned flags);
|
|
|
4b6aa8 |
static char *load_text_file_at(int dir_fd, const char *name, unsigned flags);
|
|
|
4b6aa8 |
@@ -113,6 +119,12 @@ static bool exist_file_dir_at(int dir_fd, const char *name)
|
|
|
4b6aa8 |
return false;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
+/* A valid dump dir element name is correct filename and is not a name of any
|
|
|
4b6aa8 |
+ * internal file or directory.
|
|
|
4b6aa8 |
+ */
|
|
|
4b6aa8 |
+#define dd_validate_element_name(name) \
|
|
|
4b6aa8 |
+ (str_is_correct_filename(name) && (strcmp(META_DATA_DIR_NAME, name) != 0))
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
/* Opens the file in the three following steps:
|
|
|
4b6aa8 |
* 1. open the file with O_PATH (get a file descriptor for operations with
|
|
|
4b6aa8 |
* inode) and O_NOFOLLOW (do not dereference symbolick links)
|
|
|
4b6aa8 |
@@ -1126,30 +1138,28 @@ static void copy_file_from_chroot(struct dump_dir* dd, const char *name, const c
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
-static bool save_binary_file_at(int dir_fd, const char *name, const char* data, unsigned size, uid_t uid, gid_t gid, mode_t mode)
|
|
|
4b6aa8 |
+static int create_new_file_at(int dir_fd, int omode, const char *name, uid_t uid, gid_t gid, mode_t mode)
|
|
|
4b6aa8 |
{
|
|
|
4b6aa8 |
assert(name[0] != '/');
|
|
|
4b6aa8 |
+ assert(omode == O_WRONLY || omode == O_RDWR);
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
/* the mode is set by the caller, see dd_create() for security analysis */
|
|
|
4b6aa8 |
unlinkat(dir_fd, name, /*remove only files*/0);
|
|
|
4b6aa8 |
- int fd = openat(dir_fd, name, O_WRONLY | O_EXCL | O_CREAT | O_NOFOLLOW, mode);
|
|
|
4b6aa8 |
+ int fd = openat(dir_fd, name, omode | O_EXCL | O_CREAT | O_NOFOLLOW, mode);
|
|
|
4b6aa8 |
if (fd < 0)
|
|
|
4b6aa8 |
{
|
|
|
4b6aa8 |
perror_msg("Can't open file '%s'", name);
|
|
|
4b6aa8 |
- return false;
|
|
|
4b6aa8 |
+ return -1;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
- if (uid != (uid_t)-1L)
|
|
|
4b6aa8 |
+ if ((uid != (uid_t)-1L) && (fchown(fd, uid, gid) == -1))
|
|
|
4b6aa8 |
{
|
|
|
4b6aa8 |
- if (fchown(fd, uid, gid) == -1)
|
|
|
4b6aa8 |
- {
|
|
|
4b6aa8 |
- perror_msg("Can't change '%s' ownership to %lu:%lu", name, (long)uid, (long)gid);
|
|
|
4b6aa8 |
- close(fd);
|
|
|
4b6aa8 |
- return false;
|
|
|
4b6aa8 |
- }
|
|
|
4b6aa8 |
+ perror_msg("Can't change '%s' ownership to %lu:%lu", name, (long)uid, (long)gid);
|
|
|
4b6aa8 |
+ close(fd);
|
|
|
4b6aa8 |
+ return -1;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
- /* O_CREATE in the open() call above causes that the permissions of the
|
|
|
4b6aa8 |
+ /* O_CREAT in the open() call above causes that the permissions of the
|
|
|
4b6aa8 |
* created file are (mode & ~umask)
|
|
|
4b6aa8 |
*
|
|
|
4b6aa8 |
* This is true only if we did create file. We are not sure we created it
|
|
|
4b6aa8 |
@@ -1159,18 +1169,28 @@ static bool save_binary_file_at(int dir_fd, const char *name, const char* data,
|
|
|
4b6aa8 |
{
|
|
|
4b6aa8 |
perror_msg("Can't change mode of '%s'", name);
|
|
|
4b6aa8 |
close(fd);
|
|
|
4b6aa8 |
- return false;
|
|
|
4b6aa8 |
+ return -1;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
- unsigned r = full_write(fd, data, size);
|
|
|
4b6aa8 |
+ return fd;
|
|
|
4b6aa8 |
+}
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+static bool save_binary_file_at(int dir_fd, const char *name, const char* data, unsigned size, uid_t uid, gid_t gid, mode_t mode)
|
|
|
4b6aa8 |
+{
|
|
|
4b6aa8 |
+ const int fd = create_new_file_at(dir_fd, O_WRONLY, name, uid, gid, mode);
|
|
|
4b6aa8 |
+ if (fd < 0)
|
|
|
4b6aa8 |
+ goto fail;
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const unsigned r = full_write(fd, data, size);
|
|
|
4b6aa8 |
close(fd);
|
|
|
4b6aa8 |
if (r != size)
|
|
|
4b6aa8 |
- {
|
|
|
4b6aa8 |
- error_msg("Can't save file '%s'", name);
|
|
|
4b6aa8 |
- return false;
|
|
|
4b6aa8 |
- }
|
|
|
4b6aa8 |
+ goto fail;
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
return true;
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+fail:
|
|
|
4b6aa8 |
+ error_msg("Can't save file '%s'", name);
|
|
|
4b6aa8 |
+ return false;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
char* dd_load_text_ext(const struct dump_dir *dd, const char *name, unsigned flags)
|
|
|
4b6aa8 |
@@ -1264,6 +1284,38 @@ int dd_delete_item(struct dump_dir *dd, const char *name)
|
|
|
4b6aa8 |
return res;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
|
|
|
4b6aa8 |
+int dd_open_item(struct dump_dir *dd, const char *name, int flag)
|
|
|
4b6aa8 |
+{
|
|
|
4b6aa8 |
+ if (!dd_validate_element_name(name))
|
|
|
4b6aa8 |
+ {
|
|
|
4b6aa8 |
+ error_msg("Cannot open item as FD. '%s' is not a valid file name", name);
|
|
|
4b6aa8 |
+ return -EINVAL;
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ if (flag == O_RDONLY)
|
|
|
4b6aa8 |
+ return openat(dd->dd_fd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ if (!dd->locked)
|
|
|
4b6aa8 |
+ error_msg_and_die("dump_dir is not locked"); /* bug */
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ if (flag == O_RDWR)
|
|
|
4b6aa8 |
+ return create_new_file_at(dd->dd_fd, O_RDWR, name, dd->dd_uid, dd->dd_gid, dd->mode);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ error_msg("invalid open item flag");
|
|
|
4b6aa8 |
+ return -ENOTSUP;
|
|
|
4b6aa8 |
+}
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+FILE *dd_open_item_file(struct dump_dir *dd, const char *name, int flag)
|
|
|
4b6aa8 |
+{
|
|
|
4b6aa8 |
+ const int item_fd = dd_open_item(dd, name, flag);
|
|
|
4b6aa8 |
+ if (item_fd < 0)
|
|
|
4b6aa8 |
+ return NULL;
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const char *mode = flag == O_RDONLY ? "r" : "w+";
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ return fdopen(item_fd, mode);
|
|
|
4b6aa8 |
+}
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
DIR *dd_init_next_file(struct dump_dir *dd)
|
|
|
4b6aa8 |
{
|
|
|
4b6aa8 |
// if (!dd->locked)
|
|
|
4b6aa8 |
diff --git a/tests/dump_dir.at b/tests/dump_dir.at
|
|
|
4b6aa8 |
index 70a97e6e..78ea60d1 100644
|
|
|
4b6aa8 |
--- a/tests/dump_dir.at
|
|
|
4b6aa8 |
+++ b/tests/dump_dir.at
|
|
|
4b6aa8 |
@@ -355,3 +355,208 @@ int main(void)
|
|
|
4b6aa8 |
return 0;
|
|
|
4b6aa8 |
}
|
|
|
4b6aa8 |
]])
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+## ------------ ##
|
|
|
4b6aa8 |
+## dd_open_item ##
|
|
|
4b6aa8 |
+## ------------ ##
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+AT_TESTFUN([dd_open_item], [[
|
|
|
4b6aa8 |
+#include "testsuite.h"
|
|
|
4b6aa8 |
+#include "testsuite_tools.h"
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+TS_MAIN
|
|
|
4b6aa8 |
+{
|
|
|
4b6aa8 |
+ struct dump_dir *dd = testsuite_dump_dir_create(-1, -1, 0);
|
|
|
4b6aa8 |
+ dd->dd_time = (time_t)1234567;
|
|
|
4b6aa8 |
+ dd_create_basic_files(dd, geteuid(), NULL);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/a", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "a/", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, ".", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "..", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/.", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//.", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "./", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, ".//", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/./", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/..", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "//..", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "../", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "..//", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/../", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "/.././", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "looks-good-but-evil/", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "looks-good-but-evil/../../", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-=", O_RDWR), -EINVAL);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const int fd_rdonly_noent = dd_open_item(dd, "nofile", O_RDONLY);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_LT(fd_rdonly_noent, 0);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const int fd_wronly_noent = dd_open_item(dd, "nofile", O_RDWR);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_GE(fd_wronly_noent, 0);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ full_write_str(fd_wronly_noent, "fd_wronly_noent");
|
|
|
4b6aa8 |
+ close(fd_wronly_noent);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char *const noent_contents = dd_load_text(dd, "nofile");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(noent_contents, "fd_wronly_noent", "Successfully wrote data");
|
|
|
4b6aa8 |
+ free(noent_contents);
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "time", O_RDONLY | O_EXCL), -ENOTSUP);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const int fd_rdonly_time = dd_open_item(dd, "time", O_RDONLY);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_GE(fd_rdonly_time, 0);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ char *time = dd_load_text(dd, "time");
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(time);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char rdonly_time_contents[16];
|
|
|
4b6aa8 |
+ int bytes_rdonly_time = full_read(fd_rdonly_time, rdonly_time_contents, sizeof(rdonly_time_contents));
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_GT(bytes_rdonly_time, 0);
|
|
|
4b6aa8 |
+ if (bytes_rdonly_time > 0) {
|
|
|
4b6aa8 |
+ rdonly_time_contents[bytes_rdonly_time] = '\0';
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time");
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ else {
|
|
|
4b6aa8 |
+ TS_PRINTF("FD %d read error: %s\n", fd_rdonly_time, strerror(errno));
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ free(time);
|
|
|
4b6aa8 |
+ close(fd_rdonly_time);
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_EQ(dd_open_item(dd, "time", O_RDWR | O_EXCL), -ENOTSUP);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ const int fd_rdwr_time = dd_open_item(dd, "time", O_RDWR);
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_GE(fd_rdwr_time, 0);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ full_write_str(fd_rdwr_time, "7654321");
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_FUNCTION(lseek(fd_rdwr_time, 0, SEEK_SET));
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char rdwr_time_contents[16];
|
|
|
4b6aa8 |
+ int bytes_rdwr_time = full_read(fd_rdwr_time, rdwr_time_contents, sizeof(rdwr_time_contents));
|
|
|
4b6aa8 |
+ close(fd_rdwr_time);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_SIGNED_GT(bytes_rdwr_time, 0);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ rdwr_time_contents[bytes_rdwr_time] = '\0';
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char *const time_contents = dd_load_text(dd, "time");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdwr_time_contents, "7654321", "Successfully wrote time data");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdwr_time_contents, time_contents, "Read only time");
|
|
|
4b6aa8 |
+ free(time_contents);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ else {
|
|
|
4b6aa8 |
+ TS_PRINTF("FD %d read error: %s\n", fd_rdwr_time, strerror(errno));
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ testsuite_dump_dir_delete(dd);
|
|
|
4b6aa8 |
+}
|
|
|
4b6aa8 |
+TS_RETURN_MAIN
|
|
|
4b6aa8 |
+]])
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+## ----------------- ##
|
|
|
4b6aa8 |
+## dd_open_item_file ##
|
|
|
4b6aa8 |
+## ----------------- ##
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+AT_TESTFUN([dd_open_item_file], [[
|
|
|
4b6aa8 |
+#include "testsuite.h"
|
|
|
4b6aa8 |
+#include "testsuite_tools.h"
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+TS_MAIN
|
|
|
4b6aa8 |
+{
|
|
|
4b6aa8 |
+ struct dump_dir *dd = testsuite_dump_dir_create(-1, -1, 0);
|
|
|
4b6aa8 |
+ dd->dd_time = (time_t)1234567;
|
|
|
4b6aa8 |
+ dd_create_basic_files(dd, geteuid(), NULL);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/a", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "a/", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, ".", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "..", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/.", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//.", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "./", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, ".//", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/./", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/..", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "//..", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "../", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "..//", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/../", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "/.././", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "looks-good-but-evil/", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "looks-good-but-evil/../../", O_RDWR));
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-=", O_RDWR));
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "nofile", O_RDONLY));
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ FILE *const f_rdwr_noent = dd_open_item_file(dd, "nofile", O_RDWR);
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_noent);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ fprintf(f_rdwr_noent, "%s", "f_rdwr_noent");
|
|
|
4b6aa8 |
+ rewind(f_rdwr_noent);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char rdwr_contents[256];
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent));
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdwr_contents, "f_rdwr_noent", "Successfully read data");
|
|
|
4b6aa8 |
+ fclose(f_rdwr_noent);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char *const noent_contents = dd_load_text(dd, "nofile");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(noent_contents, "f_rdwr_noent", "Successfully wrote data");
|
|
|
4b6aa8 |
+ free(noent_contents);
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDONLY | O_EXCL));
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ FILE *const f_rdonly_time = dd_open_item_file(dd, "time", O_RDONLY);
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(f_rdonly_time);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ char *time = dd_load_text(dd, "time");
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(time);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char rdonly_time_contents[16];
|
|
|
4b6aa8 |
+ char *const res = fgets(rdonly_time_contents, sizeof(rdonly_time_contents), f_rdonly_time);
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_EQ(rdonly_time_contents, res);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdonly_time_contents, time, "Read only time");
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ else {
|
|
|
4b6aa8 |
+ TS_PRINTF("File 'time' read error: %s\n", strerror(errno));
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+ fclose(f_rdonly_time);
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NULL(dd_open_item_file(dd, "time", O_RDWR | O_EXCL));
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ FILE *const f_rdwr_time = dd_open_item_file(dd, "time", O_RDWR);
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(f_rdwr_time);
|
|
|
4b6aa8 |
+ if (g_testsuite_last_ok) {
|
|
|
4b6aa8 |
+ fprintf(f_rdwr_time, "7654321");
|
|
|
4b6aa8 |
+ rewind(f_rdwr_noent);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char rdwr_contents[256];
|
|
|
4b6aa8 |
+ TS_ASSERT_PTR_IS_NOT_NULL(fgets(rdwr_contents, sizeof(rdwr_contents), f_rdwr_noent));
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(rdwr_contents, "7654321", "Successfully read time data");
|
|
|
4b6aa8 |
+ fclose(f_rdwr_time);
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ char *const time_contents = dd_load_text(dd, "time");
|
|
|
4b6aa8 |
+ TS_ASSERT_STRING_EQ(time_contents, "7654321", "Successfully wrote time data");
|
|
|
4b6aa8 |
+ free(time_contents);
|
|
|
4b6aa8 |
+ }
|
|
|
4b6aa8 |
+
|
|
|
4b6aa8 |
+ testsuite_dump_dir_delete(dd);
|
|
|
4b6aa8 |
+}
|
|
|
4b6aa8 |
+TS_RETURN_MAIN
|
|
|
4b6aa8 |
+]])
|
|
|
4b6aa8 |
--
|
|
|
4b6aa8 |
2.17.2
|
|
|
4b6aa8 |
|