return TAKE_FD(fd);
}
+
+int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created) {
+ unsigned attempts = 7;
+
+ /* Just like openat(), but adds one thing: optionally returns whether we created the file anew or if
+ * it already existed before. This is only relevant of O_CREAT is set without O_EXCL, and thus will
+ * shortcut to openat() otherwise */
+
+ if (!FLAGS_SET(flags, O_CREAT) || FLAGS_SET(flags, O_EXCL) || !ret_newly_created)
+ return RET_NERRNO(openat(dirfd, pathname, flags, mode));
+
+ for (;;) {
+ int fd;
+
+ /* First, attempt to open without O_CREAT/O_EXCL, i.e. open existing file */
+ fd = openat(dirfd, pathname, flags & ~(O_CREAT | O_EXCL), mode);
+ if (fd >= 0) {
+ *ret_newly_created = false;
+ return fd;
+ }
+ if (errno != ENOENT)
+ return -errno;
+
+ /* So the file didn't exist yet, hence create it with O_CREAT/O_EXCL. */
+ fd = openat(dirfd, pathname, flags | O_CREAT | O_EXCL, mode);
+ if (fd >= 0) {
+ *ret_newly_created = true;
+ return fd;
+ }
+ if (errno != EEXIST)
+ return -errno;
+
+ /* Hmm, so now we got EEXIST? So it apparently exists now? If so, let's try to open again
+ * without the two flags. But let's not spin forever, hnce put a limit on things */
+
+ if (--attempts == 0) /* Give up eventually, somebody is playing with us */
+ return -EEXIST;
+ }
+}
int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
+
+int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
assert_se(subsubdir_fd >= 0);
}
+TEST(openat_report_new) {
+ _cleanup_free_ char *j = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
+ _cleanup_close_ int fd = -1;
+ bool b;
+
+ assert_se(mkdtemp_malloc(NULL, &d) >= 0);
+
+ j = path_join(d, "test");
+ assert_se(j);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(b);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(!b);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(!b);
+
+ assert_se(unlink(j) >= 0);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(b);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(!b);
+
+ assert_se(unlink(j) >= 0);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, NULL);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+
+ fd = openat_report_new(AT_FDCWD, j, O_RDWR|O_CREAT, 0666, &b);
+ assert_se(fd >= 0);
+ fd = safe_close(fd);
+ assert_se(!b);
+}
+
static int intro(void) {
arg_test_dir = saved_argv[1];
return EXIT_SUCCESS;