Files
interactive/fhs/sh-opendav/dbms.c
2026-08-07 17:38:18 +09:00

4684 lines
150 KiB
C

/****************************************************************************
mod_dav_pgsql (DASL) for apache 2.X
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Author : sean kim (sean@solutionbox.co.kr)
$Id: dbms.c,v 1.5 2007/02/22 08:22:12 elenoa Exp $
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
****************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <httpd.h>
#include <http_protocol.h>
#include <http_log.h>
#include <http_core.h> /* for ap_construct_url */
#include <apr.h>
#include <apr_strings.h>
#include <apr_hash.h>
#include <apr_uuid.h>
#include <apr_file_io.h>
#include <stdio.h>
//#include <libpq-fe.h>
#include "dav_repos.h"
#include "lock.h"
#include "dbms.h"
#include "util.h"
#include "share_common.h"
#include "share_fhs_stat.h"
#define DASL_PGSQL_DEBUG
#define STRING_FROM_DBENTRY(pool, element, num) \
do { \
const char *temp = apr_dbd_get_entry(db->driver, row, num); \
element = (temp == NULL ? NULL : \
apr_pstrndup(pool, temp, strlen(temp))); \
} while (0)
/**
* Show error message of SQL operations
* @param conn The database connection
* @param db_error_message_str An application level error message string
*/
void db_error_message(ap_dbd_t *db, char *message_str, int errnum)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: database: %s: (%d)%s"
, message_str
, errnum
, (errnum == 0 ? "*NONE*" : apr_dbd_error(db->driver, db->handle, errnum))
);
}
/**
* r->uri for search key
* @param d DB connection struct containing the user, password, and DB name
* @param r Out variable to hold the result
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return 1 on success, 0 for no result, -1 on fail
*/
int dbms_get_property(dav_repos_resource *db_r, bool is_uricaseignore )
{
int iret = 0;
char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char tblname[20] = {0};
if (!db_r)
return -6;
char* db_uri = NULL;
// UTF-8 -> DB client encoding 로 변환 처리
db_uri = transformDBCharacter(db_r->r, db_r->m_fake_uri, "dbms_get_property");
// 2014-04-24 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_property: at_split func fail.");
return -7;
}
// CHG 2012-03-20 유희곤
// 해당 서비스에 대해 URI 대소문자 구분, 무시 여부를 판단하여
// 무시일 경우 해당 요청을 소문자로 변환처리하여 조회 결과값을 반환한다.
char * whereParse = NULL;
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
whereParse = apr_psprintf(db_r->p, " WHERE sp_svc_tran_id = %s "
"AND depth = %d AND %s = lower('%s') "
, user_info.szVolumeID
, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_uri );
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
whereParse = apr_psprintf(db_r->p, " WHERE sp_svc_tran_id = %s "
"AND depth = %d AND uri = '%s' "
, user_info.szVolumeID, db_r->m_depth, db_uri );
}
#ifdef __PROPFIND_RANDOM_FILE__
int ntuple = 0;
int i;
unsigned int n;
bool alive = false;
/*2010.12.07 : dadamin / PROPFIND 처리시 FHS 정보 Random(파일 관련) */
// NetCache Agent 인지를 확인하기 위해 PROFPIND Header 의 User-Agent 정보 검사.
const char * userAgent = NULL;
userAgent = apr_table_get( db_r->r->headers_in, "User-Agent");
if( db_r->r->method_number == M_PROPFIND && userAgent != NULL && strncmp(userAgent, "NetCache", 8)==0 )
{
query = apr_psprintf(db_r->p,
"SELECT resource_id, "
" resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" uri, "
" filename_org, "
" filename_hash, "
" depth, "
" creation_date, "
" display_name, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length, "
" get_content_type, "
" get_lastmodified, "
" source, "
" host_name, "
" file_lastmodified, " // ADD 2010-02-16 huibong : File 속성 정보 조회
" is_cache "
"FROM %s "
"%s "
" AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname), whereParse
);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_get_property: database acquire timeout", 0);
return -2;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_get_property: random select", rv);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
ntuple = apr_dbd_num_tuples(db->driver, res);
if( ntuple == 0 )
{
iret = 0;
}
else
{
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
if( rv )
{
db_error_message(db, "dbms_get_property(1): get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -3;
}
// 디렉토리 경우 램덤 선택 필요 없음
if(atoi(apr_dbd_get_entry(db->driver, row, 1)) == 1)
{
// dir
solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
}
else
{
// file
// 해당 서버 정보 random 처리 및 서버 alive 체크
for (i = 0; i < ntuple; ++i)
{
apr_generate_random_bytes((unsigned char *)&n, sizeof(int));
n = n % ntuple;
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, n);
if( rv )
{
db_error_message(db, "dbms_get_property(2): get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -3;
}
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
if( dav_shared_du_is_alive( apr_dbd_get_entry(db->driver, row, 13) ) != 0 )
{
alive = true;
break;
}
}
// 램덤 실패 시 해당 결과 순회 후 Alive된 서버 선택
if( alive == false )
{
int first = 0;
first = n;
for ( n = first ; n < ntuple; ++n)
{
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, n);
if( rv )
{
db_error_message(db, "dbms_get_property(3): get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -3;
}
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
if(dav_shared_du_is_alive(apr_dbd_get_entry(db->driver, row, 13)) != 0)
{
alive = true;
break;
}
if( first > 0 && (n+1) >= ntuple )
{
n = -1;
ntuple = first;
first = 0;
}
}
if(alive == false)
{
// 2012.06.16 : dadamin
// NetCache 경우 Alive 된 서버가 없을 경우 에러를 리턴
//dav_repos_release_db( db_r->r, db, rv );
//return -5;
// CHG 2019-10-01 huibong 0 파일 관련 CDN 장애 회피를 위한 기능 개선 (#32812 )
// - 0 파일은 replication 을 하지 않으므로.. 해당 FHS 가 죽는 경우....
// - soldrive 에서 오류 상태로 인식하여 업로드 실패 등의 문제가 발생
// - 따라서 이를 개선하기 위해 다음과 같이 처리한다.
// -- PROPFIND 요청, agent 가 NetCache, 0 파일, 유효한 FHS 가 없는 경우
// -- 오류 가 아닌 정상 상태로 응답 처리하도록 수정.
if( atoll( apr_dbd_get_entry( db->driver, row, 9 ) ) != 0 )
{
dav_repos_release_db( db_r->r, db, rv );
return -5;
}
else
{
// NetCache agent, 파일에 대한 PROPFIND 요청, 0 파일인데.. 원본 FHS 가 죽은 경우...
// for logging
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL
, "dbms_get_property: size 0 and fhs dead. but return normal status [propfind][%s][%s]"
, db_uri, apr_dbd_get_entry( db->driver, row, 13 )
);
}
}
}
}
/*Get the data of every column of this row to a link */
db_r->m_resource_id = atoll(apr_dbd_get_entry(db->driver, row, 0));
#ifdef __OPENDISK_SOLUTION__
db_r->m_resource_type = dav_repos_change_resource_type(atoi(apr_dbd_get_entry(db->driver, row, 1)));
#else
db_r->m_resource_type = atoi(apr_dbd_get_entry(db->driver, row, 1));
#endif
db_r->m_owner_id = atoll(apr_dbd_get_entry(db->driver, row, 2));
STRING_FROM_DBENTRY(db_r->p, db_r->m_filename_org, 4);
STRING_FROM_DBENTRY(db_r->p, db_r->m_filename_hash, 5);
db_r->m_depth = atoi(apr_dbd_get_entry(db->driver, row, 6));
db_r->m_creation_date = atoll(apr_dbd_get_entry(db->driver, row, 7));
STRING_FROM_DBENTRY(db_r->p, db_r->m_displayname, 8);
db_r->m_get_content_length = atoll(apr_dbd_get_entry(db->driver, row, 9));
STRING_FROM_DBENTRY(db_r->p, db_r->m_get_content_type, 10);
// ADD 2010-02-16 huibong
// SBFS Mode : 파일 속성 중 최종 수정일자는 get_lastmodified 필드 대신 file_lastmodified 값을 사용한다.
db_r->m_get_lastmodified = atoll(apr_dbd_get_entry(db->driver, row, 14));
db_r->m_source = atoi(apr_dbd_get_entry(db->driver, row, 12));
STRING_FROM_DBENTRY(db_r->p, db_r->m_host_name, 13);
db_r->next = NULL;
iret = 1;
}
}
else
#endif //__PROPFIND_RANDOM_FILE__
{
query = apr_psprintf(db_r->p,
"SELECT resource_id, "
" resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" uri, "
" filename_org, "
" filename_hash, "
" depth, "
" creation_date, "
" display_name, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length, "
" get_content_type, "
" get_lastmodified, "
" source, "
" host_name, "
" file_lastmodified " // ADD 2010-02-16 huibong : File 속성 정보 조회
"FROM %s "
"%s "
" AND deleted_yn = 'N' AND is_cache = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname), whereParse );
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_get_property: database acquire timeout", 0);
return -2;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_get_property: select", rv);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
// 해당 정보가 존재하지 않는 경우
if( apr_dbd_num_tuples(db->driver, res) == 0 )
{
iret = 0;
}
else
{
// CHG 2012-03-20 huibong
// 아래 코드는 미사용 코드로 판단되어 우선 주석 처리함.
//if( apr_dbd_num_cols(db->driver, res) == 1 )
//{
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Parent? (in2) START ---->");
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Parent? (in2) %s ", apr_dbd_get_entry(db->driver, row, 0));
//}
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
if( rv )
{
db_error_message(db, "dbms_get_property: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -3;
}
/*Get the data of every column of this row to a link */
db_r->m_resource_id = atoll(apr_dbd_get_entry(db->driver, row, 0));
#ifdef __OPENDISK_SOLUTION__
db_r->m_resource_type = dav_repos_change_resource_type(atoi(apr_dbd_get_entry(db->driver, row, 1)));
#else
db_r->m_resource_type = atoi(apr_dbd_get_entry(db->driver, row, 1));
#endif
db_r->m_owner_id = atoll(apr_dbd_get_entry(db->driver, row, 2));
STRING_FROM_DBENTRY(db_r->p, db_r->m_filename_org, 4);
STRING_FROM_DBENTRY(db_r->p, db_r->m_filename_hash, 5);
db_r->m_depth = atoi(apr_dbd_get_entry(db->driver, row, 6));
db_r->m_creation_date = atoll(apr_dbd_get_entry(db->driver, row, 7));
STRING_FROM_DBENTRY(db_r->p, db_r->m_displayname, 8);
db_r->m_get_content_length = atoll(apr_dbd_get_entry(db->driver, row, 9));
STRING_FROM_DBENTRY(db_r->p, db_r->m_get_content_type, 10);
// ADD 2010-02-16 huibong
// SBFS Mode : 파일 속성 중 최종 수정일자는 get_lastmodified 필드 대신 file_lastmodified 값을 사용한다.
//db_r->m_get_lastmodified = atoll(apr_dbd_get_entry(db->driver, row, 13));
db_r->m_get_lastmodified = atoll(apr_dbd_get_entry(db->driver, row, 14));
db_r->m_source = atoi(apr_dbd_get_entry(db->driver, row, 12));
STRING_FROM_DBENTRY(db_r->p, db_r->m_host_name, 13);
db_r->next = NULL;
iret = 1;
}
}
dav_repos_release_db(db_r->r, db, rv);
return iret;
}
// 2018-02-13 CHG huibong
// - redirection 정보 조회시 시스템 오류, RCDB 오류, Flow 오류 등의 상황을 처리하기 위해
// - 기존 dbms_get_redirect() 함수 다시 작성 처리
// return : NULL 아닌 경우 정상
// NULL 인 경우 오류 발생했으며.. 인자로 전달한 error_code 내역 참고
// error_code : return 값이 NULL 인 경우
// 내부적으로 발생한 error 상황을 어떤 HTTP Response code 로 처리할지를 나타냄
char * dbms_get_redirect( dav_repos_resource *db_r, bool is_uricaseignore, bool is_random, int *error_code )
{
// server 설정 정보 추출.
dav_repos_server_conf *dsc = NULL;
dsc = dav_repos_get_server_conf( db_r->r->server );
if( !dsc )
{
// 시스템 설정 오류로 인한 처리 불가 상황
// 이런 경우는 일시적인 장애보다... FHS 설정 장애 또는 apache 재기동 문제 이므로....
// 명시적으로 HTTP 500 internal server 오류로 처리한다.
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: dav_repos_get_server_conf func fail." );
*error_code = HTTP_INTERNAL_SERVER_ERROR;
return NULL;
}
// UTF-8 -> DB client encoding 로 변환 처리
char *db_uri = NULL;
db_uri = transformDBCharacter( db_r->r, db_r->m_fake_uri, "dbms_get_redirect" );
// 2014-04-24 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if( at_split( db_r->r->user, &user_info ) < 0 )
{
// user 정보에 대한 인식 처리 실패, client 에서 인증 정보를 안 보낼 경우 발생 가능.
// - HTTP 400 잘못된 요청으로 처리
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: at_split func fail." );
*error_code = HTTP_BAD_REQUEST;
return NULL;
}
// CHG 2012-03-20 유희곤
// 해당 서비스에 대해 URI 대소문자 구분, 무시 여부를 판단하여
// 무시일 경우 해당 요청을 소문자로 변환처리하여 조회 결과값을 반환한다.
char * whereParse = NULL;
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
whereParse = apr_psprintf( db_r->p, " WHERE sp_svc_tran_id = %s "
"AND depth = %d AND %s = lower('%s') "
, user_info.szVolumeID
, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_uri );
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
whereParse = apr_psprintf( db_r->p, " WHERE sp_svc_tran_id = %s "
"AND depth = %d AND uri = '%s' "
, user_info.szVolumeID, db_r->m_depth, db_uri );
}
// 2012.04.19 : dadamin , 해당 쿼리 일부 응답성 개선을 위해서 GROUP BY, ORDER BY 삭제
// Redirction 처리 대상 장비 선정을 위한 Query
char tblname[20] = { 0 };
char *query;
query = apr_psprintf( db_r->p,
"SELECT host_name, is_cache, filename_hash "
"FROM %s "
"%s"
"AND deleted_yn = 'N' AND get_content_length = %" APR_INT64_T_FMT " "
, dav_get_target_table( user_info.szVolumeID, tblname ), whereParse, db_r->m_get_content_length );
ap_dbd_t *db = dav_repos_get_db( db_r->r );
if( db == NULL )
{
// DB 세션 획득 실패
// - 요청 수가 많거나... 설정값이 너무 작아 DB 세션 획득 실패 가능
// - 부하 상황으로 가정하고.. HTTP 503 값을 줘서... NetCache Client 에서 요청이 감소하도록 한다.
db_error_message( db, "dbms_get_redirect: database acquire timeout", 0 );
*error_code = HTTP_SERVICE_UNAVAILABLE;
return NULL;
}
apr_dbd_results_t *res = NULL;
int rv = apr_dbd_select( db->driver, db_r->r->pool, db->handle, &res, query, 1 );
if( rv )
{
// select query 실패시
// - DB 가 일시적으로 죽은 경우로 판단, HTTP 503 반환.
db_error_message( db, "dbms_get_redirect: select", rv );
dav_repos_release_db( db_r->r, db, rv );
*error_code = HTTP_SERVICE_UNAVAILABLE;
return NULL;
}
int ntuple = apr_dbd_num_tuples( db->driver, res );
if( ntuple < 1 )
{
// DB 조회 결과가 존재하지 않는 경우....
// - 순간적으로 삭제 처리된 경우로 판단. HTTP 404 응답
dav_repos_release_db( db_r->r, db, rv );
*error_code = HTTP_NOT_FOUND;
return NULL;
}
// NetCache 처리 관련 User-Agent 정보 추출.
const char *userAgent = NULL;
userAgent = apr_table_get( db_r->r->headers_in, "User-Agent" );
// NEW 2011-05-16 huibong
// GET 요청에 대해 FHS 제외 목록 정보를 HTTP Header 상의 Except-for : <host-name> 형식으로 전달받는 경우
// 해당 FHS 정보는 Redirect 전달 대상에서 제외시키고
// 다른 FHS 정보만을 검토하여 전달한다.
// 단 Except-for 로 전달되는 FHS 정보는 1 대로만 지정처리한다. ( 2012-01-18 다중 FHS 정보 전달 및 탐색으로 수정 처리함 )
const char * exceptFhsName = NULL;
exceptFhsName = apr_table_get( db_r->r->headers_in, "Except-for" );
if( exceptFhsName != NULL )
{
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: Except-for set [%s][%" APR_INT64_T_FMT "][%s]", db_uri, db_r->m_get_content_length, exceptFhsName );
}
// 2012.06.13 : dadamin
// Alive 체크 및 램덤 처리
apr_dbd_row_t *row = NULL;
char *retval = NULL;
// 2010.12.07 C99을 지원하는 컴파일일 경우 배열의 인자로 처리 가능 만약을 대비하여 동적할당 방식으로 수정
int *host_alive_index;
int host_alive_count = 0;
// 메모리 할당
host_alive_index = ( int * ) calloc( ntuple, sizeof( int ) );
// 메모리 할당 실패시
if( host_alive_index == NULL )
{
// FHS 목록 구성을 해서 Alive Check 를 할 수 없는 상황, 조회된 첫번째 DB row 는 존재함.
// - NetCache 인 경우 조회된 첫번째 FHS 가 살아 있는지 체크하여....
// 살아 있는 경우 해당 FHS 정보 전송, 죽은 경우 HTTP 404 전달
// - 양방향 기본은 그냥 조회된 첫번째 FHS 정보를 전달한다
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, 0 );
if( userAgent != NULL && strncmp( userAgent, "NetCache", 8 ) == 0 )
{
// except-for 에 조회된 FHS 가 존재하는 경우
if( exceptFhsName != NULL && strcasestr( exceptFhsName, apr_dbd_get_entry( db->driver, row, 0 ) ) != NULL )
{
// except-for 에 첫번재 FHS 가 포함된 경우.
// - 전송할 FHS 가 없는 경우 사전 정의된 대로.. HTTP 410 반환한다.
*error_code = HTTP_GONE;
retval = NULL;
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: memory alloc error & first include Except-for. return code 410 [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, apr_dbd_get_entry( db->driver, row, 0 ) );
}
else if( dav_shared_du_is_alive( apr_dbd_get_entry( db->driver, row, 0 ) ) != 0 ) // 해당 장비의 Alive 여부 판단.
{
// 해당 장비가 살아 있는 경우...
*error_code = 0;
retval = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 0 ) );
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: memory alloc error. but first alive. return first [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, retval );
}
else
{
// except-for 에 포함되지 않지만... 해당 장비가 죽은 경우...
// - 전송할 FHS 가 없는 경우 사전 정의된 대로.. HTTP 410 반환한다.
*error_code = HTTP_GONE;
retval = NULL;
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: memory alloc error & first dead. return code 410 [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, apr_dbd_get_entry( db->driver, row, 0 ) );
}
}
else
{
// 양방향 기본인 경우
// - 조회된 FHS 정보를 그냥 전달한다.
*error_code = 0;
retval = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 0 ) );
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: memory alloc error. default return first [%s][%" APR_INT64_T_FMT "][%s]", db_uri, db_r->m_get_content_length, retval );
}
}
else
{
// 메모리 할당 성공시
// - 조회된 FHS 정보를 해당 메모리에 저장하고... 가장 적합한 FHS 를 전달한다.
// NEW 2011-05-16 huibong
// GET 요청에 대해 FHS 제외 목록 정보를 HTTP Header 상의 Except-for : <host-name> 형식으로 전달받는 경우
// 해당 FHS 정보는 Redirect 전달 대상에서 제외시키고
// 다른 FHS 정보만을 검토하여 전달한다.
// 단 Except-for 로 전달되는 FHS 정보는 1 대로만 지정처리한다. ( 2012-01-18 다중 FHS 정보 전달 및 탐색으로 수정 처리함 )
int i;
int sourceindex = 0;
int selfindex = -1;
// 조회된 DB 결과에서 alive, except 대상이 아닌 FHS 정보를 메모리에 저장 처리
for( i = 0; i < ntuple; i++ )
{
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, i );
// 원본 FHS 인 경우 해당 row index 저장
if( strcmp( "N", apr_dbd_get_entry( db->driver, row, 1 ) ) == 0 )
{
sourceindex = i;
}
// CHG 2012-01-18 huibong
// 조회된 목록 중 제외 FHS 가 존재하는 경우 해당 장비는 Redirect 전달 대상에서 제외시킨다. ( 대소문자 구문 안함 )
// 단, 전달된 제외 FHS 목록이 blank 로 구분되는 다중 FHS 목록이므로...
// DB 조회 값이 제외 FHS 목록상에 존재하는지 기존과 같은 비교가 아니라 검색으로 방식을 변경처리한다.
// - 현재 장비가 except-for 에 등록된 경우.. 포함되지 않도록 하기 위해.. 아래 현재 장비 check 보다 먼저 수행한다.
if( exceptFhsName != NULL && strcasestr( exceptFhsName, apr_dbd_get_entry( db->driver, row, 0 ) ) != NULL )
{
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: target excepted by Except-for Header [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, apr_dbd_get_entry( db->driver, row, 0 ) );
continue;
}
// except-for 에 포함 안되고.. 현재 장비인 경우
if( strcmp( dsc->host_name, apr_dbd_get_entry( db->driver, row, 0 ) ) == 0 )
{
selfindex = i;
// Random 처리 인 경우 해당 장비에 파일이 존재해도 random 처리 한다.
if( is_random == false )
{
// random 처리가 아닌 경우.. 현재 장비 정보 반환 처리하고 끝낸다.
*error_code = 0;
retval = apr_pstrdup( db_r->p, dsc->host_name );
db_r->m_filename_hash = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 2 ) );
// 메모리 해제
free( host_alive_index );
// 마무리 후 반환
dav_repos_release_db( db_r->r, db, rv );
return retval;
}
}
// 최종.. 정리할 거 다 하고...해당 장비가 Alive 상태인 경우
if( dav_shared_du_is_alive( apr_dbd_get_entry( db->driver, row, 0 ) ) != 0 )
{
// 해당 장비가 alive 상태인 경우.. 메모리에 저장 처리.
host_alive_index[host_alive_count] = i;
host_alive_count++;
}
}
// alive 장비가 없는 경우...
if( host_alive_count <= 0 )
{
// NetCache 의 Content 요청인 경우
if( db_r->m_resource_type == 0 && userAgent != NULL && strncmp( userAgent, "NetCache", 8 ) == 0 )
{
// 2012.06.13 : dadamin
// NetCache 경우 Alive 된 목록이 없을 시 NULL 리턴하며,
// 해당 장비에 파일이 존재하면 서비스 될 수 있게 한다.
// 위에서 현재 장비가 except-for 에 등록되어 있는 경우는 selfindex 값이 처리 안되므르....
// 현재 장비가 except-for 에 포함 안된 경우 임.
if( selfindex >= 0 )
{
// 현재 장비에 파일 존재하는 경우..
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, selfindex );
*error_code = 0;
retval = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 0 ) );
db_r->m_filename_hash = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 2 ) );
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: alive target nothing. return My self [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, retval );
}
else
{
// alive 장비가 전혀 없는 경우...
// - 전송할 FHS 가 없는 경우 사전 정의된 대로.. HTTP 410 반환한다.
// 참고사항
// - ntuple 값을 이용하여 원본만 존재하는지, 복제본까지 존재하는지 예측 가능
// - 해당값을 이용하여 원본만 존재하고 FHS 죽은 경우 HTTP 410 반환
// - 원본, 복제본이 다 죽은 경우 Backup RC 로 넘어가도록 HTTP 500 반환하려 했으나...
// 관련 담당자들이 해당 발생 확률 낮고.. Backup 이 없는 경우 Backup 으로 넘어가서 서비스 장애를 발생시키는게 더 문제라고 함
// - Backup failover 는 본 건 아니어도 SolDrive, SolProxy 에서 connection 처리를 이용하여 판단하므로.. 신경 쓸 필요 없다고 함.
// - 그래서 관련 담당자들과 협의하에 원본, 복제본이 다 죽은 경우에도 HTTP 410 처리하는 것으로 최종 협의함.
*error_code = HTTP_GONE;
retval = NULL;
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: alive target nothing. return code 410 [%s][%" APR_INT64_T_FMT "]"
, db_uri, db_r->m_get_content_length );
}
}
else
{
// 양방향 기본
// - alive 장비가 없는 경우... 원본 장비 정보를 반환한다.
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, sourceindex );
*error_code = 0;
retval = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 0 ) );
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: alive target nothing. default return first [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, retval );
}
}
else
{
// alive 장비가 존재하는 경우
// 장비가 다중인 경우 => Random 장비를 선택하여 전송한다.
unsigned int n;
apr_generate_random_bytes( ( unsigned char * ) &n, sizeof( int ) );
n = n % host_alive_count;
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, host_alive_index[n] );
*error_code = 0;
retval = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 0 ) );
// 2012.05.03, dadamin
// 램덤 처리 경우 해당 장비가 원본이 아닌 경우 저장 위치가 다를 수 있으므로
// 해당 파일위치를 다시 한 번 더 저장함
db_r->m_filename_hash = apr_pstrdup( db_r->p, apr_dbd_get_entry( db->driver, row, 2 ) );
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_redirect: alive target random select [%s][%" APR_INT64_T_FMT "][%s]"
, db_uri, db_r->m_get_content_length, retval );
}
// 메모리 해제
free( host_alive_index );
}
dav_repos_release_db( db_r->r, db, rv );
// 최종 결과 반환
return retval;
}
// NEW 2011-03-23 dadamin
// 각 디렉토리 서비스 용량정보( Total, 현재사용량, Used 용량)를 조회하기 위한 함수(단 t_sms_sp_svc_product의 cal_used_depth 기준)
// tran_id [in] 서비스 Tran ID 정보
// is_uricaseignore URI 에 대한 대소문자 구분 여부, true : 대소문자 무시, false: 대소문자 구분
// total_byte [out] 해당 서비스 Tran ID 의 Total 스토리지 계약 용량 정보
// used_tbyte [out] 해당 uri가 사용하고있는 용량 정보
// return 오류발생시 -1, 해당정보가 존재하지 않는 경우 0, 정상 처리된 경우 1.
int dbms_get_service_quotaex( const dav_repos_resource * db_r, const char * tran_id, bool is_uricaseignore, apr_int64_t * total_byte, apr_int64_t * used_byte )
{
ap_dbd_t * db = NULL;
char * query = NULL;
int rv;
apr_dbd_results_t * res = NULL;
apr_dbd_row_t * row = NULL;
char tblname[20] = {0};
// 전달받은 인자값 확인, 인자값이 유효하지 않은 경우 -1 을 반환
if( tran_id == NULL || total_byte == NULL || used_byte == NULL )
return -1;
// 2014-04-24 : dadamin
// where 구문에 기준값, depth 추가
// CHG 2012-03-20 유희곤
// 해당 서비스에 대해 URI 대소문자 구분, 무시 여부를 판단하여
// 무시일 경우 해당 요청을 소문자로 변환처리하여 조회 결과값을 반환한다.
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
// CHG 2013-10-07 dadamin
// 삭제후 재생성된 디렉토리에 대해서 422 에러 방지를 위해서 삭제 플래그 검사 쿼리 추가
query = apr_psprintf( db_r->p,
"SELECT T.*, SUM(R.dir_used) FROM ("
" SELECT R.max_str_size, R.cal_used_depth, L.uri, L.depth, L.deleted_yn"
" FROM %s L"
" JOIN t_sms_sp_svc_product R"
" ON L.sp_svc_tran_id = R.sp_svc_tran_id "
" WHERE L.sp_svc_tran_id = %s AND L.depth = %d "
"AND %s = lower('%s') AND L.deleted_yn = 'N') T "
"LEFT JOIN t_dav_use_dir R "
"ON %s "
"GROUP BY T.max_str_size, T.cal_used_depth, T.uri, T.deleted_yn, T.depth"
, dav_get_target_table(tran_id, tblname), tran_id, db_r->m_depth
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(L.uri)" : "L.uri"
, db_r->m_fake_uri
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(T.uri) = lower(R.path_name)" : "T.uri = R.path_name"
);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
// CHG 2013-10-07 dadamin
// 삭제후 재생성된 디렉토리에 대해서 422 에러 방지를 위해서 삭제 플래그 검사 쿼리 추가
query = apr_psprintf( db_r->p,
"SELECT T.*, R.dir_used FROM ("
" SELECT R.max_str_size, R.cal_used_depth, L.uri, L.depth, L.deleted_yn"
" FROM %s L"
" JOIN t_sms_sp_svc_product R"
" ON L.sp_svc_tran_id = R.sp_svc_tran_id "
" WHERE L.sp_svc_tran_id = %s AND L.depth = %d "
"AND L.uri = '%s' AND L.deleted_yn = 'N') T "
"LEFT JOIN t_dav_use_dir R "
"ON T.uri = R.path_name "
, dav_get_target_table(tran_id, tblname), tran_id, db_r->m_depth, db_r->m_fake_uri
);
}
// Query 실행
db = dav_repos_get_db( db_r->r );
if(db == NULL)
{
db_error_message(db, "dbms_get_service_quotaex: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
// Query 실행 실패시, -1 값을 반환함.
if( rv != 0 )
{
db_error_message(db, "dbms_get_service_quotaex: select", rv );
dav_repos_release_db( db_r->r, db, rv );
return -1;
}
// Query 결과 데이터가 존재하지 않는 경우, 0 값을 반환함.
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, 0);
if( rv != 0 )
{
db_error_message(db, "dbms_get_service_quotaex: get row", rv );
dav_repos_release_db( db_r->r, db, rv );
return 0;
}
// 2012.09.03 : dadamin
// 용량 산정이 되지 않을 경우 사용량을 0으로 리턴
// 요청 경로(depth)에 depth가 용량 산정(cal_used_depth)에 depth 보다 크면 422 리턴
// 삭제된 경우라면 상위 로직에서 404 에러 리턴되므로 해당 체크 필요 없음
// error : different depth
if( strcmp(apr_dbd_get_entry(db->driver, row, 1), apr_dbd_get_entry(db->driver, row, 3)) < 0 )
{
dav_repos_release_db( db_r->r, db, rv );
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_service_quotaex: cal_used_depth and depth are different.[%s]", db_r->m_fake_uri);
return 0;
}
// 서비스 계약 용량 및 사용가능용량(Free)을 Byte 단위로 계산처리.
*total_byte = atoll( apr_dbd_get_entry(db->driver, row, 0));
*used_byte = atoll( apr_dbd_get_entry(db->driver, row, 5));
// DB release 처리 및 1 을 반환.
dav_repos_release_db( db_r->r, db, rv );
return 1;
}
/**
* Inserts a resource into the dasl_resource table
* @param d DB connection struct containing the user, password, and DB name
* @param r The resource to insert
* @param lserialno The serial number assigned to the resource when inserted
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return 0 if success, -1 if fail
*/
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가를 위해 본 함수를 수정 처리
// 그 외 로깅 처리 내역 보강.
static int db_insert_resource(const dav_repos_resource * db_r, apr_int64_t *resource_id, const dav_resource * resource, bool is_uricaseignore )
{
char *query = NULL;
acct_info user_info;
dav_repos_server_conf *dsc;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
int nrows;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// path depth 추출 로직 삭제 : 상위 로직에서 해당값을 추출하여 가지고 있음
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "db_insert_resource: at_split func fail.");
return -1;
}
dsc = dav_repos_get_server_conf(db_r->r->server);
if( !dsc )
{
// conf 정보를 가져오지 못한 경우.
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "db_insert_resource: dav_repos_get_server_conf func fail.");
// CHG 2012-03-15 huibong
// 본 함수를 사용하는 코드에서는 -1 을 반환할 경우에만 오류로 처리...
// 따라서 아래 코드는 잘못되었으므로 수정 처리
//return -5;
return -1;
}
// CHG 2010-01-19 huibong
// file_lastmodified column info insert ( equal to creation_date info)
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분 무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf(db_r->p,
"INSERT INTO %s ( "
" resource_type,"
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id,"
#else
" sp_user_seq, sp_svc_tran_id,"
#endif
" uri,"
" filename_org,"
" filename_hash,"
" depth,"
" creation_date,"
" display_name,"
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length,"
" get_content_type,"
" get_lastmodified,"
" file_lastmodified," // ADD 2010-01-19 huibong
" source,"
" host_name,"
" deleted_yn ) "
"VALUES "
" ( %d , %s, %s, lower('%s'), '%s', '%s', %d, %" APR_INT64_T_FMT ", '%s', %" APR_INT64_T_FMT ", '%s', %" APR_INT64_T_FMT ", %" APR_INT64_T_FMT ", %d, '%s', 'N' ) "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r->m_resource_type
#ifdef __OPENDISK_SOLUTION__
, user_info.szVolumeID, user_info.szVolumeID
#else
, user_info.szUserID, user_info.szVolumeID
#endif
, db_r->m_fake_uri
, db_r->m_filename_org
, db_r->m_filename_hash
, db_r->m_depth
, db_r->m_creation_date
, db_r->m_displayname
, db_r->m_get_content_length
, db_r->m_get_content_type
, db_r->m_get_lastmodified
, db_r->m_get_lastmodified
, db_r->m_source
, dsc->host_name
);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf(db_r->p,
"INSERT INTO %s ( "
" resource_type,"
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id,"
#else
" sp_user_seq, sp_svc_tran_id,"
#endif
" uri,"
" filename_org,"
" filename_hash,"
" depth,"
" creation_date,"
" display_name,"
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length,"
" get_content_type,"
" get_lastmodified,"
" file_lastmodified," // ADD 2010-01-19 huibong
" source,"
" host_name,"
" deleted_yn ) "
"VALUES "
" ( %d , %s, %s,'%s', '%s', '%s', %d, %"APR_INT64_T_FMT ", '%s', %" APR_INT64_T_FMT ", '%s', %" APR_INT64_T_FMT ", %" APR_INT64_T_FMT ", %d, '%s', 'N' ) "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r->m_resource_type
#ifdef __OPENDISK_SOLUTION__
, user_info.szVolumeID, user_info.szVolumeID
#else
, user_info.szUserID, user_info.szVolumeID
#endif
, db_r->m_fake_uri
, db_r->m_filename_org
, db_r->m_filename_hash
, db_r->m_depth
, db_r->m_creation_date
, db_r->m_displayname
, db_r->m_get_content_length
, db_r->m_get_content_type
, db_r->m_get_lastmodified
, db_r->m_get_lastmodified
, db_r->m_source
, dsc->host_name
);
}
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "db_insert_resource: database acquire timeout", 0);
return -1;
}
// insert query 실행
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
// insert query 실패 발생시
db_error_message(db, "db_insert_resource: insert fail.", rv);
dav_repos_release_db(db_r->r, db, rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "db_insert_resource: insert query fail.");
return -1;
}
// 2012-04-04 dadamin : 세션 해지 기능 삭제 처리
// 동일 세션에 대해서 해당 시퀀스 마지막 값을 요청해야 하기 때문에 해당 세션을 계속 유지하여 사용
// INSERT 처리한 row 에 대한 resource_id 값을 조회하여 인자로 반환.
// 2012-03-15 huibong
// insert 작업 후 resource_id 조회 기능은 현재 pgpool 전환으로 인해 의미가 없지만..
// 향후 resource_id 정보 재사용을 고려하고 있으므로 현재 방식 그대로 유지한다.
query = NULL;
query = apr_psprintf(db_r->p, "SELECT last_value FROM t_dav_resource_resource_id_seq ");
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "db_insert_resource: select", rv);
dav_repos_release_db(db_r->r, db, rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "db_insert_resource: sequence select query fail.");
return -1;
}
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
if( rv )
{
db_error_message(db, "db_insert_resource: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "db_insert_resource: sequence select fetch fail.");
return -1;
}
*resource_id = atoll(apr_dbd_get_entry(db->driver, row, 0)) + 1;
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/**
* Set a property on a resource
* @param d DB connection struct containing the user, password, and DB name
* @param r Identifies the resource to set the property on r->uri.
* Contains the live property and value to set.
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return The serial number of the resource, or -1 on fail
*/
// CHG 2012.07.12 dadamin
// close 관련 구분 인자 추가
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가를 위해 본 함수를 수정 처리
// 그 외에 함수 상에 불필요한 소스 정리 처리
// CHG 2014.07.07 dadamin
// flag 인자 추가(write trunc 경우에 대한 사이즈 오류 방지)
// CHG 2015.06.04 dadamin
// end_pos 인자 추가 (요청 처리 후 file end position 추가)
apr_int64_t dbms_set_property(dav_repos_resource *db_r, const dav_resource *resource, bool is_uricaseignore, bool is_close, int flag, apr_off_t end_pos)
{
char *query = NULL;
apr_int64_t l_resource_id = 0;
char tmpOrgURI[ MaxSizeOfFileNameLength + MaxSizeOfFileNameLength ];
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
int nrows;
bool is_insert = false;
dav_repos_server_conf *dsc;
char tblname[20] = {0};
dsc = dav_repos_get_server_conf( db_r->r->server );
if( !dsc )
{
// conf 정보를 가져오지 못한 경우.
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: dav_repos_get_server_conf func fail.");
// CHG 2012-03-15 huibong
// 본 함수를 사용하는 코드에서는 -1 을 반환할 경우에만 오류로 처리...
// 따라서 아래 코드는 잘못되었으므로 수정 처리
//return -7;
return -1;
}
// 2014-04-24 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: at_split func fail.");
return -1;
}
// CHG 2012-03-23 huibong
// 서비스별 URI 대소문자 구분/무시 기능 추가
// 요청한 URI 가 기존에 존재하는지 확인
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"SELECT resource_id "
"FROM %s "
"WHERE sp_svc_tran_id = %s AND depth = %d AND %s = lower('%s') "
" AND deleted_yn = 'N' "
" AND is_cache = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
,user_info.szVolumeID
, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri );
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"SELECT resource_id "
"FROM %s "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' "
" AND deleted_yn = 'N' "
" AND is_cache = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri );
}
db = dav_repos_get_db( db_r->r );
if(db == NULL)
{
db_error_message(db, "dbms_set_property: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_set_property: select query fail.", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
nrows = apr_dbd_num_tuples(db->driver, res);
// 2012.07.13 dadamin
// rows == 0 && close 이면 config의 DavProviderCloseInsert On 일때
// 해당 rows를 insert 처리 한다.
if(is_close)
{
// 존재하는 경우 update
if( nrows > 0 )
{
is_insert = false;
}
else
{
// 존재 하지 않을 때
// config 상 DavProviderCloseInsert On 일때 insert 처리
if( dsc->close_insertoff )
{
// error 리턴
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: Close & Not Fond Mate info.[%s]", db_r->m_fake_uri);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
else
{
is_insert = true;
//단순 logging
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: Close & insert[%s]", db_r->m_fake_uri);
}
}
}
else
{
if( nrows == 0)
{
// 신규 생성
is_insert = true;
}
else
{
// open 이면서, rows 가 존재하는 경우
// rows 1개인 경우 : 이어 올리기, range put
// rows 2개 이상인 경우 : 동일한 시각대 동일한 파일에 대한 요청
is_insert = false;
}
}
// 요청한 URI 가 Meta 상에 존재하지 않는 경우 -> 신규로 insert 처리
if( is_insert )
{
// 기존 RCDB 연결 해제
dav_repos_release_db(db_r->r, db, rv);
// RCDB 상에 해당 URI 정보를 INSERT 처리
// CHG 2012-03-23 huibong
// db_insert_resource 함수상에 대소문자 구분 여부 정보를 인자로 전달토록 수정..
// 하지만 NTFS 와 동일하게 나타나도록 하기 위해서는 입력 받은 값을 그대로 저장 처리한다.
// 따라서 서비스에 상관없이 is_uricaseignore 값을 항상 false 로 처리하여... 대소문자가 구분된 상태로 INSERT 되도록 한다.
//if( db_insert_resource( db_r, &l_resource_id, resource, false ) != 0 )
// 2014.06.12 dadamin
// 신규 형상(9.3)에서 대소문자 구분 기능을 display name 컬럼을 연계하여 지원하며,
// 기존 uri에 lower된 값을 저장하기 위해서 대소문자 구분값을 전달한다.
// 단, 기존 형상 지원을 위해서 기존 형상인 경우 기존과 동일하게 false 전달
if( dav_use_display_name() == 0)
is_uricaseignore = false;
if( db_insert_resource( db_r, &l_resource_id, resource, is_uricaseignore ) != 0 )
{
// RCDB INSERT 작업 실패시
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: db_insert_resource func fail.");
// CHG 2012-03-15 huibong
// 본 함수를 사용하는 코드에서는 -1 을 반환할 경우에만 오류로 처리...
// 따라서 아래 코드는 잘못되었으므로 수정 처리
//return -2;
return -1;
}
else
{
// RCDB INSERT 작업 성공시 해당 resouce_id 필드 값을 반환.
return l_resource_id;
}
}
else // 요청한 URI 정보가 이미 Meta 상에 존재하는 경우 -> 기존 정보를 update 처리
{
// 앞의 SELECT Query 에서 나온 결과 중
// 첫번째 결과 값의 resource_id 값 정보를 반환 처리
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, 0 );
if( rv )
{
// DB Fectch 작업시 오류가 발생한 경우
db_error_message(db, "dbms_set_property: get_row function fail.", rv);
dav_repos_release_db(db_r->r, db, rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: solbox_apr_dbd_get_row func fail.");
// CHG 2012-03-15 huibong
// 본 함수를 사용하는 코드에서는 -1 을 반환할 경우에만 오류로 처리...
// 따라서 아래 코드는 잘못되었으므로 수정 처리
//return -3;
return -1;
}
// 반환값으로 사용할 resource_id 정보 추출.
l_resource_id = atoll(apr_dbd_get_entry(db->driver, row, 0));
// RCDB 연결 해제
dav_repos_release_db(db_r->r, db, rv);
// NEW 2019-02-20 huibong RCDB deadlock 을 발생시키는 불필요한 폴더 정보 업데이트 상황 발생 회피 (#32499)
// - MKCOL 요청에 대해
// - 해당 폴더가 존재하지 않는 경우.. 본 함수가 호출되어 INSERT QUERY 가 수행됨.
// - 해당 폴더가 존재하는 경우.. Apache 기본 DAV 에서 HTTP 405 Method Not Allowed 응답 처리됨.
// - 아래의 폴더 정보 UPDATE 가 호출되는 상황은 전혀 예상치 못한 상황임
// 1. MKCOL 요청에 대해 Apache 기본 DAV 에서 1차로 확인시 해당 폴더가 존재하지 않아..
// 2. 이에 대한 생성을 위해 dav_repos_create_collection() -> dbms_set_property() 순으로 호출..
// 3. 그런데.. 본 함수인 dbms_set_property() 에서 확인시 존재하지 않던 폴더가 갑자기 존재하여...
// 4. 전혀 예상치 않은 폴더에 대한 UPDATE query 가 수행됨 ( 아래의 UPDATE query 는 실제로 파일에 대한 크기 갱신을 위한 UPDATE 처리 구문임)
// - 폴더에 대한 업데이트 상황은 비상식적인 고객사 user 들이 거의 동시에 폴더에 대한 MKCOL 을 전송하면서
// 아주 희박하던 폴더 업데이트가 동시에 발생하여 DB deadlock 발생. 이로 인해 최종 응답은 HTTP 500 이 발생.
// - 따라서 이미 생성된 폴더에 대해 정보를 다시 업데이트할 필요 없으므로...
// 대상이 폴더인 경우.. 바로 반환 처리하여 아래의 update flow 가 동작하지 않도록 한다.
if( db_r->m_resource_type == 1 )
{
return l_resource_id;
}
// 문자열 형식 변경 처리
dav_repos_replace_unsafe_chars(db_r->m_filename_org, tmpOrgURI);
// NEW 2012-03-15 huibong
// 기존 Data 에 대한 UPDATE 처리시..
// 기존 Data 가 2건 이상 존재할 경우 향후 문제점 분석 등을 위해 로깅 처리한다.
if( nrows > 1 )
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: update row multiple.[%s][%d][%s]"
, (is_uricaseignore == true ? "ignore case-sensitive" : "case-sensitive"), nrows, db_r->m_fake_uri );
}
apr_int64_t get_content_length = db_r->m_get_content_length;
// 2014.01.09 dadamin
// DB Pool 획득 전후 수행하던 로직은 Pool획득 이후로 수정함
// write close 시 파일 사이즈 확인 필요
if(db_r->m_resource_type == 0 && is_close)
{
struct stat fs;
int stat_ret = 0;
memset(&fs , 0x00 , sizeof(struct stat));
stat_ret = lstat ( db_r->m_filename_hash, &fs ) ;
if(stat_ret < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: lstat func fail[%d]. uri[%s][%" APR_INT64_T_FMT "] name[%s][%" APR_OFF_T_FMT "] err[%d][%s]"
, stat_ret
, db_r->m_fake_uri, get_content_length
, db_r->m_filename_hash, fs.st_size
, errno, strerror(errno)
);
}
else
{
get_content_length = fs.st_size;
}
// 2015.06.04 dadamin
// 현재 요청에 대한 처리 후 파일크기와 물리적인 파일 크기 동일한지 비교
// 이를 통해서 멀티 블록 업로드 시 불필요한(?) DB 작업을 줄임
if (get_content_length != end_pos)
{
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: write end and skip update. uri[%s][%" APR_OFF_T_FMT "] name[%s][%" APR_OFF_T_FMT "]."
// , db_r->m_fake_uri, end_pos
// , db_r->m_filename_hash, fs.st_size
// );
return l_resource_id;
}
}
// 2014.06.16 dadamin
// 완료 후 업로드 size 고객사로 보낼 때 해당 값이 '0' 보내지는 버그 수정
db_r->m_get_content_length = get_content_length;
// 2014.08.24 dadamin
// buffer overflow 발생으로 해당 크기 변경함
// 2014.07.07 dadamin
// write trunc 경우에 대한 사이즈 오류 개선
char szLengthSql[255] = {0};
if((flag & APR_TRUNCATE) != APR_TRUNCATE)
{
// 2014.01.08 dadamin
// Soldrive 경우 병렬 블록 쓰는 기능 때문에 논리적인, 물리적인 다른 경우가 발생하며,
// Pool 획득 후 로컬 파일 사이즈 재체크로도 해당 문제를 해결되지 않아서,
// 파일 크기 줄어드는 경우가 없기 때문에 항상 큰 값을 유지할 수 있게 수정함
sprintf(szLengthSql, "GREATEST( %" APR_INT64_T_FMT ", get_content_length )", db_r->m_get_content_length);
}
else
{
sprintf(szLengthSql, "%" APR_INT64_T_FMT, db_r->m_get_content_length );
}
// CHG 2010-03-19 webting
// Meta 정보 업데이트시 get_lastmodified 값을 기존 조회된 값을 사용토록 되어 있음.
// 이로 인해 replication 생성 등의 여러가지 문제점이 발생하여..
// 기존 정보 변경 update 시 get_lastmodified 값이 현재값으로 설정되도록 수정 처리함.
// 변경전/후: db_r->m_get_lastmodified => apr_time_now()
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET "
" resource_type = %d, "
" filename_org = '%s', "
" filename_hash = '%s', "
" depth = %d, "
" creation_date = %" APR_INT64_T_FMT ", "
// 2015.06.11 : 불필요한 display_name 컬럼 업데이트 삭제
//" display_name = '%s', "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length = %s, "
" get_content_type = '%s', "
" get_lastmodified = %" APR_TIME_T_FMT ", "
" source = %d, "
" host_name = '%s' "
"WHERE "
" sp_svc_tran_id = %s AND depth = %d AND"
" %s = lower('%s') AND host_name = '%s' AND filename_hash = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r->m_resource_type
, tmpOrgURI
, db_r->m_filename_hash
, db_r->m_depth
, db_r->m_creation_date
//, db_r->m_displayname
, szLengthSql
, db_r->m_get_content_type
, apr_time_now()
, db_r->m_source
, dsc->host_name
, user_info.szVolumeID
, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
, dsc->host_name
, db_r->m_filename_hash );
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET "
" resource_type = %d, "
" filename_org = '%s', "
" filename_hash = '%s', "
" depth = %d, "
" creation_date = %" APR_INT64_T_FMT ", "
// 2015.06.11 : 불필요한 display_name 컬럼 업데이트 삭제
//" display_name = '%s', "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" get_content_length = %s, "
" get_content_type = '%s', "
" get_lastmodified = %" APR_TIME_T_FMT ", "
" source = %d, "
" host_name = '%s' "
"WHERE "
" sp_svc_tran_id = %s AND depth = %d AND"
" uri = '%s' AND host_name = '%s' AND filename_hash = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r->m_resource_type
, tmpOrgURI
, db_r->m_filename_hash
, db_r->m_depth
, db_r->m_creation_date
//, db_r->m_displayname
, szLengthSql
, db_r->m_get_content_type
, apr_time_now()
, db_r->m_source
, dsc->host_name
, user_info.szVolumeID
, db_r->m_depth
, db_r->m_fake_uri
, dsc->host_name
, db_r->m_filename_hash);
}
/*Execute the update command */
db = dav_repos_get_db( db_r->r );
if(db == NULL)
{
db_error_message(db, "dbms_set_property: database acquire timeout", 0);
return -1;
}
// Update Query 실행
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
// Query 실행 실패시
db_error_message(db, "dbms_set_property: update", rv);
dav_repos_release_db(db_r->r, db, rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_set_property: update query fail.");
return -1;
}
dav_repos_release_db(db_r->r, db, rv);
return l_resource_id;
}
}
/**
* Checks a resource by its serialno whether it is in the resource link or not if exists, set locate_resource to the pointer of the resource whose serialno is 'serialno'
* @param bd_r A linked list of resources to check
* @param serialno The serial number of the resource to look for
* @param resource_pointer Out variable which points to the resource, if found
* @return 1 if the resource exists, otherwise 0
*/
static int resource_in_link(dav_repos_resource * db_r, apr_int64_t resource_id, dav_repos_resource ** locate_resource)
{
dav_repos_resource *resource_pointer = NULL;
resource_pointer = db_r;
while (resource_pointer != NULL)
{
if (resource_pointer->m_resource_id == resource_id)
{
*locate_resource = resource_pointer;
return 1;
}
resource_pointer = resource_pointer->next;
}
*locate_resource = NULL;
return 0;
}
/**
* Inserts a dead property struct into the dead property list of the current resource node, if name does exist in the dead property list
* @param db_r The resource to add the property to
* @param resource_node ???
* @param name The name of the property to add
* @param value The value of the property to add
*/
static void add_dead_property_inlink(dav_repos_resource * db_r, dav_repos_resource * resource_node, char *name, char *value)
{
dav_repos_resource *presource_node = resource_node;
dav_repos_property *pproperty_node = NULL;
/*Is the previous node of pproperty_node */
dav_repos_property *pupper_property = NULL;
dav_repos_property *pnew_property = NULL;
pproperty_node = presource_node->pr;
pupper_property = presource_node->pr;
/*check whether the property with the name 'name' exists
*in the property link or not*/
while ((pproperty_node != NULL) && (apr_strnatcmp(pproperty_node->m_propname, name) != 0))
{
pupper_property = pproperty_node;
pproperty_node = pproperty_node->next;
}
if( pproperty_node == NULL )
{
/*'name' does not exist, so add a new property node */
pnew_property = apr_pcalloc(db_r->p, sizeof(*pnew_property));
pnew_property->m_propname = apr_pstrndup(db_r->p, name, sizeof(name));
pnew_property->m_propvalue = apr_pstrndup(db_r->p, value, sizeof(value));
pnew_property->next = NULL;
if (presource_node->pr == NULL) /*Property link is originally empty */
presource_node->pr = pnew_property;
else /*Add the new node to the tail of the link */
pupper_property->next = pnew_property;
}
}
/**
* Execute the search query and return the search result in the link db_r including property link in db_r
* @param d DB connection struct containing the user, password, and DB name
* @param search_command SQL query to execute, the serialno field must always appear in fields of the search_command
* @param db_r Out variable containing the result of the search. The result starts from db_r->next
* @return 0 on success, -1 on failure
*/
int dbms_search(char *query, dav_repos_resource *db_r)
{
int tup = 0;
int iret = 0;
int bfields_got = 0;
unsigned int i = 0;
unsigned int j = 0;
unsigned int num_fields = 0;
char szRealURI[MaxSizeOfPathLength];
dav_repos_server_conf *dsc;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
/* Pointer to the tail of the resource link */
struct dav_repos_resource *pr_tail = NULL;
/* Pointer to the new item of resource */
struct dav_repos_resource *pnew_link_item = NULL;
/* Pointer to resource in the link currently being set */
struct dav_repos_resource *presource_current_set = NULL;
dsc = dav_repos_get_server_conf(db_r->r->server);
if( !dsc )
{
return -7;
}
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_search: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_search: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
pr_tail = db_r;
presource_current_set = db_r;
pr_tail->next = NULL;
pr_tail->pr = NULL;
tup = apr_dbd_num_tuples(db->driver, res);
/* Deal with every records from the search result */
for( i = 0; i < tup; i++ )
{
int resource_exists = 0; /*resource exists in the resource link */
apr_int64_t resource_id = 0; /*resource_id */
if( bfields_got == 0 ) /*not got the fields yet */
{
/*Get the fields of the search command, because the fields in the command are not fixed*/
num_fields = apr_dbd_num_cols(db->driver, res);
if (num_fields == 0)
{
db_error_message(db, "dbms_search: field zero", 0);
dav_repos_release_db(db_r->r, db, rv);
return -2;
}
bfields_got = 1;
}
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, i);
if( rv )
{
db_error_message(db, "dbms_search: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
/*Check where resource has existed in the resource link */
resource_id = atoll(apr_dbd_get_entry(db->driver, row, 0));
resource_exists = resource_in_link(db_r->next, resource_id, &presource_current_set);
if( resource_exists == 0 ) /*Resource not in the resource link */
{
/*Resource not the resource link then create a new struct node Malloc a new structure */
pnew_link_item = apr_pcalloc(db_r->p, sizeof(*pnew_link_item));
pr_tail->next = pnew_link_item;
pr_tail = pnew_link_item;
/*Set value of the record by every field */
for( j = 0; j < num_fields; j++ )
{
/*i is the number of the column starting from 0 */
/*Get the data of every column of this row to a link */
#define SEARCH_COMPARE_INDEX(index) \
apr_strnatcasecmp(apr_dbd_get_name(db->driver, res, j), index)
if( SEARCH_COMPARE_INDEX("resource_id") == 0) {
pr_tail->m_resource_id = atoll(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("filename_org") == 0) {
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_filename_org, j);
}
else if( SEARCH_COMPARE_INDEX("filename_hash") == 0) {
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_filename_hash, j);
}
else if( SEARCH_COMPARE_INDEX("uri") == 0)
{
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_fake_uri, j);
remove_user_root_dir_from_fake_uri(pr_tail->m_uri, szRealURI);
pr_tail->m_uri = apr_psprintf(db_r->p, "%s%s", dsc->base_uri, szRealURI);
}
else if( SEARCH_COMPARE_INDEX("creation_date") == 0)
{
pr_tail->m_creation_date = atoll(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("display_name") == 0) {
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_displayname, j);
}
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
else if( SEARCH_COMPARE_INDEX("get_content_type") == 0) {
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_get_content_type, j);
}
else if( SEARCH_COMPARE_INDEX("get_content_length") == 0) {
pr_tail->m_get_content_length =
atol(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("get_lastmodified") == 0) {
pr_tail->m_get_lastmodified =
atoll(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("resource_type") == 0) {
pr_tail->m_resource_type =
atoi(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("source") == 0) {
pr_tail->m_source =
atoi(apr_dbd_get_entry(db->driver, row, j));
}
else if( SEARCH_COMPARE_INDEX("depth") == 0 )
{
pr_tail->m_depth = atoi(apr_dbd_get_entry(db->driver, row, j));
}
} /*End of for every field */
/*Used when setting dead properties */
presource_current_set = pr_tail;
}
/*deal with the dead property section in this row */
j = 0;
/*Locate the dead properties, 'name' and 'value', in the query command */
while( (j < num_fields) && (SEARCH_COMPARE_INDEX("name") != 0))
{
j++;
}
#undef SEARCH_COMPARE_INDEX
if( j < num_fields)
{
/* Found the name field */
/* Insert a dead property node to the dead property link
* in the current resource node, if name does exist in the
* dead property link*/
add_dead_property_inlink(db_r, presource_current_set,
(char *)apr_dbd_get_entry(db->driver, row, j) /*name */ ,
(char *)apr_dbd_get_entry(db->driver, row, j + 1) /*value */ );
}
pr_tail->next = NULL;
pr_tail->pr = NULL;
}
dav_repos_release_db(db_r->r, db, rv);
pr_tail = db_r;
while (pr_tail != NULL)
{
pr_tail = pr_tail->next;
}
return iret;
}
// NEW 2010-03-24 webting
// dbms.h의 dbms_remove_replicate 함수 정의에서 내용 확인 요망.
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가를 위해 본 함수를 수정 처리
// @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
// QUERY_AND_RETRY 매크로의 반환값 처리로 인해... 반환값 void -> int 로 수정 처리
// @return 0 on success, -1 on failure
int dbms_remove_replicate( const dav_repos_resource* db_r, bool is_uricaseignore )
{
char* query = NULL;
ap_dbd_t* db;
apr_status_t rv = 0;
int nrows;
char tblname[20] = {0};
// 2014-04-25 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_remove_replicate: at_split func fail.");
return -1;
}
db = dav_repos_get_db(db_r->r);
if( db == NULL )
{
db_error_message(db, "dbms_remove_replicate: database acquire timeout", 0);
return -1;
}
if( db_r->m_resource_type == 0)
{
/* 2010.12.09 : dadamin / 양방향의 적용된(Revision 0237) 내용 적용 */
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND %s = lower('%s') AND deleted_yn = 'N' AND is_cache != 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now()
, user_info.szVolumeID, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT" "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N' AND is_cache != 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now()
, user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri
);
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_remove_replicate: update: file", rv);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_remove_replicate query fail [%s]", db_r->m_fake_uri);
}
}
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/**
* Removes a resource from the repository. If the resource is collection, all the resources it contains will also be removed.
* @param d DB connection struct containing the user, password, and DB name.
* @param r A pointer to the resource to be removed.
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return 0 on success, -1 on failure
*/
int dbms_remove_resource( const dav_repos_resource *db_r, bool is_uricaseignore )
{
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv = 0;
int nrows;
int retval = 0;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_remove_resource: at_split func fail.");
return -1;
}
// RCDB 연결
db = dav_repos_get_db(db_r->r);
if( db == NULL )
{
db_error_message(db, "dbms_remove_resource: database acquire timeout", 0);
return -1;
}
// 요청 대상이 file 인지 directory 인지 검사.
if( db_r->m_resource_type == 0 ) // 삭제 요청 대상이 file 인 경우
{
// CHG 2012-03-21 huibong
// 서비스별 대소문자 무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND "
"%s = lower('%s') AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now(), user_info.szVolumeID, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND "
"uri = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now(), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri
);
}
// Query 수행
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
// Query 수행 오류 발생시 반환값 조정.
if( rv )
{
db_error_message( db, "dbms_remove_resource: file delete fail", rv );;
retval = -1;
}
}
else if( db_r->m_resource_type == 1 ) // 삭제 요청 대상이 directory 인 경우 : 해당 Directory 및 하위 directory, content 모두 삭제 처리.
{
// 2016.04.23 LIKE 구문 특수 문자 제거(_,%)
/* 2010.10.13 : dadmain / 8.1.2 -> 8.4.5 변경시 발생한 쿼리 warning 제거 */
// CHG 2012-03-21 huibong
// 서비스별 대소문자 무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth >= %d "
"AND ( %s = lower('%s') OR %s LIKE regexp_replace( lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now(), user_info.szVolumeID, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET deleted_yn = 'Y', get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = '%s' OR uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now(), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri, db_r->m_fake_uri
);
}
// Query 수행
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
// Query 수행 오류 발생시 반환값 조정.
if( rv )
{
db_error_message( db, "dbms_remove_resource: directory delete fail", rv );;
retval = -2;
}
}
// Logging 처리 목적
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_remove_resource completed. uri[%s][%s] rv[%d] retval[%d]"
, db_r->m_fake_uri
, ( is_uricaseignore == true ? "uri case ignore" : "uri case sensitive" )
, rv, retval
);
// RCDB 연결 해제
dav_repos_release_db( db_r->r, db, rv );
return retval;
}
// NEW 2010-01-18 huibong
// client ModifyTime filed send to dav. This value is File attribute.
// So we saved this value to file_lastmodified column, not get_lastmodified column.
// CHG 2012-03-23
// 서비스별 URI 대소문자 구분/무시 기능 추가를 위해 is_uricaseignore 인자값 추가
// is_uricaseignore true: URI 대소문자 무시, false: URI 대소문자 구분 (default)
int dbms_update_file_lastmodified(const dav_repos_resource *db_r, apr_int64_t mtime, bool is_uricaseignore)
{
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv = 0;
int nrows;
int retval = 0;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_update_file_lastmodified: at_split func fail.");
return -1;
}
db = dav_repos_get_db( db_r->r );
if(db == NULL)
{
db_error_message(db, "dbms_update_file_lastmodified: database acquire timeout", 0);
return -1;
}
// CHG 2011-11-29 huibong
// file_lastmodified 값 변경시 get_lastmodified 값도 현재 시간으로 변경되도록 수정 처리
// 본 수정은 서비스간 동기화 처리 기능 지원 목적임.
// CHG 2012-03-23 huibong
// 서비스별 URI 대소문자 구분/무시 기능 추가를 위한 Query 구문 변경
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET file_lastmodified = %" APR_INT64_T_FMT ", get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND %s = lower('%s') AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, mtime, apr_time_now(), user_info.szVolumeID, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET file_lastmodified = %" APR_INT64_T_FMT " , get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, mtime, apr_time_now(), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri);
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message( db, "dbms_update_file_lastmodified: update: mtime", rv );
retval = -1;
}
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_update_file_lastmodified completed. ModifyTime[%s][%"APR_INT64_T_FMT "] rv[%d] retval[%d]"
, db_r->m_fake_uri, mtime, rv, retval);
dav_repos_release_db(db_r->r, db, rv);
return retval;
}
// 2013.08.21 dadamin
// Set hidden property of DAV:(t_dav_resource)
// hidden : 1, not hidden : 0
int dbms_update_hidden(const dav_repos_resource *db_r, int hidden , bool is_uricaseignore)
{
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv = 0;
int nrows;
int retval = 0;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_update_hidden: at_split func fail.");
return -1;
}
// t_dav_resource 의 source 필드를 hidden 속성값을 의미
// 팀 협의 완료되었으며, WebDAV source 와는 다름 의미로 사용하게 됨
db = dav_repos_get_db( db_r->r );
if(db == NULL)
{
db_error_message(db, "dbms_update_hidden: database acquire timeout", 0);
return -1;
}
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET source = %d , get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND %s = lower('%s') AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, hidden, apr_time_now(), user_info.szVolumeID, db_r->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf( db_r->p,
"UPDATE %s "
"SET source = %d , get_lastmodified = %" APR_TIME_T_FMT " "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, hidden, apr_time_now(), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri);
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message( db, "dbms_update_hidden: update: hidden", rv );
retval = -1;
}
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_update_hidden completed. hidden[%s][%d] rv[%d] retval[%d]"
, db_r->m_fake_uri, hidden, rv, retval);
dav_repos_release_db(db_r->r, db, rv);
return retval;
}
/**
* Adds a new dead property record the the dead property table in the DB
* @param d DB connection struct
* @param r Identifies the resource to associate the property with
* @param pr The property to insert
* @return 0 on success, -1 on failure
*/
int db_insert_property( const dav_repos_resource *db_r, const dav_repos_property *pr )
{
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv;
int nrows;
char* szfilename_hash = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 32+1 -> 32 + 8 + 8 + 1 로 변경한다.
char szTemp[49] = {0};
// 2013.08.14 dadamin
// pgpool 사용으로 resource_id가 RCDB01, RCDB02 서로 다른 경우 발생으로
// 참조키를 filename_hash의 hash 값을 참조키로 변경함
szfilename_hash = strrchr(db_r->m_filename_hash, '/');
if(szfilename_hash)
{
szfilename_hash = szfilename_hash + 1;
}
else
{
// 디렉토리 경우 hash 없을 수 있으므로 etag rule 과 동일하게 생성
sprintf( szTemp, "00000000000000000000000000000000%x%x",
(unsigned int)db_r->m_get_content_length,
(unsigned int)db_r->m_get_lastmodified );
szfilename_hash = szTemp;
}
/* Create the insert command */
query = apr_psprintf(db_r->p,
"INSERT INTO t_dav_property "
"(ns_id, filename_hash, propname, propvalue) "
"VALUES (%ld, '%s', '%s', '%s')"
, pr->m_ns_id, szfilename_hash, pr->m_propname, pr->m_propvalue
);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "db_insert_property: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "db_insert_property: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/**
* Set the value of a dead property on a resrouce identified by serialno
* @param d DB connection struct
* @param r Identified the resource to set the property on
* @param pr The dead property to set
* @return 0 on success, -1 on failure
*/
int dbms_set_dead_property(const dav_repos_resource *db_r,
const dav_repos_property *pr)
{
char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_status_t rv;
int nrows;
char *szfilename_hash = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 32+1 -> 32 + 8 + 8 + 1 로 변경한다.
char szTemp[49] = {0};
// 2013.08.14 dadamin
// pgpool 사용으로 resource_id가 RCDB01, RCDB02 서로 다른 경우 발생으로
// 참조키를 filename_hash의 hash 값을 참조키로 변경함
szfilename_hash = strrchr(db_r->m_filename_hash, '/');
if(szfilename_hash)
{
szfilename_hash = szfilename_hash + 1;
}
else
{
// 디렉토리 경우 hash 없을 수 있으므로 etag rule 과 동일하게 생성
sprintf( szTemp, "00000000000000000000000000000000%x%x",
(unsigned int)db_r->m_get_content_length,
(unsigned int)db_r->m_get_lastmodified );
szfilename_hash = szTemp;
}
/* Create the select command to get the serialno by serialno */
query = apr_psprintf(db_r->p,
"SELECT filename_hash "
"FROM t_dav_property "
"WHERE filename_hash = '%s' "
" AND ns_id = %ld"
" AND propname = '%s' "
, szfilename_hash, pr->m_ns_id, pr->m_propname
);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_set_dead_property: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_set_dead_property: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
if( apr_dbd_num_tuples(db->driver, res) == 0)
{
/* No result */
dav_repos_release_db(db_r->r, db, rv);
/* Insert a new property record */
if( db_insert_property(db_r, pr) != 0)
{
return -2;
}
else
{
return 0;
}
}
/* Create update command */
query = apr_psprintf(db_r->p,
"UPDATE t_dav_property "
"SET propvalue='%s' "
"WHERE filename_hash = '%s' AND ns_id = %ld AND propname='%s'"
, pr->m_propvalue
, szfilename_hash, pr->m_ns_id, pr->m_propname
);
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_set_dead_property: update", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -3;
}
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/**
* I'll fill pr->name , r->serialno and you will fill pr->value
* @param d DB connection struct
* @param r Identifies the resource
* @param pr Identifies the property to retrieve
* @return 0 on success, 100 if not found, -1 on failure
* */
int dbms_get_dead_property(const dav_repos_resource * db_r, dav_repos_property * pr)
{
int iret = 0;
char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char * szfilename_hash = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 32+1 -> 32 + 8 + 8 + 1 로 변경한다.
char szTemp[49] = {0};
// 2013.08.14 dadamin
// pgpool 사용으로 resource_id가 RCDB01, RCDB02 서로 다른 경우 발생으로
// 참조키를 filename_hash의 hash 값을 참조키로 변경함
szfilename_hash = strrchr(db_r->m_filename_hash, '/');
if(szfilename_hash)
{
szfilename_hash = szfilename_hash + 1;
}
else
{
// 디렉토리 경우 hash 없을 수 있으므로 etag rule 과 동일하게 생성
sprintf( szTemp, "00000000000000000000000000000000%x%x",
(unsigned int)db_r->m_get_content_length,
(unsigned int)db_r->m_get_lastmodified );
szfilename_hash = szTemp;
}
/* Create the search command */
query = apr_psprintf(db_r->p,
"SELECT ns_id, propvalue FROM t_dav_property "
"WHERE filename_hash = '%s' "
" AND ns_id = %ld"
" AND propname = '%s' "
, szfilename_hash, pr->m_ns_id, pr->m_propname);
/* Execute sequry */
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_get_dead_property: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_get_dead_property: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
if( apr_dbd_num_tuples(db->driver, res) == 0 )
{
/* No result */
iret = 100;
}
else
{
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
if(rv)
{
iret = -1;
db_error_message(db, "dbms_get_dead_property: get row", rv);
}
else
{
/* One row fetched */
/* TODO: may be.. */
/* Get the data of every column of this row to a link */
/* Fetch value column of the row */
STRING_FROM_DBENTRY(db_r->p, pr->m_propvalue, 1);
pr->next = NULL;
}
}
dav_repos_release_db(db_r->r, db, rv);
return iret;
}
/* Support function. update modified time */
int dbms_modify_resource(const dav_resource *resource)
{
#if 0
const dav_repos_resource *db_r;
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv;
int nrows;
char tblname[20] = {0};
if (!resource || !resource->info || !resource->info->db_r)
return -1;
if (resource->exists == 0)
return -2;
db_r = resource->info->db_r;
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_modify_resource: at_split func fail.");
return -1;
}
//apr_thread_rwlock_wrlock(db_lock);
query = apr_psprintf(db_r->p,
"UPDATE %s "
"SET get_lastmodified = %lld "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, apr_time_now(), user_info.szVolumeID, db_r->m_depth, db_r->m_fake_uri);
DBG1("dbms_modify_resource: query: %s", query);
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_modify_resource: query: %s", query);
db = dav_repos_get_db(db_r->r);
if (db == NULL ) {
db_error_message(db, "dbms_modify_resource: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_modify_resource: update", rv);;
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return -1;
}
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
#endif
return 0;
}
/**
* Moves a resource. If the source is a regular file,
* just change the URI. If the source is collection,
* move all files in the collection
* @param d DB connection struct
* @param db_r_src source
* @param db_r_des destination ( only contains URI field )
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return 0 on success -1 on failure
*/
int dbms_move_resource(const dav_repos_resource * db_r_src, const dav_repos_resource * db_r_des, const dav_resource * resource, bool is_uricaseignore )
{
int depth_diff = 0;
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv = 0;
int nrows;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r_src->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_move_resource: at_split func fail.");
return -1;
}
// 2014-04-28 : dadamin
// depth 추출 로직 삭제 : 상위 로직에서 추출됨
depth_diff = db_r_des->m_depth - db_r_src->m_depth;
db = dav_repos_get_db(db_r_src->r);
if(db == NULL)
{
db_error_message(db, "dbms_move_resource: database acquire timeout", 0);
return -1;
}
if( db_r_src->m_resource_type == 0 )
{
/* Is a regular file, not directory Change the URI directly */
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = lower('%s'), display_name = '%s',"
" get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d AND uri = lower('%s') AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = '%s', get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d AND lower(uri) = lower('%s') AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = '%s', display_name = '%s', "
" get_lastmodified = %" APR_TIME_T_FMT" , depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = '%s', get_lastmodified = %" APR_TIME_T_FMT" , depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d AND uri = '%s' AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
}
/* Execute the move command */
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_move_resource: update", rv);;
dav_repos_release_db(db_r_src->r, db, rv);
return -1;
}
}
else if( db_r_src->m_resource_type == 1 ) // 폴더인 경우
{
// 2016.04.23 LIKE 구문 특수 문자 제거(_,%)
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
// 2015.06.10 dadamin
// 디록토리 변경 시 기존 display_name를 활용해서 replace 시
// 변경되지 않을 수 있으므로 uri 필드 값을 사용 한다.
" uri = replace(uri, lower('%s'), lower('%s')), display_name = replace(uri, lower('%s'), lower('%s')), "
" get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = lower('%s') OR uri LIKE regexp_replace( lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = replace(URI, '%s', '%s'), get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( lower(uri) = lower('%s') OR lower(uri) LIKE regexp_replace( lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = replace(URI, '%s', '%s'), display_name = replace(display_name, '%s', '%s'), "
" get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = '%s' OR uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"UPDATE %s "
"SET "
" uri = replace(URI, '%s', '%s'), get_lastmodified = %" APR_TIME_T_FMT ", depth = depth + %d "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = '%s' OR uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N'"
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri
, db_r_des->m_fake_uri
, apr_time_now()
, depth_diff
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
}
/* Execute the update command */
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_move_resource: update", rv);;
dav_repos_release_db(db_r_src->r, db, rv);
return -2;
}
}
dav_repos_release_db(db_r_src->r, db, rv);
return 0;
}
/**
* Copy the source to the destination. If the source is a regular file,
* just copy the record in the database with the new URI.
* If the source is collection, duplicate all records in the collection
* in the database with the new URIs
* @param d DB connection struct
* @param db_r_src The source
* @param db_r_des The destination ( only contains URI field )
* @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
* @return 0 on success, -1 on failure
*/
/* Elenoa CHECK */
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가를 위해 본 함수를 수정 처리
int dbms_copy_resource(const dav_repos_resource * db_r_src, const dav_repos_resource * db_r_des, bool is_uricaseignore )
{
int depth_diff = 0;
char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
int nrows;
char tblname[20] = {0};
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r_src->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_copy_resource: at_split func fail.");
return -1;
}
// 2014-04-28 : dadamin
// depth 추출 로직 삭제 : 상위 로직에서 추출됨
depth_diff = db_r_des->m_depth - db_r_src->m_depth;
/* Is a regular file, not directory */
/* Copy the record in the database with the new URI */
/* Store the source record into a temporary table */
// CHG 2010-01-19 huibong
// Copy file_lastmodified info from source to dst when file, directory copy
// CHG 2011-03-09 huibong
// 원본에 대한 조회만 수행하도록 is_cache='N' 구문 추가.
// CHG 2012-03-23 huibong
// 서비스별 URI 대소문자 구분/무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
query = apr_psprintf(db_r_src->p,
"SELECT resource_id, "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, "
" source, file_lastmodified " // ADD 2010-01-19 huibong
"FROM %s "
"WHERE sp_svc_tran_id = %s AND depth = %d AND %s = lower('%s') "
"AND deleted_yn = 'N' AND is_cache = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID, db_r_src->m_depth
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r_src->m_fake_uri);
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
query = apr_psprintf(db_r_src->p,
"SELECT resource_id, "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, "
" source, file_lastmodified " // ADD 2010-01-19 huibong
"FROM %s "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' "
"AND deleted_yn = 'N' AND is_cache = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID, db_r_src->m_depth, db_r_src->m_fake_uri);
}
// CHG 2011-03-03 huibong
// resource_id 의 cross 생성 문제로 인해 Copy 시 resource_id 가 아닌 uri 를 기준으로
// Copy 작업이 수행되도록 수정처리함.
/*
"WHERE resource_id = %lld "
"AND "
"deleted_yn = 'N'", db_r_src->m_resource_id);
*/
db = dav_repos_get_db(db_r_src->r);
if(db == NULL)
{
db_error_message(db, "dbms_copy_resource: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r_src->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_copy_resource: select", rv);;
dav_repos_release_db(db_r_src->r, db, rv);
return -1;
}
if( apr_dbd_num_tuples(db->driver, res) == 0 )
{
dav_repos_release_db(db_r_src->r, db, rv);
return -2;
}
rv = solbox_apr_dbd_get_row(db->driver, db_r_src->r->pool, res, &row, 0);
if(rv)
{
db_error_message(db, "dbms_copy_resource: get row", rv);
dav_repos_release_db(db_r_src->r, db, rv);
return -1;
}
// 파일에 대한 COPY 처리시
if (db_r_src->m_resource_type == 0)
{
/* Is a regular file, not directory */
//char *tmpOrgURI = NULL;
//dav_repos_replace_unsafe_chars(apr_dbd_get_entry(db->driver, row, 6), tmpOrgURI);
// CHG 2010-01-19 huibong
// Copy file_lastmodified info from source to dst when file, directory copy
// CHG 2011-03-09 huibong
// 파일에 대한 COPY 처리시 Replication 된 파일까지 Copy 되도록 수정처리.
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, display_name, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, lower('%s'), '%s', filename_org, "
" filename_hash, depth + %d, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d "
"AND uri = lower('%s') AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, '%s', filename_org, "
" filename_hash, depth + %d, "
" display_name, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d "
"AND lower(uri) = lower('%s') AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, display_name, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, '%s', '%s', filename_org, "
" filename_hash, depth + %d, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d "
"AND uri = '%s' AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
else
{
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, '%s', filename_org, "
" filename_hash, depth + %d, "
" display_name, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth = %d "
"AND uri = '%s' AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
);
}
}
}
else if (db_r_src->m_resource_type == 1) // 폴더에 COPY 처리시
{
// 2016.04.23 LIKE 구문 특수 문자 제거(_,%)
// CHG 2010-01-19 huibong
// Copy file_lastmodified info from source to dst when file, directory copy
// CHG 2011-03-09 huibong
// 폴더 복사시 is_cache 정보도 복사되도록 수정 처리
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분, 무시 기능 추가
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf(db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, display_name, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
// 2016.04.28
// 저장된 display_name 과 요청이 서로 상반된 경우
// 해당 디렉토리 복사 시 display_name 변경되지 않기 때문에 uri값을 display_name 사용
" resource_type, replace(uri, lower('%s'), lower('%s')), replace(uri, lower('%s'), lower('%s')), "
" filename_org, filename_hash, depth + %d, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = lower('%s') OR uri LIKE regexp_replace(lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
else
{
/* 2010.10.13 : dadmain / 8.1.2 -> 8.4.5 변경시 발생한 쿼리 warning 제거 */
query = apr_psprintf(db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, replace(uri, '%s', '%s'), filename_org, "
" filename_hash, depth + %d, "
" display_name, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( lower(uri) = lower('%s') OR lower(uri) LIKE regexp_replace(lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri
, db_r_src->m_fake_uri
);
}
}
else // 양방향 기본 ( URI 대소문자 구분 )
{
// 2014.06.13
// 신규 형상(9.3)에서 대소문자 구분 기능을 display_name, uri 컬럼 활용함
if( dav_use_display_name() == 1 )
{
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, display_name, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, replace(uri, '%s', '%s'), replace(display_name, '%s', '%s'), "
" filename_org, filename_hash, depth + %d, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = '%s' OR uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri, db_r_src->m_fake_uri
);
}
else
{
/* 2010.10.13 : dadmain / 8.1.2 -> 8.4.5 변경시 발생한 쿼리 warning 제거 */
query = apr_psprintf( db_r_src->p,
"INSERT INTO %s "
"( "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache, file_lastmodified ) "
"SELECT "
#ifdef __OPENDISK_SOLUTION__
" subuser_id, owner_id, "
#else
" sp_user_seq, sp_svc_tran_id, "
#endif
" host_name, "
" resource_type, replace(uri, '%s', '%s'), filename_org, "
" filename_hash, depth + %d, "
" display_name, "
" get_content_length, get_content_type, %" APR_TIME_T_FMT ", %" APR_TIME_T_FMT ", "
" source, 'N', is_cache, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified
"FROM %s "
"WHERE "
"sp_svc_tran_id = %s AND depth >= %d "
"AND ( uri = '%s' OR uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' ) "
"AND deleted_yn = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, db_r_src->m_fake_uri, db_r_des->m_fake_uri
, depth_diff
, apr_time_now(), apr_time_now()
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r_src->m_depth
, db_r_src->m_fake_uri, db_r_src->m_fake_uri
);
}
}
}
dav_repos_release_db(db_r_src->r, db, rv);
/* Execute the command */
db = dav_repos_get_db(db_r_src->r);
if( db == NULL)
{
db_error_message(db, "dbms_copy_resource: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_copy_resource: insert", rv);;
dav_repos_release_db(db_r_src->r, db, rv);
return -1;
}
dav_repos_release_db(db_r_src->r, db, rv);
return 0;
}
// 2014-04-28 dadamin
// 사용되지 않는 함수 삭제 dbms_exists
/**
* Get properties in a form of property link for every resource
* @param d DB connection struct
* @param db_r
* @return 0 on success, -1 on failure
*/
int dbms_fill_dead_property(dav_repos_resource *db_r)
{
char *query = NULL;
int tup = 0, lengths = 0;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv = 0;
char *szfilename_hash = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 32+1 -> 32 + 8 + 8 + 1 로 변경한다.
char szTemp[49] = {0};
struct dav_repos_resource *pr_tail = NULL;
struct dav_repos_property *pp_tail = NULL;
struct dav_repos_property *pnew_link_item = NULL;
pr_tail = db_r;
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_fill_dead_property: database acquire timeout", 0);
return -1;
}
while (pr_tail != NULL) {
/*Create the search command */
DBG1("dbms_fill_dead_property: pr_tail.m_uri: %s", pr_tail->m_uri);
DBG1("dbms_fill_dead_property: pr_tail.m_fake_uri: %s", pr_tail->m_fake_uri);
// 2013.08.14 dadamin
// pgpool 사용으로 resource_id가 RCDB01, RCDB02 서로 다른 경우 발생으로
// 참조키를 filename_hash의 hash 값을 참조키로 변경함
szfilename_hash = strrchr(pr_tail->m_filename_hash, '/');
if(szfilename_hash)
{
szfilename_hash = szfilename_hash + 1;
}
else
{
// 디렉토리 경우 hash 없을 수 있으므로 etag rule 과 동일하게 생성
sprintf( szTemp, "00000000000000000000000000000000%x%x",
(unsigned int)pr_tail->m_get_content_length,
(unsigned int)pr_tail->m_get_lastmodified );
szfilename_hash = szTemp;
}
query = apr_psprintf(db_r->p,
"SELECT filename_hash, ns_id, propname, propvalue "
"FROM t_dav_property "
"WHERE filename_hash = '%s' "
"ORDER BY propname ",
szfilename_hash);
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if (rv)
{
db_error_message(db, "dbms_fill_dead_property: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
/* Deal with every records from the search result */
for (tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++) {
/* Get the length of every field */
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, tup);
if (rv)
{
db_error_message(db, "dbms_fill_dead__property: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
lengths = (apr_dbd_get_entry(db->driver, row, 1) ?
strlen(apr_dbd_get_entry(db->driver, row, 1)) : 0);
if (lengths == 0)
{
db_error_message(db, "dbms_fill_dead_property: lengths: 0", 0);
dav_repos_release_db(db_r->r, db, rv);
return -2;
}
/* Malloc a new property structure */
pnew_link_item = apr_pcalloc(db_r->p, sizeof(*pnew_link_item));
if (pr_tail->pr == NULL)
{
/* It is the first property record */
pr_tail->pr = pnew_link_item;
pp_tail = pnew_link_item;
}
else
{
/* It is not the first property record */
if (pp_tail)
{
pp_tail->next = pnew_link_item;
}
pp_tail = pnew_link_item;
}
/* Get the data of every column of this row to a link */
pp_tail->m_resource_id = pr_tail->m_resource_id;
pp_tail->m_ns_id = atol(apr_dbd_get_entry(db->driver, row, 1));
STRING_FROM_DBENTRY(db_r->p, pp_tail->m_propname, 2);
STRING_FROM_DBENTRY(db_r->p, pp_tail->m_propvalue, 3);
pp_tail->next = NULL;
}
/* Next resource */
pr_tail = pr_tail->next;
}
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/**
* Retrieve all the resources in a collection
* @param d DB connection struct
* @param db_r A pointer to a resource struct which identifies the collection
* @param depth==1 one depth, other infinity
* @return 0 on success, -1 on failure
*/
// CHG 2010-03-29 huibong
// 조회시작 시간 정보를 함수의 인자로 추가함
// 본 기능은 연합뉴스 요구사항을 반영하기 위함임.
// CHG 2012-03-23 huibong
// 서비스별 URI 대소문자 구분/무시 기능 추가를 위해 is_uricaseignore 인자 추가.
// @param is_uricaseignore URI 에 대한 대소문자 무시 여부, true : URI 대소문자 무시, false: URI 대소문자 구분
int dbms_get_collection_resource( dav_repos_resource * db_r, int depth, const char * startTime, bool is_uricaseignore )
{
int tup = 0;
int iret = 0;
int infinity = 0;
char * query = NULL;
// CHG 2010-03-29 huibong
// 조회시작 시간 정보 및 각 Where 조건절을 저장하기 위한 변수 생성.
char * whereParse = NULL;
char szRealURI[MaxSizeOfPathLength];
struct dav_repos_resource *pnew_link_item = NULL;
struct dav_repos_resource *pr_tail = NULL;
dav_repos_server_conf *dsc;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char tblname[20] = {0};
dsc = dav_repos_get_server_conf(db_r->r->server);
if( !dsc )
return -8;
if( depth == DAV_INFINITY )
infinity = 1;
// 2014-04-24 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_collection_resource: at_split func fail.");
return -9;
}
// 2016.04.23 LIKE 구문 특수 문자 제거(_,%)
if( infinity )
{
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
whereParse = apr_psprintf(db_r->p, "sp_svc_tran_id = %s AND depth >= %d "
"AND %s LIKE regexp_replace( lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' "
"AND %s <> lower('%s') "
,user_info.szVolumeID, (db_r->m_depth+1)
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri);
else
whereParse = apr_psprintf(db_r->p, "sp_svc_tran_id = %s AND depth >= %d "
"AND uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' "
"AND uri <> '%s' "
,user_info.szVolumeID, (db_r->m_depth+1), db_r->m_fake_uri, db_r->m_fake_uri);
}
else
{
if( is_uricaseignore == true ) // URI 대소문자 무시 서비스인 경우
whereParse = apr_psprintf(db_r->p, "sp_svc_tran_id = %s AND depth = %d "
"AND %s LIKE regexp_replace( lower('%s/'), '(%%|_)', '\\\\\\1', 'g') || '%%' "
"AND %s <> lower('%s') "
,user_info.szVolumeID, (db_r->m_depth+1)
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri
// 2014.06.12
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
, db_r->m_fake_uri);
else
whereParse = apr_psprintf(db_r->p, "sp_svc_tran_id = %s AND depth = %d "
"AND uri LIKE regexp_replace('%s/', '(%%|_)', '\\\\\\1', 'g') || '%%' "
"AND uri <> '%s' "
,user_info.szVolumeID, (db_r->m_depth+1), db_r->m_fake_uri, db_r->m_fake_uri);
}
// CHG 2010-01-19 huibong
// Select file_lastmodified column to send client that file attribute
// Not use get_lastmodified
// CHG 2010-07-08 huibong
// NetCache PROPFIND 성능 개선을 위해 조회 Query 상에 distinct, ORDER BY 구문 제거처리
// CHG 2011-07-07 huibong
// HTTP Header 상에 Case-Sensitive: NO 가 설정되어 있으면 소문자로 변환 후 조회
// 그밖에는 대소문자를 구분하도록 설정
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분/무시 여부 기능 추가..
// 기존 Case-Sensitive 기능은 제거함.
/* Create the search command */
// 2010-03-29 huibong
// 조회조건상에 조회 시작 시간 정보를 추가함.
// SBFS 는 특성상 조회 시작 시간 정보를 get_lastmodified 값이 아닌 file_lastmodified 값을 사용한다.
if( startTime == NULL )
{
query = apr_psprintf(db_r->p,
//"SELECT distinct(uri), resource_id, resource_type, " // 2010-07-08 NetCache 성능 개선을 위한 변경처리
"SELECT uri, resource_id, resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" filename_org, filename_hash, depth, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, source, "
" deleted_yn, host_name, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified column
"FROM %s "
"WHERE %s "
" AND deleted_yn = 'N' AND is_cache = 'N' "
//"ORDER BY uri asc, resource_id asc" // 2010-07-08 NetCache 성능 개선을 위한 변경처리
, dav_get_target_table(user_info.szVolumeID, tblname)
, whereParse
);
}
else
{
query = apr_psprintf(db_r->p,
//"SELECT distinct(uri), resource_id, resource_type, " // 2010-07-08 NetCache 성능 개선을 위한 변경처리
"SELECT uri, resource_id, resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" filename_org, filename_hash, depth, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, source, "
" deleted_yn, host_name, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified column
"FROM %s "
"WHERE %s "
"AND deleted_yn = 'N' AND is_cache = 'N' "
"AND file_lastmodified >= %s"
//"ORDER BY uri asc, resource_id asc" // 2010-07-08 NetCache 성능 개선을 위한 변경처리
, dav_get_target_table(user_info.szVolumeID, tblname)
, whereParse
, startTime);
}
#ifdef __PROPFIND_RANDOM_DIR__
/* 2010.12.07 : dadamin / PROPFIND 처리시 FHS 정보 Random(디렉토리 관련) */
// NetCache Agent 인지를 확인하기 위해 PROFPIND Header 의 User-Agent 정보 검사.
const char * userAgent = NULL;
userAgent = apr_table_get( db_r->r->headers_in, "User-Agent");
if( db_r->r->method_number == M_PROPFIND && userAgent != NULL && strncmp(userAgent, "NetCache", 8)==0 )
{
// CHG 2011-07-07 huibong
// HTTP Header 상에 Case-Sensitive: NO 가 설정되어 있으면 소문자로 변환 후 조회
// 그밖에는 대소문자를 구분하도록 설정
// CHG 2012-03-23 huibong
// 서비스별 대소문자 구분/무시 여부 기능 추가..
// 기존 Case-Sensitive 기능은 제거함.
if( startTime == NULL )
{
query = apr_psprintf(db_r->p,
"SELECT DISTINCT ON (uri) uri, resource_id, resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" filename_org, filename_hash, depth, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, source, "
" deleted_yn, host_name, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified column
"FROM %s "
"WHERE %s "
" AND deleted_yn = 'N' "
"ORDER BY uri, RANDOM()"
, dav_get_target_table(user_info.szVolumeID, tblname)
, whereParse
);
}
else
{
query = apr_psprintf( db_r->p,
"SELECT DISTINCT ON (uri) uri, resource_id, resource_type, "
#ifdef __OPENDISK_SOLUTION__
" owner_id, "
#else
" sp_user_seq, "
#endif
" filename_org, filename_hash, depth, "
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
" creation_date, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, source, "
" deleted_yn, host_name, file_lastmodified " // ADD 2010-01-19 huibong file_lastmodified column
"FROM %s "
"WHERE %s "
"AND deleted_yn = 'N' "
"AND file_lastmodified >= %s "
"ORDER BY uri, RANDOM()"
, dav_get_target_table(user_info.szVolumeID, tblname)
, whereParse
, startTime);
}
}
/* 2010.12.07 : dadamin / PROPFIND 처리시 FHS 정보 Random / 디렉토리 관련 */
#endif // __PROPFIND_RANDOM_DIR__
/* Execute sequry */
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_get_collection_resource: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if( rv )
{
db_error_message(db, "dbms_get_collection_resource: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
pr_tail = db_r;
pr_tail->next = NULL;
pr_tail->pr = NULL;
for( tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++ )
{
/* Fetch every row */
rv = solbox_apr_dbd_get_row( db->driver, db_r->r->pool, res, &row, tup );
if( rv )
{
db_error_message(db, "dbms_get_collection_resource: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
return -2;
}
memset(szRealURI, 0, MaxSizeOfPathLength);
/* Malloc a new structure */
pnew_link_item = apr_pcalloc(db_r->p, sizeof(*pnew_link_item));
pr_tail->next = pnew_link_item;
pr_tail = pnew_link_item;
/* Get the data of every column of this row to a link */
pr_tail->m_resource_id = atoll(apr_dbd_get_entry(db->driver, row, 1));
#ifdef __OPENDISK_SOLUTION__
pr_tail->m_resource_type = dav_repos_change_resource_type( atoi(apr_dbd_get_entry(db->driver, row, 2)));
#else
pr_tail->m_resource_type = atoi(apr_dbd_get_entry(db->driver, row, 2));
#endif
pr_tail->m_owner_id = atoll(apr_dbd_get_entry(db->driver, row, 3));
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_fake_uri, 0);
if( pr_tail->m_fake_uri != NULL )
{
remove_user_root_dir_from_fake_uri(pr_tail->m_fake_uri, szRealURI);
pr_tail->m_uri = apr_psprintf(db_r->p, "%s%s", dsc->base_uri, szRealURI);
}
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_filename_org, 4);
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_filename_hash, 5);
pr_tail->m_depth = atoi(apr_dbd_get_entry(db->driver, row, 6));
pr_tail->m_creation_date = atoll(apr_dbd_get_entry(db->driver, row, 7));
// 2014.11.27 dadamin
// PROPFIND 응답 시 경로 /dav 로 리턴하도록 수정함
if( dav_use_display_name() == 1 )
{
memset(szRealURI, 0, MaxSizeOfPathLength);
remove_user_root_dir_from_fake_uri(apr_dbd_get_entry(db->driver, row, 8), szRealURI);
pr_tail->m_displayname = apr_psprintf(db_r->p, "%s%s", dsc->base_uri, szRealURI);
}
else
{
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_displayname, 8);
}
// 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery)
pr_tail->m_get_content_length = atoll(apr_dbd_get_entry(db->driver, row, 9));
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_get_content_type, 10);
// CHG 2010-01-19 huibong
// PROFIND file list send to client, and last modify time is file_lastmodified column, not get_lastmodified column
//pr_tail->m_get_lastmodified = atoll(apr_dbd_get_entry(db->driver, row, 13));
pr_tail->m_get_lastmodified = atoll(apr_dbd_get_entry(db->driver, row, 15));
pr_tail->m_source = atoi(apr_dbd_get_entry(db->driver, row, 12));
STRING_FROM_DBENTRY(db_r->p, pr_tail->m_host_name, 14);
pr_tail->next = NULL;
pr_tail->pr = NULL;
}
dav_repos_release_db(db_r->r, db, rv);
return iret;
}
/* Deletes a dasl_property by serialno and property name
* @param d DB connection struct
* @param r A pointer to a resource struct identifying
* the resource to be operated upon
* @param pr A pointer to a property struct identifying the property to delete
* @return 0 on success, 1 on failure
* */
int dbms_del_dead_property(const dav_repos_resource *db_r, const dav_repos_property *pr)
{
char *query = NULL;
ap_dbd_t *db;
apr_status_t rv;
int nrows;
char* szfilename_hash = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 32+1 -> 32 + 8 + 8 + 1 로 변경한다.
char szTemp[49] = {0};
// 2013.08.14 dadamin
// pgpool 사용으로 resource_id가 RCDB01, RCDB02 서로 다른 경우 발생으로
// 참조키를 filename_hash의 hash 값을 참조키로 변경함
szfilename_hash = strrchr(db_r->m_filename_hash, '/');
if(szfilename_hash)
{
szfilename_hash = szfilename_hash + 1;
}
else
{
// 디렉토리 경우 hash 없을 수 있으므로 etag rule 과 동일하게 생성
sprintf( szTemp, "00000000000000000000000000000000%x%x",
(unsigned int)db_r->m_get_content_length,
(unsigned int)db_r->m_get_lastmodified );
szfilename_hash = szTemp;
}
query = apr_psprintf(db_r->p,
"DELETE FROM t_dav_property "
"WHERE filename_hash = '%s' AND ns_id = %ld AND propname = '%s' "
, szfilename_hash, pr->m_ns_id, pr->m_propname);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_del_dead_property: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if( rv )
{
db_error_message(db, "dbms_del_dead_property: delete", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
dav_repos_release_db(db_r->r, db, rv);
return 0;
}
/* Get resourcetype by uri
* @param d DB connection struct
* Return 0: success; 100: not found; -1: failure
* */
int dbms_get_resourcetype(dav_repos_resource *db_r)
{
int iret = 0;
const char *query;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char tblname[20] = {0};
TRACE();
// 2014-04-28 : dadamin
// where 구문에 파티셔닝 기준값, depth 추가
acct_info user_info;
if(at_split(db_r->r->user, &user_info ) < 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dbms_get_resourcetype: at_split func fail.");
return -1;
}
//apr_thread_rwlock_rdlock(db_lock);
query = apr_psprintf(db_r->p,
"SELECT resource_type "
"FROM %s "
"WHERE sp_svc_tran_id = %s AND depth = %d AND uri = '%s' "
"AND is_cache = 'N' "
, dav_get_target_table(user_info.szVolumeID, tblname)
, user_info.szVolumeID
, db_r->m_depth
, db_r->m_fake_uri);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_get_resourcetype: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if (rv) {
db_error_message(db, "dbms_get_resourcetype: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return -1;
}
if (apr_dbd_num_tuples(db->driver, res) == 0) {
/* No result */
iret = 100;
} else {
/* One row fetched */
/* Get the resourcetype data */
/* Fetch value column of the row */
#ifdef __OPENDISK_SOLUTION__
db_r->m_resource_type =
dav_repos_change_resource_type(
atoi(apr_dbd_get_entry(db->driver, row, 0)));
#else
db_r->m_resource_type = atoi(apr_dbd_get_entry(db->driver, row, 0));
#endif
iret = 0;
} /*End of else one row fetched */
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return iret;
} /*End of dbms_get_resourcetype */
/* Build namespace
*
* Read namespace infor from DB and fill hash
* db_r must have pool
* This hash is for PROPFIND
* */
void dbms_build_ns_id_hash(dav_repos_resource *db_r)
{
int tup = 0;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char *query = NULL;
/* id_hash is not clean */
if (db_r->ns_id_hash != NULL)
{
/* Build hash */
db_r->ns_id_hash = apr_hash_make(db_r->p);
}
/* Execute sequry */
//apr_thread_rwlock_rdlock(db_lock);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_build_ns_id_hash: database acquire timeout", 0);
return;
}
query = apr_pstrdup(db_r->p, "SELECT * FROM t_dav_namespace");
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if (rv) {
db_error_message(db, "dbms_build_ns_id_hash: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
for( tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++)
{
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, tup);
if (rv) {
db_error_message(db, "dbms_build_ns_id_hash: get row", 0);
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
if (apr_dbd_get_entry(db->driver, row, 0) == NULL) {
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
apr_hash_set(db_r->ns_id_hash,
apr_pstrdup(db_r->p, apr_dbd_get_entry(db->driver, row, 0)),
APR_HASH_KEY_STRING,
apr_pstrdup(db_r->p, apr_dbd_get_entry(db->driver, row, 1)));
}
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
}
// 2013.08.22 dadamin
// set namespace
void dbms_set_namespace(dav_repos_resource * db_r, dav_repos_property *pr, const char *snamespace)
{
/* id_hash is not clean */
if (db_r->ns_id_hash == NULL)
{
/* Build hash */
db_r->ns_id_hash = apr_hash_make(db_r->p);
}
char szns_id[10] = {0};
sprintf(szns_id, "%ld", pr->m_ns_id);
apr_hash_set(db_r->ns_id_hash,
apr_pstrdup(db_r->p, szns_id),
APR_HASH_KEY_STRING,
apr_pstrdup(db_r->p, snamespace));
}
// set ns_id
void dbms_set_ns_id(dav_repos_resource * db_r, const char *snamespace, dav_repos_property *pr)
{
/* id_hash is not clean */
if (db_r->ns_hash == NULL)
{
/* Build hash */
db_r->ns_hash = apr_hash_make(db_r->p);
}
char szns_id[10] = {0};
sprintf(szns_id, "%ld", pr->m_ns_id);
apr_hash_set(db_r->ns_hash,
apr_pstrdup(db_r->p, snamespace),
APR_HASH_KEY_STRING,
apr_pstrdup(db_r->p, szns_id));
}
/* Get namespace
* If new namespace, save it and return ns_id
*
* This hash is for PROPPATCH
* It must be rebuild after adding new namespace
* */
static void dbms_build_ns_hash(dav_repos_resource *db_r)
{
int tup = 0;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char *query = NULL;
TRACE();
/* Already built */
if (db_r->ns_hash) return;
db_r->ns_hash = apr_hash_make(db_r->p);
/* Execute sequry */
//apr_thread_rwlock_rdlock(db_lock);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_build_ns_hash: database acquire timeout", 0);
return;
}
query = apr_pstrdup(db_r->p, "SELECT * FROM t_dav_namespace");
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if (rv) {
db_error_message(db, "dbms_build_ns_hash: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
for (tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++) {
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, tup);
if (rv) {
db_error_message(db, "dbms_build_ns_hash: get row", rv);
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
/* XXX: It's right? */
apr_hash_set(db_r->ns_hash,
// 2013.08.12 dadmain
// 네임스페이스 통해서 해당 ns_id 획득을 위해서 해쉬테이블 설정
apr_pstrdup(db_r->p, apr_dbd_get_entry(db->driver, row, 1)),
APR_HASH_KEY_STRING,
apr_pstrdup(db_r->p, apr_dbd_get_entry(db->driver, row, 0)));
}
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return;
}
/* Insert new namespace
* Must build hash and try to find namespace first.
*/
static long dbms_select_ns(dav_repos_resource *db_r, const char *namespace)
{
const char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
query = apr_psprintf(db_r->p,
"SELECT * "
"FROM t_dav_namespace "
"WHERE ns_name = '%s'", namespace);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_select_ns: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, db_r->r->pool, db->handle, &res, query, 1);
if (rv) {
db_error_message(db, "dbms_select_ns: select", rv);;
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
rv = solbox_apr_dbd_get_row(db->driver, db_r->r->pool, res, &row, 0);
if (rv) {
db_error_message(db, "dbms_select_ns: get row", 0);
dav_repos_release_db(db_r->r, db, rv);
return -1;
}
long r = atol(apr_dbd_get_entry(db->driver, row, 0));
dav_repos_release_db(db_r->r, db, rv);
return r;
}
static long dbms_insert_ns(dav_repos_resource *db_r, const char *namespace)
{
long ns_id = -1;
const char *query = NULL;
// CHG 2019-08-28 huibong buffer overflow 수정 (#32780)
// - buffer 크기를 10 -> 20 + 1 로 변경한다.
char szns_id[21] = {0};
ap_dbd_t *db;
apr_status_t rv;
int nrows;
TRACE();
// 2013.08.23 dadamin
// 해당 네임스페이스 RCDB 상 등록되어 있는지 조회
ns_id = dbms_select_ns(db_r, namespace);
if(ns_id < 0)
{
// 2013.08.12 dadamin
// ns_id 값을 SEQUENCE 입력된 경우 RCDB01, RCDB02 서로 다름 값을 가질 수 있으므로
// time 값을 해당값으로 입력하여 RCDB01, RCDB02 서로 같을 가질 수 있게 수정하였으며,
// 네임스페이스로 최대 1024(DAV_REPOS_MAX_NAMESPACE)까지 가질 수 있게 로직 구성하였으며,
// DAV: 네임스페이스 경우 ns_id 는 0으로 고정함
if(strcmp(namespace, "DAV:") == 0)
{
ns_id = 0;
}
else
{
ns_id = (long) time(0);
if( ns_id > 0 )
ns_id = ns_id % DAV_REPOS_MAX_NAMESPACE + 1;
}
sprintf(szns_id, "%ld", ns_id);
/* We need to add name space to DB and fill hash */
//apr_thread_rwlock_wrlock(db_lock);
query = apr_psprintf(db_r->p,
"INSERT INTO t_dav_namespace (ns_id, ns_name) VALUES (%s, '%s')", szns_id, namespace);
db = dav_repos_get_db(db_r->r);
if(db == NULL)
{
db_error_message(db, "dbms_insert_ns: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_insert_ns: insert", rv);;
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return -1;
}
dav_repos_release_db(db_r->r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
}
else
{
sprintf(szns_id, "%ld", ns_id);
}
/* Add to hash_table */
// 2013.08.12 dadamin
// 네임스페이스로 ns_id 구하기 위한 설정
if (db_r->ns_hash) {
apr_hash_set(db_r->ns_hash, namespace, APR_HASH_KEY_STRING, szns_id);
}
return ns_id;
}
/*## FIXME : Make it building hash only once per request
*
*/
/* Get namespace
* If new namespace, save it and return ns_idmod_dav
*
* @param d DB connection struct
* @param r Pointer to a resource struct identifying the resource in question
* @param namespace namespace
* @return name space. Should not return NULL
* */
const char *dbms_get_ns(dav_repos_resource * db_r, const long ns_id)
{
const char *namespace;
const char *ns_id_str;
const char *ns_default = DEFAULT_NAMESPACE_URI;
/* Build hash first */
if( db_r->ns_id_hash == NULL )
{
return ns_default;
}
/* Build key */
ns_id_str = apr_psprintf(db_r->p, "%ld", ns_id);
namespace = (const char *) apr_hash_get(db_r->ns_id_hash, ns_id_str, APR_HASH_KEY_STRING);
/* We can't return NULL, so let's return default NS */
if( namespace == NULL )
{
return ns_default;
}
return namespace;
}
/* Get namespace
* If new namespace, save it and return ns_id
*
* @param d DB connection struct
* @param r Pointer to a resource struct identifying the resource in question
* @param namespace namespace
* @return ns_id
* */
long dbms_get_ns_id(dav_repos_resource * db_r, const char *namespace)
{
char *ns_id = NULL;
dbms_build_ns_hash(db_r);
/* Now, We have Hash table */
ns_id = apr_hash_get(db_r->ns_hash, namespace, APR_HASH_KEY_STRING);
if (ns_id)
{
return atol(ns_id);
}
/* name space is not found */
return dbms_insert_ns(db_r, namespace);
}
/* This function for walker */
dav_error *dbms_load_locknull_list(request_rec *r, const char *path, apr_text_header *phdr, apr_pool_t *pool)
{
int tup = 0;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
const char *query = NULL;
//apr_thread_rwlock_rdlock(db_lock);
query = apr_psprintf(pool,
"SELECT filename_hash "
"FROM t_dav_locknull "
"WHERE path = '%s'", path);
/* Execute sequry */
db = dav_repos_get_db(r);
if(db == NULL)
{
db_error_message(db, "dbms_load_locknull_list: database acquire timeout", 0);
return NULL;
}
rv = apr_dbd_select(db->driver, r->pool, db->handle, &res, query, 1);
if (rv)
{
db_error_message(db, "dbms_load_locknull_list: select", rv);;
dav_repos_release_db(r, db, rv);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DBMS Error");
}
for (tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++)
{
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, tup);
if (rv)
{
db_error_message(db, "dbms_load_locknull_list: get row", rv);
dav_repos_release_db(r, db, rv);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,"DBMS Error");
}
/* Add it to the text */
apr_text_append(pool, phdr, apr_pstrdup(pool, apr_dbd_get_entry(db->driver, row, 0)));
}
dav_repos_release_db(r, db, rv);
return NULL;
}
dav_error *dbms_save_locknull_member(request_rec *r, const char *filename, apr_pool_t * pool)
{
const char *query = NULL;
char *path = ap_make_dirstr_parent(pool, filename);
char tmpOrgURI[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
ap_dbd_t *db;
apr_status_t rv;
int nrows;
dav_repos_replace_unsafe_chars(path, tmpOrgURI);
/* No trailing */
dav_repos_no_trail(path);
/* We need to add name space to DB and fill hash */
//apr_thread_rwlock_wrlock(db_lock);
query = apr_psprintf(pool,
"INSERT INTO t_dav_locknull VALUES ('%s', '%s')",
tmpOrgURI, filename);
/* Execute sequry */
db = dav_repos_get_db(r);
if(db == NULL)
{
return solbox_dav_new_error(pool, HTTP_SERVICE_UNAVAILABLE, 0, "dbms_save_locknull_member: database acquire timeout");
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_save_locknull_member: select", rv);;
dav_repos_release_db(r, db, rv);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DBMS Error");
}
dav_repos_release_db(r, db, rv);
return NULL;
}
dav_error *dbms_remove_locknull_member(request_rec *r, const char *filename, apr_pool_t * pool)
{
const char *query = NULL;
char *path = ap_make_dirstr_parent(pool, filename);
char tmpOrgURI[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
char tmpOrgFile[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
ap_dbd_t *db;
apr_status_t rv;
int nrows;
dav_repos_replace_unsafe_chars(path, tmpOrgURI);
dav_repos_replace_unsafe_chars(filename, tmpOrgFile);
/* no trailing */
dav_repos_no_trail(path);
/* We need to add name space to DB and fill hash */
//apr_thread_rwlock_wrlock(db_lock);
query = apr_psprintf(pool,
"DELETE FROM t_dav_locknull "
"WHERE path='%s' AND filename_hash='%s'",
tmpOrgURI, tmpOrgFile);
db = dav_repos_get_db(r);
if (db == NULL)
{
return solbox_dav_new_error(pool, HTTP_SERVICE_UNAVAILABLE, 0, "dbms_remove_locknull_member: database acquire timeout");
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv)
{
db_error_message(db, "dbms_remove_locknull_member: delete", rv);;
dav_repos_release_db(r, db, rv);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DBMS Error");
}
dav_repos_release_db(r, db, rv);
return NULL;
}
dav_error *dbms_load_lock_record(request_rec *r, const char *lock_key, dav_lock_discovery ** direct, dav_lock_indirect ** indirect, int *need_save, apr_pool_t * pool)
{
int tup = 0;
dav_lock_discovery *dp = NULL;
dav_lock_indirect *ip = NULL;
const char *query = NULL;
char tmpOrgURI[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
TRACE();
dav_repos_replace_unsafe_chars(lock_key, tmpOrgURI);
//apr_thread_rwlock_rdlock(db_lock);
query = apr_psprintf(pool,
"SELECT lock_type, scope, file_type, depth, "
"timeout, lock_token, owner, auth_user, lockkey "
"FROM t_dav_lock "
#ifdef __IGNORE_CASE_DOWNLOAD__
//"WHERE lower(uri) = lower('%s') "
"WHERE uri = '%s' "
#else
"WHERE uri = '%s' "
#endif
, tmpOrgURI);
db = dav_repos_get_db(r);
if(db == NULL)
{
return solbox_dav_new_error(pool, HTTP_SERVICE_UNAVAILABLE, 0, "dbms_load_lock_record: database acquire timeout");
}
rv = apr_dbd_select(db->driver,r->pool, db->handle, &res, query, 1);
if (rv) {
db_error_message(db, "dbms_load_lock_record: select", rv);;
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DBMS Error");
}
// CHECK THIS OUT LATER - apr_dbd_get_entry(db->driver, rowN
DBG1("dbms_load_lock_record::tuples = %d",
apr_dbd_num_tuples(db->driver, res));
for (tup = 0; tup < apr_dbd_num_tuples(db->driver, res); tup++) {
dav_locktoken *locktoken = NULL;
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, tup);
if (rv) {
db_error_message(db, "dbms_load_lock_record: get row", rv);
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return
solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,"DBMS Error");
}
/* Check timeout */
if (dav_repos_lock_expired(atoi(apr_dbd_get_entry(db->driver, row, 4)))) {
*need_save = DAV_TRUE;
DBG0("dbms_load_lock_record: DAV_TRUE!");
continue;
}
locktoken = apr_pcalloc(pool, sizeof(*locktoken));
locktoken->char_uuid =
apr_pstrdup(pool, apr_dbd_get_entry(db->driver, row, 5));
if (atoi(apr_dbd_get_entry(db->driver, row, 0)) == DAV_LOCK_DIRECT) {
dp = apr_pcalloc(pool, sizeof(*dp));
/* Fill DP */
dp->f.scope = atoi(apr_dbd_get_entry(db->driver, row, 1));
dp->f.type = atoi(apr_dbd_get_entry(db->driver, row, 2));
dp->f.depth = atoi(apr_dbd_get_entry(db->driver, row, 3));
dp->f.timeout = atoi(apr_dbd_get_entry(db->driver, row, 4));
dp->locktoken = locktoken;
dp->owner =
apr_pstrdup(pool, apr_dbd_get_entry(db->driver, row, 6));
if (apr_dbd_get_entry(db->driver, row, 7) &&
strlen(apr_dbd_get_entry(db->driver, row, 7)))
dp->auth_user =
apr_pstrdup(pool, apr_dbd_get_entry(db->driver, row, 7));
dp->next = *direct;
*direct = dp;
} else {
ip = apr_pcalloc(pool, sizeof(*ip));
/* Fill IP */
ip->timeout = atoi(apr_dbd_get_entry(db->driver, row, 4));
ip->locktoken = locktoken;
ip->key = apr_pstrdup(pool, apr_dbd_get_entry(db->driver, row, 8));
/* Put it in the chain */
ip->next = *indirect;
*indirect = ip;
}
}
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return NULL;
}
/* DIRECT LOCK save
** lock info has linked list data
** #FIXME : Need rollback if we had error
*/
dav_error *dbms_save_lock_record(request_rec *r, const char *key,
const dav_lock_discovery * direct, const dav_lock_indirect * indirect,
apr_pool_t * pool)
{
const char *query = NULL;
const dav_lock_discovery *dp;
const dav_lock_indirect *ip;
ap_dbd_t *db;
apr_status_t rv = 0;
int nrows, i;
TRACE();
if (direct == NULL && indirect == NULL) {
DBG0("dbms_save_lock_record: nothing to save");
return NULL;
}
//apr_thread_rwlock_wrlock(db_lock);
db = dav_repos_get_db(r);
if (db == NULL) {
return solbox_dav_new_error(pool, HTTP_SERVICE_UNAVAILABLE, 0, "dbms_save_lock_record: database acquire timeout");
}
i = 0;
for (dp = direct; dp; dp = dp->next) {
i++;
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: dplock: (%d) %s",
i, dp->locktoken->char_uuid);
query = apr_psprintf(pool,
"INSERT INTO t_dav_lock ("
"uri, lock_type, scope, file_type, depth, "
"timeout, lock_token, owner, auth_user) "
"VALUES ('%s', %d, %d, %d, %d, %d, '%s', '%s', '%s')",
key, DAV_LOCK_DIRECT, (int)dp->f.scope,
dp->f.type, dp->f.depth,
(int)dp->f.timeout,
(dp->locktoken->char_uuid ? dp->locktoken->char_uuid : ""),
dp->owner ? dp->owner : "",
dp->auth_user ? dp->auth_user : "");
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_save_lock_record: insert(1)", rv);;
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return
solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,"DBMS Error");
}
}
i = 0;
for (ip = indirect; ip; ip = ip->next) {
i++;
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: iplock: (%d) %s",
i, ip->locktoken->char_uuid);
query = apr_psprintf(pool,
"INSERT INTO t_dav_lock ( "
"uri, lock_type, timeout, lock_token, lockkey) "
"VALUES ('%s', %d, %d, '%s', '%s')",
key, DAV_LOCK_INDIRECT, (int)ip->timeout,
ip->locktoken->char_uuid ? ip->locktoken->char_uuid : "",
ip->key ? ip->key : "");
/* Execute sequry */
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_save_lock_record: insert(2)", rv);;
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return
solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,"DBMS Error");
}
}
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return NULL;
}
dav_error *dbms_remove_lock_record(request_rec *r,
const char *key, apr_pool_t * pool)
{
const char *query;
ap_dbd_t *db;
apr_status_t rv;
int nrows;
char tmpOrgURI[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
TRACE();
dav_repos_replace_unsafe_chars(key, tmpOrgURI);
/* We need to add name space to DB and fill hash */
//apr_thread_rwlock_wrlock(db_lock);
query =
apr_psprintf(pool, "DELETE FROM t_dav_lock WHERE URI='%s'", tmpOrgURI);
/* Execute sequry */
db = dav_repos_get_db(r);
if (db == NULL) {
return solbox_dav_new_error(pool, HTTP_SERVICE_UNAVAILABLE, 0, "dbms_remove_lock_record: database acquire timeout");
}
rv = apr_dbd_query(db->driver, db->handle, &nrows, query);
if (rv) {
db_error_message(db, "dbms_remove_lock_record: delete", rv);;
dav_repos_release_db(r, db, rv);
//apr_thread_rwlock_unlock(db_lock);
return solbox_dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DBMS Error");
}
dav_repos_release_db(r, db, rv);
return NULL;
}
int dbms_lock_exists(request_rec *r, const char *key, apr_pool_t * pool)
{
int iret = 0;
int iselected_attr = 0;
char *query = NULL;
ap_dbd_t *db;
apr_dbd_results_t *res = NULL;
apr_dbd_row_t *row = NULL;
apr_status_t rv;
char tmpOrgURI[MaxSizeOfFileNameLength + MaxSizeOfFileNameLength];
dav_repos_replace_unsafe_chars(key, tmpOrgURI);
query = apr_psprintf(pool,
"SELECT COUNT(uri) FROM t_dav_lock "
#ifdef __IGNORE_CASE_DOWNLOAD__
//"WHERE lower(uri) = lower('%s'); "
"WHERE uri = '%s'; "
#else
"WHERE uri = '%s'; "
#endif
, tmpOrgURI);
/* Execute sequry */
db = dav_repos_get_db(r);
if(db == NULL)
{
db_error_message(db, "dbms_lock_exists: database acquire timeout", 0);
return -1;
}
rv = apr_dbd_select(db->driver, r->pool, db->handle, &res, query, 1);
if (rv)
{
db_error_message(db, "dbms_lock_exists: select", rv);;
dav_repos_release_db(r, db, rv);
return -1;
}
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, 0);
if (rv)
{
db_error_message(db, "dbms_lock_exists: get row", rv);
dav_repos_release_db(r, db, rv);
return -2;
}
iselected_attr = atoi(apr_dbd_get_entry(db->driver, row,0));
if( iselected_attr < 0)
{
iret = -1;
}
else if( iselected_attr == 0)
{
iret = 0;
}
else
{
iret = 1;
}
dav_repos_release_db(r, db, rv);
return iret;
}