homeanddirs.c
guylhem@oeil.qc.ca
27 Jul 1998 08:41:34 -0000
/*
* Handle directories & files
*
* Copyright (c) 1998 Michael Vitecek <M.Vitecek@sh.cvut.cz>
* Copyright (c) 1998 Chris Ridd <c.ridd@isode.com>
* Copyright (c) 1997 Guylhem AZNAR <guylhem@oeil.qc.ca>
*
*/
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include "../include/configure.h"
#include "../include/afterstep.h"
#include "../include/aftersteplib.h"
my_sort_f my_sort_list[] =
{my_dirsort,
my_alphasort,
NULL};
int HomeCreate(const char *filename)
{
int c;
char *target, *source;
FILE *targetfile, *sourcefile;
target = (char *) safemalloc(strlen(AFTER_DIR) + strlen(filename) + 2);
sprintf(target, "%s/%s", AFTER_DIR, filename);
source = (char *) safemalloc(strlen(AFTER_SHAREDIR) + strlen(filename) + 2);
sprintf(source, "%s/%s", AFTER_SHAREDIR, filename);
if ((targetfile = fopen(PutHome(target), "w")) == NULL) {
fprintf(stderr, "can't open %s !", target);
return (-1);
}
if ((sourcefile = fopen(PutHome(source), "r")) == NULL) {
fprintf(stderr, "can't open %s !", source);
return (-2);
}
/* free memory allocated for the filenames */
free(target);
free(source);
/* copy the source file to the target file */
while ((c = getc(sourcefile)) != EOF)
putc(c, targetfile);
fclose(targetfile);
fclose(sourcefile);
return 0;
}
int CheckFile(const char *file)
{
struct stat st;
if ((stat(file, &st) == -1) || (st.st_mode & S_IFMT) != S_IFREG)
return (-1);
else
return (0);
}
int CheckDir(const char *directory)
{
struct stat st;
if ((stat(directory, &st) == -1) || (st.st_mode & S_IFMT) != S_IFDIR)
return (-1);
else
return (0);
}
char *CheckOrShare(const char *directory, const char *homedir, const char *sharedir, const int share)
{
char *result_dir;
result_dir = (char *) safemalloc(PATH_MAX + 1);
sprintf(result_dir, "%s/%s", homedir, directory);
if (CheckDir(result_dir) != 0) {
/* the home directory doesn't exist or there's a problem with accessing it */
if (!share) {
/* try it with the system directory */
sprintf(result_dir, "%s/%s", sharedir, directory);
if (CheckDir(result_dir) != 0) {
/* problems with accessing the system directory */
free(result_dir);
return (NULL);
} else
return (result_dir);
} else {
/* ahh - it already was the system directory! */
free(result_dir);
return (NULL);
}
}
return (result_dir);
}
char *PutHome(const char *path_with_home)
{
char *home; /* the HOME environment variable */
char *realpath;
/* home dir ? */
if (!strncmp(path_with_home, "~/", 2)) {
/* get home */
if ((home = getenv("HOME")) == NULL)
home = "./";
/* alloc it */
realpath = (char *) safemalloc(strlen(home) + strlen(path_with_home) + 1);
strcpy(realpath, home);
strcat(realpath, "/");
strcat(realpath, path_with_home + 2);
} else {
realpath = (char *) safemalloc(strlen(path_with_home) + 1);
strcpy(realpath, path_with_home);
}
return (realpath);
}
int CheckOrCreate(const char *what)
{
char *checkdir;
mode_t perms = 0755;
checkdir = PutHome(what);
if (CheckDir(checkdir) != 0) {
fprintf(stderr, "Creating %s ... ", what);
if (mkdir(checkdir, perms)) {
free(checkdir);
fprintf(stderr, "ERROR !\n AfterStep depends on %s directory !\nPlease check permissions or contact your sysadmin !\n", what);
return (-1);
} else
fprintf(stderr, "done\n");
}
free(checkdir);
return (0);
}
int CheckOrCreateFile(const char *what)
{
char *checkfile;
FILE *touch;
checkfile = PutHome(what);
if (CheckFile(checkfile) != 0) {
fprintf(stderr, "Creating %s ... ", what);
if ((touch = fopen(checkfile, "w")) == NULL) {
free(checkfile);
fprintf(stderr, "ERROR !\n Cannot open file %s for writing!\n"
" Please check permissions or contact your sysadmin !\n", what);
return (-1);
} else {
fclose(touch);
fprintf(stderr, "done\n");
}
}
free(checkfile);
return (0);
}
/*
* Non-NULL select and dcomp pointers are *NOT* tested, but should be OK.
* They are not used by afterstep however, so this implementation should
* be good enough.
*
* c.ridd@isode.com
*/
int my_scandir(char *dirname, struct direntry *(*namelist[]),
int (*select) (struct dirent *),
int (*dcomp) (struct direntry **, struct direntry **))
{
DIR *d;
struct dirent *e; /* Pointer to static struct inside readdir() */
struct direntry **nl; /* Array of pointers to dirents */
struct direntry **nnl;
int n; /* Count of nl used so far */
int sizenl; /* Number of entries in nl array */
int j;
size_t realsize;
char *filename; /* For building filename to pass to stat */
char *p; /* Place where filename starts */
struct stat buf;
d = opendir(dirname);
if (d == NULL)
return -1;
filename = (char *) safemalloc(strlen(dirname) + PATH_MAX + 2);
if (filename == NULL) {
closedir(d);
return -1;
}
strcpy(filename, dirname);
p = filename + strlen(filename);
*p++ = '/';
*p = 0; /* Just in case... */
nl = NULL;
n = 0;
sizenl = 0;
while ((e = readdir(d)) != NULL) {
if ((select == NULL) || select(e)) {
/* add */
if (sizenl == n) {
/* Grow array */
sizenl += 32; /* arbitrary delta */
nnl = realloc(nl, sizenl * sizeof(struct direntry *));
if (nnl == NULL) {
/* Free the old array */
for (j = 0; j < n; j++)
free(nl[j]);
free(nl);
free(filename);
closedir(d);
return -1;
}
nl = nnl;
}
realsize = offsetof(struct direntry, d_name) +strlen(e->d_name) + 1;
nl[n] = (struct direntry *) safemalloc(realsize);
if (nl[n] == NULL) {
for (j = 0; j < n; j++)
free(nl[j]);
free(nl);
free(filename);
closedir(d);
return -1;
}
/* Fill in the fields using stat() */
strcpy(p, e->d_name);
if (stat(filename, &buf) == -1) {
for (j = 0; j <= n; j++)
free(nl[j]);
free(nl);
free(filename);
closedir(d);
return -1;
}
nl[n]->d_mode = buf.st_mode;
nl[n]->d_mtime = buf.st_mtime;
strcpy(nl[n]->d_name, e->d_name);
n++;
}
}
free(filename);
if (closedir(d) == -1) {
free(nl);
return -1;
}
*namelist = realloc(nl, n * sizeof(struct direntry *));
if (n == 0)
/* OK, but not point sorting or freeing anything */
return 0;
if (*namelist == NULL) {
for (j = 0; j < n; j++)
free(nl[j]);
free(nl);
return -1;
}
/* Optionally sort the list */
if (dcomp)
qsort(*namelist, n, sizeof(struct direntry *), (int (*)()) dcomp);
/* Return the count of the entries */
return n;
}
/* sort entries based on the array my_sort_list */
int my_sort(struct direntry **d1, struct direntry **d2)
{
int i, diff = 0;
for (i = 0; i < 5; i++) {
if (my_sort_list[i] != NULL) {
diff = my_sort_list[i] (d1, d2);
if (diff != 0)
break;
}
}
return diff;
}
/* sort entries based on their type. directories come first */
int my_dirsort(struct direntry **d1, struct direntry **d2)
{
return (*d1)->d_mode - (*d2)->d_mode;
}
/* Sort entries based on their names. A comes before Z. */
#define BUF_SIZE 10
int my_alphasort(struct direntry **d1, struct direntry **d2)
{
char *under1, *under2;
int num1, num2, len, final_len;
char buf[BUF_SIZE + 1];
/* if the item name(s) that are compared begin with digit, try to get the
numbers */
if(isdigit(*((*d1)->d_name)) || (isdigit(*((*d2)->d_name))))
{
/* find out if the names are in the format <number>_<Item name> */
under1 = (*d1)->d_name;
while((*under1) && (isdigit(*under1)) && (*under1 != '_')) under1++;
under2 = (*d2)->d_name;
while((*under2) && (isdigit(*under2)) && (*under2 != '_')) under2++;
/* <number>_<Item name> takes precedence before <Item name> */
fprintf(stderr, "%s ?= %s : ", (*d1)->d_name, (*d2)->d_name);
if((*under1 == '_') && (!*under2)) fprintf(stderr, "-1\n");
else if((!*under2) && (*under2)) fprintf(stderr, "1\n");
if((*under1 == '_') && (!*under2)) return(-1);
else if((!*under2) && (*under2)) return(1);
/* both names are in format <number>_<Item name> */
else if((*under1 == '_') && (*under2 == '_'))
{
/* copy the number to buf */
strncpy(buf, (*d1)->d_name, (final_len = ((len = under1 -
(*d1)->d_name) < BUF_SIZE ? len : BUF_SIZE)));
buf[final_len] = '\0';
num1 = atoi(buf);
/* copy the number to buf */
strncpy(buf, (*d2)->d_name, (final_len = ((len = under2 -
(*d2)->d_name) < BUF_SIZE ? len : BUF_SIZE)));
buf[final_len] = '\0';
num2 = atoi(buf);
if(num1 < num2) return(-1);
else if(num1 > num2) return(1);
return(0);
}
/* it was only a plain attack, the names are not in the format we want */
}
return(strcmp((*d1)->d_name, (*d2)->d_name));
}
#undef BUF_SIZE
/* Sort entries based on their mtimes. Old entries come before new entries,
* entries with the same times get sorted alphabetically.
*/
int my_datesort(struct direntry **d1, struct direntry **d2)
{
int diff = (*d1)->d_mtime - (*d2)->d_mtime;
if (diff == 0)
diff = my_alphasort(d1, d2);
return diff;
}
/*
* Use this function as the select argument to my_scandir to make it ignore
* all files and directories starting with "."
*/
int ignore_dots(struct dirent *e)
{
return (e->d_name[0] != '.');
}