Thread: Getting absolute path of a file in c

  1. #1
    Registered User
    Join Date
    Dec 2018
    Posts
    13

    Unhappy Getting absolute path of a file in c

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<fcntl.h>
    #include<error.h>
    #include<limits.h>
    #include<sys/mman.h>
    #include<unistd.h>
    #include<memory.h>
    #include<sys/sysinfo.h>
    #include<dirent.h>
    #define  _POSIX_C_SOURCE 200809L
    
    //Sizes for an arr with files and dirs:
    #define A 4096
    #define B 512// Overflow - Why I cant put here ie 1024 but 512 works fine? 
    
    void pout( char (*array)[B])
    {
    for (size_t idx = 0; *array[idx] != 0; idx++)
        {
            printf("%s\n", array[idx]);
        }
    }
    
    int filemapper()
    {
    char files[A][B] = {0}, dirs[A][B] = {0};
        DIR* dir = opendir("/proc/self"); //random test dir
    if (dir == NULL)
        {
    return1;
        }
    
        size_t fidx = 0, didx = 0;
    struct dirent* entity;
        entity = readdir(dir);
    
    char CWD[PATH_MAX+1] = {0};
        getcwd(CWD, sizeof(CWD));
        printf("CWD : %s\n", CWD);
    char buf[PATH_MAX+1];
    
    while (entity != NULL)
        {
    char* path = realpath(entity->d_name, buf); // realpath not found
    
    switch (entity->d_type)
            {
    case4:
                    memcpy(dirs[didx], path, strlen(path));
                    strcat(dirs[didx], entity->d_name);
                    didx++;
    break;
    case8:
                    memcpy(files[fidx], path, strlen(path));
                    strcat(dirs[fidx], entity->d_name);
                    printf("FILE : %s\n", entity->d_name);
                    fidx++;
    break;
    default:
                    printf("Weird d_type of %hhd at %s\n", 
                    entity->d_type, entity->d_name);
    break;
            }
         entity = readdir(dir);   
        }
        printf("\nFILES:\n");
        pout(files);
        printf("\nDIRS:\n");
        pout(dirs);
        free(entity);free(dir);
    return0;
    }
    
    int main()
    {
        filemapper();
    return0;
    }
    
    
    or Compiler Explorer

    It is a simplified representation of my problem, the biggest issue is not having anything to get the absolute path that just works in c. I am sadly considering converting my project to C++, is there any other way?

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    You are defining the "feature test macro" _POSIX_C_SOURCE in the wrong place. It must be defined before the includes as that is where it is used to decide what to conditionally include.

    Why I cant put here ie 1024 but 512 works fine?
    Because you are defining the 2D array on the stack (two of them) and making them that big overflows the stack space. If you really need them that big you can 1) make them dynamic, 2) make them static, 3) make them global.

    Why this:
    Code:
    memcpy(dirs[didx], path, strlen(path));
    instead of this?
    Code:
    strcpy(dirs[didx], path);
    You are not supposed to free the return value of readdir. Where you are doing it entity is NULL anyway.
    You are not supposed to free dir, either. Instead, call closedir with it.
    Last edited by john.c; 11-17-2022 at 12:52 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Dec 2018
    Posts
    13
    Thank you for help, I've updated the code a bit, but it still has the problem with realpath:
    Compiler Explorer

  4. #4
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,115
    Quote Originally Posted by ansgar.snow View Post
    Thank you for help, I've updated the code a bit, but it still has the problem with realpath:
    Compiler Explorer
    Please post your code here in Code Blocks rather than a link to an unrelated site, as specified in the Forum rules.

    Thank you!

  5. #5
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    To your study:
    Code:
    // test.c
    
    // FIXME: For MSVC we need to use _findfirst/_findnext, instead of opendir/readdir/closedir.
    //        This code works on Cygwin, MSYS, Linux, but not on MSVC.
    
    #define _GNU_SOURCE   /* using glibc (asprintf) */
    // if you don't have asprintf on your libc, it is easy to make one with vsnprintf/snprintf.
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    
    #ifdef _MSC_VER
      #define realpath(P,RP) _fullpath((R),(RP),_MAX_PATH)
    #endif
    
    // opendir(), readdir() & closedir() not available on MSVC!
    #include <dirent.h>
    
    // Sizes for an arr with files and dirs:
    #define ASIZE 4096
    
    static void pout ( char **array )
    {
      while ( *array )
        printf ( "\t%s\n", *array++ );
    }
    
    static void freelist ( char **array )
    {
      while ( *array )
        free ( *array++ );
    }
    
    int filemapper ( char *directory )
    {
      static char *files[ASIZE];
      static char *dirs[ASIZE];
    
      // Dinamically allocated because we'll change it below.
      char *path = strdup ( directory );
    
      if ( ! path )
        return 1;
    
      DIR *dir = opendir ( path );
    
      if ( ! dir )
        return 1;
    
      unsigned int fidx = 0, didx = 0;
      struct dirent *entity;
    
      // NOTE: entity points to a statically allocated buffer (must not free!).
      entity = readdir ( dir );
    
      while ( entity )
      {
        switch ( entity->d_type )
        {
          case DT_DIR:
            // Discards "." and ".." references.
            if ( ! strcmp ( entity->d_name, "." ) || ! strcmp ( entity->d_name, ".." ) )
              break;
    
            if ( didx < ASIZE )
            {
              char *tmpp;
    
              if ( asprintf ( &tmpp, "%s/%s", path, entity->d_name ) >= 0 )
              {
                free ( path );
                path = strdup ( tmpp );
                dirs[didx++] = tmpp;
              }
            }
            else
              fputs ( "ERROR: Number of directory entries exausted.\n", stderr );
    
            break;
    
          // FIXED:
          case DT_REG:
          case DT_LNK:
            if ( fidx < ASIZE )
            {
              if ( asprintf ( &files[fidx], "%s/%s", path, entity->d_name ) >= 0 )
              {
                printf ( "[%s] FILE : %s\n",
                         entity->d_type == DT_REG ? "\033[1;32mregular\033[m" : "\033[1;33msymlink\033[m",
                         files[fidx] );
                fidx++;
              }
            }
            else
              fputs ( "ERROR: Number of file entries exausted.\n", stderr );
    
            break;
    
          // Ignores everything else.
          default:
            fprintf ( stderr, "Weird d_type (%hhu) at %s/%s\n",
                      entity->d_type, path, entity->d_name );
        }
    
        entity = readdir ( dir );
      }
    
      free ( path );
    
      closedir ( dir );
    
      printf ( "\nFILES:\n" );
      pout ( files );
      freelist ( files );
    
      printf ( "\nDIRS:\n" );
      pout ( dirs );
      freelist ( dirs );
    
      return 0;
    }
    
    int main ( int argc, char *argv[] )
    {
      struct stat st;
      char path[PATH_MAX];
    
      if ( argc != 2 )
      {
        fprintf( stderr, "Usage: %s <dir>\n", argv[0] );
        return EXIT_FAILURE;
      }
    
      if ( stat( argv[1], &st ) )
      {
        fprintf( stderr, "Cannot stat '%s'.\n", argv[1] );
        return EXIT_FAILURE;
      }
    
      if ( ! S_ISDIR( st.st_mode ) )
      {
        fprintf( stderr, "'%s' isn't a directory.\n", argv[1] );
        return EXIT_FAILURE;
      }
    
      // Gets realpath only once (realpath is a glibc function!).
      if ( ! realpath( argv[1], path ) )
      {
        fputs( "ERROR: Cannot get realpath.\n", stderr );
        return EXIT_FAILURE;
      }
    
      printf( "Scanning '%s'\n", path );
    
      if ( filemapper ( path ) )
      {
        fputs ( "ERRO!\n", stderr );
        return EXIT_FAILURE;
      }
    
      return EXIT_SUCCESS;
    }
    Getting absolute path of a file in c-untitled-png
    Last edited by flp1969; 11-18-2022 at 10:28 AM.

  6. #6
    Registered User
    Join Date
    Dec 2018
    Posts
    13
    Nicely done, thank you for help.
    For the edge cases, I think ASIZE should be 4096+1 or PATH_MAX+1, but I am not sure on this.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Generated absolute path via for in doesn't exist
    By awsdert in forum Linux Programming
    Replies: 3
    Last Post: 02-06-2019, 04:31 AM
  2. Absolute path C
    By midnight in forum C Programming
    Replies: 1
    Last Post: 11-13-2009, 08:11 AM
  3. How to judge whether a path is relative or absolute?
    By bbebfe in forum C Programming
    Replies: 2
    Last Post: 11-16-2008, 03:23 AM
  4. problem with fopen and absolute path
    By kobra_swe in forum C Programming
    Replies: 19
    Last Post: 04-17-2008, 01:31 AM
  5. how to obtain the absolute application path
    By jagerhans in forum Linux Programming
    Replies: 4
    Last Post: 12-23-2004, 05:48 PM

Tags for this Thread