|
|
1.1 root 1: /* dirwrap.c */
2:
3: /* Directory-related system-call wrappers */
4:
1.1.1.2 ! root 5: /* $Id: dirwrap.c,v 1.83 2011/09/08 22:22:48 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <string.h> /* strrchr */
39:
40: #if defined(_WIN32)
41:
42: #include <windows.h> /* WINAPI, etc */
43: #include <io.h> /* _findfirst */
44:
45: #elif defined __unix__
46:
47: #include <unistd.h> /* usleep */
48: #include <fcntl.h> /* O_NOCCTY */
49: #include <ctype.h> /* toupper */
50: #include <sys/param.h>
51:
52: #if defined(BSD)
53: #include <sys/mount.h>
54: #endif
55: #if defined(__FreeBSD__)
56: #include <sys/kbio.h>
57: #endif
58: #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 300000000 /* NetBSD 3.0 */)
59: #include <sys/statvfs.h>
60: #endif
61:
62: #include <sys/ioctl.h> /* ioctl */
63:
64: #if defined(__GLIBC__) /* actually, BSD, but will work for now */
65: #include <sys/vfs.h> /* statfs() */
66: #endif
67:
68: #if defined(__solaris__)
69: #include <sys/statvfs.h>
70: #endif
71:
72: #endif /* __unix__ */
73:
74: #if defined(__WATCOMC__)
75: #include <dos.h>
76: #endif
77:
78: #include <sys/types.h> /* _dev_t */
79: #include <sys/stat.h> /* struct stat */
80:
81: #include <stdio.h> /* sprintf */
82: #include <stdlib.h> /* rand */
83: #include <errno.h> /* ENOENT definitions */
84:
85: #include "genwrap.h" /* strupr/strlwr */
86: #include "dirwrap.h" /* DLLCALL */
87:
88: /****************************************************************************/
89: /* Return the filename portion of a full pathname */
90: /****************************************************************************/
91: char* DLLCALL getfname(const char* path)
92: {
93: const char* fname;
94: const char* bslash;
95:
96: fname=strrchr(path,'/');
97: bslash=strrchr(path,'\\');
98: if(bslash>fname)
99: fname=bslash;
100: if(fname!=NULL)
101: fname++;
102: else
103: fname=(char*)path;
104: return((char*)fname);
105: }
106:
107: /****************************************************************************/
108: /* Return a pointer to a file's extesion (beginning with '.') */
109: /****************************************************************************/
110: char* DLLCALL getfext(const char* path)
111: {
112: char *fname;
113: char *fext;
114:
115: fname=getfname(path);
116: fext=strrchr(fname,'.');
117: if(fext==NULL || fext==fname)
118: return(NULL);
119: return(fext);
120: }
121:
122: /****************************************************************************/
123: /* Break a path name into components. */
124: /****************************************************************************/
125: #if defined(__unix__)
126: void DLLCALL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
127: {
128: char* p;
129:
130: ext[0]=0;
131: drive[0]=0; /* no drive letters on Unix */
132:
133: strcpy(dir,path); /* Optional directory path, including trailing slash. */
134: p=getfname(dir);
135: strcpy(fname,p); /* Base filename (no extension) */
136: if(p==dir)
137: dir[0]=0; /* no directory specified in path */
138: else
139: *p=0; /* truncate dir at filename */
140: p=getfext(fname);
141: if(p!=NULL) {
142: strcpy(ext,p); /* Optional filename extension, including leading period (.) */
143: *p=0;
144: }
145: }
146: #endif
147:
148: /****************************************************************************/
149: /* Win32 (minimal) implementation of POSIX.2 glob() function */
150: /* This code _may_ work on other DOS-based platforms (e.g. OS/2) */
151: /****************************************************************************/
152: #if !defined(__unix__)
153: static int _cdecl glob_compare( const void *arg1, const void *arg2 )
154: {
155: /* Compare all of both strings: */
156: return stricmp( * ( char** ) arg1, * ( char** ) arg2 );
157: }
158:
159: #if defined(__BORLANDC__)
160: #pragma argsused
161: #endif
162:
163: #if defined(__WATCOMC__)
164:
165: int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t* glob)
166: {
167: struct find_t ff;
168: size_t found=0;
169: char path[MAX_PATH+1];
170: char* p;
171: char** new_pathv;
172:
173: if(!(flags&GLOB_APPEND)) {
174: glob->gl_pathc=0;
175: glob->gl_pathv=NULL;
176: }
177:
1.1.1.2 ! root 178: if(_dos_findfirst((char*)pattern,(flags&GLOB_PERIOD) ? _A_HIDDEN : _A_NORMAL,&ff)!=0)
1.1 root 179: return(GLOB_NOMATCH);
180:
181: do {
182: if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
183: (!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
184: if((new_pathv=realloc(glob->gl_pathv
185: ,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
186: globfree(glob);
187: return(GLOB_NOSPACE);
188: }
189: glob->gl_pathv=new_pathv;
190:
191: /* build the full pathname */
192: SAFECOPY(path,pattern);
193: p=getfname(path);
194: *p=0;
195: strcat(path,ff.name);
196:
197: if((glob->gl_pathv[glob->gl_pathc]=malloc(strlen(path)+2))==NULL) {
198: globfree(glob);
199: return(GLOB_NOSPACE);
200: }
201: strcpy(glob->gl_pathv[glob->gl_pathc],path);
202: if(flags&GLOB_MARK && ff.attrib&_A_SUBDIR)
203: strcat(glob->gl_pathv[glob->gl_pathc],"/");
204:
205: glob->gl_pathc++;
206: found++;
207: }
208: } while(_dos_findnext(&ff)==0);
209: _dos_findclose(&ff);
210:
211: if(found==0)
212: return(GLOB_NOMATCH);
213:
214: if(!(flags&GLOB_NOSORT)) {
215: qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
216: }
217:
218: return(0); /* success */
219: }
220:
221: #else
222:
223: int DLLCALL glob(const char *pattern, int flags, void* unused, glob_t* glob)
224: {
225: struct _finddata_t ff;
226: long ff_handle;
227: size_t found=0;
228: char path[MAX_PATH+1];
229: char* p;
230: char** new_pathv;
231:
232: if(!(flags&GLOB_APPEND)) {
233: glob->gl_pathc=0;
234: glob->gl_pathv=NULL;
235: }
236:
237: ff_handle=_findfirst((char*)pattern,&ff);
238: while(ff_handle!=-1) {
1.1.1.2 ! root 239: if((flags&GLOB_PERIOD || (ff.name[0]!='.' && !(ff.attrib&_A_HIDDEN))) &&
1.1 root 240: (!(flags&GLOB_ONLYDIR) || ff.attrib&_A_SUBDIR)) {
241: if((new_pathv=(char**)realloc(glob->gl_pathv
242: ,(glob->gl_pathc+1)*sizeof(char*)))==NULL) {
243: globfree(glob);
244: return(GLOB_NOSPACE);
245: }
246: glob->gl_pathv=new_pathv;
247:
248: /* build the full pathname */
249: SAFECOPY(path,pattern);
250: p=getfname(path);
251: *p=0;
252: strcat(path,ff.name);
253:
254: if((glob->gl_pathv[glob->gl_pathc]=(char*)malloc(strlen(path)+2))==NULL) {
255: globfree(glob);
256: return(GLOB_NOSPACE);
257: }
258: strcpy(glob->gl_pathv[glob->gl_pathc],path);
259: if(flags&GLOB_MARK && ff.attrib&_A_SUBDIR)
260: strcat(glob->gl_pathv[glob->gl_pathc],"/");
261:
262: glob->gl_pathc++;
263: found++;
264: }
265: if(_findnext(ff_handle, &ff)!=0) {
266: _findclose(ff_handle);
267: ff_handle=-1;
268: }
269: }
270:
271: if(found==0)
272: return(GLOB_NOMATCH);
273:
274: if(!(flags&GLOB_NOSORT)) {
275: qsort(glob->gl_pathv,found,sizeof(char*),glob_compare);
276: }
277:
278: return(0); /* success */
279: }
280:
281: #endif
282:
283: void DLLCALL globfree(glob_t* glob)
284: {
285: size_t i;
286:
287: if(glob==NULL)
288: return;
289:
290: if(glob->gl_pathv!=NULL) {
291: for(i=0;i<glob->gl_pathc;i++)
292: if(glob->gl_pathv[i]!=NULL)
293: free(glob->gl_pathv[i]);
294:
295: free(glob->gl_pathv);
296: glob->gl_pathv=NULL;
297: }
298: glob->gl_pathc=0;
299: }
300:
301: #endif /* !defined(__unix__) */
302:
1.1.1.2 ! root 303: long DLLCALL getdirsize(const char* path, BOOL include_subdirs, BOOL subdir_only)
! 304: {
! 305: char match[MAX_PATH+1];
! 306: glob_t g;
! 307: unsigned gi;
! 308: long count=0;
! 309:
! 310: if(!isdir(path))
! 311: return -1;
! 312:
! 313: SAFECOPY(match,path);
! 314: backslash(match);
! 315: strcat(match,ALLFILES);
! 316: glob(match,GLOB_MARK,NULL,&g);
! 317: if(include_subdirs && !subdir_only)
! 318: count=g.gl_pathc;
! 319: else
! 320: for(gi=0;gi<g.gl_pathc;gi++) {
! 321: if(*lastchar(g.gl_pathv[gi])=='/') {
! 322: if(!include_subdirs)
! 323: continue;
! 324: } else
! 325: if(subdir_only)
! 326: continue;
! 327: count++;
! 328: }
! 329: globfree(&g);
! 330: return(count);
! 331: }
! 332:
1.1 root 333: /****************************************************************************/
334: /* POSIX directory operations using Microsoft _findfirst/next API. */
335: /****************************************************************************/
336: #if defined(_MSC_VER) || defined(__DMC__)
337: DIR* opendir(const char* dirname)
338: {
339: DIR* dir;
340:
341: if((dir=(DIR*)calloc(1,sizeof(DIR)))==NULL) {
342: errno=ENOMEM;
343: return(NULL);
344: }
345: sprintf(dir->filespec,"%.*s",sizeof(dir->filespec)-5,dirname);
346: if(*dir->filespec && dir->filespec[strlen(dir->filespec)-1]!='\\')
347: strcat(dir->filespec,"\\");
348: strcat(dir->filespec,"*.*");
349: dir->handle=_findfirst(dir->filespec,&dir->finddata);
350: if(dir->handle==-1) {
351: errno=ENOENT;
352: free(dir);
353: return(NULL);
354: }
355: return(dir);
356: }
357: struct dirent* readdir(DIR* dir)
358: {
359: if(dir==NULL)
360: return(NULL);
361: if(dir->end==TRUE)
362: return(NULL);
363: if(dir->handle==-1)
364: return(NULL);
365: sprintf(dir->dirent.d_name,"%.*s",sizeof(struct dirent)-1,dir->finddata.name);
366: if(_findnext(dir->handle,&dir->finddata)!=0)
367: dir->end=TRUE;
368: return(&dir->dirent);
369: }
370: int closedir (DIR* dir)
371: {
372: if(dir==NULL)
373: return(-1);
374: _findclose(dir->handle);
375: free(dir);
376: return(0);
377: }
378: void rewinddir(DIR* dir)
379: {
380: if(dir==NULL)
381: return;
382: _findclose(dir->handle);
383: dir->end=FALSE;
384: dir->handle=_findfirst(dir->filespec,&dir->finddata);
385: }
386: #endif /* defined(_MSC_VER) */
387:
388: /****************************************************************************/
389: /* Returns the time/date of the file in 'filename' in time_t (unix) format */
390: /****************************************************************************/
391: time_t DLLCALL fdate(const char* filename)
392: {
393: struct stat st;
394:
395: if(access(filename,0)==-1)
396: return(-1);
397:
398: if(stat(filename, &st)!=0)
399: return(-1);
400:
401: return(st.st_mtime);
402: }
403:
404: /****************************************************************************/
405: /* Change the access and modification times for specified filename */
406: /****************************************************************************/
407: int DLLCALL setfdate(const char* filename, time_t t)
408: {
409: struct utimbuf ut;
410:
411: memset(&ut,0,sizeof(ut));
412:
413: ut.actime=t;
414: ut.modtime=t;
415:
416: return(utime(filename,&ut));
417: }
418:
419: /****************************************************************************/
420: /* Returns the length of the file in 'filename' */
1.1.1.2 ! root 421: /* or -1 if the file doesn't exist */
1.1 root 422: /****************************************************************************/
1.1.1.2 ! root 423: off_t DLLCALL flength(const char *filename)
1.1 root 424: {
425: #if defined(__BORLANDC__) && !defined(__unix__) /* stat() doesn't work right */
426:
427: long handle;
428: struct _finddata_t f;
429:
430: if(access((char*)filename,0)==-1)
1.1.1.2 ! root 431: return(-1);
1.1 root 432:
433: if((handle=_findfirst((char*)filename,&f))==-1)
434: return(-1);
435:
436: _findclose(handle);
437:
438: return(f.size);
439:
440: #else
441:
442: struct stat st;
443:
444: if(access(filename,0)==-1)
1.1.1.2 ! root 445: return(-1);
1.1 root 446:
447: if(stat(filename, &st)!=0)
1.1.1.2 ! root 448: return(-1);
1.1 root 449:
450: return(st.st_size);
451:
452: #endif
453: }
454:
455:
456: /****************************************************************************/
457: /* Checks the file system for the existence of one or more files. */
458: /* Returns TRUE if it exists, FALSE if it doesn't. */
459: /* 'filespec' may *NOT* contain wildcards! */
460: /****************************************************************************/
461: static BOOL fnameexist(const char *filename)
462: {
463: if(access(filename,0)==-1)
464: return(FALSE);
465: if(!isdir(filename))
466: return(TRUE);
467: return(FALSE);
468: }
469:
470: /****************************************************************************/
471: /* Checks the file system for the existence of one or more files. */
472: /* Returns TRUE if it exists, FALSE if it doesn't. */
473: /* 'filespec' may contain wildcards! */
474: /****************************************************************************/
475: BOOL DLLCALL fexist(const char *filespec)
476: {
477: #if defined(_WIN32)
478:
479: long handle;
480: struct _finddata_t f;
1.1.1.2 ! root 481: BOOL found;
1.1 root 482:
483: if(!strchr(filespec,'*') && !strchr(filespec,'?'))
484: return(fnameexist(filespec));
485:
486: if((handle=_findfirst((char*)filespec,&f))==-1)
487: return(FALSE);
1.1.1.2 ! root 488: found=TRUE;
! 489: while(f.attrib&_A_SUBDIR)
! 490: if(_findnext(handle,&f)!=0) {
! 491: found=FALSE;
! 492: break;
! 493: }
1.1 root 494:
495: _findclose(handle);
496:
1.1.1.2 ! root 497: return(found);
1.1 root 498:
499: #else /* Unix or OS/2 */
500:
501: /* portion by cmartin */
502:
503: glob_t g;
504: int c;
505:
506: if(!strchr(filespec,'*') && !strchr(filespec,'?'))
507: return(fnameexist(filespec));
508:
509: /* start the search */
510: glob(filespec, GLOB_MARK | GLOB_NOSORT, NULL, &g);
511:
512: if (!g.gl_pathc) {
513: /* no results */
514: globfree(&g);
515: return FALSE;
516: }
517:
518: /* make sure it's not a directory */
519: c = g.gl_pathc;
520: while (c--) {
521: if (*lastchar(g.gl_pathv[c]) != '/') {
522: globfree(&g);
523: return TRUE;
524: }
525: }
526:
527: globfree(&g);
528: return FALSE;
529:
530: #endif
531: }
532:
533: /****************************************************************************/
534: /* Fixes upper/lowercase filename for Unix file systems */
535: /****************************************************************************/
536: BOOL DLLCALL fexistcase(char *path)
537: {
538: #if defined(_WIN32)
539:
540: char* fname;
541: long handle;
542: struct _finddata_t f;
543:
544: if(access(path,0)==-1 && !strchr(path,'*') && !strchr(path,'?'))
545: return(FALSE);
546:
547: if((handle=_findfirst((char*)path,&f))==-1)
548: return(FALSE);
549:
550: _findclose(handle);
551:
552: if(f.attrib&_A_SUBDIR)
553: return(FALSE);
554:
555: fname=getfname(path); /* Find filename in path */
556: strcpy(fname,f.name); /* Correct filename */
557:
558: return(TRUE);
559:
560: #else /* Unix or OS/2 */
561:
562: char globme[MAX_PATH*4+1];
563: char fname[MAX_PATH+1];
564: char tmp[5];
565: char *p;
566: int i;
567: glob_t glb;
568:
1.1.1.2 ! root 569: if(path[0]==0) /* work around glibc bug 574274 */
! 570: return FALSE;
! 571:
1.1 root 572: if(!strchr(path,'*') && !strchr(path,'?') && fnameexist(path))
573: return(TRUE);
574:
575: SAFECOPY(globme,path);
576: p=getfname(globme);
577: SAFECOPY(fname,p);
578: *p=0;
579: for(i=0;fname[i];i++) {
580: if(isalpha(fname[i]))
581: sprintf(tmp,"[%c%c]",toupper(fname[i]),tolower(fname[i]));
582: else
583: sprintf(tmp,"%c",fname[i]);
584: strncat(globme,tmp,MAX_PATH*4);
585: }
586: #if 0
587: if(strcspn(path,"?*")!=strlen(path)) {
588: sprintf(path,"%.*s",MAX_PATH,globme);
589: return(fexist(path));
590: }
591: #endif
592:
593: if(glob(globme,GLOB_MARK,NULL,&glb) != 0)
594: return(FALSE);
595:
596: if(glb.gl_pathc>0) {
597: for(i=0;i<glb.gl_pathc;i++) {
598: if(*lastchar(glb.gl_pathv[i]) != '/')
599: break;
600: }
601: if(i<glb.gl_pathc) {
602: sprintf(path,"%.*s",MAX_PATH,glb.gl_pathv[i]);
603: globfree(&glb);
604: return TRUE;
605: }
606: }
607:
608: globfree(&glb);
609: return FALSE;
610:
611: #endif
612: }
613:
614: #if !defined(S_ISDIR)
615: #define S_ISDIR(x) ((x)&S_IFDIR)
616: #endif
617:
618: /****************************************************************************/
619: /* Returns TRUE if the filename specified is a directory */
620: /****************************************************************************/
621: BOOL DLLCALL isdir(const char *filename)
622: {
623: char path[MAX_PATH+1];
624: char* p;
625: struct stat st;
626:
627: SAFECOPY(path,filename);
628:
629: p=lastchar(path);
630: if(p!=path && IS_PATH_DELIM(*p)) { /* chop off trailing slash */
631: #if !defined(__unix__)
632: if(*(p-1)!=':') /* Don't change C:\ to C: */
633: #endif
634: *p=0;
635: }
636:
637: #if defined(__BORLANDC__) && !defined(__unix__) /* stat() doesn't work right */
638: if(stat(path, &st)!=0 || strchr(path,'*')!=NULL || strchr(path,'?')!=NULL)
639: #else
640: if(stat(path, &st)!=0)
641: #endif
642: return(FALSE);
643:
644: return(S_ISDIR(st.st_mode) ? TRUE : FALSE);
645: }
646:
647: /****************************************************************************/
648: /* Returns the attributes (mode) for specified 'filename' */
649: /****************************************************************************/
650: int DLLCALL getfattr(const char* filename)
651: {
652: #if defined(_WIN32)
653: long handle;
654: struct _finddata_t finddata;
655:
656: if((handle=_findfirst((char*)filename,&finddata))==-1) {
657: errno=ENOENT;
658: return(-1);
659: }
660: _findclose(handle);
661: return(finddata.attrib);
662: #else
663: struct stat st;
664:
665: if(stat(filename, &st)!=0) {
666: errno=ENOENT;
667: return(-1L);
668: }
669:
670: return(st.st_mode);
671: #endif
672: }
673:
674: #ifdef __unix__
1.1.1.2 ! root 675: int removecase(const char *path)
1.1 root 676: {
677: char inpath[MAX_PATH+1];
678: char fname[MAX_PATH*4+1];
679: char tmp[5];
680: char *p;
681: int i;
682:
683: if(strchr(path,'?') || strchr(path,'*'))
684: return(-1);
685: SAFECOPY(inpath,path);
686: p=getfname(inpath);
687: fname[0]=0;
688: for(i=0;p[i];i++) {
689: if(isalpha(p[i]))
690: sprintf(tmp,"[%c%c]",toupper(p[i]),tolower(p[i]));
691: else
692: sprintf(tmp,"%c",p[i]);
693: strncat(fname,tmp,MAX_PATH*4);
694: }
695: *p=0;
696:
697: return(delfiles(inpath,fname)?-1:0);
698: }
699: #endif
700:
701: /****************************************************************************/
702: /* Deletes all files in dir 'path' that match file spec 'spec' */
703: /****************************************************************************/
1.1.1.2 ! root 704: ulong DLLCALL delfiles(const char *inpath, const char *spec)
1.1 root 705: {
706: char path[MAX_PATH+1];
707: char lastch;
708: uint i,files=0;
709: glob_t g;
710:
711: lastch=*lastchar(inpath);
712: if(!IS_PATH_DELIM(lastch) && lastch)
713: sprintf(path,"%s%c",inpath,PATH_DELIM);
714: else
715: strcpy(path,inpath);
716: strcat(path,spec);
717: glob(path,0,NULL,&g);
718: for(i=0;i<g.gl_pathc;i++) {
719: if(isdir(g.gl_pathv[i]))
720: continue;
721: CHMOD(g.gl_pathv[i],S_IWRITE); /* Incase it's been marked RDONLY */
722: if(remove(g.gl_pathv[i])==0)
723: files++;
724: }
725: globfree(&g);
726: return(files);
727: }
728:
729: /****************************************************************************/
730: /* Return free disk space in bytes (up to a maximum of 4GB) */
731: /****************************************************************************/
732: #if defined(_WIN32)
733: typedef BOOL(WINAPI * GetDiskFreeSpaceEx_t)
734: (LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
735:
736: static int bit_num(ulong val)
737: {
738: int i;
739:
740: for(i=31;i>=0;i--)
741: if(val&(1<<i))
742: return(i);
743:
744: return(-1);
745: }
746: #endif
747:
748: /* Unit should be a power-of-2 (e.g. 1024 to report kilobytes) or 1 (to report bytes) */
749: static ulong getdiskspace(const char* path, ulong unit, BOOL freespace)
750: {
751: #if defined(_WIN32)
752: char root[16];
753: DWORD TotalNumberOfClusters;
754: DWORD NumberOfFreeClusters;
755: DWORD BytesPerSector;
756: DWORD SectorsPerCluster;
757: ULARGE_INTEGER avail;
758: ULARGE_INTEGER size;
759: static HINSTANCE hK32;
760: GetDiskFreeSpaceEx_t GetDiskFreeSpaceEx;
761:
762: if(hK32 == NULL)
763: hK32 = LoadLibrary("KERNEL32");
764: GetDiskFreeSpaceEx
765: = (GetDiskFreeSpaceEx_t)GetProcAddress(hK32,"GetDiskFreeSpaceExA");
766:
767: if (GetDiskFreeSpaceEx!=NULL) { /* Windows 95-OSR2 or later */
768: if(!GetDiskFreeSpaceEx(
769: path, /* pointer to the directory name */
770: &avail, /* receives the number of bytes on disk avail to the caller */
771: &size, /* receives the number of bytes on disk */
772: NULL)) /* receives the free bytes on disk */
773: return(0);
774:
775: if(freespace)
776: size=avail;
777:
778: if(unit>1)
779: size.QuadPart=Int64ShrlMod32(size.QuadPart,bit_num(unit));
780:
781: #if defined(_ANONYMOUS_STRUCT)
782: if(size.HighPart)
783: #else
784: if(size.u.HighPart)
785: #endif
786: return(0xffffffff); /* 4GB max */
787:
788: #if defined(_ANONYMOUS_STRUCT)
789: return(size.LowPart);
790: #else
791: return(size.u.LowPart);
792: #endif
793: }
794:
795: /* Windows 95 (old way), limited to 2GB */
796: sprintf(root,"%.3s",path);
797: if(!GetDiskFreeSpace(
798: root, /* pointer to root path */
799: &SectorsPerCluster, /* pointer to sectors per cluster */
800: &BytesPerSector, /* pointer to bytes per sector */
801: &NumberOfFreeClusters, /* pointer to number of free clusters */
802: &TotalNumberOfClusters /* pointer to total number of clusters */
803: ))
804: return(0);
805:
806: if(freespace)
807: TotalNumberOfClusters = NumberOfFreeClusters;
808: if(unit>1)
809: TotalNumberOfClusters/=unit;
810: return(TotalNumberOfClusters*SectorsPerCluster*BytesPerSector);
811:
812:
813: #elif defined(__solaris__) || (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 300000000 /* NetBSD 3.0 */))
814:
815: struct statvfs fs;
816: unsigned long blocks;
817:
818: if (statvfs(path, &fs) < 0)
819: return 0;
820:
821: if(freespace)
822: blocks=fs.f_bavail;
823: else
824: blocks=fs.f_blocks;
825:
826: if(unit>1)
827: blocks/=unit;
828: return fs.f_bsize * blocks;
829:
830: /* statfs is also used under FreeBSD (Though it *supports* statvfs() now too) */
831: #elif defined(__GLIBC__) || defined(BSD)
832:
833: struct statfs fs;
834: unsigned long blocks;
835:
836: if (statfs(path, &fs) < 0)
837: return 0;
838:
839: if(freespace)
840: blocks=fs.f_bavail;
841: else
842: blocks=fs.f_blocks;
843:
844: if(unit>1)
845: blocks/=unit;
846: return fs.f_bsize * blocks;
847:
848: #else
849:
850: fprintf(stderr,"\n*** !Missing getfreediskspace implementation ***\n");
851: return(0);
852:
853: #endif
854: }
855:
856: ulong DLLCALL getfreediskspace(const char* path, ulong unit)
857: {
858: return getdiskspace(path, unit, /* freespace? */TRUE);
859: }
860:
861: ulong DLLCALL getdisksize(const char* path, ulong unit)
862: {
863: return getdiskspace(path, unit, /* freespace? */FALSE);
864: }
865:
866: /****************************************************************************/
867: /* Resolves //, /./, and /../ in a path. Should work indetically to Windows */
868: /****************************************************************************/
869: #if defined(__unix__)
870: char * DLLCALL _fullpath(char *target, const char *path, size_t size) {
871: char *out;
872: char *p;
873:
874: if(target==NULL) {
875: if((target=malloc(MAX_PATH+1))==NULL) {
876: return(NULL);
877: }
878: }
879: out=target;
880: *out=0;
881:
882: if(*path != '/') {
883: if(*path == '~') {
884: p=getenv("HOME");
885: if(p==NULL || strlen(p)+strlen(path)>=size)
886: return(NULL);
887: strcpy(target,p);
888: out=strrchr(target,'\0');
889: path++;
890: }
891: else {
892: p=getcwd(NULL,size);
893: if(p==NULL || strlen(p)+strlen(path)>=size)
894: return(NULL);
895: strcpy(target,p);
896: free(p);
897: out=strrchr(target,'\0');
898: *(out++)='/';
899: *out=0;
900: out--;
901: }
902: }
903: strncat(target,path,size-1);
904:
905: /* if(stat(target,&sb))
906: return(NULL);
907: if(sb.st_mode&S_IFDIR)
908: strcat(target,"/"); */
909:
910: for(;*out;out++) {
911: while(*out=='/') {
912: if(*(out+1)=='/')
913: memmove(out,out+1,strlen(out));
914: else if(*(out+1)=='.' && (*(out+2)=='/' || *(out+2)==0))
915: memmove(out,out+2,strlen(out)-1);
916: else if(*(out+1)=='.' && *(out+2)=='.' && (*(out+3)=='/' || *(out+3)==0)) {
917: *out=0;
918: p=strrchr(target,'/');
919: if(p==NULL)
920: p=target;
921: memmove(p,out+3,strlen(out+3)+1);
922: out=p;
923: }
924: else {
925: out++;
926: }
927: }
928: }
929: return(target);
930: }
931: #endif
932:
933: /****************************************************************************/
934: /* Adds a trailing slash/backslash (path delimiter) on path strings */
935: /****************************************************************************/
936: char* DLLCALL backslash(char* path)
937: {
938: char* p;
939:
940: p=lastchar(path);
941:
942: if(*p && !IS_PATH_DELIM(*p)) {
943: #if defined(__unix__)
944: /* Convert trailing backslash to forwardslash on *nix */
945: if(*p!='\\')
946: #endif
947: p++;
948: *p=PATH_DELIM;
949: *(++p)=0;
950: }
951: return(path);
952: }
953:
954: /****************************************************************************/
955: /* Returns true if the specified filename an aboslute pathname */
956: /****************************************************************************/
957: BOOL DLLCALL isabspath(const char *filename)
958: {
959: char path[MAX_PATH+1];
960:
961: return(stricmp(filename,FULLPATH(path,filename,sizeof(path)))==0);
962: }
963:
964: /****************************************************************************/
965: /* Returns true if the specified filename is a full ("rooted") path */
966: /****************************************************************************/
967: BOOL DLLCALL isfullpath(const char* filename)
968: {
969: return(filename[0]=='/'
970: #ifdef WIN32
971: || filename[0]=='\\' || filename[1]==':'
972: #endif
973: );
974: }
975:
976: /****************************************************************************/
977: /* Matches file name against filespec */
978: /* Optionally not allowing * to match PATH_DELIM (for paths) */
979: /****************************************************************************/
1.1.1.2 ! root 980:
1.1 root 981: BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
982: {
983: char *specp;
984: char *fnamep;
1.1.1.2 ! root 985: char *wildend;
1.1 root 986:
987: specp=(char *)spec;
988: fnamep=(char *)fname;
989: for(;;specp++, fnamep++) {
990: switch(*specp) {
991: case '?':
992: if(!(*fnamep))
993: return(FALSE);
994: break;
995: case 0:
996: if(!*fnamep)
997: return(TRUE);
998: break;
999: case '*':
1000: while(*specp=='*')
1001: specp++;
1.1.1.2 ! root 1002: if(path) {
! 1003: for(wildend=fnamep; *wildend; wildend++) {
! 1004: if(IS_PATH_DELIM(*wildend)) {
! 1005: wildend--;
! 1006: break;
! 1007: }
! 1008: }
! 1009: }
! 1010: else
! 1011: wildend=strchr(fnamep, 0);
! 1012: for(;wildend >= fnamep;wildend--) {
! 1013: if(wildmatch(wildend, specp, path))
! 1014: return(TRUE);
1.1 root 1015: }
1.1.1.2 ! root 1016: return(FALSE);
1.1 root 1017: default:
1018: if(*specp != *fnamep)
1019: return(FALSE);
1020: }
1021: if(!(*specp && *fnamep))
1022: break;
1023: }
1024: while(*specp=='*')
1025: specp++;
1026: if(*specp==*fnamep)
1027: return(TRUE);
1028: return(FALSE);
1029: }
1030:
1031: /****************************************************************************/
1032: /* Matches file name against filespec, ignoring case */
1033: /****************************************************************************/
1034: BOOL DLLCALL wildmatchi(const char *fname, const char *spec, BOOL path)
1035: {
1036: char* s1;
1037: char* s2;
1038: BOOL result;
1039:
1040: if((s1=strdup(fname))==NULL)
1041: return(FALSE);
1042: if((s2=strdup(spec))==NULL) {
1043: free(s1);
1044: return(FALSE);
1045: }
1046: strupr(s1);
1047: strupr(s2);
1048: result = wildmatch(s1, s2, path);
1049: free(s1);
1050: free(s2);
1051: return(result);
1052: }
1053:
1054: /****************************************************************************/
1055: /* Creates all the necessary directories in the specified path */
1056: /****************************************************************************/
1.1.1.2 ! root 1057: int DLLCALL mkpath(const char* path)
1.1 root 1058: {
1059: const char* p=path;
1060: const char* tp;
1061: const char* sep=
1062: #ifdef _WIN32
1063: "\\"
1064: #endif
1065: "/";
1066: char dir[MAX_PATH+1];
1067: int result=0;
1068:
1069: #ifdef _WIN32
1070: if(p[1]==':') /* Skip drive letter, if specified */
1071: p+=2;
1072: #endif
1073:
1074: while(*p) {
1075: SKIP_CHARSET(p,sep);
1076: if(*p==0)
1077: break;
1078: tp=p;
1079: FIND_CHARSET(tp,sep);
1080: safe_snprintf(dir,sizeof(dir),"%.*s",tp-path, path);
1081: if(!isdir(dir)) {
1082: if((result=MKDIR(dir))!=0)
1083: break;
1084: }
1085: p=tp;
1086: }
1087:
1088: return(result);
1089: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.