1 /*
2  * Copyright (C) 1999 Sasha Vasko <sasha at aftercode.net>
3  * merged with envvar.c originally created by :
4  * Copyright (C) 1999 Ethan Fischer <allanon@crystaltokyo.com>
5  * Copyright (C) 1998 Pierre Clerissi <pierre.clerissi@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #undef LOCAL_DEBUG
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <limits.h>
34 
35 #if HAVE_DIRENT_H
36 # include <dirent.h>
37 # define NAMLEN(dirent) strlen((dirent)->d_name)
38 #else
39 # if HAVE_SYS_DIRENT_H
40 #  include <sys/dirent.h>
41 #  define NAMLEN(dirent) strlen((dirent)->d_name)
42 # else
43 #  define dirent direct
44 #  define NAMLEN(dirent) (dirent)->d_namlen
45 #  if HAVE_SYS_NDIR_H
46 #   include <sys/ndir.h>
47 #  endif
48 #  if HAVE_SYS_DIR_H
49 #   include <sys/dir.h>
50 #  endif
51 #  if HAVE_NDIR_H
52 #   include <ndir.h>
53 #  endif
54 # endif
55 #endif
56 
57 /* Even if limits.h is included, allow PATH_MAX to sun unices */
58 #ifndef PATH_MAX
59 #define PATH_MAX 255
60 #endif
61 
62 
63 #include "astypes.h"
64 #include "mystring.h"
65 #include "safemalloc.h"
66 #include "fs.h"
67 #include "output.h"
68 #include "audit.h"
69 
70 
71 /*
72  * get the date stamp on a file
73  */
get_file_modified_time(const char * filename)74 time_t get_file_modified_time (const char *filename)
75 {
76 	struct stat   st;
77 	time_t        stamp = 0;
78 
79 	if (stat (filename, &st) != -1)
80 		stamp = st.st_mtime;
81 	return stamp;
82 }
83 
84 int
check_file_mode(const char * file,int mode)85 check_file_mode (const char *file, int mode)
86 {
87 	struct stat   st;
88 
89 	if ((stat (file, &st) == -1) || (st.st_mode & S_IFMT) != mode)
90 		return (-1);
91 	else
92 		return (0);
93 }
94 
95 /* copy file1 into file2 */
96 int
copy_file(const char * realfilename1,const char * realfilename2)97 copy_file (const char *realfilename1, const char *realfilename2)
98 {
99 	FILE         *targetfile, *sourcefile;
100 	int           c;
101 
102 #ifdef __CYGWIN__
103     targetfile = fopen (realfilename2, "wb");
104 #else
105     targetfile = fopen (realfilename2, "w");
106 #endif
107     if (targetfile == NULL)
108 	{
109 		fprintf (stderr, "can't open %s !\n", realfilename2);
110 		return (-1);
111 	}
112 #ifdef __CYGWIN__
113     sourcefile = fopen (realfilename1, "rb");
114 #else
115     sourcefile = fopen (realfilename1, "r");
116 #endif
117     if (sourcefile == NULL)
118 	{
119 		fprintf (stderr, "can't open %s !\n", realfilename1);
120 		fclose (targetfile);
121 		return (-2);
122 	}
123 	while ((c = getc (sourcefile)) != EOF)
124 		putc (c, targetfile);
125 
126 	fclose (targetfile);
127 	fclose (sourcefile);
128 	return 0;
129 }
130 
131 char*
load_binary_file(const char * realfilename,long * file_size_return)132 load_binary_file(const char* realfilename, long *file_size_return)
133 {
134 	struct stat st;
135 	FILE* fp;
136 	char* data = NULL ;
137 
138 	/* Get the file size. */
139 	if (stat(realfilename, &st)) return NULL;
140 	/* Open the file. */
141 	fp = fopen(realfilename, "rb");
142 	if ( fp != NULL )
143 	{
144 		long len ;
145 		/* Read in the file. */
146 		data = safemalloc(st.st_size + 1);
147 		len = fread(data, 1, st.st_size, fp);
148 		if( file_size_return )
149 			*file_size_return = len ;
150 		fclose(fp);
151 	}
152 	return data;
153 }
154 
155 char*
load_file(const char * realfilename)156 load_file(const char* realfilename)
157 {
158 	long len;
159 	char* str = load_binary_file( realfilename, &len );
160 
161 	if (str != NULL && len >= 0)
162 		str[len] = '\0';
163 
164 	return str;
165 }
166 
167 void
parse_file_name(const char * filename,char ** path,char ** file)168 parse_file_name(const char *filename, char **path, char **file)
169 {
170 	register int i = 0 ;
171 	register char *ptr = (char*)filename;
172 	int len = 0 ;
173 	while( ptr[i] ) ++i ;
174 	len = i ;
175 	while( --i >= 0 )
176 		if( ptr[i] == '/' )
177 			break;
178 	++i ;
179 	if( path )
180 		*path = mystrndup(ptr, i);
181 	if( file )
182 		*file = mystrndup(&(ptr[i]), len-i);
183 }
184 
185 char         *
add_file_extension(const char * file,const char * ext)186 add_file_extension (const char *file, const char *ext)
187 {
188 	char *res;
189 	int fname_len;
190 	if (file == NULL)
191 		return NULL;
192 	if (ext == NULL)
193 		return mystrdup (file);
194 	fname_len = strlen(file);
195 	res = safemalloc (fname_len+1+strlen(ext) + 1);
196 	strcpy (res, file);
197 	res[fname_len] = '.';
198 	strcpy (&res[fname_len+1], ext);
199 	return res;
200 }
201 
202 char         *
make_file_name(const char * path,const char * file)203 make_file_name (const char *path, const char *file)
204 {
205 	register int  i = 0;
206 	register char *ptr;
207 	char         *filename;
208 	int 		  len;
209 
210 	if( file == NULL )
211 	{
212 		if( path == NULL )
213 			return NULL;
214 		return mystrdup(path);
215 	}else if( path == NULL )
216 		return mystrdup(file);
217 	/* getting length */
218 	for (ptr = (char *)path; ptr[i]; i++);
219 	len = i+1;
220 	ptr = (char *)file ;
221 	for ( i = 0; ptr[i]; i++);
222 	len += i+1;
223 	ptr = filename = safemalloc (len);
224 	/* copying path */
225 	for (i = 0; path[i]; i++)
226 		ptr[i] = path[i];
227 	/* copying filename */
228 	ptr[i] = '/';
229 	ptr += i+1 ;
230 	for (i = 0; file[i]; i++)
231 		ptr[i] = file[i];
232 	ptr[i] = '\0';						   /* zero byte */
233 
234 	return filename;
235 }
236 
237 char         *
put_file_home(const char * path_with_home)238 put_file_home (const char *path_with_home)
239 {
240 	static char  *home = NULL;				   /* the HOME environment variable */
241 	static char   default_home[3] = "./";
242 	static int    home_len = 0;
243 	char         *str = NULL, *ptr;
244 	register int  i;
245 	if (path_with_home == NULL)
246 		return NULL;
247 	/* home dir ? */
248 	if ( strncmp(  path_with_home, "$HOME/", 6 ) == 0 )
249 		path_with_home += 5 ;
250 	else if (path_with_home[0] == '~' && path_with_home[1] == '/')
251 		path_with_home += 1 ;
252 	else
253 		return mystrdup(path_with_home);
254 
255 	if (home == NULL)
256 	{
257 		if ((home = getenv ("HOME")) == NULL)
258 			home = &(default_home[0]);
259 		home_len = strlen (home);
260 	}
261 
262 	for (i = 0; path_with_home[i]; i++);
263 	str = safemalloc (home_len + i + 1);
264 	for (ptr = str + home_len; i >= 0; i--)
265 		ptr[i] = path_with_home[i];
266 	for (i = 0; i < home_len; i++)
267 		str[i] = home[i];
268 	return str;
269 }
270 
271 
272 /****************************************************************************
273  *
274  * Find the specified icon file somewhere along the given path.
275  *
276  * There is a possible race condition here:  We check the file and later
277  * do something with it.  By then, the file might not be accessible.
278  * Oh well.
279  *
280  ****************************************************************************/
281 /* supposedly pathlist should not include any environment variables
282    including things like ~/
283  */
284 
285 char         *
find_file(const char * file,const char * pathlist,int type)286 find_file (const char *file, const char *pathlist, int type)
287 {
288 	char 		  *path;
289 	register int   len;
290 	int            max_path = 0;
291 	register char *ptr;
292 	register int   i;
293 	Bool local = False ;
294 LOCAL_DEBUG_CALLER_OUT( "file \"%s\", pathlist = \"%s\"", file, pathlist );
295 	if (file == NULL)
296 		return NULL;
297 
298 	if (*file == '/' || *file == '~' || ((pathlist == NULL) || (*pathlist == '\0')))
299 		local = True ;
300 	else if( file[0] == '.' && (file[1] == '/' || (file[1] == '.' && file[2] == '/')))
301 		local = True ;
302 	else if( strncmp( file, "$HOME", 5) == 0 )
303 		local = True ;
304 	if( local )
305 	{
306 		path = put_file_home (file);
307 		if ( access (path, type) == 0 )
308 		{
309 			return path;
310 		}
311 		free (path);
312 		return NULL;
313 	}
314 /*	return put_file_home(file); */
315 	for (i = 0; file[i]; ++i);
316 	len = i ;
317 	for (ptr = (char *)pathlist; *ptr; ptr += i)
318 	{
319 		if (*ptr == ':')
320 			ptr++;
321 		for (i = 0; ptr[i] && ptr[i] != ':'; i++);
322 		if (i > max_path)
323 			max_path = i;
324 	}
325 
326 	path = safecalloc (1, max_path + 1 + len + 1);
327 	strcpy( path+max_path+1, file );
328 	path[max_path] = '/' ;
329 
330 	ptr = (char*)&(pathlist[0]) ;
331 	while( ptr[0] != '\0' )
332 	{
333 		int skip ;
334 		for( i = 0 ; ptr[i] == ':' ; ++i );
335 		ptr += i ;
336 		for( i = 0 ; ptr[i] != ':' && ptr[i] != '\0' ; ++i );
337 		skip = i ;
338 		if( i > 0 && ptr[i-1] == '/' )
339 			i-- ;
340 		if( i > 0 )
341 		{
342 			register char *try_path = path+max_path-i;
343 			strncpy( try_path, ptr, i );
344 LOCAL_DEBUG_OUT( "errno = %d, file %s: checking path \"%s\"", errno, file, try_path );
345 			if ( access(try_path, type) == 0 )
346 			{
347 				char* res = mystrdup(try_path);
348 				free( path );
349 LOCAL_DEBUG_OUT( " found at: \"%s\"", res );
350 				return res;
351 			}
352 #ifdef LOCAL_DEBUG
353 			else
354 				show_system_error(" looking for file %s:", file );
355 #endif
356 		}
357 		ptr += skip ;
358 	}
359 	free (path);
360 	return NULL;
361 }
362 
363 static char *default_kdegnome_dir = "/usr" ;
364 static char *default_kdehome_dir = "~/.kde" ;
365 
366 static char         *
find_envvar(char * var_start,int * end_pos)367 find_envvar (char *var_start, int *end_pos)
368 {
369 	register int  i;
370 	static char tmp[256];
371 	char *result ;
372 
373 	if (var_start[0] == '{')
374 	{
375 		for (i = 1; var_start[i] && var_start[i] != '}' && i < 255; i++)
376 			tmp[i-1] = var_start[i] ;
377 		tmp[i-1] = '\0' ;
378 	} else
379 	{
380 		for (i = 0; (isalnum ((int)var_start[i]) || var_start[i] == '_') && i < 255; i++)
381 			tmp[i] = var_start[i] ;
382 		tmp[i] = '\0';
383 	}
384 	*end_pos = i;
385 	if (var_start[i] == '}')
386 		(*end_pos)++;
387 
388 	result = getenv (tmp);
389 	if( result == NULL )
390 	{
391 		if( strcmp( tmp, "KDEDIR" ) == 0 || strcmp( tmp, "GNOMEDIR" ) == 0 )
392 			result = default_kdegnome_dir ;
393 		else if( strcmp( tmp, "KDEHOME" ) == 0 )
394 			result = default_kdehome_dir ;
395 	}
396 	return result;
397 }
398 
399 static char *
do_replace_envvar(const char * path)400 do_replace_envvar (const char *path)
401 {
402 	char         *data = (char*)path, *tmp;
403 	char         *home = getenv ("HOME");
404 	int           pos = 0, len, home_len = 0;
405 
406 	if (path == NULL)
407 		return NULL;
408 	if (*path == '\0')
409 		return (char*)path;
410 	len = strlen (path);
411 	if (home)
412 		home_len = strlen (home);
413 
414 	while (*(data + pos))
415 	{
416 		char         *var;
417 		int           var_len, end_pos;
418 
419 		while (*(data + pos) != '$' && *(data + pos))
420 		{
421 			if (*(data + pos) == '~' && *(data + pos + 1) == '/')
422 			{
423 				if (pos > 0)
424 					if (*(data + pos - 1) != ':')
425 					{
426 						pos += 2;
427 						continue;
428 					}
429 				if (home == NULL)
430 					*(data + (pos++)) = '.';
431 				else
432 				{
433 					len += home_len;
434 					tmp = safemalloc (len);
435 					strncpy (tmp, data, pos);
436 					strcpy (tmp + pos, home);
437 					strcpy (tmp + pos + home_len, data + pos + 1);
438 					if( data != path )
439 						free (data);
440 					data = tmp;
441 					pos += home_len;
442 				}
443 			}
444 			pos++;
445 		}
446 		if (*(data + pos) == '\0')
447 			break;
448 		/* found $ sign - trying to replace var */
449 		if ((var = find_envvar (data + pos + 1, &end_pos)) == NULL)
450 		{
451 			++pos;
452 			continue;
453 		}
454 		var_len = strlen (var);
455 		len += var_len;
456 		tmp = safemalloc (len);
457 		strncpy (tmp, data, pos);
458 		strcpy (tmp + pos, var);
459 		strcpy (tmp + pos + var_len, data + pos + end_pos + 1);
460 		if( data != path )
461 			free (data);
462 		data = tmp;
463 	}
464 	return data;
465 }
466 
467 void
replace_envvar(char ** path)468 replace_envvar (char **path)
469 {
470 	char         *res = do_replace_envvar( *path );
471 	if( res != *path )
472 	{
473 		free( *path );
474 		*path = res ;
475 	}
476 }
477 
478 char*
copy_replace_envvar(const char * path)479 copy_replace_envvar (const char *path)
480 {
481 	char         *res = do_replace_envvar( path );
482 	return ( res == path )?mystrdup( res ):res;
483 }
484 
485 /*
486  * only checks first word in name, to allow full command lines with
487  * options to be passed
488  */
489 int
get_executable_in_path(const char * name,char ** fullname_return)490 get_executable_in_path (const char *name, char **fullname_return)
491 {
492 	static char  *cache = NULL;
493 	static char  *cache_path = NULL;
494 	static int    cache_result = 0, cache_len = 0, cache_size = 0;
495 	static char  *env_path = NULL;
496 	static int    max_path = 0;
497 	register int  i;
498 
499 	if (name == NULL)
500 	{
501 		if (cache)
502 		{
503 			free (cache);
504 			cache = NULL;
505 		}
506 		if (cache_path)
507 		{
508 			free (cache_path);
509 			cache_path = NULL;
510 		}
511 		cache_size = 0;
512 		cache_len = 0;
513 		if (env_path)
514 		{
515 			free (env_path);
516 			env_path = NULL;
517 		}
518 		max_path = 0;
519 		return 0;
520 	}
521 
522 	/* cut leading "exec" enclosed in spaces */
523 	for (; isspace ((int)*name); name++);
524 	if (!mystrncasecmp(name, "exec", 4) && isspace ((int)name[4]))
525 		name += 4;
526 	for (; isspace ((int)*name); name++);
527 	if (*name == '\0')
528 		return 0;
529 
530 	for (i = 0; name[i] && !isspace ((int)name[i]); i++);
531 	if (i == 0)
532 		return 0;
533 
534 	if (cache)
535 		if (i == cache_len && strncmp (cache, name, i) == 0)
536 		{
537 			if (cache_result && fullname_return)
538 				*fullname_return = mystrdup(cache_path);
539 			return cache_result;
540 		}
541 
542 	if (i > cache_size)
543 	{
544 		if (cache)
545 			free (cache);
546 		/* allocating slightly more space then needed to avoid
547 		   too many reallocations */
548 		cache = (char *)safemalloc (i + (i >> 1) + 1);
549 		cache_size = i + (i >> 1);
550 	}
551 	strncpy (cache, name, i);
552 	cache[i] = '\0';
553 	cache_len = i;
554 	if (cache_path)
555 	{
556 		free(cache_path);
557 		cache_path = NULL;
558 	}
559 
560 	if (*cache == '/')
561 	{
562 		cache_result = (CheckFile (cache) == 0) ? 1 : 0;
563 		cache_path = mystrdup (cache);
564 	}else
565 	{
566 		char         *ptr, *path;
567 		struct stat   st;
568 
569 		if (env_path == NULL)
570 		{
571 			env_path = mystrdup (getenv ("PATH"));
572 			replace_envvar (&env_path);
573 			for (ptr = env_path; *ptr; ptr += i)
574 			{
575 				if (*ptr == ':')
576 					ptr++;
577 				for (i = 0; ptr[i] && ptr[i] != ':'; i++);
578 				if (i > max_path)
579 					max_path = i;
580 			}
581 		}
582 		path = safemalloc (max_path + cache_len + 2);
583 		cache_result = 0;
584 		for (ptr = env_path; *ptr ; ptr += i)
585 		{
586 			if (*ptr == ':')
587 				ptr++;
588 			for (i = 0; ptr[i] && ptr[i] != ':'; i++)
589 				path[i] = ptr[i];
590 			path[i] = '/';
591 			path[i + 1] = '\0';
592 			strcat (path, cache);
593 			if ((stat (path, &st) != -1) && (st.st_mode & S_IXUSR))
594 			{
595 				cache_result = 1;
596 				cache_path = path;
597 				path = NULL;
598 				break;
599 			}
600 			LOCAL_DEBUG_OUT( "%s found \"%s\"", path, cache_result?"":"not" );
601 		}
602 		if (path)
603 			free (path);
604 	}
605 
606 	if (cache_result && fullname_return)
607 		*fullname_return = mystrdup(cache_path);
608 	return cache_result;
609 }
610 
611 int
is_executable_in_path(const char * name)612 is_executable_in_path (const char *name)
613 {
614 	return get_executable_in_path (name, NULL);
615 }
616 
617 
618 
619 int
my_scandir_ext(const char * dirname,int (* filter_func)(const char *),Bool (* handle_direntry_func)(const char * fname,const char * fullname,struct stat * stat_info,void * aux_data),void * aux_data)620 my_scandir_ext ( const char *dirname, int (*filter_func) (const char *),
621 				 Bool (*handle_direntry_func)( const char *fname, const char *fullname, struct stat *stat_info, void *aux_data),
622 				 void *aux_data)
623 {
624 	DIR          *d;
625 	struct dirent *e;						   /* Pointer to static struct inside readdir() */
626 	int           n = 0;					   /* Count of nl used so far */
627 	char         *filename;					   /* For building filename to pass to stat */
628 	char         *p;						   /* Place where filename starts */
629 	struct stat   stat_info;
630 
631 	d = opendir (dirname);
632 
633 	if (d == NULL)
634 		return -1;
635 
636 	filename = (char *)safemalloc (strlen (dirname) + PATH_MAX + 2);
637 	if (filename == NULL)
638 	{
639 		closedir (d);
640 		return -1;
641 	}
642 	strcpy (filename, dirname);
643 	p = filename + strlen (filename);
644 	if( *p != '/' )
645 	{
646 		*p++ = '/';
647 		*p = 0;									   /* Just in case... */
648 	}
649 
650 	while ((e = readdir (d)) != NULL)
651 	{
652 		if ((filter_func == NULL) || filter_func (&(e->d_name[0])))
653 		{
654 			/* Fill in the fields using stat() */
655 			strcpy (p, e->d_name);
656 			if (stat (filename, &stat_info) != -1)
657 			{
658 				if( handle_direntry_func( e->d_name, filename, &stat_info, aux_data) )
659 					n++;
660 			}
661 		}
662 	}
663 	free (filename);
664 
665 	if (closedir (d) == -1)
666 		return -1;
667 	/* Return the count of the entries */
668 	return n;
669 }
670 
671 
672 /*
673  * Non-NULL select and dcomp pointers are *NOT* tested, but should be OK.
674  * They are not used by afterstep however, so this implementation should
675  * be good enough.
676  *
677  * c.ridd@isode.com
678  */
679 /* essentially duplicates whats above,
680  * but for performance sake we don't want to merge them together :*/
681 
682 /* sort entries based on their type; directories come first */
683 int
direntry_compar_type(const struct direntry ** d1,const struct direntry ** d2)684 direntry_compar_type (const struct direntry ** d1, const struct direntry ** d2)
685 {
686 
687 	return S_ISDIR ((**d2).d_mode) - S_ISDIR ((**d1).d_mode);
688 }
689 
690 /* sort entries based on their names; A comes before Z */
691 int
direntry_compar_alpha(const struct direntry ** d1,const struct direntry ** d2)692 direntry_compar_alpha (const struct direntry ** d1, const struct direntry ** d2)
693 {
694 	return strcmp ((**d1).d_name, (**d2).d_name);
695 }
696 
697 int
direntry_compar_type_alpha(const struct direntry ** d1,const struct direntry ** d2)698 direntry_compar_type_alpha (const struct direntry ** d1, const struct direntry ** d2)
699 {
700 	int d = (S_ISDIR ((**d2).d_mode) - S_ISDIR ((**d1).d_mode)) ;
701 	if( d == 0 )
702 		return strcmp ((**d1).d_name, (**d2).d_name);
703 	return d;
704 }
705 
706 /* sort entries based on their mtimes; old entries before new entries */
707 int
direntry_compar_mtime(const struct direntry ** d1,const struct direntry ** d2)708 direntry_compar_mtime (const struct direntry ** d1, const struct direntry ** d2)
709 {
710 	return (**d1).d_mtime - (**d2).d_mtime;
711 }
712 
713 int
direntry_compar_size(const struct direntry ** d1,const struct direntry ** d2)714 direntry_compar_size (const struct direntry ** d1, const struct direntry ** d2)
715 {
716 	return (**d1).d_size - (**d2).d_size;
717 }
718 
719 
720 int
my_scandir(char * dirname,struct direntry * (* namelist[]),int (* filter_func)(const char *),my_sort_f dcomp)721 my_scandir (char *dirname, struct direntry *(*namelist[]),
722 			int (*filter_func) (const char *), my_sort_f dcomp)
723 {
724 	DIR          *d;
725 	struct dirent *e;						   /* Pointer to static struct inside readdir() */
726 	struct direntry **nl;					   /* Array of pointers to dirents */
727 	struct direntry **nnl;
728 	int           n;						   /* Count of nl used so far */
729 	int           sizenl;					   /* Number of entries in nl array */
730 	int           j;
731 	char         *filename;					   /* For building filename to pass to stat */
732 	char         *p;						   /* Place where filename starts */
733 	struct stat   buf;
734 
735 	*namelist = NULL ;
736 
737 	d = opendir (dirname);
738 
739 	if (d == NULL)
740 		return -1;
741 
742 	filename = (char *)safemalloc (strlen (dirname) + PATH_MAX + 2);
743 	if (filename == NULL)
744 	{
745 		closedir (d);
746 		return -1;
747 	}
748 	strcpy (filename, dirname);
749 	p = filename + strlen (filename);
750 	if( *p != '/' )
751 	{
752 		*p++ = '/';
753 		*p = 0;									   /* Just in case... */
754 	}
755 
756 	nl = NULL;
757 	n = 0;
758 	sizenl = 0;
759 
760 	while ((e = readdir (d)) != NULL)
761 	{
762 		if ((filter_func == NULL) || filter_func (&(e->d_name[0])))
763 		{
764 			/* add */
765 			if (sizenl == n)
766 			{
767 				/* Grow array */
768 				sizenl += 32;				   /* arbitrary delta */
769 				nnl = realloc (nl, sizenl * sizeof (struct direntry *));
770 				if (nnl == NULL)
771 				{
772 					/* Free the old array */
773 					for (j = 0; j < n; j++)
774 						free (nl[j]);
775 					free (nl);
776 					free (filename);
777 					closedir (d);
778 					return -1;
779 				}
780 				nl = nnl;
781 			}
782 			/* Fill in the fields using stat() */
783 			strcpy (p, e->d_name);
784 			if (stat (filename, &buf) != -1)
785 			{
786 				size_t realsize = offsetof (struct direntry, d_name)+strlen (e->d_name) + 1;
787 				nl[n] = (struct direntry *)safemalloc (realsize);
788 				nl[n]->d_mode = buf.st_mode;
789 				nl[n]->d_mtime = buf.st_mtime;
790 				nl[n]->d_size  = buf.st_size;
791 				strcpy (nl[n]->d_name, e->d_name);
792 				n++;
793 			}
794 		}
795 	}
796 	free (filename);
797 
798 	if (closedir (d) == -1)
799 	{
800 		free (nl);
801 		return -1;
802 	}
803 	if (n == 0)
804 	{
805 		if (nl)
806 			free (nl);
807 /* OK, but not point sorting or freeing anything */
808 		return 0;
809 	}
810 	*namelist = realloc (nl, n * sizeof (struct direntry *));
811 
812 	if (*namelist == NULL)
813 	{
814 		for (j = 0; j < n; j++)
815 			free (nl[j]);
816 		free (nl);
817 		return -1;
818 	}
819 	/* Optionally sort the list */
820 	if (dcomp)
821 		qsort (*namelist, n, sizeof (struct direntry *), (int (*)())dcomp);
822 
823 	/* Return the count of the entries */
824 	return n;
825 }
826 
827 /*
828  * Use this function as the filter_func argument to my_scandir to make it ignore
829  * all files and directories starting with "."
830  */
831 int
ignore_dots(const char * d_name)832 ignore_dots (const char *d_name)
833 {
834 	return (d_name[0] != '.');
835 }
836 
837 int
no_dots_except_include(const char * d_name)838 no_dots_except_include (const char *d_name)
839 {
840 	if( d_name[0] != '.' || mystrcasecmp (d_name, ".include") == 0 )
841 	{
842 		register  int i = 0;
843 		while( d_name[i] != '\0' ) ++i ;
844 		return (i > 0 && d_name[i-1] != '~');
845 	}
846 	return False;
847 }
848 
849 int
no_dots_except_directory(const char * d_name)850 no_dots_except_directory (const char *d_name)
851 {
852 	if( d_name[0] != '.' || mystrcasecmp (d_name, ".directory") == 0 )
853 	{
854 		register  int i = 0;
855 		while( d_name[i] != '\0' ) ++i ;
856 		return (i > 0 && d_name[i-1] != '~');
857 	}
858 	return False;
859 }
860 
861 
862