1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/win32.h"
29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <algorithm>
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/basictypes.h"
32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h"
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base {
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Unix time is in seconds relative to 1/1/1970.  So we compute the windows
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// FILETIME of that time/date, then we add/subtract in appropriate units to
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// convert to/from unix time.
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// The units of FILETIME are 100ns intervals, so by multiplying by or dividing
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// by 10000000, we can convert to/from seconds.
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// FileTime = UnixTime*10000000 + FileTime(1970)
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// UnixTime = (FileTime-FileTime(1970))/10000000
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid FileTimeToUnixTime(const FILETIME& ft, time_t* ut) {
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(NULL != ut);
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // FILETIME has an earlier date base than time_t (1/1/1970), so subtract off
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // the difference.
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SYSTEMTIME base_st;
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memset(&base_st, 0, sizeof(base_st));
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wDay = 1;
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wMonth = 1;
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wYear = 1970;
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  FILETIME base_ft;
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SystemTimeToFileTime(&base_st, &base_ft);
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ULARGE_INTEGER base_ul, current_ul;
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memcpy(&base_ul, &base_ft, sizeof(FILETIME));
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memcpy(&current_ul, &ft, sizeof(FILETIME));
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Divide by big number to convert to seconds, then subtract out the 1970
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // base date value.
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const ULONGLONG RATIO = 10000000;
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *ut = static_cast<time_t>((current_ul.QuadPart - base_ul.QuadPart) / RATIO);
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid UnixTimeToFileTime(const time_t& ut, FILETIME* ft) {
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(NULL != ft);
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // FILETIME has an earlier date base than time_t (1/1/1970), so add in
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // the difference.
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SYSTEMTIME base_st;
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memset(&base_st, 0, sizeof(base_st));
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wDay = 1;
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wMonth = 1;
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  base_st.wYear = 1970;
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  FILETIME base_ft;
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SystemTimeToFileTime(&base_st, &base_ft);
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ULARGE_INTEGER base_ul;
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memcpy(&base_ul, &base_ft, sizeof(FILETIME));
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Multiply by big number to convert to 100ns units, then add in the 1970
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // base date value.
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const ULONGLONG RATIO = 10000000;
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ULARGE_INTEGER current_ul;
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  current_ul.QuadPart = base_ul.QuadPart + static_cast<int64>(ut) * RATIO;
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memcpy(ft, &current_ul, sizeof(FILETIME));
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename) {
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Integrate into fileutils.h
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Handle wide and non-wide cases via TCHAR?
99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Skip \\?\ processing if the length is not > MAX_PATH?
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Write unittests
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Convert to Utf16
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int wlen = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.length() + 1,
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                   NULL, 0);
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == wlen) {
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t* wfilename = STACK_ARRAY(wchar_t, wlen);
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.length() + 1,
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                 wfilename, wlen)) {
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Replace forward slashes with backslashes
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::replace(wfilename, wfilename + wlen, L'/', L'\\');
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Convert to complete filename
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD full_len = ::GetFullPathName(wfilename, 0, NULL, NULL);
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == full_len) {
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t* filepart = NULL;
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t* full_filename = STACK_ARRAY(wchar_t, full_len + 6);
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  wchar_t* start = full_filename + 6;
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 == ::GetFullPathName(wfilename, full_len, start, &filepart)) {
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Add long-path prefix
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const wchar_t kLongPathPrefix[] = L"\\\\?\\UNC";
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((start[0] != L'\\') || (start[1] != L'\\')) {
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Non-unc path:     <pathname>
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //      Becomes: \\?\<pathname>
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    start -= 4;
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(start >= full_filename);
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    memcpy(start, kLongPathPrefix, 4 * sizeof(wchar_t));
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (start[2] != L'?') {
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Unc path:       \\<server>\<pathname>
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //  Becomes: \\?\UNC\<server>\<pathname>
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    start -= 6;
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(start >= full_filename);
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    memcpy(start, kLongPathPrefix, 7 * sizeof(wchar_t));
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Already in long-path form.
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  filename->assign(start);
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool GetOsVersion(int* major, int* minor, int* build) {
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  OSVERSIONINFO info = {0};
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  info.dwOSVersionInfoSize = sizeof(info);
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (GetVersionEx(&info)) {
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (major) *major = info.dwMajorVersion;
152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (minor) *minor = info.dwMinorVersion;
153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (build) *build = info.dwBuildNumber;
154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool GetCurrentProcessIntegrityLevel(int* level) {
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool ret = false;
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HANDLE process = GetCurrentProcess(), token;
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &token)) {
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    DWORD size;
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!GetTokenInformation(token, TokenIntegrityLevel, NULL, 0, &size) &&
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      char* buf = STACK_ARRAY(char, size);
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      TOKEN_MANDATORY_LABEL* til =
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf);
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (GetTokenInformation(token, TokenIntegrityLevel, til, size, &size)) {
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        DWORD count = *GetSidSubAuthorityCount(til->Label.Sid);
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        *level = *GetSidSubAuthority(til->Label.Sid, count - 1);
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ret = true;
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    CloseHandle(token);
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ret;
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // namespace talk_base
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
184