"Fossies" - the Fresh Open Source Software Archive

Member "sitecopy-0.16.6/src/lsparser.c" (24 Oct 2005, 7043 Bytes) of archive /linux/www/sitecopy-0.16.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lsparser.c" see the Fossies "Dox" file reference documentation.

    1 /* 
    2    'ls' output parser, for rsh and ftp drivers
    3    Copyright (C) 1998-2005, Joe Orton <joe@manyfish.co.uk>
    4                                                                      
    5    This program is free software; you can redistribute it and/or modify
    6    it under the terms of the GNU General Public License as published by
    7    the Free Software Foundation; either version 2 of the License, or
    8    (at your option) any later version.
    9   
   10    This program is distributed in the hope that it will be useful,
   11    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13    GNU General Public License for more details.
   14   
   15    You should have received a copy of the GNU General Public License
   16    along with this program; if not, write to the Free Software
   17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
   18 
   19 */
   20 
   21 #include "config.h"
   22 
   23 #include <stdlib.h>
   24 #include <ctype.h>
   25 #include <string.h>
   26 
   27 #include <ne_string.h>
   28 #include <ne_alloc.h>
   29 #include <ne_utils.h>
   30 
   31 #include "common.h"
   32 #include "lsparser.h"
   33 
   34 struct ls_context {
   35     int after_blank;
   36     char *topdir;
   37     char *curdir;
   38     const char *error;
   39 };
   40 
   41 ls_context_t *ls_init(const char *dir)
   42 {
   43     ls_context_t *ctx = ne_malloc(sizeof *ctx);
   44     char *ptr;
   45 
   46     ctx->after_blank = 0;
   47     ctx->curdir = ne_strdup("");
   48     ctx->topdir = ne_strdup(dir);
   49 
   50     ptr = ctx->topdir + strlen(ctx->topdir) - 1;
   51     if (*ptr == '/') *ptr = '\0';
   52 
   53     NE_DEBUG(DEBUG_FTP, "ls: init, topdir: [%s]\n", ctx->topdir);
   54     
   55     return ctx;
   56 }
   57 
   58 void ls_destroy(ls_context_t *ctx)
   59 {
   60     ne_free(ctx->curdir);
   61     ne_free(ctx->topdir);
   62     ne_free(ctx);
   63 }
   64 
   65 /* Parse LINE of length LEN as a directory line. */
   66 static enum ls_result parse_directory(ls_context_t *ctx, char *line, size_t len)
   67 {
   68     /* A new directory name indicator, which goes:
   69      *    `directory/name/here:'
   70      * We want directory names as:
   71      *    `directory/name/here/' 
   72      * Hence a bit of messing about. */
   73     ne_free(ctx->curdir);
   74     
   75     /* Skip a leading Windows drive specification */
   76     if (len > 3 &&
   77         isalpha(line[0]) && line[1] == ':' && line[2] == '/') {
   78         line += 2;
   79     }
   80     
   81     if (strncmp(line, ctx->topdir, strlen(ctx->topdir)) == 0) {
   82         line += strlen(ctx->topdir);
   83     }
   84     
   85     /* Skip a single . if .:  */
   86     if (strcmp(line,".:") == 0) {
   87         line++;
   88     }
   89     
   90     /* Skip a leading "./" */
   91     if (strncmp(line, "./", 2) == 0) {
   92         line += 2;
   93     }
   94     
   95     /* Skip repeated '/' characters */
   96     while (*line == '/') line++;
   97     
   98     line = ne_strdup(line);
   99     len = strlen(line);
  100     
  101     if (len > 1) {
  102         line[len-1] = '/';  /* change ':' to '/' */
  103     } else {
  104         /* this is just the top-level directory... */
  105         line[0] = '\0';
  106     }
  107     
  108     ctx->curdir = line;
  109     NE_DEBUG(DEBUG_FTP, "ls: Now in directory: [%s]\n", ctx->curdir);
  110     return ls_nothing;
  111 }
  112 
  113 static inline char *skip_field(char *line)
  114 {
  115     while (*line != '\0' && *line != ' ')
  116         line++;
  117     
  118     while (*line != '\0' && *line == ' ')
  119         line++;
  120     
  121     return line;
  122 }
  123 
  124 /* Return mode bits for permissions string PERMS */
  125 static mode_t parse_permissions(const char *perms)
  126 {
  127     mode_t ret = 0;
  128     const char *p = perms;
  129     while (*p) {
  130     ret <<= 1;
  131     if (*p != '-') {
  132         ret |= 1;
  133         }
  134         p++;
  135     }
  136     return ret & 0777;
  137 }
  138 
  139 static enum ls_result fail(ls_context_t *ctx, const char *errstr)
  140 {
  141     ctx->error = errstr;
  142     return ls_error;
  143 }
  144 
  145 /* Parse LINE of length LEN as a "file" line, placing result in *FILE */
  146 static enum ls_result parse_file(ls_context_t *ctx, char *line, size_t len,
  147                                  struct ls_file *file)
  148 {
  149     char *perms, *size;
  150 
  151     perms = ne_token(&line, ' ');
  152     if (!line) return fail(ctx, "Missing token at beginning of line");
  153     while (*line++ == ' ') /* nullop */;
  154  
  155     /* skip inode, user and group fields */
  156     line = skip_field(skip_field(skip_field(line)));
  157     if (*line == '\0') {
  158         return fail(ctx, "Missing token in inode/user/group fields");
  159     }
  160 
  161     size = ne_token(&line, ' ');
  162     if (!line) {
  163         return fail(ctx, "Missing token after inode/user/group fields");
  164     }
  165     while (*line++ == ' ') /* nullop */;
  166 
  167     /* skip Month, day, time fields */
  168     line = skip_field(skip_field(skip_field(line)));
  169     if (*line == '\0') {
  170         return fail(ctx, "Missing token after timestamp field");
  171     }
  172  
  173     /* Bail out if this isn't a file or directory. */
  174     if (perms[0] != '-' && perms[0] != 'd') {
  175         NE_DEBUG(DEBUG_FTP, "ls: ignored line\n");
  176         return ls_nothing;
  177     }
  178 
  179     /* line now points at the last field, the filename.  Reject any
  180      * relative filenames. */
  181     if (strchr(line, '/') != NULL) {
  182         return fail(ctx, "Relative filename disallowed");
  183     }
  184 
  185     if (perms[0] == '-') {
  186         /* Normal file */
  187         file->mode = parse_permissions(perms);
  188         file->name = ne_concat(ctx->curdir, line, NULL);
  189         file->size = strtol(size, NULL, 10);
  190         NE_DEBUG(DEBUG_FTP, "ls: file (%03o, %" NE_FMT_OFF_T "): [%s]\n",
  191                  file->mode, file->size, file->name);
  192         return ls_file;
  193     } else /* perms[0] == 'd' */ {
  194         if (strcmp(line, ".") == 0 || strcmp(line, "..") == 0) {
  195             return ls_nothing;
  196         }
  197         file->mode = parse_permissions(perms);
  198         file->name = ne_concat(ctx->curdir, line, NULL);
  199         NE_DEBUG(DEBUG_FTP, "ls: directory (%03o): %s\n", file->mode, file->name);
  200         return ls_directory;
  201     }
  202 }
  203 
  204 enum ls_result ls_parse(ls_context_t *ctx, char *line, struct ls_file *file)
  205 {
  206     size_t len;
  207 
  208     line = ne_shave(line, "\r\n\t ");
  209     len = strlen(line);
  210 
  211     NE_DEBUG(DEBUG_FTP, "ls: [%s]\n", line);
  212 
  213     if (len == 0) {
  214         ctx->after_blank = 1;
  215         return ls_nothing;
  216     }
  217 
  218     ctx->after_blank = 0;
  219 
  220     if (strncmp(line, "total ", 6) == 0) {
  221         /* ignore the line */
  222         return ls_nothing;
  223     }
  224 
  225     if (line[len-1] == ':' && (ctx->after_blank || strchr(line, ' ') == NULL)) {
  226         return parse_directory(ctx, line, len);        
  227     } else {
  228         return parse_file(ctx, line, len, file);
  229     }
  230 }
  231 
  232 const char *ls_geterror(ls_context_t *ctx)
  233 {
  234     return ctx->error;
  235 }
  236 
  237 void ls_pflist_add(struct proto_file **list, struct proto_file **tail,
  238                    const struct ls_file *lsf, enum ls_result result)
  239 {
  240     struct proto_file *pf = ne_calloc(sizeof *pf);
  241 
  242     switch (result) {
  243     case ls_file:
  244         pf->filename = lsf->name;
  245         pf->mode = lsf->mode;
  246         pf->type = proto_file;
  247         pf->size = lsf->size;
  248         
  249         pf->next = *list;
  250         *list = pf;
  251         if (*tail == NULL) *tail = pf;
  252         break;
  253 
  254     case ls_directory:
  255         pf->filename = lsf->name;
  256         pf->mode = lsf->mode;
  257         pf->type = proto_dir;
  258         
  259         if (*tail == NULL) {
  260             *list = pf;
  261         } else {
  262             (*tail)->next = pf;
  263         }
  264         *tail = pf;
  265         break;
  266 
  267     default:
  268         ne_free(pf);
  269         break;
  270     }
  271 }