/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ #include #include "mrilib.h" #include "thd.h" /*-------------------------------------------------------------*/ /*! Return the time at which the file was last modified. */ time_t THD_file_mtime( char *pathname ) /* 05 Dec 2001 */ { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; return (time_t)buf.st_mtime ; } /*-----------------------------------------------------------*/ /*! Determine if this exists at all (file, directory, ...). */ int THD_is_ondisk( char *pathname ) /* 19 Dec 2002 */ { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; return (ii == 0) ; } /*-----------------------------------------------------------*/ /*! Determine if a prefix is that of a dset on disk. */ int THD_is_prefix_ondisk( char *pathname, int stripsels) { int ii, open1, open2, open3, open4; char *ppp=pathname; if (!pathname) return(0); if (stripsels) { ppp = strdup(pathname); open1 = open2 = open3 = open4 = 0; for (ii=strlen(ppp)-1; ii>=0; --ii) { if (ppp[ii] == ']' && !open1) open1=1; else if (ppp[ii] == '[' && open1) ppp[ii] = '\0'; else if (ppp[ii] == '>' && !open2) open2=1; else if (ppp[ii] == '<' && open2) ppp[ii] = '\0'; else if (ppp[ii] == '}' && !open3) open3=1; else if (ppp[ii] == '{' && open3) ppp[ii] = '\0'; else if (ppp[ii] == '#' && !open4) open4=1; else if (ppp[ii] == '#' && open4) ppp[ii] = '\0'; } } if (THD_is_directory(ppp)) { if (ppp!=pathname) free(ppp); return(0); } if (THD_is_ondisk(ppp)) { if (ppp!=pathname) free(ppp); return (1); } ii = THD_is_dataset(THD_filepath(ppp), THD_trailname(ppp,0), -1); if (ii ==-1) { if (ppp!=pathname) free(ppp); return(0); } else { if (ppp!=pathname) free(ppp); return(1); } } /*-----------------------------------------------------------*/ /*! Change working directory. */ int THD_cwd( char *pathname ) /* 19 Dec 2002 */ { if( pathname == NULL || *pathname == '\0' ) return 0 ; return ( chdir(pathname) == 0 ) ; } /*-----------------------------------------------------------*/ /*! Create a directory. Returns 1 if OK, 0 if not. */ int THD_mkdir( char *pathname ) /* 19 Dec 2002 */ { int lp , ii , jj ; char *pnam ; /* check if input is OK, or if it already exists */ if( !THD_filename_ok(pathname) ) return 0 ; if( THD_is_ondisk (pathname) ) return THD_is_directory(pathname) ; pnam = strdup(pathname) ; /* modifiable copy */ lp = strlen(pnam) ; ii = 0 ; /* loop over path segments, creating them if needed */ while(1){ /* advance ii to point to end of next path segment, at the next '/' character, or at the end of pnam */ ii += strspn(pnam+ii,"/") ; ii += strcspn(pnam+ii,"/") ; /* insert a NUL to replace the '/', temporarily */ if( ii < lp ) pnam[ii] = '\0' ; /* if this segment doesn't already exist, create it */ if( !THD_is_directory(pnam) ){ jj = mkdir( pnam , 0755 ) ; if( jj != 0 ){ free(pnam); return 0; } /* bad */ } /* if reached end of path string, we're done */ if( ii == lp ){ free(pnam); return 1; } /* good */ /* reinsert '/' if it was excised */ pnam[ii] = '/' ; } return 0 ; /* unreachable */ } /*-----------------------------------------------------------*/ /*! Determine if this is really a regular file or not. */ int THD_is_file( char *pathname ) { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IFREG) != 0 ; return ii ; } /*-----------------------------------------------------------*/ /*! Determine if this is a FIFO or not. [27 Aug 2019] */ int THD_is_fifo( char *pathname ) { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IFIFO) != 0 ; return ii ; } /*------------------------------------------------------------*/ /*! Determine if this is really a symbolic link or not. */ int THD_is_symlink( char *pathname ) /* 03 Mar 1999 */ { char buf[32] ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = readlink( pathname , buf , 32 ) ; return (ii > 0) ; } /*-------------------------------------------------------*/ /*! Return the file length (0 if file not found). */ long long THD_filesize( char *pathname ) { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; return (long long)buf.st_size ; } /*-------------------------------------------------------*/ /*! Return the file's last modified date in a string */ char *THD_filetime( char *pathname ) { static struct stat buf ; int ii ; static char sout[10][64]; static int icall=0; static struct tm *lt=NULL ; ++icall; if (icall > 9) icall=0; sout[icall][0]='\0'; if( pathname == NULL || *pathname == '\0' ) return (sout[icall]); ii = stat( pathname , &buf ) ; if( ii != 0 ) return (sout[icall]) ; lt = localtime(&buf.st_mtime); sprintf(sout[icall], "%04d_%02d_%02d-%02d_%02d_%02d", lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec); return (sout[icall]) ; } /*-------------------------------------------------------*/ /*! Compare file's last modified date to reference -1 file modification predates the specified day 0 same as specified day 1 newer 2 for error in input or file not found */ int THD_filetime_diff( char *pathname, int year, int month, int day ) { static struct stat buf ; int ii ; static struct tm *lt=NULL ; int fday, Dday = year*10000+month*100+day; if( pathname == NULL || *pathname == '\0' ) return (2); ii = stat( pathname , &buf ) ; if( ii != 0 ) return (2) ; lt = localtime(&buf.st_mtime); fday = (lt->tm_year+1900)*10000+(lt->tm_mon+1)*100+lt->tm_mday; if (Dday > fday) return(-1); else if (Dday < fday) return(1); else return(0); } char *THD_homedir(byte withslash) { static char sout[3][520]; static int icall=0; char *home=NULL; int nn=0; struct passwd *pw = NULL; ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; home = getenv("HOME"); if (!home) { pw = getpwuid(getuid()); if (pw) home = (char *)pw->pw_dir; } if (home) { if (strlen(home) > 510) { ERROR_message("Not enough space to store home dir of '%s'.\n"); } else { sprintf(sout[icall], "%s", home); } } /* remove slash */ while ( (nn=strlen(sout[icall])-1) && sout[icall][nn] == '/') sout[icall][nn] = '\0'; if (withslash) { nn=strlen(sout[icall]); sout[icall][nn] = '/'; sout[icall][nn+1] = '\0'; } return (sout[icall]) ; } char *THD_afnirc(void) { static char sout[3][520]; static int icall=0; ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; strcpy(sout[icall],THD_homedir(1)); strcat(sout[icall],".afnirc"); return(sout[icall]); } char *THD_custom_atlas_dir(byte withslash) { static char sout[3][520]; static int icall=0; char *home=NULL; int nn=0; /* struct passwd *pw = NULL;*/ ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; if (!(home = getenv("AFNI_SUPP_ATLAS_DIR"))) { return(sout[icall]); } if (strlen(home) > 510) { ERROR_message("Not enough space to store AFNI_SUPP_ATLAS_DIR dir of '%s'.\n"); } else { sprintf(sout[icall], "%s", home); } /* remove slash */ while ( (nn=strlen(sout[icall])-1)>=0 && sout[icall][nn] == '/') sout[icall][nn] = '\0'; if (withslash) { nn=strlen(sout[icall]); sout[icall][nn] = '/'; sout[icall][nn+1] = '\0'; } return (sout[icall]) ; } /* retrieve custom atlas directory and make sure it is present Do not free returned pointer. Failure is a NULL pointer */ char *THD_get_custom_atlas_dir(byte withslash) { char *cadir = NULL; cadir = THD_custom_atlas_dir(withslash); if (cadir[0] == '\0') { ERROR_message("Have no custom atlas directory\n"); return(NULL); } if (!THD_mkdir(cadir)) { ERROR_message("Cannot create %s directory\n", cadir); return(NULL); } return(cadir); } char *THD_custom_atlas_file(char *name) { static char sout[3][1024]; static int icall=0; /* struct passwd *pw = NULL;*/ ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; if (!name) name = getenv("AFNI_SUPP_ATLAS"); if (name) { if (THD_is_file(name)) { snprintf(sout[icall], 1020*sizeof(char),"%s",name); return (sout[icall]) ; } else { snprintf(sout[icall], 1020*sizeof(char), "%s/%s",THD_custom_atlas_dir(0),name); if (!THD_is_file(sout[icall])) { ERROR_message("Supp atlas file %s not found", name); } return (sout[icall]) ; } } /* no name, try default */ name = "CustomAtlases.niml"; if (THD_is_file(name)) { snprintf(sout[icall], 1020*sizeof(char),"%s",name); return (sout[icall]) ; } else { snprintf(sout[icall], 1020*sizeof(char), "%s/%s",THD_custom_atlas_dir(0),name); if (THD_is_file(sout[icall])) { return (sout[icall]) ; } else { sout[icall][0]='\0'; return (sout[icall]) ; } } return (sout[icall]) ; } /* Return the name of the help directory, no guarantee that it exists Consider THD_get_helpdir() Do not free returned pointer. Failure results in an empty string. */ char *THD_helpdir(byte withslash) { static char sout[3][610]; static int icall=0; char *home=NULL; ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; home = THD_homedir(0); if (home[0]=='\0') return(sout[icall]); if (withslash) snprintf(sout[icall],600*sizeof(char),"%s/.afni/help/",home); else snprintf(sout[icall],599*sizeof(char),"%s/.afni/help",home); return (sout[icall]) ; } /* Return the name of the data directory, no guarantee that it exists Consider THD_get_datadir() Do not free returned pointer. Failure results in an empty string. */ char *THD_datadir(byte withslash) { static char sout[3][610]; static int icall=0; char *home=NULL; ++icall; if (icall>2) icall=0; sout[icall][0]='\0'; home = THD_homedir(0); if (home[0]=='\0') return(sout[icall]); if (withslash) snprintf(sout[icall],600*sizeof(char),"%s/.afni/data/",home); else snprintf(sout[icall],599*sizeof(char),"%s/.afni/data",home); return (sout[icall]) ; } /* retrieve help directory and make sure it is present Do not free returned pointer. Failure is a NULL pointer */ char *THD_get_helpdir(byte withslash) { char *hdir = NULL; hdir = THD_helpdir(withslash); if (hdir[0] == '\0') { ERROR_message("Have no help directory\n"); return(NULL); } if (!THD_mkdir(hdir)) { ERROR_message("Cannot create %s directory\n", hdir); return(NULL); } return(hdir); } /* retrieve data directory and make sure it is present Do not free returned pointer. Failure is a NULL pointer */ char *THD_get_datadir(byte withslash) { char *hdir = NULL; hdir = THD_datadir(withslash); if (hdir[0] == '\0') { ERROR_message("Have no data directory\n"); return(NULL); } if (!THD_mkdir(hdir)) { ERROR_message("Cannot create %s directory\n", hdir); return(NULL); } return(hdir); } char *THD_helpsearchlog(int createpath) { static int bad = 0; static char shelpname[256]={""}; if (!bad && createpath && !THD_mkdir(THD_helpdir(0))) { ERROR_message("Cannot create %s help directory\n", THD_helpdir(0)); bad = 1; } snprintf(shelpname,255*sizeof(char), "%s/aps.log.txt",THD_helpdir(0)); return(shelpname); } /*--------------------------------------------------------*/ /*! Determine if this is really a directory or not. */ int THD_is_directory( char *pathname ) { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii != 0 ) return 0 ; ii = (buf.st_mode & S_IFDIR) != 0 ; return ii ; } /*---------------------------------------------------------------*/ /*! Determine if this is really an executable file or not. */ int THD_is_executable( char *pathname ) /* 26 Jun 2001 */ { static struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return 0 ; ii = stat( pathname , &buf ) ; if( ii ) return 0 ; ii = (buf.st_mode & S_IXOTH) != 0 ; if( ii ) return ii ; /* 15 Jul 2002: also check if file is owned & executable by user */ ii = ( getuid() == buf.st_uid && (buf.st_mode & S_IXUSR) != 0 ) ; return ii ; } /*--------------------------------------------------------------*/ /*! Determine if two filenames are really the same thing. */ int THD_equiv_files( char *path1 , char *path2 ) { static struct stat buf1 , buf2 ; int ii ; if( path1 == NULL || path2 == NULL ) return -1 ; ii = stat( path1 , &buf1 ) ; if( ii != 0 ) return -1 ; ii = stat( path2 , &buf2 ) ; if( ii != 0 ) return -1 ; ii = (buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino) ; return ii ; } /*-----------------------------------------------------------------*/ /*! Find a 'trailing name in a pathname. For example, for fname = "/bob/cox/is/the/author/of/AFNI", - the lev=0 trailing name is "AFNI", - the lev=1 trailing name is "of/AFNI", - the lev=2 trailing name is "author/of/AFNI", and so on. That is, "lev" is the number of directory names above the last name to keep. The pointer returned is to some place in the middle of fname; that is, this is not a malloc()-ed string, so don't try to free() it!. -------------------------------------------------------------------*/ char * THD_trailname( char *fname , int lev ) { int fpos , flen , flev ; if( fname == NULL || (flen=strlen(fname)) <= 1 ) return fname ; if( lev < 0 ) lev = 0 ; flev = 0 ; fpos = flen ; if( fname[fpos-1] == '/' ) fpos-- ; /* skip trailing slash */ /* fpos = index of latest character I've accepted, fpos-1 = index of next character to examine, flev = number of directory levels found so far */ while( fpos > 0 ){ if( fname[fpos-1] == '/' ){ flev++ ; if( flev > lev ) break ; /* reached the lev we like */ } fpos-- ; /* scan backwards */ } return (fname+fpos) ; } /*----------------------------------------------------------------------*/ /*! Return the path to fname. Do not free returned string. */ char * THD_filepath( char *fname ) { static int icall=-1; static char pname[10][THD_MAX_NAME]; char *ppp = NULL; long lend=0; ++icall; if (icall > 9) icall = 0; pname[icall][0]='.'; pname[icall][1]='/'; pname[icall][2]='\0'; if (!fname) return(pname[icall]); lend = strlen(fname); if (fname[lend-1] == '/') { /* fname is a path*/ if (lend >= THD_MAX_NAME-1) { ERROR_message("Path name too long. Returning './' as the file path :("); ERROR_message(" Offending input is:\n %s",fname) ; ERROR_message("Almost certainly something bad will happen below here!") ; } else { strncpy(pname[icall], fname, lend); pname[icall][lend]='\0'; } return(pname[icall]); } if (!(ppp=THD_trailname(fname,0))) return(pname[icall]); if (!(lend = ppp-fname)) return(pname[icall]); /* no path on name */ if (lend >= THD_MAX_NAME-1) { ERROR_message("Path name too long. Returning './' as the file path :-("); ERROR_message(" Offending input is:\n %s",fname) ; ERROR_message("Almost certainly something bad will happen below here!") ; return(pname[icall]); } strncpy(pname[icall], fname, lend); pname[icall][lend]='\0'; if( pname[icall][lend-1] != '/' ){ pname[icall][lend-1] = '/'; pname[icall][lend] = '\0'; } return(pname[icall]); } /*----------------------------------------------------------------------*/ /* Does filename have a path */ int THD_filehaspath ( char *fname) { if (!fname) return(0); while (*fname!='\0') { if (*fname=='/') return(1); else ++fname; } return(0); } /*----------------------------------------------------------------------*/ int THD_character_ok( char c ) /* 04 Feb 2010 */ { if( iscntrl(c) || isspace(c) || c == ';' || c == '*' || c == '?' || c == '&' || c == '|' || c == '"' || c == '>' || c == '<' || c == '\'' || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '!' || (c & 128) != 0 ) return 0 ; return 1 ; } /*----------------------------------------------------------------------*/ int THD_filename_fix( char *name ) /* 04 Feb 2010 */ { int ll , ii , nfix ; if( name == NULL ) return -1 ; ll = strlen( name ) ; if( ll == 0 ) return -1 ; for( nfix=ii=0 ; ii < ll ; ii++ ){ if( !THD_character_ok(name[ii]) ){ name[ii] = '_' ; nfix++ ; } } return nfix ; } /*----------------------------------------------------------------------*/ /*! Check if a filename is OK - that is, has no crummy characters. The filename can have a '/' in it. To insist that there be not '/', use THD_filename_pure(). The list of crummy characters can be inferred from the source code. */ int THD_filename_ok( char *name ) /* 24 Apr 1997 */ { int ll , ii ; if( name == NULL ) return 0 ; ll = strlen( name ) ; if( ll == 0 ) return 0 ; if (ll > 6 && strstr(name, "3dcalc") == name) { return 1; /* have a 3dcalc command, let it be*/ } if( AFNI_yesenv("AFNI_ALLOW_ARBITRARY_FILENAMES") ) return 1 ; /* 08 Apr 2009 */ for( ii=0 ; ii < ll ; ii++ ) if( iscntrl(name[ii]) || isspace(name[ii]) || name[ii] == ';' || name[ii] == '*' || name[ii] == '?' || name[ii] == '&' || name[ii] == '|' || name[ii] == '"' || name[ii] == '>' || name[ii] == '<' || name[ii] == '\'' || name[ii] == '[' || name[ii] == ']' || name[ii] == '(' || name[ii] == ')' || name[ii] == '{' || name[ii] == '}' || name[ii] == '!' || (name[ii] & 128) != 0 ) return 0 ; return 1 ; } /*--------------------------------------------------------------------*/ /*! Check if a filename is pure - no crummy characters, no '/'. */ int THD_filename_pure( char *name ) /* 28 Feb 2001 */ { int ii ; ii = THD_filename_ok( name ) ; if( ii ) ii = (strstr(name,"/") == NULL) ; return ii ; } /*--------------------------------------------------------------*/ #undef FNAME #undef FSTYP #undef BSIZE #undef BFREE #if defined(DARWIN) || defined(FreeBSD) /* Mac or BSD */ # include # include # define FNAME(a,b) statfs(a,b) # define FSTYP statfs # define BSIZE f_bsize # define BFREE f_bavail #elif defined(LINUX) /* Linux */ # include # define FNAME(a,b) statfs(a,b) # define FSTYP statfs # define BSIZE f_bsize # define BFREE f_bavail #elif defined(SOLARIS) || defined(SGI) /* Sun or SGI */ # include # include # define FNAME(a,b) statvfs64(a,b) # define FSTYP statvfs64 # define BSIZE f_bsize # define BFREE f_bavail #endif /*--------------------------------------------------------------*/ /*! Get free space (in megabytes) on a disk partition. Return value is -1 if can't be determined. ----------------------------------------------------------------*/ int THD_freemegabytes( char *pathname ) { #ifdef FNAME int ii ; struct FSTYP buf ; if( pathname == NULL || *pathname == '\0' ) return -1 ; ii = FNAME( pathname , &buf ) ; if( ii ) return -1 ; ii = (int)((double)(buf.BFREE) * (double)(buf.BSIZE) / (1024.0*1024.0)) ; return ii ; #else return -1 ; #endif } /*----------------------------------------------------------------------*/ /*! Check a list of dataset names for duplicates. Return value is number of duplicates found. - ns = number of strings - sar = string array - flag = 1 to print warnings, 0 to be silent ------------------------------------------------------------------------*/ int THD_check_for_duplicates( int ns , char **sar , int flag ) { int verb = (flag & 1) != 0 ; int ii,jj,li,lj,nw=0 ; char *di, *dj ; ENTRY("THD_check_for_duplicates") ; if( sar == NULL ) RETURN(0) ; for( ii=0 ; ii < ns-1 ; ii++ ){ if( sar[ii] == NULL ) continue ; di = strdup(sar[ii] ) ; li = strlen(di) ; if( strcmp(di+li-5,".HEAD" ) == 0 ) di[li-5] = '\0' ; else if( strcmp(di+li-5,".BRIK" ) == 0 ) di[li-5] = '\0' ; else if( strcmp(di+li-8,".BRIK.gz") == 0 ) di[li-8] = '\0' ; else if( strcmp(di+li-7,".nii.gz" ) == 0 ) di[li-3] = '\0' ; else if( strcmp(di+li-1,"." ) == 0 ) di[li-1] = '\0' ; for( jj=ii+1 ; jj < ns ; jj++ ){ if( sar[jj] == NULL ) continue ; dj = strdup(sar[jj]) ; lj = strlen(dj) ; if( strcmp(dj+lj-5,".HEAD" ) == 0 ) dj[lj-5] = '\0' ; else if( strcmp(dj+lj-5,".BRIK" ) == 0 ) dj[lj-5] = '\0' ; else if( strcmp(dj+lj-8,".BRIK.gz") == 0 ) dj[lj-8] = '\0' ; else if( strcmp(dj+lj-7,".nii.gz" ) == 0 ) dj[lj-3] = '\0' ; else if( strcmp(dj+lj-1,"." ) == 0 ) dj[lj-1] = '\0' ; if( strcmp(di,dj) == 0 ){ nw++ ; if( verb ) WARNING_message("Datasets '%s' and '%s' are the same?!?", sar[ii] , sar[jj] ) ; } free(dj) ; } free(di) ; } RETURN(nw) ; } /*----------------------------------------------------------------------*/ /* Check if this directory name is forbidden fruit. */ /*----------------------------------------------------------------------*/ int THD_forbidden_directory( char *dname ) { if( dname == NULL || *dname == '\0' ) return 1 ; #ifdef DARWIN /* skip system name directories if on MacOS X [18 Sep 2020] */ if( strcasestr(dname,"Applications") != NULL || strcasestr(dname,"Desktop") != NULL || strcasestr(dname,"Documents") != NULL || strcasestr(dname,"Downloads") != NULL || strcasestr(dname,"Library") != NULL || strcasestr(dname,"Movies") != NULL || strcasestr(dname,"Music") != NULL || strcasestr(dname,"Pictures") != NULL ) return 1 ; #endif /** Other possibilities could go here **/ return 0 ; }