Lines 1-5
Link Here
|
1 |
/*- |
1 |
/*- |
2 |
* Copyright (c) 2016 - 2019 Rozhuk Ivan <rozhuk.im@gmail.com> |
2 |
* Copyright (c) 2016 - 2021 Rozhuk Ivan <rozhuk.im@gmail.com> |
3 |
* All rights reserved. |
3 |
* All rights reserved. |
4 |
* |
4 |
* |
5 |
* Redistribution and use in source and binary forms, with or without |
5 |
* Redistribution and use in source and binary forms, with or without |
Lines 130-142
typedef struct kq_file_mon_msg_pkt_s {
Link Here
|
130 |
#define KF_MSG_PKT_MAGIC 0xffddaa00 |
130 |
#define KF_MSG_PKT_MAGIC 0xffddaa00 |
131 |
|
131 |
|
132 |
|
132 |
|
|
|
133 |
#ifdef O_PATH |
134 |
# define OPEN_MODE_FLAG O_PATH |
135 |
#elif defined(O_EVTONLY) |
136 |
# define OPEN_MODE_FLAG O_EVTONLY |
137 |
#else |
138 |
# define OPEN_MODE_FLAG O_RDONLY |
139 |
#endif |
133 |
#ifndef O_NOATIME |
140 |
#ifndef O_NOATIME |
134 |
# define O_NOATIME 0 |
141 |
# define O_NOATIME 0 |
135 |
#endif |
142 |
#endif |
136 |
#ifndef O_EVTONLY |
143 |
#define OPEN_FILE_MON_FLAGS (O_NONBLOCK | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | OPEN_MODE_FLAG) |
137 |
# define O_EVTONLY O_RDONLY |
144 |
#define OPEN_FILE_READ_FLAGS (O_NONBLOCK | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | O_RDONLY) |
138 |
#endif |
|
|
139 |
#define OPEN_FILE_FLAGS (O_EVTONLY | O_NONBLOCK | O_NOFOLLOW | O_NOATIME | O_CLOEXEC) |
140 |
|
145 |
|
141 |
#ifndef NOTE_CLOSE_WRITE |
146 |
#ifndef NOTE_CLOSE_WRITE |
142 |
# define NOTE_CLOSE_WRITE 0 |
147 |
# define NOTE_CLOSE_WRITE 0 |
Lines 273-321
mounts_find_name(struct statfs *mounts, size_t mounts_count,
Link Here
|
273 |
} |
278 |
} |
274 |
|
279 |
|
275 |
|
280 |
|
|
|
281 |
static void |
282 |
readdir_free(readdir_ctx_p rdd) { |
283 |
|
284 |
if (NULL == rdd) |
285 |
return; |
286 |
|
287 |
if (-1 != rdd->fd) { |
288 |
close(rdd->fd); |
289 |
rdd->fd = -1; |
290 |
} |
291 |
if (NULL != rdd->buf) { |
292 |
free(rdd->buf); |
293 |
rdd->buf = NULL; |
294 |
} |
295 |
} |
296 |
|
276 |
static int |
297 |
static int |
277 |
readdir_start(int fd, struct stat *sb, size_t exp_count, readdir_ctx_p rdd) { |
298 |
readdir_start(const int fd, struct stat *sb, const size_t exp_count, |
278 |
size_t buf_size; |
299 |
readdir_ctx_p rdd) { |
|
|
300 |
struct stat _sb; |
279 |
|
301 |
|
280 |
if (-1 == fd || NULL == sb || NULL == rdd) |
302 |
if (-1 == fd || NULL == rdd) |
281 |
return (EINVAL); |
303 |
return (EINVAL); |
282 |
if (-1 == lseek(fd, 0, SEEK_SET)) |
304 |
|
|
|
305 |
if (NULL == sb) { |
306 |
sb = &_sb; |
307 |
if (0 != fstat(fd, sb)) |
308 |
return (errno); |
309 |
} |
310 |
/* Init. */ |
311 |
memset(rdd, 0x00, sizeof(readdir_ctx_t)); |
312 |
/* Reopen for read. */ |
313 |
rdd->fd = openat(fd, ".", (OPEN_FILE_READ_FLAGS | O_DIRECTORY)); |
314 |
if (-1 == rdd->fd) |
283 |
return (errno); |
315 |
return (errno); |
284 |
/* Calculate buf size for getdents(). */ |
316 |
/* Calculate buf size for getdents(). */ |
285 |
buf_size = MAX((size_t)sb->st_size, (exp_count * sizeof(struct dirent))); |
317 |
rdd->buf_size = MAX((size_t)sb->st_size, (exp_count * sizeof(struct dirent))); |
286 |
if (0 == buf_size) { |
318 |
if (0 == rdd->buf_size) { |
287 |
buf_size = (16 * PAGE_SIZE); |
319 |
rdd->buf_size = (16 * PAGE_SIZE); |
288 |
} |
320 |
} |
289 |
/* Make buf size well aligned. */ |
321 |
/* Make buf size well aligned. */ |
290 |
if (0 != sb->st_blksize) { |
322 |
if (0 != sb->st_blksize) { |
291 |
if (powerof2(sb->st_blksize)) { |
323 |
if (powerof2(sb->st_blksize)) { |
292 |
buf_size = roundup2(buf_size, sb->st_blksize); |
324 |
rdd->buf_size = roundup2(rdd->buf_size, sb->st_blksize); |
293 |
} else { |
325 |
} else { |
294 |
buf_size = roundup(buf_size, sb->st_blksize); |
326 |
rdd->buf_size = roundup(rdd->buf_size, sb->st_blksize); |
295 |
} |
327 |
} |
296 |
} else { |
328 |
} else { |
297 |
buf_size = round_page(buf_size); |
329 |
rdd->buf_size = round_page(rdd->buf_size); |
298 |
} |
330 |
} |
299 |
/* Init. */ |
331 |
/* Allocate buf. */ |
300 |
memset(rdd, 0x00, sizeof(readdir_ctx_t)); |
332 |
rdd->buf = malloc(rdd->buf_size); |
301 |
rdd->buf = malloc(buf_size); |
333 |
if (NULL == rdd->buf) { |
302 |
if (NULL == rdd->buf) |
334 |
readdir_free(rdd); |
303 |
return (ENOMEM); |
335 |
return (ENOMEM); |
304 |
rdd->buf_size = buf_size; |
336 |
} |
305 |
rdd->fd = fd; |
|
|
306 |
|
337 |
|
307 |
return (0); |
338 |
return (0); |
308 |
} |
339 |
} |
309 |
|
340 |
|
310 |
static void |
|
|
311 |
readdir_free(readdir_ctx_p rdd) { |
312 |
|
313 |
if (NULL == rdd || NULL == rdd->buf) |
314 |
return; |
315 |
free(rdd->buf); |
316 |
memset(rdd, 0x00, sizeof(readdir_ctx_t)); |
317 |
} |
318 |
|
319 |
static int |
341 |
static int |
320 |
readdir_next(readdir_ctx_p rdd, struct dirent *de) { |
342 |
readdir_next(readdir_ctx_p rdd, struct dirent *de) { |
321 |
int error = 0; |
343 |
int error = 0; |
Lines 362-368
readdir_next(readdir_ctx_p rdd, struct dirent *de) {
Link Here
|
362 |
return (0); /* OK. */ |
384 |
return (0); /* OK. */ |
363 |
} |
385 |
} |
364 |
|
386 |
|
365 |
/* Err or no more files. */ |
387 |
/* Err or no more files, auto cleanup. */ |
366 |
readdir_free(rdd); |
388 |
readdir_free(rdd); |
367 |
|
389 |
|
368 |
return (error); |
390 |
return (error); |
Lines 678-684
kq_fnmo_readdir(kq_fnmo_p fnmo, size_t exp_count) {
Link Here
|
678 |
fnmo->files = NULL; |
700 |
fnmo->files = NULL; |
679 |
fnmo->files_count = 0; |
701 |
fnmo->files_count = 0; |
680 |
fnmo->files_allocated = 0; |
702 |
fnmo->files_allocated = 0; |
681 |
readdir_free(&rdd); |
703 |
readdir_free(&rdd); /* Force cleanup here. */ |
682 |
return (ENOMEM); |
704 |
return (ENOMEM); |
683 |
} |
705 |
} |
684 |
de = &fnmo->files[fnmo->files_count].de; /* Use short name. */ |
706 |
de = &fnmo->files[fnmo->files_count].de; /* Use short name. */ |
Lines 697-702
kq_fnmo_readdir(kq_fnmo_p fnmo, size_t exp_count) {
Link Here
|
697 |
fnmo->files[fnmo->files_count].fd = -1; |
719 |
fnmo->files[fnmo->files_count].fd = -1; |
698 |
fnmo->files_count ++; |
720 |
fnmo->files_count ++; |
699 |
} |
721 |
} |
|
|
722 |
|
700 |
/* Mem compact. */ |
723 |
/* Mem compact. */ |
701 |
tmfi = reallocarray(fnmo->files, sizeof(file_info_t), (fnmo->files_count + 1)); |
724 |
tmfi = reallocarray(fnmo->files, sizeof(file_info_t), (fnmo->files_count + 1)); |
702 |
if (NULL != tmfi) { /* realloc ok. */ |
725 |
if (NULL != tmfi) { /* realloc ok. */ |
Lines 704-711
kq_fnmo_readdir(kq_fnmo_p fnmo, size_t exp_count) {
Link Here
|
704 |
fnmo->files_allocated = (fnmo->files_count + 1); |
727 |
fnmo->files_allocated = (fnmo->files_count + 1); |
705 |
} |
728 |
} |
706 |
|
729 |
|
707 |
readdir_free(&rdd); |
|
|
708 |
|
709 |
return (0); /* OK. */ |
730 |
return (0); /* OK. */ |
710 |
} |
731 |
} |
711 |
|
732 |
|
Lines 716-728
kq_fnmo_fi_start(kq_fnmo_p fnmo, file_info_p fi) {
Link Here
|
716 |
|
737 |
|
717 |
if (NULL == fnmo || -1 == fnmo->fd || NULL == fi) |
738 |
if (NULL == fnmo || -1 == fnmo->fd || NULL == fi) |
718 |
return; |
739 |
return; |
719 |
fi->fd = openat(fnmo->fd, fi->de.d_name, OPEN_FILE_FLAGS); |
740 |
/* Filter files that can not be monitored, redice openat() calls. */ |
|
|
741 |
switch (fi->de.d_type) { |
742 |
case DT_FIFO: |
743 |
case DT_SOCK: |
744 |
#ifdef DT_WHT |
745 |
case DT_WHT: |
746 |
#endif |
747 |
return; |
748 |
} |
749 |
fi->fd = openat(fnmo->fd, fi->de.d_name, OPEN_FILE_MON_FLAGS); |
720 |
if (-1 == fi->fd) |
750 |
if (-1 == fi->fd) |
721 |
return; |
751 |
return; |
722 |
EV_SET(&kev, fi->fd, EVFILT_VNODE, |
752 |
EV_SET(&kev, fi->fd, EVFILT_VNODE, |
723 |
(EV_ADD | EV_CLEAR), |
753 |
(EV_ADD | EV_CLEAR), |
724 |
EVFILT_VNODE_SUB_FLAGS, 0, fnmo); |
754 |
EVFILT_VNODE_SUB_FLAGS, 0, fnmo); |
725 |
kevent(fnmo->kfnm->fd, &kev, 1, NULL, 0, NULL); |
755 |
if (-1 == kevent(fnmo->kfnm->fd, &kev, 1, NULL, 0, NULL)) { |
|
|
756 |
close(fi->fd); |
757 |
fi->fd = -1; |
758 |
} |
726 |
} |
759 |
} |
727 |
|
760 |
|
728 |
static int |
761 |
static int |
Lines 757-763
kq_fnmo_reopen_fd(kq_fnmo_p fnmo) {
Link Here
|
757 |
fnmo->fd = -1; |
790 |
fnmo->fd = -1; |
758 |
} |
791 |
} |
759 |
|
792 |
|
760 |
fd = open(fnmo->path, OPEN_FILE_FLAGS); |
793 |
fd = open(fnmo->path, (OPEN_FILE_MON_FLAGS | O_DIRECTORY)); |
761 |
if (-1 == fd) |
794 |
if (-1 == fd) |
762 |
return (errno); |
795 |
return (errno); |
763 |
if (0 != fstat(fd, &fnmo->sb)) { |
796 |
if (0 != fstat(fd, &fnmo->sb)) { |
Lines 1021-1036
notify_removed:
Link Here
|
1021 |
/* Get parent folder name. */ |
1054 |
/* Get parent folder name. */ |
1022 |
fnmo->path[fnmo->name_offset] = 0; |
1055 |
fnmo->path[fnmo->name_offset] = 0; |
1023 |
/* Try to open. */ |
1056 |
/* Try to open. */ |
1024 |
up_dir_fd = open(fnmo->path, (OPEN_FILE_FLAGS | O_DIRECTORY)); |
1057 |
up_dir_fd = open(fnmo->path, (OPEN_FILE_MON_FLAGS | O_DIRECTORY)); |
1025 |
/* Restore '/' after parent folder. */ |
1058 |
/* Restore '/' after parent folder. */ |
1026 |
fnmo->path[fnmo->name_offset] = '/'; |
1059 |
fnmo->path[fnmo->name_offset] = '/'; |
1027 |
if (-1 == up_dir_fd) |
1060 |
if (-1 == up_dir_fd) |
1028 |
goto notify_removed_errno; |
1061 |
goto notify_removed_errno; |
1029 |
if (0 != fstat(up_dir_fd, &sb)) { |
1062 |
error = readdir_start(up_dir_fd, NULL, 0, &rdd); |
1030 |
close(up_dir_fd); |
|
|
1031 |
goto notify_removed_errno; |
1032 |
} |
1033 |
error = readdir_start(up_dir_fd, &sb, 0, &rdd); |
1034 |
if (0 != error) { |
1063 |
if (0 != error) { |
1035 |
close(up_dir_fd); |
1064 |
close(up_dir_fd); |
1036 |
goto notify_removed; |
1065 |
goto notify_removed; |
Lines 1039-1044
notify_removed:
Link Here
|
1039 |
while (0 == readdir_next(&rdd, &de)) { |
1068 |
while (0 == readdir_next(&rdd, &de)) { |
1040 |
if (0 == fstatat(up_dir_fd, de.d_name, &sb, AT_SYMLINK_NOFOLLOW) && |
1069 |
if (0 == fstatat(up_dir_fd, de.d_name, &sb, AT_SYMLINK_NOFOLLOW) && |
1041 |
0 == memcmp(&fnmo->sb, &sb, sizeof(struct stat))) { |
1070 |
0 == memcmp(&fnmo->sb, &sb, sizeof(struct stat))) { |
|
|
1071 |
readdir_free(&rdd); /* Force cleanup here. */ |
1042 |
found ++; |
1072 |
found ++; |
1043 |
break; |
1073 |
break; |
1044 |
} |
1074 |
} |