| File: | usr/include/string.h |
| Warning: | line 281, column 10 Value of 'errno' was not checked and may be overwritten by function '__builtin_strrchr' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 4 | ||||
| 5 | #include "updatedefines.h" | |||
| 6 | #if defined(XP_WIN) | |||
| 7 | # include <windows.h> | |||
| 8 | # include <winioctl.h> // for FSCTL_GET_REPARSE_POINT | |||
| 9 | # include <shlobj.h> | |||
| 10 | # ifndef RRF_SUBKEY_WOW6464KEY | |||
| 11 | # define RRF_SUBKEY_WOW6464KEY 0x00010000 | |||
| 12 | # endif | |||
| 13 | #endif | |||
| 14 | ||||
| 15 | #if defined(XP_MACOSX) | |||
| 16 | # include <os/log.h> | |||
| 17 | #endif | |||
| 18 | ||||
| 19 | #include <stdio.h> | |||
| 20 | #include <stdarg.h> | |||
| 21 | ||||
| 22 | #include "updatecommon.h" | |||
| 23 | #ifdef XP_WIN | |||
| 24 | # include "updatehelper.h" | |||
| 25 | # include "nsWindowsHelpers.h" | |||
| 26 | # include "mozilla/UniquePtr.h" | |||
| 27 | # include "mozilla/WinHeaderOnlyUtils.h" | |||
| 28 | ||||
| 29 | // This struct isn't in any SDK header, so this definition was copied from: | |||
| 30 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_reparse_data_buffer | |||
| 31 | typedef struct _REPARSE_DATA_BUFFER { | |||
| 32 | ULONG ReparseTag; | |||
| 33 | USHORT ReparseDataLength; | |||
| 34 | USHORT Reserved; | |||
| 35 | union { | |||
| 36 | struct { | |||
| 37 | USHORT SubstituteNameOffset; | |||
| 38 | USHORT SubstituteNameLength; | |||
| 39 | USHORT PrintNameOffset; | |||
| 40 | USHORT PrintNameLength; | |||
| 41 | ULONG Flags; | |||
| 42 | WCHAR PathBuffer[1]; | |||
| 43 | } SymbolicLinkReparseBuffer; | |||
| 44 | struct { | |||
| 45 | USHORT SubstituteNameOffset; | |||
| 46 | USHORT SubstituteNameLength; | |||
| 47 | USHORT PrintNameOffset; | |||
| 48 | USHORT PrintNameLength; | |||
| 49 | WCHAR PathBuffer[1]; | |||
| 50 | } MountPointReparseBuffer; | |||
| 51 | struct { | |||
| 52 | UCHAR DataBuffer[1]; | |||
| 53 | } GenericReparseBuffer; | |||
| 54 | } DUMMYUNIONNAME; | |||
| 55 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; | |||
| 56 | #endif | |||
| 57 | ||||
| 58 | void UpdateLog::Init(NS_tchar* logFilePath) { | |||
| 59 | if (logFP) { | |||
| 60 | return; | |||
| 61 | } | |||
| 62 | ||||
| 63 | // When the path is over the length limit disable logging by not opening the | |||
| 64 | // file and not setting logFP. | |||
| 65 | int dstFilePathLen = NS_tstrlenstrlen(logFilePath); | |||
| 66 | if (dstFilePathLen > 0 && dstFilePathLen < MAXPATHLEN4096 - 1) { | |||
| 67 | NS_tstrncpystrncpy(mDstFilePath, logFilePath, MAXPATHLEN4096); | |||
| 68 | #if defined(XP_WIN) || defined(XP_MACOSX) | |||
| 69 | logFP = CreateAndOpenFile(mDstFilePath, false); | |||
| 70 | if (logFP == nullptr) { | |||
| 71 | LogToOS(NS_T("Failed to create FILE*")"Failed to create FILE*"); | |||
| 72 | } | |||
| 73 | #else | |||
| 74 | // On platforms that have an updates directory in the installation directory | |||
| 75 | // (e.g. platforms other than Windows and Mac) the update log is written to | |||
| 76 | // a temporary file and then to the update log file. This is needed since | |||
| 77 | // the installation directory is moved during a replace request. This can be | |||
| 78 | // removed when the platform's updates directory is located outside of the | |||
| 79 | // installation directory. | |||
| 80 | logFP = tmpfile(); | |||
| 81 | #endif | |||
| 82 | } | |||
| 83 | } | |||
| 84 | ||||
| 85 | void UpdateLog::Finish() { | |||
| 86 | if (!logFP) { | |||
| ||||
| 87 | return; | |||
| 88 | } | |||
| 89 | ||||
| 90 | #if !defined(XP_WIN) && !defined(XP_MACOSX) | |||
| 91 | const int blockSize = 1024; | |||
| 92 | char buffer[blockSize]; | |||
| 93 | fflush(logFP); | |||
| 94 | rewind(logFP); | |||
| 95 | ||||
| 96 | FILE* updateLogFP = CreateAndOpenFile(mDstFilePath, true); | |||
| 97 | if (updateLogFP == nullptr) { | |||
| 98 | return; | |||
| 99 | } | |||
| 100 | ||||
| 101 | while (!feof(logFP)) { | |||
| 102 | size_t read = fread(buffer, 1, blockSize, logFP); | |||
| 103 | if (ferror(logFP)) { | |||
| 104 | fclose(logFP); | |||
| 105 | logFP = nullptr; | |||
| 106 | fclose(updateLogFP); | |||
| 107 | updateLogFP = nullptr; | |||
| 108 | return; | |||
| 109 | } | |||
| 110 | ||||
| 111 | size_t written = 0; | |||
| 112 | ||||
| 113 | while (written < read) { | |||
| 114 | size_t chunkWritten = fwrite(buffer, 1, read - written, updateLogFP); | |||
| 115 | if (chunkWritten <= 0) { | |||
| 116 | fclose(logFP); | |||
| 117 | logFP = nullptr; | |||
| 118 | fclose(updateLogFP); | |||
| 119 | updateLogFP = nullptr; | |||
| 120 | return; | |||
| 121 | } | |||
| 122 | ||||
| 123 | written += chunkWritten; | |||
| 124 | } | |||
| 125 | } | |||
| 126 | fclose(updateLogFP); | |||
| 127 | updateLogFP = nullptr; | |||
| 128 | #endif | |||
| 129 | ||||
| 130 | fclose(logFP); | |||
| 131 | logFP = nullptr; | |||
| 132 | } | |||
| 133 | ||||
| 134 | void UpdateLog::Flush() { | |||
| 135 | if (!logFP) { | |||
| 136 | return; | |||
| 137 | } | |||
| 138 | ||||
| 139 | fflush(logFP); | |||
| 140 | } | |||
| 141 | ||||
| 142 | void UpdateLog::PrintTimestampPrefix() { | |||
| 143 | if (!logFP) { | |||
| 144 | return; | |||
| 145 | } | |||
| 146 | ||||
| 147 | time_t rawtime = time(nullptr); | |||
| 148 | struct tm* timeinfo = localtime(&rawtime); | |||
| 149 | ||||
| 150 | if (nullptr != timeinfo) { | |||
| 151 | // attempt to format the time similar to rfc-3339 so that it works with | |||
| 152 | // sort(1). xxxx-xx-xx xx:xx:xx+xxxx -> 24 chars + 1 NUL | |||
| 153 | const size_t buffer_size = 25; | |||
| 154 | char buffer[buffer_size] = {0}; | |||
| 155 | ||||
| 156 | if (0 == strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S%z", timeinfo)) { | |||
| 157 | buffer[0] = '\0'; // reset buffer into a defined state and try posix ts | |||
| 158 | if (0 > snprintf(buffer, buffer_size, "%d", (int)mktime(timeinfo))) { | |||
| 159 | buffer[0] = '\0'; // reset and give up | |||
| 160 | } | |||
| 161 | } | |||
| 162 | ||||
| 163 | fprintf(logFP, "%s: ", buffer); | |||
| 164 | } | |||
| 165 | } | |||
| 166 | ||||
| 167 | void UpdateLog::Printf(const char* fmt, ...) { | |||
| 168 | if (!logFP) { | |||
| 169 | return; | |||
| 170 | } | |||
| 171 | ||||
| 172 | PrintTimestampPrefix(); | |||
| 173 | ||||
| 174 | va_list ap; | |||
| 175 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 176 | vfprintf(logFP, fmt, ap); | |||
| 177 | va_end(ap)__builtin_va_end(ap); | |||
| 178 | ||||
| 179 | fprintf(logFP, "\n"); | |||
| 180 | // When the updater crashes on Windows the log file won't be flushed and this | |||
| 181 | // can make it easier to debug what is going on. | |||
| 182 | fflush(logFP); | |||
| 183 | } | |||
| 184 | ||||
| 185 | void UpdateLog::WarnPrintf(const char* fmt, ...) { | |||
| 186 | if (!logFP) { | |||
| 187 | return; | |||
| 188 | } | |||
| 189 | ||||
| 190 | PrintTimestampPrefix(); | |||
| 191 | ||||
| 192 | va_list ap; | |||
| 193 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 194 | fprintf(logFP, "*** Warning: "); | |||
| 195 | vfprintf(logFP, fmt, ap); | |||
| 196 | fprintf(logFP, "***\n"); | |||
| 197 | va_end(ap)__builtin_va_end(ap); | |||
| 198 | // When the updater crashes on Windows the log file won't be flushed and this | |||
| 199 | // can make it easier to debug what is going on. | |||
| 200 | fflush(logFP); | |||
| 201 | } | |||
| 202 | ||||
| 203 | /** | |||
| 204 | * Creates and opens a file for logging in read/write mode. | |||
| 205 | * | |||
| 206 | * @param filePath The path of the log file. | |||
| 207 | * @param binary If the file should be opened as binary (ignored on | |||
| 208 | * macOS/Linux). | |||
| 209 | * @return a pointer to the FILE struct or nullptr on error. | |||
| 210 | */ | |||
| 211 | FILE* CreateAndOpenFile(NS_tchar* filePath, bool binary) { | |||
| 212 | #ifdef XP_WIN | |||
| 213 | return NS_tfopenfopen(filePath, binary ? NS_T("wb+")"wb+" : NS_T("w+")"w+"); | |||
| 214 | #else | |||
| 215 | LogToOS(NS_T("Opening logfile")"Opening logfile"); | |||
| 216 | NS_tchar* lastSeperator = NS_tstrrchrstrrchr(filePath, '/'); | |||
| 217 | if (lastSeperator == nullptr) { | |||
| 218 | // No separator, disable logging. | |||
| 219 | return nullptr; | |||
| 220 | } | |||
| 221 | ||||
| 222 | const NS_tchar templateSuffix[] = NS_T("/temp.XXXXXX")"/temp.XXXXXX"; | |||
| 223 | size_t templateLen = NS_tstrlenstrlen(templateSuffix); | |||
| 224 | ||||
| 225 | long dirLength = lastSeperator - filePath; | |||
| 226 | // +1 to account for the \0 terminator | |||
| 227 | if (dirLength < 0 || | |||
| 228 | (unsigned long)dirLength >= MAXPATHLEN4096 - (templateLen + 1)) { | |||
| 229 | // Too short, or too long. Disable logging. | |||
| 230 | return nullptr; | |||
| 231 | } | |||
| 232 | ||||
| 233 | NS_tchar tmpFilePath[MAXPATHLEN4096] = {L'\0'}; | |||
| 234 | // Use memcpy here to only copy the directory portion of filePath | |||
| 235 | // and using strncpy triggered GCC's stringop-truncation error because | |||
| 236 | // filePath's \0 terminator wasn't being carried over. This isn't a problem | |||
| 237 | // here because the next strncpy adds it. | |||
| 238 | memcpy(tmpFilePath, filePath, dirLength); | |||
| 239 | NS_tstrncpystrncpy(tmpFilePath + dirLength, templateSuffix, MAXPATHLEN4096 - dirLength); | |||
| 240 | ||||
| 241 | int fd = mkstemp(tmpFilePath); | |||
| 242 | if (fd == -1) { | |||
| 243 | LogToOS(NS_T("Failed to open tmp")"Failed to open tmp"); | |||
| 244 | return nullptr; | |||
| 245 | } | |||
| 246 | ||||
| 247 | if (rename(tmpFilePath, filePath) == -1) { | |||
| 248 | LogToOS(NS_T("Failed to rename")"Failed to rename"); | |||
| 249 | close(fd); | |||
| 250 | return nullptr; | |||
| 251 | } | |||
| 252 | ||||
| 253 | LogToOS(NS_T("Opening file*")"Opening file*"); | |||
| 254 | return fdopen(fd, "w+"); | |||
| 255 | #endif | |||
| 256 | } | |||
| 257 | ||||
| 258 | #ifdef XP_WIN | |||
| 259 | /** | |||
| 260 | * Determine if a path contains symlinks or junctions to disallowed locations | |||
| 261 | * | |||
| 262 | * @param fullPath The full path to check. | |||
| 263 | * @return true if the path contains invalid links or on errors, | |||
| 264 | * false if the check passes and the path can be used | |||
| 265 | */ | |||
| 266 | bool PathContainsInvalidLinks(wchar_t* const fullPath) { | |||
| 267 | wchar_t pathCopy[MAXPATHLEN4096 + 1] = L""; | |||
| 268 | wcsncpy(pathCopy, fullPath, MAXPATHLEN4096); | |||
| 269 | wchar_t* remainingPath = nullptr; | |||
| 270 | wchar_t* nextToken = wcstok_s(pathCopy, L"\\", &remainingPath); | |||
| 271 | wchar_t* partialPath = nextToken; | |||
| 272 | ||||
| 273 | while (nextToken) { | |||
| 274 | if ((GetFileAttributesW(partialPath) & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { | |||
| 275 | nsAutoHandle h(CreateFileW( | |||
| 276 | partialPath, 0, | |||
| 277 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, | |||
| 278 | OPEN_EXISTING, | |||
| 279 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); | |||
| 280 | if (h == INVALID_HANDLE_VALUE) { | |||
| 281 | if (GetLastError() == ERROR_FILE_NOT_FOUND) { | |||
| 282 | // The path can't be an invalid link if it doesn't exist. | |||
| 283 | return false; | |||
| 284 | } else { | |||
| 285 | return true; | |||
| 286 | } | |||
| 287 | } | |||
| 288 | ||||
| 289 | mozilla::UniquePtr<UINT8[]> byteBuffer = | |||
| 290 | mozilla::MakeUnique<UINT8[]>(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); | |||
| 291 | ZeroMemory(byteBuffer.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE); | |||
| 292 | REPARSE_DATA_BUFFER* buffer = (REPARSE_DATA_BUFFER*)byteBuffer.get(); | |||
| 293 | DWORD bytes = 0; | |||
| 294 | if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer, | |||
| 295 | MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, nullptr)) { | |||
| 296 | return true; | |||
| 297 | } | |||
| 298 | ||||
| 299 | wchar_t* reparseTarget = nullptr; | |||
| 300 | switch (buffer->ReparseTag) { | |||
| 301 | case IO_REPARSE_TAG_MOUNT_POINT: | |||
| 302 | reparseTarget = | |||
| 303 | buffer->MountPointReparseBuffer.PathBuffer + | |||
| 304 | (buffer->MountPointReparseBuffer.SubstituteNameOffset / | |||
| 305 | sizeof(wchar_t)); | |||
| 306 | if (buffer->MountPointReparseBuffer.SubstituteNameLength < | |||
| 307 | ARRAYSIZE(L"\\??\\")) { | |||
| 308 | return false; | |||
| 309 | } | |||
| 310 | break; | |||
| 311 | case IO_REPARSE_TAG_SYMLINK: | |||
| 312 | reparseTarget = | |||
| 313 | buffer->SymbolicLinkReparseBuffer.PathBuffer + | |||
| 314 | (buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset / | |||
| 315 | sizeof(wchar_t)); | |||
| 316 | if (buffer->SymbolicLinkReparseBuffer.SubstituteNameLength < | |||
| 317 | ARRAYSIZE(L"\\??\\")) { | |||
| 318 | return false; | |||
| 319 | } | |||
| 320 | break; | |||
| 321 | default: | |||
| 322 | return true; | |||
| 323 | break; | |||
| 324 | } | |||
| 325 | ||||
| 326 | if (!reparseTarget) { | |||
| 327 | return false; | |||
| 328 | } | |||
| 329 | if (wcsncmp(reparseTarget, L"\\??\\", ARRAYSIZE(L"\\??\\") - 1) != 0) { | |||
| 330 | return true; | |||
| 331 | } | |||
| 332 | } | |||
| 333 | ||||
| 334 | nextToken = wcstok_s(nullptr, L"\\", &remainingPath); | |||
| 335 | PathAppendW(partialPath, nextToken); | |||
| 336 | } | |||
| 337 | ||||
| 338 | return false; | |||
| 339 | } | |||
| 340 | ||||
| 341 | /** | |||
| 342 | * Determine if a path is located within Program Files, either native or x86 | |||
| 343 | * | |||
| 344 | * @param fullPath The full path to check. | |||
| 345 | * @return true if fullPath begins with either Program Files directory, | |||
| 346 | * false if it does not or if an error is encountered | |||
| 347 | */ | |||
| 348 | bool IsProgramFilesPath(NS_tchar* fullPath) { | |||
| 349 | // Make sure we don't try to compare against a short path. | |||
| 350 | DWORD longInstallPathChars = GetLongPathNameW(fullPath, nullptr, 0); | |||
| 351 | if (longInstallPathChars == 0) { | |||
| 352 | return false; | |||
| 353 | } | |||
| 354 | mozilla::UniquePtr<wchar_t[]> longInstallPath = | |||
| 355 | mozilla::MakeUnique<wchar_t[]>(longInstallPathChars); | |||
| 356 | if (!GetLongPathNameW(fullPath, longInstallPath.get(), | |||
| 357 | longInstallPathChars)) { | |||
| 358 | return false; | |||
| 359 | } | |||
| 360 | ||||
| 361 | // First check for Program Files (x86). | |||
| 362 | { | |||
| 363 | PWSTR programFiles32PathRaw = nullptr; | |||
| 364 | // FOLDERID_ProgramFilesX86 gets native Program Files directory on a 32-bit | |||
| 365 | // OS or the (x86) directory on a 64-bit OS regardless of this binary's | |||
| 366 | // bitness. | |||
| 367 | if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, nullptr, | |||
| 368 | &programFiles32PathRaw))) { | |||
| 369 | // That call should never fail on any supported OS version. | |||
| 370 | return false; | |||
| 371 | } | |||
| 372 | mozilla::UniquePtr<wchar_t, mozilla::CoTaskMemFreeDeleter> | |||
| 373 | programFiles32Path(programFiles32PathRaw); | |||
| 374 | // We need this path to have a trailing slash so our prefix test doesn't | |||
| 375 | // match on a different folder which happens to have a name beginning with | |||
| 376 | // the prefix we're looking for but then also more characters after that. | |||
| 377 | size_t length = wcslen(programFiles32Path.get()); | |||
| 378 | if (length == 0) { | |||
| 379 | return false; | |||
| 380 | } | |||
| 381 | if (programFiles32Path.get()[length - 1] == L'\\') { | |||
| 382 | if (wcsnicmp(longInstallPath.get(), programFiles32Path.get(), length) == | |||
| 383 | 0) { | |||
| 384 | return true; | |||
| 385 | } | |||
| 386 | } else { | |||
| 387 | // Allocate space for a copy of the string along with a terminator and one | |||
| 388 | // extra character for the trailing backslash. | |||
| 389 | length += 1; | |||
| 390 | mozilla::UniquePtr<wchar_t[]> programFiles32PathWithSlash = | |||
| 391 | mozilla::MakeUnique<wchar_t[]>(length + 1); | |||
| 392 | ||||
| 393 | NS_tsnprintfsnprintf(programFiles32PathWithSlash.get(), length + 1, NS_T("%s\\")"%s\\", | |||
| 394 | programFiles32Path.get()); | |||
| 395 | ||||
| 396 | if (wcsnicmp(longInstallPath.get(), programFiles32PathWithSlash.get(), | |||
| 397 | length) == 0) { | |||
| 398 | return true; | |||
| 399 | } | |||
| 400 | } | |||
| 401 | } | |||
| 402 | ||||
| 403 | // If we didn't find (x86), check for the native Program Files. | |||
| 404 | { | |||
| 405 | // In case we're a 32-bit binary on 64-bit Windows, we now have a problem | |||
| 406 | // getting the right "native" Program Files path, which is that there is no | |||
| 407 | // FOLDERID_* value that returns that path. So we always read that one out | |||
| 408 | // of its canonical registry location instead. If we're on a 32-bit OS, this | |||
| 409 | // will be the same path that we just checked. First get the buffer size to | |||
| 410 | // allocate for the path. | |||
| 411 | DWORD length = 0; | |||
| 412 | if (RegGetValueW(HKEY_LOCAL_MACHINE, | |||
| 413 | L"Software\\Microsoft\\Windows\\CurrentVersion", | |||
| 414 | L"ProgramFilesDir", RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY, | |||
| 415 | nullptr, nullptr, &length) != ERROR_SUCCESS) { | |||
| 416 | return false; | |||
| 417 | } | |||
| 418 | // RegGetValue returns the length including the terminator, but it's in | |||
| 419 | // bytes, so convert that to characters. | |||
| 420 | DWORD lengthChars = (length / sizeof(wchar_t)); | |||
| 421 | if (lengthChars <= 1) { | |||
| 422 | return false; | |||
| 423 | } | |||
| 424 | mozilla::UniquePtr<wchar_t[]> programFilesNativePath = | |||
| 425 | mozilla::MakeUnique<wchar_t[]>(lengthChars); | |||
| 426 | ||||
| 427 | // Now actually read the value. | |||
| 428 | if (RegGetValueW( | |||
| 429 | HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", | |||
| 430 | L"ProgramFilesDir", RRF_RT_REG_SZ | RRF_SUBKEY_WOW6464KEY, nullptr, | |||
| 431 | programFilesNativePath.get(), &length) != ERROR_SUCCESS) { | |||
| 432 | return false; | |||
| 433 | } | |||
| 434 | size_t nativePathStrLen = | |||
| 435 | wcsnlen_s(programFilesNativePath.get(), lengthChars); | |||
| 436 | if (nativePathStrLen == 0) { | |||
| 437 | return false; | |||
| 438 | } | |||
| 439 | ||||
| 440 | // As before, append a backslash if there isn't one already. | |||
| 441 | if (programFilesNativePath.get()[nativePathStrLen - 1] == L'\\') { | |||
| 442 | if (wcsnicmp(longInstallPath.get(), programFilesNativePath.get(), | |||
| 443 | nativePathStrLen) == 0) { | |||
| 444 | return true; | |||
| 445 | } | |||
| 446 | } else { | |||
| 447 | // Allocate space for a copy of the string along with a terminator and one | |||
| 448 | // extra character for the trailing backslash. | |||
| 449 | nativePathStrLen += 1; | |||
| 450 | mozilla::UniquePtr<wchar_t[]> programFilesNativePathWithSlash = | |||
| 451 | mozilla::MakeUnique<wchar_t[]>(nativePathStrLen + 1); | |||
| 452 | ||||
| 453 | NS_tsnprintfsnprintf(programFilesNativePathWithSlash.get(), nativePathStrLen + 1, | |||
| 454 | NS_T("%s\\")"%s\\", programFilesNativePath.get()); | |||
| 455 | ||||
| 456 | if (wcsnicmp(longInstallPath.get(), programFilesNativePathWithSlash.get(), | |||
| 457 | nativePathStrLen) == 0) { | |||
| 458 | return true; | |||
| 459 | } | |||
| 460 | } | |||
| 461 | } | |||
| 462 | ||||
| 463 | return false; | |||
| 464 | } | |||
| 465 | #endif | |||
| 466 | ||||
| 467 | /** | |||
| 468 | * Performs checks of a full path for validity for this application. | |||
| 469 | * | |||
| 470 | * @param origFullPath | |||
| 471 | * The full path to check. | |||
| 472 | * @return true if the path is valid for this application and false otherwise. | |||
| 473 | */ | |||
| 474 | bool IsValidFullPath(NS_tchar* origFullPath) { | |||
| 475 | // Subtract 1 from MAXPATHLEN for null termination. | |||
| 476 | if (NS_tstrlenstrlen(origFullPath) > MAXPATHLEN4096 - 1) { | |||
| 477 | // The path is longer than acceptable for this application. | |||
| 478 | return false; | |||
| 479 | } | |||
| 480 | ||||
| 481 | #ifdef XP_WIN | |||
| 482 | NS_tchar testPath[MAXPATHLEN4096] = {NS_T('\0')'\0'}; | |||
| 483 | // GetFullPathNameW will replace / with \ which PathCanonicalizeW requires. | |||
| 484 | if (GetFullPathNameW(origFullPath, MAXPATHLEN4096, testPath, nullptr) == 0) { | |||
| 485 | // Unable to get the full name for the path (e.g. invalid path). | |||
| 486 | return false; | |||
| 487 | } | |||
| 488 | ||||
| 489 | NS_tchar canonicalPath[MAXPATHLEN4096] = {NS_T('\0')'\0'}; | |||
| 490 | if (!PathCanonicalizeW(canonicalPath, testPath)) { | |||
| 491 | // Path could not be canonicalized (e.g. invalid path). | |||
| 492 | return false; | |||
| 493 | } | |||
| 494 | ||||
| 495 | // Check if the path passed in resolves to a differerent path. | |||
| 496 | if (NS_tstricmpstrcasecmp(origFullPath, canonicalPath) != 0) { | |||
| 497 | // Case insensitive string comparison between the supplied path and the | |||
| 498 | // canonical path are not equal. This will prevent directory traversal and | |||
| 499 | // the use of / in paths since they are converted to \. | |||
| 500 | return false; | |||
| 501 | } | |||
| 502 | ||||
| 503 | NS_tstrncpystrncpy(testPath, origFullPath, MAXPATHLEN4096); | |||
| 504 | if (!PathStripToRootW(testPath)) { | |||
| 505 | // It should always be possible to strip a valid path to its root. | |||
| 506 | return false; | |||
| 507 | } | |||
| 508 | ||||
| 509 | if (origFullPath[0] == NS_T('\\')'\\') { | |||
| 510 | // Only allow UNC server share paths. | |||
| 511 | if (!PathIsUNCServerShareW(testPath)) { | |||
| 512 | return false; | |||
| 513 | } | |||
| 514 | } | |||
| 515 | ||||
| 516 | if (PathContainsInvalidLinks(canonicalPath)) { | |||
| 517 | return false; | |||
| 518 | } | |||
| 519 | #else | |||
| 520 | // Only allow full paths. | |||
| 521 | if (origFullPath[0] != NS_T('/')'/') { | |||
| 522 | return false; | |||
| 523 | } | |||
| 524 | ||||
| 525 | // The path must not traverse directories | |||
| 526 | if (NS_tstrstrstrstr(origFullPath, NS_T("/../")"/../") != nullptr) { | |||
| 527 | return false; | |||
| 528 | } | |||
| 529 | ||||
| 530 | // The path shall not have a path traversal suffix | |||
| 531 | const NS_tchar invalidSuffix[] = NS_T("/..")"/.."; | |||
| 532 | size_t pathLen = NS_tstrlenstrlen(origFullPath); | |||
| 533 | size_t invalidSuffixLen = NS_tstrlenstrlen(invalidSuffix); | |||
| 534 | if (invalidSuffixLen <= pathLen && | |||
| 535 | NS_tstrncmpstrncmp(origFullPath + pathLen - invalidSuffixLen, invalidSuffix, | |||
| 536 | invalidSuffixLen) == 0) { | |||
| 537 | return false; | |||
| 538 | } | |||
| 539 | #endif | |||
| 540 | return true; | |||
| 541 | } | |||
| 542 | ||||
| 543 | #if defined(XP_MACOSX) | |||
| 544 | // This is never deallocated by the system | |||
| 545 | MOZ_RUNINIT static os_log_t updaterLogger = | |||
| 546 | os_log_create("org.mozilla.updater", "Updater"); | |||
| 547 | #endif | |||
| 548 | ||||
| 549 | /** | |||
| 550 | * Logs a message to the system log for debugging purposes before our log | |||
| 551 | * file has been set up. | |||
| 552 | * | |||
| 553 | * @param message | |||
| 554 | * The message to log. | |||
| 555 | */ | |||
| 556 | void LogToOS(const NS_tchar* message) { | |||
| 557 | #if defined(XP_MACOSX) | |||
| 558 | os_log(updaterLogger, "%{public}s", message); | |||
| 559 | #endif | |||
| 560 | } |
| 1 | /* Copyright (C) 1991-2026 Free Software Foundation, Inc. | |||
| 2 | This file is part of the GNU C Library. | |||
| 3 | ||||
| 4 | The GNU C Library is free software; you can redistribute it and/or | |||
| 5 | modify it under the terms of the GNU Lesser General Public | |||
| 6 | License as published by the Free Software Foundation; either | |||
| 7 | version 2.1 of the License, or (at your option) any later version. | |||
| 8 | ||||
| 9 | The GNU C Library is distributed in the hope that it will be useful, | |||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 12 | Lesser General Public License for more details. | |||
| 13 | ||||
| 14 | You should have received a copy of the GNU Lesser General Public | |||
| 15 | License along with the GNU C Library; if not, see | |||
| 16 | <https://www.gnu.org/licenses/>. */ | |||
| 17 | ||||
| 18 | /* | |||
| 19 | * ISO C99 Standard: 7.21 String handling <string.h> | |||
| 20 | */ | |||
| 21 | ||||
| 22 | #ifndef _STRING_H1 | |||
| 23 | #define _STRING_H1 1 | |||
| 24 | ||||
| 25 | #define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION | |||
| 26 | #include <bits/libc-header-start.h> | |||
| 27 | ||||
| 28 | __BEGIN_DECLSextern "C" { | |||
| 29 | ||||
| 30 | #if __GLIBC_USE (ISOC23)1 | |||
| 31 | # define __STDC_VERSION_STRING_H__202311L 202311L | |||
| 32 | #endif | |||
| 33 | ||||
| 34 | /* Get size_t and NULL from <stddef.h>. */ | |||
| 35 | #define __need_size_t | |||
| 36 | #define __need_NULL | |||
| 37 | #include <stddef.h> | |||
| 38 | ||||
| 39 | /* Tell the caller that we provide correct C++ prototypes. */ | |||
| 40 | #if defined __cplusplus202002L && (__GNUC_PREREQ (4, 4)((4 << 16) + 2 >= ((4) << 16) + (4)) \ | |||
| 41 | || __glibc_clang_prereq (3, 5)((23 << 16) + 1 >= ((3) << 16) + (5))) | |||
| 42 | # define __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 43 | #endif | |||
| 44 | ||||
| 45 | ||||
| 46 | /* Copy N bytes of SRC to DEST. */ | |||
| 47 | extern void *memcpy (void *__restrict __dest, const void *__restrict __src, | |||
| 48 | size_t __n) __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 49 | /* Copy N bytes of SRC to DEST, guaranteeing | |||
| 50 | correct behavior for overlapping strings. */ | |||
| 51 | extern void *memmove (void *__dest, const void *__src, size_t __n) | |||
| 52 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 53 | ||||
| 54 | /* Copy no more than N bytes of SRC to DEST, stopping when C is found. | |||
| 55 | Return the position in DEST one byte past where C was copied, | |||
| 56 | or NULL if C was not found in the first N bytes of SRC. */ | |||
| 57 | #if defined __USE_MISC1 || defined __USE_XOPEN1 || __GLIBC_USE (ISOC23)1 | |||
| 58 | extern void *memccpy (void *__restrict __dest, const void *__restrict __src, | |||
| 59 | int __c, size_t __n) | |||
| 60 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__write_only__, 1, 4)); | |||
| 61 | #endif /* Misc || X/Open. */ | |||
| 62 | ||||
| 63 | ||||
| 64 | /* Set N bytes of S to C. */ | |||
| 65 | extern void *memset (void *__s, int __c, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 66 | ||||
| 67 | #if defined __USE_MISC1 || __GLIBC_USE (ISOC23)1 | |||
| 68 | /* Like memset, but the compiler will not delete a call to this | |||
| 69 | function, even if S is dead after the call. */ | |||
| 70 | extern void *memset_explicit (void *__s, int __c, size_t __n) | |||
| 71 | __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))) __fortified_attr_access (__write_only__, 1, 3); | |||
| 72 | #endif | |||
| 73 | ||||
| 74 | /* Compare N bytes of S1 and S2. */ | |||
| 75 | extern int memcmp (const void *__s1, const void *__s2, size_t __n) | |||
| 76 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 77 | ||||
| 78 | /* Compare N bytes of S1 and S2. Return zero if S1 and S2 are equal. | |||
| 79 | Return some non-zero value otherwise. | |||
| 80 | ||||
| 81 | Essentially __memcmpeq has the exact same semantics as memcmp | |||
| 82 | except the return value is less constrained. memcmp is always a | |||
| 83 | correct implementation of __memcmpeq. As well !!memcmp, -memcmp, | |||
| 84 | or bcmp are correct implementations. | |||
| 85 | ||||
| 86 | __memcmpeq is meant to be used by compilers when memcmp return is | |||
| 87 | only used for its boolean value. | |||
| 88 | ||||
| 89 | __memcmpeq is declared only for use by compilers. Programs should | |||
| 90 | continue to use memcmp. */ | |||
| 91 | extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n) | |||
| 92 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 93 | ||||
| 94 | /* Search N bytes of S for C. */ | |||
| 95 | #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 96 | extern "C++" | |||
| 97 | { | |||
| 98 | extern void *memchr (void *__s, int __c, size_t __n) | |||
| 99 | __THROWnoexcept (true) __asm ("memchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 100 | extern const void *memchr (const void *__s, int __c, size_t __n) | |||
| 101 | __THROWnoexcept (true) __asm ("memchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 102 | ||||
| 103 | # ifdef __OPTIMIZE__1 | |||
| 104 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) void * | |||
| 105 | memchr (void *__s, int __c, size_t __n) __THROWnoexcept (true) | |||
| 106 | { | |||
| 107 | return __builtin_memchr (__s, __c, __n); | |||
| 108 | } | |||
| 109 | ||||
| 110 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) const void * | |||
| 111 | memchr (const void *__s, int __c, size_t __n) __THROWnoexcept (true) | |||
| 112 | { | |||
| 113 | return __builtin_memchr (__s, __c, __n); | |||
| 114 | } | |||
| 115 | # endif | |||
| 116 | } | |||
| 117 | #else | |||
| 118 | extern void *memchr (const void *__s, int __c, size_t __n) | |||
| 119 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 120 | # if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC | |||
| 121 | # define memchr(S, C, N) \ | |||
| 122 | __glibc_const_generic (S, const void *, memchr (S, C, N)) | |||
| 123 | # endif | |||
| 124 | #endif | |||
| 125 | ||||
| 126 | #ifdef __USE_GNU1 | |||
| 127 | /* Search in S for C. This is similar to `memchr' but there is no | |||
| 128 | length limit. */ | |||
| 129 | # ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 130 | extern "C++" void *rawmemchr (void *__s, int __c) | |||
| 131 | __THROWnoexcept (true) __asm ("rawmemchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 132 | extern "C++" const void *rawmemchr (const void *__s, int __c) | |||
| 133 | __THROWnoexcept (true) __asm ("rawmemchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 134 | # else | |||
| 135 | extern void *rawmemchr (const void *__s, int __c) | |||
| 136 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 137 | # endif | |||
| 138 | ||||
| 139 | /* Search N bytes of S for the final occurrence of C. */ | |||
| 140 | # ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 141 | extern "C++" void *memrchr (void *__s, int __c, size_t __n) | |||
| 142 | __THROWnoexcept (true) __asm ("memrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))) | |||
| 143 | __attr_access ((__read_only__, 1, 3)); | |||
| 144 | extern "C++" const void *memrchr (const void *__s, int __c, size_t __n) | |||
| 145 | __THROWnoexcept (true) __asm ("memrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))) | |||
| 146 | __attr_access ((__read_only__, 1, 3)); | |||
| 147 | # else | |||
| 148 | extern void *memrchr (const void *__s, int __c, size_t __n) | |||
| 149 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))) | |||
| 150 | __attr_access ((__read_only__, 1, 3)); | |||
| 151 | # endif | |||
| 152 | #endif | |||
| 153 | ||||
| 154 | ||||
| 155 | /* Copy SRC to DEST. */ | |||
| 156 | extern char *strcpy (char *__restrict __dest, const char *__restrict __src) | |||
| 157 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 158 | /* Copy no more than N characters of SRC to DEST. */ | |||
| 159 | extern char *strncpy (char *__restrict __dest, | |||
| 160 | const char *__restrict __src, size_t __n) | |||
| 161 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 162 | ||||
| 163 | /* Append SRC onto DEST. */ | |||
| 164 | extern char *strcat (char *__restrict __dest, const char *__restrict __src) | |||
| 165 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 166 | /* Append no more than N characters from SRC onto DEST. */ | |||
| 167 | extern char *strncat (char *__restrict __dest, const char *__restrict __src, | |||
| 168 | size_t __n) __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 169 | ||||
| 170 | /* Compare S1 and S2. */ | |||
| 171 | extern int strcmp (const char *__s1, const char *__s2) | |||
| 172 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 173 | /* Compare N characters of S1 and S2. */ | |||
| 174 | extern int strncmp (const char *__s1, const char *__s2, size_t __n) | |||
| 175 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 176 | ||||
| 177 | /* Compare the collated forms of S1 and S2. */ | |||
| 178 | extern int strcoll (const char *__s1, const char *__s2) | |||
| 179 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 180 | /* Put a transformation of SRC into no more than N bytes of DEST. */ | |||
| 181 | extern size_t strxfrm (char *__restrict __dest, | |||
| 182 | const char *__restrict __src, size_t __n) | |||
| 183 | __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __attr_access ((__write_only__, 1, 3)); | |||
| 184 | ||||
| 185 | #ifdef __USE_XOPEN2K81 | |||
| 186 | /* POSIX.1-2008 extended locale interface (see locale.h). */ | |||
| 187 | # include <bits/types/locale_t.h> | |||
| 188 | ||||
| 189 | /* Compare the collated forms of S1 and S2, using sorting rules from L. */ | |||
| 190 | extern int strcoll_l (const char *__s1, const char *__s2, locale_t __l) | |||
| 191 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2, 3))__attribute__ ((__nonnull__ (1, 2, 3))); | |||
| 192 | /* Put a transformation of SRC into no more than N bytes of DEST, | |||
| 193 | using sorting rules from L. */ | |||
| 194 | extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n, | |||
| 195 | locale_t __l) __THROWnoexcept (true) __nonnull ((2, 4))__attribute__ ((__nonnull__ (2, 4))) | |||
| 196 | __attr_access ((__write_only__, 1, 3)); | |||
| 197 | #endif | |||
| 198 | ||||
| 199 | #if (defined __USE_XOPEN_EXTENDED1 || defined __USE_XOPEN2K81 \ | |||
| 200 | || __GLIBC_USE (LIB_EXT2)1 || __GLIBC_USE (ISOC23)1) | |||
| 201 | /* Duplicate S, returning an identical malloc'd string. */ | |||
| 202 | extern char *strdup (const char *__s) | |||
| 203 | __THROWnoexcept (true) __attribute_malloc____attribute__ ((__malloc__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 204 | #endif | |||
| 205 | ||||
| 206 | /* Return a malloc'd copy of at most N bytes of STRING. The | |||
| 207 | resultant string is terminated even if no null terminator | |||
| 208 | appears before STRING[N]. */ | |||
| 209 | #if defined __USE_XOPEN2K81 || __GLIBC_USE (LIB_EXT2)1 || __GLIBC_USE (ISOC23)1 | |||
| 210 | extern char *strndup (const char *__string, size_t __n) | |||
| 211 | __THROWnoexcept (true) __attribute_malloc____attribute__ ((__malloc__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 212 | #endif | |||
| 213 | ||||
| 214 | #if defined __USE_GNU1 && defined __GNUC__4 | |||
| 215 | /* Duplicate S, returning an identical alloca'd string. */ | |||
| 216 | # define strdupa(s)(__extension__ ({ const char *__old = (s); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca (__len) ; (char *) memcpy (__new, __old, __len); })) \ | |||
| 217 | (__extension__ \ | |||
| 218 | ({ \ | |||
| 219 | const char *__old = (s); \ | |||
| 220 | size_t __len = strlen (__old) + 1; \ | |||
| 221 | char *__new = (char *) __builtin_alloca (__len); \ | |||
| 222 | (char *) memcpy (__new, __old, __len); \ | |||
| 223 | })) | |||
| 224 | ||||
| 225 | /* Return an alloca'd copy of at most N bytes of string. */ | |||
| 226 | # define strndupa(s, n)(__extension__ ({ const char *__old = (s); size_t __len = strnlen (__old, (n)); char *__new = (char *) __builtin_alloca (__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len ); })) \ | |||
| 227 | (__extension__ \ | |||
| 228 | ({ \ | |||
| 229 | const char *__old = (s); \ | |||
| 230 | size_t __len = strnlen (__old, (n)); \ | |||
| 231 | char *__new = (char *) __builtin_alloca (__len + 1); \ | |||
| 232 | __new[__len] = '\0'; \ | |||
| 233 | (char *) memcpy (__new, __old, __len); \ | |||
| 234 | })) | |||
| 235 | #endif | |||
| 236 | ||||
| 237 | /* Find the first occurrence of C in S. */ | |||
| 238 | #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 239 | extern "C++" | |||
| 240 | { | |||
| 241 | extern char *strchr (char *__s, int __c) | |||
| 242 | __THROWnoexcept (true) __asm ("strchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 243 | extern const char *strchr (const char *__s, int __c) | |||
| 244 | __THROWnoexcept (true) __asm ("strchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 245 | ||||
| 246 | # ifdef __OPTIMIZE__1 | |||
| 247 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * | |||
| 248 | strchr (char *__s, int __c) __THROWnoexcept (true) | |||
| 249 | { | |||
| 250 | return __builtin_strchr (__s, __c); | |||
| 251 | } | |||
| 252 | ||||
| 253 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) const char * | |||
| 254 | strchr (const char *__s, int __c) __THROWnoexcept (true) | |||
| 255 | { | |||
| 256 | return __builtin_strchr (__s, __c); | |||
| 257 | } | |||
| 258 | # endif | |||
| 259 | } | |||
| 260 | #else | |||
| 261 | extern char *strchr (const char *__s, int __c) | |||
| 262 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 263 | # if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC | |||
| 264 | # define strchr(S, C) \ | |||
| 265 | __glibc_const_generic (S, const char *, strchr (S, C)) | |||
| 266 | # endif | |||
| 267 | #endif | |||
| 268 | /* Find the last occurrence of C in S. */ | |||
| 269 | #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 270 | extern "C++" | |||
| 271 | { | |||
| 272 | extern char *strrchr (char *__s, int __c) | |||
| 273 | __THROWnoexcept (true) __asm ("strrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 274 | extern const char *strrchr (const char *__s, int __c) | |||
| 275 | __THROWnoexcept (true) __asm ("strrchr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 276 | ||||
| 277 | # ifdef __OPTIMIZE__1 | |||
| 278 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * | |||
| 279 | strrchr (char *__s, int __c) __THROWnoexcept (true) | |||
| 280 | { | |||
| 281 | return __builtin_strrchr (__s, __c); | |||
| ||||
| 282 | } | |||
| 283 | ||||
| 284 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) const char * | |||
| 285 | strrchr (const char *__s, int __c) __THROWnoexcept (true) | |||
| 286 | { | |||
| 287 | return __builtin_strrchr (__s, __c); | |||
| 288 | } | |||
| 289 | # endif | |||
| 290 | } | |||
| 291 | #else | |||
| 292 | extern char *strrchr (const char *__s, int __c) | |||
| 293 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 294 | # if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC | |||
| 295 | # define strrchr(S, C) \ | |||
| 296 | __glibc_const_generic (S, const char *, strrchr (S, C)) | |||
| 297 | # endif | |||
| 298 | #endif | |||
| 299 | ||||
| 300 | #ifdef __USE_MISC1 | |||
| 301 | /* This function is similar to `strchr'. But it returns a pointer to | |||
| 302 | the closing NUL byte in case C is not found in S. */ | |||
| 303 | # ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 304 | extern "C++" char *strchrnul (char *__s, int __c) | |||
| 305 | __THROWnoexcept (true) __asm ("strchrnul") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 306 | extern "C++" const char *strchrnul (const char *__s, int __c) | |||
| 307 | __THROWnoexcept (true) __asm ("strchrnul") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 308 | # else | |||
| 309 | extern char *strchrnul (const char *__s, int __c) | |||
| 310 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 311 | # endif | |||
| 312 | #endif | |||
| 313 | ||||
| 314 | /* Return the length of the initial segment of S which | |||
| 315 | consists entirely of characters not in REJECT. */ | |||
| 316 | extern size_t strcspn (const char *__s, const char *__reject) | |||
| 317 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 318 | /* Return the length of the initial segment of S which | |||
| 319 | consists entirely of characters in ACCEPT. */ | |||
| 320 | extern size_t strspn (const char *__s, const char *__accept) | |||
| 321 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 322 | /* Find the first occurrence in S of any character in ACCEPT. */ | |||
| 323 | #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 324 | extern "C++" | |||
| 325 | { | |||
| 326 | extern char *strpbrk (char *__s, const char *__accept) | |||
| 327 | __THROWnoexcept (true) __asm ("strpbrk") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 328 | extern const char *strpbrk (const char *__s, const char *__accept) | |||
| 329 | __THROWnoexcept (true) __asm ("strpbrk") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 330 | ||||
| 331 | # ifdef __OPTIMIZE__1 | |||
| 332 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * | |||
| 333 | strpbrk (char *__s, const char *__accept) __THROWnoexcept (true) | |||
| 334 | { | |||
| 335 | return __builtin_strpbrk (__s, __accept); | |||
| 336 | } | |||
| 337 | ||||
| 338 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) const char * | |||
| 339 | strpbrk (const char *__s, const char *__accept) __THROWnoexcept (true) | |||
| 340 | { | |||
| 341 | return __builtin_strpbrk (__s, __accept); | |||
| 342 | } | |||
| 343 | # endif | |||
| 344 | } | |||
| 345 | #else | |||
| 346 | extern char *strpbrk (const char *__s, const char *__accept) | |||
| 347 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 348 | # if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC | |||
| 349 | # define strpbrk(S, ACCEPT) \ | |||
| 350 | __glibc_const_generic (S, const char *, strpbrk (S, ACCEPT)) | |||
| 351 | # endif | |||
| 352 | #endif | |||
| 353 | /* Find the first occurrence of NEEDLE in HAYSTACK. */ | |||
| 354 | #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 355 | extern "C++" | |||
| 356 | { | |||
| 357 | extern char *strstr (char *__haystack, const char *__needle) | |||
| 358 | __THROWnoexcept (true) __asm ("strstr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 359 | extern const char *strstr (const char *__haystack, const char *__needle) | |||
| 360 | __THROWnoexcept (true) __asm ("strstr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 361 | ||||
| 362 | # ifdef __OPTIMIZE__1 | |||
| 363 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * | |||
| 364 | strstr (char *__haystack, const char *__needle) __THROWnoexcept (true) | |||
| 365 | { | |||
| 366 | return __builtin_strstr (__haystack, __needle); | |||
| 367 | } | |||
| 368 | ||||
| 369 | __extern_always_inlineextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) const char * | |||
| 370 | strstr (const char *__haystack, const char *__needle) __THROWnoexcept (true) | |||
| 371 | { | |||
| 372 | return __builtin_strstr (__haystack, __needle); | |||
| 373 | } | |||
| 374 | # endif | |||
| 375 | } | |||
| 376 | #else | |||
| 377 | extern char *strstr (const char *__haystack, const char *__needle) | |||
| 378 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 379 | # if __GLIBC_USE (ISOC23)1 && defined __glibc_const_generic && !defined _LIBC | |||
| 380 | # define strstr(HAYSTACK, NEEDLE) \ | |||
| 381 | __glibc_const_generic (HAYSTACK, const char *, \ | |||
| 382 | strstr (HAYSTACK, NEEDLE)) | |||
| 383 | # endif | |||
| 384 | #endif | |||
| 385 | ||||
| 386 | ||||
| 387 | /* Divide S into tokens separated by characters in DELIM. */ | |||
| 388 | extern char *strtok (char *__restrict __s, const char *__restrict __delim) | |||
| 389 | __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))); | |||
| 390 | ||||
| 391 | /* Divide S into tokens separated by characters in DELIM. Information | |||
| 392 | passed between calls are stored in SAVE_PTR. */ | |||
| 393 | extern char *__strtok_r (char *__restrict __s, | |||
| 394 | const char *__restrict __delim, | |||
| 395 | char **__restrict __save_ptr) | |||
| 396 | __THROWnoexcept (true) __nonnull ((2, 3))__attribute__ ((__nonnull__ (2, 3))); | |||
| 397 | #ifdef __USE_POSIX1 | |||
| 398 | extern char *strtok_r (char *__restrict __s, const char *__restrict __delim, | |||
| 399 | char **__restrict __save_ptr) | |||
| 400 | __THROWnoexcept (true) __nonnull ((2, 3))__attribute__ ((__nonnull__ (2, 3))); | |||
| 401 | #endif | |||
| 402 | ||||
| 403 | #ifdef __USE_MISC1 | |||
| 404 | /* Similar to `strstr' but this function ignores the case of both strings. */ | |||
| 405 | # ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 406 | extern "C++" char *strcasestr (char *__haystack, const char *__needle) | |||
| 407 | __THROWnoexcept (true) __asm ("strcasestr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 408 | extern "C++" const char *strcasestr (const char *__haystack, | |||
| 409 | const char *__needle) | |||
| 410 | __THROWnoexcept (true) __asm ("strcasestr") __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 411 | # else | |||
| 412 | extern char *strcasestr (const char *__haystack, const char *__needle) | |||
| 413 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 414 | # endif | |||
| 415 | #endif | |||
| 416 | ||||
| 417 | #ifdef __USE_MISC1 | |||
| 418 | /* Find the first occurrence of NEEDLE in HAYSTACK. | |||
| 419 | NEEDLE is NEEDLELEN bytes long; | |||
| 420 | HAYSTACK is HAYSTACKLEN bytes long. */ | |||
| 421 | extern void *memmem (const void *__haystack, size_t __haystacklen, | |||
| 422 | const void *__needle, size_t __needlelen) | |||
| 423 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 3))__attribute__ ((__nonnull__ (1, 3))) | |||
| 424 | __attr_access ((__read_only__, 1, 2)) | |||
| 425 | __attr_access ((__read_only__, 3, 4)); | |||
| 426 | ||||
| 427 | /* Copy N bytes of SRC to DEST, return pointer to bytes after the | |||
| 428 | last written byte. */ | |||
| 429 | extern void *__mempcpy (void *__restrict __dest, | |||
| 430 | const void *__restrict __src, size_t __n) | |||
| 431 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 432 | extern void *mempcpy (void *__restrict __dest, | |||
| 433 | const void *__restrict __src, size_t __n) | |||
| 434 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 435 | #endif | |||
| 436 | ||||
| 437 | ||||
| 438 | /* Return the length of S. */ | |||
| 439 | extern size_t strlen (const char *__s) | |||
| 440 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 441 | ||||
| 442 | #ifdef __USE_XOPEN2K81 | |||
| 443 | /* Find the length of STRING, but scan at most MAXLEN characters. | |||
| 444 | If no '\0' terminator is found in that many characters, return MAXLEN. */ | |||
| 445 | extern size_t strnlen (const char *__string, size_t __maxlen) | |||
| 446 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 447 | #endif | |||
| 448 | ||||
| 449 | ||||
| 450 | /* Return a string describing the meaning of the `errno' code in ERRNUM. */ | |||
| 451 | extern char *strerror (int __errnum) __THROWnoexcept (true); | |||
| 452 | #ifdef __USE_XOPEN2K1 | |||
| 453 | /* Reentrant version of `strerror'. | |||
| 454 | There are 2 flavors of `strerror_r', GNU which returns the string | |||
| 455 | and may or may not use the supplied temporary buffer and POSIX one | |||
| 456 | which fills the string into the buffer. | |||
| 457 | To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L | |||
| 458 | without -D_GNU_SOURCE is needed, otherwise the GNU version is | |||
| 459 | preferred. */ | |||
| 460 | # if defined __USE_XOPEN2K1 && !defined __USE_GNU1 | |||
| 461 | /* Fill BUF with a string describing the meaning of the `errno' code in | |||
| 462 | ERRNUM. */ | |||
| 463 | # ifdef __REDIRECT_NTH | |||
| 464 | extern int __REDIRECT_NTH (strerror_r,strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept (true) __asm__ ("" "__xpg_strerror_r") | |||
| 465 | (int __errnum, char *__buf, size_t __buflen),strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept (true) __asm__ ("" "__xpg_strerror_r") | |||
| 466 | __xpg_strerror_r)strerror_r (int __errnum, char *__buf, size_t __buflen) noexcept (true) __asm__ ("" "__xpg_strerror_r") __nonnull ((2))__attribute__ ((__nonnull__ (2))) | |||
| 467 | __attr_access ((__write_only__, 2, 3)); | |||
| 468 | # else | |||
| 469 | extern int __xpg_strerror_r (int __errnum, char *__buf, size_t __buflen) | |||
| 470 | __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __attr_access ((__write_only__, 2, 3)); | |||
| 471 | # define strerror_r __xpg_strerror_r | |||
| 472 | # endif | |||
| 473 | # else | |||
| 474 | /* If a temporary buffer is required, at most BUFLEN bytes of BUF will be | |||
| 475 | used. */ | |||
| 476 | extern char *strerror_r (int __errnum, char *__buf, size_t __buflen) | |||
| 477 | __THROWnoexcept (true) __nonnull ((2))__attribute__ ((__nonnull__ (2))) __wur__attribute__ ((__warn_unused_result__)) __attr_access ((__write_only__, 2, 3)); | |||
| 478 | # endif | |||
| 479 | ||||
| 480 | # ifdef __USE_GNU1 | |||
| 481 | /* Return a string describing the meaning of tthe error in ERR. */ | |||
| 482 | extern const char *strerrordesc_np (int __err) __THROWnoexcept (true); | |||
| 483 | /* Return a string with the error name in ERR. */ | |||
| 484 | extern const char *strerrorname_np (int __err) __THROWnoexcept (true); | |||
| 485 | # endif | |||
| 486 | #endif | |||
| 487 | ||||
| 488 | #ifdef __USE_XOPEN2K81 | |||
| 489 | /* Translate error number to string according to the locale L. */ | |||
| 490 | extern char *strerror_l (int __errnum, locale_t __l) __THROWnoexcept (true); | |||
| 491 | #endif | |||
| 492 | ||||
| 493 | #ifdef __USE_MISC1 | |||
| 494 | # include <strings.h> | |||
| 495 | ||||
| 496 | /* Set N bytes of S to 0. The compiler will not delete a call to this | |||
| 497 | function, even if S is dead after the call. */ | |||
| 498 | extern void explicit_bzero (void *__s, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))) | |||
| 499 | __fortified_attr_access (__write_only__, 1, 2); | |||
| 500 | ||||
| 501 | /* Return the next DELIM-delimited token from *STRINGP, | |||
| 502 | terminating it with a '\0', and update *STRINGP to point past it. */ | |||
| 503 | extern char *strsep (char **__restrict __stringp, | |||
| 504 | const char *__restrict __delim) | |||
| 505 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 506 | #endif | |||
| 507 | ||||
| 508 | #ifdef __USE_XOPEN2K81 | |||
| 509 | /* Return a string describing the meaning of the signal number in SIG. */ | |||
| 510 | extern char *strsignal (int __sig) __THROWnoexcept (true); | |||
| 511 | ||||
| 512 | # ifdef __USE_GNU1 | |||
| 513 | /* Return an abbreviation string for the signal number SIG. */ | |||
| 514 | extern const char *sigabbrev_np (int __sig) __THROWnoexcept (true); | |||
| 515 | /* Return a string describing the meaning of the signal number in SIG, | |||
| 516 | the result is not translated. */ | |||
| 517 | extern const char *sigdescr_np (int __sig) __THROWnoexcept (true); | |||
| 518 | # endif | |||
| 519 | ||||
| 520 | /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ | |||
| 521 | extern char *__stpcpy (char *__restrict __dest, const char *__restrict __src) | |||
| 522 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 523 | extern char *stpcpy (char *__restrict __dest, const char *__restrict __src) | |||
| 524 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 525 | ||||
| 526 | /* Copy no more than N characters of SRC to DEST, returning the address of | |||
| 527 | the last character written into DEST. */ | |||
| 528 | extern char *__stpncpy (char *__restrict __dest, | |||
| 529 | const char *__restrict __src, size_t __n) | |||
| 530 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 531 | extern char *stpncpy (char *__restrict __dest, | |||
| 532 | const char *__restrict __src, size_t __n) | |||
| 533 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 534 | #endif | |||
| 535 | ||||
| 536 | #ifdef __USE_MISC1 | |||
| 537 | /* Copy at most N - 1 characters from SRC to DEST. */ | |||
| 538 | extern size_t strlcpy (char *__restrict __dest, | |||
| 539 | const char *__restrict __src, size_t __n) | |||
| 540 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__write_only__, 1, 3)); | |||
| 541 | ||||
| 542 | /* Append SRC to DEST, possibly with truncation to keep the total size | |||
| 543 | below N. */ | |||
| 544 | extern size_t strlcat (char *__restrict __dest, | |||
| 545 | const char *__restrict __src, size_t __n) | |||
| 546 | __THROWnoexcept (true) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))) __attr_access ((__read_write__, 1, 3)); | |||
| 547 | #endif | |||
| 548 | ||||
| 549 | #ifdef __USE_GNU1 | |||
| 550 | /* Compare S1 and S2 as strings holding name & indices/version numbers. */ | |||
| 551 | extern int strverscmp (const char *__s1, const char *__s2) | |||
| 552 | __THROWnoexcept (true) __attribute_pure____attribute__ ((__pure__)) __nonnull ((1, 2))__attribute__ ((__nonnull__ (1, 2))); | |||
| 553 | ||||
| 554 | /* Sautee STRING briskly. */ | |||
| 555 | extern char *strfry (char *__string) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 556 | ||||
| 557 | /* Frobnicate N bytes of S. */ | |||
| 558 | extern void *memfrob (void *__s, size_t __n) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))) | |||
| 559 | __attr_access ((__read_write__, 1, 2)); | |||
| 560 | ||||
| 561 | # ifndef basename | |||
| 562 | /* Return the file name within directory of FILENAME. We don't | |||
| 563 | declare the function if the `basename' macro is available (defined | |||
| 564 | in <libgen.h>) which makes the XPG version of this function | |||
| 565 | available. */ | |||
| 566 | # ifdef __CORRECT_ISO_CPP_STRING_H_PROTO | |||
| 567 | extern "C++" char *basename (char *__filename) | |||
| 568 | __THROWnoexcept (true) __asm ("basename") __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 569 | extern "C++" const char *basename (const char *__filename) | |||
| 570 | __THROWnoexcept (true) __asm ("basename") __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 571 | # else | |||
| 572 | extern char *basename (const char *__filename) __THROWnoexcept (true) __nonnull ((1))__attribute__ ((__nonnull__ (1))); | |||
| 573 | # endif | |||
| 574 | # endif | |||
| 575 | #endif | |||
| 576 | ||||
| 577 | #if __GNUC_PREREQ (3,4)((4 << 16) + 2 >= ((3) << 16) + (4)) | |||
| 578 | # if __USE_FORTIFY_LEVEL2 > 0 && defined __fortify_functionextern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) __attribute__ ((__artificial__)) | |||
| 579 | /* Functions with security checks. */ | |||
| 580 | # include <bits/string_fortified.h> | |||
| 581 | # endif | |||
| 582 | #endif | |||
| 583 | ||||
| 584 | __END_DECLS} | |||
| 585 | ||||
| 586 | #endif /* string.h */ |