示例#1
0
/// Insert a list of all dynamically loaded functions into the specified list.
static void autoload_names(std::set<wcstring> &names, int get_hidden) {
    size_t i;

    const env_var_t path_var_wstr = env_get_string(L"fish_function_path");
    if (path_var_wstr.missing()) return;
    const wchar_t *path_var = path_var_wstr.c_str();

    wcstring_list_t path_list;

    tokenize_variable_array(path_var, path_list);
    for (i = 0; i < path_list.size(); i++) {
        const wcstring &ndir_str = path_list.at(i);
        const wchar_t *ndir = (wchar_t *)ndir_str.c_str();
        DIR *dir = wopendir(ndir);
        if (!dir) continue;

        wcstring name;
        while (wreaddir(dir, name)) {
            const wchar_t *fn = name.c_str();
            const wchar_t *suffix;
            if (!get_hidden && fn[0] == L'_') continue;

            suffix = wcsrchr(fn, L'.');
            if (suffix && (wcscmp(suffix, L".fish") == 0)) {
                wcstring name(fn, suffix - fn);
                names.insert(name);
            }
        }
        closedir(dir);
    }
}
示例#2
0
bool DirectoryExists(const OsPath& path)
{
	WDIR* dir = wopendir(path);
	if(dir)
	{
		wclosedir(dir);
		return true;
	}
	return false;
}
示例#3
0
 // Helper to resolve using our prefix.
 DIR *open_dir(const wcstring &base_dir) const {
     wcstring path = this->working_directory;
     append_path_component(path, base_dir);
     if (flags & EXPAND_SPECIAL_FOR_CD) {
         // cd operates on logical paths.
         // for example, cd ../<tab> should complete "without resolving symlinks".
         path = normalize_path(path);
     } else {
         // Other commands operate on physical paths.
         if (auto tmp = wrealpath(path)) {
             path = tmp.acquire();
         }
     }
     return wopendir(path);
 }
示例#4
0
    // Given a start point as an absolute path, for any directory that has exactly one non-hidden
    // entity in it which is itself a directory, return that. The result is a relative path. For
    // example, if start_point is '/usr' we may return 'local/bin/'.
    //
    // The result does not have a leading slash, but does have a trailing slash if non-empty.
    wcstring descend_unique_hierarchy(const wcstring &start_point) {
        assert(!start_point.empty() && start_point.at(0) == L'/');

        wcstring unique_hierarchy;
        wcstring abs_unique_hierarchy = start_point;

        bool stop_descent = false;
        DIR *dir;
        while (!stop_descent && (dir = wopendir(abs_unique_hierarchy))) {
            // We keep track of the single unique_entry entry. If we get more than one, it's not
            // unique and we stop the descent.
            wcstring unique_entry;

            bool child_is_dir;
            wcstring child_entry;
            while (wreaddir_resolving(dir, abs_unique_hierarchy, child_entry, &child_is_dir)) {
                if (child_entry.empty() || child_entry.at(0) == L'.') {
                    continue;  // either hidden, or . and .. entries -- skip them
                } else if (child_is_dir && unique_entry.empty()) {
                    unique_entry = child_entry;  // first candidate
                } else {
                    // We either have two or more candidates, or the child is not a directory. We're
                    // done.
                    stop_descent = true;
                    break;
                }
            }

            // We stop if we got two or more entries; also stop if we got zero or were interrupted
            if (unique_entry.empty() || interrupted()) {
                stop_descent = true;
            }

            if (!stop_descent) {
                // We have an entry in the unique hierarchy!
                append_path_component(unique_hierarchy, unique_entry);
                unique_hierarchy.push_back(L'/');

                append_path_component(abs_unique_hierarchy, unique_entry);
                abs_unique_hierarchy.push_back(L'/');
            }
            closedir(dir);
        }
        return unique_hierarchy;
    }
