Пример #1
0
 std::string read(HKEY hive) const {
     HKEY keyHandle;
     // RegGetValue would let us replace most of this function with a single line but "Requires Windows Vista or Windows XP Professional x64 Edition".
     LONG errorCode = RegOpenKey(hive, keyName, &keyHandle);
     if (errorCode != ERROR_SUCCESS) {
         throw WindowsError("RegOpenKey(" + toString(hive) + ", " + keyName + ", &keyHandle)", errorCode);
     }
     // MAX_PATH seems likely to be enough.
     std::vector<BYTE> buffer(MAX_PATH);
     DWORD type;
     DWORD size = buffer.size();
     // FIXME: We could make some effort towards Unicode support.
     errorCode = RegQueryValueEx(keyHandle, valueName, 0, &type, &buffer[0], &size);
     if (errorCode != ERROR_SUCCESS) {
         throw WindowsError("RegQueryValueEx(" + toString(keyHandle) + " (\"" + keyName + "\"), \"" + valueName + "\", 0, &type, &buffer[0], &size)", errorCode);
     }
     if (type != REG_SZ) {
         throw std::runtime_error("The type of registry entry hive " + toString(hive) + ", key " + keyName + ", value " + valueName + " was not REG_SZ (" + toString(REG_SZ) + ") as expected but " + toString(type));
     }
     // MSDN's article on RegQueryValueEx explains that the value may or may not include the null terminator.
     if (size != 0 && buffer[size - 1] == 0) {
         -- size;
     }
     return std::string(reinterpret_cast<const char*>(&buffer[0]), size);
 }
