root/src/filemanager/dir.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. key_collate
  2. clean_sort_keys
  3. handle_dirent
  4. dir_get_dotdot_stat
  5. alloc_dir_copy
  6. dir_list_grow
  7. dir_list_append
  8. unsorted
  9. sort_name
  10. sort_vers
  11. sort_ext
  12. sort_time
  13. sort_ctime
  14. sort_atime
  15. sort_inode
  16. sort_size
  17. dir_list_sort
  18. dir_list_clean
  19. dir_list_free_list
  20. dir_list_init
  21. handle_path
  22. dir_list_load
  23. if_link_is_exe
  24. dir_list_reload

   1 /*
   2    Directory routines
   3 
   4    Copyright (C) 1994-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2013
   9    Andrew Borodin <aborodin@vmail.ru>, 2013
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 /** \file src/filemanager/dir.c
  28  *  \brief Source: directory routines
  29  */
  30 
  31 #include <config.h>
  32 
  33 #include <stdio.h>
  34 #include <stdlib.h>
  35 #include <string.h>
  36 #include <sys/stat.h>
  37 
  38 #include "lib/global.h"
  39 #include "lib/tty/tty.h"
  40 #include "lib/search.h"
  41 #include "lib/vfs/vfs.h"
  42 #include "lib/fs.h"
  43 #include "lib/strutil.h"
  44 #include "lib/util.h"
  45 
  46 #include "src/setup.h"          /* panels_options */
  47 
  48 #include "treestore.h"
  49 #include "file.h"               /* file_is_symlink_to_dir() */
  50 #include "dir.h"
  51 
  52 /*** global variables ****************************************************************************/
  53 
  54 /*** file scope macro definitions ****************************************************************/
  55 
  56 #define MY_ISDIR(x) (\
  57     (is_exe (x->st.st_mode) && !(S_ISDIR (x->st.st_mode) || link_isdir (x)) && exec_first) \
  58         ? 1 \
  59         : ( (S_ISDIR (x->st.st_mode) || link_isdir (x)) ? 2 : 0) )
  60 
  61 /*** file scope type declarations ****************************************************************/
  62 
  63 /*** file scope variables ************************************************************************/
  64 
  65 /* Reverse flag */
  66 static int reverse = 1;
  67 
  68 /* Are the files sorted case sensitively? */
  69 static gboolean case_sensitive = OS_SORT_CASE_SENSITIVE_DEFAULT;
  70 
  71 /* Are the exec_bit files top in list */
  72 static gboolean exec_first = TRUE;
  73 
  74 static dir_list dir_copy = { NULL, 0, 0, NULL };
  75 
  76 /*** file scope functions ************************************************************************/
  77 /* --------------------------------------------------------------------------------------------- */
  78 
  79 /*
  80    sort_orders_t sort_orders [SORT_TYPES_TOTAL] = {
  81    { N_("&Unsorted"),    unsorted },
  82    { N_("&Name"),        sort_name },
  83    { N_("&Extension"),   sort_ext },
  84    { N_("&Modify time"), sort_time },
  85    { N_("&Access time"), sort_atime },
  86    { N_("C&Hange time"), sort_ctime },
  87    { N_("&Size"),        sort_size },
  88    { N_("&Inode"),       sort_inode },
  89    };
  90  */
  91 
  92 static inline int
  93 key_collate (const char *t1, const char *t2)
     /* [previous][next][first][last][top][bottom][index][help]  */
  94 {
  95     int dotdot = 0;
  96     int ret;
  97 
  98     dotdot = (t1[0] == '.' ? 1 : 0) | ((t2[0] == '.' ? 1 : 0) << 1);
  99 
 100     switch (dotdot)
 101     {
 102     case 0:
 103     case 3:
 104         ret = str_key_collate (t1, t2, case_sensitive) * reverse;
 105         break;
 106     case 1:
 107         ret = -1;               /* t1 < t2 */
 108         break;
 109     case 2:
 110         ret = 1;                /* t1 > t2 */
 111         break;
 112     default:
 113         ret = 0;                /* it must not happen */
 114     }
 115 
 116     return ret;
 117 }
 118 
 119 /* --------------------------------------------------------------------------------------------- */
 120 /**
 121  * clear keys, should be call after sorting is finished.
 122  */
 123 
 124 static void
 125 clean_sort_keys (dir_list * list, int start, int count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 126 {
 127     int i;
 128 
 129     for (i = 0; i < count; i++)
 130     {
 131         file_entry_t *fentry;
 132 
 133         fentry = &list->list[i + start];
 134         str_release_key (fentry->sort_key, case_sensitive);
 135         fentry->sort_key = NULL;
 136         str_release_key (fentry->second_sort_key, case_sensitive);
 137         fentry->second_sort_key = NULL;
 138     }
 139 }
 140 
 141 /* --------------------------------------------------------------------------------------------- */
 142 /**
 143  * If you change handle_dirent then check also handle_path.
 144  * @return FALSE = don't add, TRUE = add to the list
 145  */
 146 
 147 static gboolean
 148 handle_dirent (struct dirent *dp, const char *fltr, struct stat *buf1, gboolean * link_to_dir,
     /* [previous][next][first][last][top][bottom][index][help]  */
 149                gboolean * stale_link)
 150 {
 151     vfs_path_t *vpath;
 152 
 153     if (DIR_IS_DOT (dp->d_name) || DIR_IS_DOTDOT (dp->d_name))
 154         return FALSE;
 155     if (!panels_options.show_dot_files && (dp->d_name[0] == '.'))
 156         return FALSE;
 157     if (!panels_options.show_backups && dp->d_name[strlen (dp->d_name) - 1] == '~')
 158         return FALSE;
 159 
 160     vpath = vfs_path_from_str (dp->d_name);
 161     if (mc_lstat (vpath, buf1) == -1)
 162     {
 163         /*
 164          * lstat() fails - such entries should be identified by
 165          * buf1->st_mode being 0.
 166          * It happens on QNX Neutrino for /fs/cd0 if no CD is inserted.
 167          */
 168         memset (buf1, 0, sizeof (*buf1));
 169     }
 170 
 171     if (S_ISDIR (buf1->st_mode))
 172         tree_store_mark_checked (dp->d_name);
 173 
 174     /* A link to a file or a directory? */
 175     *link_to_dir = file_is_symlink_to_dir (vpath, buf1, stale_link);
 176 
 177     vfs_path_free (vpath);
 178 
 179     return (S_ISDIR (buf1->st_mode) || *link_to_dir || fltr == NULL
 180             || mc_search (fltr, NULL, dp->d_name, MC_SEARCH_T_GLOB));
 181 }
 182 
 183 /* --------------------------------------------------------------------------------------------- */
 184 /** get info about ".." */
 185 
 186 static gboolean
 187 dir_get_dotdot_stat (const vfs_path_t * vpath, struct stat *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 188 {
 189     gboolean ret = FALSE;
 190 
 191     if ((vpath != NULL) && (st != NULL))
 192     {
 193         const char *path;
 194 
 195         path = vfs_path_get_by_index (vpath, 0)->path;
 196         if (path != NULL && *path != '\0')
 197         {
 198             vfs_path_t *tmp_vpath;
 199 
 200             tmp_vpath = vfs_path_append_new (vpath, "..", (char *) NULL);
 201             ret = mc_stat (tmp_vpath, st) == 0;
 202             vfs_path_free (tmp_vpath);
 203         }
 204     }
 205 
 206     return ret;
 207 }
 208 
 209 /* --------------------------------------------------------------------------------------------- */
 210 
 211 static void
 212 alloc_dir_copy (int size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 213 {
 214     if (dir_copy.size < size)
 215     {
 216         if (dir_copy.list != NULL)
 217             dir_list_free_list (&dir_copy);
 218 
 219         dir_copy.list = g_new0 (file_entry_t, size);
 220         dir_copy.size = size;
 221         dir_copy.len = 0;
 222     }
 223 }
 224 
 225 /* --------------------------------------------------------------------------------------------- */
 226 /*** public functions ****************************************************************************/
 227 /* --------------------------------------------------------------------------------------------- */
 228 /**
 229  * Increase or decrease directory list size.
 230  *
 231  * @param list directory list
 232  * @param delta value by increase (if positive) or decrease (if negative) list size
 233  *
 234  * @return FALSE on failure, TRUE on success
 235  */
 236 
 237 gboolean
 238 dir_list_grow (dir_list * list, int delta)
     /* [previous][next][first][last][top][bottom][index][help]  */
 239 {
 240     int size;
 241     gboolean clear_flag = FALSE;
 242 
 243     if (list == NULL)
 244         return FALSE;
 245 
 246     if (delta == 0)
 247         return TRUE;
 248 
 249     size = list->size + delta;
 250     if (size <= 0)
 251     {
 252         size = DIR_LIST_MIN_SIZE;
 253         clear_flag = TRUE;
 254     }
 255 
 256     if (size != list->size)
 257     {
 258         file_entry_t *fe;
 259 
 260         fe = g_try_renew (file_entry_t, list->list, size);
 261         if (fe == NULL)
 262             return FALSE;
 263 
 264         list->list = fe;
 265         list->size = size;
 266     }
 267 
 268     list->len = clear_flag ? 0 : MIN (list->len, size);
 269 
 270     return TRUE;
 271 }
 272 
 273 /* --------------------------------------------------------------------------------------------- */
 274 /**
 275  * Append file info to the directory list.
 276  *
 277  * @param list directory list
 278  * @param fname file name
 279  * @param st file stat info
 280  * @param link_to_dir is file link to directory
 281  * @param stale_link is file stale elink
 282  *
 283  * @return FALSE on failure, TRUE on success
 284  */
 285 
 286 gboolean
 287 dir_list_append (dir_list * list, const char *fname, const struct stat * st,
     /* [previous][next][first][last][top][bottom][index][help]  */
 288                  gboolean link_to_dir, gboolean stale_link)
 289 {
 290     file_entry_t *fentry;
 291 
 292     /* Need to grow the *list? */
 293     if (list->len == list->size && !dir_list_grow (list, DIR_LIST_RESIZE_STEP))
 294         return FALSE;
 295 
 296     fentry = &list->list[list->len];
 297     fentry->fnamelen = strlen (fname);
 298     fentry->fname = g_strndup (fname, fentry->fnamelen);
 299     fentry->f.marked = 0;
 300     fentry->f.link_to_dir = link_to_dir ? 1 : 0;
 301     fentry->f.stale_link = stale_link ? 1 : 0;
 302     fentry->f.dir_size_computed = 0;
 303     fentry->st = *st;
 304     fentry->sort_key = NULL;
 305     fentry->second_sort_key = NULL;
 306 
 307     list->len++;
 308 
 309     return TRUE;
 310 }
 311 
 312 /* --------------------------------------------------------------------------------------------- */
 313 
 314 int
 315 unsorted (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 316 {
 317     (void) a;
 318     (void) b;
 319 
 320     return 0;
 321 }
 322 
 323 /* --------------------------------------------------------------------------------------------- */
 324 
 325 int
 326 sort_name (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 327 {
 328     int ad = MY_ISDIR (a);
 329     int bd = MY_ISDIR (b);
 330 
 331     if (ad == bd || panels_options.mix_all_files)
 332     {
 333         /* create key if does not exist, key will be freed after sorting */
 334         if (a->sort_key == NULL)
 335             a->sort_key = str_create_key_for_filename (a->fname, case_sensitive);
 336         if (b->sort_key == NULL)
 337             b->sort_key = str_create_key_for_filename (b->fname, case_sensitive);
 338 
 339         return key_collate (a->sort_key, b->sort_key);
 340     }
 341 
 342     return bd - ad;
 343 }
 344 
 345 /* --------------------------------------------------------------------------------------------- */
 346 
 347 int
 348 sort_vers (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 349 {
 350     int ad = MY_ISDIR (a);
 351     int bd = MY_ISDIR (b);
 352 
 353     if (ad == bd || panels_options.mix_all_files)
 354         return filevercmp (a->fname, b->fname) * reverse;
 355 
 356     return bd - ad;
 357 }
 358 
 359 /* --------------------------------------------------------------------------------------------- */
 360 
 361 int
 362 sort_ext (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 363 {
 364     int ad = MY_ISDIR (a);
 365     int bd = MY_ISDIR (b);
 366 
 367     if (ad == bd || panels_options.mix_all_files)
 368     {
 369         int r;
 370 
 371         if (a->second_sort_key == NULL)
 372             a->second_sort_key = str_create_key (extension (a->fname), case_sensitive);
 373         if (b->second_sort_key == NULL)
 374             b->second_sort_key = str_create_key (extension (b->fname), case_sensitive);
 375 
 376         r = str_key_collate (a->second_sort_key, b->second_sort_key, case_sensitive);
 377         if (r != 0)
 378             return r * reverse;
 379 
 380         return sort_name (a, b);
 381     }
 382 
 383     return bd - ad;
 384 }
 385 
 386 /* --------------------------------------------------------------------------------------------- */
 387 
 388 int
 389 sort_time (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 390 {
 391     int ad = MY_ISDIR (a);
 392     int bd = MY_ISDIR (b);
 393 
 394     if (ad == bd || panels_options.mix_all_files)
 395     {
 396         int result = a->st.st_mtime < b->st.st_mtime ? -1 : a->st.st_mtime > b->st.st_mtime;
 397 
 398         if (result != 0)
 399             return result * reverse;
 400 
 401         return sort_name (a, b);
 402     }
 403 
 404     return bd - ad;
 405 }
 406 
 407 /* --------------------------------------------------------------------------------------------- */
 408 
 409 int
 410 sort_ctime (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 411 {
 412     int ad = MY_ISDIR (a);
 413     int bd = MY_ISDIR (b);
 414 
 415     if (ad == bd || panels_options.mix_all_files)
 416     {
 417         int result = a->st.st_ctime < b->st.st_ctime ? -1 : a->st.st_ctime > b->st.st_ctime;
 418 
 419         if (result != 0)
 420             return result * reverse;
 421 
 422         return sort_name (a, b);
 423     }
 424 
 425     return bd - ad;
 426 }
 427 
 428 /* --------------------------------------------------------------------------------------------- */
 429 
 430 int
 431 sort_atime (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 432 {
 433     int ad = MY_ISDIR (a);
 434     int bd = MY_ISDIR (b);
 435 
 436     if (ad == bd || panels_options.mix_all_files)
 437     {
 438         int result = a->st.st_atime < b->st.st_atime ? -1 : a->st.st_atime > b->st.st_atime;
 439 
 440         if (result != 0)
 441             return result * reverse;
 442 
 443         return sort_name (a, b);
 444     }
 445 
 446     return bd - ad;
 447 }
 448 
 449 /* --------------------------------------------------------------------------------------------- */
 450 
 451 int
 452 sort_inode (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 453 {
 454     int ad = MY_ISDIR (a);
 455     int bd = MY_ISDIR (b);
 456 
 457     if (ad == bd || panels_options.mix_all_files)
 458         return (a->st.st_ino - b->st.st_ino) * reverse;
 459 
 460     return bd - ad;
 461 }
 462 
 463 /* --------------------------------------------------------------------------------------------- */
 464 
 465 int
 466 sort_size (file_entry_t * a, file_entry_t * b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 467 {
 468     int ad = MY_ISDIR (a);
 469     int bd = MY_ISDIR (b);
 470 
 471     if (ad == bd || panels_options.mix_all_files)
 472     {
 473         int result = a->st.st_size < b->st.st_size ? -1 : a->st.st_size > b->st.st_size;
 474 
 475         if (result != 0)
 476             return result * reverse;
 477 
 478         return sort_name (a, b);
 479     }
 480 
 481     return bd - ad;
 482 }
 483 
 484 /* --------------------------------------------------------------------------------------------- */
 485 
 486 void
 487 dir_list_sort (dir_list * list, GCompareFunc sort, const dir_sort_options_t * sort_op)
     /* [previous][next][first][last][top][bottom][index][help]  */
 488 {
 489     if (list->len > 1 && sort != (GCompareFunc) unsorted)
 490     {
 491         file_entry_t *fentry = &list->list[0];
 492         int dot_dot_found;
 493 
 494         /* If there is an ".." entry the caller must take care to
 495            ensure that it occupies the first list element. */
 496         dot_dot_found = DIR_IS_DOTDOT (fentry->fname) ? 1 : 0;
 497         reverse = sort_op->reverse ? -1 : 1;
 498         case_sensitive = sort_op->case_sensitive ? 1 : 0;
 499         exec_first = sort_op->exec_first;
 500         qsort (&(list->list)[dot_dot_found], list->len - dot_dot_found, sizeof (file_entry_t),
 501                sort);
 502 
 503         clean_sort_keys (list, dot_dot_found, list->len - dot_dot_found);
 504     }
 505 }
 506 
 507 /* --------------------------------------------------------------------------------------------- */
 508 
 509 void
 510 dir_list_clean (dir_list * list)
     /* [previous][next][first][last][top][bottom][index][help]  */
 511 {
 512     int i;
 513 
 514     for (i = 0; i < list->len; i++)
 515     {
 516         file_entry_t *fentry;
 517 
 518         fentry = &list->list[i];
 519         MC_PTR_FREE (fentry->fname);
 520     }
 521 
 522     list->len = 0;
 523     /* reduce memory usage */
 524     dir_list_grow (list, DIR_LIST_MIN_SIZE - list->size);
 525 }
 526 
 527 /* --------------------------------------------------------------------------------------------- */
 528 
 529 void
 530 dir_list_free_list (dir_list * list)
     /* [previous][next][first][last][top][bottom][index][help]  */
 531 {
 532     int i;
 533 
 534     for (i = 0; i < list->len; i++)
 535     {
 536         file_entry_t *fentry;
 537 
 538         fentry = &list->list[i];
 539         g_free (fentry->fname);
 540     }
 541 
 542     MC_PTR_FREE (list->list);
 543     list->len = 0;
 544     list->size = 0;
 545 }
 546 
 547 /* --------------------------------------------------------------------------------------------- */
 548 /** Used to set up a directory list when there is no access to a directory */
 549 
 550 gboolean
 551 dir_list_init (dir_list * list)
     /* [previous][next][first][last][top][bottom][index][help]  */
 552 {
 553     file_entry_t *fentry;
 554 
 555     /* Need to grow the *list? */
 556     if (list->size == 0 && !dir_list_grow (list, DIR_LIST_RESIZE_STEP))
 557     {
 558         list->len = 0;
 559         return FALSE;
 560     }
 561 
 562     fentry = &list->list[0];
 563     memset (fentry, 0, sizeof (*fentry));
 564     fentry->fnamelen = 2;
 565     fentry->fname = g_strndup ("..", fentry->fnamelen);
 566     fentry->f.link_to_dir = 0;
 567     fentry->f.stale_link = 0;
 568     fentry->f.dir_size_computed = 0;
 569     fentry->f.marked = 0;
 570     fentry->st.st_mode = 040755;
 571     list->len = 1;
 572     return TRUE;
 573 }
 574 
 575 /* --------------------------------------------------------------------------------------------- */
 576 /**
 577    handle_path is a simplified handle_dirent. The difference is that
 578    handle_path doesn't pay attention to panels_options.show_dot_files
 579    and panels_options.show_backups.
 580    Moreover handle_path can't be used with a filemask.
 581    If you change handle_path then check also handle_dirent. */
 582 /* Return values: FALSE = don't add, TRUE = add to the list */
 583 
 584 gboolean
 585 handle_path (const char *path, struct stat * buf1, gboolean * link_to_dir, gboolean * stale_link)
     /* [previous][next][first][last][top][bottom][index][help]  */
 586 {
 587     vfs_path_t *vpath;
 588 
 589     if (DIR_IS_DOT (path) || DIR_IS_DOTDOT (path))
 590         return FALSE;
 591 
 592     vpath = vfs_path_from_str (path);
 593     if (mc_lstat (vpath, buf1) == -1)
 594     {
 595         vfs_path_free (vpath);
 596         return FALSE;
 597     }
 598 
 599     if (S_ISDIR (buf1->st_mode))
 600         tree_store_mark_checked (path);
 601 
 602     /* A link to a file or a directory? */
 603     *link_to_dir = FALSE;
 604     *stale_link = FALSE;
 605     if (S_ISLNK (buf1->st_mode))
 606     {
 607         struct stat buf2;
 608 
 609         if (mc_stat (vpath, &buf2) == 0)
 610             *link_to_dir = S_ISDIR (buf2.st_mode) != 0;
 611         else
 612             *stale_link = TRUE;
 613     }
 614 
 615     vfs_path_free (vpath);
 616 
 617     return TRUE;
 618 }
 619 
 620 /* --------------------------------------------------------------------------------------------- */
 621 
 622 gboolean
 623 dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
     /* [previous][next][first][last][top][bottom][index][help]  */
 624                const dir_sort_options_t * sort_op, const char *fltr)
 625 {
 626     DIR *dirp;
 627     struct dirent *dp;
 628     struct stat st;
 629     file_entry_t *fentry;
 630     const char *vpath_str;
 631     gboolean ret = TRUE;
 632 
 633     /* ".." (if any) must be the first entry in the list */
 634     if (!dir_list_init (list))
 635         return FALSE;
 636 
 637     fentry = &list->list[0];
 638     if (dir_get_dotdot_stat (vpath, &st))
 639         fentry->st = st;
 640 
 641     if (list->callback != NULL)
 642         list->callback (DIR_OPEN, (void *) vpath);
 643     dirp = mc_opendir (vpath);
 644     if (dirp == NULL)
 645         return FALSE;
 646 
 647     tree_store_start_check (vpath);
 648 
 649     vpath_str = vfs_path_as_str (vpath);
 650     /* Do not add a ".." entry to the root directory */
 651     if (IS_PATH_SEP (vpath_str[0]) && vpath_str[1] == '\0')
 652         dir_list_clean (list);
 653 
 654     while (ret && (dp = mc_readdir (dirp)) != NULL)
 655     {
 656         gboolean link_to_dir, stale_link;
 657 
 658         if (list->callback != NULL)
 659             list->callback (DIR_READ, dp);
 660 
 661         if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link))
 662             continue;
 663 
 664         if (!dir_list_append (list, dp->d_name, &st, link_to_dir, stale_link))
 665             ret = FALSE;
 666     }
 667 
 668     if (ret)
 669         dir_list_sort (list, sort, sort_op);
 670 
 671     if (list->callback != NULL)
 672         list->callback (DIR_CLOSE, NULL);
 673     mc_closedir (dirp);
 674     tree_store_end_check ();
 675 
 676     return ret;
 677 }
 678 
 679 /* --------------------------------------------------------------------------------------------- */
 680 
 681 gboolean
 682 if_link_is_exe (const vfs_path_t * full_name_vpath, const file_entry_t * file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 683 {
 684     struct stat b;
 685 
 686     if (S_ISLNK (file->st.st_mode) && mc_stat (full_name_vpath, &b) == 0)
 687         return is_exe (b.st_mode);
 688 
 689     return TRUE;
 690 }
 691 
 692 /* --------------------------------------------------------------------------------------------- */
 693 /** If fltr is null, then it is a match */
 694 
 695 gboolean
 696 dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
     /* [previous][next][first][last][top][bottom][index][help]  */
 697                  const dir_sort_options_t * sort_op, const char *fltr)
 698 {
 699     DIR *dirp;
 700     struct dirent *dp;
 701     int i;
 702     struct stat st;
 703     int marked_cnt;
 704     GHashTable *marked_files;
 705     const char *tmp_path;
 706     gboolean ret = TRUE;
 707 
 708     if (list->callback != NULL)
 709         list->callback (DIR_OPEN, (void *) vpath);
 710     dirp = mc_opendir (vpath);
 711     if (dirp == NULL)
 712     {
 713         dir_list_clean (list);
 714         dir_list_init (list);
 715         return FALSE;
 716     }
 717 
 718     tree_store_start_check (vpath);
 719 
 720     marked_files = g_hash_table_new (g_str_hash, g_str_equal);
 721     alloc_dir_copy (list->len);
 722     for (marked_cnt = i = 0; i < list->len; i++)
 723     {
 724         file_entry_t *fentry, *dfentry;
 725 
 726         fentry = &list->list[i];
 727         dfentry = &dir_copy.list[i];
 728 
 729         dfentry->fnamelen = fentry->fnamelen;
 730         dfentry->fname = g_strndup (fentry->fname, fentry->fnamelen);
 731         dfentry->f.marked = fentry->f.marked;
 732         dfentry->f.dir_size_computed = fentry->f.dir_size_computed;
 733         dfentry->f.link_to_dir = fentry->f.link_to_dir;
 734         dfentry->f.stale_link = fentry->f.stale_link;
 735         dfentry->sort_key = NULL;
 736         dfentry->second_sort_key = NULL;
 737         if (fentry->f.marked)
 738         {
 739             g_hash_table_insert (marked_files, dfentry->fname, dfentry);
 740             marked_cnt++;
 741         }
 742     }
 743 
 744     /* save len for later dir_list_clean() */
 745     dir_copy.len = list->len;
 746 
 747     /* Add ".." except to the root directory. The ".." entry
 748        (if any) must be the first in the list. */
 749     tmp_path = vfs_path_get_by_index (vpath, 0)->path;
 750     if (vfs_path_elements_count (vpath) == 1 && IS_PATH_SEP (tmp_path[0]) && tmp_path[1] == '\0')
 751     {
 752         /* root directory */
 753         dir_list_clean (list);
 754     }
 755     else
 756     {
 757         dir_list_clean (list);
 758         if (!dir_list_init (list))
 759         {
 760             dir_list_free_list (&dir_copy);
 761             return FALSE;
 762         }
 763 
 764         if (dir_get_dotdot_stat (vpath, &st))
 765         {
 766             file_entry_t *fentry;
 767 
 768             fentry = &list->list[0];
 769             fentry->st = st;
 770         }
 771     }
 772 
 773     while (ret && (dp = mc_readdir (dirp)) != NULL)
 774     {
 775         gboolean link_to_dir, stale_link;
 776 
 777         if (list->callback != NULL)
 778             list->callback (DIR_READ, dp);
 779 
 780         if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link))
 781             continue;
 782 
 783         if (!dir_list_append (list, dp->d_name, &st, link_to_dir, stale_link))
 784             ret = FALSE;
 785         else
 786         {
 787             file_entry_t *fentry;
 788 
 789             fentry = &list->list[list->len - 1];
 790 
 791             /*
 792              * If we have marked files in the copy, scan through the copy
 793              * to find matching file.  Decrease number of remaining marks if
 794              * we copied one.
 795              */
 796             fentry->f.marked = (marked_cnt > 0
 797                                 && g_hash_table_lookup (marked_files, dp->d_name) != NULL);
 798             if (fentry->f.marked)
 799                 marked_cnt--;
 800         }
 801     }
 802 
 803     if (ret)
 804         dir_list_sort (list, sort, sort_op);
 805 
 806     if (list->callback != NULL)
 807         list->callback (DIR_CLOSE, NULL);
 808     mc_closedir (dirp);
 809     tree_store_end_check ();
 810 
 811     g_hash_table_destroy (marked_files);
 812     dir_list_free_list (&dir_copy);
 813 
 814     return ret;
 815 }
 816 
 817 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */