]> granicus.if.org Git - apache/commitdiff
Add various file existance test operators to ap_expr
authorStefan Fritsch <sf@apache.org>
Sat, 14 May 2011 13:22:11 +0000 (13:22 +0000)
committerStefan Fritsch <sf@apache.org>
Sat, 14 May 2011 13:22:11 +0000 (13:22 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1103097 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/expr.html.en
docs/manual/expr.xml
server/util_expr_eval.c

diff --git a/CHANGES b/CHANGES
index 2cd9baa971d7027122aad943eb957293abaccb31..e5bba159d76f013133a127a250ec6f13bfcb0da0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
 
 Changes with Apache 2.3.13
 
+  *) core: Add various file existance test operators to ap_expr.
+     [Stefan Fritsch]
+
   *) mod_proxy_express: New mass reverse-proxy switch extension for
      mod_proxy. [Jim Jagielski]
 
index 6fc51f6b307518a0a1ceb39562a7e782b368316f..f0e9c2077548cd0d237f00c8c2dc55869432153f 100644 (file)
@@ -324,15 +324,25 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
     Modules may register additional unary operators.</p>
 
     <table class="bordered"><tr class="header"><th>Name</th><th>Description</th></tr>
-<tr><td><code>-n</code></td>
+<tr><td><code>-d</code></td>
+        <td>True if file exists and is a directory</td></tr>
+<tr class="odd"><td><code>-e</code></td>
+        <td>True if file (or dir or special) exists</td></tr>
+<tr><td><code>-f</code></td>
+        <td>True if file exists and is regular file</td></tr>
+<tr class="odd"><td><code>-L</code></td>
+        <td>True if file exists and is symlink</td></tr>
+<tr><td><code>-h</code></td>
+        <td>True if file exists and is symlink (same as <code>-L</code>)</td></tr>
+<tr class="odd"><td><code>-n</code></td>
         <td>True if string is not empty</td></tr>
-<tr class="odd"><td><code>-z</code></td>
+<tr><td><code>-z</code></td>
         <td>True if string is empty</td></tr>
-<tr><td><code>-T</code></td>
+<tr class="odd"><td><code>-T</code></td>
         <td>False if string is empty, "<code>0</code>", "<code>off</code>",
             "<code>false</code>", or "<code>no</code>" (case insensitive).
             True otherwise.</td></tr>
-<tr class="odd"><td><code>-R</code></td>
+<tr><td><code>-R</code></td>
         <td>Same as "<code>%{REMOTE_ADDR} -ipmatch ...</code>", but more efficient
         </td></tr>
 </table>
@@ -370,6 +380,8 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
         <td>Unescape %hex encoded string, leaving URL-special characters encoded (XXX: describe better)</td></tr>
 <tr><td><code>file</code></td>
         <td>Read contents from a file</td></tr>
+<tr class="odd"><td><code>filesize</code></td>
+        <td>Return size of a file (or 0 if file does not exist or is not regular file)</td></tr>
 </table>
 
     <p>In addition to string-valued functions, there are also list-valued functions which
index ea9a182929f3d330670d9c24b0d835e2f7ef96b6..bc2604e82c735f4a1dfc3bf32aed111d82cdf819 100644 (file)
@@ -347,6 +347,16 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
     <columnspec><column width=".2"/><column width=".2"/><column width=".6"/></columnspec>
 
     <tr><th>Name</th><th>Description</th></tr>
+    <tr><td><code>-d</code></td>
+        <td>True if file exists and is a directory</td></tr>
+    <tr><td><code>-e</code></td>
+        <td>True if file (or dir or special) exists</td></tr>
+    <tr><td><code>-f</code></td>
+        <td>True if file exists and is regular file</td></tr>
+    <tr><td><code>-L</code></td>
+        <td>True if file exists and is symlink</td></tr>
+    <tr><td><code>-h</code></td>
+        <td>True if file exists and is symlink (same as <code>-L</code>)</td></tr>
     <tr><td><code>-n</code></td>
         <td>True if string is not empty</td></tr>
     <tr><td><code>-z</code></td>
