diff options
Diffstat (limited to 'src/kqueue.c')
| -rw-r--r-- | src/kqueue.c | 190 |
1 files changed, 140 insertions, 50 deletions
diff --git a/src/kqueue.c b/src/kqueue.c index 0425a142a98..2097b7ed492 100644 --- a/src/kqueue.c +++ b/src/kqueue.c | |||
| @@ -35,16 +35,42 @@ static int kqueuefd = -1; | |||
| 35 | /* This is a list, elements are (DESCRIPTOR FILE FLAGS CALLBACK [DIRLIST]) */ | 35 | /* This is a list, elements are (DESCRIPTOR FILE FLAGS CALLBACK [DIRLIST]) */ |
| 36 | static Lisp_Object watch_list; | 36 | static Lisp_Object watch_list; |
| 37 | 37 | ||
| 38 | /* Generate a temporary list from the directory_files_internal output. | ||
| 39 | Items are (INODE FILE_NAME LAST_MOD LAST_STATUS_MOD SIZE). */ | ||
| 40 | Lisp_Object | ||
| 41 | kqueue_directory_listing (Lisp_Object directory_files) | ||
| 42 | { | ||
| 43 | Lisp_Object dl, result = Qnil; | ||
| 44 | for (dl = directory_files; ! NILP (dl); dl = XCDR (dl)) { | ||
| 45 | result = Fcons | ||
| 46 | (list5 (/* inode. */ | ||
| 47 | XCAR (Fnthcdr (make_number (11), XCAR (dl))), | ||
| 48 | /* filename. */ | ||
| 49 | XCAR (XCAR (dl)), | ||
| 50 | /* last modification time. */ | ||
| 51 | XCAR (Fnthcdr (make_number (6), XCAR (dl))), | ||
| 52 | /* last status change time. */ | ||
| 53 | XCAR (Fnthcdr (make_number (7), XCAR (dl))), | ||
| 54 | /* size. */ | ||
| 55 | XCAR (Fnthcdr (make_number (8), XCAR (dl)))), | ||
| 56 | result); | ||
| 57 | } | ||
| 58 | return result; | ||
| 59 | } | ||
| 60 | |||
| 38 | /* Generate a file notification event. */ | 61 | /* Generate a file notification event. */ |
| 39 | static void | 62 | static void |
| 40 | kqueue_generate_event | 63 | kqueue_generate_event |
| 41 | (Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object callback) | 64 | (Lisp_Object ident, Lisp_Object actions, Lisp_Object file, Lisp_Object file1, Lisp_Object callback) |
| 42 | { | 65 | { |
| 43 | struct input_event event; | 66 | struct input_event event; |
| 44 | EVENT_INIT (event); | 67 | EVENT_INIT (event); |
| 45 | event.kind = FILE_NOTIFY_EVENT; | 68 | event.kind = FILE_NOTIFY_EVENT; |
| 46 | event.frame_or_window = Qnil; | 69 | event.frame_or_window = Qnil; |
| 47 | event.arg = list2 (Fcons (ident, Fcons (actions, Fcons (file, Qnil))), | 70 | event.arg = list2 (Fcons (ident, Fcons (actions, |
| 71 | NILP (file1) | ||
| 72 | ? Fcons (file, Qnil) | ||
| 73 | : list2 (file, file1))), | ||
| 48 | callback); | 74 | callback); |
| 49 | 75 | ||
| 50 | /* Store it into the input event queue. */ | 76 | /* Store it into the input event queue. */ |
| @@ -53,73 +79,140 @@ kqueue_generate_event | |||
| 53 | 79 | ||
| 54 | /* This compares two directory listings in case of a `write' event for | 80 | /* This compares two directory listings in case of a `write' event for |
| 55 | a directory. The old directory listing is stored in watch_object, | 81 | a directory. The old directory listing is stored in watch_object, |
| 56 | it will be replaced by a new directory listing at the end. */ | 82 | it will be replaced by a new directory listing at the end of this |
| 83 | function. */ | ||
| 57 | static void | 84 | static void |
| 58 | kqueue_compare_dir_list (Lisp_Object watch_object) | 85 | kqueue_compare_dir_list |
| 86 | (Lisp_Object watch_object) | ||
| 59 | { | 87 | { |
| 60 | Lisp_Object dir, callback, old_dl, new_dl, dl, actions; | 88 | Lisp_Object dir, callback, actions; |
| 89 | Lisp_Object old_directory_files, old_dl, new_directory_files, new_dl, dl; | ||
| 61 | 90 | ||
| 62 | dir = XCAR (XCDR (watch_object)); | 91 | dir = XCAR (XCDR (watch_object)); |
| 63 | callback = XCAR (XCDR (XCDR (XCDR (watch_object)))); | 92 | callback = XCAR (Fnthcdr (make_number (3), watch_object)); |
| 64 | old_dl = XCAR (XCDR (XCDR (XCDR (XCDR (watch_object))))); | 93 | old_directory_files = XCAR (Fnthcdr (make_number (4), watch_object)); |
| 65 | new_dl = directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil); | 94 | old_dl = kqueue_directory_listing (old_directory_files); |
| 66 | 95 | new_directory_files = | |
| 67 | for (dl = old_dl; ! NILP (dl); dl = XCDR (dl)) { | 96 | directory_files_internal (dir, Qnil, Qnil, Qnil, 1, Qnil); |
| 97 | new_dl = kqueue_directory_listing (new_directory_files); | ||
| 98 | |||
| 99 | /* Parse through the old list. */ | ||
| 100 | dl = old_dl; | ||
| 101 | while (1) { | ||
| 68 | Lisp_Object old_entry, new_entry; | 102 | Lisp_Object old_entry, new_entry; |
| 69 | old_entry = XCAR (dl); | 103 | if (NILP (dl)) |
| 70 | new_entry = Fassoc (XCAR (old_entry), new_dl); | 104 | break; |
| 71 | 105 | ||
| 72 | /* We ignore "." and "..". */ | 106 | /* We ignore "." and "..". */ |
| 73 | if ((strcmp (".", SSDATA (XCAR (old_entry))) == 0) || | 107 | old_entry = XCAR (dl); |
| 74 | (strcmp ("..", SSDATA (XCAR (old_entry))) == 0)) | 108 | if ((strcmp (".", SSDATA (XCAR (XCDR (old_entry)))) == 0) || |
| 75 | continue; | 109 | (strcmp ("..", SSDATA (XCAR (XCDR (old_entry)))) == 0)) |
| 110 | goto the_end; | ||
| 76 | 111 | ||
| 77 | /* A file has disappeared. */ | 112 | /* Search for an entry with the same inode. */ |
| 78 | if (NILP (new_entry)) | 113 | new_entry = Fassoc (XCAR (old_entry), new_dl); |
| 79 | kqueue_generate_event | 114 | if (! NILP (Fequal (old_entry, new_entry))) { |
| 80 | (XCAR (watch_object), Fcons (Qdelete, Qnil), | 115 | /* Both entries are identical. Nothing happens. */ |
| 81 | XCAR (old_entry), callback); | 116 | new_dl = Fdelq (new_entry, new_dl); |
| 82 | 117 | goto the_end; | |
| 83 | else { | 118 | } |
| 84 | /* A file has changed. We compare last modification time. */ | 119 | |
| 85 | if (NILP | 120 | if (! NILP (new_entry)) { |
| 86 | (Fequal | 121 | /* Both entries have the same inode. */ |
| 87 | (XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (old_entry))))))), | 122 | if (strcmp (SSDATA (XCAR (XCDR (old_entry))), |
| 88 | XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (new_entry)))))))))) | 123 | SSDATA (XCAR (XCDR (new_entry)))) == 0) { |
| 124 | /* Both entries have the same file name. */ | ||
| 125 | if (! NILP (Fequal (XCAR (Fnthcdr (make_number (2), old_entry)), | ||
| 126 | XCAR (Fnthcdr (make_number (2), new_entry))))) | ||
| 127 | /* Modification time has been changed, the file has been written. */ | ||
| 128 | kqueue_generate_event | ||
| 129 | (XCAR (watch_object), Fcons (Qwrite, Qnil), | ||
| 130 | XCAR (XCDR (old_entry)), Qnil, callback); | ||
| 131 | if (! NILP (Fequal (XCAR (Fnthcdr (make_number (3), old_entry)), | ||
| 132 | XCAR (Fnthcdr (make_number (3), new_entry))))) | ||
| 133 | /* Status change time has been changed, the file attributes | ||
| 134 | have changed. */ | ||
| 135 | kqueue_generate_event | ||
| 136 | (XCAR (watch_object), Fcons (Qattrib, Qnil), | ||
| 137 | XCAR (XCDR (old_entry)), Qnil, callback); | ||
| 138 | |||
| 139 | } else { | ||
| 140 | /* The file has been renamed. */ | ||
| 89 | kqueue_generate_event | 141 | kqueue_generate_event |
| 90 | (XCAR (watch_object), Fcons (Qwrite, Qnil), | 142 | (XCAR (watch_object), Fcons (Qrename, Qnil), |
| 91 | XCAR (old_entry), callback); | 143 | XCAR (XCDR (old_entry)), XCAR (XCDR (new_entry)), callback); |
| 144 | } | ||
| 145 | new_dl = Fdelq (new_entry, new_dl); | ||
| 146 | goto the_end; | ||
| 147 | } | ||
| 92 | 148 | ||
| 93 | /* A file attribute has changed. We compare last status change time. */ | 149 | /* Search, whether there is a file with the same name (with |
| 94 | if (NILP | 150 | another inode). */ |
| 95 | (Fequal | 151 | Lisp_Object dl1; |
| 96 | (XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (old_entry)))))))), | 152 | for (dl1 = new_dl; ! NILP (dl1); dl1 = XCDR (dl1)) { |
| 97 | XCAR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (XCDR (new_entry))))))))))) | 153 | new_entry = XCAR (dl1); |
| 154 | if (strcmp (SSDATA (XCAR (XCDR (old_entry))), | ||
| 155 | SSDATA (XCAR (XCDR (new_entry)))) == 0) { | ||
| 98 | kqueue_generate_event | 156 | kqueue_generate_event |
| 99 | (XCAR (watch_object), Fcons (Qattrib, Qnil), | 157 | (XCAR (watch_object), Fcons (Qwrite, Qnil), |
| 100 | XCAR (old_entry), callback); | 158 | XCAR (XCDR (old_entry)), Qnil, callback); |
| 159 | new_dl = Fdelq (new_entry, new_dl); | ||
| 160 | goto the_end; | ||
| 161 | } | ||
| 101 | } | 162 | } |
| 163 | |||
| 164 | /* A file has been deleted. */ | ||
| 165 | kqueue_generate_event | ||
| 166 | (XCAR (watch_object), Fcons (Qdelete, Qnil), | ||
| 167 | XCAR (XCDR (old_entry)), Qnil, callback); | ||
| 168 | |||
| 169 | the_end: | ||
| 170 | dl = XCDR (dl); | ||
| 171 | old_dl = Fdelq (old_entry, old_dl); | ||
| 102 | } | 172 | } |
| 103 | 173 | ||
| 104 | for (dl = new_dl; ! NILP (dl); dl = XCDR (dl)) { | 174 | /* Parse through the shortened new list. */ |
| 105 | Lisp_Object old_entry, new_entry; | 175 | dl = new_dl; |
| 106 | new_entry = XCAR (dl); | 176 | while (1) { |
| 107 | old_entry = Fassoc (XCAR (new_entry), old_dl); | 177 | Lisp_Object new_entry; |
| 178 | if (NILP (dl)) | ||
| 179 | break; | ||
| 108 | 180 | ||
| 109 | /* We ignore "." and "..". */ | 181 | /* We ignore "." and "..". */ |
| 110 | if ((strcmp (".", SSDATA (XCAR (new_entry))) == 0) || | 182 | new_entry = XCAR (dl); |
| 111 | (strcmp ("..", SSDATA (XCAR (new_entry))) == 0)) | 183 | if ((strcmp (".", SSDATA (XCAR (XCDR (new_entry)))) == 0) || |
| 184 | (strcmp ("..", SSDATA (XCAR (XCDR (new_entry)))) == 0)) { | ||
| 185 | dl = XCDR (dl); | ||
| 186 | new_dl = Fdelq (new_entry, new_dl); | ||
| 112 | continue; | 187 | continue; |
| 188 | } | ||
| 113 | 189 | ||
| 114 | /* A new file has appeared. */ | 190 | /* A new file has appeared. */ |
| 115 | if (NILP (old_entry)) | 191 | kqueue_generate_event |
| 192 | (XCAR (watch_object), Fcons (Qcreate, Qnil), | ||
| 193 | XCAR (XCDR (new_entry)), Qnil, callback); | ||
| 194 | |||
| 195 | /* Check size of that file. */ | ||
| 196 | Lisp_Object size = XCAR (Fnthcdr (make_number (4), new_entry)); | ||
| 197 | if (FLOATP (size) || (XINT (size) > 0)) | ||
| 116 | kqueue_generate_event | 198 | kqueue_generate_event |
| 117 | (XCAR (watch_object), Fcons (Qcreate, Qnil), | 199 | (XCAR (watch_object), Fcons (Qwrite, Qnil), |
| 118 | XCAR (new_entry), callback); | 200 | XCAR (XCDR (new_entry)), Qnil, callback); |
| 201 | |||
| 202 | dl = XCDR (dl); | ||
| 203 | new_dl = Fdelq (new_entry, new_dl); | ||
| 119 | } | 204 | } |
| 120 | 205 | ||
| 206 | /* At this point, both old_dl and new_dl shall be empty. Let's make | ||
| 207 | a check for this (might be removed once the code is stable). */ | ||
| 208 | if (! NILP (old_dl)) | ||
| 209 | report_file_error ("Old list not empty", old_dl); | ||
| 210 | if (! NILP (new_dl)) | ||
| 211 | report_file_error ("New list not empty", new_dl); | ||
| 212 | |||
| 121 | /* Replace directory listing with the new one. */ | 213 | /* Replace directory listing with the new one. */ |
| 122 | XSETCDR (XCDR (XCDR (XCDR (watch_object))), Fcons (new_dl, Qnil)); | 214 | XSETCDR (XCDR (XCDR (XCDR (watch_object))), |
| 215 | Fcons (new_directory_files, Qnil)); | ||
| 123 | return; | 216 | return; |
| 124 | } | 217 | } |
| 125 | 218 | ||
| @@ -173,7 +266,7 @@ kqueue_callback (int fd, void *data) | |||
| 173 | 266 | ||
| 174 | /* Construct an event. */ | 267 | /* Construct an event. */ |
| 175 | if (! NILP (actions)) | 268 | if (! NILP (actions)) |
| 176 | kqueue_generate_event (monitor_object, actions, file, callback); | 269 | kqueue_generate_event (monitor_object, actions, file, Qnil, callback); |
| 177 | 270 | ||
| 178 | /* Cancel monitor if file or directory is deleted. */ | 271 | /* Cancel monitor if file or directory is deleted. */ |
| 179 | if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) | 272 | if (kev.fflags & (NOTE_DELETE | NOTE_RENAME)) |
| @@ -352,9 +445,6 @@ syms_of_kqueue (void) | |||
| 352 | 445 | ||
| 353 | #endif /* HAVE_KQUEUE */ | 446 | #endif /* HAVE_KQUEUE */ |
| 354 | 447 | ||
| 355 | /* TODO | ||
| 356 | * Add FILE1 in case of `rename'. */ | ||
| 357 | |||
| 358 | /* PROBLEMS | 448 | /* PROBLEMS |
| 359 | * https://bugs.launchpad.net/ubuntu/+source/libkqueue/+bug/1514837 | 449 | * https://bugs.launchpad.net/ubuntu/+source/libkqueue/+bug/1514837 |
| 360 | prevents tests on Ubuntu. */ | 450 | prevents tests on Ubuntu. */ |