libuv学习笔记(17)

libuv学习笔记(17)

uv_fs_event_t数据结构与相关函数

数据结构

typedef struct uv_fs_event_s uv_fs_event_t;
struct uv_fs_event_s {
  UV_HANDLE_FIELDS//uv_handle_t的成员
  /* private */
  char* path;//路径,utf8编码,由libuv申请、释放
  //UV_FS_EVENT_PRIVATE_FIELDS展开如下:
  struct uv_fs_event_req_s {                                                  
    UV_REQ_FIELDS                                                             
  } req;                 //请求                                                         
  HANDLE dir_handle;//文件夹句柄,通过CreateFileW获取                                                          
  int req_pending;//表计量,判断是否开始监听文件                                                           
  uv_fs_event_cb cb;//回调函数                                                          
  WCHAR* filew;/utf16文件名,由libuv申请、释放                                                                   
  WCHAR* short_filew;//utf16编码的短路径文件名,由libuv申请、释放                                                       
  WCHAR* dirw;//utf16编码的文件夹路径,由libuv申请、释放                                                             
  char* buffer;//存放监控返回的信息,由libuv申请、释放
};

相关函数

初始化
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
  uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);//初始化handle
  handle->dir_handle = INVALID_HANDLE_VALUE;
  handle->buffer = NULL;
  handle->req_pending = 0;
  handle->filew = NULL;
  handle->short_filew = NULL;
  handle->dirw = NULL;
  uv_req_init(loop, (uv_req_t*)&handle->req);//初始化请求
  handle->req.type = UV_FS_EVENT_REQ;//请求类型
  handle->req.data = handle;
  return 0;
}
开始event
int uv_fs_event_start(uv_fs_event_t* handle,
                      uv_fs_event_cb cb,
                      const char* path,
                      unsigned int flags) {
  int name_size, is_path_dir;
  DWORD attr, last_error;
  WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
  WCHAR short_path[MAX_PATH];
  if (uv__is_active(handle))//活动状态,返回
    return UV_EINVAL;
  handle->cb = cb;
  handle->path = uv__strdup(path);//复制路径
  if (!handle->path) {
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
  }
  uv__handle_start(handle);//设为活动状态
  //utf8转utf16   path  ------》 pathw
  ......
  //判断路径是文件还是文件夹
  attr = GetFileAttributesW(pathw);
  if (attr == INVALID_FILE_ATTRIBUTES) {
    last_error = GetLastError();
    goto error;
  }
  is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
  if (is_path_dir) {
     //路径是文件夹
    handle->dirw = pathw;
    dir_to_watch = pathw;
  } else {
    //路径是文件,获取文件名与路径
    //转换为短路径
    if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
      last_error = GetLastError();
      goto error;
    }
    //分割路径,获取路径与文件夹
    if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
      last_error = GetLastError();
      goto error;
    }

    if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
      last_error = GetLastError();
      goto error;
    }

    dir_to_watch = dir;
    uv__free(pathw);//释放
    pathw = NULL;
  }
  //获取文件夹句柄
  handle->dir_handle = CreateFileW(dir_to_watch,
                                   FILE_LIST_DIRECTORY,
                                   FILE_SHARE_READ | FILE_SHARE_DELETE |
                                     FILE_SHARE_WRITE,
                                   NULL,
                                   OPEN_EXISTING,
                                   FILE_FLAG_BACKUP_SEMANTICS |
                                     FILE_FLAG_OVERLAPPED,
                                   NULL);

  if (dir) {//在路径为文件的情况下释放文件夹路径
    uv__free(dir);
    dir = NULL;
  }
  //未能获取句柄,返回错误
  if (handle->dir_handle == INVALID_HANDLE_VALUE) {
    last_error = GetLastError();
    goto error;
  }
  //与iocp端口联系起来
  if (CreateIoCompletionPort(handle->dir_handle,
                             handle->loop->iocp,
                             (ULONG_PTR)handle,
                             0) == NULL) {
    last_error = GetLastError();
    goto error;
  }
  //分配handle->buffer内存
  if (!handle->buffer) {
    handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
  }
  if (!handle->buffer) {
    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
  }
  memset(&(handle->req.u.io.overlapped), 0,
         sizeof(handle->req.u.io.overlapped));
  //异步监控文件夹
  if (!ReadDirectoryChangesW(handle->dir_handle,
                             handle->buffer,
                             uv_directory_watcher_buffer_size,
                             (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
                             FILE_NOTIFY_CHANGE_FILE_NAME      |
                               FILE_NOTIFY_CHANGE_DIR_NAME     |
                               FILE_NOTIFY_CHANGE_ATTRIBUTES   |
                               FILE_NOTIFY_CHANGE_SIZE         |
                               FILE_NOTIFY_CHANGE_LAST_WRITE   |
                               FILE_NOTIFY_CHANGE_LAST_ACCESS  |
                               FILE_NOTIFY_CHANGE_CREATION     |
                               FILE_NOTIFY_CHANGE_SECURITY,
                             NULL,
                             &handle->req.u.io.overlapped,
                             NULL)) {
    last_error = GetLastError();
    goto error;
  }
  handle->req_pending = 1;
  return 0;
error:
  if (handle->path) {
    uv__free(handle->path);
    handle->path = NULL;
  }
  if (handle->filew) {
    uv__free(handle->filew);
    handle->filew = NULL;
  }

  if (handle->short_filew) {
    uv__free(handle->short_filew);
    handle->short_filew = NULL;
  }

  uv__free(pathw);

  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
    CloseHandle(handle->dir_handle);
    handle->dir_handle = INVALID_HANDLE_VALUE;
  }

  if (handle->buffer) {
    uv__free(handle->buffer);
    handle->buffer = NULL;
  }

  return uv_translate_sys_error(last_error);
}

