/* This function cleans a path to its most basic form, performing the following transformations : * * - ./ -> [empty] * - // -> / * - /base/parent/../ -> /base/ * * If possible, it leaves the original string in place and does not copy characters, otherwise * characters are copied. */ void ndk_clean_path (ngx_str_t *path, ngx_uint_t complex, size_t off) { u_char *s, *p, *m, *e, c, *l; ngx_uint_t root; if (path->len == 1) { if (path->data[0] == '.') { path->len = 0; } return; } /* strip initial './' */ s = path->data; e = s + path->len; if (off) { p = s + off; goto check_basic; } if (*s == '/') root = 1; else root = 0; while (s < e) { switch (*s) { case '/' : /* '//' => '/' */ s++; continue; case '.' : if (s == e-1) { if (root) { path->data[0] = '/'; path->len = 1; } else { path->len = 0; } return; } /* './' => '' */ if (s[1] == '/') { s += 2; if (s == e) { path->len = 0; return; } continue; } } break; } if (root && *s != '/') { s--; } p = s; check_basic : for ( ; p '/' */ m = p + 2; goto copy; case '.' : if (e - p == 2) break; switch (p[2]) { case '/' : /* './' => '' */ m = p + 2; goto copy; case '.' : if (e - p == 3 || p[3] == '/') { if (p == s) { s += 3; continue; } if (p - s >= 2) { if (p[-1] == '.' && p[-2] == '.') { if (p - s == 2 || p[-3] == '/') { /* = '../../' */ p += 2; /* 3? */ continue; } } } m = p + 4; if (complex) { for (p--; p >= s; p--) { switch (*p) { case '/' : goto copy; case '$' : p = m - 1; if (m == e) goto end_basic; goto new_dir_first; } } } else { for (p--; p > s; p--) { /* '/path/folder/../' => '/path/' */ if (*p == '/') break; } } goto copy; } } } } } end_basic : path->data = s; path->len = p - s; return; copy : p++; if (m < e) goto new_dir; while (m < e) { c = *m; *p = c; p++; if (c == '/') { m++; new_dir : for ( ; m '' */ m += 2; if (m == e) break; goto new_dir; case '.' : if (e - m == 2 || m[2] == '/') { if (m - s >= 3) { /* NOTE : this is one higher than above because m has moved on 1 */ if (p[-2] == '.' && p[-3] == '.') { if (m - s == 3 || p[-4] == '/') { /* = '../../' */ p[0] = '.'; p[1] = '.'; p[2] = '/'; p += 3; m += 3; goto new_dir; } } } if (complex) { l = p; for (p -= 2; p >= s; p--) { switch (*p) { case '/' : break; case '$' : l[0] = '.'; l[1] = '.'; l[2] = '/'; p = l + 4; break; default : continue; } break; } m += 3; if (m == e) goto end; goto new_dir; } else { for (p -= 2; p > s; p--) { /* '/path/folder/../' => '/path/' */ if (*p == '/') break; } m += 3; if (m == e) goto end; goto new_dir; } } } } } else { m++; } } end : path->data = s; path->len = p - s; } /* This function converts a path to its directory version, and assumes that there is always space * to allocatate an extra character on the end (which is only true if the provided strings always * have NULL's at the end (hence the 'safe'). */ void ndk_path_to_dir_safe (ngx_str_t *path, ngx_uint_t complex, size_t off) { size_t len; u_char *p, *m; ndk_clean_path (path, complex, off); len = path->len; if (!len) return; p = path->data; m = p + len - 1; if (*m != '/') { p [len] = '/'; path->len++; } } /* Divides a path given by path/to/path1:path/to/path2 into separate strings and returns an * array of these strings. */ ngx_array_t * ndk_split_path_create (ngx_conf_t *cf, ngx_str_t *path) { ngx_str_t *str; int n; u_char *m, *s, *e; ngx_array_t *a; if (path == NULL) return NULL; n = ndk_strcntc (path, ':'); a = ngx_array_create (cf->pool, n + 1, sizeof (ngx_str_t)); if (a == NULL) { return NULL; } s = path->data; e = s + path->len; while (s < e) { m = s; while (m < e && *m != ':') m++; if (m == s) { s = m+1; continue; } str = ngx_array_push (a); if (str == NULL) { return NULL; } str->data = s; str->len = m - s; if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) return NULL; s = m+1; } return a; } ngx_array_t * ndk_split_path_create_raw (ngx_conf_t *cf, char *path) { ngx_str_t *str; int n; char *m, *s; ngx_array_t *a; if (path == NULL) return NULL; n = ndk_strccnt (path, ':'); a = ngx_array_create (cf->pool, n + 1, sizeof (ngx_str_t)); if (a == NULL) { return NULL; } s = path; while (*s != '\0') { m = s; while (*m != '\0' && *m != ':') m++; if (m == s) { s = m+1; continue; } str = ngx_array_push (a); if (str == NULL) { return NULL; } str->data = (u_char *) s; str->len = m - s; if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) return NULL; if (*m == '\0') break; s = m+1; } return a; } char * ndk_conf_set_full_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_str_t *path, *value; ngx_conf_post_t *post; path = (ngx_str_t *) (p + cmd->offset); if (path->data) { return "is duplicate"; } value = cf->args->elts; *path = value[1]; if (ngx_conf_full_name (cf->cycle, path, 0) == NGX_ERROR) return NGX_CONF_ERROR; if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, path); } return NGX_CONF_OK; } char * ndk_conf_set_split_path_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { /* TODO : change to use the path func above */ char *p = conf; ngx_str_t *value, *str; ngx_array_t **a; ngx_conf_post_t *post; int n; u_char *m, *s, *e; a = (ngx_array_t **) (p + cmd->offset); if (*a != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; value++; n = ndk_strcntc (value, ':') + 1; *a = ngx_array_create (cf->pool, n, sizeof (ngx_str_t)); if (*a == NULL) { return NGX_CONF_ERROR; } s = value->data; e = s + value->len; while (s < e) { m = s; while (m < e && *m != ':') m++; if (m == s) { s = m+1; continue; } str = ngx_array_push (*a); if (str == NULL) { return NGX_CONF_ERROR; } str->data = s; str->len = m - s; if (ngx_conf_full_name (cf->cycle, str, 0) == NGX_ERROR) return NGX_CONF_ERROR; s = m+1; } if (cmd->post) { post = cmd->post; return post->post_handler (cf, post, a); } return NGX_CONF_OK; } char * ndk_conf_set_full_path (ngx_conf_t *cf, void *data, ngx_str_t *path) { if (ngx_conf_full_name (cf->cycle, path, 0) == NGX_ERROR) return NGX_CONF_ERROR; return NGX_CONF_OK; } char * ndk_conf_set_full_conf_path (ngx_conf_t *cf, void *data, ngx_str_t *path) { if (ngx_conf_full_name (cf->cycle, path, 1) == NGX_ERROR) return NGX_CONF_ERROR; return NGX_CONF_OK; }