//Russell's Paradox in C
// or finding the directory of all directories without links to themselves
//
//Greg Michaelson
//G.Michaelson@hw.ac.uk
//2018
//
// runs in current directory, so best in an empty one...
//
// $ gcc -o para para.c
// $ ./para
// 
// press return at > to step

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>

char * join(char * s1,char * s2)
{  char * s;
   int i;
   i = 0;
   s = (char *)malloc(sizeof(char)*(strlen(s1)+strlen(s2)));
   while(*s1!='\0')
   {  s[i] = *s1;
      s1++;
      i++;
   }
   s[i] = '/';
   i++;
   while(*s2!='\0')
   {  s[i] = *s2;
      s2++;
      i++;
   }
   s[i] = '\0';
   return s;
}

void delCreate(char * dir)
{  DIR * d;
   struct dirent * rd;

   if(access(dir,F_OK)==0)
   {  d = opendir(dir);
      rd = readdir(d);
      while(rd!=NULL)
      {  if(rd->d_type==DT_LNK &&
            strcmp(rd->d_name,"..")!=0 &&
            strcmp(rd->d_name,".")!=0)
            unlink(join(dir,rd->d_name));
         rd = readdir(d);
      }
      closedir(d);
      unlink(dir);
   }
   mkdir(dir,S_IRWXU);
}

int contains(char * d1,char * d2)
{  DIR * d;
   struct dirent * rd;
   d = opendir(d1);
   rd = readdir(d);
   while(rd!=NULL)
    if(strcmp(rd->d_name,d2)==0)
    {  closedir(d);
       return 1;
    }
    else
     rd = readdir(d);
   closedir(d);
   return 0;
}

void self(char * s)
{  DIR * d;
   struct dirent * rd;

   int selfed;

   printf("checking %s\n",s);

   selfed = 0;

   d = opendir(s);
   rd = readdir(d);
   while(rd!=NULL)
   {  if(rd->d_type==DT_LNK)
       selfed =  selfed || strcmp(rd->d_name,s)==0;
      else
      if(rd->d_type==DT_DIR &&
         strcmp(rd->d_name,".")!=0 &&
         strcmp(rd->d_name,"..")!=0)
       self(rd->d_name);
      rd = readdir(d);
   }
   closedir(d);
   if(selfed)
   {  printf("%s - selfed - ",s);
      if(!contains("has-self",s))
      {  if(contains("no-self",s))
         {  printf("removing from no-self - ");
            unlink(join("no-self",s));
         }
         printf("adding to has-self >");
         symlink(s,join("has-self",s));
      }
      else
       printf("known >");
   }
   else
   {  printf("%s - not selfed - ",s);
      if(!contains("no-self",s))
      {  if(contains("has-self",s))
         {  printf("removing from has-self - ");
            unlink(join("has-self",s));
         }
         printf("adding to no-self >");
         symlink(s,join("no-self",s));
      }
      else
       printf("known >");
   }
getchar();
}

void main(int argc,char ** argv)
{  DIR * d;
   struct dirent * rd;

   delCreate("has-self");
   printf("made directory has-self\n");
   delCreate("no-self");
   printf("made directory no-self\n");

   while(1)
    self(".");
}
