Fix exec from setuid/setgid binaries
[dragonfly.git] / gnu / lib / libdialog / dir.c
blob5348c2fba4fe9aed552877a8e8641586115e6faf
1 /****************************************************************************
3 * Program: dir.c
4 * Author: Marc van Kempen
5 * desc: Directory routines, sorting and reading
7 * Copyright (c) 1995, Marc van Kempen
9 * All rights reserved.
11 * This software may be used, modified, copied, distributed, and
12 * sold, in both source and binary form provided that the above
13 * copyright and these terms are retained, verbatim, as the first
14 * lines of this file. Under no circumstances is the author
15 * responsible for the proper functioning of this software, nor does
16 * the author assume any responsibility for damages incurred with
17 * its use.
19 ****************************************************************************/
21 #include <sys/types.h>
22 #include <sys/stat.h>
24 #include <unistd.h> /* XXX for _POSIX_VERSION ifdefs */
26 #if !defined sgi && !defined _POSIX_VERSION
27 #include <sys/dir.h>
28 #endif
29 #if defined __sun__
30 #include <sys/dirent.h>
31 #endif
32 #if defined sgi || defined _POSIX_VERSION
33 #include <dirent.h>
34 #endif
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <fnmatch.h>
40 #include <sys/param.h>
41 #include "dir.h"
43 /****************************************************************************
45 * local prototypes
47 ****************************************************************************/
49 void toggle_dotfiles(void);
50 int show_dotfiles(void);
51 int dir_alphasort(const void *d1, const void *d2);
52 int dir_sizesort(const void *d1, const void *d2);
53 int dir_datesort(const void *d1, const void *d2);
54 int dir_extsort(const void *d1, const void *d2);
56 /****************************************************************************
58 * global variables
60 ****************************************************************************/
63 /* This is user-selectable, I've set them fixed for now however */
65 void *_sort_func = dir_alphasort;
66 static int _showdotfiles = TRUE;
68 /****************************************************************************
70 * Functions
72 ****************************************************************************/
74 int
75 dir_select_nd(
76 #if defined __linux__
77 const struct dirent *d
78 #else
79 struct dirent *d
80 #endif
83 * desc: allways include a directory entry <d>, except
84 * for the current directory and other dot-files
85 * keep '..' however.
86 * pre: <d> points to a dirent
87 * post: returns TRUE if d->d_name != "." else FALSE
90 if (strcmp(d->d_name, ".")==0 ||
91 (d->d_name[0] == '.' && strlen(d->d_name) > 1 && d->d_name[1] != '.')) {
92 return(FALSE);
93 } else {
94 return(TRUE);
96 }/* dir_select_nd() */
99 int
100 dir_select(
101 #ifdef __linux__
102 const struct dirent *d
103 #else
104 struct dirent *d
105 #endif
108 * desc: allways include a directory entry <d>, except
109 * for the current directory
110 * pre: <d> points to a dirent
111 * post: returns TRUE if d->d_name != "." else FALSE
114 if (strcmp(d->d_name, ".")==0) { /* don't include the current directory */
115 return(FALSE);
116 } else {
117 return(TRUE);
119 } /* dir_select() */
122 dir_select_root_nd(
123 #ifdef __linux__
124 const struct dirent *d
125 #else
126 struct dirent *d
127 #endif
130 * desc: allways include a directory entry <d>, except
131 * for the current directory and the parent directory.
132 * Also skip any other dot-files.
133 * pre: <d> points to a dirent
134 * post: returns TRUE if d->d_name[0] != "." else FALSE
137 if (d->d_name[0] == '.') { /* don't include the current directory */
138 return(FALSE); /* nor the parent directory */
139 } else {
140 return(TRUE);
142 } /* dir_select_root_nd() */
146 dir_select_root(
147 #ifdef __linux__
148 const struct dirent *d
149 #else
150 struct dirent *d
151 #endif
154 * desc: allways include a directory entry <d>, except
155 * for the current directory and the parent directory
156 * pre: <d> points to a dirent
157 * post: returns TRUE if d->d_name[0] != "." else FALSE
160 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
161 return(FALSE);
162 } else {
163 return(TRUE);
165 }/* dir_select_root() */
168 #ifdef NO_ALPHA_SORT
170 alphasort(const void *d1, const void *d2)
172 * desc: a replacement for what should be in the library
175 return(strcmp(((struct dirent *) d1)->d_name,
176 ((struct dirent *) d2)->d_name));
177 } /* alphasort() */
178 #endif
181 dir_alphasort(const void *d1, const void *d2)
183 * desc: compare d1 and d2, but put directories always first
184 * put '..' always on top
188 DirList *f1 = ((DirList *) d1),
189 *f2 = ((DirList *) d2);
190 struct stat *s1 = &(f1->filestatus);
191 struct stat *s2 = &(f2->filestatus);
193 /* check for '..' */
194 if (strcmp(((DirList *) d1)->filename, "..") == 0) {
195 return(-1);
197 if (strcmp(((DirList *) d2)->filename, "..") == 0) {
198 return(1);
201 /* put directories first */
202 if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
203 return(strcmp(f1->filename, f2->filename));
205 if (s1->st_mode & S_IFDIR) {
206 return(-1);
208 if (s2->st_mode & S_IFDIR) {
209 return(1);
211 return(strcmp(f1->filename, f2->filename));
213 } /* dir_alphasort() */
217 dir_sizesort(const void *d1, const void *d2)
219 * desc: compare d1 and d2, but put directories always first
223 DirList *f1 = ((DirList *) d1),
224 *f2 = ((DirList *) d2);
225 struct stat *s1 = &(f1->filestatus);
226 struct stat *s2 = &(f2->filestatus);
228 /* check for '..' */
229 if (strcmp(((DirList *) d1)->filename, "..") == 0) {
230 return(-1);
232 if (strcmp(((DirList *) d2)->filename, "..") == 0) {
233 return(1);
236 /* put directories first */
237 if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
238 return(s1->st_size < s2->st_size ?
241 s1->st_size >= s2->st_size);
243 if (s1->st_mode & S_IFDIR) {
244 return(-1);
246 if (s2->st_mode & S_IFDIR) {
247 return(1);
249 return(s1->st_size < s2->st_size ?
252 s1->st_size >= s2->st_size);
254 } /* dir_sizesort() */
257 dir_datesort(const void *d1, const void *d2)
259 * desc: compare d1 and d2 on date, but put directories always first
262 DirList *f1 = ((DirList *) d1),
263 *f2 = ((DirList *) d2);
264 struct stat *s1 = &(f1->filestatus);
265 struct stat *s2 = &(f2->filestatus);
268 /* check for '..' */
269 if (strcmp(((DirList *) d1)->filename, "..") == 0) {
270 return(-1);
272 if (strcmp(((DirList *) d2)->filename, "..") == 0) {
273 return(1);
276 /* put directories first */
277 if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
278 return(s1->st_mtime < s2->st_mtime ?
281 s1->st_mtime >= s2->st_mtime);
283 if (s1->st_mode & S_IFDIR) {
284 return(-1);
286 if (s2->st_mode & S_IFDIR) {
287 return(1);
289 return(s1->st_mtime < s2->st_mtime ?
292 s1->st_mtime >= s2->st_mtime);
294 } /* dir_datesort() */
298 null_strcmp(char *s1, char *s2)
300 * desc: compare strings allowing NULL pointers
303 if ((s1 == NULL) && (s2 == NULL)) {
304 return(0);
306 if (s1 == NULL) {
307 return(-1);
309 if (s2 == NULL) {
310 return(1);
312 return(strcmp(s1, s2));
313 } /* null_strcmp() */
317 dir_extsort(const void *d1, const void *d2)
319 * desc: compare d1 and d2 on extension, but put directories always first
320 * extension = "the characters after the last dot in the filename"
321 * pre: d1 and d2 are pointers to DirList type records
322 * post: see code
325 DirList *f1 = ((DirList *) d1),
326 *f2 = ((DirList *) d2);
327 struct stat *s1 = &(f1->filestatus);
328 struct stat *s2 = &(f2->filestatus);
329 char *ext1, *ext2;
330 int extf, ret;
333 /* check for '..' */
334 if (strcmp(((DirList *) d1)->filename, "..") == 0) {
335 return(-1);
337 if (strcmp(((DirList *) d2)->filename, "..") == 0) {
338 return(1);
342 /* find the first extension */
344 ext1 = f1->filename + strlen(f1->filename);
345 extf = FALSE;
346 while (!extf && (ext1 > f1->filename)) {
347 extf = (*--ext1 == '.');
349 if (!extf) {
350 ext1 = NULL;
351 } else {
352 ext1++;
354 /* ext1 == NULL if there's no "extension" else ext1 points */
355 /* to the first character of the extension string */
357 /* find the second extension */
359 ext2 = f2->filename + strlen(f2->filename);
360 extf = FALSE;
361 while (!extf && (ext2 > f2->filename)) {
362 extf = (*--ext2 == '.');
364 if (!extf) {
365 ext2 = NULL;
366 } else {
367 ext2++;
369 /* idem as for ext1 */
371 if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
372 ret = null_strcmp(ext1, ext2);
373 if (ret == 0) {
374 return(strcmp(f1->filename, f2->filename));
375 } else {
376 return(ret);
379 if (s1->st_mode & S_IFDIR) {
380 return(-1);
382 if (s2->st_mode & S_IFDIR) {
383 return(1);
385 ret = null_strcmp(ext1, ext2);
386 if (ret == 0) {
387 return(strcmp(f1->filename, f2->filename));
388 } else {
389 return(ret);
392 } /* dir_extsort() */
395 void
396 get_dir(char *dirname, char *fmask, DirList **dir, int *n)
398 * desc: get the files in the current directory
399 * pre: <dir> == NULL
400 * post: <dir> contains <n> dir-entries
403 char cwd[MAXPATHLEN];
404 char buf[256];
405 struct dirent **dire;
406 struct stat status;
407 int i, j, nb;
408 long d;
411 getcwd(cwd, MAXPATHLEN);
412 if (strcmp(cwd, "/") == 0) { /* we are in the root directory */
413 if (show_dotfiles()) {
414 *n = scandir(dirname, &dire, dir_select_root, alphasort);
415 } else {
416 *n = scandir(dirname, &dire, dir_select_root_nd, alphasort);
418 } else {
419 if (show_dotfiles()) {
420 *n = scandir(dirname, &dire, dir_select, alphasort);
421 } else {
422 *n = scandir(dirname, &dire, dir_select_nd, alphasort);
426 /* There is the possibility that we have entered a directory */
427 /* which we are not allowed to read, scandir thus returning */
428 /* -1 for *n. */
429 /* Actually I should also check for lack of memory, but I'll */
430 /* let my application happily crash if this is the case */
431 /* Solution: */
432 /* manually insert the parent directory as the only */
433 /* directory entry, and return. */
435 if (*n == -1) {
436 *n = 1;
437 *dir = (DirList *) malloc(sizeof(DirList));
438 strcpy((*dir)[0].filename, "..");
439 lstat("..", &status);
440 (*dir)[0].filestatus = status;
441 (*dir)[0].link = FALSE;
442 return;
445 *dir = (DirList *) malloc( *n * sizeof(DirList) );
446 d = 0;
447 i = 0;
448 j = 0;
449 while (j<*n) {
450 lstat(dire[j]->d_name, &status);
451 /* check if this file is to be included */
452 /* always include directories, the rest is subject to fmask */
453 if (S_ISDIR(status.st_mode)
454 || fnmatch(fmask, dire[j]->d_name, FNM_NOESCAPE) != FNM_NOMATCH) {
455 strcpy((*dir)[i].filename, dire[j]->d_name);
456 (*dir)[i].filestatus = status;
457 if ((S_IFMT & status.st_mode) == S_IFLNK) { /* handle links */
458 (*dir)[i].link = TRUE;
459 stat(dire[j]->d_name, &status);
460 nb = readlink(dire[j]->d_name, buf, sizeof(buf) - 1);
461 if (nb == -1) {
462 printf("get_dir(): Error reading link: %s\n", dire[j]->d_name);
463 exit(-1);
464 } else {
465 (*dir)[i].linkname = malloc(sizeof(char) * nb + 1);
466 strncpy((*dir)[i].linkname, buf, nb);
467 (*dir)[i].linkname[nb] = 0;
469 (*dir)[i].filestatus = status;
470 } else {
471 (*dir)[i].link = FALSE;
472 (*dir)[i].linkname = NULL;
474 i++;
475 } else {
476 /* skip this entry */
478 j++;
480 *n = i;
482 /* sort the directory with the directory names on top */
483 qsort((*dir), *n, sizeof(DirList), _sort_func);
485 /* Free the allocated memory */
486 for (i=0; i<*n; i++) {
487 free(dire[i]);
489 free(dire);
491 return;
492 }/* get_dir() */
495 void
496 FreeDir(DirList *d, int n)
498 * desc: free the dirlist d
499 * pre: d != NULL
500 * post: memory allocated to d has been released
503 int i;
505 if (d) {
506 for (i=0; i<n; i++) {
507 if (d[i].linkname) {
508 free(d[i].linkname);
511 free(d);
512 } else {
513 printf("dir.c:FreeDir(): d == NULL\n");
514 exit(-1);
517 return;
518 } /* FreeDir() */
520 void
521 toggle_dotfiles(void)
523 * desc: toggle visibility of dot-files
526 _showdotfiles = !_showdotfiles;
528 return;
529 } /* toggle_dotfiles() */
532 show_dotfiles(void)
534 * desc: return the value of _showdotfiles
537 return(_showdotfiles);
538 } /* show_dotfiles() */
540 void
541 set_dotfiles(int b)
543 * desc: set the value of _showdotfiles
546 _showdotfiles = b;
548 return;
549 } /* set_dotfiles() */