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     // cppcheck-suppress invalidscanf
 193     if (sscanf (str, "%ld", &year) != 1)
 194         return FALSE;
 195 
 196     if (year < 1900 || year > 3000)
 197         return FALSE;
 198 
 199     tim->tm_year = (int) (year - 1900);
 200 
 201     return TRUE;
 202 }
 203 
 204 /* --------------------------------------------------------------------------------------------- */
 205 /*** public functions ****************************************************************************/
 206 /* --------------------------------------------------------------------------------------------- */
 207 
 208 gboolean
 209 vfs_parse_filetype (const char *s, size_t *ret_skipped, mode_t *ret_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 210 {
 211     mode_t type;
 212 
 213     switch (*s)
 214     {
 215     case 'd':
 216         type = S_IFDIR;
 217         break;
 218     case 'b':
 219         type = S_IFBLK;
 220         break;
 221     case 'c':
 222         type = S_IFCHR;
 223         break;
 224     case 'l':
 225         type = S_IFLNK;
 226         break;
 227 #ifdef S_IFSOCK
 228     case 's':
 229         type = S_IFSOCK;
 230         break;
 231 #else
 232     case 's':
 233         type = S_IFIFO;
 234         break;
 235 #endif
 236 #ifdef S_IFDOOR  // Solaris door
 237     case 'D':
 238         type = S_IFDOOR;
 239         break;
 240 #else
 241     case 'D':
 242         type = S_IFIFO;
 243         break;
 244 #endif
 245     case 'p':
 246         type = S_IFIFO;
 247         break;
 248 #ifdef S_IFNAM  // Special named files
 249     case 'n':
 250         type = S_IFNAM;
 251         break;
 252 #else
 253     case 'n':
 254         type = S_IFREG;
 255         break;
 256 #endif
 257     case 'm':  // Don't know what these are :-)
 258     case '-':
 259     case '?':
 260         type = S_IFREG;
 261         break;
 262     default:
 263         return FALSE;
 264     }
 265 
 266     *ret_type = type;
 267 
 268     if (ret_skipped != NULL)
 269         *ret_skipped = 1;
 270     return TRUE;
 271 }
 272 
 273 /* --------------------------------------------------------------------------------------------- */
 274 
 275 gboolean
 276 vfs_parse_fileperms (const char *s, size_t *ret_skipped, mode_t *ret_perms)
     /* [previous][next][first][last][top][bottom][index][help]  */
 277 {
 278     const char *p = s;
 279     mode_t perms = 0;
 280 
 281     switch (*p++)
 282     {
 283     case '-':
 284         break;
 285     case 'r':
 286         perms |= S_IRUSR;
 287         break;
 288     default:
 289         return FALSE;
 290     }
 291 
 292     switch (*p++)
 293     {
 294     case '-':
 295         break;
 296     case 'w':
 297         perms |= S_IWUSR;
 298         break;
 299     default:
 300         return FALSE;
 301     }
 302 
 303     switch (*p++)
 304     {
 305     case '-':
 306         break;
 307     case 'S':
 308         perms |= S_ISUID;
 309         break;
 310     case 's':
 311         perms |= S_IXUSR | S_ISUID;
 312         break;
 313     case 'x':
 314         perms |= S_IXUSR;
 315         break;
 316     default:
 317         return FALSE;
 318     }
 319 
 320     switch (*p++)
 321     {
 322     case '-':
 323         break;
 324     case 'r':
 325         perms |= S_IRGRP;
 326         break;
 327     default:
 328         return FALSE;
 329     }
 330 
 331     switch (*p++)
 332     {
 333     case '-':
 334         break;
 335     case 'w':
 336         perms |= S_IWGRP;
 337         break;
 338     default:
 339         return FALSE;
 340     }
 341 
 342     switch (*p++)
 343     {
 344     case '-':
 345         break;
 346     case 'S':
 347         perms |= S_ISGID;
 348         break;
 349     case 'l':
 350         perms |= S_ISGID;
 351         break;  // found on Solaris
 352     case 's':
 353         perms |= S_IXGRP | S_ISGID;
 354         break;
 355     case 'x':
 356         perms |= S_IXGRP;
 357         break;
 358     default:
 359         return FALSE;
 360     }
 361 
 362     switch (*p++)
 363     {
 364     case '-':
 365         break;
 366     case 'r':
 367         perms |= S_IROTH;
 368         break;
 369     default:
 370         return FALSE;
 371     }
 372 
 373     switch (*p++)
 374     {
 375     case '-':
 376         break;
 377     case 'w':
 378         perms |= S_IWOTH;
 379         break;
 380     default:
 381         return FALSE;
 382     }
 383 
 384     switch (*p++)
 385     {
 386     case '-':
 387         break;
 388     case 'T':
 389         perms |= S_ISVTX;
 390         break;
 391     case 't':
 392         perms |= S_IXOTH | S_ISVTX;
 393         break;
 394     case 'x':
 395         perms |= S_IXOTH;
 396         break;
 397     default:
 398         return FALSE;
 399     }
 400 
 401     if (*p == '+')
 402         // ACLs on Solaris, HP-UX and others
 403         p++;
 404 
 405     if (ret_skipped != NULL)
 406         *ret_skipped = p - s;
 407     *ret_perms = perms;
 408 
 409     return TRUE;
 410 }
 411 
 412 /* --------------------------------------------------------------------------------------------- */
 413 
 414 gboolean
 415 vfs_parse_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 416 {
 417     const char *p = s;
 418     mode_t type, perms;
 419     size_t skipped;
 420 
 421     if (!vfs_parse_filetype (p, &skipped, &type))
 422         return FALSE;
 423 
 424     p += skipped;
 425     if (!vfs_parse_fileperms (p, &skipped, &perms))
 426         return FALSE;
 427 
 428     p += skipped;
 429     *ret_skipped = p - s;
 430     *ret_mode = type | perms;
 431 
 432     return TRUE;
 433 }
 434 
 435 /* --------------------------------------------------------------------------------------------- */
 436 
 437 gboolean
 438 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 439 {
 440     const char *p = s;
 441     mode_t remote_type = 0, local_type, perms = 0;
 442 
 443     // isoctal
 444     for (; *p >= '0' && *p <= '7'; p++)
 445     {
 446         perms *= 010;
 447         perms += (*p - '0');
 448     }
 449 
 450     if (*p++ != ' ')
 451         return FALSE;
 452 
 453     for (; *p >= '0' && *p <= '7'; p++)
 454     {
 455         remote_type *= 010;
 456         remote_type += (*p - '0');
 457     }
 458 
 459     if (*p++ != ' ')
 460         return FALSE;
 461 
 462     /* generated with:
 463        $ perl -e 'use Fcntl ":mode";
 464        my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
 465        foreach $t (@modes) { printf ("%o\n", $t); };'
 466        TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
 467        (see vfs_parse_filetype)
 468      */
 469 
 470     switch (remote_type)
 471     {
 472     case 020000:
 473         local_type = S_IFCHR;
 474         break;
 475     case 040000:
 476         local_type = S_IFDIR;
 477         break;
 478     case 060000:
 479         local_type = S_IFBLK;
 480         break;
 481     case 0120000:
 482         local_type = S_IFLNK;
 483         break;
 484     case 0100000:
 485     default:  // don't know what is it
 486         local_type = S_IFREG;
 487         break;
 488     }
 489 
 490     *ret_skipped = p - s;
 491     *ret_mode = local_type | perms;
 492 
 493     return TRUE;
 494 }
 495 
 496 /* --------------------------------------------------------------------------------------------- */
 497 
 498 gboolean
 499 vfs_parse_month (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 500 {
 501     static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
 502     const char *pos;
 503 
 504     if (str == NULL)
 505         return FALSE;
 506 
 507     pos = strstr (month, str);
 508     if (pos == NULL)
 509         return FALSE;
 510 
 511     if (tim != NULL)
 512         tim->tm_mon = (pos - month) / 3;
 513 
 514     return TRUE;
 515 }
 516 
 517 /* --------------------------------------------------------------------------------------------- */
 518 /** This function parses from idx in the columns[] array */
 519 
 520 int
 521 vfs_parse_filedate (int idx, time_t *t)
     /* [previous][next][first][last][top][bottom][index][help]  */
 522 {
 523     char *p;
 524     struct tm tim;
 525     int d[3];
 526     gboolean got_year = FALSE;
 527     gboolean l10n = FALSE;  // Locale's abbreviated month name
 528     time_t current_time;
 529     struct tm *local_time;
 530 
 531     // Let's setup default time values
 532     current_time = time (NULL);
 533     local_time = localtime (&current_time);
 534     tim.tm_mday = local_time->tm_mday;
 535     tim.tm_mon = local_time->tm_mon;
 536     tim.tm_year = local_time->tm_year;
 537 
 538     tim.tm_hour = 0;
 539     tim.tm_min = 0;
 540     tim.tm_sec = 0;
 541     tim.tm_isdst = -1;  // Let mktime() try to guess correct dst offset
 542 
 543     p = columns[idx++];
 544 
 545     // We eat weekday name in case of extfs
 546     if (is_week (p, &tim))
 547         p = columns[idx++];
 548 
 549     /*
 550        ALLOWED DATE FORMATS
 551 
 552        We expect 3 fields max or we'll see oddities with certain file names.
 553 
 554        Formats that contain either year or time (the default 'ls' formats):
 555 
 556        * Mon DD hh:mm[:ss]
 557        * Mon DD YYYY
 558 
 559        Formats that contain both year and time, to make it easier to write
 560        extfs scripts:
 561 
 562        * MM-DD-YYYY hh:mm[:ss]
 563        * MM-DD-YY hh:mm[:ss]
 564 
 565        ('/' and '\' can be used instead of '-'.)
 566 
 567        where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
 568        YYYY four digit year, hh, mm, ss two digit hour, minute or second.
 569 
 570        (As for the "3 fields max" restriction: this prevents, for example, a
 571        file name "13:48" from being considered part of a "Sep 19 2016" date
 572        string preceding it.)
 573      */
 574 
 575     // Month name
 576     if (vfs_parse_month (p, &tim))
 577     {
 578         // And we expect, it followed by day number
 579         if (!is_num (idx))
 580             return 0;  // No day
 581 
 582         tim.tm_mday = (int) atol (columns[idx++]);
 583     }
 584     else if (is_dos_date (p))
 585     {
 586         // Case with MM-DD-YY or MM-DD-YYYY
 587         p[2] = p[5] = '-';
 588 
 589         // cppcheck-suppress invalidscanf
 590         if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) != 3)
 591             return 0;  // sscanf failed
 592 
 593         // Months are zero based
 594         if (d[0] > 0)
 595             d[0]--;
 596 
 597         if (d[2] > 1900)
 598             d[2] -= 1900;
 599         else if (d[2] < 70)
 600             // Y2K madness
 601             d[2] += 100;
 602 
 603         tim.tm_mon = d[0];
 604         tim.tm_mday = d[1];
 605         tim.tm_year = d[2];
 606         got_year = TRUE;
 607     }
 608     else if (is_localized_month (p) && is_num (idx++))
 609         // Locale's abbreviated month name followed by day number
 610         l10n = TRUE;
 611     else
 612         return 0;  // unsupported format
 613 
 614     // Here we expect to find time or year
 615     if (!is_num (idx)
 616         || !(is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim))))
 617         return 0;  // Neither time nor date
 618 
 619     idx++;
 620 
 621     /*
 622      * If the date is less than 6 months in the past, it is shown without year
 623      * other dates in the past or future are shown with year but without time
 624      * This does not check for years before 1900 ... I don't know, how
 625      * to represent them at all
 626      */
 627     if (!got_year && local_time->tm_mon < 6 && local_time->tm_mon < tim.tm_mon
 628         && tim.tm_mon - local_time->tm_mon >= 6)
 629         tim.tm_year--;
 630 
 631     *t = mktime (&tim);
 632     if (l10n || (*t < 0))
 633         *t = 0;
 634 
 635     return idx;
 636 }
 637 
 638 /* --------------------------------------------------------------------------------------------- */
 639 
 640 int
 641 vfs_split_text (char *p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 642 {
 643     char *original = p;
 644     int numcols;
 645 
 646     memset (columns, 0, sizeof (columns));
 647 
 648     for (numcols = 0; *p != '\0' && numcols < MAXCOLS; numcols++)
 649     {
 650         for (; *p == ' ' || *p == '\r' || *p == '\n'; p++)
 651             *p = '\0';
 652 
 653         columns[numcols] = p;
 654         column_ptr[numcols] = p - original;
 655 
 656         for (; *p != '\0' && *p != ' ' && *p != '\r' && *p != '\n'; p++)
 657             ;
 658     }
 659 
 660     return numcols;
 661 }
 662 
 663 /* --------------------------------------------------------------------------------------------- */
 664 
 665 void
 666 vfs_parse_ls_lga_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 667 {
 668     vfs_parse_ls_final_num_spaces = 1;
 669 }
 670 
 671 /* --------------------------------------------------------------------------------------------- */
 672 
 673 size_t
 674 vfs_parse_ls_lga_get_final_spaces (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 675 {
 676     return vfs_parse_ls_final_num_spaces;
 677 }
 678 
 679 /* --------------------------------------------------------------------------------------------- */
 680 
 681 gboolean
 682 vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname,
     /* [previous][next][first][last][top][bottom][index][help]  */
 683                   size_t *num_spaces)
 684 {
 685     int idx, idx2, num_cols;
 686     int i;
 687     char *p_copy = NULL;
 688     char *t = NULL;
 689     const char *line = p;
 690     size_t skipped;
 691 
 692     if (strncmp (p, "total", 5) == 0)
 693         return FALSE;
 694 
 695     if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
 696         goto error;
 697 
 698     p += skipped;
 699     if (*p == ' ')  // Notwell 4
 700         p++;
 701     if (*p == '[')
 702     {
 703         if (strlen (p) <= 8 || p[8] != ']')
 704             goto error;
 705 
 706         // Should parse here the Novell permissions :)
 707         if (S_ISDIR (s->st_mode))
 708             s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
 709         else
 710             s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
 711         p += 9;
 712     }
 713     else
 714     {
 715         size_t lc_skipped;
 716         mode_t perms;
 717 
 718         if (!vfs_parse_fileperms (p, &lc_skipped, &perms))
 719             goto error;
 720 
 721         p += lc_skipped;
 722         s->st_mode |= perms;
 723     }
 724 
 725     p_copy = g_strdup (p);
 726     num_cols = vfs_split_text (p_copy);
 727 
 728     s->st_nlink = atol (columns[0]);
 729     if (s->st_nlink <= 0)
 730         goto error;
 731 
 732     if (!is_num (1))
 733         s->st_uid = vfs_finduid (columns[1]);
 734     else
 735         s->st_uid = (uid_t) atol (columns[1]);
 736 
 737     // Mhm, the ls -lg did not produce a group field
 738     for (idx = 3; idx <= 5; idx++)
 739         if (vfs_parse_month (columns[idx], NULL) || is_week (columns[idx], NULL)
 740             || is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
 741             break;
 742 
 743     if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
 744         goto error;
 745 
 746     // We don't have gid
 747     if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
 748         idx2 = 2;
 749     else
 750     {
 751         // We have gid field
 752         if (is_num (2))
 753             s->st_gid = (gid_t) atol (columns[2]);
 754         else
 755             s->st_gid = vfs_findgid (columns[2]);
 756         idx2 = 3;
 757     }
 758 
 759     // This is device
 760     if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))
 761     {
 762         int maj, min;
 763 
 764         // Corner case: there is no whitespace(s) between maj & min
 765         if (!is_num (idx2) && idx2 == 2)
 766         {
 767             // cppcheck-suppress invalidscanf
 768             if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
 769                 goto error;
 770         }
 771         else
 772         {
 773             // cppcheck-suppress invalidscanf
 774             if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
 775                 goto error;
 776 
 777             // cppcheck-suppress invalidscanf
 778             if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
 779                 goto error;
 780         }
 781 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 782         s->st_rdev = makedev (maj, min);
 783 #endif
 784         s->st_size = 0;
 785     }
 786     else
 787     {
 788         // Common file size
 789         if (!is_num (idx2))
 790             goto error;
 791 
 792         s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
 793 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 794         s->st_rdev = 0;
 795 #endif
 796     }
 797 
 798     vfs_zero_stat_times (s);
 799 
 800     idx = vfs_parse_filedate (idx, &s->st_mtime);
 801     if (idx == 0)
 802         goto error;
 803 
 804     // Use resulting time value
 805     s->st_atime = s->st_ctime = s->st_mtime;
 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_parse_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)
 828           || (num_cols == idx + 3 && s->st_nlink > 1)))  // Maybe a hardlink? (in extfs)
 829         && idx2 != 0)
 830     {
 831         if (filename != NULL)
 832             *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
 833 
 834         if (linkname != NULL)
 835         {
 836             t = g_strdup (p + column_ptr[idx2 + 1]);
 837             *linkname = t;
 838         }
 839     }
 840     else
 841     {
 842         /* Extract the filename from the string copy, not from the columns
 843          * this way we have a chance of entering hidden directories like ". ."
 844          */
 845         if (filename != NULL)
 846         {
 847             // filename = g_strdup (columns [idx++]);
 848             t = g_strdup (p + column_ptr[idx]);
 849             *filename = t;
 850         }
 851 
 852         if (linkname != NULL)
 853             *linkname = NULL;
 854     }
 855 
 856     str_rstrip_eol (t);
 857 
 858     g_free (p_copy);
 859     return TRUE;
 860 
 861 error:
 862 {
 863     static int errorcount = 0;
 864 
 865     if (++errorcount < 5)
 866         message (D_ERROR, _ ("Cannot parse:"), "%s",
 867                  (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
 868     else if (errorcount == 5)
 869         message (D_ERROR, MSG_ERROR, _ ("More parsing errors will be ignored."));
 870 }
 871 
 872     g_free (p_copy);
 873     return FALSE;
 874 }
 875 
 876 /* --------------------------------------------------------------------------------------------- */

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