tmpfile.cpp revision 3e898476c7230b60a0f76968e64ff25f475b48c0
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
413e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes#include "private/ErrnoRestorer.h"
423e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes
4391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughesclass ScopedSignalBlocker {
4491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes public:
4591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  ScopedSignalBlocker() {
4691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigset_t set;
4791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigfillset(&set);
4891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigprocmask(SIG_BLOCK, &set, &old_set_);
4991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
5091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
5191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  ~ScopedSignalBlocker() {
5291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    sigprocmask(SIG_SETMASK, &old_set_, NULL);
5391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes private:
5691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  sigset_t old_set_;
5791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes};
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughesstatic FILE* __tmpfile_dir(const char* tmp_dir) {
6091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  char buf[PATH_MAX];
6191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int path_length = snprintf(buf, sizeof(buf), "%s/tmp.XXXXXXXXXX", tmp_dir);
62ac184b21425a0681c51ef152f0567168b575da49Elliott Hughes  if (path_length >= static_cast<int>(sizeof(buf))) {
6391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return NULL;
6491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int fd;
6791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  {
6891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    ScopedSignalBlocker ssb;
6991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    fd = mkstemp(buf);
7091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (fd == -1) {
7191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
7291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Unlink the file now so that it's removed when closed.
7591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    unlink(buf);
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Can we still use the file now it's unlinked?
7891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // File systems without hard link support won't have the usual Unix semantics.
7991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    struct stat sb;
8091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    int rc = fstat(fd, &sb);
8191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (rc == -1) {
823e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes      ErrnoRestorer errno_restorer;
8391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      close(fd);
8491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
8591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
8691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
8791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
8891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Turn the file descriptor into a FILE*.
8991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  FILE* fp = fdopen(fd, "w+");
9091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (fp != NULL) {
9191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return fp;
9291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
9391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
9491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Failure. Clean up. We already unlinked, so we just need to close.
953e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes  ErrnoRestorer errno_restorer;
9691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  close(fd);
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