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* 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* 114 tempfile_path(TempFile* temp) 115 { 116 return temp ? temp->name : NULL; 117 } 118 119 void 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 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 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 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 176 atexit_close_fd(int fd) 177 { 178 if (fd >= 0) 179 atexit_fds_add(_atexit_fds, fd); 180 } 181 182 void 183 atexit_close_fd_remove(int fd) 184 { 185 if (fd >= 0) 186 atexit_fds_del(_atexit_fds, fd); 187 } 188 189 static 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