1 
2 /* globber.c */
3 /*
4    Copyright 2000-2001 Edscott Wilson Garcia
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program;  */
18 
19 /*****************************************************************/
20 
21 #include "fgr-globber.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <glob.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <sys/signal.h>
33 #include <time.h>
34 #include <sys/types.h>
35 #include <dirent.h>
36 
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40 
41 #ifdef DMALLOC
42 # include "dmalloc.h"
43 // exit(1) taken care of below.
44 #endif
45 
46 /** tripas **/
47 /* private */
48 #ifndef GLOB_TILDE
49 # define GLOB_TILDE 0x0
50 #endif
51 #ifndef GLOB_ONLYDIR
52 # define GLOB_ONLYDIR 0x0
53 #endif
54 
55 #define MONTH_T 2628000
56 #define DAY_T 86400
57 #define HOUR_T 3600
58 #define MIN_T 60
59 
60 typedef struct objeto_globber {
61     int options;
62     int type;
63     int user;
64     int group;
65     off_t sizeG;
66     off_t sizeL;
67     long unsigned month_t;
68     long unsigned day_t;
69     long unsigned hour_t;
70     long unsigned min_t;
71 /* private variables, not to be duplicated on recursion: */
72     struct stat st;
73     int pass;
74     time_t tiempo;
75     time_t actual;
76     int dostat;
77 } objeto_globber;
78 
79 static int
display(char * input)80 display (char *input) {
81     printf ("%s\n", input);     /*fflush(stdout); */
82     return 0;
83 }
84 
85 /* public */
86 int
glob_clear_options(void * address)87 glob_clear_options (void *address) {
88     if (!address) return 1;
89     objeto_globber *objeto = address;
90     memset(objeto, 0, sizeof(objeto_globber));
91     objeto->user = -1;
92     objeto->group = -1;
93     objeto->sizeL = -1;
94     objeto->sizeG = -1;
95     objeto->min_t = -1;
96     objeto->hour_t = -1;
97     objeto->day_t = -1;
98     objeto->month_t = -1;
99     return 1;
100 }
101 
102 void *
globber_create(void)103 globber_create (void) {
104     objeto_globber *objeto;
105     objeto = (objeto_globber *) malloc (sizeof (objeto_globber));
106     if (!objeto) {
107 	fprintf(stderr, "Unable to malloc basic structure.\n");
108 	exit(1);
109     }
110     glob_clear_options ((void *)objeto);
111     return (void *)objeto;
112 }
113 
114 void *
globber_destroy(void * address)115 globber_destroy (void *address) {
116     if(address)
117         free (address);
118     return NULL;
119 }
120 
121 int
glob_set_options(void * address,int options)122 glob_set_options (void *address, int options) {
123     if (!address){
124 	fprintf(stderr, "broken call to glob_set_options()\n");
125 	exit(0);
126     }
127     objeto_globber *objeto = address;
128     objeto->options |= options;
129     return 1;
130 }
131 
132 int
glob_set_type(void * address,int type)133 glob_set_type (void *address, int type) {
134     if (!address){
135 	fprintf(stderr, "broken call to glob_set_type()\n");
136 	exit(0);
137     }
138     objeto_globber *objeto = address;
139     objeto->type = type;
140     return 1;
141 }
142 
143 int
glob_set_sizeG(void * address,off_t size)144 glob_set_sizeG (void *address, off_t size) {
145     if (!address){
146 	fprintf(stderr, "broken call to glob_set_sizeG()\n");
147 	exit(0);
148     }
149     objeto_globber *objeto = address;
150     glob_set_options (objeto, GLOBBER_SIZE);
151     objeto->sizeG = size;
152     return 1;
153 }
154 
155 int
glob_set_sizeL(void * address,off_t size)156 glob_set_sizeL (void *address, off_t size) {
157     if (!address){
158 	fprintf(stderr, "broken call to glob_set_sizeL()\n");
159 	exit(0);
160     }
161     objeto_globber *objeto = address;
162     glob_set_options (objeto, GLOBBER_SIZE);
163     objeto->sizeL = size;
164     return 1;
165 }
166 
167 int
glob_set_user(void * address,int user)168 glob_set_user (void *address, int user) {
169     if (!address){
170 	fprintf(stderr, "broken call to glob_set_user()\n");
171 	exit(0);
172     }
173     objeto_globber *objeto = address;
174     glob_set_options (objeto, GLOBBER_USER);
175     objeto->user = user;
176     return 1;
177 }
178 
179 int
glob_set_group(void * address,int group)180 glob_set_group (void *address, int group) {
181     if (!address){
182 	fprintf(stderr, "broken call to glob_set_group()\n");
183 	exit(0);
184     }
185     objeto_globber *objeto = address;
186     ;
187     glob_set_options (objeto, GLOBBER_GROUP);
188     objeto->group = group;
189     return 1;
190 }
191 
192 int
glob_set_minutes(void * address,long unsigned min_t)193 glob_set_minutes (void *address, long unsigned min_t) {
194     if (!address){
195 	fprintf(stderr, "broken call to glob_set_time()\n");
196 	exit(0);
197     }
198     objeto_globber *objeto = address;
199     objeto->min_t = min_t;
200     return 1;
201 }
202 
203 int
glob_set_hours(void * address,long unsigned hour_t)204 glob_set_hours (void *address, long unsigned hour_t) {
205     if (!address){
206 	fprintf(stderr, "broken call to glob_set_time()\n");
207 	exit(0);
208     }
209     objeto_globber *objeto = address;
210     objeto->hour_t = hour_t;
211     return 1;
212 }
213 
214 int
glob_set_days(void * address,long unsigned day_t)215 glob_set_days (void *address,long unsigned day_t) {
216     if (!address){
217 	fprintf(stderr, "broken call to glob_set_time()\n");
218 	exit(0);
219     }
220     objeto_globber *objeto = address;
221     objeto->day_t = day_t;
222     return 1;
223 }
224 
225 int
glob_set_months(void * address,long unsigned month_t)226 glob_set_months (void *address, long unsigned month_t) {
227     if (!address){
228 	fprintf(stderr, "broken call to glob_set_time()\n");
229 	exit(0);
230     }
231     objeto_globber *objeto = address;
232     objeto->month_t = month_t;
233     return 1;
234 }
235 
236 /* if the user defined "operate" function returns TRUE, Globber will exit
237  * and return to calling module with the same return value  */
238 
239 int
globber(void * address,char * path,int (* operate)(char *),char * filter)240 globber (void *address, char *path, int (*operate) (char *), char *filter) {
241     /* these variables must be kept on the heap */
242     glob_t dirlist;
243     int i;
244     char *globstring,
245      *dot_filter = NULL,
246         *actual_filter = NULL;
247     objeto_globber *object;
248     struct stat path_st;
249     errno=0;
250   /*  if (!path || !strlen(path)) {
251         fprintf(stderr, "invalid path: %s\n", path?"\"\"":"NULL");
252         return -1;
253     }*/
254     if(!address)
255         object = (objeto_globber *) globber_create ();
256     else
257         object = (objeto_globber *) address;
258 
259 // this is debug rather than verbose...
260 // if (object->options & GLOBBER_VERBOSE) fprintf(stderr, "---> %s\n", path);
261     if(object->options & GLOBBER_TIME) {
262         if(object->options & GLOBBER_MTIME)
263             object->options &= ((GLOBBER_CTIME | GLOBBER_ATIME) ^ 0xffffffff);
264         else if(object->options & GLOBBER_CTIME)
265             object->options &= (GLOBBER_ATIME ^ 0xffffffff);
266     }
267 
268     dirlist.gl_offs = 2;
269     if(!operate)
270         operate = display;
271     actual_filter = filter;
272   filter_repeat:
273 
274     if(actual_filter) {
275         globstring = (char *)malloc (strlen (path) + strlen (actual_filter) + 2);
276 	if (!globstring){fprintf(stderr,"malloc: %s", strerror(errno)); exit(1);}
277         strcpy (globstring, path);
278         if(path[strlen (path) - 1] != '/')
279             strcat (globstring, "/");
280         strcat (globstring, actual_filter);
281     } else
282         globstring = path;
283 
284     // If file cannot be stat(), assume it is not there (whatever).
285     // coverity[fs_check_call : FALSE]
286     if(stat (path, &path_st) < 0) {
287         fprintf(stderr, "%s: %s\n", path, strerror (errno));
288         int pass = object->pass;
289         if (!address) free(object);
290         if (actual_filter) free(globstring);
291         return (pass);
292     }
293     if(glob (globstring, GLOB_ERR | GLOB_TILDE, NULL, &dirlist) != 0) {
294 // this is debug rather than verbose...
295 //    if (object->options & GLOBBER_VERBOSE)
296 //      fprintf(stderr, "%s: %s\n", globstring,strerror(ENOENT));
297     } else {
298         for(i = 0; i < dirlist.gl_pathc; i++) {
299             if((object->options & GLOBBER_STAT) && lstat (dirlist.gl_pathv[i], &(object->st))>=0) {
300                 if(object->options & GLOBBER_USER) {
301                     if(object->user != object->st.st_uid)
302                         continue;
303                 }
304                 if(object->options & GLOBBER_GROUP) {
305                     if(object->group != object->st.st_gid)
306                         continue;
307                 }
308                 if(object->options & GLOBBER_TIME) {
309                     object->actual = time (NULL);
310                     if(object->options & GLOBBER_MTIME)
311                         object->tiempo = object->st.st_mtime;
312                     if(object->options & GLOBBER_ATIME)
313                         object->tiempo = object->st.st_atime;
314                     if(object->options & GLOBBER_CTIME)
315                         object->tiempo = object->st.st_ctime;
316 
317                     if((object->min_t > 0) && ((object->actual - object->tiempo) / MIN_T > object->min_t))
318                         continue;
319                     if((object->hour_t > 0) && ((object->actual - object->tiempo) / HOUR_T > object->hour_t))
320                         continue;
321                     if((object->day_t > 0) && ((object->actual - object->tiempo) / DAY_T > object->day_t))
322                         continue;
323 
324                     if((object->month_t > 0) && ((object->actual - object->tiempo) / MONTH_T > object->month_t))
325                         continue;
326 
327 
328                 }
329                 if(object->options & GLOBBER_SIZE) {
330                     if((object->sizeL >= 0) && (object->st.st_size > object->sizeL))
331                         continue;
332                     if((object->sizeG > 0) && object->st.st_size < object->sizeG)
333                         continue;
334                 }
335                 if(object->options & GLOBBER_PERM) {
336                     if((object->st.st_mode & 07777) & (object->type & 07777)) ;
337                     else {
338                         if((object->st.st_mode & 07777) == (object->type & 07777)) ;
339                         else
340                             continue;
341                     }
342                 }
343 
344                 if(object->options & GLOBBER_TYPE) {
345                     if((object->st.st_mode & S_IFMT) != (object->type & S_IFMT))
346                         continue;
347                 }
348             }
349             /* done lstat'ing */
350             if((object->pass = (*(operate)) (dirlist.gl_pathv[i])) != 0)
351                 break;
352         }
353     }                           /* initial glob is done */
354     if(actual_filter) free (globstring);
355     globfree (&dirlist);
356     if(!dot_filter && object->options & GLOBBER_ADD_DOT_FILTER) {
357         dot_filter = (char *)malloc (strlen (filter) + 2);
358 	if (!dot_filter){fprintf(stderr,"malloc: %s", strerror(errno)); exit(1);}
359         strcpy (dot_filter, ".");
360         strcat (dot_filter, filter);
361         actual_filter = dot_filter;
362         goto filter_repeat;
363     }
364     if(dot_filter) {
365         free (dot_filter);
366         dot_filter = NULL;
367         actual_filter = NULL;
368     }
369     if(object->pass) {
370         int pass = object->pass;
371         if (!address) free(object);
372         return (pass);  /* error returned from function */
373     }
374 
375     if(object->options & GLOBBER_RECURSIVE) {
376         DIR *directory;
377         struct dirent *d;
378         directory = opendir (path);
379         if(directory)
380             while((d = readdir (directory)) != NULL) {
381                 char *fullpath;
382                 if(strcmp (d->d_name, ".") == 0 || strcmp (d->d_name, "..") == 0)
383                     continue;
384                 fullpath = (char *)malloc (strlen (path) + strlen (d->d_name) + 2);
385 	if (!fullpath){fprintf(stderr,"malloc: %s", strerror(errno)); exit(1);}
386                 sprintf (fullpath, "%s/%s", path, d->d_name);
387 
388                 if(lstat (fullpath, &(object->st)) < 0) {
389                     free (fullpath);
390                     continue;
391                 }
392 
393                 if(!S_ISDIR (object->st.st_mode) || (object->st.st_mode & S_IFMT) == S_IFLNK) {
394                     free (fullpath);
395                     continue;   /* dont follow symlinks */
396                 }
397                 if(S_ISDIR (object->st.st_mode) && *(d->d_name) == '.' && (object->options & GLOBBER_RECURSIVE_NO_HIDDEN)) {
398                     /*printf("object->options=0x%x\n",(unsigned)object->options); */
399                     free (fullpath);
400                     continue;   /* dont recurse into hidden directories */
401                 }
402                 if(object->options & GLOBBER_XDEV && object->st.st_dev != path_st.st_dev) {
403                     free (fullpath);
404                     continue;   /* dont leave device */
405                 }
406 // this is debug rather than verbose...
407 //      if (object->options & GLOBBER_VERBOSE) fprintf(stderr, "%s: --->\n",fullpath);
408 
409                 object->pass = globber (address, fullpath, operate, filter);
410                 if(object->pass) {
411                     free (fullpath);
412                     break;
413                 }
414                 free (fullpath);
415             }
416         closedir (directory);
417 
418     }
419     int pass = object->pass;
420     if (!address) free(object);
421     return (pass);
422 }
423