Manual pages: mcmcdiffmceditmcview

root/lib/vfs/parse_ls_vga.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_num
  2. is_dos_date
  3. is_week
  4. is_localized_month
  5. is_time
  6. is_year
  7. vfs_parse_filetype
  8. vfs_parse_fileperms
  9. vfs_parse_filemode
  10. vfs_parse_raw_filemode
  11. vfs_parse_month
  12. vfs_parse_filedate
  13. vfs_split_text
  14. vfs_parse_ls_lga_init
  15. vfs_parse_ls_lga_get_final_spaces
  16. vfs_parse_ls_lga

   1 /*
   2    Routines for parsing output from the 'ls' command.
   3 
   4    Copyright (C) 1988-2025
   5    Free Software Foundation, Inc.
   6 
   7    Copyright (C) 1995, 1996 Miguel de Icaza
   8 
   9    Written by:
  10    Miguel de Icaza, 1995, 1996
  11    Slava Zanko <slavazanko@gmail.com>, 2011
  12 
  13    This file is part of the Midnight Commander.
  14 
  15    The Midnight Commander is free software: you can redistribute it
  16    and/or modify it under the terms of the GNU General Public License as
  17    published by the Free Software Foundation, either version 3 of the License,
  18    or (at your option) any later version.
  19 
  20    The Midnight Commander is distributed in the hope that it will be useful,
  21    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23    GNU General Public License for more details.
  24 
  25    You should have received a copy of the GNU General Public License
  26    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  27  */
  28 
  29 /**
  30  * \file
  31  * \brief Source: Utilities for VFS modules
  32  * \author Miguel de Icaza
  33  * \date 1995, 1996
  34  */
  35 
  36 #include <config.h>
  37 
  38 #include <ctype.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 
  42 #include "lib/global.h"
  43 #include "lib/strutil.h"
  44 #include "lib/unixcompat.h"  // makedev
  45 #include "lib/widget.h"      // message()
  46 
  47 #include "utilvfs.h"
  48 
  49 /*** global variables ****************************************************************************/
  50 
  51 /*** file scope macro definitions ****************************************************************/
  52 
  53 /* Parsing code is used by ftpfs, shell and extfs */
  54 #define MAXCOLS 30
  55 
  56 /*** file scope type declarations ****************************************************************/
  57 
  58 /*** forward declarations (file scope functions) *************************************************/
  59 
  60 /*** file scope variables ************************************************************************/
  61 
  62 static char *columns[MAXCOLS];   // Points to the string in column n
  63 static int column_ptr[MAXCOLS];  // Index from 0 to the starting positions of the columns
  64 static size_t vfs_parse_ls_final_num_spaces = 0;
  65 
  66 /* --------------------------------------------------------------------------------------------- */
  67 /*** file scope functions ************************************************************************/
  68 /* --------------------------------------------------------------------------------------------- */
  69 
  70 static gboolean
  71 is_num (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
  72 {
  73     char *column = columns[idx];
  74 
  75     return (column != NULL && isdigit (column[0]));
  76 }
  77 
  78 /* --------------------------------------------------------------------------------------------- */
  79 /* Return TRUE for MM-DD-YY and MM-DD-YYYY */
  80 
  81 static gboolean
  82 is_dos_date (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
  83 {
  84     size_t len;
  85 
  86     if (str == NULL)
  87         return FALSE;
  88 
  89     len = strlen (str);
  90     if (len != 8 && len != 10)
  91         return FALSE;
  92 
  93     if (str[2] != str[5])
  94         return FALSE;
  95 
  96     return (strchr ("\\-/", (int) str[2]) != NULL);
  97 }
  98 
  99 /* --------------------------------------------------------------------------------------------- */
 100 
 101 static gboolean
 102 is_week (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 103 {
 104     static const char *week = "SunMonTueWedThuFriSat";
 105     const char *pos;
 106 
 107     if (str == NULL)
 108         return FALSE;
 109 
 110     pos = strstr (week, str);
 111     if (pos == NULL)
 112         return FALSE;
 113 
 114     if (tim != NULL)
 115         tim->tm_wday = (pos - week) / 3;
 116 
 117     return TRUE;
 118 }
 119 
 120 /* --------------------------------------------------------------------------------------------- */
 121 /**
 122  * Check for possible locale's abbreviated month name (Jan..Dec).
 123  * Any 3 bytes long string without digit, control and punctuation characters.
 124  * isalpha() is locale specific, so it cannot be used if current
 125  * locale is "C" and ftp server use Cyrillic.
 126  * NB: It is assumed there are no whitespaces in month.
 127  */
 128 static gboolean
 129 is_localized_month (const char *month)
     /* [previous][next][first][last][top][bottom][index][help]  */
 130 {
 131     int i;
 132 
 133     if (month == NULL)
 134         return FALSE;
 135 
 136     for (i = 0; i < 3 && *month != '\0' && !isdigit ((unsigned char) *month)
 137          && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month);
 138          i++, month++)
 139         ;
 140 
 141     return (i == 3 && *month == '\0');
 142 }
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 
 146 static gboolean
 147 is_time (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 148 {
 149     const char *p, *p2;
 150 
 151     if (str == NULL)
 152         return FALSE;
 153 
 154     p = strchr (str, ':');
 155     if (p == NULL)
 156         return FALSE;
 157 
 158     p2 = strrchr (str, ':');
 159     if (p2 == NULL)
 160         return FALSE;
 161 
 162     if (p != p2)
 163     {
 164         if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
 165             return FALSE;
 166     }
 167     else
 168     {
 169         if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
 170             return FALSE;
 171     }
 172 
 173     return TRUE;
 174 }
 175 
 176 /* --------------------------------------------------------------------------------------------- */
 177 
 178 static gboolean
 179 is_year (char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     long year;
 182 
 183     if (str == NULL)
 184         return FALSE;
 185 
 186     if (strchr (str, ':') != NULL)
 187         return FALSE;
 188 
 189     if (strlen (str) != 4)
 190         return FALSE;
 191 
 192     if (sscanf (str, "%ld", &year) != 1)
 193         return FALSE;
 194 
 195     if (year < 1900 || year > 3000)
 196         return FALSE;
 197 
 198     tim->tm_year = (int) (year - 1900);
 199 
 200     return TRUE;
 201 }
 202 
 203 /* --------------------------------------------------------------------------------------------- */
 204 /*** public functions ****************************************************************************/
 205 /* --------------------------------------------------------------------------------------------- */
 206 
 207 gboolean
 208 vfs_parse_filetype (const char *s, size_t *ret_skipped, mode_t *ret_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 209 {
 210     mode_t type;
 211 
 212     switch (*s)
 213     {
 214     case 'd':
 215         type = S_IFDIR;
 216         break;
 217     case 'b':
 218         type = S_IFBLK;
 219         break;
 220     case 'c':
 221         type = S_IFCHR;
 222         break;
 223     case 'l':
 224         type = S_IFLNK;
 225         break;
 226 #ifdef S_IFSOCK
 227     case 's':
 228         type = S_IFSOCK;
 229         break;
 230 #else
 231     case 's':
 232         type = S_IFIFO;
 233         break;
 234 #endif
 235 #ifdef S_IFDOOR  // Solaris door
 236     case 'D':
 237         type = S_IFDOOR;
 238         break;
 239 #else
 240     case 'D':
 241         type = S_IFIFO;
 242         break;
 243 #endif
 244     case 'p':
 245         type = S_IFIFO;
 246         break;
 247 #ifdef S_IFNAM  // Special named files
 248     case 'n':
 249         type = S_IFNAM;
 250         break;
 251 #else
 252     case 'n':
 253         type = S_IFREG;
 254         break;
 255 #endif
 256     case 'm':  // Don't know what these are :-)
 257     case '-':
 258     case '?':
 259         type = S_IFREG;
 260         break;
 261     default:
 262         return FALSE;
 263     }
 264 
 265     *ret_type = type;
 266 
 267     if (ret_skipped != NULL)
 268         *ret_skipped = 1;
 269     return TRUE;
 270 }
 271 
 272 /* --------------------------------------------------------------------------------------------- */
 273 
 274 gboolean
 275 vfs_parse_fileperms (const char *s, size_t *ret_skipped, mode_t *ret_perms)
     /* [previous][next][first][last][top][bottom][index][help]  */
 276 {
 277     const char *p = s;
 278     mode_t perms = 0;
 279 
 280     switch (*p++)
 281     {
 282     case '-':
 283         break;
 284     case 'r':
 285         perms |= S_IRUSR;
 286         break;
 287     default:
 288         return FALSE;
 289     }
 290 
 291     switch (*p++)
 292     {
 293     case '-':
 294         break;
 295     case 'w':
 296         perms |= S_IWUSR;
 297         break;
 298     default:
 299         return FALSE;
 300     }
 301 
 302     switch (*p++)
 303     {
 304     case '-':
 305         break;
 306     case 'S':
 307         perms |= S_ISUID;
 308         break;
 309     case 's':
 310         perms |= S_IXUSR | S_ISUID;
 311         break;
 312     case 'x':
 313         perms |= S_IXUSR;
 314         break;
 315     default:
 316         return FALSE;
 317     }
 318 
 319     switch (*p++)
 320     {
 321     case '-':
 322         break;
 323     case 'r':
 324         perms |= S_IRGRP;
 325         break;
 326     default:
 327         return FALSE;
 328     }
 329 
 330     switch (*p++)
 331     {
 332     case '-':
 333         break;
 334     case 'w':
 335         perms |= S_IWGRP;
 336         break;
 337     default:
 338         return FALSE;
 339     }
 340 
 341     switch (*p++)
 342     {
 343     case '-':
 344         break;
 345     case 'S':
 346         perms |= S_ISGID;
 347         break;
 348     case 'l':
 349         perms |= S_ISGID;
 350         break;  // found on Solaris
 351     case 's':
 352         perms |= S_IXGRP | S_ISGID;
 353         break;
 354     case 'x':
 355         perms |= S_IXGRP;
 356         break;
 357     default:
 358         return FALSE;
 359     }
 360 
 361     switch (*p++)
 362     {
 363     case '-':
 364         break;
 365     case 'r':
 366         perms |= S_IROTH;
 367         break;
 368     default:
 369         return FALSE;
 370     }
 371 
 372     switch (*p++)
 373     {
 374     case '-':
 375         break;
 376     case 'w':
 377         perms |= S_IWOTH;
 378         break;
 379     default:
 380         return FALSE;
 381     }
 382 
 383     switch (*p++)
 384     {
 385     case '-':
 386         break;
 387     case 'T':
 388         perms |= S_ISVTX;
 389         break;
 390     case 't':
 391         perms |= S_IXOTH | S_ISVTX;
 392         break;
 393     case 'x':
 394         perms |= S_IXOTH;
 395         break;
 396     default:
 397         return FALSE;
 398     }
 399 
 400     if (*p == '+')
 401         // ACLs on Solaris, HP-UX and others
 402         p++;
 403 
 404     if (ret_skipped != NULL)
 405         *ret_skipped = p - s;
 406     *ret_perms = perms;
 407 
 408     return TRUE;
 409 }
 410 
 411 /* --------------------------------------------------------------------------------------------- */
 412 
 413 gboolean
 414 vfs_parse_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 415 {
 416     const char *p = s;
 417     mode_t type, perms;
 418     size_t skipped;
 419 
 420     if (!vfs_parse_filetype (p, &skipped, &type))
 421         return FALSE;
 422 
 423     p += skipped;
 424     if (!vfs_parse_fileperms (p, &skipped, &perms))
 425         return FALSE;
 426 
 427     p += skipped;
 428     *ret_skipped = p - s;
 429     *ret_mode = type | perms;
 430 
 431     return TRUE;
 432 }
 433 
 434 /* --------------------------------------------------------------------------------------------- */
 435 
 436 gboolean
 437 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 438 {
 439     const char *p = s;
 440     mode_t remote_type = 0, local_type, perms = 0;
 441 
 442     // isoctal
 443     for (; *p >= '0' && *p <= '7'; p++)
 444     {
 445         perms *= 010;
 446         perms += (*p - '0');
 447     }
 448 
 449     if (*p++ != ' ')
 450         return FALSE;
 451 
 452     for (; *p >= '0' && *p <= '7'; p++)
 453     {
 454         remote_type *= 010;
 455         remote_type += (*p - '0');
 456     }
 457 
 458     if (*p++ != ' ')
 459         return FALSE;
 460 
 461     /* generated with:
 462        $ perl -e 'use Fcntl ":mode";
 463        my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
 464        foreach $t (@modes) { printf ("%o\n", $t); };'
 465        TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
 466        (see vfs_parse_filetype)
 467      */
 468 
 469     switch (remote_type)
 470     {
 471     case 020000:
 472         local_type = S_IFCHR;
 473         break;
 474     case 040000:
 475         local_type = S_IFDIR;
 476         break;
 477     case 060000:
 478         local_type = S_IFBLK;
 479         break;
 480     case 0120000:
 481         local_type = S_IFLNK;
 482         break;
 483     case 0100000:
 484     default:  // don't know what is it
 485         local_type = S_IFREG;
 486         break;
 487     }
 488 
 489     *ret_skipped = p - s;
 490     *ret_mode = local_type | perms;
 491 
 492     return TRUE;
 493 }
 494 
 495 /* --------------------------------------------------------------------------------------------- */
 496 
 497 gboolean
 498 vfs_parse_month (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 499 {
 500     static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
 501     const char *pos;
 502 
 503     if (str == NULL)
 504         return FALSE;
 505 
 506     pos = strstr (month, str);
 507     if (pos == NULL)
 508         return FALSE;
 509 
 510     if (tim != NULL)
 511         tim->tm_mon = (pos - month) / 3;
 512 
 513     return TRUE;
 514 }
 515 
 516 /* --------------------------------------------------------------------------------------------- */
 517 /** This function parses from idx in the columns[] array */
 518 
 519 int
 520 vfs_parse_filedate (int idx, time_t *t)
     /* [previous][next][first][last][top][bottom][index][help]  */
 521 {
 522     char *p;
 523     struct tm tim;
 524     int d[3];
 525     gboolean got_year = FALSE;
 526     gboolean l10n = FALSE;  // Locale's abbreviated month name
 527     time_t current_time;
 528     struct tm *local_time;
 529 
 530     // Let's setup default time values
 531     current_time = time (NULL);
 532     local_time = localtime (&current_time);
 533     tim.tm_mday = local_time->tm_mday;
 534     tim.tm_mon = local_time->tm_mon;
 535     tim.tm_year = local_time->tm_year;
 536 
 537     tim.tm_hour = 0;
 538     tim.tm_min = 0;
 539     tim.tm_sec = 0;
 540     tim.tm_isdst = -1;  // Let mktime() try to guess correct dst offset
 541 
 542     p = columns[idx++];
 543 
 544     // We eat weekday name in case of extfs
 545     if (is_week (p, &tim))
 546         p = columns[idx++];
 547 
 548     /*
 549        ALLOWED DATE FORMATS
 550 
 551        We expect 3 fields max or we'll see oddities with certain file names.
 552 
 553        Formats that contain either year or time (the default 'ls' formats):
 554 
 555        * Mon DD hh:mm[:ss]
 556        * Mon DD YYYY
 557 
 558        Formats that contain both year and time, to make it easier to write
 559        extfs scripts:
 560 
 561        * MM-DD-YYYY hh:mm[:ss]
 562        * MM-DD-YY hh:mm[:ss]
 563 
 564        ('/' and '\' can be used instead of '-'.)
 565 
 566        where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
 567        YYYY four digit year, hh, mm, ss two digit hour, minute or second.
 568 
 569        (As for the "3 fields max" restriction: this prevents, for example, a
 570        file name "13:48" from being considered part of a "Sep 19 2016" date
 571        string preceding it.)
 572      */
 573 
 574     // Month name
 575     if (vfs_parse_month (p, &tim))
 576     {
 577         // And we expect, it followed by day number
 578         if (!is_num (idx))
 579             return 0;  // No day
 580 
 581         tim.tm_mday = (int) atol (columns[idx++]);
 582     }
 583     else if (is_dos_date (p))
 584     {
 585         // Case with MM-DD-YY or MM-DD-YYYY
 586         p[2] = p[5] = '-';
 587 
 588         if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) != 3)
 589             return 0;  // sscanf failed
 590 
 591         // Months are zero based
 592         if (d[0] > 0)
 593             d[0]--;
 594 
 595         if (d[2] > 1900)
 596             d[2] -= 1900;
 597         else if (d[2] < 70)
 598             // Y2K madness
 599             d[2] += 100;
 600 
 601         tim.tm_mon = d[0];
 602         tim.tm_mday = d[1];
 603         tim.tm_year = d[2];
 604         got_year = TRUE;
 605     }
 606     else if (is_localized_month (p) && is_num (idx++))
 607         // Locale's abbreviated month name followed by day number
 608         l10n = TRUE;
 609     else
 610         return 0;  // unsupported format
 611 
 612     // Here we expect to find time or year
 613     if (!is_num (idx)
 614         || !(is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim))))
 615         return 0;  // Neither time nor date
 616 
 617     idx++;
 618 
 619     /*
 620      * If the date is less than 6 months in the past, it is shown without year
 621      * other dates in the past or future are shown with year but without time
 622      * This does not check for years before 1900 ... I don't know, how
 623      * to represent them at all
 624      */
 625     if (!got_year && local_time->tm_mon < 6 && local_time->tm_mon < tim.tm_mon
 626         && tim.tm_mon - local_time->tm_mon >= 6)
 627         tim.tm_year--;
 628 
 629     *t = mktime (&tim);
 630     if (l10n || (*t < 0))
 631         *t = 0;
 632 
 633     return idx;
 634 }
 635 
 636 /* --------------------------------------------------------------------------------------------- */
 637 
 638 int
 639 vfs_split_text (char *p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 640 {
 641     char *original = p;
 642     int numcols;
 643 
 644     memset (columns, 0, sizeof (columns));
 645 
 646     for (numcols = 0; *p != '\0' && numcols < MAXCOLS; numcols++)
 647     {
 648         for (; *p == ' ' || *p == '\r' || *p == '\n'; p++)
 649             *p = '\0';
 650 
 651         columns[numcols] = p;
 652         column_ptr[numcols] = p - original;
 653 
 654         for (; *p != '\0' && *p != ' ' && *p != '\r' && *p != '\n'; p++)
 655             ;
 656     }
 657 
 658     return numcols;
 659 }
 660 
 661 /* --------------------------------------------------------------------------------------------- */
 662 
 663 void
 664 vfs_parse_ls_lga_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 665 {
 666     vfs_parse_ls_final_num_spaces = 1;
 667 }
 668 
 669 /* --------------------------------------------------------------------------------------------- */
 670 
 671 size_t
 672 vfs_parse_ls_lga_get_final_spaces (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 673 {
 674     return vfs_parse_ls_final_num_spaces;
 675 }
 676 
 677 /* --------------------------------------------------------------------------------------------- */
 678 
 679 gboolean
 680 vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname,
     /* [previous][next][first][last][top][bottom][index][help]  */
 681                   size_t *num_spaces)
 682 {
 683     int idx, idx2, num_cols;
 684     int i;
 685     char *p_copy = NULL;
 686     char *t = NULL;
 687     const char *line = p;
 688     size_t skipped;
 689 
 690     if (strncmp (p, "total", 5) == 0)
 691         return FALSE;
 692 
 693     if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
 694         goto error;
 695 
 696     p += skipped;
 697     if (*p == ' ')  // Notwell 4
 698         p++;
 699     if (*p == '[')
 700     {
 701         if (strlen (p) <= 8 || p[8] != ']')
 702             goto error;
 703 
 704         // Should parse here the Novell permissions :)
 705         if (S_ISDIR (s->st_mode))
 706             s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
 707         else
 708             s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
 709         p += 9;
 710     }
 711     else
 712     {
 713         size_t lc_skipped;
 714         mode_t perms;
 715 
 716         if (!vfs_parse_fileperms (p, &lc_skipped, &perms))
 717             goto error;
 718 
 719         p += lc_skipped;
 720         s->st_mode |= perms;
 721     }
 722 
 723     p_copy = g_strdup (p);
 724     num_cols = vfs_split_text (p_copy);
 725 
 726     s->st_nlink = atol (columns[0]);
 727     if (s->st_nlink <= 0)
 728         goto error;
 729 
 730     if (!is_num (1))
 731         s->st_uid = vfs_finduid (columns[1]);
 732     else
 733         s->st_uid = (uid_t) atol (columns[1]);
 734 
 735     // Mhm, the ls -lg did not produce a group field
 736     for (idx = 3; idx <= 5; idx++)
 737         if (vfs_parse_month (columns[idx], NULL) || is_week (columns[idx], NULL)
 738             || is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
 739             break;
 740 
 741     if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
 742         goto error;
 743 
 744     // We don't have gid
 745     if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
 746         idx2 = 2;
 747     else
 748     {
 749         // We have gid field
 750         if (is_num (2))
 751             s->st_gid = (gid_t) atol (columns[2]);
 752         else
 753             s->st_gid = vfs_findgid (columns[2]);
 754         idx2 = 3;
 755     }
 756 
 757     // This is device
 758     if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))
 759     {
 760         int maj, min;
 761 
 762         // Corner case: there is no whitespace(s) between maj & min
 763         if (!is_num (idx2) && idx2 == 2)
 764         {
 765             if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
 766                 goto error;
 767         }
 768         else
 769         {
 770             if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
 771                 goto error;
 772 
 773             if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
 774                 goto error;
 775         }
 776 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 777         s->st_rdev = makedev (maj, min);
 778 #endif
 779         s->st_size = 0;
 780     }
 781     else
 782     {
 783         // Common file size
 784         if (!is_num (idx2))
 785             goto error;
 786 
 787         s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
 788 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 789         s->st_rdev = 0;
 790 #endif
 791     }
 792 
 793     vfs_zero_stat_times (s);
 794 
 795     idx = vfs_parse_filedate (idx, &s->st_mtime);
 796     if (idx == 0)
 797         goto error;
 798 
 799     // Use resulting time value
 800     s->st_atime = s->st_ctime = s->st_mtime;
 801 
 802     // s->st_dev and s->st_ino must be initialized by vfs_s_new_inode ()
 803 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
 804     s->st_blksize = 512;
 805 #endif
 806     vfs_adjust_stat (s);
 807 
 808     if (num_spaces != NULL)
 809     {
 810         *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
 811         if (DIR_IS_DOTDOT (columns[idx]))
 812             vfs_parse_ls_final_num_spaces = *num_spaces;
 813     }
 814 
 815     for (i = idx + 1, idx2 = 0; i < num_cols; i++)
 816         if (strcmp (columns[i], "->") == 0)
 817         {
 818             idx2 = i;
 819             break;
 820         }
 821 
 822     if (((S_ISLNK (s->st_mode)
 823           || (num_cols == idx + 3 && s->st_nlink > 1)))  // Maybe a hardlink? (in extfs)
 824         && idx2 != 0)
 825     {
 826         if (filename != NULL)
 827             *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
 828 
 829         if (linkname != NULL)
 830         {
 831             t = g_strdup (p + column_ptr[idx2 + 1]);
 832             *linkname = t;
 833         }
 834     }
 835     else
 836     {
 837         /* Extract the filename from the string copy, not from the columns
 838          * this way we have a chance of entering hidden directories like ". ."
 839          */
 840         if (filename != NULL)
 841         {
 842             // filename = g_strdup (columns [idx++]);
 843             t = g_strdup (p + column_ptr[idx]);
 844             *filename = t;
 845         }
 846 
 847         if (linkname != NULL)
 848             *linkname = NULL;
 849     }
 850 
 851     str_rstrip_eol (t);
 852 
 853     g_free (p_copy);
 854     return TRUE;
 855 
 856 error:
 857 {
 858     static int errorcount = 0;
 859 
 860     if (++errorcount < 5)
 861         message (D_ERROR, _ ("Cannot parse:"), "%s",
 862                  (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
 863     else if (errorcount == 5)
 864         message (D_ERROR, MSG_ERROR, _ ("More parsing errors will be ignored."));
 865 }
 866 
 867     g_free (p_copy);
 868     return FALSE;
 869 }
 870 
 871 /* --------------------------------------------------------------------------------------------- */

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