@@ -396,6 +406,9 @@ listfunction ::= listfuncname "<strong>(</strong>" word "<strong>)</strong>"
         <td>Unescape %hex encoded string, leaving URL-special characters encoded (XXX: describe better)</td></tr>
     <tr><td><code>file</code></td>
         <td>Read contents from a file</td></tr>
+    <tr><td><code>filesize</code></td>
+        <td>Return size of a file (or 0 if file does not exist or is not regular file)</td></tr>
+
     </table>
 
     <p>In addition to string-valued functions, there are also list-valued functions which
index 9a1c80d13c61470f7ab986c8b9a8ed964bf0331f..57a328b18ff7631b5b83f04274848c665e802cee 100644 (file)
@@ -872,6 +872,16 @@ static const char *file_func(ap_expr_eval_ctx_t *ctx, const void *data,
     return buf;
 }
 
+static const char *filesize_func(ap_expr_eval_ctx_t *ctx, const void *data,
+                                  char *arg)
+{
+    apr_finfo_t sb;
+    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) == APR_SUCCESS
+        && sb.filetype == APR_REG && sb.size > 0)
+        return apr_psprintf(ctx->p, "%" APR_OFF_T_FMT, sb.size);
+    else
+        return "0";
+}
 
 static const char *unescape_func(ap_expr_eval_ctx_t *ctx, const void *data,
                                  const char *arg)
@@ -893,6 +903,50 @@ static int op_nz(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
         return (arg[0] != '\0');
 }
 
+static int op_file_min(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
+{
+    apr_finfo_t sb;
+    const char *name = (const char *)data;
+    if (apr_stat(&sb, arg, APR_FINFO_MIN, ctx->p) != APR_SUCCESS)
+        return 0;
+    switch (name[0]) {
+    case 'd':
+        return (sb.filetype == APR_DIR);
+    case 'e':
+        return 1;
+    case 'f':
+        return (sb.filetype == APR_REG);
+    case 's':
+        return (sb.filetype == APR_REG && sb.size > 0);
+    default:
+        ap_assert(0);
+    }
+    return 0;
+}
+
+static int op_file_link(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
+{
+    apr_finfo_t sb;
+#if !defined(OS2)
+    if (apr_stat(&sb, arg, APR_FINFO_MIN | APR_FINFO_LINK, ctx->p) == APR_SUCCESS
+        && sb.filetype == APR_LNK) {
+        return 1;
+    }
+#endif
+    return 0;
+}
+
+static int op_file_xbit(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
+{
+    apr_finfo_t sb;
+    if (apr_stat(&sb, arg, APR_FINFO_PROT| APR_FINFO_LINK, ctx->p) == APR_SUCCESS
+        && (sb.protection & (APR_UEXECUTE | APR_GEXECUTE | APR_WEXECUTE))) {
+        return 1;
+    }
+    return 0;
+}
+
+
 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *is_https = NULL;
 
@@ -1255,15 +1309,23 @@ static const struct expr_provider_single string_func_providers[] = {
     { escape_func,          "escape",         NULL },
     { unescape_func,        "unescape",       NULL },
     { file_func,            "file",           NULL },
+    { filesize_func,        "filesize",       NULL },
     { NULL, NULL, NULL}
 };
 /* XXX: base64 encode/decode ? */
 
 static const struct expr_provider_single unary_op_providers[] = {
-    { op_nz, "n", NULL },
-    { op_nz, "z", NULL },
-    { op_R,  "R", subnet_parse_arg },
-    { op_T,  "T", NULL },
+    { op_nz,        "n", NULL },
+    { op_nz,        "z", NULL },
+    { op_R,         "R", subnet_parse_arg },
+    { op_T,         "T", NULL },
+    { op_file_min,  "d", NULL },
+    { op_file_min,  "e", NULL },
+    { op_file_min,  "f", NULL },
+    { op_file_min,  "s", NULL },
+    { op_file_link, "L", NULL },
+    { op_file_link, "h", NULL },
+    { op_file_xbit, "x", NULL },
     { NULL, NULL, NULL }
 };