Пример #2
0
inline Try<Nothing> nonblock(int fd)
{
  if (net::is_socket(fd)) {
    const u_long non_block_mode = 1;
    u_long mode = non_block_mode;

    int result = ioctlsocket(fd, FIONBIO, &mode);
    if (result != NO_ERROR) {
      return WindowsSocketError();
    }
  } else {
    // Extract handle from file descriptor.
    HANDLE handle = reinterpret_cast<HANDLE>(::_get_osfhandle(fd));
    if (handle == INVALID_HANDLE_VALUE) {
      return WindowsError("Failed to get `HANDLE` for file descriptor");
    }

    if (GetFileType(handle) == FILE_TYPE_PIPE) {
      DWORD pipe_mode = PIPE_NOWAIT;
      if (SetNamedPipeHandleState(handle, &pipe_mode, nullptr, nullptr)) {
        return WindowsError();
      }
    }
  }

  return Nothing();
}
Пример #3
0
inline Result<PROCESSENTRY32> process_entry(pid_t pid)
{
  // Get a snapshot of the processes in the system. NOTE: We should not check
  // whether the handle is `NULL`, because this API will always return
  // `INVALID_HANDLE_VALUE` on error.
  HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid);
  if (snapshot_handle == INVALID_HANDLE_VALUE) {
    return WindowsError(
        "os::process_entry: Call to `CreateToolhelp32Snapshot` failed");
  }

  SharedHandle safe_snapshot_handle(snapshot_handle, ::CloseHandle);

  // Initialize process entry.
  PROCESSENTRY32 process_entry;
  ZeroMemory(&process_entry, sizeof(PROCESSENTRY32));
  process_entry.dwSize = sizeof(PROCESSENTRY32);

  // Get first process so that we can loop through process entries until we
  // find the one we care about.
  SetLastError(ERROR_SUCCESS);
  bool has_next = Process32First(safe_snapshot_handle.get(), &process_entry);
  if (!has_next) {
    // No first process was found. We should never be here; it is arguable we
    // should return `None`, since we won't find the PID we're looking for, but
    // we elect to return `Error` because something terrible has probably
    // happened.
    if (GetLastError() != ERROR_SUCCESS) {
      return WindowsError("os::process_entry: Call to `Process32First` failed");
    } else {
      return Error("os::process_entry: Call to `Process32First` failed");
    }
  }

  // Loop through processes until we find the one we're looking for.
  while (has_next) {
    if (process_entry.th32ProcessID == pid) {
      // Process found.
      return process_entry;
    }

    has_next = Process32Next(safe_snapshot_handle.get(), &process_entry);
    if (!has_next) {
      DWORD last_error = GetLastError();
      if (last_error != ERROR_NO_MORE_FILES && last_error != ERROR_SUCCESS) {
        return WindowsError(
            "os::process_entry: Call to `Process32Next` failed");
      }
    }
  }

  return None();
}
Пример #4
0
// Overload of os::pids for filtering by groups and sessions. A group / session
// id of 0 will fitler on the group / session ID of the calling process.
// NOTE: Windows does not have the concept of a process group, so we need to
// enumerate all processes.
inline Try<std::set<pid_t>> pids(Option<pid_t> group, Option<pid_t> session)
{
  DWORD max_items = 4096;
  DWORD bytes_returned;
  std::vector<pid_t> processes;
  size_t size_in_bytes;

  // Attempt to populate `processes` with PIDs. We repeatedly call
  // `EnumProcesses` with increasingly large arrays until it "succeeds" at
  // populating the array with PIDs. The criteria for determining when
  // `EnumProcesses` has succeeded are:
  //   (1) the return value is nonzero.
  //   (2) the `bytes_returned` is less than the number of bytes in the array.
  do {
    // TODO(alexnaparu): Set a limit to the memory that can be used.
    processes.resize(max_items);
    size_in_bytes = processes.size() * sizeof(pid_t);
    BOOL result = ::EnumProcesses(processes.data(), size_in_bytes,
                                  &bytes_returned);

    if (!result) {
      return WindowsError("os::pids: Call to `EnumProcesses` failed");
    }

    max_items *= 2;
  } while (bytes_returned >= size_in_bytes);

  return std::set<pid_t>(processes.begin(), processes.end());
}
Пример #5
0
fmt::LongLong fmt::File::size() const {
#ifdef _WIN32
  // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
  // is less than 0x0500 as is the case with some default MinGW builds.
  // Both functions support large file sizes.
  DWORD size_upper = 0;
  HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
  DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
  if (size_lower == INVALID_FILE_SIZE) {
    DWORD error = GetLastError();
    if (error != NO_ERROR)
      throw WindowsError(GetLastError(), "cannot get file size");
  }
  fmt::ULongLong long_size = size_upper;
  return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
#else
  typedef struct stat Stat;
  Stat file_stat = Stat();
  if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
    throw SystemError(errno, "cannot get file attributes");
  FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
      "return type of File::size is not large enough");
  return file_stat.st_size;
