VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/pathhost-posix.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.0 KB
Line 
1/* $Id: pathhost-posix.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Path Conversions, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_PATH
42#include "internal/iprt.h"
43#include "internal/path.h"
44#include "internal/string.h"
45#include "internal/thread.h"
46
47#include <iprt/env.h>
48#include <iprt/err.h>
49#include <iprt/string.h>
50#include <iprt/once.h>
51
52
53/*********************************************************************************************************************************
54* Global Variables *
55*********************************************************************************************************************************/
56/** Initialize once object. */
57static RTONCE g_OnceInitPathConv = RTONCE_INITIALIZER;
58/** If set, then we can pass UTF-8 thru directly. */
59static bool g_fPassthruUtf8 = false;
60/** The UTF-8 to FS iconv cache entry. */
61static RTSTRICONV g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_LOCALE;
62/** The FS to UTF-8 iconv cache entry. */
63static RTSTRICONV g_enmFsToUtf8Idx = RTSTRICONV_LOCALE_TO_UTF8;
64/** The codeset we're using. */
65static char g_szFsCodeset[32];
66
67
68/**
69 * Do a case insensitive compare where the 2nd string is known and can be case
70 * folded when writing the code.
71 *
72 * @returns see strcmp.
73 * @param pszStr1 The string to compare against pszLower and
74 * pszUpper.
75 * @param pszUpper The upper case edition of the 2nd string.
76 * @param pszLower The lower case edition of the 2nd string.
77 */
78static int rtPathStrICmp(const char *pszStr1, const char *pszUpper, const char *pszLower)
79{
80 Assert(strlen(pszLower) == strlen(pszUpper));
81 for (;;)
82 {
83 char ch1 = *pszStr1++;
84 char ch2Upper = *pszUpper++;
85 char ch2Lower = *pszLower++;
86 if ( ch1 != ch2Upper
87 && ch1 != ch2Lower)
88 return ch1 < ch2Upper ? -1 : 1;
89 if (!ch1)
90 return 0;
91 }
92}
93
94/**
95 * Is the specified codeset something we can treat as UTF-8.
96 *
97 * @returns true if we can do UTF-8 passthru, false if not.
98 * @param pszCodeset The codeset in question.
99 */
100static bool rtPathConvInitIsUtf8(const char *pszCodeset)
101{
102 /* Paranoia. */
103 if (!pszCodeset)
104 return false;
105
106 /*
107 * Avoid RTStrICmp at this point.
108 */
109 static struct
110 {
111 const char *pszUpper;
112 const char *pszLower;
113 } const s_aUtf8Compatible[] =
114 {
115 /* The default locale. */
116 { "C" , "c" },
117 { "POSIX" , "posix" },
118 /* 7-bit ASCII. */
119 { "ANSI_X3.4-1968" , "ansi_x3.4-1968" },
120 { "ANSI_X3.4-1986" , "ansi_x3.4-1986" },
121 { "US-ASCII" , "us-ascii" },
122 { "ISO646-US" , "iso646-us" },
123 { "ISO_646.IRV:1991" , "iso_646.irv:1991" },
124 { "ISO-IR-6" , "iso-ir-6" },
125 { "IBM367" , "ibm367" },
126 /* UTF-8 */
127 { "UTF-8" , "utf-8" },
128 { "UTF8" , "utf8" },
129 { "ISO-10646/UTF-8" , "iso-10646/utf-8" },
130 { "ISO-10646/UTF8" , "iso-10646/utf8" }
131 };
132
133 for (size_t i = 0; i < RT_ELEMENTS(s_aUtf8Compatible); i++)
134 if (!rtPathStrICmp(pszCodeset, s_aUtf8Compatible[i].pszUpper, s_aUtf8Compatible[i].pszLower))
135 return true;
136
137 return false;
138}
139
140
141/**
142 * Init once for the path conversion code.
143 *
144 * @returns IPRT status code.
145 * @param pvUser1 Unused.
146 * @param pvUser2 Unused.
147 */
148static DECLCALLBACK(int32_t) rtPathConvInitOnce(void *pvUser)
149{
150 /*
151 * Read the environment variable, no mercy on misconfigs here except that
152 * empty values are quietly ignored. (We use a temp buffer for stripping.)
153 */
154 char *pszEnvValue = NULL;
155 char szEnvValue[sizeof(g_szFsCodeset)];
156 int rc = RTEnvGetEx(RTENV_DEFAULT, RTPATH_CODESET_ENV_VAR, szEnvValue, sizeof(szEnvValue), NULL);
157 if (rc != VERR_ENV_VAR_NOT_FOUND && RT_FAILURE(rc))
158 return rc;
159 if (RT_SUCCESS(rc))
160 pszEnvValue = RTStrStrip(szEnvValue);
161
162 if (pszEnvValue && *pszEnvValue)
163 {
164 g_fPassthruUtf8 = rtPathConvInitIsUtf8(pszEnvValue);
165 g_enmFsToUtf8Idx = RTSTRICONV_FS_TO_UTF8;
166 g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_FS;
167 strcpy(g_szFsCodeset, pszEnvValue);
168 }
169 else
170 {
171 const char *pszCodeset = rtStrGetLocaleCodeset();
172 size_t cchCodeset = pszCodeset ? strlen(pszCodeset) : sizeof(g_szFsCodeset);
173 if (cchCodeset >= sizeof(g_szFsCodeset))
174 /* This shouldn't happen, but we'll manage. */
175 g_szFsCodeset[0] = '\0';
176 else
177 {
178 memcpy(g_szFsCodeset, pszCodeset, cchCodeset + 1);
179 pszCodeset = g_szFsCodeset;
180 }
181 g_fPassthruUtf8 = rtPathConvInitIsUtf8(pszCodeset);
182 g_enmFsToUtf8Idx = RTSTRICONV_LOCALE_TO_UTF8;
183 g_enmUtf8ToFsIdx = RTSTRICONV_UTF8_TO_LOCALE;
184 }
185
186 NOREF(pvUser);
187 return VINF_SUCCESS;
188}
189
190
191int rtPathToNative(char const **ppszNativePath, const char *pszPath, const char *pszBasePath)
192{
193 *ppszNativePath = NULL;
194
195 int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
196 if (RT_SUCCESS(rc))
197 {
198 if (g_fPassthruUtf8 || !*pszPath)
199 *ppszNativePath = pszPath;
200 else
201 rc = rtStrConvert(pszPath, strlen(pszPath), "UTF-8",
202 (char **)ppszNativePath, 0, g_szFsCodeset,
203 2, g_enmUtf8ToFsIdx);
204 }
205 NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
206 return rc;
207}
208
209
210void rtPathFreeNative(char const *pszNativePath, const char *pszPath)
211{
212 if ( pszNativePath != pszPath
213 && pszNativePath)
214 RTStrFree((char *)pszNativePath);
215}
216
217
218int rtPathFromNative(const char **ppszPath, const char *pszNativePath, const char *pszBasePath)
219{
220 *ppszPath = NULL;
221
222 int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
223 if (RT_SUCCESS(rc))
224 {
225 if (g_fPassthruUtf8 || !*pszNativePath)
226 {
227 size_t cCpsIgnored;
228 size_t cchNativePath;
229 rc = rtUtf8Length(pszNativePath, RTSTR_MAX, &cCpsIgnored, &cchNativePath);
230 if (RT_SUCCESS(rc))
231 {
232 char *pszPath;
233 *ppszPath = pszPath = RTStrAlloc(cchNativePath + 1);
234 if (pszPath)
235 memcpy(pszPath, pszNativePath, cchNativePath + 1);
236 else
237 rc = VERR_NO_STR_MEMORY;
238 }
239 }
240 else
241 rc = rtStrConvert(pszNativePath, strlen(pszNativePath), g_szFsCodeset,
242 (char **)ppszPath, 0, "UTF-8",
243 2, g_enmFsToUtf8Idx);
244 }
245 NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
246 return rc;
247}
248
249
250void rtPathFreeIprt(const char *pszPath, const char *pszNativePath)
251{
252 if ( pszPath != pszNativePath
253 && pszPath)
254 RTStrFree((char *)pszPath);
255}
256
257
258int rtPathFromNativeCopy(char *pszPath, size_t cbPath, const char *pszNativePath, const char *pszBasePath)
259{
260 int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
261 if (RT_SUCCESS(rc))
262 {
263 if (g_fPassthruUtf8 || !*pszNativePath)
264 rc = RTStrCopy(pszPath, cbPath, pszNativePath);
265 else if (cbPath)
266 rc = rtStrConvert(pszNativePath, strlen(pszNativePath), g_szFsCodeset,
267 &pszPath, cbPath, "UTF-8",
268 2, g_enmFsToUtf8Idx);
269 else
270 rc = VERR_BUFFER_OVERFLOW;
271 }
272
273 NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
274 return rc;
275}
276
277
278int rtPathFromNativeDup(char **ppszPath, const char *pszNativePath, const char *pszBasePath)
279{
280 int rc = RTOnce(&g_OnceInitPathConv, rtPathConvInitOnce, NULL);
281 if (RT_SUCCESS(rc))
282 {
283 if (g_fPassthruUtf8 || !*pszNativePath)
284 rc = RTStrDupEx(ppszPath, pszNativePath);
285 else
286 rc = rtStrConvert(pszNativePath, strlen(pszNativePath), g_szFsCodeset,
287 ppszPath, 0, "UTF-8",
288 2, g_enmFsToUtf8Idx);
289 }
290
291 NOREF(pszBasePath); /* We don't query the FS for codeset preferences. */
292 return rc;
293}
294
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use