This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+506
View File
@@ -0,0 +1,506 @@
/****************************************************************************
mod_dav_pgsql (DASL) for apache 2.X
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Author : sean kim (sean@solutionbox.co.kr)
$Id: props.c,v 1.2 2006/09/20 09:22:59 sean Exp $
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
****************************************************************************/
/* TODO
1. remove etags filed
2. change collection to int
3. change all time field to long
*/
#include <httpd.h>
#include <http_protocol.h>
#include <http_log.h>
#include <http_core.h> /* for ap_construct_url */
#include <apr_strings.h>
#include <apr_hash.h>
#include <apr_dbm.h>
#include <apr_file_io.h>
#include "dav_repos.h"
#include "dbms.h"
#include "util.h"
struct dav_namespace_map
{
int *ns_map;
};
struct dav_db
{
apr_pool_t *pool;
dav_repos_resource *mdb_r;
/* when used as a property database: */
int version; /* *minor* version of this db */
dav_buffer ns_table; /* table of namespace URIs */
short ns_count; /* number of entries in table */
int ns_table_dirty; /* ns_table was modified */
apr_hash_t *uri_index;
dav_buffer wb_key; /* work buffer for dav_key */
apr_datum_t iter; /* iteration key */
};
static dav_error *dav_repos_db_open(apr_pool_t * p,
const dav_resource * resource, int ro,
dav_db ** pdb)
{
DBG0("dav_repos_db_open: ");
// 2013.08.22 dadamin
// 디렉토리 경우 유일한 값을 추출할 수 없어서 속성 변경 불가능 하도록함
if(resource && resource->info)
{
dav_resource_private *ctx = resource->info;
if(ctx->db_r)
{
if(ctx->db_r->m_resource_type)
{
*pdb = NULL;
return NULL;
}
}
}
dav_db *db = apr_pcalloc(p, sizeof(*db));
TRACE();
/* Set some values for DB */
db->pool = p;
db->mdb_r = (dav_repos_resource *) resource->info->db_r;
*pdb = db;
db->uri_index = apr_hash_make(p);
return NULL;
}
static void dav_repos_db_close(dav_db * db)
{
TRACE();
}
static dav_error *dav_repos_db_define_namespaces(dav_db * db,
dav_xmlns_info * xi)
{
const char *ns, *xmlns;
dav_repos_property *dead_prop;
dav_repos_resource *dbr = db->mdb_r;
DBG0("dav_repos_db_define_namespaces: ");
TRACE();
/* Null lock */
if (dbr == NULL)
return NULL;
// 2013.08.22 dadamin
/* Check all used name space in this resource */
for (dead_prop = dbr->pr; dead_prop; dead_prop = dead_prop->next)
{
ns = dbms_get_ns(dbr, dead_prop->m_ns_id);
if (ns && strlen(ns))
{ /* not nullns */
xmlns = apr_psprintf(dbr->p, "ns%ld", dead_prop->m_ns_id);
dav_xmlns_add(xi, xmlns, ns);
}
}
/* ### we don't have any other possible namespaces right now. */
return NULL;
}
static dav_error *dav_repos_db_output_value(dav_db * db,
const dav_prop_name * name,
dav_xmlns_info * xi,
apr_text_header * phdr,
int *found)
{
const char *s = NULL;
const char *val;
/* Get resource records */
dav_repos_resource *dbr = db->mdb_r;
apr_pool_t *pool = db->pool;
DBG1("dav_repos_db_output_value: name:%s", name->name);
TRACE();
if (dbr == NULL) {
*found = 0;
return NULL;
}
DBG2("OUT %s [] %s\n", name->ns, name->name);
if (!strcmp(name->ns, "DAV:")) {
val = apr_hash_get(dbr->lpr_hash, name->name, APR_HASH_KEY_STRING);
if (val) {
s = apr_psprintf(pool, "<D:%s>%s</D:%s>" DEBUG_CR,
name->name, val, name->name);
}
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
else if (!strcmp(name->name, "lockdiscovery") ) {
s = apr_psprintf(pool, "<D:%s></D:%s>" DEBUG_CR,
name->name, name->name);
}
else if (!strcmp(name->name, "supportedlock")) {
}
}
DBG2("OUT2 %s [] %s\n", name->ns, name->name);
if (s == NULL) { /* Dead props or Not found */
/* Get the key */
const char *key =
dav_repos_build_ns_name_key(name->ns, name->name, pool);
/* Get the dead prop */
dav_repos_property *dead_prop =
apr_hash_get(dbr->pr_hash, key, APR_HASH_KEY_STRING);
if (dead_prop != NULL) {
/* Null ns */
if (strlen(name->ns) == 0 || !strcmp(name->ns, " ")) {
s = apr_psprintf(pool, "<%s xmlns=\"\">%s</%s>" DEBUG_CR,
name->name, dead_prop->m_propvalue, name->name);
} else { /* Not null ns */
s = apr_psprintf(pool, "<ns%ld:%s>%s</ns%ld:%s>" DEBUG_CR,
dead_prop->m_ns_id, name->name,
dead_prop->m_propvalue, dead_prop->m_ns_id,
name->name);
}
} else {
// 2013.08.27 dadamin
// SolDirve PROPFIND 시 네임스페이스 사용하기 때문에
// 해당 파일(디렉토리 경우 소속된 모든 정보)에 대해서
// RCDB 네임스페이스 관련 조회 발생으로 응답 성능 저하가
// 발생함으로 opendav 지정된(DAV:)와 기본 속성이 외에 값에
// 대해서 오퍼레이션되지 않게함
#ifdef __USE_NAMESPACE__
// 2013.08.22 dadamin
// t_dav_resource 없는 property에 대해서 조회
dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr));
// Let's fill fill pr
pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns);
pr->m_propname = name->name;
if(dbms_get_dead_property(dbr, pr) == 0)
{
dbr->pr = pr;
s = apr_psprintf(pool, "<ns%ld:%s>%s</ns%ld:%s>" DEBUG_CR,
pr->m_ns_id, pr->m_propname,
pr->m_propvalue, pr->m_ns_id,
pr->m_propname);
// set namespace
// 해당 네임스페이스 존재하지 않을 시 PROPFIND에서
// 올바른 네임스페이스로 리턴되지 않는 것을 방지하기 위해서
// 관련 네임스페이스를 헤쉬테이블에 저장함
dbms_set_namespace(dbr, pr, name->ns);
}
else
#endif // __USE_NAMESPACE__
{
DBG1("NOFPUND [%s]\n", key);
}
}
}
if (s) {
*found = 1;
apr_text_append(pool, phdr, s);
}
else {
*found = 0;
}
return NULL;
}
static dav_error *dav_repos_db_map_namespaces(dav_db * db,
const apr_array_header_t *
namespaces,
dav_namespace_map ** mapping)
{
dav_namespace_map *m = apr_palloc(db->pool, sizeof(*m));
int i;
int *pmap;
const char **puri;
TRACE();
/*
** Iterate over the provided namespaces. If a namespace already appears
** in our internal map of URI -> ns_id, then store that in the map. If
** we don't know the namespace yet, then add it to the map and to our
** table of known namespaces.
*/
pmap = apr_palloc(db->pool, namespaces->nelts * sizeof(*pmap));
for (i = namespaces->nelts, puri = (const char **) namespaces->elts;
i-- > 0; ++puri, ++pmap) {
const char *uri = *puri;
apr_size_t uri_len = strlen(uri);
long ns_id = (long) apr_hash_get(db->uri_index, uri, uri_len);
if (ns_id == 0) {
dav_check_bufsize(db->pool, &db->ns_table, uri_len + 1);
memcpy(db->ns_table.buf + db->ns_table.cur_len, uri, uri_len + 1);
db->ns_table.cur_len += uri_len + 1;
/* copy the uri in case the passed-in namespaces changes in
some way. */
apr_hash_set(db->uri_index, apr_pstrdup(db->pool, uri), uri_len,
(void *) ((long)(db->ns_count + 1)));
db->ns_table_dirty = 1;
*pmap = db->ns_count++;
}
else {
*pmap = ns_id - 1;
}
}
m->ns_map = pmap;
*mapping = m;
return NULL;
}
static dav_error *dav_repos_db_store(dav_db * db, const dav_prop_name * name,
const apr_xml_elem * elem,
dav_namespace_map * mapping)
{
size_t l_val;
#ifdef __OPENDAV_DEBUG__
char *buf;
#endif // __OPENDAV_DEBUG__
char *val;
dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr));
TRACE();
// 2013.08.27 dadamin
// SolDirve PROPFIND 시 네임스페이스 사용하기 때문에
// 해당 파일(디렉토리 경우 소속된 모든 정보)에 대해서
// RCDB 네임스페이스 관련 조회 발생으로 응답 성능 저하가
// 발생함으로 opendav 지정된(DAV:)와 기본 속성이 외에 값에
// 대해서 오퍼레이션되지 않게함
#ifndef __USE_NAMESPACE__
return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0,
"Invalid namespace declaration.");
#endif // !__USE_NAMESPACE__
/* Litmus test <aa xmlns=""> case */
/*
if(name->ns==NULL || strlen(name->ns)==0) {
return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0,
"Invalid namespace declaration.");
}
*/
/* quote all the values in the element */
/* ### be nice to do this without affecting the element itself */
/* ### of course, the cast indicates Badness is occurring here */
apr_xml_quote_elem(db->pool, (apr_xml_elem *) elem);
/* generate a text blob for the xml:lang plus the contents */
apr_xml_to_text(db->pool, elem, APR_XML_X2T_LANG_INNER, NULL,
mapping->ns_map, (const char **) &val, &l_val);
/* Warning : val[0] value is NULL, so you should use 'val+1' */
/* Let's fill fill pr */
pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns);
pr->m_propname = name->name;
pr->m_propvalue = val + 1;
if (dbms_set_dead_property(db->mdb_r, pr) != 0) {
return solbox_dav_new_error(db->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"An error occurred while getting a dead property.");
}
#ifdef __OPENDAV_DEBUG__
buf = apr_psprintf(db->pool, "I want to save [%ld:%s] [%s]",
pr->m_ns_id, pr->m_propname, pr->m_propvalue);
DBG0(buf);
#endif // __OPENDAV_DEBUG__
return NULL;
}
static dav_error *dav_repos_db_remove(dav_db * db, const dav_prop_name * name)
{
// 2013.08.27 dadamin
// SolDirve PROPFIND 시 네임스페이스 사용하기 때문에
// 해당 파일(디렉토리 경우 소속된 모든 정보)에 대해서
// RCDB 네임스페이스 관련 조회 발생으로 응답 성능 저하가
// 발생함으로 opendav 지정된(DAV:)와 기본 속성이 외에 값에
// 대해서 오퍼레이션되지 않게함
#ifndef __USE_NAMESPACE__
return solbox_dav_new_error(db->pool, HTTP_BAD_REQUEST, 0,
"Invalid namespace declaration.");
#endif // !__USE_NAMESPACE__
#ifdef __OPENDAV_DEBUG__
char *buf;
#endif // __OPENDAV_DEBUG__
dav_repos_property *pr = apr_palloc(db->pool, sizeof(*pr));
pr->m_ns_id = dbms_get_ns_id(db->mdb_r, name->ns);
pr->m_propname = name->name;
if (dbms_del_dead_property(db->mdb_r, pr) != 0) {
return solbox_dav_new_error(db->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"An error occurred while deleting a dead property.");
}
TRACE();
#ifdef __OPENDAV_DEBUG__
buf = apr_psprintf(db->pool, "I want to delete [%s] ", pr->m_propname);
DBG0(buf);
#endif // __OPENDAV_DEBUG__
return NULL;
}
static int dav_repos_db_exists(dav_db * db, const dav_prop_name * name)
{
/* Get resource records */
dav_repos_resource *dbr = db->mdb_r;
/* Build the key */
const char *key;
TRACE();
if (dbr == NULL)
return 0;
key = dav_repos_build_ns_name_key(name->ns, name->name, dbr->p);
/* Get the the prop */
if (apr_hash_get(dbr->pr_hash, key, APR_HASH_KEY_STRING))
return 1;
return 0;
}
static dav_error *dav_repos_db_first_name(dav_db * db, dav_prop_name * pname)
{
const char *key = NULL;
apr_ssize_t klen;
dav_repos_property *pr;
/* Get resource records */
dav_repos_resource *dbr = db->mdb_r;
TRACE();
if (dbr == NULL) {
pname->ns = NULL;
pname->name = NULL;
return NULL;
}
dbr->pr_hash_index = apr_hash_first(db->pool, dbr->pr_hash);
if (dbr->pr_hash_index == NULL) {
pname->ns = NULL;
pname->name = NULL;
return NULL;
}
apr_hash_this(dbr->pr_hash_index, (void *) &key, &klen, (void *) &pr);
/* Get ns and name from the key */
dav_repos_get_ns_name_key(key, pname, db->pool);
return NULL;
}
static dav_error *dav_repos_db_next_name(dav_db * db, dav_prop_name * pname)
{
const char *key = NULL;
apr_ssize_t klen;
dav_repos_property *pr;
/* Get resource records */
dav_repos_resource *dbr = db->mdb_r;
TRACE();
pname->ns = NULL;
pname->name = NULL;
if (dbr == NULL) {
return NULL;
}
/* Run first_name first */
if (dbr->pr_hash_index == NULL)
return NULL;
dbr->pr_hash_index = apr_hash_next(dbr->pr_hash_index);
/* End of hash */
if (dbr->pr_hash_index == NULL)
return NULL;
apr_hash_this(dbr->pr_hash_index, (void *) &key, &klen, (void *) &pr);
/* Get ns and name from the key */
dav_repos_get_ns_name_key(key, pname, db->pool);
return NULL;
}
static dav_error *dav_repos_db_get_rollback(dav_db * db,
const dav_prop_name * name,
dav_deadprop_rollback **
prollback)
{
TRACE();
return NULL;
}
static dav_error *dav_repos_db_apply_rollback(dav_db * db,
dav_deadprop_rollback *
rollback)
{
TRACE();
return NULL;
}
const dav_hooks_propdb dav_repos_hooks_propdb = {
dav_repos_db_open,
dav_repos_db_close,
dav_repos_db_define_namespaces,
dav_repos_db_output_value,
dav_repos_db_map_namespaces,
dav_repos_db_store,
dav_repos_db_remove,
dav_repos_db_exists,
dav_repos_db_first_name,
dav_repos_db_next_name,
dav_repos_db_get_rollback,
dav_repos_db_apply_rollback,
};