View | Details | Raw Unified | Return to bug 27578
Collapse All | Expand All

(-)modules/dav/fs/mod_dav_fs.c (-2 / +47 lines)
Lines 24-32 Link Here
24
/* per-server configuration */
24
/* per-server configuration */
25
typedef struct {
25
typedef struct {
26
    const char *lockdb_path;
26
    const char *lockdb_path;
27
28
} dav_fs_server_conf;
27
} dav_fs_server_conf;
29
28
29
/* per-context configuration */
30
typedef struct {
31
    int allow_set_mtime;
32
} dav_fs_context_conf;
33
30
extern module AP_MODULE_DECLARE_DATA dav_fs_module;
34
extern module AP_MODULE_DECLARE_DATA dav_fs_module;
31
35
32
const char *dav_get_lockdb_path(const request_rec *r)
36
const char *dav_get_lockdb_path(const request_rec *r)
Lines 37-42 Link Here
37
    return conf->lockdb_path;
41
    return conf->lockdb_path;
38
}
42
}
39
43
44
int dav_get_allow_set_mtime(const request_rec *r)
45
{
46
    dav_fs_context_conf *conf;
47
    
48
    conf = ap_get_module_config(r->per_dir_config, &dav_fs_module);
49
    return conf->allow_set_mtime;
50
}
51
40
static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s)
52
static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s)
41
{
53
{
42
    return apr_pcalloc(p, sizeof(dav_fs_server_conf));
54
    return apr_pcalloc(p, sizeof(dav_fs_server_conf));
Lines 57-63 Link Here
57
    return newconf;
69
    return newconf;
58
}
70
}
59
71
72
static void *dav_fs_create_dir_config(apr_pool_t *pool, char *context)
73
{
74
    dav_fs_context_conf *cfg;
75
    cfg = apr_palloc(pool, sizeof(*cfg));
76
    
77
    /* Set the default values */
78
    cfg->allow_set_mtime = 0;  /* Disabled by default, for back compat */
79
80
    return cfg;
81
}
82
60
/*
83
/*
84
 * We don't have a dav_fs_merge_dir_config() because the default
85
 * behavior of simply replacing the entire config is correct for us.
86
 */
87
88
/*
61
 * Command handler for the DAVLockDB directive, which is TAKE1
89
 * Command handler for the DAVLockDB directive, which is TAKE1
62
 */
90
 */
63
static const char *dav_fs_cmd_davlockdb(cmd_parms *cmd, void *config,
91
static const char *dav_fs_cmd_davlockdb(cmd_parms *cmd, void *config,
Lines 76-87 Link Here
76
    return NULL;
104
    return NULL;
77
}
105
}
78
106
107
/*
108
 * Command handler for the DAVPropsetModTime directive, which takes a FLAG
109
 */
110
static const char *dav_fs_cmd_allowmtime(cmd_parms *cmd, void *config,
111
                                         int enable)
112
{
113
    dav_fs_context_conf *conf = config;
114
    conf->allow_set_mtime = enable? 1 : 0;
115
    return NULL;
116
}
117
79
static const command_rec dav_fs_cmds[] =
118
static const command_rec dav_fs_cmds[] =
80
{
119
{
81
    /* per server */
120
    /* per server */
82
    AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF,
121
    AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF,
83
                  "specify a lock database"),
122
                  "specify a lock database"),
84
123
124
    /* can vary by location */
125
    AP_INIT_FLAG("DAVAllowSetModTime", dav_fs_cmd_allowmtime, NULL,
126
                 RSRC_CONF | ACCESS_CONF | OR_OPTIONS,
127
                 "allow PROPPATCH to change a resource's modification time"),
128
    
85
    { NULL }
129
    { NULL }
