|
|
1.1 root 1: /* dirwrap.c */
2:
3: /* Directory-related system-call wrappers */
4:
5: /* $Id: dirwrap.c,v 1.70 2006/08/24 00:20:48 deuce Exp $ */
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: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
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:
178: if(_dos_findfirst((char*)pattern,_A_NORMAL,&ff)!=0)
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) {
239: if((flags&GLOB_PERIOD || ff.name[0]!='.') &&
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:
303: /****************************************************************************/
304: /* POSIX directory operations using Microsoft _findfirst/next API. */
305: /****************************************************************************/
306: #if defined(_MSC_VER) || defined(__DMC__)
307: DIR* opendir(const char* dirname)
308: {
309: DIR* dir;
310:
311: if((dir=(DIR*)calloc(1,sizeof(DIR)))==NULL) {
312: errno=ENOMEM;
313: return(NULL);
314: }
315: sprintf(dir->filespec,"%.*s",sizeof(dir->filespec)-5,dirname);
316: if(*dir->filespec && dir->filespec[strlen(dir->filespec)-1]!='\\')
317: strcat(dir->filespec,"\\");
318: strcat(dir->filespec,"*.*");
319: dir->handle=_findfirst(dir->filespec,&dir->finddata);
320: if(dir->handle==-1) {
321: errno=ENOENT;
322: free(dir);
323: return(NULL);
324: }
325: return(dir);
326: }
327: struct dirent* readdir(DIR* dir)
328: {
329: if(dir==NULL)
330: return(NULL);
331: if(dir->end==TRUE)
332: return(NULL);
333: if(dir->handle==-1)
334: return(NULL);
335: sprintf(dir->dirent.d_name,"%.*s",sizeof(struct dirent)-1,dir->finddata.name);
336: if(_findnext(dir->handle,&dir->finddata)!=0)
337: dir->end=TRUE;
338: return(&dir->dirent);
339: }
340: int closedir (DIR* dir)
341: {
342: if(dir==NULL)
343: return(-1);
344: _findclose(dir->handle);
345: free(dir);
346: return(0);
347: }
348: void rewinddir(DIR* dir)
349: {
350: if(dir==NULL)
351: return;
352: _findclose(dir->handle);
353: dir->end=FALSE;
354: dir->handle=_findfirst(dir->filespec,&dir->finddata);
355: }
356: #endif /* defined(_MSC_VER) */
357:
358: /****************************************************************************/
359: /* Returns the time/date of the file in 'filename' in time_t (unix) format */
360: /****************************************************************************/
361: time_t DLLCALL fdate(const char* filename)
362: {
363: struct stat st;
364:
365: if(access(filename,0)==-1)
366: return(-1);
367:
368: if(stat(filename, &st)!=0)
369: return(-1);
370:
371: return(st.st_mtime);
372: }
373:
374: /****************************************************************************/
375: /* Change the access and modification times for specified filename */
376: /****************************************************************************/
377: int DLLCALL setfdate(const char* filename, time_t t)
378: {
379: struct utimbuf ut;
380:
381: memset(&ut,0,sizeof(ut));
382:
383: ut.actime=t;
384: ut.modtime=t;
385:
386: return(utime(filename,&ut));
387: }
388:
389: /****************************************************************************/
390: /* Returns the length of the file in 'filename' */
391: /****************************************************************************/
392: long DLLCALL flength(const char *filename)
393: {
394: #if defined(__BORLANDC__) && !defined(__unix__) /* stat() doesn't work right */
395:
396: long handle;
397: struct _finddata_t f;
398:
399: if(access((char*)filename,0)==-1)
400: return(-1L);
401:
402: if((handle=_findfirst((char*)filename,&f))==-1)
403: return(-1);
404:
405: _findclose(handle);
406:
407: return(f.size);
408:
409: #else
410:
411: struct stat st;
412:
413: if(access(filename,0)==-1)
414: return(-1L);
415:
416: if(stat(filename, &st)!=0)
417: return(-1L);
418:
419: return(st.st_size);
420:
421: #endif
422: }
423:
424:
425: /****************************************************************************/
426: /* Checks the file system for the existence of one or more files. */
427: /* Returns TRUE if it exists, FALSE if it doesn't. */
428: /* 'filespec' may *NOT* contain wildcards! */
429: /****************************************************************************/
430: static BOOL fnameexist(const char *filename)
431: {
432: if(access(filename,0)==-1)
433: return(FALSE);
434: if(!isdir(filename))
435: return(TRUE);
436: return(FALSE);
437: }
438:
439: /****************************************************************************/
440: /* Checks the file system for the existence of one or more files. */
441: /* Returns TRUE if it exists, FALSE if it doesn't. */
442: /* 'filespec' may contain wildcards! */
443: /****************************************************************************/
444: BOOL DLLCALL fexist(const char *filespec)
445: {
446: #if defined(_WIN32)
447:
448: long handle;
449: struct _finddata_t f;
450:
451: if(!strchr(filespec,'*') && !strchr(filespec,'?'))
452: return(fnameexist(filespec));
453:
454: if((handle=_findfirst((char*)filespec,&f))==-1)
455: return(FALSE);
456:
457: _findclose(handle);
458:
459: if(f.attrib&_A_SUBDIR)
460: return(FALSE);
461:
462: return(TRUE);
463:
464: #else /* Unix or OS/2 */
465:
466: /* portion by cmartin */
467:
468: glob_t g;
469: int c;
470:
471: if(!strchr(filespec,'*') && !strchr(filespec,'?'))
472: return(fnameexist(filespec));
473:
474: /* start the search */
475: glob(filespec, GLOB_MARK | GLOB_NOSORT, NULL, &g);
476:
477: if (!g.gl_pathc) {
478: /* no results */
479: globfree(&g);
480: return FALSE;
481: }
482:
483: /* make sure it's not a directory */
484: c = g.gl_pathc;
485: while (c--) {
486: if (*lastchar(g.gl_pathv[c]) != '/') {
487: globfree(&g);
488: return TRUE;
489: }
490: }
491:
492: globfree(&g);
493: return FALSE;
494:
495: #endif
496: }
497:
498: /****************************************************************************/
499: /* Fixes upper/lowercase filename for Unix file systems */
500: /****************************************************************************/
501: BOOL DLLCALL fexistcase(char *path)
502: {
503: #if defined(_WIN32)
504:
505: char* fname;
506: long handle;
507: struct _finddata_t f;
508:
509: if(access(path,0)==-1 && !strchr(path,'*') && !strchr(path,'?'))
510: return(FALSE);
511:
512: if((handle=_findfirst((char*)path,&f))==-1)
513: return(FALSE);
514:
515: _findclose(handle);
516:
517: if(f.attrib&_A_SUBDIR)
518: return(FALSE);
519:
520: fname=getfname(path); /* Find filename in path */
521: strcpy(fname,f.name); /* Correct filename */
522:
523: return(TRUE);
524:
525: #else /* Unix or OS/2 */
526:
527: char globme[MAX_PATH*4+1];
528: char fname[MAX_PATH+1];
529: char tmp[5];
530: char *p;
531: int i;
532: glob_t glb;
533:
534: if(!strchr(path,'*') && !strchr(path,'?') && fnameexist(path))
535: return(TRUE);
536:
537: SAFECOPY(globme,path);
538: p=getfname(globme);
539: SAFECOPY(fname,p);
540: *p=0;
541: for(i=0;fname[i];i++) {
542: if(isalpha(fname[i]))
543: sprintf(tmp,"[%c%c]",toupper(fname[i]),tolower(fname[i]));
544: else
545: sprintf(tmp,"%c",fname[i]);
546: strncat(globme,tmp,MAX_PATH*4);
547: }
548: #if 0
549: if(strcspn(path,"?*")!=strlen(path)) {
550: sprintf(path,"%.*s",MAX_PATH,globme);
551: return(fexist(path));
552: }
553: #endif
554:
555: if(glob(globme,GLOB_MARK,NULL,&glb) != 0)
556: return(FALSE);
557:
558: if(glb.gl_pathc>0) {
559: for(i=0;i<glb.gl_pathc;i++) {
560: if(*lastchar(glb.gl_pathv[i]) != '/')
561: break;
562: }
563: if(i<glb.gl_pathc) {
564: sprintf(path,"%.*s",MAX_PATH,glb.gl_pathv[i]);
565: globfree(&glb);
566: return TRUE;
567: }
568: }
569:
570: globfree(&glb);
571: return FALSE;
572:
573: #endif
574: }
575:
576: #if !defined(S_ISDIR)
577: #define S_ISDIR(x) ((x)&S_IFDIR)
578: #endif
579:
580: /****************************************************************************/
581: /* Returns TRUE if the filename specified is a directory */
582: /****************************************************************************/
583: BOOL DLLCALL isdir(const char *filename)
584: {
585: char path[MAX_PATH+1];
586: char* p;
587: struct stat st;
588:
589: SAFECOPY(path,filename);
590:
591: p=lastchar(path);
592: if(p!=path && IS_PATH_DELIM(*p)) { /* chop off trailing slash */
593: #if !defined(__unix__)
594: if(*(p-1)!=':') /* Don't change C:\ to C: */
595: #endif
596: *p=0;
597: }
598:
599: #if defined(__BORLANDC__) && !defined(__unix__) /* stat() doesn't work right */
600: if(stat(path, &st)!=0 || strchr(path,'*')!=NULL || strchr(path,'?')!=NULL)
601: #else
602: if(stat(path, &st)!=0)
603: #endif
604: return(FALSE);
605:
606: return(S_ISDIR(st.st_mode) ? TRUE : FALSE);
607: }
608:
609: /****************************************************************************/
610: /* Returns the attributes (mode) for specified 'filename' */
611: /****************************************************************************/
612: int DLLCALL getfattr(const char* filename)
613: {
614: #if defined(_WIN32)
615: long handle;
616: struct _finddata_t finddata;
617:
618: if((handle=_findfirst((char*)filename,&finddata))==-1) {
619: errno=ENOENT;
620: return(-1);
621: }
622: _findclose(handle);
623: return(finddata.attrib);
624: #else
625: struct stat st;
626:
627: if(stat(filename, &st)!=0) {
628: errno=ENOENT;
629: return(-1L);
630: }
631:
632: return(st.st_mode);
633: #endif
634: }
635:
636: #ifdef __unix__
637: int removecase(char *path)
638: {
639: char inpath[MAX_PATH+1];
640: char fname[MAX_PATH*4+1];
641: char tmp[5];
642: char *p;
643: int i;
644:
645: if(strchr(path,'?') || strchr(path,'*'))
646: return(-1);
647: SAFECOPY(inpath,path);
648: p=getfname(inpath);
649: fname[0]=0;
650: for(i=0;p[i];i++) {
651: if(isalpha(p[i]))
652: sprintf(tmp,"[%c%c]",toupper(p[i]),tolower(p[i]));
653: else
654: sprintf(tmp,"%c",p[i]);
655: strncat(fname,tmp,MAX_PATH*4);
656: }
657: *p=0;
658:
659: return(delfiles(inpath,fname)?-1:0);
660: }
661: #endif
662:
663: /****************************************************************************/
664: /* Deletes all files in dir 'path' that match file spec 'spec' */
665: /****************************************************************************/
666: ulong DLLCALL delfiles(char *inpath, char *spec)
667: {
668: char path[MAX_PATH+1];
669: char lastch;
670: uint i,files=0;
671: glob_t g;
672:
673: lastch=*lastchar(inpath);
674: if(!IS_PATH_DELIM(lastch) && lastch)
675: sprintf(path,"%s%c",inpath,PATH_DELIM);
676: else
677: strcpy(path,inpath);
678: strcat(path,spec);
679: glob(path,0,NULL,&g);
680: for(i=0;i<g.gl_pathc;i++) {
681: if(isdir(g.gl_pathv[i]))
682: continue;
683: CHMOD(g.gl_pathv[i],S_IWRITE); /* Incase it's been marked RDONLY */
684: if(remove(g.gl_pathv[i])==0)
685: files++;
686: }
687: globfree(&g);
688: return(files);
689: }
690:
691: /****************************************************************************/
692: /* Return free disk space in bytes (up to a maximum of 4GB) */
693: /****************************************************************************/
694: #if defined(_WIN32)
695: typedef BOOL(WINAPI * GetDiskFreeSpaceEx_t)
696: (LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
697:
698: static int bit_num(ulong val)
699: {
700: int i;
701:
702: for(i=31;i>=0;i--)
703: if(val&(1<<i))
704: return(i);
705:
706: return(-1);
707: }
708: #endif
709:
710: /* Unit should be a power-of-2 (e.g. 1024 to report kilobytes) or 1 (to report bytes) */
711: static ulong getdiskspace(const char* path, ulong unit, BOOL freespace)
712: {
713: #if defined(_WIN32)
714: char root[16];
715: DWORD TotalNumberOfClusters;
716: DWORD NumberOfFreeClusters;
717: DWORD BytesPerSector;
718: DWORD SectorsPerCluster;
719: ULARGE_INTEGER avail;
720: ULARGE_INTEGER size;
721: static HINSTANCE hK32;
722: GetDiskFreeSpaceEx_t GetDiskFreeSpaceEx;
723:
724: if(hK32 == NULL)
725: hK32 = LoadLibrary("KERNEL32");
726: GetDiskFreeSpaceEx
727: = (GetDiskFreeSpaceEx_t)GetProcAddress(hK32,"GetDiskFreeSpaceExA");
728:
729: if (GetDiskFreeSpaceEx!=NULL) { /* Windows 95-OSR2 or later */
730: if(!GetDiskFreeSpaceEx(
731: path, /* pointer to the directory name */
732: &avail, /* receives the number of bytes on disk avail to the caller */
733: &size, /* receives the number of bytes on disk */
734: NULL)) /* receives the free bytes on disk */
735: return(0);
736:
737: if(freespace)
738: size=avail;
739:
740: if(unit>1)
741: size.QuadPart=Int64ShrlMod32(size.QuadPart,bit_num(unit));
742:
743: #if defined(_ANONYMOUS_STRUCT)
744: if(size.HighPart)
745: #else
746: if(size.u.HighPart)
747: #endif
748: return(0xffffffff); /* 4GB max */
749:
750: #if defined(_ANONYMOUS_STRUCT)
751: return(size.LowPart);
752: #else
753: return(size.u.LowPart);
754: #endif
755: }
756:
757: /* Windows 95 (old way), limited to 2GB */
758: sprintf(root,"%.3s",path);
759: if(!GetDiskFreeSpace(
760: root, /* pointer to root path */
761: &SectorsPerCluster, /* pointer to sectors per cluster */
762: &BytesPerSector, /* pointer to bytes per sector */
763: &NumberOfFreeClusters, /* pointer to number of free clusters */
764: &TotalNumberOfClusters /* pointer to total number of clusters */
765: ))
766: return(0);
767:
768: if(freespace)
769: TotalNumberOfClusters = NumberOfFreeClusters;
770: if(unit>1)
771: TotalNumberOfClusters/=unit;
772: return(TotalNumberOfClusters*SectorsPerCluster*BytesPerSector);
773:
774:
775: #elif defined(__solaris__) || (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 300000000 /* NetBSD 3.0 */))
776:
777: struct statvfs fs;
778: unsigned long blocks;
779:
780: if (statvfs(path, &fs) < 0)
781: return 0;
782:
783: if(freespace)
784: blocks=fs.f_bavail;
785: else
786: blocks=fs.f_blocks;
787:
788: if(unit>1)
789: blocks/=unit;
790: return fs.f_bsize * blocks;
791:
792: /* statfs is also used under FreeBSD (Though it *supports* statvfs() now too) */
793: #elif defined(__GLIBC__) || defined(BSD)
794:
795: struct statfs fs;
796: unsigned long blocks;
797:
798: if (statfs(path, &fs) < 0)
799: return 0;
800:
801: if(freespace)
802: blocks=fs.f_bavail;
803: else
804: blocks=fs.f_blocks;
805:
806: if(unit>1)
807: blocks/=unit;
808: return fs.f_bsize * blocks;
809:
810: #else
811:
812: fprintf(stderr,"\n*** !Missing getfreediskspace implementation ***\n");
813: return(0);
814:
815: #endif
816: }
817:
818: ulong DLLCALL getfreediskspace(const char* path, ulong unit)
819: {
820: return getdiskspace(path, unit, /* freespace? */TRUE);
821: }
822:
823: ulong DLLCALL getdisksize(const char* path, ulong unit)
824: {
825: return getdiskspace(path, unit, /* freespace? */FALSE);
826: }
827:
828: /****************************************************************************/
829: /* Resolves //, /./, and /../ in a path. Should work indetically to Windows */
830: /****************************************************************************/
831: #if defined(__unix__)
832: char * DLLCALL _fullpath(char *target, const char *path, size_t size) {
833: char *out;
834: char *p;
835:
836: if(target==NULL) {
837: if((target=malloc(MAX_PATH+1))==NULL) {
838: return(NULL);
839: }
840: }
841: out=target;
842: *out=0;
843:
844: if(*path != '/') {
845: if(*path == '~') {
846: p=getenv("HOME");
847: if(p==NULL || strlen(p)+strlen(path)>=size)
848: return(NULL);
849: strcpy(target,p);
850: out=strrchr(target,'\0');
851: path++;
852: }
853: else {
854: p=getcwd(NULL,size);
855: if(p==NULL || strlen(p)+strlen(path)>=size)
856: return(NULL);
857: strcpy(target,p);
858: free(p);
859: out=strrchr(target,'\0');
860: *(out++)='/';
861: *out=0;
862: out--;
863: }
864: }
865: strncat(target,path,size-1);
866:
867: /* if(stat(target,&sb))
868: return(NULL);
869: if(sb.st_mode&S_IFDIR)
870: strcat(target,"/"); */
871:
872: for(;*out;out++) {
873: while(*out=='/') {
874: if(*(out+1)=='/')
875: memmove(out,out+1,strlen(out));
876: else if(*(out+1)=='.' && (*(out+2)=='/' || *(out+2)==0))
877: memmove(out,out+2,strlen(out)-1);
878: else if(*(out+1)=='.' && *(out+2)=='.' && (*(out+3)=='/' || *(out+3)==0)) {
879: *out=0;
880: p=strrchr(target,'/');
881: if(p==NULL)
882: p=target;
883: memmove(p,out+3,strlen(out+3)+1);
884: out=p;
885: }
886: else {
887: out++;
888: }
889: }
890: }
891: return(target);
892: }
893: #endif
894:
895: /****************************************************************************/
896: /* Adds a trailing slash/backslash (path delimiter) on path strings */
897: /****************************************************************************/
898: char* DLLCALL backslash(char* path)
899: {
900: char* p;
901:
902: p=lastchar(path);
903:
904: if(*p && !IS_PATH_DELIM(*p)) {
905: #if defined(__unix__)
906: /* Convert trailing backslash to forwardslash on *nix */
907: if(*p!='\\')
908: #endif
909: p++;
910: *p=PATH_DELIM;
911: *(++p)=0;
912: }
913: return(path);
914: }
915:
916: /****************************************************************************/
917: /* Returns true if the specified filename an aboslute pathname */
918: /****************************************************************************/
919: BOOL DLLCALL isabspath(const char *filename)
920: {
921: char path[MAX_PATH+1];
922:
923: return(stricmp(filename,FULLPATH(path,filename,sizeof(path)))==0);
924: }
925:
926: /****************************************************************************/
927: /* Returns true if the specified filename is a full ("rooted") path */
928: /****************************************************************************/
929: BOOL DLLCALL isfullpath(const char* filename)
930: {
931: return(filename[0]=='/'
932: #ifdef WIN32
933: || filename[0]=='\\' || filename[1]==':'
934: #endif
935: );
936: }
937:
938: /****************************************************************************/
939: /* Matches file name against filespec */
940: /* Optionally not allowing * to match PATH_DELIM (for paths) */
941: /****************************************************************************/
942: BOOL DLLCALL wildmatch(const char *fname, const char *spec, BOOL path)
943: {
944: char *specp;
945: char *fnamep;
946:
947: specp=(char *)spec;
948: fnamep=(char *)fname;
949: for(;;specp++, fnamep++) {
950: switch(*specp) {
951: case '?':
952: if(!(*fnamep))
953: return(FALSE);
954: break;
955: case 0:
956: if(!*fnamep)
957: return(TRUE);
958: break;
959: case '*':
960: while(*specp=='*')
961: specp++;
962: for(;*fnamep!=*specp && *fnamep;fnamep++) {
963: if(path && IS_PATH_DELIM(*fnamep))
964: return(FALSE);
965: }
966: default:
967: if(*specp != *fnamep)
968: return(FALSE);
969: }
970: if(!(*specp && *fnamep))
971: break;
972: }
973: while(*specp=='*')
974: specp++;
975: if(*specp==*fnamep)
976: return(TRUE);
977: return(FALSE);
978: }
979:
980: /****************************************************************************/
981: /* Matches file name against filespec, ignoring case */
982: /****************************************************************************/
983: BOOL DLLCALL wildmatchi(const char *fname, const char *spec, BOOL path)
984: {
985: char* s1;
986: char* s2;
987: BOOL result;
988:
989: if((s1=strdup(fname))==NULL)
990: return(FALSE);
991: if((s2=strdup(spec))==NULL) {
992: free(s1);
993: return(FALSE);
994: }
995: strupr(s1);
996: strupr(s2);
997: result = wildmatch(s1, s2, path);
998: free(s1);
999: free(s2);
1000: return(result);
1001: }
1002:
1003: /****************************************************************************/
1004: /* Creates all the necessary directories in the specified path */
1005: /****************************************************************************/
1006: int DLLCALL mkdirs(const char* path)
1007: {
1008: const char* p=path;
1009: const char* tp;
1010: const char* sep=
1011: #ifdef _WIN32
1012: "\\"
1013: #endif
1014: "/";
1015: char dir[MAX_PATH+1];
1016: int result=0;
1017:
1018: #ifdef _WIN32
1019: if(p[1]==':') /* Skip drive letter, if specified */
1020: p+=2;
1021: #endif
1022:
1023: while(*p) {
1024: SKIP_CHARSET(p,sep);
1025: if(*p==0)
1026: break;
1027: tp=p;
1028: FIND_CHARSET(tp,sep);
1029: safe_snprintf(dir,sizeof(dir),"%.*s",tp-path, path);
1030: if(!isdir(dir)) {
1031: if((result=MKDIR(dir))!=0)
1032: break;
1033: }
1034: p=tp;
1035: }
1036:
1037: return(result);
1038: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.