]> git.sur5r.net Git - openldap/commitdiff
ITS#5408 part 9 - Sorted RDNs.
authorHallvard Furuseth <hallvard@openldap.org>
Wed, 12 Nov 2008 00:03:55 +0000 (00:03 +0000)
committerHallvard Furuseth <hallvard@openldap.org>
Wed, 12 Nov 2008 00:03:55 +0000 (00:03 +0000)
- Parse sorted attrs more carefully:
  Accept only attr={num}val.ldif and attr=val{num}.ldif and only base 10.
  Sort "attr=foo" before "attr=foo{n}".  Truncate at ".ldif" while sorting.
- Make the sort order independent of the LDIF files' order in the directory.

servers/slapd/back-ldif/ldif.c

index a6407d73a0b44781a3a2c6ed415c9d98f8821408..edbbf93ddc18a5ee06cbfe3183eb386bdd349b00 100644 (file)
@@ -137,6 +137,7 @@ struct ldif_info {
 
 /* Collect other "safe char" tests here, until someone needs a fix. */
 enum {
+       eq_unsafe = LDIF_UNSAFE_CHAR('='),
        safe_filenames = STRLENOF("" LDAP_DIRSEP "") == 1 && !(
                LDIF_UNSAFE_CHAR('-') || /* for "{-1}frontend" in bconfig.c */
                LDIF_UNSAFE_CHAR(LDIF_ESCAPE_CHAR) ||
@@ -565,11 +566,14 @@ get_entry(
 
 /*
  * RDN-named directory entry, with special handling of "attr={num}val" RDNs.
+ * For sorting, filename "attr=val.ldif" is truncated to "attr="val\0ldif",
+ * and filename "attr={num}val.ldif" to "attr={\0um}val.ldif".
+ * Does not sort escaped chars correctly, would need to un-escape them.
  */
 typedef struct bvlist {
        struct bvlist *next;
        char *trunc;    /* filename was truncated here */
-       int  inum;              /* num from "attr={num}" in filename, if any */
+       int  inum;              /* num from "attr={num}" in filename, or INT_MIN */
        char savech;    /* original char at *trunc */
        char fname;             /* variable length array BVL_NAME(bvl) = &fname */
 #      define BVL_NAME(bvl) ((char *) (bvl) + offsetof(bvlist, fname))
@@ -667,10 +671,10 @@ ldif_readdir(
                while ( (dir = readdir( dir_of_path )) != NULL ) {
                        size_t fname_len;
                        bvlist *bvl, **prev;
-                       char *idxp, *endp;
+                       char *trunc, *idxp, *endp, *endp2;
 
                        fname_len = strlen( dir->d_name );
-                       if ( fname_len <= STRLENOF( LDIF ))
+                       if ( fname_len < STRLENOF( "x=" LDIF )) /* min filename size */
                                continue;
                        if ( strcmp( dir->d_name + fname_len - STRLENOF(LDIF), LDIF ))
                                continue;
@@ -685,22 +689,28 @@ ldif_readdir(
                        }
                        strcpy( BVL_NAME( bvl ), dir->d_name );
 
-                       bvl->savech = '\0';
-                       if ( (idxp = strchr( BVL_NAME( bvl ), IX_FSL )) != NULL &&
-                                (endp = strchr( ++idxp, IX_FSR )) != NULL )
+                       /* Make it sortable by ("attr=val" or <preceding {num}, num>) */
+                       trunc = BVL_NAME( bvl ) + fname_len - STRLENOF( LDIF );
+                       if ( (idxp = strchr( BVL_NAME( bvl ) + 2, IX_FSL )) != NULL &&
+                                (endp = strchr( ++idxp, IX_FSR )) != NULL && endp > idxp &&
+                                (eq_unsafe || idxp[-2] == '=' || endp + 1 == trunc) )
                        {
                                /* attr={n}val or bconfig.c's "pseudo-indexed" attr=val{n} */
-                               bvl->inum = strtol( idxp, NULL, 0 );
-                               bvl->trunc = idxp;
-                               bvl->savech = *idxp;
-                               *idxp = '\0';
+                               bvl->inum = strtol( idxp, &endp2, 10 );
+                               if ( endp2 == endp ) {
+                                       trunc = idxp;
+                                       goto truncate;
+                               }
                        }
+                       bvl->inum = INT_MIN;
+               truncate:
+                       bvl->trunc = trunc;
+                       bvl->savech = *trunc;
+                       *trunc = '\0';
 
                        for ( prev = listp; (ptr = *prev) != NULL; prev = &ptr->next ) {
                                int cmp = strcmp( BVL_NAME( bvl ), BVL_NAME( ptr ));
-                               if ( !cmp && bvl->savech )
-                                       cmp = bvl->inum - ptr->inum;
-                               if ( cmp < 0 )
+                               if ( cmp < 0 || (cmp == 0 && bvl->inum < ptr->inum) )
                                        break;
                        }
                        *prev = bvl;
@@ -776,7 +786,6 @@ ldif_search_entry(
                                ptr = list;
 
                                if ( rc == LDAP_SUCCESS ) {
-                                       if ( ptr->savech )
                                        *ptr->trunc = ptr->savech;
                                        FILL_PATH( &fpath, dir_end, BVL_NAME( ptr ));