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