--- libeio/eio.c 2009/06/06 17:25:13 1.31 +++ libeio/eio.c 2009/06/06 20:13:46 1.35 @@ -82,12 +82,18 @@ /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -# define D_INO(de) (de)->d_fileno # define _DIRENT_HAVE_D_TYPE /* sigh */ +# define D_INO(de) (de)->d_fileno +# define D_NAMLEN(de) (de)->d_namlen # elif defined(__linux) || defined(d_ino) || _XOPEN_SOURCE >= 600 # define D_INO(de) (de)->d_ino # endif +#ifdef _D_EXACT_NAMLEN +# undef D_NAMLEN +# define D_NAMLEN(de) _D_EXACT_NAMLEN (de) +#endif + # ifdef _DIRENT_HAVE_D_TYPE # define D_TYPE(de) (de)->d_type # endif @@ -116,10 +122,12 @@ #ifndef D_TYPE # define D_TYPE(de) 0 #endif - #ifndef D_INO # define D_INO(de) 0 #endif +#ifndef D_NAMLEN +# define D_NAMLEN(de) strlen ((de)->d_name) +#endif /* number of seconds after which an idle threads exit */ #define IDLE_TIMEOUT 10 @@ -180,6 +188,7 @@ closedir (wrk->dirp); \ wrk->dirp = 0; \ } + #define ETP_WORKER_COMMON \ void *dbuf; \ DIR *dirp; @@ -1012,13 +1021,11 @@ flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); X_LOCK (wrklock); - /* the corresponding closedir is in ETP_WORKER_CLEAR */ self->dirp = dirp = opendir (req->ptr1); req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; req->ptr1 = names = malloc (namesalloc); req->ptr2 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; - X_UNLOCK (wrklock); if (dirp && names && (!flags || dents)) @@ -1036,17 +1043,28 @@ req->int1 = flags; req->result = dentoffs; - if (flags & EIO_READDIR_STAT_ORDER || !(~flags & (EIO_READDIR_DIRS_FIRST | EIO_READDIR_FOUND_UNKNOWN)) + if (dents) + { + eio_dirent *ent = dents + dentoffs; + + while (ent > dents) + (--ent)->name = names + (size_t)ent->name; + } + + if (flags & EIO_READDIR_STAT_ORDER + || !(~flags & (EIO_READDIR_DIRS_FIRST | EIO_READDIR_FOUND_UNKNOWN))) { /* pray your qsort doesn't use quicksort */ qsort (dents, dentoffs, sizeof (*dents), eio_dent_cmp); /* score depends of DIRS_FIRST */ } - else if (flags & EIO_READDIR_DIRS_FIRST && !(flags & EIO_READDIR_FOUND_UNKNOWN)) + else if (flags & EIO_READDIR_DIRS_FIRST) { /* in this case, all is known, and we just put dirs first and sort them */ eio_dirent *ent = dents + dentoffs; eio_dirent *dir = dents; + /* now move dirs to the front, and non-dirs to the back */ + /* by walkign from both sides and swapping if necessary */ while (ent > dir) { if (dir->type == DT_DIR) @@ -1070,16 +1088,26 @@ qsort (dents, dir - dents, sizeof (*dents), eio_dent_cmp); } - {int i; for(i=0;iinode,e->score,e->name);}}//D + /* only provide the names array unless DENTS is specified */ + if (!(flags & EIO_READDIR_DENTS)) + { + X_LOCK (wrklock); + assert (!dents); + req->ptr1 = 0; + req->ptr2 = names; + X_UNLOCK (wrklock); + } break; } + /* now add the entry to our list(s) */ name = entp->d_name; + /* skip . and .. entries */ if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2]))) { - int len = strlen (name) + 1; + int len = D_NAMLEN (entp) + 1; while (expect_false (namesoffs + len > namesalloc)) { @@ -1111,7 +1139,7 @@ ent = dents + dentoffs; - ent->name = names + namesoffs; + ent->name = (char *)(size_t)namesoffs; /* rather dirtily we store the offset in the pointer */ ent->namelen = len - 1; ent->inode = D_INO (entp); @@ -1128,21 +1156,39 @@ #ifdef DT_CHR case DT_CHR: ent->type = EIO_DT_CHR; break; #endif - #ifdef DT_DIR + #ifdef DT_MPC + case DT_MPC: ent->type = EIO_DT_MPC; break; + #endif + #ifdef DT_DIR case DT_DIR: ent->type = EIO_DT_DIR; break; #endif - #ifdef DT_BLK + #ifdef DT_NAM + case DT_NAM: ent->type = EIO_DT_NAM; break; + #endif + #ifdef DT_BLK case DT_BLK: ent->type = EIO_DT_BLK; break; #endif - #ifdef DT_REG + #ifdef DT_MPB + case DT_MPB: ent->type = EIO_DT_MPB; break; + #endif + #ifdef DT_REG case DT_REG: ent->type = EIO_DT_REG; break; #endif - #ifdef DT_LNK + #ifdef DT_NWK + case DT_NWK: ent->type = EIO_DT_NWK; break; + #endif + #ifdef DT_CMP + case DT_CMP: ent->type = EIO_DT_CMP; break; + #endif + #ifdef DT_LNK case DT_LNK: ent->type = EIO_DT_LNK; break; #endif #ifdef DT_SOCK case DT_SOCK: ent->type = EIO_DT_SOCK; break; #endif + #ifdef DT_DOOR + case DT_DOOR: ent->type = EIO_DT_DOOR; break; + #endif #ifdef DT_WHT case DT_WHT: ent->type = EIO_DT_WHT; break; #endif @@ -1157,9 +1203,9 @@ if (*name == '.') /* leading dots are likely directories, and, in any case, rare */ ent->score = 98; else if (!strchr (name, '.')) /* absense of dots indicate likely dirs */ - ent->score = len <= 4 ? 5 : len <= 7 ? 4 : 1; /* shorter == more likely dir, but avoid too many classes */ + ent->score = len <= 2 ? len + 6 : len <= 4 ? 5 : len <= 7 ? 4 : 1; /* shorter == more likely dir, but avoid too many classes */ } - else if (ent->type == DT_DIR) + else if (ent->type == EIO_DT_DIR) ent->score = 100; } } @@ -1170,16 +1216,6 @@ } else req->result = -1; - - /* if user doesn't want the dents, do not provide it */ - if (!(flags & EIO_READDIR_DENTS)) - { - X_LOCK (wrklock); - free (dents); - req->ptr2 = req->ptr1; - req->ptr1 = 0; - X_UNLOCK (wrklock); - } } #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)