86
};
130
};
87
131
Lines 99-108 Link Here
99
AP_DECLARE_MODULE(dav_fs) =
143
AP_DECLARE_MODULE(dav_fs) =
100
{
144
{
101
    STANDARD20_MODULE_STUFF,
145
    STANDARD20_MODULE_STUFF,
102
    NULL,                        /* dir config creater */
146
    dav_fs_create_dir_config,    /* dir config creater */
103
    NULL,                        /* dir merger --- default is to override */
147
    NULL,                        /* dir merger --- default is to override */
104
    dav_fs_create_server_config, /* server config */
148
    dav_fs_create_server_config, /* server config */
105
    dav_fs_merge_server_config,  /* merge server config */
149
    dav_fs_merge_server_config,  /* merge server config */
106
    dav_fs_cmds,                 /* command table */
150
    dav_fs_cmds,                 /* command table */
107
    register_hooks,              /* register hooks */
151
    register_hooks,              /* register hooks */
108
};
152
};
153
(-)modules/dav/fs/repos.c (-78 / +152 lines)
Lines 22-27 Link Here
22
#include "apr_file_io.h"
22
#include "apr_file_io.h"
23
#include "apr_strings.h"
23
#include "apr_strings.h"
24
#include "apr_buckets.h"
24
#include "apr_buckets.h"
25
#include "apr_date.h"
25
26
26
#if APR_HAVE_UNISTD_H
27
#if APR_HAVE_UNISTD_H
27
#include <unistd.h>             /* for getpid() */
28
#include <unistd.h>             /* for getpid() */
Lines 170-176 Link Here
170
        DAV_FS_URI_DAV,
171
        DAV_FS_URI_DAV,
171
        "getlastmodified",
172
        "getlastmodified",
172
        DAV_PROPID_getlastmodified,
173
        DAV_PROPID_getlastmodified,
173
        0
174
        0	/* handled specially in dav_fs_is_writable */
174
    },
175
    },
175
176
176
    /* our custom properties */
177
    /* our custom properties */
Lines 2024-2096 Link Here
2024
        return 1;
2025
        return 1;
2025
#endif
2026
#endif
2026
2027
2028
    if (propid == DAV_PROPID_getlastmodified) {
2029
        if(!resource->exists)
2030
            return 0;
2031
        return dav_get_allow_set_mtime(dav_fs_get_request_rec(resource));
2032
    }
2033
    
2027
    (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
2034
    (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
2028
    return info->is_writable;
2035
    return info->is_writable;
2029
}
2036
}
2030
2037
2038
struct dav_fs_patch_context {
2039
    int propid;
2040
    union rollback
2041
    {
2042
        apr_time_t mtime;
2043
        apr_fileperms_t perms;
2044
    } oldvalue;
2045
    union context
2046
    {
2047
        apr_time_t mtime;
2048
        int executable;
2049
    } newvalue;
2050
};
2051
2031
static dav_error *dav_fs_patch_validate(const dav_resource *resource,
2052
static dav_error *dav_fs_patch_validate(const dav_resource *resource,
2032
                                        const apr_xml_elem *elem,
2053
                                        const apr_xml_elem *elem,
2033
                                        int operation,
2054
                                        int operation,
2034
                                        void **context,
2055
                                        void **context,
2035
                                        int *defer_to_dead)
2056
                                        int *defer_to_dead)
2036
{
2057
{
2037
    const apr_text *cdata;
2058
    const char *cdata;
2038
    const apr_text *f_cdata;
2039
    char value;
2040
    dav_elem_private *priv = elem->priv;
2059
    dav_elem_private *priv = elem->priv;
2060
    int propid = priv->propid;
2061
    struct dav_fs_patch_context *fscontext;
2041
2062
2042
    if (priv->propid != DAV_PROPID_FS_executable) {
2063
    if (propid != DAV_PROPID_FS_executable &&
2064
        propid != DAV_PROPID_getlastmodified) {
2043
        *defer_to_dead = 1;
2065
        *defer_to_dead = 1;
2044
        return NULL;
2066
        return NULL;
2045
    }
2067
    }
2046
2068
2047
    if (operation == DAV_PROP_OP_DELETE) {
2069
    if (operation != DAV_PROP_OP_SET) {
2070
        const char *msg = apr_psprintf(resource->info->pool,
2071
                                       "The '%s' property cannot be removed.",
2072
                                       elem->name);
2048
        return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2073
        return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2049
                             "The 'executable' property cannot be removed.");
2074
                             msg);
2050
    }
2075
    }