#endif
}
Пример #6
0
// Creates a file for a subprocess's stdin, stdout, or stderr.
//
// NOTE: For portability, Libprocess implements POSIX-style semantics for these
// files, and make no assumptions about who has access to them. For example, we
// do not enforce a process-level write lock on stdin, and we do not enforce a
// similar read lock from stdout.
//
// TODO(hausdorff): Rethink name here, write a comment about this function.
static Try<HANDLE> createIoPath(const string& path, DWORD accessFlags)
{
  // Per function comment, the flags `FILE_SHARE_READ`, `FILE_SHARE_WRITE`, and
  // `OPEN_ALWAYS` are all important. The former two make sure we do not
  // acquire a process-level lock on reading/writing the file, and the last one
  // ensures that we open the file if it exists, and create it if it does not.
  // Note that we specify both `FILE_SHARE_READ` and `FILE_SHARE_WRITE` because
  // the documentation is not clear about whether `FILE_SHARE_WRITE` also
  // ensures we don't take a read lock out.
  SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE };
  const HANDLE handle = ::CreateFile(
      path.c_str(),
      accessFlags,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      &sa,
      OPEN_ALWAYS,
      FILE_ATTRIBUTE_NORMAL,
      nullptr);

  if (handle == INVALID_HANDLE_VALUE) {
    return WindowsError("Failed to open '" + path + "'");
  }

  return handle;
}
Пример #7
0
inline Try<Nothing> rename(
    const std::string& from,
    const std::string& to,
    bool sync = false)
{
  // Use `MoveFile` to perform the file move. The MSVCRT implementation of
  // `::rename` fails if the `to` file already exists[1], while some UNIX
  // implementations allow that[2].
  //
  // Use `MOVEFILE_COPY_ALLOWED` to allow moving the file to another volume and
  // `MOVEFILE_REPLACE_EXISTING` to comply with the UNIX implementation and
  // replace an existing file[3].
  //
  // [1] https://msdn.microsoft.com/en-us/library/zw5t957f.aspx
  // [2] http://man7.org/linux/man-pages/man2/rename.2.html
  // [3] https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx
  const BOOL result = ::MoveFileExW(
      ::internal::windows::longpath(from).data(),
      ::internal::windows::longpath(to).data(),
      MOVEFILE_COPY_ALLOWED |
        MOVEFILE_REPLACE_EXISTING |
        (sync ? MOVEFILE_WRITE_THROUGH : 0));

  if (!result) {
    return WindowsError(
        "`os::rename` failed to move file '" + from + "' to '" + to + "'");
  }

  return Nothing();
}
Пример #8
0
// Returns a `Try` of the result of attempting to set the `hostname`.
inline Try<Nothing> setHostname(const std::string& hostname)
{
  if (SetComputerName(hostname.c_str()) == 0) {
    return WindowsError();
  }

  return Nothing();
}
Пример #9
0
 static inline T* checkIgnore (const char* function, T* value, ErrorNumType ignore) {
   if (!value) {
     ErrorNumType errnum = getLastError ();
     if (errnum != ignore)
       throw WindowsError (function, errnum);
   }
   return value;
 }
Пример #10
0
 static inline uint32_t checkIgnore (const char* function, uint32_t value, ErrorNumType ignore) {
   if (value == 0) {
     ErrorNumType errnum = getLastError ();
     if (errnum != ignore)
       throw WindowsError (function, errnum);
   }
   return value;
 }
Пример #11
0
// Returns a `Try` of the result of attempting to set the `hostname`.
inline Try<Nothing> setHostname(const std::string& hostname)
{
  if (::SetComputerNameW(wide_stringify(hostname).data()) == 0) {
    return WindowsError();
  }

  return Nothing();
}
Пример #12
0
void Keyboard::WindowsModifierKey(ModifierKeycode key, bool up)
{
    WORD wkey;
    switch(key)
    {
    case ModCtrlL:
        wkey = VK_LCONTROL;
        break;
    case ModCtrlR:
        wkey = VK_RCONTROL;
        break;
    case ModCtrl:
        wkey = VK_CONTROL;
        break;
    case ModAltL:
        wkey = VK_LMENU;
        break;
    case ModAltR:
        wkey = VK_RMENU;
        break;
    case ModAlt:
        wkey = VK_MENU;
        break;
    case ModShiftL:
        wkey = VK_LSHIFT;
        break;
    case ModShiftR:
        wkey = VK_RSHIFT;
        break;
    case ModShift:
        wkey = VK_SHIFT;
        break;
    case ModMetaL:
        wkey = VK_LWIN; // This might not have any effect, Windows key may be read-only at user level
        break;
    case ModMetaR:
        wkey = VK_RWIN;
        break;
    case ModMeta:
        wkey = VK_LWIN; // Windows has no generic 'sideless' windows key, so just use left
        break;
    default:
        wkey = 0;
        break;
    }
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = wkey;
    input.ki.wScan = 0;
    input.ki.dwFlags = up ? KEYEVENTF_KEYUP : 0;
    input.ki.time = 0;
    input.ki.dwExtraInfo = (ULONG_PTR)NULL;

    if (SendInput(1, &input, sizeof(INPUT)) != 1)
    {
        WindowsError("SendInput");
    }
}
Пример #13
0
inline Try<Version> release()
{
  OSVERSIONINFOEX os_version;
  os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  if (!::GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&os_version))) {
    return WindowsError("os::release: Call to `GetVersionEx` failed");
  }

  return Version(os_version.dwMajorVersion, os_version.dwMinorVersion, 0);
}
Пример #14
0
static Try<HANDLE> getHandleFromFileDescriptor(int_fd fd)
{
  // Extract handle from file descriptor.
  const HANDLE handle = fd;
  if (handle == INVALID_HANDLE_VALUE) {
    return WindowsError("Failed to get `HANDLE` for file descriptor");
  }

  return handle;
}
Пример #15
0
static Try<HANDLE> getHandleFromFileDescriptor(int fd)
{
  // Extract handle from file descriptor.
  const HANDLE handle = reinterpret_cast<HANDLE>(::_get_osfhandle(fd));
  if (handle == INVALID_HANDLE_VALUE) {
    return WindowsError("Failed to get `HANDLE` for file descriptor");
  }

  return handle;
}
Пример #16
0
// This function enables or disables inheritance for a Windows file handle.
//
// NOTE: By default, handles on Windows are not inheritable, so this is
// primarily used to enable inheritance when passing handles to child processes,
// and subsequently disable inheritance.
inline Try<Nothing> set_inherit(const os::WindowsFD& fd, const bool inherit)
{
  const BOOL result = ::SetHandleInformation(
      fd, HANDLE_FLAG_INHERIT, inherit ? HANDLE_FLAG_INHERIT : 0);

  if (result == FALSE) {
    return WindowsError();
  }

  return Nothing();
}
Пример #17
0
inline Try<OSVERSIONINFOEX> os_version()
{
  OSVERSIONINFOEX os_version;
  os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  if (!::GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&os_version))) {
    return WindowsError(
        "os::internal::os_version: Call to `GetVersionEx` failed");
  }

  return os_version;
}
Пример #18
0
inline Try<std::string> nodename()
{
  // Get DNS name of the local computer. First, find the size of the output
  // buffer.
  DWORD size = 0;
  if (!::GetComputerNameEx(ComputerNameDnsHostname, NULL, &size) &&
      ::GetLastError() != ERROR_MORE_DATA) {
    return WindowsError(
        "os::internal::nodename: Call to `GetComputerNameEx` failed");
  }

  std::unique_ptr<char[]> name(new char[size + 1]);

  if (!::GetComputerNameEx(ComputerNameDnsHostname, name.get(), &size)) {
    return WindowsError(
        "os::internal::nodename: Call to `GetComputerNameEx` failed");
  }

  return std::string(name.get());
}
Пример #19
0
// Opens an inheritable pipe[1] represented as a pair of file handles. On
// success, the first handle returned recieves the 'read' handle of the pipe,
// while the second receives the 'write' handle. The pipe handles can then be
// passed to a child process, as exemplified in [2].
//
// [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx
// [2] https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
static Try<array<HANDLE, 2>> createPipeHandles()
{
  // The `TRUE` in the last field makes this duplicate handle inheritable.
  SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  array<HANDLE, 2> handles{ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };

  if (!::CreatePipe(&handles[0], &handles[1], &sa, 0)) {
    return WindowsError("createPipeHandles: could not create pipe");
  }

  return handles;
}
Пример #20
0
Subprocess::IO Subprocess::PIPE()
{
  return Subprocess::IO(
      []() -> Try<InputFileDescriptors> {
        const Try<array<HANDLE, 2>> handles = internal::createPipeHandles();
        if (handles.isError()) {
          return Error(handles.error());
        }

        // Create STDIN pipe and set the 'write' component to not be
        // inheritable.
        if (!::SetHandleInformation(handles.get()[1], HANDLE_FLAG_INHERIT, 0)) {
          return WindowsError(
              "PIPE: Failed to call SetHandleInformation on stdin pipe");
        }

        InputFileDescriptors fds;
        fds.read = handles.get()[0];
        fds.write = handles.get()[1];
        return fds;
      },
      []() -> Try<OutputFileDescriptors> {
        const Try<array<HANDLE, 2>> handles = internal::createPipeHandles();
        if (handles.isError()) {
          return Error(handles.error());
        }

        // Create OUT pipe and set the 'read' component to not be inheritable.
        if (!::SetHandleInformation(handles.get()[0], HANDLE_FLAG_INHERIT, 0)) {
          return WindowsError(
              "PIPE: Failed to call SetHandleInformation on out pipe");
        }

        OutputFileDescriptors fds;
        fds.read = handles.get()[0];
        fds.write = handles.get()[1];
        return fds;
      });
}
Пример #21
0
void Keyboard::WindowsKey(Keycode key, bool up)
{
    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki.wVk = 0;
    input.ki.wScan = WindowsDIConvert( key );
	input.ki.dwFlags = KEYEVENTF_SCANCODE | ( up ? KEYEVENTF_KEYUP : 0 );
    input.ki.time = 0;
    input.ki.dwExtraInfo = (ULONG_PTR)NULL;

    if (SendInput(1, &input, sizeof(INPUT)) != 1)
    {
        WindowsError("SendInput");
    }
}
Пример #22
0
  Try<Nothing> close()
  {
    if (handle_ == NULL) {
      return Error("Could not close library; handle was already `NULL`");
    }

    if (!FreeLibrary(handle_)) {
      return WindowsError(
          "Could not close library '" + (path_.isSome() ? path_.get() : ""));
    }

    handle_ = NULL;
    path_ = None();

    return Nothing();
  }
Пример #23
0
  Try<Nothing> open(const std::string& path)
  {
    // Check if we've already opened a library.
    if (handle_ != NULL) {
      return Error("Library already opened");
    }

    handle_ = LoadLibrary(path.c_str());

    if (handle_ == NULL) {
      return WindowsError("Could not load library '" + path + "'");
    }

    path_ = path;

    return Nothing();
  }
Пример #24
0
  Try<void*> loadSymbol(const std::string& name)
  {
    if (handle_ == NULL) {
      return Error(
          "Could not get symbol '" + name + "'; library handle was `NULL`");
    }

    void* symbol = GetProcAddress(handle_, name.c_str());

    if (symbol == NULL) {
      return WindowsError(
          "Error looking up symbol '" + name + "' in '" +
          (path_.isSome() ? path_.get() : ""));
    }

    return symbol;
  }
Пример #25
0
// Returns the total size of main and free memory.
inline Try<Memory> memory()
{
  Memory memory;

  MEMORYSTATUSEX memory_status;
  memory_status.dwLength = sizeof(MEMORYSTATUSEX);
  if (!::GlobalMemoryStatusEx(&memory_status)) {
    return WindowsError("os::memory: Call to `GlobalMemoryStatusEx` failed");
  }

  memory.total = Bytes(memory_status.ullTotalPhys);
  memory.free = Bytes(memory_status.ullAvailPhys);
  memory.totalSwap = Bytes(memory_status.ullTotalPageFile);
  memory.freeSwap = Bytes(memory_status.ullAvailPageFile);

  return memory;
}
Пример #26
0
// TODO(hausdorff): Rethink name here, write a comment about this function.
static Try<HANDLE> createIoPath(const string& path, DWORD accessFlags)
{
  // The `TRUE` in the last field makes this duplicate handle inheritable.
  SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
  const HANDLE handle = ::CreateFile(
      path.c_str(),
      accessFlags,
      FILE_SHARE_READ,
      &sa,
      CREATE_NEW,
      FILE_ATTRIBUTE_NORMAL,
      NULL);

  if (handle == INVALID_HANDLE_VALUE) {
    return WindowsError("Failed to open '" + path + "'");
  }

  return handle;
}
Пример #27
0
void Mouse::WindowsButton(unsigned int button, bool up)
{
    // Create INPUT struct, most feilds can be set as 0
    INPUT input;
    input.type = INPUT_MOUSE;
    input.mi.dx = 0;
    input.mi.dy = 0;
    input.mi.mouseData = 0;
    input.mi.dwFlags = 0;
    input.mi.time = 0;
    input.mi.dwExtraInfo = (ULONG_PTR)NULL;

    // Fill dwFlags based on button and up
    switch(button)
    {
        case sLeft:
            input.mi.dwFlags = up ? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_LEFTDOWN;
            break;
        case sRight:
            input.mi.dwFlags = up ? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_RIGHTDOWN;
            break;
        case sMiddle:
            input.mi.dwFlags = up ? MOUSEEVENTF_MIDDLEUP : MOUSEEVENTF_MIDDLEDOWN;
            break;
        case sMouse4:
            input.mi.dwFlags = up ? MOUSEEVENTF_XUP : MOUSEEVENTF_XDOWN;
            input.mi.mouseData = XBUTTON1;
            break;
        case sMouse5:
            input.mi.dwFlags = up ? MOUSEEVENTF_XUP : MOUSEEVENTF_XDOWN;
            input.mi.mouseData = XBUTTON2;
            break;
        default:
            // Invalid button
            break;
    }
    // Send the single input and report errors
    if (SendInput(1, &input, sizeof(INPUT)) != 1)
    {
        WindowsError("SendInput");
    }
}
Пример #28
0
// Terminate the process tree rooted at the specified pid.
// Note that if the process 'pid' has exited we'll terminate the process
// tree(s) rooted at pids.
// Returns the process trees that were succesfully or unsuccessfully
// signaled. Note that the process trees can be stringified.
inline Try<std::list<ProcessTree>> killtree(
    pid_t pid,
    int signal,
    bool groups = false,
    bool sessions = false)
{
  std::list<ProcessTree> process_tree_list;
  Try<ProcessTree> process_tree = os::pstree(pid);
  if (process_tree.isError()) {
    return WindowsError();
  }

  process_tree_list.push_back(process_tree.get());

  Try<Nothing> kill_job = os::kill_job(pid);
  if (kill_job.isError())
  {
    return Error(kill_job.error());
  }
  return process_tree_list;
}
Пример #29
0
static Try<HANDLE> duplicateHandle(const HANDLE handle)
{
  HANDLE duplicate = INVALID_HANDLE_VALUE;

  // TODO(anaparu): Do we need to scope the duplicated handle
  // to the child process?
  BOOL result = ::DuplicateHandle(
      ::GetCurrentProcess(),  // Source process == current.
      handle,                 // Handle to duplicate.
      ::GetCurrentProcess(),  // Target process == current.
      &duplicate,
      0,                      // Ignored (DUPLICATE_SAME_ACCESS).
      TRUE,                   // Inheritable handle.
      DUPLICATE_SAME_ACCESS); // Same access level as source.

  if (!result) {
    return WindowsError("Failed to duplicate handle of stdin file");
  }

  return duplicate;
}
Пример #30
0
Future<size_t> write(int_fd fd, const void* data, size_t size)
{
  process::initialize();

  // TODO(benh): Let the system calls do what ever they're supposed to
  // rather than return 0 here?
  if (size == 0) {
    return 0;
  }

  // Just do a synchronous call.
  if (!fd.is_overlapped()) {
    ssize_t result = os::write(fd, data, size);
    if (result == -1) {
      return Failure(WindowsError().message);
    }
    return static_cast<size_t>(result);
  }

  return windows::write(fd, data, size);
}