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