2051
2076
2052
    cdata = elem->first_cdata.first;
2077
    cdata = dav_xml_get_cdata(elem, resource->info->pool, 0);
2053
2078
2054
    /* ### hmm. this isn't actually looking at all the possible text items */
2079
    fscontext = apr_pcalloc(resource->info->pool, sizeof(*fscontext));
2055
    f_cdata = elem->first_child == NULL
2080
    fscontext->propid = propid;
2056
        ? NULL
2081
    
2057
        : elem->first_child->following_cdata.first;
2082
    if (propid == DAV_PROPID_FS_executable) {
2058
2083
        if (cdata == NULL ||
2059
    /* DBG3("name=%s  cdata=%s  f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */
2084
            strlen(cdata) != 1 ||
2060
2085
            (cdata[0] != 'T' && cdata[0] != 'F')) {
2061
    if (cdata == NULL) {
2062
        if (f_cdata == NULL) {
2063
            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2086
            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2064
                                 "The 'executable' property expects a single "
2087
                                 "The 'executable' property expects a single "
2065
                                 "character, valued 'T' or 'F'. There was no "
2088
                                 "character, valued 'T' or 'F'.");
2066
                                 "value submitted.");
2067
        }
2089
        }
2068
        cdata = f_cdata;
2069
    }
2070
    else if (f_cdata != NULL)
2071
        goto too_long;
2072
2090
2073
    if (cdata->next != NULL || strlen(cdata->text) != 1)
2091
        fscontext->newvalue.executable = (cdata[0] == 'T');
2074
        goto too_long;
2092
    } else if (propid == DAV_PROPID_getlastmodified) {
2093
        apr_time_t new_mtime = apr_date_parse_http(cdata);
2094
        if (new_mtime == APR_DATE_BAD) {
2095
            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2096
                                 "The 'getlastmodified' property must "
2097
                                 "be an HTTP date string.");
2098
        }
2075
2099
2076
    value = cdata->text[0];
2100
        fscontext->newvalue.mtime = new_mtime;
2077
    if (value != 'T' && value != 'F') {
2078
        return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2079
                             "The 'executable' property expects a single "
2080
                             "character, valued 'T' or 'F'. The value "
2081
                             "submitted is invalid.");
2082
    }
2101
    }
2083
2102
2084
    *context = (void *)((long)(value == 'T'));
2103
    *context = fscontext;
2085
2086
    return NULL;
2104
    return NULL;
2087
2088
  too_long:
2089
    return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2090
                         "The 'executable' property expects a single "
2091
                         "character, valued 'T' or 'F'. The value submitted "
2092
                         "has too many characters.");
2093
2094
}
2105
}
2095
2106
2096
static dav_error *dav_fs_patch_exec(const dav_resource *resource,
2107
static dav_error *dav_fs_patch_exec(const dav_resource *resource,
Lines 2099-2133 Link Here
2099
                                    void *context,
2110
                                    void *context,
2100
                                    dav_liveprop_rollback **rollback_ctx)
2111
                                    dav_liveprop_rollback **rollback_ctx)
2101
{
2112
{
2102
    long value = context != NULL;
2113
    struct dav_fs_patch_context *fscontext = context;
2103
    apr_fileperms_t perms = resource->info->finfo.protection;
2104
    apr_status_t status;
2105
    long old_value = (perms & APR_UEXECUTE) != 0;
2106
2114
2107
    /* assert: prop == executable. operation == SET. */
2115
    if (operation != DAV_PROP_OP_SET) {
2116
        ap_log_assert("operation == SET", __FILE__, __LINE__);
2117
        return dav_new_error(resource->info->pool,
2118
                             HTTP_INTERNAL_SERVER_ERROR, 0, 0, NULL);
2119
    }
2120
    
2121
    if (fscontext->propid == DAV_PROPID_FS_executable) {
2122
        apr_fileperms_t perms = resource->info->finfo.protection;
2123
        apr_status_t status;
2124
        struct dav_error *err;
2125
        
2126
        fscontext->oldvalue.perms = perms;
2108
2127
2109
    /* don't do anything if there is no change. no rollback info either. */
2128
        perms &= ~(APR_UEXECUTE);
2110
    /* DBG2("new value=%d  (old=%d)", value, old_value); */
2129
        if (fscontext->newvalue.executable)
2111
    if (value == old_value)
2130
            perms |= APR_UEXECUTE;
2112
        return NULL;
2131
        
2132
        /* don't do anything if there is no change. no rollback info either. */
2133
        if (perms == resource->info->finfo.protection)
2134
            return NULL;
2135
        
2136
        status = apr_file_perms_set(resource->info->pathname, perms);
2113
2137
2114
    perms &= ~APR_UEXECUTE;
2138
        if (status == APR_SUCCESS) {
2115
    if (value)
2139
            /* update the resource and set up the rollback context */
2116
        perms |= APR_UEXECUTE;
2140
            resource->info->finfo.protection = perms;
2141
            *rollback_ctx = (dav_liveprop_rollback *)fscontext;
2142
            return NULL;
2143
        }
2117
2144
2118
    if ((status = apr_file_perms_set(resource->info->pathname, perms))
2145
        err = dav_new_error(resource->info->pool,
2119
        != APR_SUCCESS) {
2146
                            HTTP_INTERNAL_SERVER_ERROR, 0, status,
2147
                            "Could not set the executable flag of the "
2148
                            "target resource.");
2149
        if (APR_STATUS_IS_EACCES(status))
2150
            err->status = HTTP_FORBIDDEN;
2151
        return err;
2152
    } else if (fscontext->propid == DAV_PROPID_getlastmodified) {
2153
        apr_status_t status;
2154
        struct dav_error *err;
2155
        
2156
        fscontext->oldvalue.mtime = resource->info->finfo.mtime;
2157
        
2158
        status = apr_file_mtime_set(resource->info->pathname, fscontext->newvalue.mtime, resource->info->pool);
2159
2160
        if (status == APR_SUCCESS) {
2161
            /* update the resource and set up the rollback context */
2162
            resource->info->finfo.mtime = fscontext->newvalue.mtime;
2163
            *rollback_ctx = (dav_liveprop_rollback *)fscontext;
2164
            return NULL;
2165
        }
2166
2167
        err = dav_new_error(resource->info->pool,
2168
                            HTTP_INTERNAL_SERVER_ERROR, 0, status,
2169
                            "Could not set the last-modified-time of the "
2170
                            "target resource.");
2171
        if (APR_STATUS_IS_EACCES(status))
2172
            err->status = HTTP_FORBIDDEN;
2173
        return err;
2174
    } else {
2175
        ap_log_assert("unknown propid", __FILE__, __LINE__);
2120
        return dav_new_error(resource->info->pool,
2176
        return dav_new_error(resource->info->pool,
2121
                             HTTP_INTERNAL_SERVER_ERROR, 0, status,
2177
                             HTTP_INTERNAL_SERVER_ERROR, 0, 0, NULL);
2122
                             "Could not set the executable flag of the "
2123
                             "target resource.");
2124
    }
2178
    }
2125
2126
    /* update the resource and set up the rollback context */
2127
    resource->info->finfo.protection = perms;
2128
    *rollback_ctx = (dav_liveprop_rollback *)old_value;
2129
2130
    return NULL;
2131
}
2179
}
2132
2180
2133
static void dav_fs_patch_commit(const dav_resource *resource,
2181
static void dav_fs_patch_commit(const dav_resource *resource,
Lines 2143-2169 Link Here
2143
                                        void *context,
2191
                                        void *context,
2144
                                        dav_liveprop_rollback *rollback_ctx)
2192
                                        dav_liveprop_rollback *rollback_ctx)
