/* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 1, or (at your option) ** any later version. ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Author : Alexandre Parenteau --- April 1998 */ /* * FileTraversal.cpp : class to traverse a file hierarchy */ #include "stdafx.h" #ifdef WIN32 # include "resource.h" #endif /* WIN32 */ #if TARGET_OS_MAC # include "GUSIInternal.h" # include "GUSIFileSpec.h" #endif #if TARGET_RT_MAC_CFM # include "GUSIDevice.h" #endif /* TARGET_RT_MAC_CFM */ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_ERRNO_H # include #endif /* HAVE_ERRNO_H */ #include "FileTraversal.h" #include "CPStr.h" #include "umain.h" #ifdef WIN32 # include "AppConsole.h" # include "wincvsdebug.h" # ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; # endif #endif /* WIN32 */ // in order to accelerate GUSI, we avoid using full paths #if TARGET_RT_MAC_CFM typedef GUSIDirectory * GUSIDirPtr; static DIR * opendir(const GUSIFileSpec & spec) { GUSIFileToken file(spec, GUSIFileToken::kWillOpendir); GUSIDirectory * dir; if (GUSIDevice * device = file.Device()) dir = device->opendir(file); else { GUSISetPosixError(ENOENT); dir = static_cast(nil); } return dir ? reinterpret_cast(new GUSIDirPtr(dir)) : 0; } static int stat(const GUSIFileSpec & inspec, struct stat * sb) { GUSIFileToken file(inspec, GUSIFileToken::kWillStat); if (GUSIDevice * device = file.Device()) return device->stat(file, sb); GUSISetPosixError(ENOENT); return -1; } #endif bool TraversalReport::gRunning = false; kTraversal FileTraverse(const char *path, TraversalReport & report, const UFSSpec * macDirSpec) { DIR *dirp = 0L; STRUCT_DIRENT *dp; struct stat sb; CStr fullname, errstr, dirname, tmpname; kTraversal res = kContinueTraversal; char *tmp; const UFSSpec *macspec = 0L; #if defined(WIN32) unsigned long dbg_mask = GetWinCvsDebugMask(false); CStr tracestr; #endif // used to restore the current directory static bool getPathFlag = false; char* szOriginalPath = NULL; USemaphore policeman(getPathFlag); USemaphore runstate(TraversalReport::gRunning); if(!policeman.IsEnteredTwice()) { szOriginalPath = getcwd(NULL, MAX_PATH); } #if !TARGET_OS_MAC if(path == 0L || (dirp = opendir(path)) == 0L) #elif TARGET_RT_MAC_CFM GUSIFileSpec folderspec; UFSSpec foldermacspec; if(macDirSpec != 0L) folderspec = *macDirSpec; else if(path != 0L) folderspec = path; foldermacspec = folderspec; macspec = &foldermacspec; if((dirp = opendir(folderspec)) == 0L) #else FSRef foldermacspec; if(macDirSpec != 0L) foldermacspec = *macDirSpec; else if(path != 0L) FSPathMakeRef(posix_to_utf8(path), &foldermacspec, NULL); macspec = &foldermacspec; if(path == 0L || (dirp = opendir(path)) == 0L) #endif { errstr = "Error while accessing "; errstr << path; errstr << " (error " << errno << ')'; res = report.OnError(errstr, errno); goto exit; } tmpname = path; tmp = tmpname; char *next; if(tmpname.endsWith(kPathDelimiter)) tmp[strlen(tmp) - 1] = '\0'; next = tmp; while((tmp = strchr(next, kPathDelimiter)) != 0L) { next = ++tmp; } dirname = next; res = report.EnterDirectory(path, dirname, macspec); if(res != kContinueTraversal) goto abort; while ((dp = readdir (dirp)) != NULL) { res = report.OnIdle(path); if(res != kContinueTraversal) goto abort; #if !TARGET_RT_MAC_CFM if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; #endif /* !TARGET_RT_MAC_CFM */ fullname = path; if(!fullname.endsWith(kPathDelimiter)) fullname << kPathDelimiter; fullname << dp->d_name; macspec = 0L; int statres; #if TARGET_RT_MAC_CFM GUSIFileSpec inspec(folderspec); inspec += dp->d_name; UFSSpec infspec = inspec; macspec = &infspec; statres = stat(inspec, &sb); #elif TARGET_RT_MAC_MACHO GUSIFileSpec inspec(foldermacspec); inspec += dp->d_name; UFSSpec infspec = inspec; macspec = &infspec; statres = stat(fullname, &sb); #else # if defined(WIN32) if ( (dbg_mask & wcvsdbg_trace_modified_checks) && (dbg_mask & wcvsdbg_verbose) ) { AppendWinCvsDebugMask(wcvsdbg_trace_dst_checks | wcvsdbg_trace_stat); tracestr = "Stat("; tracestr << static_cast(fullname); tracestr << ") ...\n"; cvs_err(tracestr); OutputDebugString(tracestr); } # endif // defined(WIN32) statres = stat(fullname, &sb); #endif if (statres != -1) { if(S_ISDIR(sb.st_mode)) { res = report.OnDirectory(path, fullname, dp->d_name, sb, macspec); if(res == kSkipFile) continue; if(res != kContinueTraversal) goto abort; res = FileTraverse(fullname, report, macspec); if(res != kContinueTraversal) goto abort; } else if(S_ISREG(sb.st_mode)) { res = report.OnFile(path, fullname, dp->d_name, sb, macspec); if(res == kSkipFile) continue; if(res != kContinueTraversal) goto abort; } #ifdef S_ISLNK else if(S_ISLNK(sb.st_mode)) { res = report.OnAlias(path, fullname, dp->d_name, sb, macspec); if(res == kSkipFile) continue; if(res != kContinueTraversal) goto abort; } #endif /* S_ISLNK */ else { /* TODO : Unix devices */ errstr = "Error while accessing "; errstr << fullname; errstr << " (error " << errno << ')'; res = report.OnError(errstr, errno); goto abort; } } else { errstr = "Error while accessing "; errstr << fullname; errstr << " (error " << errno << ')'; res = report.OnError(errstr, errno); // no abort, because all // * files not read yet will be signed as missing and all // * folder will not be displayed //goto abort; } } res = report.ExitDirectory(path); abort: closedir (dirp); exit: if(0L != szOriginalPath) { #if !TARGET_RT_MAC_CFM chdir(szOriginalPath); #endif free(szOriginalPath); szOriginalPath = NULL; } #if defined(WIN32) SetWinCvsDebugMask(dbg_mask); #endif // defined(WIN32) return res; }