示例#5
0
Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames* subdirectoryNames)
{
	// open directory
	errno = 0;
	WDIR* pDir = wopendir(path);
	if(!pDir)
		return StatusFromErrno();	// NOWARN
	shared_ptr<WDIR> osDir(pDir, DirDeleter());

	for(;;)
	{
		errno = 0;
		struct wdirent* osEnt = wreaddir(osDir.get());
		if(!osEnt)
		{
			// no error, just no more entries to return
			if(!errno)
				return INFO::OK;
			WARN_RETURN(StatusFromErrno());
		}

		for(size_t i = 0; osEnt->d_name[i] != '\0'; i++)
			RETURN_STATUS_IF_ERR(Path::Validate(osEnt->d_name[i]));
		const OsPath name(osEnt->d_name);

		// get file information (mode, size, mtime)
		struct stat s;
#if OS_WIN
		// .. return wdirent directly (much faster than calling stat).
		RETURN_STATUS_IF_ERR(wreaddir_stat_np(osDir.get(), &s));
#else
		// .. call regular stat().
		errno = 0;
		const OsPath pathname = path / name;
		if(wstat(pathname, &s) != 0)
			WARN_RETURN(StatusFromErrno());
#endif

		if(files && S_ISREG(s.st_mode))
			files->push_back(CFileInfo(name, s.st_size, s.st_mtime));
		else if(subdirectoryNames && S_ISDIR(s.st_mode) && name != L"." && name != L"..")
			subdirectoryNames->push_back(name);
	}
}
示例#6
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards. 
 */
static int wildcard_expand_internal( const wchar_t *wc,
									 const wchar_t *base_dir,
									 expand_flags_t flags,
									 std::vector<completion_t> &out,
                                     std::set<wcstring> &completion_set,
                                     std::set<file_id_t> &visited_files
                                   )
{

	/* Points to the end of the current wildcard segment */
	const wchar_t *wc_end;

	/* Variables for traversing a directory */
	DIR *dir;
	
	/* The result returned */
	int res = 0;
	
	/* Length of the directory to search in */
	size_t base_len;

	/* Variables for testing for presense of recursive wildcards */
	const wchar_t *wc_recursive;
	int is_recursive;

	/* Slightly mangled version of base_dir */
	const wchar_t *dir_string;
	
	//	debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

	if( reader_interrupted() )
	{
		return -1;
	}
	
	if( !wc || !base_dir )
	{
		debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
		return 0;		
	}

	if( flags & ACCEPT_INCOMPLETE )
	{	
		/* 
		   Avoid excessive number of returned matches for wc ending with a * 
		*/
		size_t len = wcslen(wc);
		if( len && (wc[len-1]==ANY_STRING) )
		{
			wchar_t * foo = wcsdup( wc );
			foo[len-1]=0;
			int res = wildcard_expand_internal( foo, base_dir, flags, out, completion_set, visited_files );
			free( foo );
			return res;			
		}
	}

	/*
	  Initialize various variables
	*/

	dir_string = base_dir[0]==L'\0'?L".":base_dir;
	
	if( !(dir = wopendir( dir_string )))
	{
		return 0;
	}

	wc_end = wcschr(wc,L'/');
	base_len = wcslen( base_dir );

	/*
	  Test for recursive match string in current segment
	*/	
	wc_recursive = wcschr( wc, ANY_STRING_RECURSIVE );
	is_recursive = ( wc_recursive && (!wc_end || wc_recursive < wc_end));

	/*
	  Is this segment of the wildcard the last?
	*/
	if( !wc_end )
	{
		/*
		  Wildcard segment is the last segment,

		  Insert all matching files/directories
		*/
		if( wc[0]=='\0' )
		{
			/*
			  The last wildcard segment is empty. Insert everything if
			  completing, the directory itself otherwise.
			*/
			if( flags & ACCEPT_INCOMPLETE )
			{
                wcstring next;
				while(wreaddir(dir, next))
				{
					if( next[0] != L'.' )
					{
						wcstring long_name = make_path( base_dir, next );
						
						if( test_flags( long_name.c_str(), flags ) )
						{
							wildcard_completion_allocate( out,
														  long_name,
														  next,
														  L"",
                                                          flags);
						}
					}					
				}
			}
			else
			{
				res = 1;
                insert_completion_if_missing(base_dir, out, completion_set);
			}
		}
		else
		{
			/*
			  This is the last wildcard segment, and it is not empty. Match files/directories.
			*/
            wcstring next;
			while (wreaddir(dir, next))
			{
                const wchar_t * const name = next.c_str();
				if( flags & ACCEPT_INCOMPLETE )
				{
					
					const wcstring long_name = make_path( base_dir, next );

					/*
					  Test for matches before stating file, so as to minimize the number of calls to the much slower stat function 
					*/
					std::vector<completion_t> test;
					if( wildcard_complete( name,
										   wc,
										   L"",
										   0,
										   test,
										   0 ) )
					{
						if( test_flags( long_name.c_str(), flags ) )
						{
							wildcard_completion_allocate( out,
														  long_name,
                                                          name,
														  wc,
                                                          flags);
							
						}
					}					
				}
				else
				{
					if( wildcard_match2( name, wc, 1 ) )
					{
                        const wcstring long_name = make_path(base_dir, next);
						int skip = 0;
						
						if( is_recursive )
						{
							/*
							  In recursive mode, we are only
							  interested in adding files -directories
							  will be added in the next pass.
							*/
							struct stat buf;
							if( !wstat( long_name, &buf ) )
							{
								skip = S_ISDIR(buf.st_mode);
							}							
						}
						if (! skip)
						{
                            insert_completion_if_missing(long_name, out, completion_set);
						}
						res = 1;
					}
				}
			}
		}
	}

	if( wc_end || is_recursive )
	{
		/*
		  Wilcard segment is not the last segment.  Recursively call
		  wildcard_expand for all matching subdirectories.
		*/
		
		/*
		  wc_str is the part of the wildcarded string from the
		  beginning to the first slash
		*/
		wchar_t *wc_str;

		/*
		  new_dir is a scratch area containing the full path to a
		  file/directory we are iterating over
		*/
		wchar_t *new_dir;

		/*
		  The maximum length of a file element
		*/
		long ln=MAX_FILE_LENGTH;
		char * narrow_dir_string = wcs2str( dir_string );

		/*
		  In recursive mode, we look through the directory twice. If
		  so, this rewind is needed.
		*/
		rewinddir( dir );

		if( narrow_dir_string )
		{
			/* 
			   Find out how long the filename can be in a worst case
			   scenario
			*/
			ln = pathconf( narrow_dir_string, _PC_NAME_MAX ); 

			/*
			  If not specified, use som large number as fallback
			*/
			if( ln < 0 )
				ln = MAX_FILE_LENGTH;		
			free( narrow_dir_string );
		}
		new_dir= (wchar_t *)malloc( sizeof(wchar_t)*(base_len+ln+2)  );

		wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc);

		if( (!new_dir) || (!wc_str) )
		{
			DIE_MEM();
		}

		wcscpy( new_dir, base_dir );
		
        wcstring next;
		while (wreaddir(dir, next))
		{
			const wchar_t *name = next.c_str();
			
			/*
			  Test if the file/directory name matches the whole
			  wildcard element, i.e. regular matching.
			*/
			int whole_match = wildcard_match2( name, wc_str, 1 );
			int partial_match = 0;
			
			/* 
			   If we are doing recursive matching, also check if this
			   directory matches the part up to the recusrive
			   wildcard, if so, then we can search all subdirectories
			   for matches.
			*/
			if( is_recursive )
			{
				const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE );
				wchar_t *wc_sub = wcsndup( wc, end-wc+1);
				partial_match = wildcard_match2( name, wc_sub, 1 );
				free( wc_sub );
			}			

			if( whole_match || partial_match )
			{
				struct stat buf;			
				char *dir_str;
				int stat_res;
				int new_res;

				wcscpy(&new_dir[base_len], name );
				dir_str = wcs2str( new_dir );
				
				if( dir_str )
				{
					stat_res = stat( dir_str, &buf );
					free( dir_str );
					
					if( !stat_res )
					{
                        // Insert a "file ID" into visited_files
                        // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                        const file_id_t file_id(buf.st_dev, buf.st_ino);
						if( S_ISDIR(buf.st_mode) && visited_files.insert(file_id).second)
						{
							size_t new_len = wcslen( new_dir );
							new_dir[new_len] = L'/';
							new_dir[new_len+1] = L'\0';
							
							/*
							  Regular matching
							*/
							if( whole_match )
							{
								const wchar_t *new_wc = L"";
								if( wc_end )
								{
									new_wc=wc_end+1;
									/*
									  Accept multiple '/' as a single direcotry separator
									*/
									while(*new_wc==L'/')
									{
										new_wc++;
									}
								}
								
								new_res = wildcard_expand_internal( new_wc,
																	new_dir, 
																	flags, 
																	out,
                                                                    completion_set,
                                                                    visited_files );

								if( new_res == -1 )
								{
									res = -1;
									break;
								}								
								res |= new_res;
								
							}
							
							/*
							  Recursive matching
							*/
							if( partial_match )
							{
								
								new_res = wildcard_expand_internal( wcschr( wc, ANY_STRING_RECURSIVE ), 
																	new_dir,
																	flags | WILDCARD_RECURSIVE, 
																	out,
                                                                    completion_set,
                                                                    visited_files);

								if( new_res == -1 )
								{
									res = -1;
									break;
								}								
								res |= new_res;
								
							}
						}								
					}
				}
			}
		}
		
		free( wc_str );
		free( new_dir );
	}
	closedir( dir );

	return res;
}
示例#7
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards.

   Because this function calls itself recursively with substrings,
   it's important that the parameters be raw pointers instead of wcstring,
   which would be too expensive to construct for all substrings.
 */
