| /* Copyright (C) 2007-2008 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| |
| #include "android/utils/tempfile.h" |
| #include "android/utils/bufprint.h" |
| #include "android/utils/debug.h" |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| |
| #ifdef _WIN32 |
| # define WIN32_LEAN_AND_MEAN |
| # include <windows.h> |
| #else |
| # include <unistd.h> |
| #endif |
| |
| #define D(...) ((void)0) |
| |
| /** TEMP FILE SUPPORT |
| ** |
| ** simple interface to create an empty temporary file on the system. |
| ** |
| ** create the file with tempfile_create(), which returns a reference to a TempFile |
| ** object, or NULL if your system is so weird it doesn't have a temporary directory. |
| ** |
| ** you can then call tempfile_path() to retrieve the TempFile's real path to open |
| ** it. the returned path is owned by the TempFile object and should not be freed. |
| ** |
| ** all temporary files are destroyed when the program quits, unless you explicitely |
| ** close them before that with tempfile_close() |
| **/ |
| |
| struct TempFile |
| { |
| const char* name; |
| TempFile* next; |
| }; |
| |
| static void tempfile_atexit(); |
| static TempFile* _all_tempfiles; |
| |
| TempFile* |
| tempfile_create( void ) |
| { |
| TempFile* tempfile; |
| const char* tempname = NULL; |
| |
| #ifdef _WIN32 |
| char temp_namebuff[MAX_PATH]; |
| char temp_dir[MAX_PATH]; |
| char *p = temp_dir, *end = p + sizeof(temp_dir); |
| UINT retval; |
| |
| p = bufprint_temp_dir( p, end ); |
| if (p >= end) { |
| D( "TEMP directory path is too long" ); |
| return NULL; |
| } |
| |
| retval = GetTempFileName(temp_dir, "TMP", 0, temp_namebuff); |
| if (retval == 0) { |
| D( "can't create temporary file in '%s'", temp_dir ); |
| return NULL; |
| } |
| |
| tempname = temp_namebuff; |
| #else |
| #define TEMPLATE "/tmp/.android-emulator-XXXXXX" |
| int tempfd = -1; |
| char template[512]; |
| char *p = template, *end = p + sizeof(template); |
| |
| p = bufprint_temp_file( p, end, "emulator-XXXXXX" ); |
| if (p >= end) { |
| D( "Xcannot create temporary file in /tmp/android !!" ); |
| return NULL; |
| } |
| |
| D( "template: %s", template ); |
| tempfd = mkstemp( template ); |
| if (tempfd < 0) { |
| D("cannot create temporary file in /tmp/android !!"); |
| return NULL; |
| } |
| close(tempfd); |
| tempname = template; |
| #endif |
| tempfile = malloc( sizeof(*tempfile) + strlen(tempname) + 1 ); |
| tempfile->name = (char*)(tempfile + 1); |
| strcpy( (char*)tempfile->name, tempname ); |
| |
| tempfile->next = _all_tempfiles; |
| _all_tempfiles = tempfile; |
| |
| if ( !tempfile->next ) { |
| atexit( tempfile_atexit ); |
| } |
| |
| return tempfile; |
| } |
| |
| const char* |
| tempfile_path(TempFile* temp) |
| { |
| return temp ? temp->name : NULL; |
| } |
| |
| void |
| tempfile_close(TempFile* tempfile) |
| { |
| #ifdef _WIN32 |
| DeleteFile(tempfile->name); |
| #else |
| unlink(tempfile->name); |
| #endif |
| } |
| |
| /** TEMP FILE CLEANUP |
| ** |
| **/ |
| |
| /* we don't expect to use many temporary files */ |
| #define MAX_ATEXIT_FDS 16 |
| |
| typedef struct { |
| int count; |
| int fds[ MAX_ATEXIT_FDS ]; |
| } AtExitFds; |
| |
| static void |
| atexit_fds_add( AtExitFds* t, int fd ) |
| { |
| if (t->count < MAX_ATEXIT_FDS) |
| t->fds[t->count++] = fd; |
| else { |
| dwarning("%s: over %d calls. Program exit may not cleanup all temporary files", |
| __FUNCTION__, MAX_ATEXIT_FDS); |
| } |
| } |
| |
| static void |
| atexit_fds_del( AtExitFds* t, int fd ) |
| { |
| int nn; |
| for (nn = 0; nn < t->count; nn++) |
| if (t->fds[nn] == fd) { |
| /* move the last element to the current position */ |
| t->count -= 1; |
| t->fds[nn] = t->fds[t->count]; |
| break; |
| } |
| } |
| |
| static void |
| atexit_fds_close_all( AtExitFds* t ) |
| { |
| int nn; |
| for (nn = 0; nn < t->count; nn++) |
| close(t->fds[nn]); |
| } |
| |
| static AtExitFds _atexit_fds[1]; |
| |
| void |
| atexit_close_fd(int fd) |
| { |
| if (fd >= 0) |
| atexit_fds_add(_atexit_fds, fd); |
| } |
| |
| void |
| atexit_close_fd_remove(int fd) |
| { |
| if (fd >= 0) |
| atexit_fds_del(_atexit_fds, fd); |
| } |
| |
| static void |
| tempfile_atexit( void ) |
| { |
| TempFile* tempfile; |
| |
| atexit_fds_close_all( _atexit_fds ); |
| |
| for (tempfile = _all_tempfiles; tempfile; tempfile = tempfile->next) |
| tempfile_close(tempfile); |
| } |