📄 ldif.c
字号:
/* ldif.c - the ldif backend *//* $OpenLDAP: pkg/ldap/servers/slapd/back-ldif/ldif.c,v 1.1.2.22 2007/01/02 21:44:03 kurt Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2005-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was originally developed by Eric Stokes for inclusion * in OpenLDAP Software. */#include "portable.h"#include <stdio.h>#include <ac/string.h>#include <sys/types.h>#include <sys/stat.h>#include <ac/dirent.h>#include <fcntl.h>#include <ac/errno.h>#include <ac/unistd.h>#include "slap.h"#include "lutil.h"#include "config.h"typedef struct enumCookie { Operation *op; SlapReply *rs; Entry **entries; int elen; int eind;} enumCookie;struct ldif_info { struct berval li_base_path; enumCookie li_tool_cookie; ID li_tool_current; ldap_pvt_thread_rdwr_t li_rdwr;};#ifdef _WIN32#define mkdir(a,b) mkdir(a)#endif#define LDIF ".ldif"#define IX_DNL '{'#define IX_DNR '}'#ifndef IX_FSL#define IX_FSL IX_DNL#define IX_FSR IX_DNR#endif#define ENTRY_BUFF_INCREMENT 500static ConfigTable ldifcfg[] = { { "directory", "dir", 2, 2, 0, ARG_BERVAL|ARG_OFFSET, (void *)offsetof(struct ldif_info, li_base_path), "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' " "DESC 'Directory for database content' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL, NULL, NULL, NULL }};static ConfigOCs ldifocs[] = { { "( OLcfgDbOc:2.1 " "NAME 'olcLdifConfig' " "DESC 'LDIF backend configuration' " "SUP olcDatabaseConfig " "MUST ( olcDbDirectory ) )", Cft_Database, ldifcfg }, { NULL, 0, NULL }};static voiddn2path(struct berval * dn, struct berval * suffixdn, struct berval * base_path, struct berval *res){ char *ptr, *sep, *end; assert( dn != NULL ); assert( !BER_BVISNULL( dn ) ); assert( suffixdn != NULL ); assert( !BER_BVISNULL( suffixdn ) ); assert( dnIsSuffix( dn, suffixdn ) ); res->bv_len = dn->bv_len + base_path->bv_len + 1 + STRLENOF( LDIF ); res->bv_val = ch_malloc( res->bv_len + 1 ); ptr = lutil_strcopy( res->bv_val, base_path->bv_val ); *ptr++ = LDAP_DIRSEP[0]; ptr = lutil_strcopy( ptr, suffixdn->bv_val ); end = dn->bv_val + dn->bv_len - suffixdn->bv_len - 1; while ( end > dn->bv_val ) { for (sep = end-1; sep >=dn->bv_val && !DN_SEPARATOR( *sep ); sep--); *ptr++ = LDAP_DIRSEP[0]; ptr = lutil_strncopy( ptr, sep+1, end-sep-1 ); end = sep; } strcpy(ptr, LDIF);#if IX_FSL != IX_DNL ptr = res->bv_val; while( ptr=strchr(ptr, IX_DNL) ) { *ptr++ = IX_FSL; ptr = strchr(ptr, IX_DNR); if ( ptr ) *ptr++ = IX_FSR; else break; }#endif}static char * slurp_file(int fd) { int read_chars_total = 0; int read_chars = 0; int entry_size; char * entry; char * entry_pos; struct stat st; fstat(fd, &st); entry_size = st.st_size; entry = ch_malloc( entry_size+1 ); entry_pos = entry; while(1) { read_chars = read(fd, (void *) entry_pos, entry_size - read_chars_total); if(read_chars == -1) { SLAP_FREE(entry); return NULL; } if(read_chars == 0) { entry[read_chars_total] = '\0'; break; } else { read_chars_total += read_chars; entry_pos += read_chars; } } return entry;}static int spew_file(int fd, char * spew, int len) { int writeres = 0; while(len > 0) { writeres = write(fd, spew, len); if(writeres == -1) { Debug( LDAP_DEBUG_ANY, "could not spew write: %s\n", STRERROR( errno ), 0, 0 ); return -1; } else { spew += writeres; len -= writeres; } } return writeres;}static int spew_entry(Entry * e, struct berval * path) { int rs; int openres; int spew_res; int entry_length; char * entry_as_string; openres = open(path->bv_val, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR); if(openres == -1) { if(errno == ENOENT) rs = LDAP_NO_SUCH_OBJECT; else rs = LDAP_UNWILLING_TO_PERFORM; Debug( LDAP_DEBUG_ANY, "could not open \"%s\": %s\n", path->bv_val, STRERROR( errno ), 0 ); } else { struct berval rdn; int tmp; /* Only save the RDN onto disk */ dnRdn( &e->e_name, &rdn ); if ( rdn.bv_len != e->e_name.bv_len ) { e->e_name.bv_val[rdn.bv_len] = '\0'; tmp = e->e_name.bv_len; e->e_name.bv_len = rdn.bv_len; rdn.bv_len = tmp; } entry_as_string = entry2str(e, &entry_length); /* Restore full DN */ if ( rdn.bv_len != e->e_name.bv_len ) { e->e_name.bv_val[e->e_name.bv_len] = ','; e->e_name.bv_len = rdn.bv_len; } if(entry_as_string == NULL) { rs = LDAP_UNWILLING_TO_PERFORM; close(openres); } else { spew_res = spew_file(openres, entry_as_string, entry_length); close(openres); if(spew_res == -1) rs = LDAP_UNWILLING_TO_PERFORM; else rs = LDAP_SUCCESS; } } return rs;}static Entry * get_entry_for_fd(int fd, struct berval *pdn, struct berval *pndn){ char * entry = (char *) slurp_file(fd); Entry * ldentry = NULL; /* error reading file */ if(entry == NULL) { goto return_value; } ldentry = str2entry(entry); if ( ldentry ) { struct berval rdn; rdn = ldentry->e_name; build_new_dn( &ldentry->e_name, pdn, &rdn, NULL ); ch_free( rdn.bv_val ); rdn = ldentry->e_nname; build_new_dn( &ldentry->e_nname, pndn, &rdn, NULL ); ch_free( rdn.bv_val ); } return_value: if(fd != -1) { if(close(fd) != 0) { /* log error */ } } if(entry != NULL) SLAP_FREE(entry); return ldentry;}static Entry * get_entry(Operation *op, struct berval *base_path) { struct berval path, pdn, pndn; int fd; dnParent(&op->o_req_dn, &pdn); dnParent(&op->o_req_ndn, &pndn); dn2path(&op->o_req_ndn, op->o_bd->be_nsuffix, base_path, &path); fd = open(path.bv_val, O_RDONLY); /* error opening file (mebbe should log error) */ if ( fd == -1 && ( errno != ENOENT || op->o_tag != LDAP_REQ_ADD ) ) { Debug( LDAP_DEBUG_ANY, "failed to open file \"%s\": %s\n", path.bv_val, STRERROR(errno), 0 ); } if(path.bv_val != NULL) SLAP_FREE(path.bv_val); if ( fd != -1 ) { return get_entry_for_fd(fd, &pdn, &pndn); } return NULL;}static void fullpath(struct berval *base, struct berval *name, struct berval *res) { char *ptr; res->bv_len = name->bv_len + base->bv_len + 1; res->bv_val = ch_malloc( res->bv_len + 1 ); strcpy(res->bv_val, base->bv_val); ptr = res->bv_val + base->bv_len; *ptr++ = LDAP_DIRSEP[0]; strcpy(ptr, name->bv_val);}typedef struct bvlist { struct bvlist *next; struct berval bv; struct berval num; unsigned int inum; int off;} bvlist;static int r_enum_tree(enumCookie *ck, struct berval *path, struct berval *pdn, struct berval *pndn){ Entry *e; int fd, rc = LDAP_SUCCESS; fd = open( path->bv_val, O_RDONLY ); if ( fd < 0 ) { Debug( LDAP_DEBUG_ANY, "=> ldif_enum_tree: failed to open %s: %s\n", path->bv_val, STRERROR(errno), 0 ); return LDAP_NO_SUCH_OBJECT; } e = get_entry_for_fd(fd, pdn, pndn); if ( !e ) { Debug( LDAP_DEBUG_ANY, "=> ldif_enum_tree: failed to read entry for %s\n", path->bv_val, 0, 0 ); return LDAP_BUSY; } if ( ck->op->ors_scope == LDAP_SCOPE_BASE || ck->op->ors_scope == LDAP_SCOPE_SUBTREE ) { /* Send right away? */ if ( ck->rs ) { /* * if it's a referral, add it to the list of referrals. only do * this for non-base searches, and don't check the filter * explicitly here since it's only a candidate anyway. */ if ( !get_manageDSAit( ck->op ) && ck->op->ors_scope != LDAP_SCOPE_BASE && is_entry_referral( e ) ) { BerVarray erefs = get_entry_referrals( ck->op, e ); ck->rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL, ck->op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE ); ck->rs->sr_entry = e; rc = send_search_reference( ck->op, ck->rs ); ber_bvarray_free( ck->rs->sr_ref ); ber_bvarray_free( erefs ); ck->rs->sr_ref = NULL; ck->rs->sr_entry = NULL; } else if ( test_filter( ck->op, e, ck->op->ors_filter ) == LDAP_COMPARE_TRUE ) { ck->rs->sr_entry = e; ck->rs->sr_attrs = ck->op->ors_attrs; ck->rs->sr_flags = REP_ENTRY_MODIFIABLE; rc = send_search_entry(ck->op, ck->rs); ck->rs->sr_entry = NULL; } fd = 1; if ( rc ) goto done; } else { /* Queueing up for tool mode */ if(ck->entries == NULL) { ck->entries = (Entry **) ch_malloc(sizeof(Entry *) * ENTRY_BUFF_INCREMENT); ck->elen = ENTRY_BUFF_INCREMENT; } if(ck->eind >= ck->elen) { /* grow entries if necessary */ ck->entries = (Entry **) ch_realloc(ck->entries, sizeof(Entry *) * (ck->elen) * 2); ck->elen *= 2; } ck->entries[ck->eind++] = e; fd = 0; } } else { fd = 1; } if ( ck->op->ors_scope != LDAP_SCOPE_BASE ) { DIR * dir_of_path; bvlist *list = NULL, *ptr; path->bv_len -= STRLENOF( LDIF ); path->bv_val[path->bv_len] = '\0'; dir_of_path = opendir(path->bv_val); if(dir_of_path == NULL) { /* can't open directory */ if ( errno != ENOENT ) { /* it shouldn't be treated as an error * only if the directory doesn't exist */ rc = LDAP_BUSY; Debug( LDAP_DEBUG_ANY, "=> ldif_enum_tree: failed to opendir %s (%d)\n", path->bv_val, errno, 0 ); } goto done; } while(1) { struct berval fname, itmp; struct dirent * dir; bvlist *bvl, **prev; dir = readdir(dir_of_path); if(dir == NULL) break; /* end of the directory */ fname.bv_len = strlen( dir->d_name ); if ( fname.bv_len <= STRLENOF( LDIF )) continue; if ( strcmp( dir->d_name + (fname.bv_len - STRLENOF(LDIF)), LDIF)) continue; fname.bv_val = dir->d_name; bvl = ch_malloc( sizeof(bvlist) ); ber_dupbv( &bvl->bv, &fname ); BER_BVZERO( &bvl->num ); itmp.bv_val = strchr( bvl->bv.bv_val, IX_FSL ); if ( itmp.bv_val ) { char *ptr; itmp.bv_val++; ptr = strchr( itmp.bv_val, IX_FSR ); if ( ptr ) { itmp.bv_len = ptr - itmp.bv_val; ber_dupbv( &bvl->num, &itmp ); bvl->inum = strtol( itmp.bv_val, NULL, 0 ); itmp.bv_val[0] = '\0'; bvl->off = itmp.bv_val - bvl->bv.bv_val; } } for (prev = &list; (ptr = *prev) != NULL; prev = &ptr->next) { int cmp = strcmp( bvl->bv.bv_val, ptr->bv.bv_val ); if ( !cmp && bvl->num.bv_val ) cmp = bvl->inum - ptr->inum; if ( cmp < 0 ) break; } *prev = bvl; bvl->next = ptr; } closedir(dir_of_path); if (ck->op->ors_scope == LDAP_SCOPE_ONELEVEL) ck->op->ors_scope = LDAP_SCOPE_BASE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -