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

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