[SCM] Samba Shared Repository - branch master updated
Andrew Bartlett
abartlet at samba.org
Mon Mar 22 03:27:12 MDT 2010
The branch, master has been updated
via f8019ff... s4:dsdb Add a shortcut sequence number for schema reloads
via fe3e1af... s4:dsdb Rework schema loading and add schema reloading
via d0b5447... s4:dsdb Move dsdb_save_partition_usn() to be a module helper function
via 639728a... s4:schema Expand the schema structure
via 775c5ec... s4:dsdb Remove unused 'dsdb_make_schema_global' call from pyglue
via 7fc94eb... s4:dsdb Add 'const' to some struct dsdb_schema variables
via fc5a507... s4:dsdb Don't load the schema unconditionally
from 8195832... s3: file_walk_table -> files_forall
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit f8019ff793a735563ccedf5581c72e015fd62014
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 18:44:51 2010 +1100
s4:dsdb Add a shortcut sequence number for schema reloads
This uses the ldb sequence number, in a hope to detect an unchanged
schema quicker.
Andrew Bartlett
commit fe3e1af901c970f738bee92baac5d7d4f5736e17
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 16:03:33 2010 +1100
s4:dsdb Rework schema loading and add schema reloading
This commit reworks Samba4's schema loading code to detect when it
needs to reload the schema. This is done by watching the @REPLCHANGED
special DN.
The reload happens by means of a callback, which is only set when the
schema is loaded from the ldb - not when loaded from an LDIF file or
DRS.
We also rework the global schema handling - instead of storing the
pointer to the global schema in each ldb, we store a flag indicating
that the global schema should be returned at run time. This makes it
much easier to switch to a new global schema.
Andrew Bartlett
commit d0b54476fc9f855d1e482597538a7ec60e04f331
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 16:00:39 2010 +1100
s4:dsdb Move dsdb_save_partition_usn() to be a module helper function
This function should not traverse the module stack again, but instead
run from this point. Also add a matching
dsdb_module_load_partition_usn() and change repl_meta_data to match.
Andrew Bartlett
commit 639728a29873e4cf59dfa149a231eae353f3753a
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 15:41:51 2010 +1100
s4:schema Expand the schema structure
We now store the location of the schema in the schema, and provide
hooks for a future schema reloading mechanism.
Andrew Bartlett
commit 775c5ec1c57b4acf61c1c750c4832f64defcb5b6
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 15:20:47 2010 +1100
s4:dsdb Remove unused 'dsdb_make_schema_global' call from pyglue
commit 7fc94eb9a7034c36943efbe04f4f4cdfb174c50e
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 15:19:55 2010 +1100
s4:dsdb Add 'const' to some struct dsdb_schema variables
We don't currently require this, but we may move this way in future.
commit fc5a507a86f37aecb6702d8c2c3bdc462e49f9fd
Author: Andrew Bartlett <abartlet at samba.org>
Date: Mon Mar 22 15:17:58 2010 +1100
s4:dsdb Don't load the schema unconditionally
Schema loads now come at a price, so avoid doing them if we don't have
to (such as when doing an @REPLCHANGED or other special DN based
search).
Andrew Bartlett
-----------------------------------------------------------------------
Summary of changes:
source4/dsdb/common/util.c | 88 -------
source4/dsdb/samdb/ldb_modules/extended_dn_out.c | 7 +-
source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 23 +-
source4/dsdb/samdb/ldb_modules/schema_data.c | 17 +-
source4/dsdb/samdb/ldb_modules/schema_load.c | 296 ++++++++++++++--------
source4/dsdb/samdb/ldb_modules/util.c | 175 +++++++++++++
source4/dsdb/schema/schema.h | 11 +
source4/dsdb/schema/schema_init.c | 2 +
source4/dsdb/schema/schema_set.c | 80 ++++--
source4/lib/ldb_wrap.c | 5 +-
source4/scripting/python/pyglue.c | 17 --
11 files changed, 469 insertions(+), 252 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c
index 9c29509..b469b06 100644
--- a/source4/dsdb/common/util.c
+++ b/source4/dsdb/common/util.c
@@ -2585,94 +2585,6 @@ int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
return LDB_SUCCESS;
}
-/*
- save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
- partition
- */
-int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
- uint64_t uSN, uint64_t urgent_uSN)
-{
- struct ldb_request *req;
- struct ldb_message *msg;
- struct dsdb_control_current_partition *p_ctrl;
- int ret;
-
- msg = ldb_msg_new(ldb);
- if (msg == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
- if (msg->dn == NULL) {
- talloc_free(msg);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
- if (ret != LDB_SUCCESS) {
- talloc_free(msg);
- return ret;
- }
- msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
-
- /* urgent_uSN is optional so may not be stored */
- if (urgent_uSN) {
- ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
- if (ret != LDB_SUCCESS) {
- talloc_free(msg);
- return ret;
- }
- msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
- }
-
-
- p_ctrl = talloc(msg, struct dsdb_control_current_partition);
- if (p_ctrl == NULL) {
- talloc_free(msg);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
- p_ctrl->dn = dn;
-
- ret = ldb_build_mod_req(&req, ldb, msg,
- msg,
- NULL,
- NULL, ldb_op_default_callback,
- NULL);
-again:
- if (ret != LDB_SUCCESS) {
- talloc_free(msg);
- return ret;
- }
-
- ret = ldb_request_add_control(req,
- DSDB_CONTROL_CURRENT_PARTITION_OID,
- false, p_ctrl);
- if (ret != LDB_SUCCESS) {
- talloc_free(msg);
- return ret;
- }
-
- /* Run the new request */
- ret = ldb_request(ldb, req);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
- ret = ldb_build_add_req(&req, ldb, msg,
- msg,
- NULL,
- NULL, ldb_op_default_callback,
- NULL);
- goto again;
- }
-
- talloc_free(msg);
-
- return ret;
-}
-
int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
const struct drsuapi_DsReplicaCursor2 *c2)
{
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c
index b5f4567..f28ad8e 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c
@@ -564,6 +564,11 @@ static int extended_dn_out_search(struct ldb_module *module, struct ldb_request
struct extended_dn_out_private *p = talloc_get_type(ldb_module_get_private(module), struct extended_dn_out_private);
+ /* The schema manipulation does not apply to special DNs */
+ if (ldb_dn_is_special(req->op.search.base)) {
+ return ldb_next_request(module, req);
+ }
+
/* check if there's an extended dn control */
control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
if (control && control->data) {
@@ -743,7 +748,7 @@ static int extended_dn_out_dereference_init(struct ldb_module *module, const cha
struct dsdb_openldap_dereference_control *dereference_control;
struct dsdb_attribute *cur;
struct ldb_context *ldb = ldb_module_get_ctx(module);
- struct dsdb_schema *schema;
+ const struct dsdb_schema *schema;
ldb_module_set_private(module, p);
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index a7e2a48..8b4e012 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -454,15 +454,14 @@ static int replmd_notify_store(struct ldb_module *module)
{
struct replmd_private *replmd_private =
talloc_get_type(ldb_module_get_private(module), struct replmd_private);
- struct ldb_context *ldb = ldb_module_get_ctx(module);
while (replmd_private->ncs) {
int ret;
struct nc_entry *modified_partition = replmd_private->ncs;
- ret = dsdb_save_partition_usn(ldb, modified_partition->dn,
- modified_partition->mod_usn,
- modified_partition->mod_usn_urgent);
+ ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
+ modified_partition->mod_usn,
+ modified_partition->mod_usn_urgent);
if (ret != LDB_SUCCESS) {
DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
ldb_dn_get_linearized(modified_partition->dn)));
@@ -668,7 +667,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme
struct ldb_context *ldb = ldb_module_get_ctx(module);
/* We will take a reference to the schema in replmd_add_backlink */
- struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
+ const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
NTTIME now;
unix_to_nt_time(&now, t);
@@ -1537,7 +1536,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d
handle adding a linked attribute
*/
static int replmd_modify_la_add(struct ldb_module *module,
- struct dsdb_schema *schema,
+ const struct dsdb_schema *schema,
struct ldb_message *msg,
struct ldb_message_element *el,
struct ldb_message_element *old_el,
@@ -1656,7 +1655,7 @@ static int replmd_modify_la_add(struct ldb_module *module,
handle deleting all active linked attributes
*/
static int replmd_modify_la_delete(struct ldb_module *module,
- struct dsdb_schema *schema,
+ const struct dsdb_schema *schema,
struct ldb_message *msg,
struct ldb_message_element *el,
struct ldb_message_element *old_el,
@@ -1775,7 +1774,7 @@ static int replmd_modify_la_delete(struct ldb_module *module,
handle replacing a linked attribute
*/
static int replmd_modify_la_replace(struct ldb_module *module,
- struct dsdb_schema *schema,
+ const struct dsdb_schema *schema,
struct ldb_message *msg,
struct ldb_message_element *el,
struct ldb_message_element *old_el,
@@ -1937,7 +1936,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_message *old_msg;
- struct dsdb_schema *schema;
+ const struct dsdb_schema *schema;
struct GUID old_guid;
if (seq_num == 0) {
@@ -2235,7 +2234,7 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are
is deleted
*/
static int replmd_delete_remove_link(struct ldb_module *module,
- struct dsdb_schema *schema,
+ const struct dsdb_schema *schema,
struct ldb_dn *dn,
struct ldb_message_element *el,
const struct dsdb_attribute *sa)
@@ -2322,7 +2321,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
const struct ldb_val *rdn_value, *new_rdn_value;
struct GUID guid;
struct ldb_context *ldb = ldb_module_get_ctx(module);
- struct dsdb_schema *schema;
+ const struct dsdb_schema *schema;
struct ldb_message *msg, *old_msg;
struct ldb_message_element *el;
TALLOC_CTX *tmp_ctx;
@@ -3510,7 +3509,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module,
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_message *msg;
TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
- struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
+ const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
int ret;
const struct dsdb_attribute *attr;
struct dsdb_dn *dsdb_dn;
diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c
index 25f2dce..655b489 100644
--- a/source4/dsdb/samdb/ldb_modules/schema_data.c
+++ b/source4/dsdb/samdb/ldb_modules/schema_data.c
@@ -417,12 +417,17 @@ static int schema_data_search(struct ldb_module *module, struct ldb_request *req
int ret;
struct schema_data_search_data *search_context;
struct ldb_request *down_req;
- struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
+ const struct dsdb_schema *schema;
+ if (!ldb_module_get_private(module)) {
+ /* If there is no module data, there is little we can do */
+ return ldb_next_request(module, req);
+ }
- if (!schema || !ldb_module_get_private(module)) {
- /* If there is no schema, there is little we can do */
+ /* The schema manipulation does not apply to special DNs */
+ if (ldb_dn_is_special(req->op.search.base)) {
return ldb_next_request(module, req);
}
+
for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
break;
@@ -434,6 +439,12 @@ static int schema_data_search(struct ldb_module *module, struct ldb_request *req
return ldb_next_request(module, req);
}
+ schema = dsdb_get_schema(ldb, NULL);
+ if (!schema || !ldb_module_get_private(module)) {
+ /* If there is no schema, there is little we can do */
+ return ldb_next_request(module, req);
+ }
+
search_context = talloc(req, struct schema_data_search_data);
if (!search_context) {
ldb_oom(ldb);
diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c
index 5ea70fb..d13b339 100644
--- a/source4/dsdb/samdb/ldb_modules/schema_load.c
+++ b/source4/dsdb/samdb/ldb_modules/schema_load.c
@@ -5,8 +5,8 @@
checkings, it also loads the dsdb_schema.
Copyright (C) Stefan Metzmacher <metze at samba.org> 2007
- Copyright (C) Andrew Bartlett <abartlet at samba.org> 2009
-
+ Copyright (C) Andrew Bartlett <abartlet at samba.org> 2009-2010
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
@@ -31,19 +31,123 @@
#include "param/param.h"
#include "dsdb/samdb/ldb_modules/util.h"
+struct schema_load_private_data {
+ bool in_transaction;
+};
+
+static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn,
+ struct dsdb_schema **schema);
+
+struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct dsdb_schema *schema, bool is_global_schema)
+{
+ uint64_t current_usn;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_request *treq;
+ struct ldb_seqnum_request *tseq;
+ struct ldb_seqnum_result *tseqr;
+ struct dsdb_control_current_partition *ctrl;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct dsdb_schema *new_schema;
+
+ struct schema_load_private_data *private_data = talloc_get_type(ldb_module_get_private(module), struct schema_load_private_data);
+ if (!private_data) {
+ /* We can't refresh until the init function has run */
+ return schema;
+ }
+
+ /* We don't allow a schema reload during a transaction - nobody else can modify our schema behind our backs */
+ if (private_data->in_transaction) {
+ return schema;
+ }
+
+ res = talloc_zero(schema, struct ldb_result);
+ if (res == NULL) {
+ return NULL;
+ }
+ tseq = talloc_zero(res, struct ldb_seqnum_request);
+ if (tseq == NULL) {
+ talloc_free(res);
+ return NULL;
+ }
+ tseq->type = LDB_SEQ_HIGHEST_SEQ;
+
+ ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
+ LDB_EXTENDED_SEQUENCE_NUMBER,
+ tseq,
+ NULL,
+ res,
+ ldb_extended_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return NULL;
+ }
+
+ ctrl = talloc(treq, struct dsdb_control_current_partition);
+ if (!ctrl) {
+ talloc_free(res);
+ return NULL;
+ }
+ ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
+ ctrl->dn = schema->base_dn;
+
+ ret = ldb_request_add_control(treq,
+ DSDB_CONTROL_CURRENT_PARTITION_OID,
+ false, ctrl);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return NULL;
+ }
+
+ ret = ldb_next_request(module, treq);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return NULL;
+ }
+ ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return NULL;
+ }
+ tseqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ if (tseqr->seq_num == schema->reload_seq_number) {
+ talloc_free(res);
+ return schema;
+ }
+
+ schema->reload_seq_number = tseqr->seq_num;
+ talloc_free(res);
+
+ ret = dsdb_module_load_partition_usn(module, schema->base_dn, ¤t_usn, NULL);
+ if (ret != LDB_SUCCESS || current_usn == schema->loaded_usn) {
+ return schema;
+ }
+
+ ret = dsdb_schema_from_db(module, schema->base_dn, current_usn, &new_schema);
+ if (ret != LDB_SUCCESS) {
+ return schema;
+ }
+
+ if (is_global_schema) {
+ dsdb_make_schema_global(ldb, new_schema);
+ }
+ return new_schema;
+}
+
+
/*
Given an LDB module (pointing at the schema DB), and the DN, set the populated schema
*/
-static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *module,
- struct smb_iconv_convenience *iconv_convenience,
- struct ldb_dn *schema_dn,
- struct dsdb_schema **schema)
+static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn,
+ struct dsdb_schema **schema)
{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
TALLOC_CTX *tmp_ctx;
char *error_string;
int ret;
- struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_result *schema_res;
struct ldb_result *a_res;
struct ldb_result *c_res;
@@ -55,7 +159,7 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo
};
unsigned flags;
- tmp_ctx = talloc_new(mem_ctx);
+ tmp_ctx = talloc_new(module);
if (!tmp_ctx) {
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
@@ -71,6 +175,9 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo
ret = dsdb_module_search_dn(module, tmp_ctx, &schema_res,
schema_dn, schema_attrs, 0);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_reset_err_string(ldb);
+ ldb_debug(ldb, LDB_DEBUG_WARNING,
+ "schema_load_init: no schema head present: (skip schema loading)\n");
goto failed;
} else if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb,
@@ -112,11 +219,31 @@ static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *mo
schema_res, a_res, c_res, schema, &error_string);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ldb,
- "dsdb_schema load failed: %s",
- error_string);
+ "dsdb_schema load failed: %s",
+ error_string);
goto failed;
}
- talloc_steal(mem_ctx, *schema);
+
+ (*schema)->refresh_fn = dsdb_schema_refresh;
+ (*schema)->loaded_from_module = module;
+ (*schema)->loaded_usn = current_usn;
+
+ /* dsdb_set_schema() steal schema into the ldb_context */
+ ret = dsdb_set_schema(ldb, (*schema));
+
+ if (ret != LDB_SUCCESS) {
+ ldb_debug_set(ldb, LDB_DEBUG_FATAL,
+ "schema_load_init: dsdb_set_schema() failed: %d:%s: %s",
+ ret, ldb_strerror(ret), ldb_errstring(ldb));
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /* Ensure this module won't go away before the callback */
+ if (talloc_reference(*schema, ldb) == NULL) {
+ ldb_oom(ldb);
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
failed:
if (flags & LDB_FLG_ENABLE_TRACING) {
@@ -130,18 +257,30 @@ failed:
static int schema_load_init(struct ldb_module *module)
{
- struct ldb_context *ldb;
- TALLOC_CTX *mem_ctx;
- struct ldb_dn *schema_dn;
+ struct schema_load_private_data *private_data;
struct dsdb_schema *schema;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
int ret;
+ uint64_t current_usn;
+ struct ldb_dn *schema_dn;
+
+ private_data = talloc_zero(module, struct schema_load_private_data);
+ if (private_data == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_module_set_private(module, private_data);
ret = ldb_next_init(module);
if (ret != LDB_SUCCESS) {
return ret;
}
- ldb = ldb_module_get_ctx(module);
+ if (dsdb_get_schema(ldb, NULL)) {
+ return LDB_SUCCESS;
+ }
+
schema_dn = samdb_schema_dn(ldb);
if (!schema_dn) {
ldb_reset_err_string(ldb);
@@ -150,54 +289,51 @@ static int schema_load_init(struct ldb_module *module)
return LDB_SUCCESS;
}
- if (dsdb_get_schema(ldb, NULL)) {
- return LDB_SUCCESS;
+ ret = dsdb_module_load_partition_usn(module, schema_dn, ¤t_usn, NULL);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb,
+ "dsdb_load_partition_usn failed: %s",
--
Samba Shared Repository
More information about the samba-cvs
mailing list