Reformated comments and long lines
[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,opt.) File descriptor to temp file. */
47         FILE **fp_ret        /* (return,opt.) 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",
57                                 get_temp_dir());
58         } else {
59                 snprintf(tmpfil, sizeof(tmpfil), "%sXXXXXX", pfx_in);
60         }
61
62         fd = mkstemp(tmpfil);
63         if (fd < 0) {
64                 umask(oldmode);
65                 return NULL;
66         }
67         if (fd_ret != NULL) {
68                 *fd_ret = fd;
69                 keep_open = 1;
70         }
71         if (fp_ret != NULL) {
72                 FILE *fp = fdopen(fd, "w+");
73                 if (fp == NULL) {
74                         int olderr = errno;
75                         unlink(tmpfil);
76                         close(fd);
77                         errno = olderr;
78                         umask(oldmode);
79                         return NULL;
80                 }
81                 *fp_ret = fp;
82                 keep_open = 1;
83         }
84         if (!keep_open) {
85                 close(fd);
86         }
87         umask(oldmode);
88         return tmpfil;
89 }
90
91 /*
92 ** This version allows one to specify the directory the temp file should
93 ** by created based on a given pathname.  Although m_mktemp() technically
94 ** supports this, this version is when the directory is defined by
95 ** a separate variable from the prefix, eliminating the caller from having
96 ** to do string manipulation to generate the desired. pathname prefix.
97 **
98 ** The pfx_in parameter specifies a basename prefix for the file.  If dir_in
99 ** is NULL, then the defined temporary directory (see comments to m_mktemp()
100 ** above) is used to create the temp file.
101 */
102 char *
103 m_mktemp2 (
104         const char *dir_in,   /* Directory to place temp file. */
105         const char *pfx_in,   /* Basename prefix for temp file. */
106         int *fd_ret,          /* (return,opt.) File descriptor to temp file. */
107         FILE **fp_ret         /* (return,opt.) FILE pointer to temp file. */
108 )
109 {
110         static char buffer[BUFSIZ];
111         char *cp;
112         int n;
113
114         if (dir_in == NULL) {
115                 if (pfx_in == NULL) {
116                         return m_mktemp(NULL, fd_ret, fp_ret);
117                 }
118                 snprintf(buffer, sizeof(buffer), "%s/%s", get_temp_dir(), pfx_in);
119                 return m_mktemp(buffer, fd_ret, fp_ret);
120         }
121
122         if ((cp = r1bindex ((char *)dir_in, '/')) == dir_in) {
123                 /* No directory component */
124                 return m_mktemp(pfx_in, fd_ret, fp_ret);
125         }
126         n = (int)(cp-dir_in-1); /* Length of dir component */
127         snprintf(buffer, sizeof(buffer), "%.*s%s", n, dir_in, pfx_in);
128         return m_mktemp(buffer, fd_ret, fp_ret);
129 }
130
131
132 static char *
133 get_temp_dir()
134 {
135         /* Ignore envvars if we are setuid */
136         if ((getuid()==geteuid()) && (getgid()==getegid())) {
137                 char *tmpdir = NULL;
138                 tmpdir = getenv("MHTMPDIR");
139                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
140
141                 tmpdir = getenv("TMPDIR");
142                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
143
144                 tmpdir = getenv("TMP");
145                 if (tmpdir != NULL && *tmpdir != '\0') return tmpdir;
146         }
147         return m_maildir("");
148 }