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-2021
   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 <http://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/unixcompat.h"     /* makedev */
  44 #include "lib/widget.h"         /* message() */
  45 
  46 #include "utilvfs.h"
  47 
  48 /*** global variables ****************************************************************************/
  49 
  50 /*** file scope macro definitions ****************************************************************/
  51 
  52 /* Parsing code is used by ftpfs, fish and extfs */
  53 #define MAXCOLS         30
  54 
  55 /*** file scope type declarations ****************************************************************/
  56 
  57 /*** file scope variables ************************************************************************/
  58 
  59 static char *columns[MAXCOLS];  /* Points to the string in column n */
  60 static int column_ptr[MAXCOLS]; /* Index from 0 to the starting positions of the columns */
  61 static size_t vfs_parce_ls_final_num_spaces = 0;
  62 
  63 /* --------------------------------------------------------------------------------------------- */
  64 /*** file scope functions ************************************************************************/
  65 /* --------------------------------------------------------------------------------------------- */
  66 
  67 static gboolean
  68 is_num (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
  69 {
  70     char *column = columns[idx];
  71 
  72     return (column != NULL && isdigit (column[0]));
  73 }
  74 
  75 /* --------------------------------------------------------------------------------------------- */
  76 /* Return TRUE for MM-DD-YY and MM-DD-YYYY */
  77 
  78 static gboolean
  79 is_dos_date (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
  80 {
  81     size_t len;
  82 
  83     if (str == NULL)
  84         return FALSE;
  85 
  86     len = strlen (str);
  87     if (len != 8 && len != 10)
  88         return FALSE;
  89 
  90     if (str[2] != str[5])
  91         return FALSE;
  92 
  93     return (strchr ("\\-/", (int) str[2]) != NULL);
  94 }
  95 
  96 /* --------------------------------------------------------------------------------------------- */
  97 
  98 static gboolean
  99 is_week (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 100 {
 101     static const char *week = "SunMonTueWedThuFriSat";
 102     const char *pos;
 103 
 104     if (str == NULL)
 105         return FALSE;
 106 
 107     pos = strstr (week, str);
 108     if (pos == NULL)
 109         return FALSE;
 110 
 111     if (tim != NULL)
 112         tim->tm_wday = (pos - week) / 3;
 113 
 114     return TRUE;
 115 }
 116 
 117 /* --------------------------------------------------------------------------------------------- */
 118 /**
 119  * Check for possible locale's abbreviated month name (Jan..Dec).
 120  * Any 3 bytes long string without digit, control and punctuation characters.
 121  * isalpha() is locale specific, so it cannot be used if current
 122  * locale is "C" and ftp server use Cyrillic.
 123  * NB: It is assumed there are no whitespaces in month.
 124  */
 125 static gboolean
 126 is_localized_month (const char *month)
     /* [previous][next][first][last][top][bottom][index][help]  */
 127 {
 128     int i;
 129 
 130     if (month == NULL)
 131         return FALSE;
 132 
 133     for (i = 0;
 134          i < 3 && *month != '\0' && !isdigit ((unsigned char) *month)
 135          && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month); i++, month++)
 136         ;
 137 
 138     return (i == 3 && *month == '\0');
 139 }
 140 
 141 /* --------------------------------------------------------------------------------------------- */
 142 
 143 static gboolean
 144 is_time (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 145 {
 146     const char *p, *p2;
 147 
 148     if (str == NULL)
 149         return FALSE;
 150 
 151     p = strchr (str, ':');
 152     if (p == NULL)
 153         return FALSE;
 154 
 155     p2 = strrchr (str, ':');
 156     if (p2 == NULL)
 157         return FALSE;
 158 
 159     if (p != p2)
 160     {
 161         if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
 162             return FALSE;
 163     }
 164     else
 165     {
 166         if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
 167             return FALSE;
 168     }
 169 
 170     return TRUE;
 171 }
 172 
 173 /* --------------------------------------------------------------------------------------------- */
 174 
 175 static gboolean
 176 is_year (char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 177 {
 178     long year;
 179 
 180     if (str == NULL)
 181         return FALSE;
 182 
 183     if (strchr (str, ':') != NULL)
 184         return FALSE;
 185 
 186     if (strlen (str) != 4)
 187         return FALSE;
 188 
 189     /* cppcheck-suppress invalidscanf */
 190     if (sscanf (str, "%ld", &year) != 1)
 191         return FALSE;
 192 
 193     if (year < 1900 || year > 3000)
 194         return FALSE;
 195 
 196     tim->tm_year = (int) (year - 1900);
 197 
 198     return TRUE;
 199 }
 200 
 201 /* --------------------------------------------------------------------------------------------- */
 202 /*** public functions ****************************************************************************/
 203 /* --------------------------------------------------------------------------------------------- */
 204 
 205 gboolean
 206 vfs_parse_filetype (const char *s, size_t * ret_skipped, mode_t * ret_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 207 {
 208     mode_t type;
 209 
 210     switch (*s)
 211     {
 212     case 'd':
 213         type = S_IFDIR;
 214         break;
 215     case 'b':
 216         type = S_IFBLK;
 217         break;
 218     case 'c':
 219         type = S_IFCHR;
 220         break;
 221     case 'l':
 222         type = S_IFLNK;
 223         break;
 224 #ifdef S_IFSOCK
 225     case 's':
 226         type = S_IFSOCK;
 227         break;
 228 #else
 229     case 's':
 230         type = S_IFIFO;
 231         break;
 232 #endif
 233 #ifdef S_IFDOOR                 /* Solaris door */
 234     case 'D':
 235         type = S_IFDOOR;
 236         break;
 237 #else
 238     case 'D':
 239         type = S_IFIFO;
 240         break;
 241 #endif
 242     case 'p':
 243         type = S_IFIFO;
 244         break;
 245 #ifdef S_IFNAM                  /* Special named files */
 246     case 'n':
 247         type = S_IFNAM;
 248         break;
 249 #else
 250     case 'n':
 251         type = S_IFREG;
 252         break;
 253 #endif
 254     case 'm':                  /* Don't know what these are :-) */
 255     case '-':
 256     case '?':
 257         type = S_IFREG;
 258         break;
 259     default:
 260         return FALSE;
 261     }
 262 
 263     *ret_type = type;
 264 
 265     if (ret_skipped != NULL)
 266         *ret_skipped = 1;
 267     return TRUE;
 268 }
 269 
 270 /* --------------------------------------------------------------------------------------------- */
 271 
 272 gboolean
 273 vfs_parse_fileperms (const char *s, size_t * ret_skipped, mode_t * ret_perms)
     /* [previous][next][first][last][top][bottom][index][help]  */
 274 {
 275     const char *p = s;
 276     mode_t perms = 0;
 277 
 278     switch (*p++)
 279     {
 280     case '-':
 281         break;
 282     case 'r':
 283         perms |= S_IRUSR;
 284         break;
 285     default:
 286         return FALSE;
 287     }
 288 
 289     switch (*p++)
 290     {
 291     case '-':
 292         break;
 293     case 'w':
 294         perms |= S_IWUSR;
 295         break;
 296     default:
 297         return FALSE;
 298     }
 299 
 300     switch (*p++)
 301     {
 302     case '-':
 303         break;
 304     case 'S':
 305         perms |= S_ISUID;
 306         break;
 307     case 's':
 308         perms |= S_IXUSR | S_ISUID;
 309         break;
 310     case 'x':
 311         perms |= S_IXUSR;
 312         break;
 313     default:
 314         return FALSE;
 315     }
 316 
 317     switch (*p++)
 318     {
 319     case '-':
 320         break;
 321     case 'r':
 322         perms |= S_IRGRP;
 323         break;
 324     default:
 325         return FALSE;
 326     }
 327 
 328     switch (*p++)
 329     {
 330     case '-':
 331         break;
 332     case 'w':
 333         perms |= S_IWGRP;
 334         break;
 335     default:
 336         return FALSE;
 337     }
 338 
 339     switch (*p++)
 340     {
 341     case '-':
 342         break;
 343     case 'S':
 344         perms |= S_ISGID;
 345         break;
 346     case 'l':
 347         perms |= S_ISGID;
 348         break;                  /* found on Solaris */
 349     case 's':
 350         perms |= S_IXGRP | S_ISGID;
 351         break;
 352     case 'x':
 353         perms |= S_IXGRP;
 354         break;
 355     default:
 356         return FALSE;
 357     }
 358 
 359     switch (*p++)
 360     {
 361     case '-':
 362         break;
 363     case 'r':
 364         perms |= S_IROTH;
 365         break;
 366     default:
 367         return FALSE;
 368     }
 369 
 370     switch (*p++)
 371     {
 372     case '-':
 373         break;
 374     case 'w':
 375         perms |= S_IWOTH;
 376         break;
 377     default:
 378         return FALSE;
 379     }
 380 
 381     switch (*p++)
 382     {
 383     case '-':
 384         break;
 385     case 'T':
 386         perms |= S_ISVTX;
 387         break;
 388     case 't':
 389         perms |= S_IXOTH | S_ISVTX;
 390         break;
 391     case 'x':
 392         perms |= S_IXOTH;
 393         break;
 394     default:
 395         return FALSE;
 396     }
 397 
 398     if (*p == '+')
 399         /* ACLs on Solaris, HP-UX and others */
 400         p++;
 401 
 402     if (ret_skipped != NULL)
 403         *ret_skipped = p - s;
 404     *ret_perms = perms;
 405 
 406     return TRUE;
 407 }
 408 
 409 /* --------------------------------------------------------------------------------------------- */
 410 
 411 gboolean
 412 vfs_parse_filemode (const char *s, size_t * ret_skipped, mode_t * ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 413 {
 414     const char *p = s;
 415     mode_t type, perms;
 416     size_t skipped;
 417 
 418     if (!vfs_parse_filetype (p, &skipped, &type))
 419         return FALSE;
 420 
 421     p += skipped;
 422     if (!vfs_parse_fileperms (p, &skipped, &perms))
 423         return FALSE;
 424 
 425     p += skipped;
 426     *ret_skipped = p - s;
 427     *ret_mode = type | perms;
 428 
 429     return TRUE;
 430 }
 431 
 432 /* --------------------------------------------------------------------------------------------- */
 433 
 434 gboolean
 435 vfs_parse_raw_filemode (const char *s, size_t * ret_skipped, mode_t * ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 436 {
 437     const char *p = s;
 438     mode_t remote_type = 0, local_type, perms = 0;
 439 
 440     /* isoctal */
 441     for (; *p >= '0' && *p <= '7'; p++)
 442     {
 443         perms *= 010;
 444         perms += (*p - '0');
 445     }
 446 
 447     if (*p++ != ' ')
 448         return FALSE;
 449 
 450     for (; *p >= '0' && *p <= '7'; p++)
 451     {
 452         remote_type *= 010;
 453         remote_type += (*p - '0');
 454     }
 455 
 456     if (*p++ != ' ')
 457         return FALSE;
 458 
 459     /* generated with:
 460        $ perl -e 'use Fcntl ":mode";
 461        my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
 462        foreach $t (@modes) { printf ("%o\n", $t); };'
 463        TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
 464        (see vfs_parse_filetype)
 465      */
 466 
 467     switch (remote_type)
 468     {
 469     case 020000:
 470         local_type = S_IFCHR;
 471         break;
 472     case 040000:
 473         local_type = S_IFDIR;
 474         break;
 475     case 060000:
 476         local_type = S_IFBLK;
 477         break;
 478     case 0120000:
 479         local_type = S_IFLNK;
 480         break;
 481     case 0100000:
 482     default:                   /* don't know what is it */
 483         local_type = S_IFREG;
 484         break;
 485     }
 486 
 487     *ret_skipped = p - s;
 488     *ret_mode = local_type | perms;
 489 
 490     return TRUE;
 491 }
 492 
 493 /* --------------------------------------------------------------------------------------------- */
 494 
 495 gboolean
 496 vfs_parse_month (const char *str, struct tm * tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 497 {
 498     static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
 499     const char *pos;
 500 
 501     if (str == NULL)
 502         return FALSE;
 503 
 504     pos = strstr (month, str);
 505     if (pos == NULL)
 506         return FALSE;
 507 
 508     if (tim != NULL)
 509         tim->tm_mon = (pos - month) / 3;
 510 
 511     return TRUE;
 512 }
 513 
 514 /* --------------------------------------------------------------------------------------------- */
 515 /** This function parses from idx in the columns[] array */
 516 
 517 int
 518 vfs_parse_filedate (int idx, time_t * t)
     /* [previous][next][first][last][top][bottom][index][help]  */
 519 {
 520     char *p;
 521     struct tm tim;
 522     int d[3];
 523     gboolean got_year = FALSE;
 524     gboolean l10n = FALSE;      /* Locale's abbreviated month name */
 525     time_t current_time;
 526     struct tm *local_time;
 527 
 528     /* Let's setup default time values */
 529     current_time = time (NULL);
 530     local_time = localtime (&current_time);
 531     tim.tm_mday = local_time->tm_mday;
 532     tim.tm_mon = local_time->tm_mon;
 533     tim.tm_year = local_time->tm_year;
 534 
 535     tim.tm_hour = 0;
 536     tim.tm_min = 0;
 537     tim.tm_sec = 0;
 538     tim.tm_isdst = -1;          /* Let mktime() try to guess correct dst offset */
 539 
 540     p = columns[idx++];
 541 
 542     /* We eat weekday name in case of extfs */
 543     if (is_week (p, &tim))
 544         p = columns[idx++];
 545 
 546     /*
 547        ALLOWED DATE FORMATS
 548 
 549        We expect 3 fields max or we'll see oddities with certain file names.
 550 
 551        Formats that contain either year or time (the default 'ls' formats):
 552 
 553        * Mon DD hh:mm[:ss]
 554        * Mon DD YYYY
 555 
 556        Formats that contain both year and time, to make it easier to write
 557        extfs scripts:
 558 
 559        * MM-DD-YYYY hh:mm[:ss]
 560        * MM-DD-YY hh:mm[:ss]
 561 
 562        ('/' and '\' can be used instead of '-'.)
 563 
 564        where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
 565        YYYY four digit year, hh, mm, ss two digit hour, minute or second.
 566 
 567        (As for the "3 fields max" restriction: this prevents, for example, a
 568        file name "13:48" from being considered part of a "Sep 19 2016" date
 569        string preceding it.)
 570      */
 571 
 572     /* Month name */
 573     if (vfs_parse_month (p, &tim))
 574     {
 575         /* And we expect, it followed by day number */
 576         if (!is_num (idx))
 577             return 0;           /* No day */
 578 
 579         tim.tm_mday = (int) atol (columns[idx++]);
 580 
 581     }
 582     else if (is_dos_date (p))
 583     {
 584         /* Case with MM-DD-YY or MM-DD-YYYY */
 585         p[2] = p[5] = '-';
 586 
 587         /* cppcheck-suppress invalidscanf */
 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_parce_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_parce_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 Notwell 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             /* cppcheck-suppress invalidscanf */
 766             if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
 767                 goto error;
 768         }
 769         else
 770         {
 771             /* cppcheck-suppress invalidscanf */
 772             if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
 773                 goto error;
 774 
 775             /* cppcheck-suppress invalidscanf */
 776             if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
 777                 goto error;
 778         }
 779 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 780         s->st_rdev = makedev (maj, min);
 781 #endif
 782         s->st_size = 0;
 783 
 784     }
 785     else
 786     {
 787         /* Common file size */
 788         if (!is_num (idx2))
 789             goto error;
 790 
 791         s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
 792 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 793         s->st_rdev = 0;
 794 #endif
 795     }
 796 
 797     idx = vfs_parse_filedate (idx, &s->st_mtime);
 798     if (idx == 0)
 799         goto error;
 800 
 801     /* Use resulting time value */
 802     s->st_atime = s->st_ctime = s->st_mtime;
 803 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 804     s->st_atim.tv_nsec = s->st_mtim.tv_nsec = s->st_ctim.tv_nsec = 0;
 805 #endif
 806 
 807     /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
 808 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
 809     s->st_blksize = 512;
 810 #endif
 811     vfs_adjust_stat (s);
 812 
 813     if (num_spaces != NULL)
 814     {
 815         *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
 816         if (DIR_IS_DOTDOT (columns[idx]))
 817             vfs_parce_ls_final_num_spaces = *num_spaces;
 818     }
 819 
 820     for (i = idx + 1, idx2 = 0; i < num_cols; i++)
 821         if (strcmp (columns[i], "->") == 0)
 822         {
 823             idx2 = i;
 824             break;
 825         }
 826 
 827     if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1)))    /* Maybe a hardlink? (in extfs) */
 828         && idx2 != 0)
 829     {
 830         if (filename != NULL)
 831             *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
 832 
 833         if (linkname != NULL)
 834         {
 835             t = g_strdup (p + column_ptr[idx2 + 1]);
 836             *linkname = t;
 837         }
 838     }
 839     else
 840     {
 841         /* Extract the filename from the string copy, not from the columns
 842          * this way we have a chance of entering hidden directories like ". ."
 843          */
 844         if (filename != NULL)
 845         {
 846             /* filename = g_strdup (columns [idx++]); */
 847             t = g_strdup (p + column_ptr[idx]);
 848             *filename = t;
 849         }
 850 
 851         if (linkname != NULL)
 852             *linkname = NULL;
 853     }
 854 
 855     if (t != NULL)
 856     {
 857         size_t p2;
 858 
 859         p2 = strlen (t);
 860         if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
 861             t[p2] = '\0';
 862         if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
 863             t[p2] = '\0';
 864     }
 865 
 866     g_free (p_copy);
 867     return TRUE;
 868 
 869   error:
 870     {
 871         static int errorcount = 0;
 872 
 873         if (++errorcount < 5)
 874             message (D_ERROR, _("Cannot parse:"), "%s",
 875                      (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
 876         else if (errorcount == 5)
 877             message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored."));
 878     }
 879 
 880     g_free (p_copy);
 881     return FALSE;
 882 }
 883 
 884 /* --------------------------------------------------------------------------------------------- */

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