How to check if a folder is actually an alias in C (macOS)?

I’m writing a simple recursive program that looks for specific files in a certain directory tree on macOS.
Problem is, if it finds an alias to a folder that is above the current directory on the same branch of the tree it starts to loop infinitely and crashes after a while with segmentation fault (after only 252 levels or so of recursion it seems, which appears to be a low number to me by the way). I tried to modify my code not to navigate files which are symbolic links, but it still navigates those aliases.

Here’s an example structure of directories(every line has at the left the name of some folder, at the right its contents):

folder1: folder2

folder2: folder1(alias)

These are some lines taken out from the code I wrote, updated to be complete(without frees and error checks):

char *name = //target file name
int myfind(){
    DIR *curr_dir = opendir(".");
    struct dirent *next_entry;
    struct stat info;
    char *entry_name;
    char *path;
    while((next_entry = readdir(curr_dir)) != NULL){
        entry_name = next_entry->d_name;
        //ignore . and ..
        if(strcmp(entry_name,".") == 0 || strcmp(entry_name,"..") == 0)
            continue;
        stat(entry_name, &info);
        if(strncmp(name, entry_name, 255) == 0){
            path = realpath(entry_name, NULL);
            //print info about file found
        }
        if(S_ISDIR(info.st_mode) && !S_ISLNK(info.st_mode)){ 
            char *prev_path = getwd(NULL);
            chdir(entry_name);
            myfind();
            chdir(prev_path);
        }
    }
}

>Solution :

I tried to modify my code not to navigate files which are symbolic links, but it still navigates those aliases

stat() will never return data such that S_ISLNK(info.st_mode) is true (except see below). Per the POSIX stat() documentation:

If the named file is a symbolic link, the stat() function shall continue pathname resolution using the contents of the symbolic link, and shall return information pertaining to the resulting file if the file exists.

and

The lstat() function shall be equivalent to stat(), except when path refers to a symbolic link. In that case lstat() shall return information about the link, while stat() shall return information about the file the link references.

You need to replace

stat(entry_name, &info);
if(S_ISDIR(info.st_mode) && !S_ISLNK(info.st_mode)){ 
  //navigate to next_entry
}

with

int rc = lstat(entry_name, &info);
if((rc==0) && S_ISDIR(info.st_mode) && !S_ISLNK(info.st_mode)){ 
  //navigate to next_entry
}

Note also the return value from [l]stat() needs to be checked. The contents of the info struct will not mean anything if the [l]stat() call fails, so the checks using ISDIR() and ISLNK() could return any value.

Leave a Reply