Sign in to follow this  

get directory listing - c

This topic is 4384 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I need to get a list of files in a directory, and i remember using some c functions that work on both windows and unix. stuff related to chdir and getcwd or something. Any one know what the function names are?

Share this post


Link to post
Share on other sites
The _find* functions are not available on UNIX, so they don't quite meet supagu's requirements. He may be thinking of opendir, readdir et al, but they aren't available on Windows.

Reading directories is platform specific, in large part because of the differences in and complexities of filesystems. Sorry, your recollection may be wrong.

Share this post


Link to post
Share on other sites
the opendir(etc) and findfirst(etc) arent too different

i _think_ it wouldn't be too hard to write your own wrapper around them, it probably already has been done

EDIT: i hate when typos completly change the meaning of your post...

Share this post


Link to post
Share on other sites
Quote:
Original post by Oluseyi
He may be thinking of opendir, readdir et al, but they aren't available on Windows.

i dont know anything about msvc, but mingw (gcc for windows) does provide opendir and readdir

Share this post


Link to post
Share on other sites
Oops, overlooked the Unix requirement. In that case, you can do the following: emulate opendir() on Win32 and use POSIX interfaces in your code (this is nicer than a wrapper because people won't have to learn a new interface). Code to do so follows (200 lines; GPL license; some stuff will have to be stripped for it to compile since there are dependencies):


// opendir/readdir/closedir
//
// note: we avoid opening directories or returning entries that have
// hidden or system attributes set. this is to prevent returning something
// like "\System Volume Information", which raises an error upon opening.

// 0-initialized by wdir_alloc for safety; this is required for
// num_entries_scanned.
struct WDIR
{
HANDLE hFind;

// the dirent returned by readdir.
// note: having only one global instance is not possible because
// multiple independent opendir/readdir sequences must be supported.
struct dirent ent;

WIN32_FIND_DATA fd;

// since opendir calls FindFirstFile, we need a means of telling the
// first call to readdir that we already have a file.
// that's the case iff this is == 0; we use a counter rather than a
// flag because that allows keeping statistics.
int num_entries_scanned;
};


// suballocator - satisfies most requests with a reusable static instance.
// this avoids hundreds of alloc/free which would fragment the heap.
// to guarantee thread-safety, we fall back to malloc if the instance is
// already in use. (it's important to avoid suprises since this is such a
// low-level routine).

static WDIR global_wdir;
static uintptr_t global_wdir_is_in_use;

// zero-initializes the WDIR (code below relies on this)
static inline WDIR* wdir_alloc()
{
WDIR* d;

// successfully reserved the global instance
if(CAS(&global_wdir_is_in_use, 0, 1))
{
d = &global_wdir;
memset(d, 0, sizeof(*d));
}
else
d = (WDIR*)calloc(1, sizeof(WDIR));

return d;
}

static inline void wdir_free(WDIR* d)
{
if(d == &global_wdir)
global_wdir_is_in_use = 0;
else
free(d);
}


static const DWORD hs = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;

// make sure path exists and is a normal (according to attributes) directory.
static bool is_normal_dir(const char* path)
{
const DWORD fa = GetFileAttributes(path);
// .. path not found
if(fa == INVALID_FILE_ATTRIBUTES)
return false;
// .. not a directory
if((fa & FILE_ATTRIBUTE_DIRECTORY) == 0)
return false;
// .. hidden or system attribute(s) set
// this check is now disabled because wdetect's add_oal_dlls_in_dir
// needs to open the Windows system directory, which sometimes has
// these attributes set.
//if((fa & hs) != 0)
// return false;
return true;
}


DIR* opendir(const char* path)
{
if(!is_normal_dir(path))
{
errno = ENOENT;
fail:
debug_warn("opendir failed");
return 0;
}

WDIR* d = wdir_alloc();
if(!d)
{
errno = ENOMEM;
goto fail;
}

// build search path for FindFirstFile. note: "path\\dir" only returns
// information about that directory; trailing slashes aren't allowed.
// for dir entries to be returned, we have to append "\\*".
char search_path[PATH_MAX];
snprintf(search_path, ARRAY_SIZE(search_path), "%s\\*", path);

// note: we could store search_path and defer FindFirstFile until
// readdir. this way is a bit more complex but required for
// correctness (we must return a valid DIR iff <path> is valid).
d->hFind = FindFirstFileA(search_path, &d->fd);
if(d->hFind == INVALID_HANDLE_VALUE)
{
// not an error - the directory is just empty.
if(GetLastError() == ERROR_NO_MORE_FILES)
goto success;

// translate Win32 error to errno.
LibError err = LibError_from_win32(0);
LibError_set_errno(err);

// release the WDIR allocated above.
// unfortunately there's no way around this; we need to allocate
// d before FindFirstFile because it uses d->fd. copying from a
// temporary isn't nice either (this free doesn't happen often)
wdir_free(d);
goto fail;
}

success:
return d;
}


struct dirent* readdir(DIR* d_)
{
WDIR* const d = (WDIR*)d_;

// avoid polluting the last error.
DWORD prev_err = GetLastError();

// first call - skip FindNextFile (see opendir).
if(d->num_entries_scanned == 0)
{
// this directory is empty.
if(d->hFind == INVALID_HANDLE_VALUE)
return 0;
goto already_have_file;
}

// until end of directory or a valid entry was found:
for(;;)
{
if(!FindNextFileA(d->hFind, &d->fd))
goto fail;
already_have_file:

d->num_entries_scanned++;

// not a hidden or system entry -> it's valid.
if((d->fd.dwFileAttributes & hs) == 0)
break;
}

// this entry has passed all checks; return information about it.
// (note: d_name is a pointer; see struct dirent definition)
d->ent.d_name = d->fd.cFileName;
return &d->ent;

fail:
// FindNextFile failed; determine why and bail.
// .. legit, end of dir reached. don't pollute last error code.
if(GetLastError() == ERROR_NO_MORE_FILES)
SetLastError(prev_err);
else
debug_warn("readdir: FindNextFile failed");
return 0;
}


// return status for the dirent returned by the last successful
// readdir call from the given directory stream.
// currently sets st_size, st_mode, and st_mtime; the rest are zeroed.
// non-portable, but considerably faster than stat(). used by file_enum.
int readdir_stat_np(DIR* d_, struct stat* s)
{
WDIR* d = (WDIR*)d_;

memset(s, 0, sizeof(struct stat));
s->st_size = (off_t)u64_from_u32(d->fd.nFileSizeHigh, d->fd.nFileSizeLow);
s->st_mode = (d->fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
s->st_mtime = filetime_to_time_t(&d->fd.ftLastWriteTime);
return 0;
}


int closedir(DIR* d_)
{
WDIR* const d = (WDIR*)d_;

FindClose(d->hFind);

wdir_free(d);
return 0;
}

Share this post


Link to post
Share on other sites

This topic is 4384 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this