libuv-svace-build

Форк
0
598 строк · 17.2 Кб
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
 *
3
 * Permission is hereby granted, free of charge, to any person obtaining a copy
4
 * of this software and associated documentation files (the "Software"), to
5
 * deal in the Software without restriction, including without limitation the
6
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
 * sell copies of the Software, and to permit persons to whom the Software is
8
 * furnished to do so, subject to the following conditions:
9
 *
10
 * The above copyright notice and this permission notice shall be included in
11
 * all copies or substantial portions of the Software.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
 * IN THE SOFTWARE.
20
 */
21

22
#include <assert.h>
23
#include <errno.h>
24
#include <stdio.h>
25
#include <string.h>
26

27
#include "uv.h"
28
#include "internal.h"
29
#include "handle-inl.h"
30
#include "req-inl.h"
31

32

33
const unsigned int uv_directory_watcher_buffer_size = 4096;
34

35

36
static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop,
37
    uv_fs_event_t* handle) {
38
  assert(handle->dir_handle != INVALID_HANDLE_VALUE);
39
  assert(!handle->req_pending);
40

41
  memset(&(handle->req.u.io.overlapped), 0,
42
         sizeof(handle->req.u.io.overlapped));
43
  if (!ReadDirectoryChangesW(handle->dir_handle,
44
                             handle->buffer,
45
                             uv_directory_watcher_buffer_size,
46
                             (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
47
                             FILE_NOTIFY_CHANGE_FILE_NAME      |
48
                               FILE_NOTIFY_CHANGE_DIR_NAME     |
49
                               FILE_NOTIFY_CHANGE_ATTRIBUTES   |
50
                               FILE_NOTIFY_CHANGE_SIZE         |
51
                               FILE_NOTIFY_CHANGE_LAST_WRITE   |
52
                               FILE_NOTIFY_CHANGE_LAST_ACCESS  |
53
                               FILE_NOTIFY_CHANGE_CREATION     |
54
                               FILE_NOTIFY_CHANGE_SECURITY,
55
                             NULL,
56
                             &handle->req.u.io.overlapped,
57
                             NULL)) {
58
    /* Make this req pending reporting an error. */
59
    SET_REQ_ERROR(&handle->req, GetLastError());
60
    uv__insert_pending_req(loop, (uv_req_t*)&handle->req);
61
  }
62

63
  handle->req_pending = 1;
64
}
65

66
static void uv__relative_path(const WCHAR* filename,
67
                              const WCHAR* dir,
68
                              WCHAR** relpath) {
69
  size_t relpathlen;
70
  size_t filenamelen = wcslen(filename);
71
  size_t dirlen = wcslen(dir);
72
  assert(!_wcsnicmp(filename, dir, dirlen));
73
  if (dirlen > 0 && dir[dirlen - 1] == '\\')
74
    dirlen--;
75
  relpathlen = filenamelen - dirlen - 1;
76
  *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
77
  if (!*relpath)
78
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
79
  wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
80
  (*relpath)[relpathlen] = L'\0';
81
}
82

83
static int uv__split_path(const WCHAR* filename, WCHAR** dir,
84
    WCHAR** file) {
85
  size_t len, i;
86
  DWORD dir_len;
87

88
  if (filename == NULL) {
89
    if (dir != NULL)
90
      *dir = NULL;
91
    *file = NULL;
92
    return 0;
93
  }
94

95
  len = wcslen(filename);
96
  i = len;
97
  while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
98

99
  if (i == 0) {
100
    if (dir) {
101
      dir_len = GetCurrentDirectoryW(0, NULL);
102
      if (dir_len == 0) {
103
        return -1;
104
      }
105
      *dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
106
      if (!*dir) {
107
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
108
      }
109

110
      if (!GetCurrentDirectoryW(dir_len, *dir)) {
111
        uv__free(*dir);
112
        *dir = NULL;
113
        return -1;
114
      }
115
    }
116

117
    *file = _wcsdup(filename);
118
  } else {
119
    if (dir) {
120
      *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
121
      if (!*dir) {
122
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
123
      }
124
      wcsncpy(*dir, filename, i + 1);
125
      (*dir)[i + 1] = L'\0';
126
    }
127

128
    *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
129
    if (!*file) {
130
      uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
131
    }
132
    wcsncpy(*file, filename + i + 1, len - i - 1);
133
    (*file)[len - i - 1] = L'\0';
134
  }
135

136
  return 0;
137
}
138

139

140
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
141
  uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
142
  handle->dir_handle = INVALID_HANDLE_VALUE;
143
  handle->buffer = NULL;
144
  handle->req_pending = 0;
145
  handle->filew = NULL;
146
  handle->short_filew = NULL;
147
  handle->dirw = NULL;
148

149
  UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
150
  handle->req.data = handle;
151

152
  return 0;
153
}
154

