1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12
13 #include "android/utils/tempfile.h"
14 #include "android/utils/bufprint.h"
15 #include "android/utils/debug.h"
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <fcntl.h>
20
21 #ifdef _WIN32
22 # define WIN32_LEAN_AND_MEAN
23 # include <windows.h>
24 #else
25 # include <unistd.h>
26 #endif
27
28 #define D(...) ((void)0)
29
30 /** TEMP FILE SUPPORT
31 **
32 ** simple interface to create an empty temporary file on the system.
33 **
34 ** create the file with tempfile_create(), which returns a reference to a TempFile
35 ** object, or NULL if your system is so weird it doesn't have a temporary directory.
36 **
37 ** you can then call tempfile_path() to retrieve the TempFile's real path to open
38 ** it. the returned path is owned by the TempFile object and should not be freed.
39 **
40 ** all temporary files are destroyed when the program quits, unless you explicitely
41 ** close them before that with tempfile_close()
42 **/
43
44 struct TempFile
45 {
46 const char* name;
47 TempFile* next;
48 };
49
50 static void tempfile_atexit();
51 static TempFile* _all_tempfiles;
52
53 TempFile*
tempfile_create(void)54 tempfile_create( void )
55 {
56 TempFile* tempfile;
57 const char* tempname = NULL;
58
59 #ifdef _WIN32
60 char temp_namebuff[MAX_PATH];
61 char temp_dir[MAX_PATH];
62 char *p = temp_dir, *end = p + sizeof(temp_dir);
63 UINT retval;
64
65 p = bufprint_temp_dir( p, end );
66 if (p >= end) {
67 D( "TEMP directory path is too long" );
68 return NULL;
69 }
70
71 retval = GetTempFileName(temp_dir, "TMP", 0, temp_namebuff);
72 if (retval == 0) {
73 D( "can't create temporary file in '%s'", temp_dir );
74 return NULL;
75 }
76
77 tempname = temp_namebuff;
78 #else
79 #define TEMPLATE "/tmp/.android-emulator-XXXXXX"
80 int tempfd = -1;
81 char template[512];
82 char *p = template, *end = p + sizeof(template);
83
84 p = bufprint_temp_file( p, end, "emulator-XXXXXX" );
85 if (p >= end) {
86 D( "Xcannot create temporary file in /tmp/android !!" );
87 return NULL;
88 }
89
90 D( "template: %s", template );
91 tempfd = mkstemp( template );
92 if (tempfd < 0) {
93 D("cannot create temporary file in /tmp/android !!");
94 return NULL;
95 }
96 close(tempfd);
97 tempname = template;
98 #endif
99 tempfile = malloc( sizeof(*tempfile) + strlen(tempname) + 1 );
100 tempfile->name = (char*)(tempfile + 1);
101 strcpy( (char*)tempfile->name, tempname );
102
103 tempfile->next = _all_tempfiles;
104 _all_tempfiles = tempfile;
105
106 if ( !tempfile->next ) {
107 atexit( tempfile_atexit );
108 }
109
110 return tempfile;
111 }
112
113 const char*
tempfile_path(TempFile * temp)114 tempfile_path(TempFile* temp)
115 {
116 return temp ? temp->name : NULL;
117 }
118
119 void
tempfile_close(TempFile * tempfile)120 tempfile_close(TempFile* tempfile)
121 {
122 #ifdef _WIN32
123 DeleteFile(tempfile->name);
124 #else
125 unlink(tempfile->name);
126 #endif
127 }
128
129 /** TEMP FILE CLEANUP
130 **
131 **/
132
133 /* we don't expect to use many temporary files */
134 #define MAX_ATEXIT_FDS 16
135
136 typedef struct {
137 int count;
138 int fds[ MAX_ATEXIT_FDS ];
139 } AtExitFds;
140
141 static void
atexit_fds_add(AtExitFds * t,int fd)142 atexit_fds_add( AtExitFds* t, int fd )
143 {
144 if (t->count < MAX_ATEXIT_FDS)
145 t->fds[t->count++] = fd;
146 else {
147 dwarning("%s: over %d calls. Program exit may not cleanup all temporary files",
148 __FUNCTION__, MAX_ATEXIT_FDS);
149 }
150 }
151
152 static void
atexit_fds_del(AtExitFds * t,int fd)153 atexit_fds_del( AtExitFds* t, int fd )
154 {
155 int nn;
156 for (nn = 0; nn < t->count; nn++)
157 if (t->fds[nn] == fd) {
158 /* move the last element to the current position */
159 t->count -= 1;
160 t->fds[nn] = t->fds[t->count];
161 break;
162 }
163 }
164
165 static void
atexit_fds_close_all(AtExitFds * t)166 atexit_fds_close_all( AtExitFds* t )
167 {
168 int nn;
169 for (nn = 0; nn < t->count; nn++)
170 close(t->fds[nn]);
171 }
172
173 static AtExitFds _atexit_fds[1];
174
175 void
atexit_close_fd(int fd)176 atexit_close_fd(int fd)
177 {
178 if (fd >= 0)
179 atexit_fds_add(_atexit_fds, fd);
180 }
181
182 void
atexit_close_fd_remove(int fd)183 atexit_close_fd_remove(int fd)
184 {
185 if (fd >= 0)
186 atexit_fds_del(_atexit_fds, fd);
187 }
188
189 static void
tempfile_atexit(void)190 tempfile_atexit( void )
191 {
192 TempFile* tempfile;
193
194 atexit_fds_close_all( _atexit_fds );
195
196 for (tempfile = _all_tempfiles; tempfile; tempfile = tempfile->next)
197 tempfile_close(tempfile);
198 }
199