VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/createtemp-generic.cpp@ 78052

Last change on this file since 78052 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/* $Id: createtemp-generic.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - temporary file and directory creation, generic implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/dir.h>
32#include "internal/iprt.h"
33
34#include <iprt/assert.h>
35#include <iprt/err.h>
36#include <iprt/file.h>
37#include <iprt/path.h>
38#include <iprt/rand.h>
39#include <iprt/string.h>
40
41
42static int rtCreateTempValidateTemplate(char *pszTemplate, char **ppszX,
43 unsigned *pcXes)
44{
45 /*
46 * Validate input and count X'es.
47 *
48 * The X'es may be trailing, or they may be a cluster of 3 or more inside
49 * the file name.
50 */
51 AssertPtr(pszTemplate);
52 AssertPtr(ppszX);
53 AssertPtr(pcXes);
54 unsigned cXes = 0;
55 char *pszX = strchr(pszTemplate, '\0');
56 if ( pszX != pszTemplate
57 && pszX[-1] != 'X')
58 {
59 /* look inside the file name. */
60 char *pszFilename = RTPathFilename(pszTemplate);
61 if ( pszFilename
62 && (size_t)(pszX - pszFilename) > 3)
63 {
64 char *pszXEnd = pszX - 1;
65 pszFilename += 3;
66 do
67 {
68 if ( pszXEnd[-1] == 'X'
69 && pszXEnd[-2] == 'X'
70 && pszXEnd[-3] == 'X')
71 {
72 pszX = pszXEnd - 3;
73 cXes = 3;
74 break;
75 }
76 } while (pszXEnd-- != pszFilename);
77 }
78 }
79
80 /* count them */
81 while ( pszX != pszTemplate
82 && pszX[-1] == 'X')
83 {
84 pszX--;
85 cXes++;
86 }
87
88 /* fail if none found. */
89 if (!cXes)
90 {
91 AssertFailed();
92 return VERR_INVALID_PARAMETER;
93 }
94 *ppszX = pszX;
95 *pcXes = cXes;
96 return VINF_SUCCESS;
97}
98
99
100static void rtCreateTempFillTemplate(char *pszX, unsigned cXes)
101{
102 static char const s_sz[] = "0123456789abcdefghijklmnopqrstuvwxyz";
103 unsigned j = cXes;
104 while (j-- > 0)
105 pszX[j] = s_sz[RTRandU32Ex(0, RT_ELEMENTS(s_sz) - 2)];
106}
107
108
109RTDECL(int) RTDirCreateTemp(char *pszTemplate, RTFMODE fMode)
110{
111 char *pszX = NULL;
112 unsigned cXes = 0;
113 int rc = rtCreateTempValidateTemplate(pszTemplate, &pszX, &cXes);
114 if (RT_FAILURE(rc))
115 {
116 *pszTemplate = '\0';
117 return rc;
118 }
119 /*
120 * Try ten thousand times.
121 */
122 int i = 10000;
123 while (i-- > 0)
124 {
125 rtCreateTempFillTemplate(pszX, cXes);
126 rc = RTDirCreate(pszTemplate, fMode, 0);
127 if (RT_SUCCESS(rc))
128 return rc;
129 if (rc != VERR_ALREADY_EXISTS)
130 {
131 *pszTemplate = '\0';
132 return rc;
133 }
134 }
135
136 /* we've given up. */
137 *pszTemplate = '\0';
138 return VERR_ALREADY_EXISTS;
139}
140RT_EXPORT_SYMBOL(RTDirCreateTemp);
141
142
143/** @todo Test case for this once it is implemented. */
144RTDECL(int) RTDirCreateTempSecure(char *pszTemplate)
145{
146 size_t cchDir;
147 char chOld;
148 int rc;
149 /* bool fSafe; */
150
151 /* Temporarily convert pszTemplate to a path. */
152 RTPathParseSimple(pszTemplate, &cchDir, NULL, NULL);
153 chOld = pszTemplate[cchDir];
154 pszTemplate[cchDir] = '\0';
155 /** @todo Implement this. */
156 rc = /* RTPathIsSecure(pszTemplate, &fSafe) */ VERR_NOT_SUPPORTED;
157 pszTemplate[cchDir] = chOld;
158 if (RT_SUCCESS(rc) /* && fSafe */)
159 return RTDirCreateTemp(pszTemplate, 0700);
160 else
161 {
162 *pszTemplate = '\0';
163 /** @todo Replace VERR_PERMISSION_DENIED. VERR_INSECURE? */
164 return RT_FAILURE(rc) ? rc : VERR_PERMISSION_DENIED;
165 }
166}
167RT_EXPORT_SYMBOL(RTDirCreateTempSecure);
168
169
170RTDECL(int) RTFileCreateTemp(char *pszTemplate, RTFMODE fMode)
171{
172 char *pszX = NULL;
173 unsigned cXes = 0;
174 RTFILE hFile;
175 int rc = rtCreateTempValidateTemplate(pszTemplate, &pszX, &cXes);
176 if (RT_FAILURE(rc))
177 {
178 *pszTemplate = '\0';
179 return rc;
180 }
181 /*
182 * Try ten thousand times.
183 */
184 int i = 10000;
185 while (i-- > 0)
186 {
187 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL
188 | RTFILE_O_CREATE | RTFILE_O_NOT_CONTENT_INDEXED
189 | fMode << RTFILE_O_CREATE_MODE_SHIFT;
190 rtCreateTempFillTemplate(pszX, cXes);
191 rc = RTFileOpen(&hFile, pszTemplate, fOpen);
192 if (RT_SUCCESS(rc))
193 {
194 RTFileClose(hFile);
195 return rc;
196 }
197 /** @todo Anything else to consider? */
198 if (rc != VERR_ALREADY_EXISTS)
199 {
200 *pszTemplate = '\0';
201 return rc;
202 }
203 }
204
205 /* we've given up. */
206 *pszTemplate = '\0';
207 return VERR_ALREADY_EXISTS;
208}
209RT_EXPORT_SYMBOL(RTFileCreateTemp);
210
211
212/** @todo Test case for this once it is implemented. */
213RTDECL(int) RTFileCreateTempSecure(char *pszTemplate)
214{
215 size_t cchDir;
216 char chOld;
217 int rc;
218 /* bool fSafe; */
219
220 /* Temporarily convert pszTemplate to a path. */
221 RTPathParseSimple(pszTemplate, &cchDir, NULL, NULL);
222 chOld = pszTemplate[cchDir];
223 pszTemplate[cchDir] = '\0';
224 /** @todo Implement this. */
225 rc = /* RTPathIsSecure(pszTemplate, &fSafe) */ VERR_NOT_SUPPORTED;
226 pszTemplate[cchDir] = chOld;
227 if (RT_SUCCESS(rc) /* && fSafe */)
228 return RTFileCreateTemp(pszTemplate, 0600);
229 else
230 {
231 *pszTemplate = '\0';
232 /** @todo Replace VERR_PERMISSION_DENIED. VERR_INSECURE? */
233 return RT_FAILURE(rc) ? rc : VERR_PERMISSION_DENIED;
234 }
235}
236RT_EXPORT_SYMBOL(RTFileCreateTempSecure);
237
238
239RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen)
240{
241 AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS);
242 AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS);
243
244 /*
245 * Start by obtaining the path to the temporary directory.
246 */
247 int rc = RTPathTemp(pszFilename, cbFilename);
248 if (RT_SUCCESS(rc))
249 {
250 /*
251 * Add a filename pattern.
252 */
253 static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp";
254 rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate);
255 if (RT_SUCCESS(rc))
256 {
257 char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5;
258 unsigned cXes = sizeof(s_szTemplate) - 1 - 4 - 5;
259 Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.');
260
261 /*
262 * Try 10000 times with random names.
263 */
264 unsigned cTriesLeft = 10000;
265 while (cTriesLeft-- > 0)
266 {
267 rtCreateTempFillTemplate(pszX, cXes);
268 rc = RTFileOpen(phFile, pszFilename, fOpen);
269 if (RT_SUCCESS(rc))
270 return rc;
271 }
272 }
273 }
274
275 if (cbFilename)
276 *pszFilename = '\0';
277 *phFile = NIL_RTFILE;
278 return rc;
279}
280RT_EXPORT_SYMBOL(RTFileOpenTemp);
281
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette