/**
 * Prepends a path to our path, unless our path is an an absolute path.
 *
 * @param path		the path to prepend
 */
void Filename::prependPath(const Filename &path)
{
	if (m_path.size() != 0 && m_path[0] != PATH_SEPARATOR)
	{
		m_path = path.getPath() + m_path;
		convertToSystemPath(m_path);
		makeFullPath();
	}
}	// Filename::prependPath
/**
 * Sets the drive letter of the file name.
 *
 * @param drive		the drive
 */
void Filename::setDrive(const char *drive)
{
	if (drive != NULL && isalpha(*drive))
		m_drive = std::string(drive, 1) + ":";
	else
		m_drive = "";

	makeFullPath();
}	// Filename::setDrive
Beispiel #3
0
void makeSabun(char *sabunFile, char *beforeDir, char *afterDir, int correctAddDelete)
{
	char *dir1 = beforeDir;
	char *dir2 = afterDir;
	autoList_t *files1;
	autoList_t *files2;
	autoList_t *mfiles;
	autoList_t *trailLines = newList();
	char *file;
	char *line;
	uint index;
	FILE *fp;

	// check no dirs.
	{
		autoList_t *dirs1 = lsDirs(dir1);
		autoList_t *dirs2 = lsDirs(dir2);

		errorCase(getCount(dirs1) || getCount(dirs2));

		releaseAutoList(dirs1);
		releaseAutoList(dirs2);
	}

	files1 = lsFiles(dir1);
	files2 = lsFiles(dir2);
	dir1 = makeFullPath(dir1);
	dir2 = makeFullPath(dir2);
	changeRoots(files1, dir1, NULL);
	changeRoots(files2, dir2, NULL);

	fp = fileOpen(sabunFile, "wb");

	writeLine(fp, FILEHDR_SIGNATURE);

	rapidSortLines(files1);
	rapidSortLines(files2);

	addCwd(dir1);
	foreach(files1, file, index) // 更新前のファイルとハッシュ、確認用
	{
		writeLine(fp, file);
		writeLine_x(fp, md5_makeHexHashFile(file));
	}
/**
 * Appends a path to our path. If the path is an absolute path, replaces our path.
 *
 * @param path		the path to append
 */
void Filename::appendPath(const Filename &path)
{
	std::string localpath = path.getPath();
	convertToSystemPath(localpath);
	if (localpath.size() != 0 && localpath[0] == PATH_SEPARATOR)
		m_path = localpath;
	else
		m_path += localpath;
	makeFullPath();
}	// Filename::appendPath
Beispiel #5
0
void convertFieldData( char *indir, char *outdir, int pjid ) {
    char outpath[400];
    snprintf(outpath, sizeof(outpath), "field_data_%d_%d_%d_%d", pjid, FIELD_W, FIELD_H, (int)sizeof(Cell) );
    assertmsg( sizeof(Cell) == 48, "invalid Cell size compiled:%d. Expect 48. incorrect version?", sizeof(Cell) );
    char outfullpath[400];
    makeFullPath( outdir, outfullpath, sizeof(outfullpath), outpath );

    if( fileExist(outfullpath) ) {
        print("FATAL: File exists:'%s'", outfullpath);
        return;
    }
    
    size_t read_total = 0;
    int chw = FIELD_W / CHUNKSZ;
    int chh = FIELD_H / CHUNKSZ;
    for(int chy=0;chy<chh;chy++) {
        for( int chx=0;chx<chw;chx++) {
            char path[400];
            snprintf( path, sizeof(path), "field_data_%d_%d_%d_%d_%d", pjid, chx*CHUNKSZ, chy*CHUNKSZ, CHUNKSZ, CHUNKSZ );
            char fullpath[400];
            makeFullPath( indir, fullpath, sizeof(fullpath), path );
            char buf[32*1024];
            size_t sz = sizeof(buf);
            bool res = readFile( fullpath, buf, &sz );
            assertmsg( res, "can't read file:'%s'", fullpath);
            if(chx%8==0)prt(".");
            read_total += sz;
            if( chx==chw-1 ) print("chunk y:%d total:%d",chy, read_total );
            assertmsg( sz < sizeof(buf), "saved file is too large:'%s'", fullpath );

            char decompressed[sizeof(Cell)*CHUNKSZ*CHUNKSZ];
            int decomplen = memDecompressSnappy( decompressed, sizeof(decompressed), buf, sz );
            assertmsg(decomplen == sizeof(decompressed), "invalid decompressed size:%d file:'%s'", decomplen, fullpath );

            int chunk_index = chx + chy*chw;
            size_t offset = chunk_index * sizeof(Cell)*CHUNKSZ*CHUNKSZ;
            //            print("write. ofs:%d chx:%d chy:%d", offset, chx, chy );
            res = writeFileOffset( outfullpath, decompressed, decomplen, offset, false );
            assertmsg(res, "writeFileOffset failed for '%s'", outfullpath );
            
        }
    }
}
/**
 * Sets the name of the file name.
 * If the name has an extension, the extension will be set
 * If the name has a full path (starts with drive or separator), the path will be set
 * If the name has a relative path, the path will be appended to the current path
 *
 * @param name		the name
 */
void Filename::setName(const char *name)
{
	if (name == NULL || *name == '\0')
		m_name = "";
	else
	{
#ifdef WIN32
		if (isalpha(*name) && *(name + 1) == ':')
		{
			setDrive(name);
			name += 2;
		}
#endif
		std::string localname = name;
		convertToSystemPath(localname);
		const char *dot = strrchr(localname.c_str(), '.');
		const char *firstSeparator = strchr(localname.c_str(), PATH_SEPARATOR);
		const char *lastSeparator = strrchr(localname.c_str(), PATH_SEPARATOR);
		if (firstSeparator != NULL)
		{
			// name has a path
			if (firstSeparator == localname)
			{
				// set path
				m_path = std::string(firstSeparator, lastSeparator - firstSeparator + 1);
			}
			else
			{
				// append path
				m_path += std::string(localname.c_str(), lastSeparator - 
					localname.c_str() + 1);
			}
		}
		if (dot != NULL && (lastSeparator == NULL || dot > lastSeparator))
		{
			// name has an extension
			setExtension(dot);
			if (lastSeparator == NULL)
				m_name = std::string(localname.c_str(), dot - localname.c_str());
			else
				m_name = std::string(lastSeparator + 1, dot - (lastSeparator + 1));
		}
		else
		{
			// name doesn't have an extension
			if (lastSeparator == NULL)
				m_name = localname;
			else
				m_name = std::string(lastSeparator + 1);
		}
	}

	makeFullPath();
}	// Filename::setName
Beispiel #7
0
// public static
bool
Path::isParentPath (const String& path1, const String& path2)
{

	String tmp1 = path1;
	String tmp2 = path2;

	String realPath1 = makeFullPath (tmp1.trim ());
	String realPath2 = makeFullPath (tmp2.trim ());

	if (isSeparator (realPath1 [(int) realPath1.getLength () - 1]) == false)
		realPath1 += Path::separator;	
	
	if (isSeparator (realPath2 [(int) realPath2.getLength () - 1]) == false)
		realPath2 += Path::separator;

#ifdef __WINDOWS__
	if (realPath2.compareIgnoreCase (realPath1) == 1)
		return false;

	realPath1.toLower ();
	realPath2.toLower ();
	if (realPath2.find (realPath1) == 0)
		return true;
	else
		return false;
#else
	if (realPath2.compare (realPath1) == 0)
		return false;
	else 
		if (realPath2.find (realPath1) == 0)
			return true;
		else
			return false;
#endif
}
// import - prints the preamble, then loops over all files and import them one by one
void SpectraSTMs2LibImporter::import() {

  for (vector<string>::iterator i = m_impFileNames.begin(); i != m_impFileNames.end(); i++) {
    string fullName(*i);
    makeFullPath(fullName);
    string quoted("\"" + fullName + "\"");
    string desc = m_params.constructDescrStr(quoted, ".ms2");
    m_preamble.push_back(desc);
  }
  
  m_lib->writePreamble(m_preamble);
  
  for (vector<string>::iterator i = m_impFileNames.begin(); i != m_impFileNames.end(); i++) {
    readFromFile(*i);
  } 
}
Beispiel #9
0
    /**
     * @brief Database::save
     * @return
     */
    bool Database::save() const
    {
        if (!QDir(m_Path).exists())
            if (!QDir().mkpath(m_Path))
                return false;

        QFile f(makeFullPath());
        if (f.open(QIODevice::WriteOnly)) {
            QJsonDocument jdoc(toJson());
            QTextStream stream(&f);
            stream << jdoc.toJson();
            return true;
        }

        return false;
    }
Beispiel #10
0
// 'Corrects' the security on a file by taking ownership of it and giving the current user full control
// For directories these will do a complete recursive correction.
static void CorrectSecurity(TCHAR *f, DWORD attrib, BOOL takeownership, PSID sid, PACL acl, BOOL oneVolumeOnly) {
	BY_HANDLE_FILE_INFORMATION info;
	if (attrib != INVALID_FILE_ATTRIBUTES) {
		DWORD err;
		if (sid && takeownership) {
			err = SetNamedSecurityInfo(f, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, sid, NULL, NULL, NULL);
			if (err != ERROR_SUCCESS) { LogFileError(TEXT("SetNamedSecurityInfo (change owner)"), f, err); }
		}
		if (sid && acl) {
			err = SetNamedSecurityInfo(f, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, acl, NULL);
			if (err != ERROR_SUCCESS) { LogFileError(TEXT("SetNamedSecurityInfo (change DACL)"), f, err); }
		}
		if ((attrib & FILE_ATTRIBUTE_DIRECTORY) && !(oneVolumeOnly && FileChangesVolume(f))) {
			// Recursively go through the directories
			WIN32_FIND_DATA ffd;
			TCHAR full[BIG_PATH+5], *file = copyStr(f);
			HANDLE hFind;
			DWORD dwError;
			DWORD len = _tcslen(file);
			while (len > 0 && file[len-1] == L'\\')
				file[--len] = 0;
			file[len  ] = TEXT('\\');
			file[len+1] = TEXT('*');
			file[len+2] = 0;
			hFind = FindFirstFileEx(file, FindExInfoBasic, &ffd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
			if (hFind == INVALID_HANDLE_VALUE) {
				dwError = GetLastError();
				if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_ACCESS_DENIED)
					LogFileError(TEXT("FindFirstFileEx in CorrectSecurity failed for"), file, dwError);
			} else {
				do {
					if (_tcscmp(ffd.cFileName, TEXT("..")) == 0 || _tcscmp(ffd.cFileName, TEXT(".")) == 0)
						continue;
					CorrectSecurity(makeFullPath(f, ffd.cFileName, full), ffd.dwFileAttributes, takeownership, sid, acl, oneVolumeOnly);
				} while (FindNextFile(hFind, &ffd) != 0);
				dwError = GetLastError();
				if (dwError != ERROR_NO_MORE_FILES)
					LogError(TEXT("FindNextFile in CorrectSecurity"), dwError);
				FindClose(hFind);
			}
			free(file);
		}
		if (attrib & FILE_ATTRIBUTE_READONLY) { // Remove the read-only attribute
			SetFileAttributes(f, attrib&!FILE_ATTRIBUTE_READONLY);
		}
	}
}
Beispiel #11
0
/**
 * Sets the extension of the file name.
 *
 * @param path		the path
 */
void Filename::setExtension(const char *extension)
{
	if (extension == NULL || *extension == '\0')
		m_extension = "";
	else
	{
		if (*extension == '.')
			m_extension = extension;
		else
		{
			m_extension = ".";
			m_extension += extension;
		}
	}

	makeFullPath();
}	// Filename::setExtension
Beispiel #12
0
    /**
     * @brief Database::load
     * @param errorList
     */
    void Database::load(ErrorList &errorList)
    {
        QFile f(makeFullPath());
        if (f.open(QIODevice::ReadOnly)) {
            QJsonParseError errorMessage;
            QJsonDocument jdoc(QJsonDocument::fromJson(f.readAll(), &errorMessage));

            if (errorMessage.error == QJsonParseError::NoError) {
                fromJson(jdoc.object(), errorList);
            } else {
                errorList << errorMessage.errorString();
            }
        } else {
            errorList << QObject::tr("Can't load database: %1.").arg(f.fileName());
        }

        m_Valid = errorList.isEmpty();
    }
Beispiel #13
0
static void ShowBuildTime(char *trgPath)
{
	trgPath = makeFullPath(trgPath);

	if(existDir(trgPath))
	{
		autoList_t *paths = lss(trgPath);
		char *path;
		uint index;

		sortJLinesICase(paths);

		foreach(paths, path, index)
		{
			char *relPath = changeRoot(strx(path), trgPath, NULL);

			if(existDir(path))
			{
				cout("------------------------ %s\n", relPath);
			}
			else if(
				!_stricmp("exe", getExt(path)) ||
				!_stricmp("dll", getExt(path)) ||
				!_stricmp("exe_", getExt(path)) ||
				!_stricmp("dll_", getExt(path))
				)
			{
				ShowBuildTime_File(path, relPath);
			}
			else
			{
				char *hash = md5_makeHexHashFile(path);

				hash[16] = '\0';

				cout("    %s     %s\n", hash, relPath);

				memFree(hash);
			}
			memFree(relPath);
		}
		releaseDim(paths, 1);
	}
Beispiel #14
0
static void AntiSVN(char *targetDir)
{
	targetDir = makeFullPath(targetDir);

	if(!ForceMode)
	{
		cout("%s\n", targetDir);
		cout("ANTI-SVN PROCEED? [Any/ESC]\n");

		if(clearGetKey() == 0x1b)
			termination(1);

		cout("GO!\n");
	}
	for(; ; )
	{
		autoList_t *dirs = lssDirs(targetDir);
		char *dir;
		uint index;
		int found = 0;

		foreach(dirs, dir, index)
		{
			if(
				!_stricmp(".svn", getLocal(dir)) ||
				!_stricmp("_svn", getLocal(dir))
				)
			{
				coExecute_x(xcout("RD /S /Q \"%s\"", dir));
				found = 1;
			}
		}
		releaseDim(dirs, 1);

		if(!found)
			break;

		coSleep(1000);
	}
	memFree(targetDir);
}
Beispiel #15
0
/**
 * Sets the path of the file name.
 * If the path has a drive letter, the drive will be set (Winodws only)
 *
 * @param path		the path
 */
void Filename::setPath(const char *path)
{
	if (path == NULL || *path == '\0')
		m_path = "";
	else
	{
#ifdef WIN32
		if (isalpha(*path) && *(path + 1) == ':')
		{
			setDrive(path);
			path += 2;
		}
#endif
		m_path = path;
		convertToSystemPath(m_path);
		if (m_path[strlen(path) - 1] != PATH_SEPARATOR)
			m_path += PATH_SEPARATOR;
	}

	makeFullPath();
}	// Filename::setPath
Beispiel #16
0
    bool ConfigTree::deleteParam(
            const std::string &paramPath,
            const std::string &paramName
            )
    {
        CONFIGSYS_DEBUG_CALLS;
        
        std::string fullPath = makeFullPath(paramPath);

        try
        {
            // get the parent node
            ptree paramParent = _treeRoot.get_child(fullPath);

            // Delete the parameter.
            // (Note: Only erases 'direct children'.
            // i.e. paramParent.erase("myname") might erase something,
            //  but paramParent.erase("my.name") will never erase anything).
            int del_n = paramParent.erase(paramName);
            if(del_n == 0)
            {
                std::cout   << "ConfigTree::deleteParam(...): Nothing to erase"
                            << " (there's no '" << paramName << "' at the given path)."
                            << std::endl;
                return false; // return failure if nothing was erased
            }
            
            // put back the modified parent node
            _treeRoot.put_child(fullPath, paramParent);
        }
        catch (boost::property_tree::ptree_error e)
        {
            std::cout   << "ConfigTree::deleteParam(...): ACCESS ERROR:" 
                        << e.what() 
                        << std::endl;
            return false;
        }

        return true;
    }
Beispiel #17
0
int InputFile::load(const std::string& fpath){
	// Get full path
	fullpath = fpath;
	if(!makeFullPath(fullpath))
		return InputFile::INVALID_PATH;
	
	// Open file
	FILE* fp=fopen(fpath.c_str(),"rb");
	
	// Check is file opened properly
	if(fp==NULL)
		return InputFile::FAILED_TO_OPEN;
	
	// Check size
	fseek(fp, 0, SEEK_END);
	long fp_size = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	if(fp_size == -1L)
		return InputFile::FAILED_TO_READ;
	
	// Read
	char* data = new char[fp_size];
	fread(data, 1, fp_size, fp);
	if (data == NULL)
		return InputFile::FAILED_TO_READ;
	
	// Close
	fclose(fp);
	
	// Copy to contents
	this->contents = std::string(data);
	delete[] data;
	
	// Success!
	return SUCCESS;
}
Beispiel #18
0
/* handle a command,
   return code is 0 if the command was (at least partially) valid,
   -1 for quitting,
   -2 for if invalid
   -3 if empty.
 */
int
doCommand( char *cmdToken[] ) {
    if ( strcmp( cmdToken[0], "help" ) == 0 ||
            strcmp( cmdToken[0], "h" ) == 0 ) {
        usage( cmdToken[1] );
        return 0;
    }
    if ( strcmp( cmdToken[0], "quit" ) == 0 ||
            strcmp( cmdToken[0], "q" ) == 0 ) {
        return -1;
    }

    if ( strcmp( cmdToken[0], "create" ) == 0
            || strcmp( cmdToken[0], "make" ) == 0
            || strcmp( cmdToken[0], "mk" ) == 0
       ) {
        static char myTicket[30];
        char *fullPath = 0;
        if ( strlen( cmdToken[3] ) > 0 ) {
            strncpy( myTicket, cmdToken[3], 30 );
        }
        else {
            makeTicket( myTicket );
        }
        makeFullPath( cmdToken[2], &fullPath );
        doTicketOp( "create", myTicket, cmdToken[1], fullPath,
                    cmdToken[3] );
        return 0;
    }


    if ( strcmp( cmdToken[0], "delete" ) == 0 ) {
        doTicketOp( "delete", cmdToken[1], cmdToken[2],
                    cmdToken[3], cmdToken[4] );
        return 0;
    }


    if ( strcmp( cmdToken[0], "mod" ) == 0 ) {
        doTicketOp( "mod", cmdToken[1], cmdToken[2],
                    cmdToken[3], cmdToken[4] );
        return 0;
    }

    if ( strcmp( cmdToken[0], "ls" ) == 0 ) {
        showTickets( cmdToken[1] );
        return 0;
    }

    if ( strcmp( cmdToken[0], "ls-all" ) == 0 ) {
        printf( "Listing all of your tickets, even those for which the target collection\nor data-object no longer exists:\n" );
        showTickets1( "basic", "" );
        return 0;
    }

    if ( *cmdToken[0] != '\0' ) {
        printf( "unrecognized command, try 'help'\n" );
        return -2;
    }
    return -3;
}
Beispiel #19
0
 /**
  * @brief Database::fullPath
  * @return
  */
 QString Database::fullPath() const
 {
     return makeFullPath();
 }
Beispiel #20
0
S32 TorqueMain( S32 argc, const char **argv )
{
   S32 failed = 0;

   // Initialize the subsystems.
   StandardMainLoop::init();
   Con::setVariable( "Con::Prompt", "" );
   WindowsConsole->enable( true );

   // install all drives for now until we have everything using the volume stuff
   Platform::FS::InstallFileSystems();
   Platform::FS::MountDefaults();

   bool compatMode = false;
   bool diffuseNames = false;
   bool verbose = false;
   bool saveDTS = true;
   bool saveDSQ = false;
   bool genMaterials = false;
   Torque::Path cfgPath, srcPath, destPath;

   // Parse arguments
   S32 i;
   for ( i = 1; i < argc-1; i++ )
   {
      if ( dStrEqual( argv[i], "--config" ) )
         cfgPath = makeFullPath( argv[++i] );
      else if ( dStrEqual( argv[i], "--output" ) )
         destPath = makeFullPath( argv[++i] );
      else if ( dStrEqual( argv[i], "--dsq" ) )
         saveDSQ = true;
      else if ( dStrEqual( argv[i], "--dsq-only" ) )
      {
         saveDTS = false;
         saveDSQ = true;
      }
      else if ( dStrEqual( argv[i], "--compat" ) )
         compatMode = true;
      else if ( dStrEqual( argv[i], "--diffuse" ) )
         diffuseNames = true;
      else if ( dStrEqual( argv[i], "--materials" ) )
         genMaterials = true;
      else if ( dStrEqual( argv[i], "--verbose" ) )
         verbose = true;
   }

   if ( ( i >= argc ) || ( !dStrEndsWith(argv[i], ".dae") && !dStrEndsWith(argv[i], ".kmz" ) ) )
   {
      Con::errorf( "Error: no DAE file specified.\n" );
      printUsage();
      return -1;
   }

   srcPath = makeFullPath( argv[i] );
   if ( destPath.isEmpty() )
   {
      destPath = srcPath;
      destPath.setExtension( "dts" );
   }

   if ( !cfgPath.isEmpty() )
      Con::printf( "Configuration files not yet supported.\n" );

   // Define script callbacks
   if ( verbose )
      Con::evaluate( "function UpdateTSShapeLoadProgress(%progress, %msg) { echo(%msg); }" );
   else
      Con::evaluate( "function UpdateTSShapeLoadProgress(%progress, %msg) { }" );

   if ( verbose )
      Con::printf( "Parsing configuration file...\n" );

   // Set import options
   ColladaUtils::getOptions().reset();
   ColladaUtils::getOptions().forceUpdateMaterials = genMaterials;
   ColladaUtils::getOptions().useDiffuseNames = diffuseNames;

   if ( verbose )
      Con::printf( "Reading dae file...\n" );

   // Attempt to load the DAE file
   Resource<TSShape> shape = ResourceManager::get().load( srcPath );
   if ( !shape )
   {
      Con::errorf( "Failed to convert DAE file: %s\n", srcPath.getFullPath() );
      failed = 1;
   }
   else
   {
      if ( compatMode && !shape->canWriteOldFormat() )
      {
         Con::errorf( "Warning: Attempting to save to DTS v24 but the shape "
                      "contains v26 features. Resulting DTS file may not be valid." );
      }

      FileStream outStream;

      if ( saveDSQ )
      {
         Torque::Path dsqPath( destPath );
         dsqPath.setExtension( "dsq" );

         for ( S32 i = 0; i < shape->sequences.size(); i++ )
         {
            const String& seqName = shape->getName( shape->sequences[i].nameIndex );
            if ( verbose )
               Con::printf( "Writing DSQ file for sequence '%s'...\n", seqName.c_str() );

            dsqPath.setFileName( destPath.getFileName() + "_" + seqName );

            if ( outStream.open( dsqPath, Torque::FS::File::Write ) )
            {
               shape->exportSequence( &outStream, shape->sequences[i], compatMode );
               outStream.close();
            }
            else
            {
               Con::errorf( "Failed to save sequence to %s\n", dsqPath.getFullPath().c_str() );
               failed = 1;
            }
         }
      }
      if ( saveDTS )
      {
         if ( verbose )
            Con::printf( "Writing DTS file...\n" );

         if ( outStream.open( destPath, Torque::FS::File::Write ) )
         {
            if ( saveDSQ )
               shape->sequences.setSize(0);

            shape->write( &outStream, compatMode );
            outStream.close();
         }
         else
         {
            Con::errorf( "Failed to save shape to %s\n", destPath.getFullPath().c_str() );
            failed = 1;
         }
      }
   }

   // Clean everything up.
   StandardMainLoop::shutdown();

   // Do we need to restart?
   if( StandardMainLoop::requiresRestart() )
      Platform::restartInstance();

   return failed;
}
Beispiel #21
0
// Finds files recursively
// Committed is if the current recursive path only contains files to be deleted (and thus simply list all files found)
// Otherwise wildcards are examined and directories are recursed
static void FindFiles(TCHAR *path, BOOL committed, BOOL oneVolumeOnly) {
	WIN32_FIND_DATA ffd;
	BY_HANDLE_FILE_INFORMATION info;
	TCHAR full[BIG_PATH+5];
	HANDLE hFind;
	DWORD dwError, attrib;
	TCHAR *file, *base;
	BOOL match_all;
	set *matches = NULL;

	DWORD len = _tcslen(path);
	while (len > 0 && path[len-1] == L'\\')
		path[--len] = 0;
	file = copyStr(path);
	attrib = GetFileAttributes(path);
	match_all = attrib != INVALID_FILE_ATTRIBUTES && ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
	if (match_all) {
		committed = TRUE;
		file[len  ] = TEXT('\\');
		file[len+1] = TEXT('*');
		file[len+2] = 0;
	} else {
		file[len] = 0;
	}
	
	base = getBaseDirectory(file);
	if (!committed)
		matches = set_create((compare_func)&_tcscmp);

	// first pass we match the pattern only and everything we find is committed
	hFind = FindFirstFileEx(file, FindExInfoBasic, &ffd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
	if (hFind == INVALID_HANDLE_VALUE) {
		dwError = GetLastError();
		if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_ACCESS_DENIED)
			LogFileError(TEXT("FindFirstFileEx in FindFiles failed for"), file, dwError);
	} else {
		do {
			if (_tcscmp(ffd.cFileName, TEXT("..")) == 0 || _tcscmp(ffd.cFileName, TEXT(".")) == 0)
				continue;
			makeFullPath(base, ffd.cFileName, full);
			vector_append(files, copyStr(full));
			if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(oneVolumeOnly && (ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && FileChangesVolume(full))) {
				if (!committed)
					set_insert(matches, copyStr(ffd.cFileName));
				FindFiles(full, TRUE, oneVolumeOnly);
			}
		} while (FindNextFile(hFind, &ffd) != 0);
		dwError = GetLastError();
		if (dwError != ERROR_NO_MORE_FILES)
			LogError(TEXT("FindNextFile in FindFiles"), dwError);
		FindClose(hFind);
	}

	if (!committed) {
		// second pass we are just looking for directories to recurse into
		// if we are already committed then there is no need to do this as all directories and files will be enumerated above

		TCHAR *pattern = getFileName(file);
		TCHAR *baseSrch = copyStr(base);
		len = _tcslen(base);
		baseSrch[len ] = L'\\';
		baseSrch[len+1] = L'*';
		baseSrch[len+2] = 0;

		hFind = FindFirstFileEx(baseSrch, FindExInfoBasic, &ffd, FindExSearchLimitToDirectories, NULL, FIND_FIRST_EX_LARGE_FETCH);
		if (hFind == INVALID_HANDLE_VALUE) {
			dwError = GetLastError();
			if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_ACCESS_DENIED)
				LogFileError(TEXT("FindFirstFileEx in FindFiles2 failed for"), baseSrch, dwError);
		} else {
			do {
				if (_tcscmp(ffd.cFileName, TEXT("..")) != 0 && _tcscmp(ffd.cFileName, TEXT(".")) != 0 && ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
					if (!set_contains(matches, ffd.cFileName)) { // don't re-recurse into a directory
						makeFullPath2(base, ffd.cFileName, pattern, full);
						if (!(oneVolumeOnly && (ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && FileChangesVolume(full))) {
							FindFiles(full, FALSE, oneVolumeOnly);
						}
					}
				}
			} while (FindNextFile(hFind, &ffd) != 0);
			dwError = GetLastError();
			if (dwError != ERROR_NO_MORE_FILES)
				LogError(TEXT("FindNextFile in FindFiles2"), dwError);
			FindClose(hFind);
		}
		free(baseSrch);
	}

	free(file);
	free(base);
	if (!committed)
		set_destroy(matches, TRUE);
}