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 44struct TempFile 45{ 46 const char* name; 47 TempFile* next; 48}; 49 50static void tempfile_atexit(); 51static TempFile* _all_tempfiles; 52 53TempFile* 54tempfile_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 113const char* 114tempfile_path(TempFile* temp) 115{ 116 return temp ? temp->name : NULL; 117} 118 119void 120tempfile_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 136typedef struct { 137 int count; 138 int fds[ MAX_ATEXIT_FDS ]; 139} AtExitFds; 140 141static void 142atexit_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 152static void 153atexit_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 165static void 166atexit_fds_close_all( AtExitFds* t ) 167{ 168 int nn; 169 for (nn = 0; nn < t->count; nn++) 170 close(t->fds[nn]); 171} 172 173static AtExitFds _atexit_fds[1]; 174 175void 176atexit_close_fd(int fd) 177{ 178 if (fd >= 0) 179 atexit_fds_add(_atexit_fds, fd); 180} 181 182void 183atexit_close_fd_remove(int fd) 184{ 185 if (fd >= 0) 186 atexit_fds_del(_atexit_fds, fd); 187} 188 189static void 190tempfile_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