在uv_process_reqs中对于监控请求的处理会调用uv_process_fs_event_req

void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
    uv_fs_event_t* handle) {
  FILE_NOTIFY_INFORMATION* file_info;
  int err, sizew, size;
  char* filename = NULL;
  WCHAR* filenamew = NULL;
  WCHAR* long_filenamew = NULL;
  DWORD offset = 0;
  assert(req->type == UV_FS_EVENT_REQ);
  assert(handle->req_pending);
  handle->req_pending = 0;//标记量改为0,表示一个当前监听已被处理
  //非激活状态下,直接返回
  //closing状态下,调用uv_want_endgame,返回
  if (!uv__is_active(handle)) {
    if (handle->flags & UV__HANDLE_CLOSING) {
      uv_want_endgame(loop, (uv_handle_t*) handle);
    }
    return;
  }
  //获取文件变动信息
  file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
  if (REQ_SUCCESS(req)) {//成功
    if (req->u.io.overlapped.InternalHigh > 0) {
      do {//循环对每一个监听到的改变调用回调函数
        file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
        assert(!filename);
        assert(!filenamew);
        assert(!long_filenamew);
        //如果监听的是文件夹,或者改变的文件名与监听的文件名匹配,那么调用回调
        if (handle->dirw ||//监听的是文件夹
          _wcsnicmp(handle->filew, file_info->FileName,
            file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
          _wcsnicmp(handle->short_filew, file_info->FileName,
            file_info->FileNameLength / sizeof(WCHAR)) == 0) {
          if (handle->dirw) {
            //监听的是文件夹
            if (file_info->Action != FILE_ACTION_REMOVED &&
              file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
              //构建文件的全路径
              size = wcslen(handle->dirw) +
                file_info->FileNameLength / sizeof(WCHAR) + 2;
              filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
              if (!filenamew) {
                uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
              }
              _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
                file_info->FileNameLength / sizeof(WCHAR),
                file_info->FileName);
              filenamew[size - 1] = L'\0';
              //转换为长路径
              size = GetLongPathNameW(filenamew, NULL, 0);

              if (size) {
                long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
                if (!long_filenamew) {
                  uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
                }
                size = GetLongPathNameW(filenamew, long_filenamew, size);
                if (size) {
                  long_filenamew[size] = '\0';
                } else {
                  uv__free(long_filenamew);
                  long_filenamew = NULL;
                }
              }
              uv__free(filenamew);
              if (long_filenamew) {
                /* Get the file name out of the long path. */
                uv_relative_path(long_filenamew,
                                 handle->dirw,
                                 &filenamew);
                uv__free(long_filenamew);
                long_filenamew = filenamew;
                sizew = -1;
              } else {
                //无法获取长路径
                filenamew = file_info->FileName;
                sizew = file_info->FileNameLength / sizeof(WCHAR);
              }
            } else {
              filenamew = file_info->FileName;
              sizew = file_info->FileNameLength / sizeof(WCHAR);
            }
          } else {
            //监控的是文件,直接使用监控的文件名
            filenamew = handle->filew;
            sizew = -1;
          }
          //将文件名转为utf8
          uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
          switch (file_info->Action) {
            case FILE_ACTION_ADDED:
            case FILE_ACTION_REMOVED:
            case FILE_ACTION_RENAMED_OLD_NAME:
            case FILE_ACTION_RENAMED_NEW_NAME:
              handle->cb(handle, filename, UV_RENAME, 0);
              break;

            case FILE_ACTION_MODIFIED:
              handle->cb(handle, filename, UV_CHANGE, 0);
              break;
          }

          uv__free(filename);
          filename = NULL;
          uv__free(long_filenamew);
          long_filenamew = NULL;
          filenamew = NULL;
        }

        offset = file_info->NextEntryOffset;
      } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
    } else {
      handle->cb(handle, NULL, UV_CHANGE, 0);
    }
  } else {
    err = GET_REQ_ERROR(req);
    handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
  }

  if (!(handle->flags & UV__HANDLE_CLOSING)) {
  //不在关闭状态,继续下一次监听,也就是调用ReadDirectoryChangesW
    uv_fs_event_queue_readdirchanges(loop, handle);
  } else {
    uv_want_endgame(loop, (uv_handle_t*)handle);
  }
}
停止监听
int uv_fs_event_stop(uv_fs_event_t* handle) {
  if (!uv__is_active(handle))
    return 0;
  //关闭句柄
  if (handle->dir_handle != INVALID_HANDLE_VALUE) {
    CloseHandle(handle->dir_handle);
    handle->dir_handle = INVALID_HANDLE_VALUE;
  }
  //停止handle
  uv__handle_stop(handle);
  //释放字符串
  if (handle->filew) {
    uv__free(handle->filew);
    handle->filew = NULL;
  }
  if (handle->short_filew) {
    uv__free(handle->short_filew);
    handle->short_filew = NULL;
  }
  if (handle->path) {
    uv__free(handle->path);
    handle->path = NULL;
  }
  if (handle->dirw) {
    uv__free(handle->dirw);
    handle->dirw = NULL;
  }
  return 0;
}

uv_fs_event_t提供了对于文件的监控(文件修改、重命名等),可以看出,实际上是监视的文件所在的文件夹。整个流程相对于其他的异步事件要简单一些,特别是停止监视的流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值