155

156
int uv_fs_event_start(uv_fs_event_t* handle,
157
                      uv_fs_event_cb cb,
158
                      const char* path,
159
                      unsigned int flags) {
160
  int is_path_dir;
161
  size_t size;
162
  DWORD attr, last_error;
163
  WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
164
  DWORD short_path_buffer_len;
165
  WCHAR *short_path_buffer;
166
  WCHAR* short_path, *long_path;
167

168
  short_path = NULL;
169
  if (uv__is_active(handle))
170
    return UV_EINVAL;
171

172
  handle->cb = cb;
173
  handle->path = uv__strdup(path);
174
  if (!handle->path) {
175
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
176
  }
177

178
  uv__handle_start(handle);
179

180
  last_error = uv__convert_utf8_to_utf16(path, &pathw);
181
  if (last_error)
182
    goto error_uv;
183

184
  /* Determine whether path is a file or a directory. */
185
  attr = GetFileAttributesW(pathw);
186
  if (attr == INVALID_FILE_ATTRIBUTES) {
187
    last_error = GetLastError();
188
    goto error;
189
  }
190

191
  is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
192

193
  if (is_path_dir) {
194
     /* path is a directory, so that's the directory that we will watch. */
195

196
    /* Convert to long path. */
197
    size = GetLongPathNameW(pathw, NULL, 0);
198

199
    if (size) {
200
      long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
201
      if (!long_path) {
202
        uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
203
      }
204

205
      size = GetLongPathNameW(pathw, long_path, size);
206
      if (size) {
207
        long_path[size] = '\0';
208
      } else {
209
        uv__free(long_path);
210
        long_path = NULL;
211
      }
212

213
      if (long_path) {
214
        uv__free(pathw);
215
        pathw = long_path;
216
      }
217
    }
218

219
    dir_to_watch = pathw;
220
  } else {
221
    /*
222
     * path is a file.  So we split path into dir & file parts, and
223
     * watch the dir directory.
224
     */
225

226
    /* Convert to short path. */
227
    short_path_buffer = NULL;
228
    short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
229
    if (short_path_buffer_len == 0) {
230
      goto short_path_done;
231
    }
232
    short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
233
    if (short_path_buffer == NULL) {
234
      goto short_path_done;
235
    }
236
    if (GetShortPathNameW(pathw,
237
                          short_path_buffer,
238
                          short_path_buffer_len) == 0) {
239
      uv__free(short_path_buffer);
240
      short_path_buffer = NULL;
241
    }
242
short_path_done:
243
    short_path = short_path_buffer;
244

245
    if (uv__split_path(pathw, &dir, &handle->filew) != 0) {
246
      last_error = GetLastError();
247
      goto error;
248
    }
249

250
    if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) {
251
      last_error = GetLastError();
252
      goto error;
253
    }
254

255
    dir_to_watch = dir;
256
    uv__free(pathw);
257
    pathw = NULL;
258
  }
259

260
  handle->dir_handle = CreateFileW(dir_to_watch,
261
                                   FILE_LIST_DIRECTORY,
262
                                   FILE_SHARE_READ | FILE_SHARE_DELETE |
263
                                     FILE_SHARE_WRITE,
264
                                   NULL,
265
                                   OPEN_EXISTING,
266
                                   FILE_FLAG_BACKUP_SEMANTICS |
267
                                     FILE_FLAG_OVERLAPPED,
268
                                   NULL);
269

270
  if (dir) {
271
    uv__free(dir);
272
    dir = NULL;
273
  }
274

275
  if (handle->dir_handle == INVALID_HANDLE_VALUE) {
276
    last_error = GetLastError();
277
    goto error;
278
  }
279

280
  if (CreateIoCompletionPort(handle->dir_handle,
281
                             handle->loop->iocp,
282
                             (ULONG_PTR)handle,
283
                             0) == NULL) {
284
    last_error = GetLastError();
285
    goto error;
286
  }
287

288
  if (!handle->buffer) {
289
    handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
290
  }
291
  if (!handle->buffer) {
292
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
293
  }
294

295
  memset(&(handle->req.u.io.overlapped), 0,
296
         sizeof(handle->req.u.io.overlapped));
297

