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