+ ret = rmdir(test_directory);
+ ok(ret == 0, "Test directory is empty");
+ fd_tracker_destroy(tracker);
+ lttng_directory_handle_put(dir_handle);
+end:
+ free(test_directory);
+ free(unlinked_files_directory);
+}
+
+static
+void test_unlink(void)
+{
+ int ret;
+ struct fd_tracker *tracker;
+ const int handles_to_open = 2;
+ struct fs_handle *handles[handles_to_open];
+ struct fs_handle *new_handle = NULL;
+ struct stat statbuf;
+ struct lttng_directory_handle *dir_handle = NULL;
+ const char file_name[] = "my_file";
+ char *test_directory = NULL, *unlinked_files_directory = NULL;
+ char *unlinked_file_zero = NULL, *unlinked_file_one = NULL;
+ int fd;
+
+ get_temporary_directories(&test_directory, &unlinked_files_directory);
+ ret = asprintf(&unlinked_file_zero, "%s/%u", unlinked_files_directory,
+ 0);
+ assert(ret > 0);
+ ret = asprintf(&unlinked_file_one, "%s/%u", unlinked_files_directory,
+ 1);
+ assert(ret > 0);
+
+ tracker = fd_tracker_create(unlinked_files_directory, 1);
+ if (!tracker) {
+ goto end;
+ }
+
+ dir_handle = lttng_directory_handle_create(test_directory);
+ assert(dir_handle);
+
+ /* Open two handles to the same file. */
+ ret = open_same_file(tracker, dir_handle, file_name, handles_to_open,
+ handles);
+ ok(!ret, "Successfully opened %i handles to %s/%s", handles_to_open,
+ test_directory, file_name);
+ if (ret) {
+ goto end;
+ }
+
+ /*
+ * Unlinking the first handle should cause the file to be renamed
+ * to '0'.
+ */
+ ret = fs_handle_unlink(handles[0]);
+ ok(!ret, "Successfully unlinked the first handle to %s/%s",
+ test_directory, file_name);
+
+ /*
+ * The original file should no longer exist on the file system, and a
+ * new file named '0' should exist.
+ */
+ ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
+ errno == ENOENT,
+ "%s no longer present on file system after unlink",
+ file_name);
+ ok(lttng_directory_handle_stat(
+ dir_handle, unlinked_file_zero, &statbuf) == 0,
+ "%s exists on file system after unlink",
+ unlinked_file_zero);
+
+ /*
+ * It should be possible to use the file descriptors of both handles.
+ * Since only one file descriptor can be opened at once, this should
+ * force the fd_tracker to suspend and restore the handles.
+ */
+ fd = fs_handle_get_fd(handles[0]);
+ ok(fd >= 0, "Got fd from first handle");
+
+ fd = fs_handle_get_fd(handles[1]);
+ ok (fd < 0, "fd tracker does not allow two fds to be used at once");
+
+ fs_handle_put_fd(handles[0]);
+ fd = fs_handle_get_fd(handles[1]);
+ ok(fd >= 0, "Got fd from second handle");
+ fs_handle_put_fd(handles[1]);
+
+ /* The second unlink should fail with -ENOENT. */
+ ret = fs_handle_unlink(handles[1]);
+ ok(ret == -ENOENT,
+ "ENOENT is reported when attempting to unlink the second handle to %s/%s",
+ test_directory, file_name);
+
+ /*
+ * Opening a new handle to 'my_file' should succeed.
+ */
+ ret = open_same_file(tracker, dir_handle, file_name, 1, &new_handle);
+ ok(!ret, "Successfully opened a new handle to previously unlinked file %s/%s",
+ test_directory, file_name);
+ assert(new_handle);
+
+ /*
+ * Unlinking the new handle should cause the file to be renamed
+ * to '1' since '0' already exists.
+ */
+ ret = fs_handle_unlink(new_handle);
+ ok(!ret, "Successfully unlinked the new handle handle to %s/%s",
+ test_directory, file_name);
+ ok(stat(unlinked_file_one, &statbuf) == 0,
+ "%s exists on file system after unlink",
+ unlinked_file_one);
+
+ ret = fs_handle_close(handles[0]);
+ ok(!ret, "Successfully closed the first handle");
+ ret = fs_handle_close(handles[1]);
+ ok(!ret, "Successfully closed the second handle");
+ ret = fs_handle_close(new_handle);
+ ok(!ret, "Successfully closed the third handle");
+
+ ok(lttng_directory_handle_stat(dir_handle, file_name, &statbuf) == -1 &&
+ errno == ENOENT,
+ "%s no longer present on file system after handle close",
+ file_name);
+ ok(lttng_directory_handle_stat(
+ dir_handle, unlinked_file_zero, &statbuf) == -1 &&
+ errno == ENOENT,
+ "%s no longer present on file system after handle close",
+ unlinked_file_zero);
+ ok(lttng_directory_handle_stat(dir_handle, unlinked_file_one,
+ &statbuf) == -1 &&
+ errno == ENOENT,
+ "%s no longer present on file system after handle close",
+ unlinked_file_one);
+
+ ret = rmdir(test_directory);
+ ok(ret == 0, "Test directory is empty");
+end:
+ fd_tracker_destroy(tracker);
+ free(test_directory);
+ free(unlinked_files_directory);
+ free(unlinked_file_zero);
+ free(unlinked_file_one);
+ lttng_directory_handle_put(dir_handle);