298
  if (!ReadDirectoryChangesW(handle->dir_handle,
299
                             handle->buffer,
300
                             uv_directory_watcher_buffer_size,
301
                             (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
302
                             FILE_NOTIFY_CHANGE_FILE_NAME      |
303
                               FILE_NOTIFY_CHANGE_DIR_NAME     |
304
                               FILE_NOTIFY_CHANGE_ATTRIBUTES   |
305
                               FILE_NOTIFY_CHANGE_SIZE         |
306
                               FILE_NOTIFY_CHANGE_LAST_WRITE   |
307
                               FILE_NOTIFY_CHANGE_LAST_ACCESS  |
308
                               FILE_NOTIFY_CHANGE_CREATION     |
309
                               FILE_NOTIFY_CHANGE_SECURITY,
310
                             NULL,
311
                             &handle->req.u.io.overlapped,
312
                             NULL)) {
313
    last_error = GetLastError();
314
    goto error;
315
  }
316

317
  assert(is_path_dir ? pathw != NULL : pathw == NULL);
318
  handle->dirw = pathw;
319
  handle->req_pending = 1;
320
  return 0;
321

322
error:
323
  last_error = uv_translate_sys_error(last_error);
324

325
error_uv:
326
  if (handle->path) {
327
    uv__free(handle->path);
328
    handle->path = NULL;
329
  }
330

331
  if (handle->filew) {
332
    uv__free(handle->filew);
333
    handle->filew = NULL;
334
  }
335

336
  if (handle->short_filew) {
337
    uv__free(handle->short_filew);
338
    handle->short_filew = NULL;
339
  }
340

341
  uv__free(pathw);
342

343
  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
344
    CloseHandle(handle->dir_handle);
345
    handle->dir_handle = INVALID_HANDLE_VALUE;
346
  }
347

348
  if (handle->buffer) {
349
    uv__free(handle->buffer);
350
    handle->buffer = NULL;
351
  }
352

353
  if (uv__is_active(handle))
354
    uv__handle_stop(handle);
355

356
  uv__free(short_path);
357

358
  return last_error;
359
}
360

361

362
int uv_fs_event_stop(uv_fs_event_t* handle) {
363
  if (!uv__is_active(handle))
364
    return 0;
365

366
  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
367
    CloseHandle(handle->dir_handle);
368
    handle->dir_handle = INVALID_HANDLE_VALUE;
369
  }
370

371
  uv__handle_stop(handle);
372

373
  if (handle->filew) {
374
    uv__free(handle->filew);
375
    handle->filew = NULL;
376
  }
377

378
  if (handle->short_filew) {
379
    uv__free(handle->short_filew);
380
    handle->short_filew = NULL;
381
  }
382

383
  if (handle->path) {
384
    uv__free(handle->path);
385
    handle->path = NULL;
386
  }
387

388
  if (handle->dirw) {
389
    uv__free(handle->dirw);
390
    handle->dirw = NULL;
391
  }
392

393
  return 0;
394
}
395

396

397
static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
398
  size_t str_len;
399

400
  if (str == NULL)
401
    return -1;
402

403
  str_len = wcslen(str);
404

405
  /*
406
    Since we only care about equality, return early if the strings
407
    aren't the same length
408
  */
409
  if (str_len != (file_name_len / sizeof(WCHAR)))
410
    return -1;
411

412
  return _wcsnicmp(str, file_name, str_len);
413
}
414

415