static int wildcard_expand_internal(const wchar_t *wc,
                                    const wchar_t * const base_dir,
                                    expand_flags_t flags,
                                    std::vector<completion_t> *out,
                                    std::set<wcstring> &completion_set,
                                    std::set<file_id_t> &visited_files)
{
    /* Variables for traversing a directory */
    DIR *dir;

    /* The result returned */
    int res = 0;


    //  debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

    if (is_main_thread() ? reader_interrupted() : reader_thread_job_is_stale())
    {
        return -1;
    }

    if (!wc || !base_dir)
    {
        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
        return 0;
    }

    const size_t base_dir_len = wcslen(base_dir);
    const size_t wc_len = wcslen(wc);

    if (flags & ACCEPT_INCOMPLETE)
    {
        /*
           Avoid excessive number of returned matches for wc ending with a *
        */
        if (wc_len > 0 && (wc[wc_len-1]==ANY_STRING))
        {
            wchar_t * foo = wcsdup(wc);
            foo[wc_len-1]=0;
            int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
            free(foo);
            return res;
        }
    }

    /* Determine if we are the last segment */
    const wchar_t * const next_slash = wcschr(wc,L'/');
    const bool is_last_segment = (next_slash == NULL);
    const size_t wc_segment_len = next_slash ? next_slash - wc : wc_len;
    const wcstring wc_segment = wcstring(wc, wc_segment_len);
    
    /* Maybe this segment has no wildcards at all. If this is not the last segment, and it has no wildcards, then we don't need to match against the directory contents, and in fact we don't want to match since we may not be able to read it anyways (#2099). Don't even open the directory! */
    const bool segment_has_wildcards = wildcard_has(wc_segment, true /* internal, i.e. look for ANY_CHAR instead of ? */);
    if (! segment_has_wildcards && ! is_last_segment)
    {
        wcstring new_base_dir = make_path(base_dir, wc_segment);
        new_base_dir.push_back(L'/');
        
        /* Skip multiple separators */
        assert(next_slash != NULL);
        const wchar_t *new_wc = next_slash;
        while (*new_wc==L'/')
        {
            new_wc++;
        }
        /* Early out! */
        return wildcard_expand_internal(new_wc, new_base_dir.c_str(), flags, out, completion_set, visited_files);
    }
    
    /* Test for recursive match string in current segment */
    const bool is_recursive = (wc_segment.find(ANY_STRING_RECURSIVE) != wcstring::npos);
    

    const wchar_t *base_dir_or_cwd = (base_dir[0] == L'\0') ? L"." : base_dir;
    if (!(dir = wopendir(base_dir_or_cwd)))
    {
        return 0;
    }
    
    /*
      Is this segment of the wildcard the last?
    */
    if (is_last_segment)
    {
        /*
          Wildcard segment is the last segment,

          Insert all matching files/directories
        */
        if (wc[0]=='\0')
        {
            /*
              The last wildcard segment is empty. Insert everything if
              completing, the directory itself otherwise.
            */
            if (flags & ACCEPT_INCOMPLETE)
            {
                wcstring next;
                while (wreaddir(dir, next))
                {
                    if (next[0] != L'.')
                    {
                        wcstring long_name = make_path(base_dir, next);

                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, next, L"", flags);
                        }
                    }
                }
            }
            else
            {
                res = 1;
                insert_completion_if_missing(base_dir, out, &completion_set);
            }
        }
        else
        {
            /* This is the last wildcard segment, and it is not empty. Match files/directories. */
            wcstring name_str;
            while (wreaddir(dir, name_str))
            {
                if (flags & ACCEPT_INCOMPLETE)
                {

                    const wcstring long_name = make_path(base_dir, name_str);

                    /* Test for matches before stating file, so as to minimize the number of calls to the much slower stat function. The only expand flag we care about is EXPAND_FUZZY_MATCH; we have no complete flags. */
                    std::vector<completion_t> test;
                    if (wildcard_complete(name_str, wc, L"", NULL, &test, flags & EXPAND_FUZZY_MATCH, 0))
                    {
                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, name_str, wc, flags);

                        }
                    }
                }
                else
                {
                    if (wildcard_match(name_str, wc, true /* skip files with leading dots */))
                    {
                        const wcstring long_name = make_path(base_dir, name_str);
                        int skip = 0;

                        if (is_recursive)
                        {
                            /*
                              In recursive mode, we are only
                              interested in adding files -directories
                              will be added in the next pass.
                            */
                            struct stat buf;
                            if (!wstat(long_name, &buf))
                            {
                                skip = S_ISDIR(buf.st_mode);
                            }
                        }
                        if (! skip)
                        {
                            insert_completion_if_missing(long_name, out, &completion_set);
                        }
                        res = 1;
                    }
                }
            }
        }
    }

    if ((! is_last_segment) || is_recursive)
    {
        /*
          Wilcard segment is not the last segment.  Recursively call
          wildcard_expand for all matching subdirectories.
        */

        /*
          In recursive mode, we look through the directory twice. If
          so, this rewind is needed.
        */
        rewinddir(dir);

        /* new_dir is a scratch area containing the full path to a file/directory we are iterating over */
        wcstring new_dir = base_dir;

        wcstring name_str;
        while (wreaddir(dir, name_str))
        {
            /*
              Test if the file/directory name matches the whole
              wildcard element, i.e. regular matching.
            */
            bool whole_match = wildcard_match(name_str, wc_segment, true /* ignore leading dots */);
            bool partial_match = false;

            /*
               If we are doing recursive matching, also check if this
               directory matches the part up to the recusrive
               wildcard, if so, then we can search all subdirectories
               for matches.
            */
            if (is_recursive)
            {
                const wchar_t *end = wcschr(wc, ANY_STRING_RECURSIVE);
                wchar_t *wc_sub = wcsndup(wc, end-wc+1);
                partial_match = wildcard_match(name_str, wc_sub, true /* ignore leading dots */);
                free(wc_sub);
            }

            if (whole_match || partial_match)
            {
                struct stat buf;
                int new_res;

                // new_dir is base_dir + some other path components
                // Replace everything after base_dir with the new path component
                new_dir.replace(base_dir_len, wcstring::npos, name_str);

                int stat_res = wstat(new_dir, &buf);

                if (!stat_res)
                {
                    // Insert a "file ID" into visited_files
                    // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                    // If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
                    const file_id_t file_id = file_id_t::file_id_from_stat(&buf);
                    if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
                    {
                        new_dir.push_back(L'/');

                        /*
                          Regular matching
                        */
                        if (whole_match)
                        {
                            const wchar_t *new_wc = L"";
                            if (next_slash)
                            {
                                new_wc=next_slash+1;
                                /*
                                  Accept multiple '/' as a single directory separator
                                */
                                while (*new_wc==L'/')
                                {
                                    new_wc++;
                                }
                            }

                            new_res = wildcard_expand_internal(new_wc,
                                                               new_dir.c_str(),
                                                               flags,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }

                        /*
                          Recursive matching
                        */
                        if (partial_match)
                        {

                            new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
                                                               new_dir.c_str(),
                                                               flags | WILDCARD_RECURSIVE,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }
                    }
                }
            }
        }
    }
    closedir(dir);

    return res;
}
示例#8
0
/**
   Directory tree is now
 
     top / topfile
           middle2 /   
           middle1 / bottom1 / absfile
                   / bottom2 / file                -- read-only
 		   / read-only / sub-read-only /
                                 file
 

@SYMTestCaseID          SYSLIB-STDLIB-CT-1050
@SYMTestCaseDesc	    Tests for enumeration on directories 
@SYMTestPriority 	    High
@SYMTestActions  	    Tests by opening directories
@SYMTestExpectedResults Test must not fail
@SYMREQ                 REQ0000
*/		
void directory()
	{
	int err, count, i, j, fd;
	DIR *dp;
	struct dirent *ep;
	char name[MAXPATHLEN+1];
	off_t pos;

	test_Next("Enumerating Directories");

	err=chdir(rootpath);
	test(err==0);

	dp=opendir("topfile");
	/* test_errno(dp==0,ENOTDIR); -- not convinced about this anyway */
	test_errno(dp==0,ENOENT);

	dp=opendir("no such file");
	test_errno(dp==0,ENOENT);


	//test something sensible happens if someone uses a WDIR inplace of a DIR
	{
		WDIR *wp = wopendir((wchar_t*)L".");
		test(wp!=0);

		// Test wants a WDIR passed but won't compile under CW.
		// Force the compile by casting. The function will still get a WDIR.
		// DIR inherits from WDIR.
		ep=readdir((DIR*)wp);
		test_errno(ep==0,EINVAL);

		wclosedir(wp);
	}




	dp=opendir(".");
	test(dp!=0);

	count=0;
	do
		{
		ep=readdir(dp);
		if (ep && strcmp(ep->d_name,".")!=0 && strcmp(ep->d_name,"..")!=0)
			count++;
		}
	while (ep!=0);
	test(count==4);

	for (i=0; i<4; i++)
		{
		rewinddir(dp);
		for (j=0; j<=i; j++)
			{
			ep=readdir(dp);
			test(ep!=0);
			}
		strcpy(name,ep->d_name);
		rewinddir(dp);
		for (j=0; j<=i; j++)
			{
			ep=readdir(dp);
			test(ep!=0);
			}
		test(strcmp(name,ep->d_name)==0);
		}

	for (i=0; i<4; i++)
		{
		rewinddir(dp);
		pos=telldir(dp);
		for (j=0; j<=i; j++)
			{
			pos=telldir(dp);
			ep=readdir(dp);
			test(ep!=0);
			}
		strcpy(name,ep->d_name);
		rewinddir(dp);
		seekdir(dp, pos);
		ep=readdir(dp);
		test(ep!=0);
		test(strcmp(name,ep->d_name)==0);
		}

	err=closedir(dp);
	test(err==0);

	dp=opendir("middle2");
	test(dp!=0);

	count=0;
	do
		{
		ep=readdir(dp);
		if (ep && strcmp(ep->d_name,".")!=0 && strcmp(ep->d_name,"..")!=0)
			count++;
		}
	while (ep!=0);
	test(count==0);	/* empty directory */

	rewinddir(dp);

	fd = open("middle2/extrafile",O_RDWR+O_CREAT,0777);
	test(fd>=0);

	err=close(fd);
	test(err==0);

	count=0;
	do
		{
		ep=readdir(dp);
		if (ep && strcmp(ep->d_name,".")!=0 && strcmp(ep->d_name,"..")!=0)
			count++;
		}
	while (ep!=0);
	test(count==0);	/* shouldn't have noticed the change */

	rewinddir(dp);	/* and spot the new file */
	count=0;
	do
		{
		ep=readdir(dp);
		if (ep && strcmp(ep->d_name,".")!=0 && strcmp(ep->d_name,"..")!=0)
			count++;
		}
	while (ep!=0);
	test(count==1);

	closedir(dp);

	dp=opendir("/");
	test(dp!=0);

	count=0;
	do
		{
		ep=readdir(dp);
		if (ep && strcmp(ep->d_name,".")!=0 && strcmp(ep->d_name,"..")!=0)
			count++;
		}
	while (ep!=0);
	test(count>0);

	closedir(dp);
	}
