HashValue ContentHashCache::computeHashImmediate()

in watchman/ContentHash.cpp [57:140]


HashValue ContentHashCache::computeHashImmediate(const char* fullPath) {
  HashValue result;
  uint8_t buf[8192];

  auto stm = w_stm_open(fullPath, O_RDONLY);
  if (!stm) {
    throw std::system_error(
        errno,
        std::generic_category(),
        to<std::string>("w_stm_open ", fullPath));
  }

#ifndef _WIN32
  SHA_CTX ctx;
  SHA1_Init(&ctx);

  while (true) {
    auto n = stm->read(buf, sizeof(buf));
    if (n == 0) {
      break;
    }
    if (n < 0) {
      throw std::system_error(
          errno,
          std::generic_category(),
          to<std::string>("while reading from ", fullPath));
    }
    SHA1_Update(&ctx, buf, n);
  }

  SHA1_Final(result.data(), &ctx);
#else
  // Use the built-in crypt provider API on windows to avoid introducing a
  // dependency on openssl in the windows build.
  HCRYPTPROV provider{0};
  HCRYPTHASH ctx{0};

  if (!CryptAcquireContext(
          &provider,
          nullptr,
          nullptr,
          PROV_RSA_FULL,
          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
    throw std::system_error(
        GetLastError(), std::system_category(), "CryptAcquireContext");
  }
  SCOPE_EXIT {
    CryptReleaseContext(provider, 0);
  };

  if (!CryptCreateHash(provider, CALG_SHA1, 0, 0, &ctx)) {
    throw std::system_error(
        GetLastError(), std::system_category(), "CryptCreateHash");
  }
  SCOPE_EXIT {
    CryptDestroyHash(ctx);
  };

  while (true) {
    auto n = stm->read(buf, sizeof(buf));
    if (n == 0) {
      break;
    }
    if (n < 0) {
      throw std::system_error(
          errno,
          std::generic_category(),
          to<std::string>("while reading from ", fullPath));
    }

    if (!CryptHashData(ctx, buf, n, 0)) {
      throw std::system_error(
          GetLastError(), std::system_category(), "CryptHashData");
    }
  }

  DWORD size = result.size();
  if (!CryptGetHashParam(ctx, HP_HASHVAL, result.data(), &size, 0)) {
    throw std::system_error(
        GetLastError(), std::system_category(), "CryptGetHashParam HP_HASHVAL");
  }
#endif
  return result;
}