2145
{
2193
{
2146
    apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE;
2147
    apr_status_t status;
2194
    apr_status_t status;
2148
    int value = rollback_ctx != NULL;
2195
    struct dav_fs_patch_context *fscontext;
2149
2196
2150
    /* assert: prop == executable. operation == SET. */
2197
    /* ### The rollback hook is called for all liveprops whose
2198
           validate hook was called, even if they didn't get an exec
2199
           because an earlier exec failed or if their validate hook
2200
           failed. So we need to know not to undo anything we didn't
2201
           do. We signal this by not setting the rollback ctx unless
2202
           we want to roll something back. */
2203
    if (!rollback_ctx)
2204
      return NULL;
2151
2205
2152
    /* restore the executable bit */
2206
    fscontext = (void *)rollback_ctx;
2153
    if (value)
2207
    
2154
        perms |= APR_UEXECUTE;
2208
    /* assert: operation == SET. */
2155
2209
2156
    if ((status = apr_file_perms_set(resource->info->pathname, perms))
2210
    switch(fscontext->propid) {
2157
        != APR_SUCCESS) {
2211
    case DAV_PROPID_FS_executable:
2158
        return dav_new_error(resource->info->pool,
2212
        status = apr_file_perms_set(resource->info->pathname,
2159
                             HTTP_INTERNAL_SERVER_ERROR, 0, status,
2213
                                    fscontext->oldvalue.mtime);
2160
                             "After a failure occurred, the resource's "
2214
        if (status != APR_SUCCESS) {
2161
                             "executable flag could not be restored.");
2215
            return dav_new_error(resource->info->pool,
2216
                                 HTTP_INTERNAL_SERVER_ERROR, 0, status,
2217
                                 "After a failure occurred, the resource's "
2218
                                 "executable flag could not be restored.");
2219
        }
2220
2221
        resource->info->finfo.protection = fscontext->oldvalue.mtime;
2222
        
2223
        break;
2224
2225
    case DAV_PROPID_getlastmodified:
2226
        status = apr_file_mtime_set(resource->info->pathname,
2227
                                    fscontext->oldvalue.mtime,
2228
                                    resource->info->pool);
2229
        if (status != APR_SUCCESS) {
2230
            return dav_new_error(resource->info->pool,
2231
                                 HTTP_INTERNAL_SERVER_ERROR, 0, status,
2232
                                 "After a failure occurred, the resource's "
2233
                                 "modification date could not be restored.");
2234
        }
2235
2236
        resource->info->finfo.mtime = fscontext->oldvalue.mtime;
2237
        
2238
        break;
2162
    }
2239
    }
2163
2240
2164
    /* restore the resource's state */
2165
    resource->info->finfo.protection = perms;
2166
2167
    return NULL;
2241
    return NULL;
2168
}
2242
}
2169
2243
(-)modules/dav/fs/repos.h (+3 lines)
Lines 67-72 Link Here
67
/* where is the lock database located? */
67
/* where is the lock database located? */
68
const char *dav_get_lockdb_path(const request_rec *r);
68
const char *dav_get_lockdb_path(const request_rec *r);
69
69
70
/* can PROPPATCH write the getlastmodified property? */
71
int dav_get_allow_set_mtime(const request_rec *r);
72
70
const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r);
73
const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r);
71
const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r);
74
const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r);
72
75

Return to bug 27578