示例#9
0
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O!

   We expect the path to already be unescaped.
*/
bool is_potential_path(const wcstring &const_path, const wcstring_list_t &directories, path_flags_t flags, wcstring *out_path)
{
    ASSERT_IS_BACKGROUND_THREAD();
    
    const bool require_dir = !! (flags & PATH_REQUIRE_DIR);
    wcstring clean_path;
	int has_magic = 0;
	bool result = false;
    
    wcstring path(const_path);
    if (flags & PATH_EXPAND_TILDE)
        expand_tilde(path);    
    
    //	debug( 1, L"%ls -> %ls ->%ls", path, tilde, unescaped );
    
    for( size_t i=0; i < path.size(); i++)
    {
        wchar_t c = path.at(i);
        switch( c )
        {
            case PROCESS_EXPAND:
            case VARIABLE_EXPAND:
            case VARIABLE_EXPAND_SINGLE:
            case BRACKET_BEGIN:
            case BRACKET_END:
            case BRACKET_SEP:
            case ANY_CHAR:
            case ANY_STRING:
            case ANY_STRING_RECURSIVE:
            {
                has_magic = 1;
                break;		
            }
				
            case INTERNAL_SEPARATOR:
            {
                break;
            }
				
            default:
            {
                clean_path.push_back(c);
                break;
            }
				
        }
        
    }
    
    if( ! has_magic && ! clean_path.empty() )
    {
        /* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */
        std::set<wcstring> checked_paths;
        
        /* Keep a cache of which paths / filesystems are case sensitive */
        case_sensitivity_cache_t case_sensitivity_cache;
        
        for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) {
            const wcstring &wd = directories.at(wd_idx);
            
            const wcstring abs_path = apply_working_directory(clean_path, wd);
            
            /* Skip this if it's empty or we've already checked it */
            if (abs_path.empty() || checked_paths.count(abs_path))
                continue;
            checked_paths.insert(abs_path);
            
            /* If we end with a slash, then it must be a directory */
            bool must_be_full_dir = abs_path.at(abs_path.size()-1) == L'/';
            if (must_be_full_dir) 
            {
                struct stat buf;
                if (0 == wstat(abs_path, &buf) && S_ISDIR(buf.st_mode)) {
                    result = true;
                    /* Return the path suffix, not the whole absolute path */
                    if (out_path)
                        *out_path = clean_path;
                }
            }
            else
            {
                DIR *dir = NULL;
                
                /* We do not end with a slash; it does not have to be a directory */
                const wcstring dir_name = wdirname(abs_path);
                const wcstring base_name = wbasename(abs_path);
                if (dir_name == L"/" && base_name == L"/")
                {
                    result = true;
                    if (out_path)
                        *out_path = clean_path;
                }
                else if ((dir = wopendir(dir_name))) {
                    // We opened the dir_name; look for a string where the base name prefixes it
                    wcstring ent;
                    
                    // Check if we're case insensitive
                    bool case_insensitive = fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache);
                    
                    // Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */
                    bool is_dir = false;
                    while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL))
                    {                    

                        /* Determine which function to call to check for prefixes */
                        bool (*prefix_func)(const wcstring &, const wcstring &);
                        if (case_insensitive) {
                            prefix_func = string_prefixes_string_case_insensitive;
                        } else {
                            prefix_func = string_prefixes_string;
                        }

                        if (prefix_func(base_name, ent) && (! require_dir || is_dir))
                        {
                            result = true;
                            if (out_path) {
                                /* We want to return the path in the same "form" as it was given. Take the given path, get its basename. Append that to the output if the basename actually prefixes the path (which it won't if the given path contains no slashes), and isn't a slash (so we don't duplicate slashes). Then append the directory entry. */
                                
                                out_path->clear();
                                const wcstring path_base = wdirname(const_path);
                                
                                
                                if (prefix_func(path_base, const_path)) {
                                    out_path->append(path_base);
                                    if (! string_suffixes_string(L"/", *out_path))
                                        out_path->push_back(L'/');
                                }
                                out_path->append(ent);
                                /* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
                                if (is_dir)
                                    out_path->push_back(L'/');
                            }
                            break;
                        }
                    }
                    closedir(dir);
                }
            }
        }
    }
    return result;
}