6f2089ba4509495a789920a850de12c596852c77
[mmh] / sbr / m_mktemp.c
1 /*
2  * m_mktemp.c -- Construct a temporary file.
3  *
4  * This code is Copyright (c) 2010, by the authors of nmh.  See the
5  * COPYRIGHT file in the root directory of the nmh distribution for
6  * complete copyright information.
7  */
8
9 #include <errno.h>
10 #include <h/mh.h>
11
12 static char *get_temp_dir();
13
14 /*  Create a temporary file.  If pfx_in is null, the temporary file
15  *  will be created in the temporary directory (more on that later).
16  *  If pfx_in is not null, then the temporary file location will be
17  *  defined by the value pfx_in.
18  *
19  *  The file created will be at the pathname specified appended with
20  *  6 random (we hope :) characters.
21  *
22  *  The return value will be the pathname to the file created.
23  *
24  *  CAUTION: The return pointer references static data.  If
25  *  you need to modify, or save, the return string, make a copy of it
26  *  first.
27  *
28  *  When pfx_in is null, the temporary directory is determined as
29  *  follows, in order:
30  *
31  *    MHTMPDIR envvar
32  *    TMPDIR envvar
33  *    TMP envvar
34  *    User's mail directory.
35  *
36  *  NOTE: One will probably use m_mktemp2() instead of this function.
37  *  For example, if you want to create a temp file in the defined
38  *  temporary directory, but with a custom basename prefix, do
39  *  something like the following:
40  *
41  *    char *tmp_pathname = m_mktemp2(NULL, "mypre", ...);
42  */
43 char *
44 m_mktemp (
45         const char *pfx_in,  /* Pathname prefix for temporary file. */
46         int *fd_ret,         /* (return,optional) File descriptor to temp file. */
47         FILE **fp_ret        /* (return,optional) FILE pointer to temp file. */
48 )
49 {
50         static char tmpfil[BUFSIZ];
51         int fd = -1;
52         int keep_open = 0;
53         mode_t oldmode = umask(077);
54
55         if (pfx_in == NULL) {
56                 snprintf(tmpfil, sizeof(tmpfil), "%s/nmhXXXXXX", get_temp_dir());
57         } else {
58                 snprintf(tmpfil, sizeof(tmpfil), "%sXXXXXX", pfx_in);
59         }
60
61         fd = mkstemp(tmpfil);
62         if (fd < 0) {
63                 umask(oldmode);
64                 return NULL;
65         }
66         if (fd_ret != NULL) {
67                 *fd_ret = fd;
68                 keep_open = 1;
69         }
70         if (fp_ret != NULL) {
71                 FILE *fp = fdopen(fd, "w+");
72                 if (fp == NULL) {
73                         int olderr = errno;
74                         unlink(tmpfil);
75                         close(fd);
76                         errno = olderr;
77                         umask(oldmode);
78                         return NULL;
79                 }
80                 *fp_ret = fp;
81                 keep_open = 1;
82         }
83         if (!keep_open) {
84                 close(fd);
85         }
86         umask(oldmode);
87         return tmpfil;
88 }
89
90 /* This version allows one to specify the directory the temp file should
91  * by created based on a given pathname.  Although m_mktemp() technically
92  * supports this, this version is when the directory is defined by
93  * a separate variable from the prefix, eliminating the caller from having
94  * to do string manipulation to generate the desired. pathname prefix.
95  *
96  * The pfx_in parameter specifies a basename prefix for the file.  If dir_in
97  * is NULL, then the defined temporary directory (see comments to m_mktemp()
98  * above) is used to create the temp file.
99  */
100 char *
101 m_mktemp2 (
102         const char *dir_in,   /* Directory to place temp file. */
103         const char *pfx_in,   /* Basename prefix for temp file. */
104         int *fd_ret,          /* (return,optional) File descriptor to temp file. */
105         FILE **fp_ret         /* (return,optional) FILE pointer to temp file. */
106 )
107 {
108         static char buffer[BUFSIZ];
109         char *cp;
110         int n;
111
112         if (dir_in == NULL) {
113                 if (pfx_in == NULL) {
114                         return m_mktemp(NULL, fd_ret, fp_ret);
115                 }
116                 snprintf(buffer, sizeof(buffer), "%s/%s", get_temp_dir(), pfx_in);
117                 return m_mktemp(buffer, fd_ret, fp_ret);
118         }
119
120         if ((cp = r1bindex ((char *)dir_in, '/')) == dir_in) {
121                 /* No directory component */
122                 return m_mktemp(pfx_in, fd_ret, fp_ret);
123         }
124         n = (int)(cp-dir_in-1); /* Length of dir component */
125         snprintf(buffer, sizeof(buffer), "%.*s%s", n, dir_in, pfx_in);
126         return m_mktemp(buffer, fd_ret, fp_ret);
127 }
128
129
130 static char *
131 get_temp_dir()
132 {
133         // Ignore envvars if we are setuid
134         if ((getuid()==geteuid()) && (getgid()==getegid())) {
135                 char *tmpdir = NULL;
136                 tmpdir = getenv("MHTMPDIR");
137                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
138
139                 tmpdir = getenv("TMPDIR");
140                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
141
142                 tmpdir = getenv("TMP");
143                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
144         }
145         return m_maildir("");
146 }