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) {
60b6943186ce78105155ba67ab261a970859b190dfElliott Hughes  char* path = NULL;
61b6943186ce78105155ba67ab261a970859b190dfElliott Hughes  if (asprintf(&path, "%s/tmp.XXXXXXXXXX", tmp_dir) == -1) {
6291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return NULL;
6391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  int fd;
6691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  {
6791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    ScopedSignalBlocker ssb;
68b6943186ce78105155ba67ab261a970859b190dfElliott Hughes    fd = mkstemp(path);
6991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (fd == -1) {
70b6943186ce78105155ba67ab261a970859b190dfElliott Hughes      free(path);
7191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
7291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Unlink the file now so that it's removed when closed.
75b6943186ce78105155ba67ab261a970859b190dfElliott Hughes    unlink(path);
76b6943186ce78105155ba67ab261a970859b190dfElliott Hughes    free(path);
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // Can we still use the file now it's unlinked?
7991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // File systems without hard link support won't have the usual Unix semantics.
8091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    struct stat sb;
8191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    int rc = fstat(fd, &sb);
8291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    if (rc == -1) {
833e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes      ErrnoRestorer errno_restorer;
8491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      close(fd);
8591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes      return NULL;
8691875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    }
8791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
8891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
8991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Turn the file descriptor into a FILE*.
9091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  FILE* fp = fdopen(fd, "w+");
9191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (fp != NULL) {
9291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    return fp;
9391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
9491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes
9591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // Failure. Clean up. We already unlinked, so we just need to close.
963e898476c7230b60a0f76968e64ff25f475b48c0Elliott Hughes  ErrnoRestorer errno_restorer;
9791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  close(fd);
9891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  return NULL;
9991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes}
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott HughesFILE* tmpfile() {
10291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // TODO: get this app's temporary directory from the framework ("/data/data/app/cache").
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10491875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // $EXTERNAL_STORAGE turns out not to be very useful because it doesn't support hard links.
10591875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  // This means we can't do the usual trick of calling unlink before handing the file back.
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10791875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  FILE* fp = __tmpfile_dir("/data/local/tmp");
10891875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  if (fp == NULL) {
10991875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // P_tmpdir is "/tmp/", but POSIX explicitly says that tmpdir(3) should try P_tmpdir before
11091875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    // giving up. This is potentially useful for bionic on the host anyway.
11191875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes    fp = __tmpfile_dir(P_tmpdir);
11291875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  }
11391875dcd6e17b7f3b251efe9b236b905ef414ddeElliott Hughes  return fp;
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
115f226ee59e0effedeabed09e2d65be7fa7499cc25Elliott Hughes__strong_alias(tmpfile64, tmpfile);
116