diff --git a/src/bwrap-lock.c b/src/bwrap-lock.c index 991f1e73f5ca42351bfc521f390f185fe8c1e6f7..69c183bcc3e4d72abfb61a28edc99f95729a7005 100644 --- a/src/bwrap-lock.c +++ b/src/bwrap-lock.c @@ -55,6 +55,8 @@ struct _PvBwrapLock /** * pv_bwrap_lock_new: + * @at_fd: If not `AT_FDCWD` or -1, look up @path relative to this + * directory fd instead of the current working directory, as per `openat(2)` * @path: File to lock * @flags: Flags affecting how we lock the file * @error: Used to raise an error on failure @@ -74,7 +76,8 @@ struct _PvBwrapLock * or %NULL. */ PvBwrapLock * -pv_bwrap_lock_new (const gchar *path, +pv_bwrap_lock_new (int at_fd, + const gchar *path, PvBwrapLockFlags flags, GError **error) { @@ -95,7 +98,8 @@ pv_bwrap_lock_new (const gchar *path, else open_flags |= O_RDONLY; - fd = TEMP_FAILURE_RETRY (openat (AT_FDCWD, path, open_flags, 0644)); + at_fd = glnx_dirfd_canonicalize (at_fd); + fd = TEMP_FAILURE_RETRY (openat (at_fd, path, open_flags, 0644)); if (fd < 0) { diff --git a/src/bwrap-lock.h b/src/bwrap-lock.h index 562d28e5eb01dea1281d12deb1e8dfe161c4cc18..41c5aba6ec55bc7396e7ccd3c32328af5b5190d0 100644 --- a/src/bwrap-lock.h +++ b/src/bwrap-lock.h @@ -56,7 +56,8 @@ typedef enum typedef struct _PvBwrapLock PvBwrapLock; -PvBwrapLock *pv_bwrap_lock_new (const gchar *path, +PvBwrapLock *pv_bwrap_lock_new (int at_fd, + const gchar *path, PvBwrapLockFlags flags, GError **error); PvBwrapLock *pv_bwrap_lock_new_take (int fd, diff --git a/src/runtime.c b/src/runtime.c index 89ef744bb93eca11474b87b14ff72f8db863c16f..b4def4e1de4e7f1808360b230de1ef201f902c4c 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -314,7 +314,7 @@ pv_runtime_initable_init (GInitable *initable, /* Take a lock on the runtime until we're finished with setup, * to make sure it doesn't get deleted. */ files_ref = g_build_filename (self->source_files, ".ref", NULL); - self->runtime_lock = pv_bwrap_lock_new (files_ref, + self->runtime_lock = pv_bwrap_lock_new (AT_FDCWD, files_ref, PV_BWRAP_LOCK_FLAGS_CREATE, error); diff --git a/src/with-lock.c b/src/with-lock.c index cf185dc7de556b422d2bf0c151ee7c0d93ec3f49..2ac1b4331155ccdb5a8ee4fe5eedcd5b76d855bb 100644 --- a/src/with-lock.c +++ b/src/with-lock.c @@ -117,7 +117,7 @@ opt_lock_file_cb (const char *name, if (opt_wait) flags |= PV_BWRAP_LOCK_FLAGS_WAIT; - lock = pv_bwrap_lock_new (value, flags, error); + lock = pv_bwrap_lock_new (AT_FDCWD, value, flags, error); if (lock == NULL) return FALSE; diff --git a/tests/bwrap-lock.c b/tests/bwrap-lock.c index 7e3fa0d622b9e7e1e4313983b73c64759be4ffb1..6fe95c39f9dd40d6e820e61f93dc95f41bd5f29c 100644 --- a/tests/bwrap-lock.c +++ b/tests/bwrap-lock.c @@ -78,12 +78,14 @@ test_locks (Fixture *f, lock = g_build_filename (tmpdir.path, "lockfile", NULL); /* Take a shared (read) lock */ - read_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_CREATE, &error); + read_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_CREATE, + &error); g_assert_no_error (error); g_assert_nonnull (read_lock1); /* We cannot take an exclusive (write) lock at the same time */ - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_WRITE, + &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock1); g_clear_error (&error); @@ -92,7 +94,8 @@ test_locks (Fixture *f, is_ofd = pv_bwrap_lock_is_ofd (read_lock1); fd = pv_bwrap_lock_steal_fd (read_lock1); g_assert_cmpint (fd, >=, 0); - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_WRITE, + &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock1); g_clear_error (&error); @@ -101,7 +104,8 @@ test_locks (Fixture *f, /* The lock is held even after we free the original lock abstraction */ g_clear_pointer (&read_lock1, pv_bwrap_lock_free); - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_WRITE, + &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock1); g_clear_error (&error); @@ -109,35 +113,41 @@ test_locks (Fixture *f, /* We can make a new lock from an existing one */ read_lock1 = pv_bwrap_lock_new_take (glnx_steal_fd (&fd), is_ofd); g_assert_nonnull (read_lock1); - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_WRITE, + &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock1); g_clear_error (&error); /* We can take a second read lock at the same time */ - read_lock2 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_CREATE, &error); + read_lock2 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_CREATE, + &error); g_assert_no_error (error); g_assert_nonnull (read_lock2); /* Releasing one read lock is not enough */ g_clear_pointer (&read_lock1, pv_bwrap_lock_free); - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (AT_FDCWD, lock, PV_BWRAP_LOCK_FLAGS_WRITE, + &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock1); g_clear_error (&error); - /* Releasing both read locks is enough to allow a write lock */ + /* Releasing both read locks is enough to allow a write lock. This + * incidentally also tests the normalization of -1 to AT_FDCWD. */ g_clear_pointer (&read_lock2, pv_bwrap_lock_free); - write_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + write_lock1 = pv_bwrap_lock_new (-1, lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); g_assert_no_error (error); g_assert_nonnull (write_lock1); - /* We cannot take read or write locks while this lock is held */ - write_lock2 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); + /* We cannot take read or write locks while this lock is held. + * The second part here also exercises a non-trivial at_fd. */ + write_lock2 = pv_bwrap_lock_new (-1, lock, PV_BWRAP_LOCK_FLAGS_WRITE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (write_lock2); g_clear_error (&error); - read_lock1 = pv_bwrap_lock_new (lock, PV_BWRAP_LOCK_FLAGS_NONE, &error); + read_lock1 = pv_bwrap_lock_new (tmpdir.fd, "lockfile", + PV_BWRAP_LOCK_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_BUSY); g_assert_null (read_lock1); g_clear_error (&error);