/**************************************************************************** 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 #include #include #include #include #include /* for ap_construct_url */ #include #include #include #include #include #include //#include #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 : 형식으로 전달받는 경우 // 해당 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 : 형식으로 전달받는 경우 // 해당 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; }