• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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