tmpfile.cpp revision 91875dcd6e17b7f3b251efe9b236b905ef414dde
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*-
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (c) 1990, 1993
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	The Regents of the University of California.  All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This code is derived from software contributed to Berkeley by
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Chris Torek.
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    documentation and/or other materials provided with the distribution.
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 3. Neither the name of the University nor the names of its contributors
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    may be used to endorse or promote products derived from this software
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    without specific prior written permission.
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
3491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes#include <signal.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
3791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes#include <sys/stat.h>
3891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes#include <sys/types.h>
3991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes#include <unistd.h>
4091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
4191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughesclass ScopedSignalBlocker {
4291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes public:
4391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  ScopedSignalBlocker() {
4491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigset_t set;
4591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigfillset(&set);
4691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigprocmask(SIG_BLOCK, &set, &old_set_);
4791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
4891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
4991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  ~ScopedSignalBlocker() {
5091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigprocmask(SIG_SETMASK, &old_set_, NULL);
5191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes private:
5491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  sigset_t old_set_;
5591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes};
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughesstatic FILE* __tmpfile_dir(const char* tmp_dir) {
5891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  char buf[PATH_MAX];
5991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int path_length = snprintf(buf, sizeof(buf), "%s/tmp.XXXXXXXXXX", tmp_dir);
6091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (path_length >= sizeof(buf)) {
6191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return NULL;
6291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int fd;
6591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  {
6691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    ScopedSignalBlocker ssb;
6791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    fd = mkstemp(buf);
6891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (fd == -1) {
6991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
7091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Unlink the file now so that it's removed when closed.
7391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    unlink(buf);
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Can we still use the file now it's unlinked?
7691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // File systems without hard link support won't have the usual Unix semantics.
7791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    struct stat sb;
7891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    int rc = fstat(fd, &sb);
7991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (rc == -1) {
8091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      int old_errno = errno;
8191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      close(fd);
8291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      errno = old_errno;
8391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
8491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
8591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
8691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
8791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Turn the file descriptor into a FILE*.
8891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  FILE* fp = fdopen(fd, "w+");
8991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (fp != NULL) {
9091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return fp;
9191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
9291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
9391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Failure. Clean up. We already unlinked, so we just need to close.
9491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int old_errno = errno;
9591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  close(fd);
9691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  errno = old_errno;
9791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  return NULL;
9891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes}
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott HughesFILE* tmpfile() {
10191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // TODO: get this app's temporary directory from the framework ("/data/data/app/cache").
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // $EXTERNAL_STORAGE turns out not to be very useful because it doesn't support hard links.
10491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // This means we can't do the usual trick of calling unlink before handing the file back.
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  FILE* fp = __tmpfile_dir("/data/local/tmp");
10791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (fp == NULL) {
10891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // P_tmpdir is "/tmp/", but POSIX explicitly says that tmpdir(3) should try P_tmpdir before
10991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // giving up. This is potentially useful for bionic on the host anyway.
11091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    fp = __tmpfile_dir(P_tmpdir);
11191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
11291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  return fp;
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
114