Commit | Line | Data |
---|---|---|
184e8823 | 1 | /* $Cambridge: exim/src/src/directory.c,v 1.5 2007/01/08 10:50:18 ph10 Exp $ */ |
059ec3d9 PH |
2 | |
3 | /************************************************* | |
4 | * Exim - an Internet mail transport agent * | |
5 | *************************************************/ | |
6 | ||
184e8823 | 7 | /* Copyright (c) University of Cambridge 1995 - 2007 */ |
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 | |
39 | directory_make(uschar *parent, uschar *name, int mode, BOOL panic) | |
40 | { | |
41 | BOOL use_chown = parent == spool_directory && geteuid() == root_uid; | |
42 | uschar *p, *slash; | |
43 | int c = 1; | |
44 | struct stat statbuf; | |
45 | uschar buffer[256]; | |
46 | ||
47 | if (parent == NULL) | |
48 | { | |
49 | p = buffer + 1; | |
50 | slash = parent = US""; | |
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 */ |