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-2024
   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, shell and extfs */
  53 #define MAXCOLS         30
  54 
  55 /*** file scope type declarations ****************************************************************/
  56 
  57 /*** forward declarations (file scope functions) *************************************************/
  58 
  59 /*** file scope variables ************************************************************************/
  60 
  61 static char *columns[MAXCOLS];  /* Points to the string in column n */
  62 static int column_ptr[MAXCOLS]; /* Index from 0 to the starting positions of the columns */
  63 static size_t vfs_parse_ls_final_num_spaces = 0;
  64 
  65 /* --------------------------------------------------------------------------------------------- */
  66 /*** file scope functions ************************************************************************/
  67 /* --------------------------------------------------------------------------------------------- */
  68 
  69 static gboolean
  70 is_num (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
  71 {
  72     char *column = columns[idx];
  73 
  74     return (column != NULL && isdigit (column[0]));
  75 }
  76 
  77 /* --------------------------------------------------------------------------------------------- */
  78 /* Return TRUE for MM-DD-YY and MM-DD-YYYY */
  79 
  80 static gboolean
  81 is_dos_date (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
  82 {
  83     size_t len;
  84 
  85     if (str == NULL)
  86         return FALSE;
  87 
  88     len = strlen (str);
  89     if (len != 8 && len != 10)
  90         return FALSE;
  91 
  92     if (str[2] != str[5])
  93         return FALSE;
  94 
  95     return (strchr ("\\-/", (int) str[2]) != NULL);
  96 }
  97 
  98 /* --------------------------------------------------------------------------------------------- */
  99 
 100 static gboolean
 101 is_week (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 102 {
 103     static const char *week = "SunMonTueWedThuFriSat";
 104     const char *pos;
 105 
 106     if (str == NULL)
 107         return FALSE;
 108 
 109     pos = strstr (week, str);
 110     if (pos == NULL)
 111         return FALSE;
 112 
 113     if (tim != NULL)
 114         tim->tm_wday = (pos - week) / 3;
 115 
 116     return TRUE;
 117 }
 118 
 119 /* --------------------------------------------------------------------------------------------- */
 120 /**
 121  * Check for possible locale's abbreviated month name (Jan..Dec).
 122  * Any 3 bytes long string without digit, control and punctuation characters.
 123  * isalpha() is locale specific, so it cannot be used if current
 124  * locale is "C" and ftp server use Cyrillic.
 125  * NB: It is assumed there are no whitespaces in month.
 126  */
 127 static gboolean
 128 is_localized_month (const char *month)
     /* [previous][next][first][last][top][bottom][index][help]  */
 129 {
 130     int i;
 131 
 132     if (month == NULL)
 133         return FALSE;
 134 
 135     for (i = 0;
 136          i < 3 && *month != '\0' && !isdigit ((unsigned char) *month)
 137          && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month); i++, month++)
 138         ;
 139 
 140     return (i == 3 && *month == '\0');
 141 }
 142 
 143 /* --------------------------------------------------------------------------------------------- */
 144 
 145 static gboolean
 146 is_time (const char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 147 {
 148     const char *p, *p2;
 149 
 150     if (str == NULL)
 151         return FALSE;
 152 
 153     p = strchr (str, ':');
 154     if (p == NULL)
 155         return FALSE;
 156 
 157     p2 = strrchr (str, ':');
 158     if (p2 == NULL)
 159         return FALSE;
 160 
 161     if (p != p2)
 162     {
 163         if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
 164             return FALSE;
 165     }
 166     else
 167     {
 168         if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
 169             return FALSE;
 170     }
 171 
 172     return TRUE;
 173 }
 174 
 175 /* --------------------------------------------------------------------------------------------- */
 176 
 177 static gboolean
 178 is_year (char *str, struct tm *tim)
     /* [previous][next][first][last][top][bottom][index][help]  */
 179 {
 180     long year;
 181 
 182     if (str == NULL)
 183         return FALSE;
 184 
 185     if (strchr (str, ':') != NULL)
 186         return FALSE;
 187 
 188     if (strlen (str) != 4)
 189         return FALSE;
 190 
 191     /* cppcheck-suppress invalidscanf */
 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     }
 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     }
 787     else
 788     {
 789         /* Common file size */
 790         if (!is_num (idx2))
 791             goto error;
 792 
 793         s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
 794 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 795         s->st_rdev = 0;
 796 #endif
 797     }
 798 
 799     vfs_zero_stat_times (s);
 800 
 801     idx = vfs_parse_filedate (idx, &s->st_mtime);
 802     if (idx == 0)
 803         goto error;
 804 
 805     /* Use resulting time value */
 806     s->st_atime = s->st_ctime = s->st_mtime;
 807 
 808     /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
 809 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
 810     s->st_blksize = 512;
 811 #endif
 812     vfs_adjust_stat (s);
 813 
 814     if (num_spaces != NULL)
 815     {
 816         *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
 817         if (DIR_IS_DOTDOT (columns[idx]))
 818             vfs_parse_ls_final_num_spaces = *num_spaces;
 819     }
 820 
 821     for (i = idx + 1, idx2 = 0; i < num_cols; i++)
 822         if (strcmp (columns[i], "->") == 0)
 823         {
 824             idx2 = i;
 825             break;
 826         }
 827 
 828     if (((S_ISLNK (s->st_mode) || (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     if (t != NULL)
 857     {
 858         size_t p2;
 859 
 860         p2 = strlen (t);
 861         if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
 862             t[p2] = '\0';
 863         if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
 864             t[p2] = '\0';
 865     }
 866 
 867     g_free (p_copy);
 868     return TRUE;
 869 
 870   error:
 871     {
 872         static int errorcount = 0;
 873 
 874         if (++errorcount < 5)
 875             message (D_ERROR, _("Cannot parse:"), "%s",
 876                      (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
 877         else if (errorcount == 5)
 878             message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored."));
 879     }
 880 
 881     g_free (p_copy);
 882     return FALSE;
 883 }
 884 
 885 /* --------------------------------------------------------------------------------------------- */

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