1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_test_full_name(ngx_str_t *name);
13e18a033bSKonstantin Ananyev
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyevstatic ngx_atomic_t   temp_number = 0;
16e18a033bSKonstantin Ananyevngx_atomic_t         *ngx_temp_number = &temp_number;
17e18a033bSKonstantin Ananyevngx_atomic_int_t      ngx_random_number = 123456;
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyevngx_int_t
21e18a033bSKonstantin Ananyevngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name)
22e18a033bSKonstantin Ananyev{
23e18a033bSKonstantin Ananyev    size_t      len;
24e18a033bSKonstantin Ananyev    u_char     *p, *n;
25e18a033bSKonstantin Ananyev    ngx_int_t   rc;
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev    rc = ngx_test_full_name(name);
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyev    if (rc == NGX_OK) {
30e18a033bSKonstantin Ananyev        return rc;
31e18a033bSKonstantin Ananyev    }
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyev    len = prefix->len;
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev#if (NGX_WIN32)
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyev    if (rc == 2) {
38e18a033bSKonstantin Ananyev        len = rc;
39e18a033bSKonstantin Ananyev    }
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyev#endif
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyev    n = ngx_pnalloc(pool, len + name->len + 1);
44e18a033bSKonstantin Ananyev    if (n == NULL) {
45e18a033bSKonstantin Ananyev        return NGX_ERROR;
46e18a033bSKonstantin Ananyev    }
47e18a033bSKonstantin Ananyev
48e18a033bSKonstantin Ananyev    p = ngx_cpymem(n, prefix->data, len);
49e18a033bSKonstantin Ananyev    ngx_cpystrn(p, name->data, name->len + 1);
50e18a033bSKonstantin Ananyev
51e18a033bSKonstantin Ananyev    name->len += len;
52e18a033bSKonstantin Ananyev    name->data = n;
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev    return NGX_OK;
55e18a033bSKonstantin Ananyev}
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevstatic ngx_int_t
59e18a033bSKonstantin Ananyevngx_test_full_name(ngx_str_t *name)
60e18a033bSKonstantin Ananyev{
61e18a033bSKonstantin Ananyev#if (NGX_WIN32)
62e18a033bSKonstantin Ananyev    u_char  c0, c1;
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyev    c0 = name->data[0];
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev    if (name->len < 2) {
67e18a033bSKonstantin Ananyev        if (c0 == '/') {
68e18a033bSKonstantin Ananyev            return 2;
69e18a033bSKonstantin Ananyev        }
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyev        return NGX_DECLINED;
72e18a033bSKonstantin Ananyev    }
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyev    c1 = name->data[1];
75e18a033bSKonstantin Ananyev
76e18a033bSKonstantin Ananyev    if (c1 == ':') {
77e18a033bSKonstantin Ananyev        c0 |= 0x20;
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyev        if ((c0 >= 'a' && c0 <= 'z')) {
80e18a033bSKonstantin Ananyev            return NGX_OK;
81e18a033bSKonstantin Ananyev        }
82e18a033bSKonstantin Ananyev
83e18a033bSKonstantin Ananyev        return NGX_DECLINED;
84e18a033bSKonstantin Ananyev    }
85e18a033bSKonstantin Ananyev
86e18a033bSKonstantin Ananyev    if (c1 == '/') {
87e18a033bSKonstantin Ananyev        return NGX_OK;
88e18a033bSKonstantin Ananyev    }
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev    if (c0 == '/') {
91e18a033bSKonstantin Ananyev        return 2;
92e18a033bSKonstantin Ananyev    }
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev    return NGX_DECLINED;
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev#else
97e18a033bSKonstantin Ananyev
98e18a033bSKonstantin Ananyev    if (name->data[0] == '/') {
99e18a033bSKonstantin Ananyev        return NGX_OK;
100e18a033bSKonstantin Ananyev    }
101e18a033bSKonstantin Ananyev
102e18a033bSKonstantin Ananyev    return NGX_DECLINED;
103e18a033bSKonstantin Ananyev
104e18a033bSKonstantin Ananyev#endif
105e18a033bSKonstantin Ananyev}
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyevssize_t
109e18a033bSKonstantin Ananyevngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
110e18a033bSKonstantin Ananyev{
111e18a033bSKonstantin Ananyev    ngx_int_t  rc;
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    if (tf->file.fd == NGX_INVALID_FILE) {
114e18a033bSKonstantin Ananyev        rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
115e18a033bSKonstantin Ananyev                                  tf->persistent, tf->clean, tf->access);
116e18a033bSKonstantin Ananyev
117e18a033bSKonstantin Ananyev        if (rc != NGX_OK) {
118e18a033bSKonstantin Ananyev            return rc;
119e18a033bSKonstantin Ananyev        }
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev        if (tf->log_level) {
122e18a033bSKonstantin Ananyev            ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
123e18a033bSKonstantin Ananyev                          tf->warn, &tf->file.name);
124e18a033bSKonstantin Ananyev        }
125e18a033bSKonstantin Ananyev    }
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev#if (NGX_THREADS && NGX_HAVE_PWRITEV)
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    if (tf->thread_write) {
130e18a033bSKonstantin Ananyev        return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset,
131e18a033bSKonstantin Ananyev                                              tf->pool);
132e18a033bSKonstantin Ananyev    }
133e18a033bSKonstantin Ananyev
134e18a033bSKonstantin Ananyev#endif
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev    return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
137e18a033bSKonstantin Ananyev}
138e18a033bSKonstantin Ananyev
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyevngx_int_t
141e18a033bSKonstantin Ananyevngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
142e18a033bSKonstantin Ananyev    ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
143e18a033bSKonstantin Ananyev{
144e18a033bSKonstantin Ananyev    size_t                    levels;
145e18a033bSKonstantin Ananyev    u_char                   *p;
146e18a033bSKonstantin Ananyev    uint32_t                  n;
147e18a033bSKonstantin Ananyev    ngx_err_t                 err;
148e18a033bSKonstantin Ananyev    ngx_str_t                 name;
149e18a033bSKonstantin Ananyev    ngx_uint_t                prefix;
150e18a033bSKonstantin Ananyev    ngx_pool_cleanup_t       *cln;
151e18a033bSKonstantin Ananyev    ngx_pool_cleanup_file_t  *clnf;
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev    if (file->name.len) {
154e18a033bSKonstantin Ananyev        name = file->name;
155e18a033bSKonstantin Ananyev        levels = 0;
156e18a033bSKonstantin Ananyev        prefix = 1;
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev    } else {
159e18a033bSKonstantin Ananyev        name = path->name;
160e18a033bSKonstantin Ananyev        levels = path->len;
161e18a033bSKonstantin Ananyev        prefix = 0;
162e18a033bSKonstantin Ananyev    }
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    file->name.len = name.len + 1 + levels + 10;
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    file->name.data = ngx_pnalloc(pool, file->name.len + 1);
167e18a033bSKonstantin Ananyev    if (file->name.data == NULL) {
168e18a033bSKonstantin Ananyev        return NGX_ERROR;
169e18a033bSKonstantin Ananyev    }
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyev#if 0
172e18a033bSKonstantin Ananyev    for (i = 0; i < file->name.len; i++) {
173e18a033bSKonstantin Ananyev        file->name.data[i] = 'X';
174e18a033bSKonstantin Ananyev    }
175e18a033bSKonstantin Ananyev#endif
176e18a033bSKonstantin Ananyev
177e18a033bSKonstantin Ananyev    p = ngx_cpymem(file->name.data, name.data, name.len);
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    if (prefix) {
180e18a033bSKonstantin Ananyev        *p = '.';
181e18a033bSKonstantin Ananyev    }
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    p += 1 + levels;
184e18a033bSKonstantin Ananyev
185e18a033bSKonstantin Ananyev    n = (uint32_t) ngx_next_temp_number(0);
186e18a033bSKonstantin Ananyev
187e18a033bSKonstantin Ananyev    cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
188e18a033bSKonstantin Ananyev    if (cln == NULL) {
189e18a033bSKonstantin Ananyev        return NGX_ERROR;
190e18a033bSKonstantin Ananyev    }
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    for ( ;; ) {
193e18a033bSKonstantin Ananyev        (void) ngx_sprintf(p, "%010uD%Z", n);
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev        if (!prefix) {
196e18a033bSKonstantin Ananyev            ngx_create_hashed_filename(path, file->name.data, file->name.len);
197e18a033bSKonstantin Ananyev        }
198e18a033bSKonstantin Ananyev
199e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
200e18a033bSKonstantin Ananyev                       "hashed path: %s", file->name.data);
201e18a033bSKonstantin Ananyev
202e18a033bSKonstantin Ananyev        file->fd = ngx_open_tempfile(file->name.data, persistent, access);
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
205e18a033bSKonstantin Ananyev                       "temp fd:%d", file->fd);
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev        if (file->fd != NGX_INVALID_FILE) {
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev            cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
210e18a033bSKonstantin Ananyev            clnf = cln->data;
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev            clnf->fd = file->fd;
213e18a033bSKonstantin Ananyev            clnf->name = file->name.data;
214e18a033bSKonstantin Ananyev            clnf->log = pool->log;
215e18a033bSKonstantin Ananyev
216e18a033bSKonstantin Ananyev            return NGX_OK;
217e18a033bSKonstantin Ananyev        }
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev        err = ngx_errno;
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev        if (err == NGX_EEXIST_FILE) {
222e18a033bSKonstantin Ananyev            n = (uint32_t) ngx_next_temp_number(1);
223e18a033bSKonstantin Ananyev            continue;
224e18a033bSKonstantin Ananyev        }
225e18a033bSKonstantin Ananyev
226e18a033bSKonstantin Ananyev        if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
227e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_CRIT, file->log, err,
228e18a033bSKonstantin Ananyev                          ngx_open_tempfile_n " \"%s\" failed",
229e18a033bSKonstantin Ananyev                          file->name.data);
230e18a033bSKonstantin Ananyev            return NGX_ERROR;
231e18a033bSKonstantin Ananyev        }
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev        if (ngx_create_path(file, path) == NGX_ERROR) {
234e18a033bSKonstantin Ananyev            return NGX_ERROR;
235e18a033bSKonstantin Ananyev        }
236e18a033bSKonstantin Ananyev    }
237e18a033bSKonstantin Ananyev}
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyevvoid
241e18a033bSKonstantin Ananyevngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
242e18a033bSKonstantin Ananyev{
243e18a033bSKonstantin Ananyev    size_t      i, level;
244e18a033bSKonstantin Ananyev    ngx_uint_t  n;
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev    i = path->name.len + 1;
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev    file[path->name.len + path->len]  = '/';
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
251e18a033bSKonstantin Ananyev        level = path->level[n];
252e18a033bSKonstantin Ananyev
253e18a033bSKonstantin Ananyev        if (level == 0) {
254e18a033bSKonstantin Ananyev            break;
255e18a033bSKonstantin Ananyev        }
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev        len -= level;
258e18a033bSKonstantin Ananyev        file[i - 1] = '/';
259e18a033bSKonstantin Ananyev        ngx_memcpy(&file[i], &file[len], level);
260e18a033bSKonstantin Ananyev        i += level + 1;
261e18a033bSKonstantin Ananyev    }
262e18a033bSKonstantin Ananyev}
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyevngx_int_t
266e18a033bSKonstantin Ananyevngx_create_path(ngx_file_t *file, ngx_path_t *path)
267e18a033bSKonstantin Ananyev{
268e18a033bSKonstantin Ananyev    size_t      pos;
269e18a033bSKonstantin Ananyev    ngx_err_t   err;
270e18a033bSKonstantin Ananyev    ngx_uint_t  i;
271e18a033bSKonstantin Ananyev
272e18a033bSKonstantin Ananyev    pos = path->name.len;
273e18a033bSKonstantin Ananyev
274e18a033bSKonstantin Ananyev    for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) {
275e18a033bSKonstantin Ananyev        if (path->level[i] == 0) {
276e18a033bSKonstantin Ananyev            break;
277e18a033bSKonstantin Ananyev        }
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev        pos += path->level[i] + 1;
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev        file->name.data[pos] = '\0';
282e18a033bSKonstantin Ananyev
283e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
284e18a033bSKonstantin Ananyev                       "temp file: \"%s\"", file->name.data);
285e18a033bSKonstantin Ananyev
286e18a033bSKonstantin Ananyev        if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
287e18a033bSKonstantin Ananyev            err = ngx_errno;
288e18a033bSKonstantin Ananyev            if (err != NGX_EEXIST) {
289e18a033bSKonstantin Ananyev                ngx_log_error(NGX_LOG_CRIT, file->log, err,
290e18a033bSKonstantin Ananyev                              ngx_create_dir_n " \"%s\" failed",
291e18a033bSKonstantin Ananyev                              file->name.data);
292e18a033bSKonstantin Ananyev                return NGX_ERROR;
293e18a033bSKonstantin Ananyev            }
294e18a033bSKonstantin Ananyev        }
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev        file->name.data[pos] = '/';
297e18a033bSKonstantin Ananyev    }
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev    return NGX_OK;
300e18a033bSKonstantin Ananyev}
301e18a033bSKonstantin Ananyev
302e18a033bSKonstantin Ananyev
303e18a033bSKonstantin Ananyevngx_err_t
304e18a033bSKonstantin Ananyevngx_create_full_path(u_char *dir, ngx_uint_t access)
305e18a033bSKonstantin Ananyev{
306e18a033bSKonstantin Ananyev    u_char     *p, ch;
307e18a033bSKonstantin Ananyev    ngx_err_t   err;
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev    err = 0;
310e18a033bSKonstantin Ananyev
311e18a033bSKonstantin Ananyev#if (NGX_WIN32)
312e18a033bSKonstantin Ananyev    p = dir + 3;
313e18a033bSKonstantin Ananyev#else
314e18a033bSKonstantin Ananyev    p = dir + 1;
315e18a033bSKonstantin Ananyev#endif
316e18a033bSKonstantin Ananyev
317e18a033bSKonstantin Ananyev    for ( /* void */ ; *p; p++) {
318e18a033bSKonstantin Ananyev        ch = *p;
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev        if (ch != '/') {
321e18a033bSKonstantin Ananyev            continue;
322e18a033bSKonstantin Ananyev        }
323e18a033bSKonstantin Ananyev
324e18a033bSKonstantin Ananyev        *p = '\0';
325e18a033bSKonstantin Ananyev
326e18a033bSKonstantin Ananyev        if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
327e18a033bSKonstantin Ananyev            err = ngx_errno;
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev            switch (err) {
330e18a033bSKonstantin Ananyev            case NGX_EEXIST:
331e18a033bSKonstantin Ananyev                err = 0;
332e18a033bSKonstantin Ananyev            case NGX_EACCES:
333e18a033bSKonstantin Ananyev                break;
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev            default:
336e18a033bSKonstantin Ananyev                return err;
337e18a033bSKonstantin Ananyev            }
338e18a033bSKonstantin Ananyev        }
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev        *p = '/';
341e18a033bSKonstantin Ananyev    }
342e18a033bSKonstantin Ananyev
343e18a033bSKonstantin Ananyev    return err;
344e18a033bSKonstantin Ananyev}
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyevngx_atomic_uint_t
348e18a033bSKonstantin Ananyevngx_next_temp_number(ngx_uint_t collision)
349e18a033bSKonstantin Ananyev{
350e18a033bSKonstantin Ananyev    ngx_atomic_uint_t  n, add;
351e18a033bSKonstantin Ananyev
352e18a033bSKonstantin Ananyev    add = collision ? ngx_random_number : 1;
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev    n = ngx_atomic_fetch_add(ngx_temp_number, add);
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev    return n + add;
357e18a033bSKonstantin Ananyev}
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyevchar *
361e18a033bSKonstantin Ananyevngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
362e18a033bSKonstantin Ananyev{
363e18a033bSKonstantin Ananyev    char  *p = conf;
364e18a033bSKonstantin Ananyev
365e18a033bSKonstantin Ananyev    ssize_t      level;
366e18a033bSKonstantin Ananyev    ngx_str_t   *value;
367e18a033bSKonstantin Ananyev    ngx_uint_t   i, n;
368e18a033bSKonstantin Ananyev    ngx_path_t  *path, **slot;
369e18a033bSKonstantin Ananyev
370e18a033bSKonstantin Ananyev    slot = (ngx_path_t **) (p + cmd->offset);
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    if (*slot) {
373e18a033bSKonstantin Ananyev        return "is duplicate";
374e18a033bSKonstantin Ananyev    }
375e18a033bSKonstantin Ananyev
376e18a033bSKonstantin Ananyev    path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
377e18a033bSKonstantin Ananyev    if (path == NULL) {
378e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
379e18a033bSKonstantin Ananyev    }
380e18a033bSKonstantin Ananyev
381e18a033bSKonstantin Ananyev    value = cf->args->elts;
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyev    path->name = value[1];
384e18a033bSKonstantin Ananyev
385e18a033bSKonstantin Ananyev    if (path->name.data[path->name.len - 1] == '/') {
386e18a033bSKonstantin Ananyev        path->name.len--;
387e18a033bSKonstantin Ananyev    }
388e18a033bSKonstantin Ananyev
389e18a033bSKonstantin Ananyev    if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) {
390e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
391e18a033bSKonstantin Ananyev    }
392e18a033bSKonstantin Ananyev
393e18a033bSKonstantin Ananyev    path->conf_file = cf->conf_file->file.name.data;
394e18a033bSKonstantin Ananyev    path->line = cf->conf_file->line;
395e18a033bSKonstantin Ananyev
396e18a033bSKonstantin Ananyev    for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
397e18a033bSKonstantin Ananyev        level = ngx_atoi(value[n].data, value[n].len);
398e18a033bSKonstantin Ananyev        if (level == NGX_ERROR || level == 0) {
399e18a033bSKonstantin Ananyev            return "invalid value";
400e18a033bSKonstantin Ananyev        }
401e18a033bSKonstantin Ananyev
402e18a033bSKonstantin Ananyev        path->level[i] = level;
403e18a033bSKonstantin Ananyev        path->len += level + 1;
404e18a033bSKonstantin Ananyev    }
405e18a033bSKonstantin Ananyev
406e18a033bSKonstantin Ananyev    if (path->len > 10 + i) {
407e18a033bSKonstantin Ananyev        return "invalid value";
408e18a033bSKonstantin Ananyev    }
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev    *slot = path;
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev    if (ngx_add_path(cf, slot) == NGX_ERROR) {
413e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
414e18a033bSKonstantin Ananyev    }
415e18a033bSKonstantin Ananyev
416e18a033bSKonstantin Ananyev    return NGX_CONF_OK;
417e18a033bSKonstantin Ananyev}
418e18a033bSKonstantin Ananyev
419e18a033bSKonstantin Ananyev
420e18a033bSKonstantin Ananyevchar *
421e18a033bSKonstantin Ananyevngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **