dirwrap.c 24.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* 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)		*
 *																			*
11
 * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html		*
12
 *																			*
13
14
 * This library is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU Lesser General Public License		*
15
16
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
17
18
 * See the GNU Lesser General Public License for more details: lgpl.txt or	*
 * http://www.fsf.org/copyleft/lesser.html									*
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 *																			*
 * 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.	*
 ****************************************************************************/

38
39
#include <string.h>	/* strrchr */

40
#if defined(_WIN32)
41

42
43
	#include <windows.h>	/* WINAPI, etc */
	#include <io.h>			/* _findfirst */
44
45
46

#elif defined __unix__

47
48
49
	#include <unistd.h>		/* usleep */
	#include <fcntl.h>		/* O_NOCCTY */
	#include <ctype.h>		/* toupper */
rswindell's avatar
rswindell committed
50
	#include <sys/param.h>
51

rswindell's avatar
rswindell committed
52
	#if defined(BSD)
53
		#include <sys/mount.h>
54
	#endif
rswindell's avatar
rswindell committed
55
	#if defined(__FreeBSD__)
56
57
		#include <sys/kbio.h>
	#endif
58
59
	#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 300000000 /* NetBSD 3.0 */)
		#include <sys/statvfs.h>
rswindell's avatar
rswindell committed
60
	#endif
61

62
	#include <sys/ioctl.h>	/* ioctl */
63

64
65
66
	#if defined(__GLIBC__)		/* actually, BSD, but will work for now */
		#include <sys/vfs.h>    /* statfs() */
	#endif
67

deuce's avatar
deuce committed
68
69
70
71
	#if defined(__solaris__)
		#include <sys/statvfs.h>
	#endif

72
#endif /* __unix__ */
73

rswindell's avatar
rswindell committed
74
75
76
77
#if defined(__WATCOMC__)
	#include <dos.h>
#endif
	
78
79
80
81
82
83
84
#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 */

85
#include "genwrap.h"	/* strupr/strlwr */
86
#include "dirwrap.h"	/* DLLCALL */
87
#include "filewrap.h"	/* LARGE_FILE_SUPPORT */
88
89
90
91

/****************************************************************************/
/* Return the filename portion of a full pathname							*/
/****************************************************************************/
92
char* DLLCALL getfname(const char* path)
93
{
94
95
	const char* fname;
	const char* bslash;
96
97

	fname=strrchr(path,'/');
98
99
100
	bslash=strrchr(path,'\\');
	if(bslash>fname)
		fname=bslash;
101
102
103
	if(fname!=NULL) 
		fname++;
	else 
104
		fname=(char*)path;
105
	return((char*)fname);
106
107
}

108
109
110
111
112
113
114
115
116
117
118
119
120
121
/****************************************************************************/
/* Return a pointer to a file's extesion (beginning with '.')				*/
/****************************************************************************/
char* DLLCALL getfext(const char* path)
{
	char *fname;
	char *fext;

	fname=getfname(path);
	fext=strrchr(fname,'.');
	if(fext==NULL || fext==fname) 
		return(NULL);
	return(fext);
}
122
123
124
125
126
127
128
129
130
131

/****************************************************************************/
/* Break a path name into components.										*/
/****************************************************************************/
#if defined(__unix__)
void DLLCALL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
{
	char*	p;

	ext[0]=0;
132
133
134
135
136
137
138
139
140
141
	drive[0]=0;			/* no drive letters on Unix */

	strcpy(dir,path);	/* Optional directory path, including trailing slash. */
	p=getfname(dir);
	strcpy(fname,p);	/* Base filename (no extension) */
	if(p==dir)
		dir[0]=0;		/* no directory specified in path */
	else
		*p=0;			/* truncate dir at filename */
	p=getfext(fname);
142
	if(p!=NULL) {
143
		strcpy(ext,p);	/* Optional filename extension, including leading period (.) */
144
145
146
147
148
		*p=0;
	}
}
#endif

149
150
151
152
/****************************************************************************/
/* Win32 (minimal) implementation of POSIX.2 glob() function				*/
/* This code _may_ work on other DOS-based platforms (e.g. OS/2)			*/
/****************************************************************************/
153
#if !defined(__unix__)
154
static int _cdecl glob_compare( const void *arg1, const void *arg2 )
155
156
157
158
159
{
   /* Compare all of both strings: */
   return stricmp( * ( char** ) arg1, * ( char** ) arg2 );
}

160
#if defined(__BORLANDC__)
161
162
163
	#pragma argsused
#endif

rswindell's avatar
rswindell committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#if defined(__WATCOMC__)

int	DLLCALL	glob(const char *pattern, int flags, void* unused, glob_t* glob)
{
    struct	find_t ff;
	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;
	}

	if(_dos_findfirst((char*)pattern,_A_NORMAL,&ff)!=0)
		return(GLOB_NOMATCH);

	do {
183
184
		if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
			(!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
rswindell's avatar
rswindell committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
			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 */
			SAFECOPY(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++;
		}
	} while(_dos_findnext(&ff)==0);
	_dos_findclose(&ff);

	if(found==0)
		return(GLOB_NOMATCH);

	if(!(flags&GLOB_NOSORT)) {
		qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
	}

	return(0);	/* success */
}

#else

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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) {
240
241
		if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
			(!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
242
			if((new_pathv=(char**)realloc(glob->gl_pathv
243
244
245
246
247
248
249
				,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
				globfree(glob);
				return(GLOB_NOSPACE);
			}
			glob->gl_pathv=new_pathv;

			/* build the full pathname */
250
			SAFECOPY(path,pattern);
251
252
253
254
			p=getfname(path);
			*p=0;
			strcat(path,ff.name);

255
			if((glob->gl_pathv[glob->gl_pathc]=(char*)malloc(strlen(path)+2))==NULL) {
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
				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 */
}

rswindell's avatar
rswindell committed
282
283
#endif

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
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.			*/
/****************************************************************************/
307
#if defined(_MSC_VER) || defined(__DMC__)
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
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  */
/****************************************************************************/
362
time_t DLLCALL fdate(const char* filename)
363
364
365
366
367
368
369
370
371
372
373
374
{
	struct stat st;

	if(access(filename,0)==-1)
		return(-1);

	if(stat(filename, &st)!=0)
		return(-1);

	return(st.st_mtime);
}

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/****************************************************************************/
/* Change the access and modification times for specified filename			*/
/****************************************************************************/
int DLLCALL setfdate(const char* filename, time_t t)
{
	struct utimbuf ut;

	memset(&ut,0,sizeof(ut));

	ut.actime=t;
	ut.modtime=t;

	return(utime(filename,&ut));
}

390
391
/****************************************************************************/
/* Returns the length of the file in 'filename'                             */
392
/* or -1 if the file doesn't exist											*/
393
/****************************************************************************/
394
filelen_t DLLCALL flength(const char *filename)
395
{
396
#if defined(__BORLANDC__) && !defined(__unix__)	/* stat() doesn't work right */
397
398
399
400

	long	handle;
	struct _finddata_t f;

401
	if(access((char*)filename,0)==-1)
402
		return(-1);
403

404
	if((handle=_findfirst((char*)filename,&f))==-1)
405
406
407
408
409
410
411
412
413
414
415
		return(-1);

 	_findclose(handle);

	return(f.size);

#else 

	struct stat st;

	if(access(filename,0)==-1)
416
		return(-1);
417
418

	if(stat(filename, &st)!=0)
419
		return(-1);
420
421
422
423
424
425

	return(st.st_size);

#endif
}

426
427
428
429
430
431
432
433
434
435
436
437
438
439
440

/****************************************************************************/
/* Checks the file system for the existence of one or more files.			*/
/* Returns TRUE if it exists, FALSE if it doesn't.                          */
/* 'filespec' may *NOT* contain wildcards!									*/
/****************************************************************************/
static BOOL fnameexist(const char *filename)
{
	if(access(filename,0)==-1)
		return(FALSE);
	if(!isdir(filename))
		return(TRUE);
	return(FALSE);
}

441
442
443
444
445
/****************************************************************************/
/* 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!										*/
/****************************************************************************/
446
BOOL DLLCALL fexist(const char *filespec)
447
{
448
#if defined(_WIN32)
449
450
451

	long	handle;
	struct _finddata_t f;
452
	BOOL	found;
453

454
455
	if(!strchr(filespec,'*') && !strchr(filespec,'?'))
		return(fnameexist(filespec));
456

457
	if((handle=_findfirst((char*)filespec,&f))==-1)
458
		return(FALSE);
459
460
461
462
463
464
	found=TRUE;
	while(f.attrib&_A_SUBDIR)
		if(_findnext(handle,&f)!=0) {
			found=FALSE;
			break;
		}
465
466
467

 	_findclose(handle);

468
	return(found);
469

rswindell's avatar
rswindell committed
470
471
472
#else /* Unix or OS/2 */
	
	/* portion by cmartin */
473
474
475
476

	glob_t g;
    int c;

477
478
	if(!strchr(filespec,'*') && !strchr(filespec,'?'))
		return(fnameexist(filespec));
479

480
    /* start the search */
481
482
483
    glob(filespec, GLOB_MARK | GLOB_NOSORT, NULL, &g);

    if (!g.gl_pathc) {
484
	    /* no results */
485
486
487
488
    	globfree(&g);
    	return FALSE;
    }

489
    /* make sure it's not a directory */
490
491
	c = g.gl_pathc;
    while (c--) {
492
    	if (*lastchar(g.gl_pathv[c]) != '/') {
493
494
495
496
497
498
499
500
501
502
503
        	globfree(&g);
            return TRUE;
        }
    }
        
    globfree(&g);
    return FALSE;

#endif
}

504
505
506
507
508
/****************************************************************************/
/* Fixes upper/lowercase filename for Unix file systems						*/
/****************************************************************************/
BOOL DLLCALL fexistcase(char *path)
{
509
510
511
512
513
514
#if defined(_WIN32)

	char*	fname;
	long	handle;
	struct _finddata_t f;

515
516
	if(access(path,0)==-1 && !strchr(path,'*') && !strchr(path,'?'))
		return(FALSE);
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532

	if((handle=_findfirst((char*)path,&f))==-1)
		return(FALSE);

 	_findclose(handle);

 	if(f.attrib&_A_SUBDIR)
		return(FALSE);

	fname=getfname(path);	/* Find filename in path */
	strcpy(fname,f.name);	/* Correct filename */

	return(TRUE);

#else /* Unix or OS/2 */

533
534
535
536
	char globme[MAX_PATH*4+1];
	char fname[MAX_PATH+1];
	char tmp[5];
	char *p;
537
	int  i;
538
539
	glob_t	glb;
	
540
541
542
	if(!strchr(path,'*') && !strchr(path,'?') && fnameexist(path))
		return(TRUE);

543
	SAFECOPY(globme,path);
544
	p=getfname(globme);
545
	SAFECOPY(fname,p);
546
547
	*p=0;
	for(i=0;fname[i];i++)  {
548
		if(isalpha(fname[i]))
549
			sprintf(tmp,"[%c%c]",toupper(fname[i]),tolower(fname[i]));
550
		else
551
552
553
			sprintf(tmp,"%c",fname[i]);
		strncat(globme,tmp,MAX_PATH*4);
	}
554
#if 0
555
	if(strcspn(path,"?*")!=strlen(path))  {
556
		sprintf(path,"%.*s",MAX_PATH,globme);
557
		return(fexist(path));
558
	}
559
#endif
560

561
	if(glob(globme,GLOB_MARK,NULL,&glb) != 0)
562
563
		return(FALSE);
	
564
565
	if(glb.gl_pathc>0)  {
		for(i=0;i<glb.gl_pathc;i++)  {
566
567
			if(*lastchar(glb.gl_pathv[i]) != '/')
				break;
568
		}
569
		if(i<glb.gl_pathc)  {
570
			sprintf(path,"%.*s",MAX_PATH,glb.gl_pathv[i]);
571
572
573
			globfree(&glb);
			return TRUE;
		}
574
	}
575
576
577
578

	globfree(&glb);
	return FALSE;
	
579
580
581
#endif
}

582
583
584
585
#if !defined(S_ISDIR)
	#define S_ISDIR(x)	((x)&S_IFDIR)
#endif

586
587
588
/****************************************************************************/
/* Returns TRUE if the filename specified is a directory					*/
/****************************************************************************/
589
BOOL DLLCALL isdir(const char *filename)
590
{
591
592
	char	path[MAX_PATH+1];
	char*	p;
593
594
	struct stat st;

595
596
597
	SAFECOPY(path,filename);

	p=lastchar(path);
598
	if(p!=path && IS_PATH_DELIM(*p)) {	/* chop off trailing slash */
599
600
601
602
603
604
#if !defined(__unix__)
		if(*(p-1)!=':')		/* Don't change C:\ to C: */
#endif
			*p=0;
	}

605
606
607
#if defined(__BORLANDC__) && !defined(__unix__)	/* stat() doesn't work right */
	if(stat(path, &st)!=0 || strchr(path,'*')!=NULL || strchr(path,'?')!=NULL)
#else
608
	if(stat(path, &st)!=0)
609
#endif
610
611
		return(FALSE);

612
	return(S_ISDIR(st.st_mode) ? TRUE : FALSE);
613
614
615
616
617
}

/****************************************************************************/
/* Returns the attributes (mode) for specified 'filename'					*/
/****************************************************************************/
618
int DLLCALL getfattr(const char* filename)
619
{
620
#if defined(_WIN32)
621
622
623
	long handle;
	struct _finddata_t	finddata;

624
	if((handle=_findfirst((char*)filename,&finddata))==-1) {
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
		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
}

deuce's avatar
   
deuce committed
642
#ifdef __unix__
rswindell's avatar
rswindell committed
643
int removecase(const char *path)
deuce's avatar
   
deuce committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
{
	char inpath[MAX_PATH+1];
	char fname[MAX_PATH*4+1];
	char tmp[5];
	char *p;
	int  i;

	if(strchr(path,'?') || strchr(path,'*'))
		return(-1);
	SAFECOPY(inpath,path);
	p=getfname(inpath);
	fname[0]=0;
	for(i=0;p[i];i++)  {
		if(isalpha(p[i]))
			sprintf(tmp,"[%c%c]",toupper(p[i]),tolower(p[i]));
		else
			sprintf(tmp,"%c",p[i]);
		strncat(fname,tmp,MAX_PATH*4);
	}
	*p=0;

deuce's avatar
deuce committed
665
	return(delfiles(inpath,fname)?-1:0);
deuce's avatar
   
deuce committed
666
667
668
669
670
671
}
#endif

/****************************************************************************/
/* Deletes all files in dir 'path' that match file spec 'spec'              */
/****************************************************************************/
672
ulong DLLCALL delfiles(const char *inpath, const char *spec)
deuce's avatar
   
deuce committed
673
{
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
	char	path[MAX_PATH+1];
	char	lastch;
    uint	i,files=0;
	glob_t	g;

	lastch=*lastchar(inpath);
	if(!IS_PATH_DELIM(lastch) && lastch)
		sprintf(path,"%s%c",inpath,PATH_DELIM);
	else
		strcpy(path,inpath);
	strcat(path,spec);
	glob(path,0,NULL,&g);
	for(i=0;i<g.gl_pathc;i++) {
		if(isdir(g.gl_pathv[i]))
			continue;
		CHMOD(g.gl_pathv[i],S_IWRITE);	/* Incase it's been marked RDONLY */
		if(remove(g.gl_pathv[i])==0)
			files++;
	}
	globfree(&g);
	return(files);
deuce's avatar
   
deuce committed
695
696
}

697
/****************************************************************************/
698
699
/* Return free disk space in bytes (up to a maximum of 4GB)					*/
/****************************************************************************/
700
#if defined(_WIN32)
701
702
703
704
705
706
707
708
709
710
711
712
713
typedef BOOL(WINAPI * GetDiskFreeSpaceEx_t)
	(LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER); 

static int bit_num(ulong val)
{
	int i;

	for(i=31;i>=0;i--)
		if(val&(1<<i))
			return(i);

	return(-1);
}
714
715
#endif

716
717
/* Unit should be a power-of-2 (e.g. 1024 to report kilobytes) or 1 (to report bytes) */
static ulong getdiskspace(const char* path, ulong unit, BOOL freespace)
718
{
719
#if defined(_WIN32)
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
	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(
737
738
739
740
			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 */
741
			return(0);
742

743
744
745
		if(freespace)
			size=avail;

746
		if(unit>1)
747
			size.QuadPart=Int64ShrlMod32(size.QuadPart,bit_num(unit));
748

749
#if defined(_ANONYMOUS_STRUCT)
750
		if(size.HighPart)
751
#else
752
		if(size.u.HighPart)
753
754
755
#endif
			return(0xffffffff);	/* 4GB max */

756
#if defined(_ANONYMOUS_STRUCT)
757
		return(size.LowPart);
758
#else
759
		return(size.u.LowPart);
760
761
762
763
764
765
#endif
	}

	/* Windows 95 (old way), limited to 2GB */
	sprintf(root,"%.3s",path);
	if(!GetDiskFreeSpace(
766
767
768
769
770
		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 */
771
772
773
		))
		return(0);

774
775
	if(freespace)
		TotalNumberOfClusters = NumberOfFreeClusters;
776
	if(unit>1)
777
778
		TotalNumberOfClusters/=unit;
	return(TotalNumberOfClusters*SectorsPerCluster*BytesPerSector);
779
780


781
#elif defined(__solaris__) || (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 300000000 /* NetBSD 3.0 */))
782

783
	struct statvfs fs;
784
	unsigned long blocks;
785

786
    if (statvfs(path, &fs) < 0)
787
788
    	return 0;

789
790
791
792
793
	if(freespace)
		blocks=fs.f_bavail;
	else
		blocks=fs.f_blocks;

794
	if(unit>1)
795
796
		blocks/=unit;
    return fs.f_bsize * blocks;
797
    
798
799
/* statfs is also used under FreeBSD (Though it *supports* statvfs() now too) */
#elif defined(__GLIBC__) || defined(BSD)
deuce's avatar
deuce committed
800

801
	struct statfs fs;
802
	unsigned long blocks;
deuce's avatar
deuce committed
803

804
    if (statfs(path, &fs) < 0)
deuce's avatar
deuce committed
805
806
    	return 0;

807
808
809
810
811
	if(freespace)
		blocks=fs.f_bavail;
	else
		blocks=fs.f_blocks;

deuce's avatar
deuce committed
812
	if(unit>1)
813
814
		blocks/=unit;
    return fs.f_bsize * blocks;
deuce's avatar
deuce committed
815
    
816
817
#else

rswindell's avatar
rswindell committed
818
	fprintf(stderr,"\n*** !Missing getfreediskspace implementation ***\n");
819
820
821
822
	return(0);

#endif
}
823

824
825
826
827
828
829
830
831
832
833
ulong DLLCALL getfreediskspace(const char* path, ulong unit)
{
	return getdiskspace(path, unit, /* freespace? */TRUE);
}

ulong DLLCALL getdisksize(const char* path, ulong unit)
{
	return getdiskspace(path, unit, /* freespace? */FALSE);
}

834
835
836
837
838
839
840
/****************************************************************************/
/* Resolves //, /./, and /../ in a path. Should work indetically to Windows */
/****************************************************************************/
#if defined(__unix__)
char * DLLCALL _fullpath(char *target, const char *path, size_t size)  {
	char	*out;
	char	*p;
841

842
843
844
845
846
847
848
849
850
	if(target==NULL)  {
		if((target=malloc(MAX_PATH+1))==NULL) {
			return(NULL);
		}
	}
	out=target;
	*out=0;

	if(*path != '/')  {
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
		if(*path == '~') {
			p=getenv("HOME");
			if(p==NULL || strlen(p)+strlen(path)>=size)
				return(NULL);
			strcpy(target,p);
			out=strrchr(target,'\0');
			path++;
		}
		else {
			p=getcwd(NULL,size);
			if(p==NULL || strlen(p)+strlen(path)>=size)
				return(NULL);
			strcpy(target,p);
			free(p);
			out=strrchr(target,'\0');
			*(out++)='/';
			*out=0;
			out--;
		}
870
871
872
873
874
875
876
877
878
879
880
881
	}
	strncat(target,path,size-1);
	
/*	if(stat(target,&sb))
		return(NULL);
	if(sb.st_mode&S_IFDIR)
		strcat(target,"/"); */

	for(;*out;out++)  {
		while(*out=='/')  {
			if(*(out+1)=='/')
				memmove(out,out+1,strlen(out));
882
			else if(*(out+1)=='.' && (*(out+2)=='/' || *(out+2)==0))
883
				memmove(out,out+2,strlen(out)-1);
884
			else if(*(out+1)=='.' && *(out+2)=='.' && (*(out+3)=='/' || *(out+3)==0))  {
885
886
				*out=0;
				p=strrchr(target,'/');
887
888
				if(p==NULL)
					p=target;
889
890
891
892
893
894
895
896
897
898
899
				memmove(p,out+3,strlen(out+3)+1);
				out=p;
			}
			else  {
				out++;
			}
		}
	}
	return(target);
}
#endif
900
901

/****************************************************************************/
902
/* Adds a trailing slash/backslash (path delimiter) on path strings 		*/
903
904
905
906
907
/****************************************************************************/
char* DLLCALL backslash(char* path)
{
	char* p;

rswindell's avatar
rswindell committed
908
	p=lastchar(path);
909

910
	if(*p && !IS_PATH_DELIM(*p)) {
911
912
#if defined(__unix__)
		/* Convert trailing backslash to forwardslash on *nix */
913
		if(*p!='\\')
914
#endif
915
			p++;
916
		*p=PATH_DELIM;
rswindell's avatar
rswindell committed
917
		*(++p)=0;
918
919
920
	}
	return(path);
}
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942

/****************************************************************************/
/* Returns true if the specified filename an aboslute pathname				*/
/****************************************************************************/
BOOL DLLCALL isabspath(const char *filename)
{
	char path[MAX_PATH+1];

	return(stricmp(filename,FULLPATH(path,filename,sizeof(path)))==0);
}

/****************************************************************************/
/* Returns true if the specified filename is a full ("rooted") path			*/
/****************************************************************************/
BOOL DLLCALL isfullpath(const char* filename)
{
	return(filename[0]=='/' 
#ifdef WIN32
		|| filename[0]=='\\' || filename[1]==':'
#endif
		);
}
943
944
945
946
947

/****************************************************************************/
/* Matches file name against filespec										*/
/* Optionally not allowing * to match PATH_DELIM (for paths)				*/
/****************************************************************************/
948

949
950
951
952
BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
{
	char *specp;
	char *fnamep;
953
	char *wildend;
954
955
956
957
958
959
960
961
962
963
964
965
966
967

	specp=(char *)spec;
	fnamep=(char *)fname;
	for(;;specp++, fnamep++) {
		switch(*specp) {
			case '?':
				if(!(*fnamep))
					return(FALSE);
				break;
			case 0:
				if(!*fnamep)
					return(TRUE);
				break;
			case '*':
968
969
				while(*specp=='*')
					specp++;
970
971
972
973
974
975
976
977
978
979
980
981
982
				if(path) {
					for(wildend=fnamep; *wildend; wildend++) {
						if(IS_PATH_DELIM(*wildend)) {
							wildend--;
							break;
						}
					}
				}
				else
					wildend=strchr(fnamep, 0);
				for(;wildend >= fnamep;wildend--) {
					if(wildmatch(wildend, specp, path))
						return(TRUE);
983
				}
984
				return(FALSE);
985
986
987
988
989
990
991
992
993
994
995
996
997
			default:
				if(*specp != *fnamep)
					return(FALSE);
		}
		if(!(*specp && *fnamep))
			break;
	}
	while(*specp=='*')
		specp++;
	if(*specp==*fnamep)
		return(TRUE);
	return(FALSE);
}
998

999
1000
/****************************************************************************/
/* Matches file name against filespec, ignoring case						*/
For faster browsing, not all history is shown. View entire blame