aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
aheinecke@404:  * Software engineering by Intevation GmbH
aheinecke@404:  *
aheinecke@404:  * This file is Free Software under the GNU GPL (v>=2)
aheinecke@404:  * and comes with ABSOLUTELY NO WARRANTY!
aheinecke@404:  * See LICENSE.txt for details.
aheinecke@404:  */
wilde@146: #include "portpath.h"
andre@984: #include "strhelp.h"
andre@984: #include "util.h"
andre@1070: #include "logging.h"
wilde@146: 
wilde@146: #include <libgen.h>
wilde@146: #include <limits.h>
wilde@146: #include <stdio.h>
wilde@146: #include <stdlib.h>
wilde@168: #include <sys/stat.h>
wilde@168: #include <sys/types.h>
wilde@168: #include <unistd.h>
andre@986: #include <string.h>
wilde@146: 
andre@1157: #ifdef WIN32
andre@1157: #include <share.h>
andre@1157: #endif
andre@1157: 
wilde@146: char *
wilde@146: port_dirname(char *path)
wilde@146: {
wilde@146: #ifndef _WIN32
wilde@146:   return dirname(path);
wilde@146: #else
wilde@164:   char drive[_MAX_DRIVE];
wilde@164:   char dir[_MAX_DIR];
wilde@164:   _splitpath(path, drive, dir, NULL, NULL);
wilde@170:   size_t dlen = strlen(dir);
wilde@170:   if ((dlen > 0) &&
wilde@170:       ((dir[dlen-1] == '/') || (dir[dlen-1] == '\\')))
wilde@170:     dir[dlen-1] = '\0';
wilde@164:   /* We assume: drive + dir is shorter than
wilde@164:    * drive + dir + fname + ext */
wilde@164:   sprintf(path, "%s%s", drive, dir);
wilde@164:   return path;
wilde@146: #endif
wilde@146: }
wilde@146: 
andre@975: bool
andre@1070: port_mkdir(const char *path, bool propagate_acl)
andre@975: {
andre@975: #ifndef _WIN32
andre@1070:   if (propagate_acl)
andre@1070:     {
andre@1070:       DEBUGPRINTF("WARNING: ACL propagation only has an effect on Windows.\n");
andre@1070:     }
andre@975:   return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
andre@975: #else
andre@984:   wchar_t *wchar_path = utf8_to_wchar(path, strlen(path));
andre@984:   bool ret;
andre@984: 
andre@984:   if (!wchar_path)
andre@984:     {
andre@984:       return false;
andre@984:     }
andre@1208:   ret = create_restricted_directory (wchar_path, propagate_acl, NULL);
andre@984:   xfree (wchar_path);
andre@984:   return ret;
andre@975: #endif
andre@975: }
andre@975: 
wilde@146: char *
andre@975: port_realpath(const char *path)
wilde@146: {
wilde@146: #ifndef _WIN32
wilde@146:   return realpath(path, NULL);
wilde@146: #else
wilde@169:   char *fp = _fullpath(NULL, path, 0);
wilde@169:   if (port_fileexits(fp))
wilde@169:     return fp;
wilde@169:   else
wilde@169:     return NULL;
wilde@146: #endif
wilde@146: }
wilde@168: 
wilde@168: bool
wilde@168: port_fileexits(char *path)
wilde@168: {
wilde@168:   int ret;
wilde@168: #ifndef _WIN32
wilde@168:   struct stat sb;
wilde@168:   ret = stat(path, &sb);
wilde@168: #else
wilde@168:   struct _stat sb;
wilde@168:   ret = _stat(path, &sb);
wilde@168: #endif
wilde@168: 
wilde@168:   if (ret == 0)
wilde@168:     return true;
wilde@168:   else
wilde@168:     return false;
wilde@168: }
wilde@176: 
wilde@176: bool
andre@1070: port_mkdir_p(const char *path, bool propagate_acl)
andre@984: {
andre@984:   char *parent_path,
andre@984:        *p;
andre@984:   if (!path) {
andre@984:       return false;
andre@984:   }
andre@984:   if (port_isdir(path)) {
andre@984:       return true;
andre@984:   }
andre@984:   parent_path = xstrndup (path, strlen(path));
andre@984:   p = strrchr(parent_path, '/');
andre@984:   if (!p)
andre@984:     {
andre@984:       p = strrchr(parent_path, '\\');
andre@984:     }
andre@984:   if (!p)
andre@984:     {
andre@984:       return false;
andre@984:     }
andre@984:   *p = '\0';
andre@984:   if (!port_isdir(parent_path))
andre@984:     {
andre@1070:       port_mkdir_p(parent_path, false);
andre@984:     }
andre@1070:   return port_mkdir(path, propagate_acl);
andre@984: }
andre@984: 
andre@984: bool
andre@984: port_isdir(const char *path)
wilde@176: {
wilde@176:   int ret;
wilde@176: #ifndef _WIN32
wilde@176:   struct stat sb;
wilde@176:   ret = stat(path, &sb);
wilde@176: #else
wilde@176:   struct _stat sb;
wilde@176:   ret = _stat(path, &sb);
wilde@176: #endif
wilde@176: 
wilde@176:   if ((ret == 0) && S_ISDIR(sb.st_mode))
wilde@176:     return true;
wilde@176:   else
wilde@176:     return false;
wilde@176: }
andre@1157: 
andre@1157: FILE*
andre@1157: port_fopen_rb(const char *path, bool exclusive)
andre@1157: {
andre@1157:   FILE *f = NULL;
andre@1157:   if (!path)
andre@1157:     {
andre@1157:       return NULL;
andre@1157:     }
andre@1157: #ifdef WIN32
andre@1157:     {
andre@1157:       wchar_t *wFilename = utf8_to_wchar(path, strlen(path));
andre@1157:       if (!wFilename)
andre@1157:         {
andre@1157:           ERRORPRINTF ("Invalid encoding\n");
andre@1157:           return NULL;
andre@1157:         }
andre@1157:       /* We open and write protect the file here so that
andre@1157:          as long as the file is open we can be sure that
andre@1157:          it was not modified and can use it in subsequent
andre@1157:          calls based on the filename. */
andre@1157:       if (exclusive)
andre@1157:         {
andre@1157:           f = _wfsopen(wFilename, L"rb", _SH_DENYWR);
andre@1157:         }
andre@1157:       else
andre@1157:         {
andre@1157:           f = _wfopen(wFilename, L"rb");
andre@1157:         }
andre@1157:       xfree(wFilename);
andre@1157:       if (f == NULL)
andre@1157:         {
andre@1157:           /* Fall back to local8 bit encoding */
andre@1157:           if (exclusive)
andre@1157:             {
andre@1157:               f = _fsopen(path, "rb", _SH_DENYWR);
andre@1157:             }
andre@1157:           else
andre@1157:             {
andre@1157:               f = fopen(path, "rb");
andre@1157:             }
andre@1157:         }
andre@1157:     }
andre@1157: #else
andre@1157:   (void)(exclusive);
andre@1157:   f = fopen(path, "rb");
andre@1157: #endif
andre@1157:   return f;
andre@1157: }