Compiler masochism compliance.
[exim.git] / src / src / directory.c
CommitLineData
0a49a7a4 1/* $Cambridge: exim/src/src/directory.c,v 1.6 2009/11/16 19:50:36 nm4 Exp $ */
059ec3d9
PH
2
3/*************************************************
4* Exim - an Internet mail transport agent *
5*************************************************/
6
0a49a7a4 7/* Copyright (c) University of Cambridge 1995 - 2009 */
059ec3d9
PH
8/* See the file NOTICE for conditions of use and distribution. */
9
10#include "exim.h"
11
12
13/*************************************************
14* Attempt to create a directory *
15*************************************************/
16
17/* All the directories that Exim ever creates for itself are within the spool
18directory as defined by spool_directory. We are prepared to create as many as
19necessary from that directory downwards, inclusive. However, directory creation
20can also be required in appendfile and sieve filters. The making function
21therefore has a parent argument, below which the new directories are to go. It
22can be NULL if the name is absolute.
23
24If a non-root uid has been specified for exim, and we are currently running as
25root, ensure the directory is owned by the non-root id if the parent is the
26spool directory.
27
28Arguments:
29 parent parent directory name; if NULL the name must be absolute
30 name directory name within the parent that we want
31 mode mode for the new directory
32 panic if TRUE, panic on failure
33
34Returns: panic on failure if panic is set; otherwise return FALSE;
35 TRUE on success.
36*/
37
38BOOL
1ba28e2b
PP
39directory_make(const uschar *parent, const uschar *name,
40 int mode, BOOL panic)
059ec3d9
PH
41{
42BOOL use_chown = parent == spool_directory && geteuid() == root_uid;
1ba28e2b
PP
43uschar *p;
44const uschar *slash;
059ec3d9
PH
45int c = 1;
46struct stat statbuf;
47uschar buffer[256];
48
49if (parent == NULL)
50 {
51 p = buffer + 1;
1ba28e2b 52 slash = parent = CUS"";
059ec3d9
PH
53 }
54else
55 {
56 p = buffer + Ustrlen(parent);
57 slash = US"/";
58 }
59
60if (!string_format(buffer, sizeof(buffer), "%s%s%s", parent, slash, name))
61 log_write(0, LOG_MAIN|LOG_PANIC_DIE, "name too long in directory_make");
62
63while (c != 0 && *p != 0)
64 {
65 while (*p != 0 && *p != '/') p++;
66 c = *p;
67 *p = 0;
68 if (Ustat(buffer, &statbuf) != 0)
69 {
70 if (mkdir(CS buffer, mode) < 0 && errno != EEXIST)
71 {
72 if (!panic) return FALSE;
73 log_write(0, LOG_MAIN|LOG_PANIC_DIE,
74 "Failed to create directory \"%s\": %s\n", buffer, strerror(errno));
75 }
76
77 /* Set the ownership if necessary. */
78
ff790e47 79 if (use_chown) (void)Uchown(buffer, exim_uid, exim_gid);
059ec3d9
PH
80
81 /* It appears that any mode bits greater than 0777 are ignored by
82 mkdir(), at least on some operating systems. Therefore, if the mode
83 contains any such bits, do an explicit mode setting. */
84
ff790e47 85 if ((mode & 0777000) != 0) (void)Uchmod(buffer, mode);
059ec3d9
PH
86 }
87 *p++ = c;
88 }
89
90return TRUE;
91}
92
93/* End of directory.c */