Home | History | Annotate | Download | only in squashfs-tools
      1 /*
      2  * Create a squashfs filesystem.  This is a highly compressed read only
      3  * filesystem.
      4  *
      5  * Copyright (c) 2012
      6  * Phillip Lougher <phillip (at) squashfs.org.uk>
      7  *
      8  * This program is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU General Public License
     10  * as published by the Free Software Foundation; either version 2,
     11  * or (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     21  *
     22  * read_file.c
     23  */
     24 
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <ctype.h>
     29 #include <errno.h>
     30 
     31 #include "error.h"
     32 
     33 #define TRUE 1
     34 #define FALSE 0
     35 #define MAX_LINE 16384
     36 
     37 /*
     38  * Read file, passing each line to parse_line() for
     39  * parsing.
     40  *
     41  * Lines can be split across multiple lines using "\".
     42  *
     43  * Blank lines and comment lines indicated by # are supported.
     44  */
     45 int read_file(char *filename, char *type, int (parse_line)(char *))
     46 {
     47 	FILE *fd;
     48 	char *def, *err, *line = NULL;
     49 	int res, size = 0;
     50 
     51 	fd = fopen(filename, "r");
     52 	if(fd == NULL) {
     53 		ERROR("Could not open %s device file \"%s\" because %s\n",
     54 			type, filename, strerror(errno));
     55 		return FALSE;
     56 	}
     57 
     58 	while(1) {
     59 		int total = 0;
     60 
     61 		while(1) {
     62 			int len;
     63 
     64 			if(total + (MAX_LINE + 1) > size) {
     65 				line = realloc(line, size += (MAX_LINE + 1));
     66 				if(line == NULL)
     67 					MEM_ERROR();
     68 			}
     69 
     70 			err = fgets(line + total, MAX_LINE + 1, fd);
     71 			if(err == NULL)
     72 				break;
     73 
     74 			len = strlen(line + total);
     75 			total += len;
     76 
     77 			if(len == MAX_LINE && line[total - 1] != '\n') {
     78 				/* line too large */
     79 				ERROR("Line too long when reading "
     80 					"%s file \"%s\", larger than "
     81 					"%d bytes\n", type, filename, MAX_LINE);
     82 				goto failed;
     83 			}
     84 
     85 			/*
     86 			 * Remove '\n' terminator if it exists (the last line
     87 			 * in the file may not be '\n' terminated)
     88 			 */
     89 			if(len && line[total - 1] == '\n') {
     90 				line[-- total] = '\0';
     91 				len --;
     92 			}
     93 
     94 			/*
     95 			 * If no line continuation then jump out to
     96 			 * process line.  Note, we have to be careful to
     97 			 * check for "\\" (backslashed backslash) and to
     98 			 * ensure we don't look at the previous line
     99 			 */
    100 			if(len == 0 || line[total - 1] != '\\' || (len >= 2 &&
    101 					strcmp(line + total - 2, "\\\\") == 0))
    102 				break;
    103 			else
    104 				total --;
    105 		}
    106 
    107 		if(err == NULL) {
    108 			if(ferror(fd)) {
    109                 		ERROR("Reading %s file \"%s\" failed "
    110 					"because %s\n", type, filename,
    111 					strerror(errno));
    112 				goto failed;
    113 			}
    114 
    115 			/*
    116 			 * At EOF, normally we'll be finished, but, have to
    117 			 * check for special case where we had "\" line
    118 			 * continuation and then hit EOF immediately afterwards
    119 			 */
    120 			if(total == 0)
    121 				break;
    122 			else
    123 				line[total] = '\0';
    124 		}
    125 
    126 		/* Skip any leading whitespace */
    127 		for(def = line; isspace(*def); def ++);
    128 
    129 		/* if line is now empty after skipping characters, skip it */
    130 		if(*def == '\0')
    131 			continue;
    132 
    133 		/* if comment line, skip */
    134 		if(*def == '#')
    135 			continue;
    136 
    137 		res = parse_line(def);
    138 		if(res == FALSE)
    139 			goto failed;
    140 	}
    141 
    142 	fclose(fd);
    143 	free(line);
    144 	return TRUE;
    145 
    146 failed:
    147 	fclose(fd);
    148 	free(line);
    149 	return FALSE;
    150 }
    151