Skip to content
Snippets Groups Projects
Commit 3598a794 authored by rswindell's avatar rswindell
Browse files

New wrapper module targeted specifically at directory-related RTL functions.

parent 25bf73b8
Branches
Tags
No related merge requests found
/* dirwrap.c */
/* Directory-related system-call wrappers */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#ifdef _WIN32
#include <windows.h> /* WINAPI, etc */
#include <io.h> /* _findfirst */
#elif defined __unix__
#include <unistd.h> /* usleep */
#include <fcntl.h> /* O_NOCCTY */
#include <ctype.h> /* toupper */
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/kbio.h>
#endif
#include <sys/ioctl.h> /* ioctl */
#ifdef __GLIBC__ /* actually, BSD, but will work for now */
#include <sys/vfs.h> /* statfs() */
#endif
#endif
#include <sys/types.h> /* _dev_t */
#include <sys/stat.h> /* struct stat */
#include <stdio.h> /* sprintf */
#include <stdlib.h> /* rand */
#include <errno.h> /* ENOENT definitions */
#include "dirwrap.h" /* DLLCALL */
/****************************************************************************/
/* Return the filename portion of a full pathname */
/****************************************************************************/
char* DLLCALL getfname(char* path)
{
char *fname;
fname=strrchr(path,'/');
if(fname==NULL)
fname=strrchr(path,'\\');
if(fname!=NULL)
fname++;
else
fname=path;
return(fname);
}
#if !defined(__unix__)
/****************************************************************************/
/* Win32 (minimal) implementation of POSIX.2 glob() function */
/* This code _may_ work on other DOS-based platforms (e.g. OS/2) */
/****************************************************************************/
static int glob_compare( const void *arg1, const void *arg2 )
{
/* Compare all of both strings: */
return stricmp( * ( char** ) arg1, * ( char** ) arg2 );
}
#ifdef __BORLANDC__
#pragma argsused
#endif
int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t* glob)
{
struct _finddata_t ff;
long ff_handle;
size_t found=0;
char path[MAX_PATH+1];
char* p;
char** new_pathv;
if(!(flags&GLOB_APPEND)) {
glob->gl_pathc=0;
glob->gl_pathv=NULL;
}
ff_handle=_findfirst((char*)pattern,&ff);
while(ff_handle!=-1) {
if(!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR) {
if((new_pathv=realloc(glob->gl_pathv
,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
globfree(glob);
return(GLOB_NOSPACE);
}
glob->gl_pathv=new_pathv;
/* build the full pathname */
strcpy(path,pattern);
p=getfname(path);
*p=0;
strcat(path,ff.name);
if((glob->gl_pathv[glob->gl_pathc]=malloc(strlen(path)+2))==NULL) {
globfree(glob);
return(GLOB_NOSPACE);
}
strcpy(glob->gl_pathv[glob->gl_pathc],path);
if(flags&GLOB_MARK && ff.attrib&_A_SUBDIR)
strcat(glob->gl_pathv[glob->gl_pathc],"/");
glob->gl_pathc++;
found++;
}
if(_findnext(ff_handle, &ff)!=0) {
_findclose(ff_handle);
ff_handle=-1;
}
}
if(found==0)
return(GLOB_NOMATCH);
if(!(flags&GLOB_NOSORT)) {
qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
}
return(0); /* success */
}
void DLLCALL globfree(glob_t* glob)
{
size_t i;
if(glob==NULL)
return;
if(glob->gl_pathv!=NULL) {
for(i=0;i<glob->gl_pathc;i++)
if(glob->gl_pathv[i]!=NULL)
free(glob->gl_pathv[i]);
free(glob->gl_pathv);
glob->gl_pathv=NULL;
}
glob->gl_pathc=0;
}
#endif /* !defined(__unix__) */
/****************************************************************************/
/* POSIX directory operations using Microsoft _findfirst/next API. */
/****************************************************************************/
#if defined(_MSC_VER)
DIR* opendir(const char* dirname)
{
DIR* dir;
if((dir=(DIR*)calloc(1,sizeof(DIR)))==NULL) {
errno=ENOMEM;
return(NULL);
}
sprintf(dir->filespec,"%.*s",sizeof(dir->filespec)-5,dirname);
if(*dir->filespec && dir->filespec[strlen(dir->filespec)-1]!='\\')
strcat(dir->filespec,"\\");
strcat(dir->filespec,"*.*");
dir->handle=_findfirst(dir->filespec,&dir->finddata);
if(dir->handle==-1) {
errno=ENOENT;
free(dir);
return(NULL);
}
return(dir);
}
struct dirent* readdir(DIR* dir)
{
if(dir==NULL)
return(NULL);
if(dir->end==TRUE)
return(NULL);
if(dir->handle==-1)
return(NULL);
sprintf(dir->dirent.d_name,"%.*s",sizeof(struct dirent)-1,dir->finddata.name);
if(_findnext(dir->handle,&dir->finddata)!=0)
dir->end=TRUE;
return(&dir->dirent);
}
int closedir (DIR* dir)
{
if(dir==NULL)
return(-1);
_findclose(dir->handle);
free(dir);
return(0);
}
void rewinddir(DIR* dir)
{
if(dir==NULL)
return;
_findclose(dir->handle);
dir->end=FALSE;
dir->handle=_findfirst(dir->filespec,&dir->finddata);
}
#endif /* defined(_MSC_VER) */
/****************************************************************************/
/* Returns the time/date of the file in 'filename' in time_t (unix) format */
/****************************************************************************/
time_t DLLCALL fdate(char *filename)
{
struct stat st;
if(access(filename,0)==-1)
return(-1);
if(stat(filename, &st)!=0)
return(-1);
return(st.st_mtime);
}
/****************************************************************************/
/* Returns the length of the file in 'filename' */
/****************************************************************************/
long DLLCALL flength(char *filename)
{
#ifdef __BORLANDC__ /* stat() doesn't work right */
long handle;
struct _finddata_t f;
if(access(filename,0)==-1)
return(-1L);
if((handle=_findfirst(filename,&f))==-1)
return(-1);
_findclose(handle);
return(f.size);
#else
struct stat st;
if(access(filename,0)==-1)
return(-1L);
if(stat(filename, &st)!=0)
return(-1L);
return(st.st_size);
#endif
}
/****************************************************************************/
/* Checks the file system for the existence of one or more files. */
/* Returns TRUE if it exists, FALSE if it doesn't. */
/* 'filespec' may contain wildcards! */
/****************************************************************************/
BOOL DLLCALL fexist(char *filespec)
{
#ifdef _WIN32
long handle;
struct _finddata_t f;
if(access(filespec,0)==-1 && !strchr(filespec,'*') && !strchr(filespec,'?'))
return(FALSE);
if((handle=_findfirst(filespec,&f))==-1)
return(FALSE);
_findclose(handle);
if(f.attrib&_A_SUBDIR)
return(FALSE);
return(TRUE);
#elif defined(__unix__) /* portion by cmartin */
glob_t g;
int c;
int l;
if(access(filespec,0)==-1 && !strchr(filespec,'*') && !strchr(filespec,'?'))
return(FALSE);
// start the search
glob(filespec, GLOB_MARK | GLOB_NOSORT, NULL, &g);
if (!g.gl_pathc) {
// no results
globfree(&g);
return FALSE;
}
// make sure it's not a directory
c = g.gl_pathc;
while (c--) {
l = strlen(g.gl_pathv[c]);
if (l && g.gl_pathv[c][l-1] != '/') {
globfree(&g);
return TRUE;
}
}
globfree(&g);
return FALSE;
#else
#warning "fexist() port needs to support wildcards!"
return(FALSE);
#endif
}
/****************************************************************************/
/* Returns TRUE if the filename specified is a directory */
/****************************************************************************/
BOOL DLLCALL isdir(char *filename)
{
struct stat st;
if(stat(filename, &st)!=0)
return(FALSE);
return((st.st_mode&S_IFDIR) ? TRUE : FALSE);
}
/****************************************************************************/
/* Returns the attributes (mode) for specified 'filename' */
/****************************************************************************/
int DLLCALL getfattr(char* filename)
{
#ifdef _WIN32
long handle;
struct _finddata_t finddata;
if((handle=_findfirst(filename,&finddata))==-1) {
errno=ENOENT;
return(-1);
}
_findclose(handle);
return(finddata.attrib);
#else
struct stat st;
if(stat(filename, &st)!=0) {
errno=ENOENT;
return(-1L);
}
return(st.st_mode);
#endif
}
/****************************************************************************/
/* Return free disk space in bytes (up to a maximum of 4GB) */
/****************************************************************************/
#ifdef _WIN32
typedef BOOL(WINAPI * GetDiskFreeSpaceEx_t)
(LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
#endif
ulong DLLCALL getfreediskspace(char* path)
{
#ifdef _WIN32
char root[16];
DWORD TotalNumberOfClusters;
DWORD NumberOfFreeClusters;
DWORD BytesPerSector;
DWORD SectorsPerCluster;
ULARGE_INTEGER avail;
ULARGE_INTEGER size;
static HINSTANCE hK32;
GetDiskFreeSpaceEx_t GetDiskFreeSpaceEx;
if(hK32 == NULL)
hK32 = LoadLibrary("KERNEL32");
GetDiskFreeSpaceEx
= (GetDiskFreeSpaceEx_t)GetProcAddress(hK32,"GetDiskFreeSpaceExA");
if (GetDiskFreeSpaceEx!=NULL) { /* Windows 95-OSR2 or later */
if(!GetDiskFreeSpaceEx(
path, // pointer to the directory name
&avail, // receives the number of bytes on disk avail to the caller
&size, // receives the number of bytes on disk
NULL)) // receives the free bytes on disk
return(0);
#ifdef _ANONYMOUS_STRUCT
if(avail.HighPart)
#else
if(avail.u.HighPart)
#endif
return(0xffffffff); /* 4GB max */
#ifdef _ANONYMOUS_STRUCT
return(avail.LowPart);
#else
return(avail.u.LowPart);
#endif
}
/* Windows 95 (old way), limited to 2GB */
sprintf(root,"%.3s",path);
if(!GetDiskFreeSpace(
root, // pointer to root path
&SectorsPerCluster, // pointer to sectors per cluster
&BytesPerSector, // pointer to bytes per sector
&NumberOfFreeClusters, // pointer to number of free clusters
&TotalNumberOfClusters // pointer to total number of clusters
))
return(0);
return(NumberOfFreeClusters*SectorsPerCluster*BytesPerSector);
/* statfs is also used under FreeBSD */
#elif defined(__GLIBC__) || defined(__FreeBSD__)
struct statfs fs;
if (statfs(path, &fs) < 0)
return 0;
return fs.f_bsize * fs.f_bavail;
#else
#warning OS-specific code needed here
return(0);
#endif
}
/* dirwrap.h */
/* Directory system-call wrappers */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#ifndef _DIRWRAP_H
#define _DIRWRAP_H
#include "gen_defs.h" /* ulong */
#ifdef DLLEXPORT
#undef DLLEXPORT
#endif
#ifdef DLLCALL
#undef DLLCALL
#endif
#ifdef _WIN32
#ifdef WRAPPER_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
#ifdef __BORLANDC__
#define DLLCALL __stdcall
#else
#define DLLCALL
#endif
#else /* !_WIN32 */
#define DLLEXPORT
#define DLLCALL
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#include "msdirent.h"
#else
#include <dirent.h> /* POSIX directory functions */
#endif
/****************/
/* RTL-specific */
/****************/
#ifdef __unix__
#define ALLFILES "*" /* matches all files in a directory */
#define MKDIR(dir) _mkdir(dir)
#define RMDIR(dir) _rmdir(dir)
#define FULLPATH(a,r,l) _fullpath(a,r,l)
#include <glob.h> /* POSIX.2 directory pattern matching function */
#else
#define ALLFILES "*.*" /* matches all files in a directory */
#define MKDIR(dir) mkdir(dir,0777)
#define RMDIR(dir) rmdir(dir)
#define FULLPATH(a,r,l) realpath(r,a)
/* glob-compatible findfirst/findnext wrapper */
typedef struct
{
size_t gl_pathc; /* Count of paths matched so far */
char **gl_pathv; /* List of matched pathnames. */
size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
} glob_t;
/* Bits set in the FLAGS argument to `glob'. */
#define GLOB_ERR (1 << 0) /* Return on read errors. */
#define GLOB_MARK (1 << 1) /* Append a slash to each name. */
#define GLOB_NOSORT (1 << 2) /* Don't sort the names. */
#define GLOB_DOOFFS (1 << 3) /* Insert PGLOB->gl_offs NULLs. */
#define GLOB_NOCHECK (1 << 4) /* If nothing matches, return the pattern. */
#define GLOB_APPEND (1 << 5) /* Append to results of a previous call. */
#define GLOB_NOESCAPE (1 << 6) /* Backslashes don't quote metacharacters. */
#define GLOB_PERIOD (1 << 7) /* Leading `.' can be matched by metachars. */
#define GLOB_MAGCHAR (1 << 8) /* Set in gl_flags if any metachars seen. */
#define GLOB_ALTDIRFUNC (1 << 9) /* Use gl_opendir et al functions. */
#define GLOB_BRACE (1 << 10) /* Expand "{a,b}" to "a" "b". */
#define GLOB_NOMAGIC (1 << 11) /* If no magic chars, return the pattern. */
#define GLOB_TILDE (1 << 12) /* Expand ~user and ~ to home directories. */
#define GLOB_ONLYDIR (1 << 13) /* Match only directories. */
#define GLOB_TILDE_CHECK (1 << 14) /* Like GLOB_TILDE but return an error
if the user name is not available. */
/* Error returns from `glob'. */
#define GLOB_NOSPACE 1 /* Ran out of memory. */
#define GLOB_ABORTED 2 /* Read error. */
#define GLOB_NOMATCH 3 /* No matches found. */
#define GLOB_NOSYS 4 /* Not implemented. */
DLLEXPORT int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t*);
DLLEXPORT void DLLCALL globfree(glob_t*);
#endif
/*****************************/
/* POSIX Directory Functions */
/*****************************/
#if defined(_MSC_VER)
/* dirent structure returned by readdir().
*/
struct dirent
{
char d_name[260]; /* filename */
};
/* DIR type returned by opendir(). The members of this structure
* must not be accessed by application programs.
*/
typedef struct
{
char filespec[260];
struct dirent dirent;
long handle;
struct _finddata_t finddata;
BOOL end; /* End of directory flag */
} DIR;
/* Prototypes.
*/
DIR * opendir (const char *__dirname);
struct dirent * readdir (DIR *__dir);
int closedir (DIR *__dir);
void rewinddir(DIR *__dir);
#endif
/**********/
/* Macros */
/**********/
/* POSIX readdir convenience macro */
#ifndef DIRENT
#define DIRENT struct dirent
#endif
#if defined(__unix__)
#define BACKSLASH '/'
#else /* MS-DOS based OS */
#define BACKSLASH '\\'
#endif
#if defined(_MSC_VER) || defined(__MINGW32__)
#define CHMOD(s,m) _chmod(s,m)
#define PUTENV _putenv
#define GETCWD _getcwd
#elif defined(__BORLANDC__)
#define CHMOD(p,a) _rtl_chmod(p,1,a) /* _chmod obsolete in 4.x */
#define PUTENV putenv
#define GETCWD getcwd
#else /* ??? */
#define CHMOD(s,m) chmod(s,m)
#define PUTENV putenv
#define GETCWD getcwd
#endif
/* General file system wrappers for all platforms and compilers */
DLLEXPORT BOOL DLLCALL fexist(char *filespec);
DLLEXPORT long DLLCALL flength(char *filename);
DLLEXPORT time_t DLLCALL fdate(char *filename);
DLLEXPORT BOOL DLLCALL isdir(char *filename);
DLLEXPORT char* DLLCALL getfname(char* path);
DLLEXPORT int DLLCALL getfattr(char* filename);
DLLEXPORT ulong DLLCALL getfreediskspace(char* path);
#ifdef __cplusplus
}
#endif
#endif /* Don't add anything after this line */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment