?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. /* platform.c - platform-specific library.
  2.  
  3.    This is free and unencumbered software released into the public domain.
  4.    For more information, please refer to <http://unlicense.org>. */
  5.  
  6. #include "defs.h"
  7.  
  8. #include <stdbool.h>
  9. #include <limits.h>
  10. #include <sys/stat.h>
  11. #include <unistd.h>
  12. #include <libgen.h>
  13. #include <ctype.h>
  14. #include <errno.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include "platform.h"
  18.  
  19. #include "debug.h"
  20.  
  21. bool check_path_abs (const char *path)
  22. {
  23. #if !defined (_WIN32) && !defined(_WIN64)
  24.     return (path && (path[0] == '/' || path[0] == '\\'));
  25. #else
  26.     return (path && (isalpha (path[0])) && path[1] == ':' && (path[2] == '/' || path[2] == '\\'));
  27. #endif
  28. }
  29.  
  30. #if defined (_WIN32) || defined(_WIN64)
  31. # define ROOT_START 2    // skip disk name "A:"
  32. #else
  33. # define ROOT_START 0
  34. #endif
  35.  
  36. char *resolve_full_path (const char *path)
  37. {
  38.     char *s;
  39.     unsigned len, i, j;
  40.     bool last_sep, f;
  41.  
  42.     if (!path || path[0] == '\0')
  43.     {
  44.         errno = path ? ENOENT : EINVAL;
  45.         return (char *) NULL;
  46.     }
  47.     if (!check_path_abs (path))
  48.     {
  49.         errno = EINVAL;
  50.         return (char *) NULL;
  51.     }
  52.  
  53.     len = strlen (path);
  54.     s = malloc (len+3); // + terminating zero + 2 chars (=3)
  55.     if (!s)
  56.         return (char *) NULL;
  57.     strcpy (s, path);   // fine (sizeof (s) > sizeof (path))
  58.  
  59.     // Replace '\\' or '/' with PATHSEP. From here all '/' in comments must be treated as PATHSEP.
  60.     for (i = ROOT_START; s[i] != '\0'; i++)
  61. #if defined (_WIN32) || defined(_WIN64)
  62.         if (s[i] == '/')
  63. #else
  64.         if (s[i] == '\\')
  65. #endif
  66.             s[i] = PATHSEP;
  67.  
  68.     last_sep = s[len-1] == PATHSEP;     // remember if last char is PATHSEP to keep it
  69.  
  70.     // Replace multiple '/' with single '/'
  71.     i = ROOT_START;
  72.     j = ROOT_START;
  73.     while (s[j] != '\0')
  74.     {
  75.         if (s[j] == PATHSEP)
  76.             while (s[j+1] == PATHSEP)
  77.                 j++;    // skip one char
  78.         s[i] = s[j];
  79.         i++;
  80.         j++;
  81.     }
  82.     s[i] = '\0';
  83.     len = i;
  84.  
  85.     // Replace '/.' with '/./', and '/..' with '/../' at end
  86.     if (len >= (ROOT_START+2) && s[len-1] == '.')
  87.     {
  88.         if ((len >= (ROOT_START+3) && s[len-3] == PATHSEP && s[len-2] == '.')
  89.         ||  (s[len-2] == PATHSEP))
  90.         {
  91.             s[len] = PATHSEP;
  92.             len++;
  93.             s[len] = '\0';
  94.         }
  95.     }
  96.  
  97.     // Replace "/./" with '/'
  98.     i = ROOT_START;
  99.     j = ROOT_START;
  100.     while (s[j] != '\0')
  101.     {
  102.         if (s[j] == PATHSEP && s[j+1] == '.' && s[j+2] == PATHSEP)
  103.             j += 2;     // skip two chars
  104.         s[i] = s[j];
  105.         i++;
  106.         j++;
  107.     }
  108.     s[i] = '\0';
  109.     len = i;
  110.  
  111.     // Remove all "/../"
  112.     do
  113.     {
  114.         f = false;
  115.         i = ROOT_START;
  116.         while (s[i] != '\0'
  117.         &&     (!(s[i] == PATHSEP && s[i+1] == '.' && s[i+2] == '.' && s[i+3] == PATHSEP)))
  118.             i++;
  119.         if (s[i] != '\0')
  120.         {
  121.             // check bad path at start: "/../", "A:/../"
  122.             if (i == ROOT_START)
  123.             {
  124.                 free (s);
  125.                 errno = EINVAL;
  126.                 return (char *) NULL;
  127.             }
  128.             j = i - 1;
  129.             while (j > ROOT_START && s[j] != PATHSEP)
  130.                 j--;
  131.             // remove part of string [j, i+2]
  132.             i += 3;
  133.             while (s[i] != '\0')
  134.             {
  135.                 s[j] = s[i];
  136.                 i++;
  137.                 j++;
  138.             }
  139.             s[j] = '\0';
  140.             f = true;
  141.         }
  142.     } while (f);
  143.  
  144.     // Restore '/' at end if it was and remove it if there wasn't
  145.     len = strlen (s);
  146.     if (last_sep && len > ROOT_START && s[len-1] != PATHSEP)
  147.     {
  148.         s[len] = PATHSEP;
  149.         len++;
  150.         s[len] = '\0';
  151.     }
  152.     else if (!last_sep && len > ROOT_START && len != ROOT_START+1 && s[len-1] == PATHSEP)
  153.     {
  154.         len--;
  155.         s[len] = '\0';
  156.     }
  157.  
  158.     return realloc (s, len+1);  // + terminating zero (strlen (s) <= strlen (path))
  159. }
  160.  
  161. bool check_path_exists (const char *path)
  162. {
  163.     char *s;
  164.     struct stat st;
  165.     bool ok;
  166.  
  167.     s = resolve_full_path (path);
  168.     if (!s)
  169.         return false;
  170.  
  171.     ok = stat (s, &st) >= 0;
  172.  
  173.     free (s);
  174.  
  175.     if (!ok)
  176.         return false;
  177.  
  178.     return (S_ISDIR (st.st_mode)) != 0;
  179. }
  180.  
  181. bool check_file_exists (const char *path)
  182. {
  183.     char *s;
  184.     struct stat st;
  185.     bool ok;
  186.  
  187.     s = resolve_full_path (path);
  188.     if (!s)
  189.         return false;
  190.  
  191.     ok = stat (s, &st) >= 0;
  192.  
  193.     free (s);
  194.  
  195.     if (!ok)
  196.         return false;
  197.  
  198.     return (S_ISREG (st.st_mode)) || ((st.st_mode & S_IFMT) == 0);
  199. }
  200.  
  201. char *get_current_dir (void)
  202. {
  203.     return getcwd (NULL, 0);
  204. }
  205.  
  206. char *get_dir_name (const char *path)
  207. {
  208.     char *pathc, *d, *result;
  209.  
  210.     pathc = strdup (path);
  211.     if (!pathc)
  212.         return (char *) NULL;
  213.     d = dirname (pathc);
  214.     result = strdup (d);
  215.     free (pathc);
  216.     return result;
  217. }