1071
1071
/* "sufficient to read at least one event." - inotify(7) */
1072
1072
const size_t ievent_size = (sizeof(struct inotify_event)
1073
1073
+ NAME_MAX + 1);
1074
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
1075
struct inotify_event *ievent = ((struct inotify_event *)
1075
struct inotify_event event;
1076
char name_buffer[NAME_MAX + 1];
1078
struct inotify_event *const ievent = &ievent_buffer.event;
1078
1080
const ssize_t read_length = read(fd, ievent, ievent_size);
1079
1081
if(read_length == 0){ /* EOF */
3675
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3676
test_fixture *fixture,
3677
__attribute__((unused))
3680
__attribute__((cleanup(cleanup_close)))
3681
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3682
g_assert_cmpint(epoll_fd, >=, 0);
3683
__attribute__((cleanup(cleanup_queue)))
3684
task_queue *queue = create_queue();
3685
g_assert_nonnull(queue);
3686
__attribute__((cleanup(string_set_clear)))
3687
string_set cancelled_filenames = {};
3688
const mono_microsecs current_time = 0;
3690
bool quit_now = false;
3691
buffer password = {};
3692
bool mandos_client_exited = false;
3693
bool password_is_read = false;
3695
__attribute__((cleanup(cleanup_string)))
3696
char *tempdir = make_temporary_directory();
3697
g_assert_nonnull(tempdir);
3699
__attribute__((cleanup(cleanup_string)))
3700
char *tempfilename = make_temporary_file_in_directory(tempdir);
3701
g_assert_nonnull(tempfilename);
3703
__attribute__((cleanup(cleanup_string)))
3704
char *targetdir = make_temporary_directory();
3705
g_assert_nonnull(targetdir);
3707
__attribute__((cleanup(cleanup_string)))
3708
char *targetfilename = NULL;
3709
g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3710
basename(tempfilename)), >, 0);
3711
g_assert_nonnull(targetfilename);
3713
g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3715
&cancelled_filenames,
3717
&mandos_client_exited,
3718
&password_is_read));
3720
g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3722
const task_context *const added_read_task
3723
= find_matching_task(queue,
3724
(task_context){ .func=read_inotify_event });
3725
g_assert_nonnull(added_read_task);
3727
/* "sufficient to read at least one event." - inotify(7) */
3728
const size_t ievent_size = (sizeof(struct inotify_event)
3730
struct inotify_event *ievent = malloc(ievent_size);
3731
g_assert_nonnull(ievent);
3733
ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3735
g_assert_cmpint((int)read_size, >, 0);
3736
g_assert_true(ievent->mask & IN_MOVED_FROM);
3737
g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3741
g_assert_cmpint(unlink(targetfilename), ==, 0);
3742
g_assert_cmpint(rmdir(targetdir), ==, 0);
3743
g_assert_cmpint(rmdir(tempdir), ==, 0);
3673
3747
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3674
3748
test_fixture *fixture,
3675
3749
__attribute__((unused))
3733
3807
g_assert_cmpint(rmdir(tempdir), ==, 0);
3811
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3812
test_fixture *fixture,
3813
__attribute__((unused))
3816
__attribute__((cleanup(cleanup_close)))
3817
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3818
g_assert_cmpint(epoll_fd, >=, 0);
3819
__attribute__((cleanup(cleanup_queue)))
3820
task_queue *queue = create_queue();
3821
g_assert_nonnull(queue);
3822
__attribute__((cleanup(string_set_clear)))
3823
string_set cancelled_filenames = {};
3824
const mono_microsecs current_time = 0;
3826
bool quit_now = false;
3827
buffer password = {};
3828
bool mandos_client_exited = false;
3829
bool password_is_read = false;
3831
__attribute__((cleanup(cleanup_string)))
3832
char *tempdir = make_temporary_directory();
3833
g_assert_nonnull(tempdir);
3835
__attribute__((cleanup(cleanup_string)))
3836
char *tempfile = make_temporary_file_in_directory(tempdir);
3837
g_assert_nonnull(tempfile);
3838
int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3840
g_assert_cmpint(tempfile_fd, >, 2);
3842
g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3844
&cancelled_filenames,
3846
&mandos_client_exited,
3847
&password_is_read));
3848
g_assert_cmpint(unlink(tempfile), ==, 0);
3850
g_assert_cmpuint((unsigned int)queue->length, >, 0);
3852
const task_context *const added_read_task
3853
= find_matching_task(queue,
3854
(task_context){ .func=read_inotify_event });
3855
g_assert_nonnull(added_read_task);
3857
g_assert_cmpint(added_read_task->fd, >, 2);
3858
g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3860
/* "sufficient to read at least one event." - inotify(7) */
3861
const size_t ievent_size = (sizeof(struct inotify_event)
3863
struct inotify_event *ievent = malloc(ievent_size);
3864
g_assert_nonnull(ievent);
3866
ssize_t read_size = 0;
3867
read_size = read(added_read_task->fd, ievent, ievent_size);
3869
g_assert_cmpint((int)read_size, >, 0);
3870
g_assert_true(ievent->mask & IN_DELETE);
3871
g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3873
g_assert_cmpint(close(tempfile_fd), ==, 0);
3875
/* IN_EXCL_UNLINK should make the closing of the previously unlinked
3876
file not appear as an ievent, so we should not see it now. */
3877
read_size = read(added_read_task->fd, ievent, ievent_size);
3878
g_assert_cmpint((int)read_size, ==, -1);
3879
g_assert_true(errno == EAGAIN);
3883
g_assert_cmpint(rmdir(tempdir), ==, 0);
3736
3886
static void test_read_inotify_event_readerror(__attribute__((unused))
3737
3887
test_fixture *fixture,
3738
3888
__attribute__((unused))
3929
4079
const size_t ievent_max_size = (sizeof(struct inotify_event)
3930
4080
+ NAME_MAX + 1);
3931
4081
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
3932
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
3933
struct inotify_event *ievent = ((struct inotify_event *)
4083
struct inotify_event event;
4084
char name_buffer[NAME_MAX + 1];
4086
struct inotify_event *const ievent = &ievent_buffer.event;
3936
4088
const char dummy_file_name[] = "ask.dummy_file_name";
3937
4089
ievent->mask = IN_CLOSE_WRITE;
3939
4091
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
3940
4092
const size_t ievent_size = (sizeof(struct inotify_event)
3941
4093
+ sizeof(dummy_file_name));
3942
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4094
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
3943
4095
==, ievent_size);
3944
4096
g_assert_cmpint(close(pipefds[1]), ==, 0);
4022
4174
const size_t ievent_max_size = (sizeof(struct inotify_event)
4023
4175
+ NAME_MAX + 1);
4024
4176
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4025
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4026
struct inotify_event *ievent = ((struct inotify_event *)
4178
struct inotify_event event;
4179
char name_buffer[NAME_MAX + 1];
4181
struct inotify_event *const ievent = &ievent_buffer.event;
4029
4183
const char dummy_file_name[] = "ask.dummy_file_name";
4030
4184
ievent->mask = IN_MOVED_TO;
4032
4186
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4033
4187
const size_t ievent_size = (sizeof(struct inotify_event)
4034
4188
+ sizeof(dummy_file_name));
4035
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4189
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4036
4190
==, ievent_size);
4037
4191
g_assert_cmpint(close(pipefds[1]), ==, 0);
4256
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4257
test_fixture *fixture,
4258
__attribute__((unused))
4259
gconstpointer user_data){
4260
__attribute__((cleanup(cleanup_close)))
4261
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4262
g_assert_cmpint(epoll_fd, >=, 0);
4263
__attribute__((cleanup(string_set_clear)))
4264
string_set cancelled_filenames = {};
4265
const mono_microsecs current_time = 0;
4268
g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4270
/* "sufficient to read at least one event." - inotify(7) */
4271
const size_t ievent_max_size = (sizeof(struct inotify_event)
4273
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4275
struct inotify_event event;
4276
char name_buffer[NAME_MAX + 1];
4278
struct inotify_event *const ievent = &ievent_buffer.event;
4280
const char dummy_file_name[] = "ask.dummy_file_name";
4281
ievent->mask = IN_MOVED_FROM;
4282
ievent->len = sizeof(dummy_file_name);
4283
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4284
const size_t ievent_size = (sizeof(struct inotify_event)
4285
+ sizeof(dummy_file_name));
4286
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4288
g_assert_cmpint(close(pipefds[1]), ==, 0);
4290
bool quit_now = false;
4291
buffer password = {};
4292
bool mandos_client_exited = false;
4293
bool password_is_read = false;
4294
__attribute__((cleanup(cleanup_queue)))
4295
task_queue *queue = create_queue();
4296
g_assert_nonnull(queue);
4298
task_context task = {
4299
.func=read_inotify_event,
4302
.quit_now=&quit_now,
4303
.password=&password,
4304
.filename=strdup("/nonexistent"),
4305
.cancelled_filenames=&cancelled_filenames,
4306
.current_time=¤t_time,
4307
.mandos_client_exited=&mandos_client_exited,
4308
.password_is_read=&password_is_read,
4310
task.func(task, queue);
4311
g_assert_false(quit_now);
4312
g_assert_true(queue->next_run == 0);
4313
g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4315
g_assert_nonnull(find_matching_task(queue, (task_context){
4316
.func=read_inotify_event,
4319
.quit_now=&quit_now,
4320
.password=&password,
4321
.filename=task.filename,
4322
.cancelled_filenames=&cancelled_filenames,
4323
.current_time=¤t_time,
4324
.mandos_client_exited=&mandos_client_exited,
4325
.password_is_read=&password_is_read,
4328
g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4329
EPOLLIN | EPOLLRDHUP));
4331
__attribute__((cleanup(cleanup_string)))
4332
char *filename = NULL;
4333
g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4334
dummy_file_name), >, 0);
4335
g_assert_nonnull(filename);
4336
g_assert_true(string_set_contains(*task.cancelled_filenames,
4101
4340
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4102
4341
test_fixture *fixture,
4103
4342
__attribute__((unused))
4117
4356
const size_t ievent_max_size = (sizeof(struct inotify_event)
4118
4357
+ NAME_MAX + 1);
4119
4358
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4120
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4121
struct inotify_event *ievent = ((struct inotify_event *)
4360
struct inotify_event event;
4361
char name_buffer[NAME_MAX + 1];
4363
struct inotify_event *const ievent = &ievent_buffer.event;
4124
4365
const char dummy_file_name[] = "ask.dummy_file_name";
4125
4366
ievent->mask = IN_DELETE;
4127
4368
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4128
4369
const size_t ievent_size = (sizeof(struct inotify_event)
4129
4370
+ sizeof(dummy_file_name));
4130
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4371
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4131
4372
==, ievent_size);
4132
4373
g_assert_cmpint(close(pipefds[1]), ==, 0);
4199
4440
const size_t ievent_max_size = (sizeof(struct inotify_event)
4200
4441
+ NAME_MAX + 1);
4201
4442
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4202
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4203
struct inotify_event *ievent = ((struct inotify_event *)
4444
struct inotify_event event;
4445
char name_buffer[NAME_MAX + 1];
4447
struct inotify_event *const ievent = &ievent_buffer.event;
4206
4449
const char dummy_file_name[] = "ignored.dummy_file_name";
4207
4450
ievent->mask = IN_CLOSE_WRITE;
4209
4452
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4210
4453
const size_t ievent_size = (sizeof(struct inotify_event)
4211
4454
+ sizeof(dummy_file_name));
4212
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4455
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4213
4456
==, ievent_size);
4214
4457
g_assert_cmpint(close(pipefds[1]), ==, 0);
4273
4516
const size_t ievent_max_size = (sizeof(struct inotify_event)
4274
4517
+ NAME_MAX + 1);
4275
4518
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4276
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4277
struct inotify_event *ievent = ((struct inotify_event *)
4520
struct inotify_event event;
4521
char name_buffer[NAME_MAX + 1];
4523
struct inotify_event *const ievent = &ievent_buffer.event;
4280
4525
const char dummy_file_name[] = "ignored.dummy_file_name";
4281
4526
ievent->mask = IN_MOVED_TO;
4283
4528
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4284
4529
const size_t ievent_size = (sizeof(struct inotify_event)
4285
4530
+ sizeof(dummy_file_name));
4286
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4531
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4287
4532
==, ievent_size);
4288
4533
g_assert_cmpint(close(pipefds[1]), ==, 0);
4330
4575
EPOLLIN | EPOLLRDHUP));
4579
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4580
test_fixture *fixture,
4581
__attribute__((unused))
4584
__attribute__((cleanup(cleanup_close)))
4585
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4586
g_assert_cmpint(epoll_fd, >=, 0);
4587
__attribute__((cleanup(string_set_clear)))
4588
string_set cancelled_filenames = {};
4589
const mono_microsecs current_time = 0;
4592
g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4594
/* "sufficient to read at least one event." - inotify(7) */
4595
const size_t ievent_max_size = (sizeof(struct inotify_event)
4597
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4599
struct inotify_event event;
4600
char name_buffer[NAME_MAX + 1];
4602
struct inotify_event *const ievent = &ievent_buffer.event;
4604
const char dummy_file_name[] = "ignored.dummy_file_name";
4605
ievent->mask = IN_MOVED_FROM;
4606
ievent->len = sizeof(dummy_file_name);
4607
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4608
const size_t ievent_size = (sizeof(struct inotify_event)
4609
+ sizeof(dummy_file_name));
4610
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4612
g_assert_cmpint(close(pipefds[1]), ==, 0);
4614
bool quit_now = false;
4615
buffer password = {};
4616
bool mandos_client_exited = false;
4617
bool password_is_read = false;
4618
__attribute__((cleanup(cleanup_queue)))
4619
task_queue *queue = create_queue();
4620
g_assert_nonnull(queue);
4622
task_context task = {
4623
.func=read_inotify_event,
4626
.quit_now=&quit_now,
4627
.password=&password,
4628
.filename=strdup("/nonexistent"),
4629
.cancelled_filenames=&cancelled_filenames,
4630
.current_time=¤t_time,
4631
.mandos_client_exited=&mandos_client_exited,
4632
.password_is_read=&password_is_read,
4634
task.func(task, queue);
4635
g_assert_false(quit_now);
4636
g_assert_true(queue->next_run == 0);
4637
g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4639
g_assert_nonnull(find_matching_task(queue, (task_context){
4640
.func=read_inotify_event,
4643
.quit_now=&quit_now,
4644
.password=&password,
4645
.filename=task.filename,
4646
.cancelled_filenames=&cancelled_filenames,
4647
.current_time=¤t_time,
4648
.mandos_client_exited=&mandos_client_exited,
4649
.password_is_read=&password_is_read,
4652
g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4653
EPOLLIN | EPOLLRDHUP));
4655
__attribute__((cleanup(cleanup_string)))
4656
char *filename = NULL;
4657
g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4658
dummy_file_name), >, 0);
4659
g_assert_nonnull(filename);
4660
g_assert_false(string_set_contains(cancelled_filenames, filename));
4334
4664
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4335
4665
test_fixture *fixture,
4350
4680
const size_t ievent_max_size = (sizeof(struct inotify_event)
4351
4681
+ NAME_MAX + 1);
4352
4682
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4353
char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
4354
struct inotify_event *ievent = ((struct inotify_event *)
4684
struct inotify_event event;
4685
char name_buffer[NAME_MAX + 1];
4687
struct inotify_event *const ievent = &ievent_buffer.event;
4357
4689
const char dummy_file_name[] = "ignored.dummy_file_name";
4358
4690
ievent->mask = IN_DELETE;
4360
4692
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4361
4693
const size_t ievent_size = (sizeof(struct inotify_event)
4362
4694
+ sizeof(dummy_file_name));
4363
g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4695
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4364
4696
==, ievent_size);
4365
4697
g_assert_cmpint(close(pipefds[1]), ==, 0);
7579
7911
test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7580
7912
test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7581
7913
test_add_inotify_dir_watch_IN_MOVED_TO);
7914
test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
7915
test_add_inotify_dir_watch_IN_MOVED_FROM);
7916
test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
7917
test_add_inotify_dir_watch_IN_EXCL_UNLINK);
7582
7918
test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7583
7919
test_add_inotify_dir_watch_IN_DELETE);
7584
7920
test_add_st("/task/read_inotify_event/readerror",
7593
7929
test_read_inotify_event_IN_CLOSE_WRITE);
7594
7930
test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7595
7931
test_read_inotify_event_IN_MOVED_TO);
7932
test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
7933
test_read_inotify_event_IN_MOVED_FROM);
7596
7934
test_add_st("/task/read_inotify_event/IN_DELETE",
7597
7935
test_read_inotify_event_IN_DELETE);
7598
7936
test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7599
7937
test_read_inotify_event_IN_CLOSE_WRITE_badname);
7600
7938
test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7601
7939
test_read_inotify_event_IN_MOVED_TO_badname);
7940
test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
7941
test_read_inotify_event_IN_MOVED_FROM_badname);
7602
7942
test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7603
7943
test_read_inotify_event_IN_DELETE_badname);
7604
7944
test_add_st("/task/open_and_parse_question/ENOENT",