416
void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
417
    uv_fs_event_t* handle) {
418
  FILE_NOTIFY_INFORMATION* file_info;
419
  int err, sizew, size;
420
  char* filename = NULL;
421
  WCHAR* filenamew = NULL;
422
  WCHAR* long_filenamew = NULL;
423
  DWORD offset = 0;
424

425
  assert(req->type == UV_FS_EVENT_REQ);
426
  assert(handle->req_pending);
427
  handle->req_pending = 0;
428

429
  /* Don't report any callbacks if:
430
   * - We're closing, just push the handle onto the endgame queue
431
   * - We are not active, just ignore the callback
432
   */
433
  if (!uv__is_active(handle)) {
434
    if (handle->flags & UV_HANDLE_CLOSING) {
435
      uv__want_endgame(loop, (uv_handle_t*) handle);
436
    }
437
    return;
438
  }
439

440
  file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
441

442
  if (REQ_SUCCESS(req)) {
443
    if (req->u.io.overlapped.InternalHigh > 0) {
444
      do {
445
        file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
446
        assert(!filename);
447
        assert(!filenamew);
448
        assert(!long_filenamew);
449

450
        /*
451
         * Fire the event only if we were asked to watch a directory,
452
         * or if the filename filter matches.
453
         */
454
        if (handle->dirw ||
455
            file_info_cmp(handle->filew,
456
                          file_info->FileName,
457
                          file_info->FileNameLength) == 0 ||
458
            file_info_cmp(handle->short_filew,
459
                          file_info->FileName,
460
                          file_info->FileNameLength) == 0) {
461

462
          if (handle->dirw) {
463
            /*
464
             * We attempt to resolve the long form of the file name explicitly.
465
             * We only do this for file names that might still exist on disk.
466
             * If this fails, we use the name given by ReadDirectoryChangesW.
467
             * This may be the long form or the 8.3 short name in some cases.
468
             */
469
            if (file_info->Action != FILE_ACTION_REMOVED &&
470
              file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
471
              /* Construct a full path to the file. */
472
              size = wcslen(handle->dirw) +
473
                file_info->FileNameLength / sizeof(WCHAR) + 2;
474

475
              filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
476
              if (!filenamew) {
477
                uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
478
              }
479

480
              _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
481
                file_info->FileNameLength / (DWORD)sizeof(WCHAR),
482
                file_info->FileName);
483

484
              filenamew[size - 1] = L'\0';
485

486
              /* Convert to long name. */
487
              size = GetLongPathNameW(filenamew, NULL, 0);
488

489
              if (size) {
490
                long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
491
                if (!long_filenamew) {
492
                  uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
493
                }
494

495
                size = GetLongPathNameW(filenamew, long_filenamew, size);
496
                if (size) {
497
                  long_filenamew[size] = '\0';
498
                } else {
499
                  uv__free(long_filenamew);
500
                  long_filenamew = NULL;
501
                }
502
              }
503

504
              uv__free(filenamew);
505

506
              if (long_filenamew) {
507
                /* Get the file name out of the long path. */
508
                uv__relative_path(long_filenamew,
509
                                  handle->dirw,
510
                                  &filenamew);
511
                uv__free(long_filenamew);
512
                long_filenamew = filenamew;
513
                sizew = -1;
514
              } else {
515
                /* We couldn't get the long filename, use the one reported. */
516
                filenamew = file_info->FileName;
517
                sizew = file_info->FileNameLength / sizeof(WCHAR);
518
              }
519
            } else {
520
              /*
521
               * Removed or renamed events cannot be resolved to the long form.
522
               * We therefore use the name given by ReadDirectoryChangesW.
523
               * This may be the long form or the 8.3 short name in some cases.
524
               */
525
              filenamew = file_info->FileName;
526
              sizew = file_info->FileNameLength / sizeof(WCHAR);
527
            }
528
          } else {
529
            /* We already have the long name of the file, so just use it. */
530
            filenamew = handle->filew;
531
            sizew = -1;
532
          }
533

534
          /* Convert the filename to utf8. */
535
          uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
536

537
          switch (file_info->Action) {
538
            case FILE_ACTION_ADDED:
539
            case FILE_ACTION_REMOVED:
540
            case FILE_ACTION_RENAMED_OLD_NAME:
541
            case FILE_ACTION_RENAMED_NEW_NAME:
542
              handle->cb(handle, filename, UV_RENAME, 0);
543
              break;
544

545
            case FILE_ACTION_MODIFIED:
546
              handle->cb(handle, filename, UV_CHANGE, 0);
547
              break;
548
          }
549

550
          uv__free(filename);
551
          filename = NULL;
552
          uv__free(long_filenamew);
553
          long_filenamew = NULL;
554
          filenamew = NULL;
555
        }
556

557
        offset = file_info->NextEntryOffset;
558
      } while (offset && !(handle->flags & UV_HANDLE_CLOSING));
559
    } else {
560
      handle->cb(handle, NULL, UV_CHANGE, 0);
561
    }
562
  } else {
563
    err = GET_REQ_ERROR(req);
564
    handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
565
  }
566

567
  if (handle->flags & UV_HANDLE_CLOSING) {
568
    uv__want_endgame(loop, (uv_handle_t*)handle);
569
  } else if (uv__is_active(handle)) {
570
    uv__fs_event_queue_readdirchanges(loop, handle);
571
  }
572
}
573

574

575
void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
576
  uv_fs_event_stop(handle);
577

578
  uv__handle_closing(handle);
579

580
  if (!handle->req_pending) {
581
    uv__want_endgame(loop, (uv_handle_t*)handle);
582
  }
583

584
}
585

586

587
void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
588
  if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
589
    assert(!(handle->flags & UV_HANDLE_CLOSED));
590

591
    if (handle->buffer) {
592
      uv__free(handle->buffer);
593
      handle->buffer = NULL;
594
    }
595

596
    uv__handle_close(handle);
597
  }
598
}
599

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.