{"id":3279,"date":"2018-09-15T00:01:35","date_gmt":"2018-09-15T07:01:35","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=3279"},"modified":"2018-09-22T09:42:58","modified_gmt":"2018-09-22T16:42:58","slug":"directory-spelunking","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=3279","title":{"rendered":"Directory Spelunking"},"content":{"rendered":"<p>Exploring a folder tree &mdash; I mean <em>directory<\/em> tree &mdash; is a procedure found in many file and media utilities. From an original directory, you scan the list of files looking for a subdirectory. When it&#8217;s found, you open it and recursively continue the scan.<br \/>\n<!--more--><br \/>\nFor example, in Unix, you can use the <em>du<\/em> command to recursively scan directories and discover how many blocks they consume. (A block is 512 bytes.) In Windows, both the cmd (command prompt) and PowerShell terminals use the <code>TREE<\/code> command to list directories and subdirectories.<\/p>\n<p>To plumb these depths, you need a recursive function, which goes like this:<\/p>\n<ol>\n<li>Change to a given directory, which is passed to the recursive function as an argument.<\/li>\n<li>Open the current directory for reading.<\/li>\n<li>Scan for any subdirectory entries, ignoring the . and .. entries.<\/li>\n<li>If a subdirectory entry is found, dive into Step 2 again.<\/li>\n<li>Change back to the parent directory and continue the scan at Step 3.<\/li>\n<\/ol>\n<p>Not covered in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3263\">last week&#8217;s Lesson<\/a> is the <em>chdir()<\/em> function. Like its shell counterpart, the <em>chdir()<\/em> function changes to the named directory:<\/p>\n<p><code>int chdir(const char *path)<\/code><\/p>\n<p>The <code>path<\/code> is the name of a directory, and the . and .. abbreviations can be used. Upon success, the function returns zero, otherwise -1. The <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=1735\">errno<\/a> variable can be checked to determine the specific reason <em>chdir()<\/em> failed.<\/p>\n<p>The <em>chdir()<\/em> function is prototyped in the <code>unistd.h<\/code> header file.<\/p>\n<p>Using the code presented in last week&#8217;s Lesson as a base, I wrote the <em>dir()<\/em> function. It requires two arguments, a directory (or pathname) and an integer <code>depth<\/code> value:<\/p>\n<p><code>void dir(char *directory,int depth)<\/code><\/p>\n<p>This function changes to the named <em>directory<\/em> and reads its listing, scanning for subdirectories. If found, the function calls itself (recurses). The <code>depth<\/code> argument helps indent the directories in the output.<\/p>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;dirent.h&gt;\r\n#include &lt;sys\/stat.h&gt;\r\n\r\nvoid dir(char *directory,int depth);\r\n\r\nint main(int argc, char *argv[])\r\n{\r\n    puts(\"Finding Directories\");\r\n\r\n    if(argc==2)\r\n        dir(argv[1],0);\r\n    else\r\n        dir(\".\",0);\r\n\r\n    return(0);\r\n}\r\n\r\nvoid dir(char *directory,int depth)\r\n{\r\n    DIR *folder;\r\n    struct dirent *entry;\r\n    struct stat filestat;\r\n\r\n    <span class=\"comments\">\/* Change to the named directory *\/<\/span>\r\n    if(chdir(directory))\r\n    {\r\n        fprintf(stderr,\"Error changing to %s\\n\",directory);\r\n        exit(1);\r\n    }\r\n\r\n    <span class=\"comments\">\/* open the directory *\/<\/span>\r\n    folder = opendir(\".\");\r\n    if(folder == NULL)\r\n    {\r\n        fprintf(stderr,\"Unable to read directory %s\\n\",directory);\r\n        exit(1);\r\n    }\r\n\r\n    printf(\"%*s%s\\n\",depth*2,\" \",directory);\r\n    <span class=\"comments\">\/* Look for a subdirectory *\/<\/span>\r\n    while( (entry=readdir(folder)) )\r\n    {\r\n        stat(entry-&gt;d_name,&amp;filestat);\r\n        <span class=\"comments\">\/* look for only directories *\/<\/span>\r\n        if( S_ISDIR(filestat.st_mode) )\r\n        {\r\n            <span class=\"comments\">\/* skip the . and .. entries *\/<\/span>\r\n            if(strcmp(entry-&gt;d_name,\".\")==0 || strcmp(entry-&gt;d_name,\"..\")==0)\r\n                continue;\r\n            <span class=\"comments\">\/* recurse to the found directory *\/<\/span>\r\n            dir(entry-&gt;d_name,depth+1);\r\n        }\r\n    }\r\n\r\n    chdir(\"..\");\r\n    closedir(folder);\r\n}<\/pre>\n<p>In the <em>main()<\/em> function, you can specify a directory to plumb at the command line, otherwise the current directory is used by default.<\/p>\n<p>At the start of the <em>dir()<\/em> function, <em>chdir()<\/em> changes to the named directory, which is opened at Line 36.<\/p>\n<p>The directory name is printed at Line 43. The <code>depth<\/code> value is used to indent the name by a given number of spaces. (See <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=2972\">this Lesson<\/a>.)<\/p>\n<p>The <em>while<\/em> loop scans the directory entries, with help from the <em>if<\/em> statement at Line 49. At Line 52, the . and .. entries are skipped. Whatever remains is a subdirectory entry, which is explored recursively at Line 55, along with an incremented value for <code>depth<\/code>.<\/p>\n<p>As the recursive function rewinds, the <em>chdir()<\/em> function at Line 59 returns to the parent directory.<\/p>\n<p>This code does have some flaws. For example, it crashes when reading the root directory because you can&#8217;t change to .. (the root&#8217;s parent), which doesn&#8217;t exist. The code is unable to track the parent directories of symbolic links in some filesystems. If you encounter a folder that needs permissions to open, the program halts.<\/p>\n<p>I address the symbolic link issue in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3291\">next week&#8217;s Lesson<\/a>, which improves the code to better track parent directories.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use what you know about reading directories to recursively plumb the depths of a directory tree structure. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3279\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-3279","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3279"}],"version-history":[{"count":8,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3279\/revisions"}],"predecessor-version":[{"id":3311,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3279\/revisions\/3311"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}