Home | History | Annotate | Download | only in utils
      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