Commit | Line | Data |
---|---|---|
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 | |
18 | directory as defined by spool_directory. We are prepared to create as many as | |
19 | necessary from that directory downwards, inclusive. However, directory creation | |
20 | can also be required in appendfile and sieve filters. The making function | |
21 | therefore has a parent argument, below which the new directories are to go. It | |
22 | can be NULL if the name is absolute. | |
23 | ||
24 | If a non-root uid has been specified for exim, and we are currently running as | |
25 | root, ensure the directory is owned by the non-root id if the parent is the | |
26 | spool directory. | |
27 | ||
28 | Arguments: | |
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 | ||
34 | Returns: panic on failure if panic is set; otherwise return FALSE; | |
35 | TRUE on success. | |
36 | */ | |
37 | ||
38 | BOOL | |
1ba28e2b PP |
39 | directory_make(const uschar *parent, const uschar *name, |
40 | int mode, BOOL panic) | |
059ec3d9 PH |
41 | { |
42 | BOOL use_chown = parent == spool_directory && geteuid() == root_uid; | |
1ba28e2b PP |
43 | uschar *p; |
44 | const uschar *slash; | |
059ec3d9 PH |
45 | int c = 1; |
46 | struct stat statbuf; | |
47 | uschar buffer[256]; | |
48 | ||
49 | if (parent == NULL) | |
50 | { | |
51 | p = buffer + 1; | |
1ba28e2b | 52 | slash = parent = CUS""; |
059ec3d9 PH |
53 | } |
54 | else | |
55 | { | |
56 | p = buffer + Ustrlen(parent); | |
57 | slash = US"/"; | |
58 | } | |
59 | ||
60 | if (!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 | ||
63 | while (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 | ||
90 | return TRUE; | |
91 | } | |
92 | ||
93 | /* End of directory.c */ |