00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include <fcntl.h>
00010 #include <sys/stat.h>
00011 #include <sys/types.h>
00012 #include <errno.h>
00013 #include <unistd.h>
00014 #include <stdlib.h>
00015 #include <stdio.h>
00016 #include <string.h>
00017 #include <sys/stat.h>
00018 #include <errno.h>
00019 
00020 #include "est_ops.h"
00021 #include "direnum.h"
00022 #include "warnings.h"
00023 #include "global.h"
00024 #include "helper.h"
00025 
00026 
00057 #undef HAVE_GETDENTS64
00058 #ifdef HAVE_LINUX_TYPES_H 
00059 #ifdef HAVE_LINUX_UNISTD_H
00060 
00062 #define HAVE_GETDENTS64 1
00063 #endif
00064 #endif
00065 
00066 
00067 #ifdef HAVE_GETDENTS64
00068 
00069 #include <linux/types.h>
00070 #include <linux/unistd.h>
00071 
00073 typedef int dir__handle;
00077 typedef struct dirent64 fsvs_dirent;
00078 
00079 
00083 inline int dir__start_enum(dir__handle *dh, char *path)
00084 {   
00085     int status;
00086 
00087     status=0;
00088     *dh=open(path, O_RDONLY | O_DIRECTORY);
00089     STOPIF_CODE_ERR( *dh <= 0, errno,
00090             "open directory %s for reading", path);
00091 
00092 ex:
00093     return status;
00094 }
00095 
00096 
00103 inline int dir__enum(dir__handle dh, fsvs_dirent *dirp, unsigned int count)
00104 {
00105     return syscall(__NR_getdents64, dh, dirp, count);
00106 }
00107 
00108 
00111 inline int dir__close(dir__handle dh)
00112 {
00113     int status;
00114 
00115     status=0;
00116     STOPIF_CODE_ERR( close(dh) == -1, errno,
00117             "closing dir-handle");
00118 
00119 ex:
00120     return status;
00121 }
00122 
00123 
00126 inline int dir__get_dir_size(dir__handle dh, struct sstat_t *st)
00127 {
00128     int status;
00129 
00130     status=0;
00131     STOPIF( hlp__fstat(dh, st), "Get directory size");
00132 ex:
00133     return status;
00134 }
00135 
00136 #else
00137 
00138 
00139 
00140 
00141 #include <limits.h>
00142 #include <dirent.h>
00143 struct fsvs_dirent_t {
00144     uint64_t    d_ino;
00145     int         d_reclen;
00146     char        d_name[NAME_MAX+1];
00147 };
00148 
00149 
00150 typedef struct fsvs_dirent_t fsvs_dirent;
00151 typedef DIR* dir__handle;
00152 
00153 
00154 inline int dir__start_enum(dir__handle *dh, char *path)
00155 {
00156     int status;
00157 
00158     status=0;
00159     STOPIF_CODE_ERR( (*dh=opendir(path)) == NULL, errno,
00160             "Error opening directory %s", path);
00161 ex:
00162     return status;
00163 }
00164 
00165 
00166 
00167 inline int dir__enum(dir__handle dh, fsvs_dirent *dirp, unsigned int count)
00168 {
00169     struct dirent *de;
00170 
00171     de=readdir(dh);
00172     
00173     if (!de) return 0; 
00174 
00175     dirp[0].d_ino = de->d_ino;
00176     strcpy( dirp[0].d_name, de->d_name);
00177 
00178     dirp[0].d_reclen = sizeof(dirp[0])-sizeof(dirp[0].d_name) +
00179         strlen(dirp[0].d_name) + 1;
00180     return dirp[0].d_reclen;
00181 }
00182 
00183 
00184 inline int dir__close(dir__handle dh)
00185 {
00186     int status;
00187 
00188     status=0;
00189     STOPIF_CODE_ERR( closedir(dh) == -1, errno,
00190             "Error closing directory handle");
00191 ex:
00192     return status;
00193 }
00194 
00195 
00196 inline int dir__get_dir_size(dir__handle dh, struct sstat_t *st)
00197 {
00198     int status;
00199 
00200     status=0;
00201     st->size=0;
00202 #ifdef HAVE_DIRFD
00203     STOPIF( hlp__fstat(dirfd(dh), st), 
00204             "Get directory size()");
00205 #endif
00206 
00207 ex:
00208     return status;
00209 }
00210 
00211 #endif
00212 
00226 #define FREE_SPACE (4096)
00227 
00228 
00235 int dir___f_sort_by_inodePP(struct estat *a, struct estat *b) 
00236 {
00237     register const struct sstat_t* __a=&(a->st);
00238     register const struct sstat_t* __b=&(b->st);
00239 
00240     if (__a->dev > __b->dev) return +2;
00241     if (__a->dev < __b->dev) return -2;
00242     if (__a->ino > __b->ino) return +1;
00243     if (__a->ino < __b->ino) return -1;
00244 
00245     return 0;
00246 }
00247 
00248 
00252 int dir___f_sort_by_inode(struct estat **a, struct estat **b)
00253 {
00254     return dir___f_sort_by_inodePP(*a, *b);
00255 }
00256 
00257 
00262 inline int dir___f_sort_by_nameCC(const void *a, const void *b)
00263 {
00264     return strcoll(a,b);
00265 }
00266 
00267 
00271 int dir___f_sort_by_name(const void *a, const void *b)
00272 {
00273     register const struct estat * const *_a=a;
00274     register const struct estat * const *_b=b;
00275 
00276     return dir___f_sort_by_nameCC((*_a)->name, (*_b)->name);
00277 }
00278 
00279 
00283 int dir___f_sort_by_nameCS(const void *a, const void *b)
00284 {
00285     register const struct estat * const *_b=b;
00286 
00287     return dir___f_sort_by_nameCC(a, (*_b)->name);
00288 }
00289 
00290 
00293 int dir__sortbyname(struct estat *sts)
00294 {
00295     int count, status;
00296 
00297 
00298 
00299     count=sts->entry_count+1;
00300     
00301 
00302 
00303 
00304     STOPIF( hlp__realloc( &sts->by_name, count*sizeof(*sts->by_name)), NULL);
00305 
00306     if (sts->entry_count!=0)
00307     {
00308         memcpy(sts->by_name, sts->by_inode, count*sizeof(*sts->by_name));
00309         qsort(sts->by_name, sts->entry_count, sizeof(*sts->by_name), dir___f_sort_by_name); 
00310     }
00311 
00312     sts->by_name[sts->entry_count]=NULL;
00313     status=0;
00314 
00315 ex:
00316     return status;
00317 }
00318 
00319 
00322 int dir__sortbyinode(struct estat *sts)
00323 {
00324 
00325     if (sts->entry_count)
00326     {
00327         BUG_ON(!sts->by_inode);
00328 
00329         qsort(sts->by_inode, sts->entry_count, sizeof(*sts->by_inode), 
00330                 (comparison_fn_t)dir___f_sort_by_inode); 
00331     }
00332 
00333     return 0;
00334 }
00335 
00336 
00361 int dir__enumerator(struct estat *this,
00362         int est_count,
00363         int give_by_name)
00364 {
00365     dir__handle dirhandle;
00366     int size;
00367     int count;
00368     int i,j,l;
00369     int sts_free;
00370     int status;
00371 
00372     
00373     struct estat *sts=NULL;
00374 
00375     
00376     int alloc_count; 
00377 
00378     
00379     int mark; 
00380     
00381 
00382     void *strings=NULL;
00383     
00384 
00385 
00386 
00387     long *names=NULL;
00388 
00389     
00390     char buffer[FREE_SPACE]; 
00391     
00392     fsvs_dirent *p_de; 
00393 
00394     
00395 
00396     struct estat **sts_array=NULL;
00397     
00398     ino_t *inode_numbers=NULL; 
00399 
00400 
00401     STOPIF( dir__start_enum(&dirhandle, "."), NULL);
00402     if (!this->st.size)
00403         STOPIF( dir__get_dir_size(dirhandle, &(this->st)), NULL);
00404 
00405     
00406 
00407 
00408 
00409 
00410 
00411 
00412 
00413 
00414 
00415 
00416     alloc_count=this->st.size/(sizeof(*p_de) - sizeof(p_de->d_name) + 
00417             ESTIMATED_ENTRY_LENGTH +1);
00418     
00419     est_count= (est_count*19)/16 +1; 
00420     if (alloc_count > est_count) est_count=alloc_count;
00421     
00422 
00423 
00424 
00425 
00426     if (est_count < 32) est_count=32;
00427 
00428     size=FREE_SPACE + est_count*( ESTIMATED_ENTRY_LENGTH + 1 );
00429     STOPIF( hlp__alloc( &strings, size), NULL);
00430 
00431     mark=count=0;
00432     inode_numbers=NULL;
00433     names=NULL;
00434     alloc_count=0;
00435     
00436     while ( (i=dir__enum(dirhandle, (fsvs_dirent*)buffer, sizeof(buffer))) >0)
00437     {
00438         
00439         j=0;
00440         while (j<i)
00441         {
00442             
00443             if (count >= alloc_count)
00444             {
00445                 
00446 
00447                 if (!alloc_count) 
00448                     alloc_count=est_count;
00449                 else
00450                     alloc_count=alloc_count*19/16;
00451 
00452                 STOPIF( hlp__realloc( &names, alloc_count*sizeof(*names)), NULL);
00453 
00454                 
00455 
00456                 STOPIF( hlp__realloc( &inode_numbers, 
00457                             alloc_count*sizeof(*inode_numbers)), NULL);
00458             }
00459 
00460             p_de=(fsvs_dirent*)(buffer+j);
00461 
00462             DEBUGP("found %llu %s", (t_ull)p_de->d_ino, p_de->d_name);
00463 
00464             if (p_de->d_name[0] == '.' &&
00465                     ((p_de->d_name[1] == '\0') ||
00466                      (p_de->d_name[1] == '.' &&
00467                       p_de->d_name[2] == '\0')) )
00468             {
00469                 
00470             }
00471             else
00472             {
00473                 
00474                 inode_numbers[count] = p_de->d_ino;
00475 
00476                 
00477 
00478 
00479                 names[count] = mark;
00480 
00481                 
00482                 l=strlen(p_de->d_name);
00483                 strcpy(strings+mark, p_de->d_name);
00484                 mark += l+1;
00485 
00486                 count++;
00487             }
00488 
00489             
00490             j += p_de->d_reclen;
00491         }
00492 
00493         
00494 
00495 
00496 
00497 
00498         if (size-mark < FREE_SPACE)
00499         {
00500             
00501 
00502 
00503 
00504 
00505              
00506             size=(size*21)/16;
00507             
00508 
00509             if (size < mark+FREE_SPACE) size=mark+FREE_SPACE;
00510 
00511             STOPIF( hlp__realloc( &strings, size), NULL);
00512             DEBUGP("strings realloc(%p, %d)", strings, size);
00513         }
00514     }
00515 
00516     STOPIF_CODE_ERR(i<0, errno, "getdents64");
00517 
00518     DEBUGP("after loop found %d entries, %d bytes string-space", count, mark);
00519     this->entry_count=count;
00520 
00521     
00522     STOPIF( hlp__realloc( &strings, mark), NULL);
00523     
00524 
00525     BUG_ON(mark && !strings);
00526     this->strings=strings;
00527     
00528     strings=NULL;
00529 
00530     
00531     STOPIF( hlp__realloc( &inode_numbers, 
00532                 (count+1)*sizeof(*inode_numbers)), NULL);
00533     STOPIF( hlp__realloc( &names, (count+1)*sizeof(*names)), NULL);
00534 
00535     
00536     inode_numbers[count]=0;
00537     names[count]=0;
00538 
00539 
00540     
00541 
00542 
00543 
00544 
00545     
00546 
00547     sts_array=(struct estat**)names;
00548     sts_free=0;
00549     for(i=0; i<count; i++)
00550     {
00551         if (sts_free == 0)
00552             STOPIF( ops__allocate(count-i, &sts, &sts_free), NULL);
00553 
00554         
00555 
00556         sts->name=this->strings + names[i];
00557         sts->st.ino=inode_numbers[i];
00558 
00559         
00560         sts_array[i] = sts;
00561 
00562         sts++;
00563         sts_free--;
00564     }
00565     
00566     names=NULL;
00567 
00568     this->by_inode=sts_array;
00569     
00570     sts_array=NULL;
00571 
00572     
00573     STOPIF( dir__sortbyinode(this), NULL);
00574 
00575 
00576     
00577     for(i=0; i<count; i++)
00578     {
00579         sts=this->by_inode[i];
00580         sts->parent=this;
00581         sts->repos_rev=SVN_INVALID_REVNUM;
00582         status=hlp__lstat(sts->name, &(sts->st));
00583         if (abs(status) == ENOENT)
00584         {
00585             DEBUGP("entry \"%s\" not interesting - maybe a fifo or socket?", 
00586                     sts->name);
00587             sts->to_be_ignored=1;
00588         }
00589         else
00590             STOPIF( status, "lstat(%s)", sts->name);
00591 
00592         
00593         sts->old_rev_mode_packed = sts->local_mode_packed= 
00594             MODE_T_to_PACKED(sts->st.mode);
00595     }
00596 
00597 
00598     
00599     if (give_by_name)
00600         STOPIF(dir__sortbyname(this), NULL);
00601     else
00602         
00603         this->by_name=NULL;
00604 
00605     status=0;
00606 
00607 ex:
00608     IF_FREE(strings);
00609     IF_FREE(names);
00610     IF_FREE(inode_numbers);
00611     IF_FREE(sts_array);
00612 
00613     if (dirhandle>=0) dir__close(dirhandle);
00614     return status;
00615 }
00616 
00617