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

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