Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * Reorganised mar-01 nzc 00027 * Some really low-level file thingies. 00028 */ 00029 00035 #include <sys/types.h> 00036 #include <stdio.h> 00037 #include <stdlib.h> 00038 00039 #ifndef WIN32 00040 #include <dirent.h> 00041 #endif 00042 00043 #include <time.h> 00044 #include <sys/stat.h> 00045 00046 #if defined (__sun__) || defined (__sun) || defined (__NetBSD__) 00047 #include <sys/statvfs.h> /* Other modern unix os's should probably use this also */ 00048 #elif !defined(__FreeBSD__) && !defined(linux) && (defined(__sparc) || defined(__sparc__)) 00049 #include <sys/statfs.h> 00050 #endif 00051 00052 #if defined (__FreeBSD__) || defined (__OpenBSD__) 00053 #include <sys/param.h> 00054 #include <sys/mount.h> 00055 #endif 00056 00057 #if defined(linux) || defined(__CYGWIN32__) || defined(__hpux) || defined(__GNU__) || defined(__GLIBC__) 00058 #include <sys/vfs.h> 00059 #endif 00060 00061 #ifdef __APPLE__ 00062 /* For statfs */ 00063 #include <sys/param.h> 00064 #include <sys/mount.h> 00065 #endif /* __APPLE__ */ 00066 00067 00068 #include <fcntl.h> 00069 #include <string.h> /* strcpy etc.. */ 00070 00071 #ifndef WIN32 00072 #include <sys/ioctl.h> 00073 #include <unistd.h> /* */ 00074 #include <pwd.h> 00075 #endif 00076 00077 #ifdef WIN32 00078 #include <io.h> 00079 #include <direct.h> 00080 #include "BLI_winstuff.h" 00081 #endif 00082 00083 00084 /* lib includes */ 00085 #include "MEM_guardedalloc.h" 00086 00087 #include "DNA_listBase.h" 00088 00089 #include "BLI_fileops.h" 00090 #include "BLI_listbase.h" 00091 #include "BLI_linklist.h" 00092 #include "BLI_string.h" 00093 00094 #include "BKE_utildefines.h" 00095 00096 /* vars: */ 00097 static int totnum,actnum; 00098 static struct direntry *files; 00099 00100 static struct ListBase dirbase_={NULL, NULL}; 00101 static struct ListBase *dirbase = &dirbase_; 00102 00103 /* can return NULL when the size is not big enough */ 00104 char *BLI_current_working_dir(char *dir, const int maxncpy) 00105 { 00106 const char *pwd= getenv("PWD"); 00107 if (pwd){ 00108 BLI_strncpy(dir, pwd, maxncpy); 00109 return dir; 00110 } 00111 00112 return getcwd(dir, maxncpy); 00113 } 00114 00115 00116 static int bli_compare(struct direntry *entry1, struct direntry *entry2) 00117 { 00118 /* type is equal to stat.st_mode */ 00119 00120 if (S_ISDIR(entry1->type)){ 00121 if (S_ISDIR(entry2->type)==0) return (-1); 00122 } else{ 00123 if (S_ISDIR(entry2->type)) return (1); 00124 } 00125 if (S_ISREG(entry1->type)){ 00126 if (S_ISREG(entry2->type)==0) return (-1); 00127 } else{ 00128 if (S_ISREG(entry2->type)) return (1); 00129 } 00130 if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); 00131 if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); 00132 00133 /* make sure "." and ".." are always first */ 00134 if( strcmp(entry1->relname, ".")==0 ) return (-1); 00135 if( strcmp(entry2->relname, ".")==0 ) return (1); 00136 if( strcmp(entry1->relname, "..")==0 ) return (-1); 00137 if( strcmp(entry2->relname, "..")==0 ) return (1); 00138 00139 return (BLI_natstrcmp(entry1->relname,entry2->relname)); 00140 } 00141 00142 00143 double BLI_dir_free_space(const char *dir) 00144 { 00145 #ifdef WIN32 00146 DWORD sectorspc, bytesps, freec, clusters; 00147 char tmp[4]; 00148 00149 tmp[0]='\\'; tmp[1]=0; /* Just a failsafe */ 00150 if (dir[0]=='/' || dir[0]=='\\') { 00151 tmp[0]='\\'; 00152 tmp[1]=0; 00153 } else if (dir[1]==':') { 00154 tmp[0]=dir[0]; 00155 tmp[1]=':'; 00156 tmp[2]='\\'; 00157 tmp[3]=0; 00158 } 00159 00160 GetDiskFreeSpace(tmp,§orspc, &bytesps, &freec, &clusters); 00161 00162 return (double) (freec*bytesps*sectorspc); 00163 #else 00164 00165 #if defined (__sun__) || defined (__sun) || defined (__NetBSD__) 00166 struct statvfs disk; 00167 #else 00168 struct statfs disk; 00169 #endif 00170 char name[FILE_MAXDIR],*slash; 00171 int len = strlen(dir); 00172 00173 if (len >= FILE_MAXDIR) /* path too long */ 00174 return -1; 00175 00176 strcpy(name,dir); 00177 00178 if(len){ 00179 slash = strrchr(name,'/'); 00180 if (slash) slash[1] = 0; 00181 } else strcpy(name,"/"); 00182 00183 #if defined (__FreeBSD__) || defined (linux) || defined (__OpenBSD__) || defined (__APPLE__) || defined(__GNU__) || defined(__GLIBC__) 00184 if (statfs(name, &disk)) return(-1); 00185 #endif 00186 00187 #if defined (__sun__) || defined (__sun) || defined (__NetBSD__) 00188 if (statvfs(name, &disk)) return(-1); 00189 #elif !defined(__FreeBSD__) && !defined(linux) && (defined(__sparc) || defined(__sparc__)) 00190 /* WARNING - This may not be supported by geeneric unix os's - Campbell */ 00191 if (statfs(name, &disk, sizeof(struct statfs), 0)) return(-1); 00192 #endif 00193 00194 return ( ((double) disk.f_bsize) * ((double) disk.f_bfree)); 00195 #endif 00196 } 00197 00198 static void bli_builddir(const char *dirname, const char *relname) 00199 { 00200 struct dirent *fname; 00201 struct dirlink *dlink; 00202 int rellen, newnum = 0; 00203 char buf[256]; 00204 DIR *dir; 00205 00206 BLI_strncpy(buf, relname, sizeof(buf)); 00207 rellen=strlen(relname); 00208 00209 if (rellen){ 00210 buf[rellen]='/'; 00211 rellen++; 00212 } 00213 00214 if (chdir(dirname) == -1){ 00215 perror(dirname); 00216 return; 00217 } 00218 00219 if ( (dir = (DIR *)opendir(".")) ){ 00220 while ((fname = (struct dirent*) readdir(dir)) != NULL) { 00221 dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); 00222 if (dlink){ 00223 BLI_strncpy(buf + rellen ,fname->d_name, sizeof(buf) - rellen); 00224 dlink->name = BLI_strdup(buf); 00225 BLI_addhead(dirbase,dlink); 00226 newnum++; 00227 } 00228 } 00229 00230 if (newnum){ 00231 00232 if(files) { 00233 void *tmp= realloc(files, (totnum+newnum) * sizeof(struct direntry)); 00234 if(tmp) { 00235 files= (struct direntry *)tmp; 00236 } 00237 else { /* realloc fail */ 00238 free(files); 00239 files= NULL; 00240 } 00241 } 00242 00243 if(files==NULL) 00244 files=(struct direntry *)malloc(newnum * sizeof(struct direntry)); 00245 00246 if (files){ 00247 dlink = (struct dirlink *) dirbase->first; 00248 while(dlink){ 00249 memset(&files[actnum], 0 , sizeof(struct direntry)); 00250 files[actnum].relname = dlink->name; 00251 files[actnum].path = BLI_strdupcat(dirname, dlink->name); 00252 // use 64 bit file size, only needed for WIN32 and WIN64. 00253 // Excluding other than current MSVC compiler until able to test. 00254 #if (defined(WIN32) || defined(WIN64)) && (_MSC_VER>=1500) 00255 _stat64(dlink->name,&files[actnum].s); 00256 #elif defined(__MINGW32__) 00257 _stati64(dlink->name,&files[actnum].s); 00258 #else 00259 stat(dlink->name,&files[actnum].s); 00260 #endif 00261 files[actnum].type=files[actnum].s.st_mode; 00262 files[actnum].flags = 0; 00263 totnum++; 00264 actnum++; 00265 dlink = dlink->next; 00266 } 00267 } else{ 00268 printf("Couldn't get memory for dir\n"); 00269 exit(1); 00270 } 00271 00272 BLI_freelist(dirbase); 00273 if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *,const void*))bli_compare); 00274 } else { 00275 printf("%s empty directory\n",dirname); 00276 } 00277 00278 closedir(dir); 00279 } else { 00280 printf("%s non-existant directory\n",dirname); 00281 } 00282 } 00283 00284 static void bli_adddirstrings(void) 00285 { 00286 char datum[100]; 00287 char buf[512]; 00288 char size[250]; 00289 static const char * types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; 00290 int num, mode; 00291 #ifdef WIN32 00292 __int64 st_size; 00293 #else 00294 off_t st_size; 00295 #endif 00296 00297 struct direntry * file; 00298 struct tm *tm; 00299 time_t zero= 0; 00300 00301 for(num=0, file= files; num<actnum; num++, file++){ 00302 #ifdef WIN32 00303 mode = 0; 00304 BLI_strncpy(file->mode1, types[0], sizeof(file->mode1)); 00305 BLI_strncpy(file->mode2, types[0], sizeof(file->mode2)); 00306 BLI_strncpy(file->mode3, types[0], sizeof(file->mode3)); 00307 #else 00308 mode = file->s.st_mode; 00309 00310 BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1)); 00311 BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2)); 00312 BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3)); 00313 00314 if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2]=='-'))file->mode2[2]='l'; 00315 00316 if (mode & (S_ISUID | S_ISGID)){ 00317 if (file->mode1[2]=='x') file->mode1[2]='s'; 00318 else file->mode1[2]='S'; 00319 00320 if (file->mode2[2]=='x')file->mode2[2]='s'; 00321 } 00322 00323 if (mode & S_ISVTX){ 00324 if (file->mode3[2] == 'x') file->mode3[2] = 't'; 00325 else file->mode3[2] = 'T'; 00326 } 00327 #endif 00328 00329 #ifdef WIN32 00330 strcpy(file->owner,"user"); 00331 #else 00332 { 00333 struct passwd *pwuser; 00334 pwuser = getpwuid(file->s.st_uid); 00335 if ( pwuser ) { 00336 BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner)); 00337 } else { 00338 BLI_snprintf(file->owner, sizeof(file->owner), "%d", file->s.st_uid); 00339 } 00340 } 00341 #endif 00342 00343 tm= localtime(&file->s.st_mtime); 00344 // prevent impossible dates in windows 00345 if(tm==NULL) tm= localtime(&zero); 00346 strftime(file->time, sizeof(file->time), "%H:%M", tm); 00347 strftime(file->date, sizeof(file->date), "%d-%b-%y", tm); 00348 00349 /* 00350 * Seems st_size is signed 32-bit value in *nix and Windows. This 00351 * will buy us some time until files get bigger than 4GB or until 00352 * everyone starts using __USE_FILE_OFFSET64 or equivalent. 00353 */ 00354 st_size= file->s.st_size; 00355 00356 if (st_size > 1024*1024*1024) { 00357 BLI_snprintf(file->size, sizeof(file->size), "%.2f GB", ((double)st_size)/(1024*1024*1024)); 00358 } 00359 else if (st_size > 1024*1024) { 00360 BLI_snprintf(file->size, sizeof(file->size), "%.1f MB", ((double)st_size)/(1024*1024)); 00361 } 00362 else if (st_size > 1024) { 00363 BLI_snprintf(file->size, sizeof(file->size), "%d KB", (int)(st_size/1024)); 00364 } 00365 else { 00366 BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)st_size); 00367 } 00368 00369 strftime(datum, 32, "%d-%b-%y %H:%M", tm); /* XXX, is this used? - campbell */ 00370 00371 if (st_size < 1000) { 00372 BLI_snprintf(size, sizeof(size), "%10d", 00373 (int) st_size); 00374 } 00375 else if (st_size < 1000 * 1000) { 00376 BLI_snprintf(size, sizeof(size), "%6d %03d", 00377 (int) (st_size / 1000), (int) (st_size % 1000)); 00378 } 00379 else if (st_size < 100 * 1000 * 1000) { 00380 BLI_snprintf(size, sizeof(size), "%2d %03d %03d", 00381 (int) (st_size / (1000 * 1000)), (int) ((st_size / 1000) % 1000), (int) ( st_size % 1000)); 00382 } 00383 else { 00384 /* XXX, whats going on here?. 2x calls - campbell */ 00385 BLI_snprintf(size, sizeof(size), "> %4.1f M", (double) (st_size / (1024.0 * 1024.0))); 00386 BLI_snprintf(size, sizeof(size), "%10d", (int) st_size); 00387 } 00388 00389 BLI_snprintf(buf, sizeof(buf), "%s %s %s %7s %s %s %10s %s", 00390 file->mode1, file->mode2, file->mode3, file->owner, 00391 file->date, file->time, size, file->relname); 00392 00393 file->string = BLI_strdup(buf); 00394 } 00395 } 00396 00397 unsigned int BLI_dir_contents(const char *dirname, struct direntry **filelist) 00398 { 00399 // reset global variables 00400 // memory stored in files is free()'d in 00401 // filesel.c:freefilelist() 00402 00403 actnum = totnum = 0; 00404 files = NULL; 00405 00406 bli_builddir(dirname,""); 00407 bli_adddirstrings(); 00408 00409 if (files) { 00410 *(filelist) = files; 00411 } else { 00412 // keep blender happy. Blender stores this in a variable 00413 // where 0 has special meaning..... 00414 *(filelist) = files = malloc(sizeof(struct direntry)); 00415 } 00416 00417 return(actnum); 00418 } 00419 00420 00421 size_t BLI_file_descriptor_size(int file) 00422 { 00423 struct stat buf; 00424 00425 if (file <= 0) return (-1); 00426 fstat(file, &buf); 00427 return (buf.st_size); 00428 } 00429 00430 size_t BLI_file_size(const char *path) 00431 { 00432 int size, file = open(path, O_BINARY|O_RDONLY); 00433 00434 if (file == -1) 00435 return -1; 00436 00437 size = BLI_file_descriptor_size(file); 00438 close(file); 00439 return size; 00440 } 00441 00442 00443 int BLI_exists(const char *name) 00444 { 00445 #if defined(WIN32) && !defined(__MINGW32__) 00446 struct _stat64i32 st; 00447 /* in Windows stat doesn't recognize dir ending on a slash 00448 To not break code where the ending slash is expected we 00449 don't mess with the argument name directly here - elubie */ 00450 char tmp[FILE_MAX]; 00451 int len, res; 00452 BLI_strncpy(tmp, name, FILE_MAX); 00453 len = strlen(tmp); 00454 if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0'; 00455 res = _stat(tmp, &st); 00456 if (res == -1) return(0); 00457 #elif defined(__MINGW32__) 00458 struct _stati64 st; 00459 char tmp[FILE_MAX]; 00460 int len, res; 00461 BLI_strncpy(tmp, name, FILE_MAX); 00462 len = strlen(tmp); 00463 if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0'; 00464 res = _stati64(tmp, &st); 00465 if (res) return(0); 00466 #else 00467 struct stat st; 00468 if (stat(name,&st)) return(0); 00469 #endif 00470 return(st.st_mode); 00471 } 00472 00473 /* would be better in fileops.c except that it needs stat.h so add here */ 00474 int BLI_is_dir(const char *file) 00475 { 00476 return S_ISDIR(BLI_exists(file)); 00477 } 00478 00479 int BLI_is_file(const char *path) 00480 { 00481 int mode= BLI_exists(path); 00482 return (mode && !S_ISDIR(mode)); 00483 } 00484 00485 LinkNode *BLI_file_read_as_lines(const char *name) 00486 { 00487 FILE *fp= fopen(name, "r"); 00488 LinkNode *lines= NULL; 00489 char *buf; 00490 size_t size; 00491 00492 if (!fp) return NULL; 00493 00494 fseek(fp, 0, SEEK_END); 00495 size= (size_t)ftell(fp); 00496 fseek(fp, 0, SEEK_SET); 00497 00498 buf= MEM_mallocN(size, "file_as_lines"); 00499 if (buf) { 00500 size_t i, last= 0; 00501 00502 /* 00503 * size = because on win32 reading 00504 * all the bytes in the file will return 00505 * less bytes because of crnl changes. 00506 */ 00507 size= fread(buf, 1, size, fp); 00508 for (i=0; i<=size; i++) { 00509 if (i==size || buf[i]=='\n') { 00510 char *line= BLI_strdupn(&buf[last], i-last); 00511 00512 BLI_linklist_prepend(&lines, line); 00513 last= i+1; 00514 } 00515 } 00516 00517 MEM_freeN(buf); 00518 } 00519 00520 fclose(fp); 00521 00522 BLI_linklist_reverse(&lines); 00523 return lines; 00524 } 00525 00526 void BLI_file_free_lines(LinkNode *lines) 00527 { 00528 BLI_linklist_free(lines, (void(*)(void*)) MEM_freeN); 00529 } 00530 00531 int BLI_file_older(const char *file1, const char *file2) 00532 { 00533 struct stat st1, st2; 00534 00535 if(stat(file1, &st1)) return 0; 00536 if(stat(file2, &st2)) return 0; 00537 00538 return (st1.st_mtime < st2.st_mtime); 00539 } 00540