1 /*
2  * This file is part of libbdplus
3  * Copyright (C) 2013  VideoLAN
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see
17  * <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #include "configfile.h"
25 
26 #include "dirs.h"
27 #include "util/logging.h"
28 #include "util/macro.h"
29 #include "util/strutl.h"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 
37 #ifdef _WIN32
38 # define mkdir(p,m) win32_mkdir(p)
39 #endif
40 
41 
42 #define BDPLUS_DIR "bdplus"
43 
44 
45 #define MIN_FILE_SIZE 1
46 #define MAX_FILE_SIZE 0xffffff
47 
48 
file_mkpath(const char * path)49 int file_mkpath(const char *path)
50 {
51     struct stat s;
52     int result = 1;
53     char *dir = str_printf("%s", path);
54     char *end = dir;
55 
56     while (*end == '/')
57         end++;
58 
59     while ((end = strchr(end, '/'))) {
60         *end = 0;
61 
62         if (stat(dir, &s) != 0 || !S_ISDIR(s.st_mode)) {
63             BD_DEBUG(DBG_FILE, "Creating directory %s\n", dir);
64 
65             if (mkdir(dir, S_IRWXU|S_IRWXG|S_IRWXO) == -1) {
66                 BD_DEBUG(DBG_FILE | DBG_CRIT, "Error creating directory %s\n", dir);
67                 result = 0;
68                 break;
69             }
70         }
71 
72         *end++ = '/';
73     }
74 
75     free(dir);
76 
77     return result;
78 }
79 
file_get_cache_dir(void)80 char *file_get_cache_dir(void)
81 {
82     char *cache = file_get_cache_home();
83     char *dir;
84 
85     dir = str_printf("%s/%s", cache ? cache : "/tmp/", BDPLUS_DIR);
86     X_FREE(cache);
87     file_mkpath(dir);
88 
89     return dir;
90 }
91 
_probe_config_dir(const char * base,const char * vm,const char * file)92 static char *_probe_config_dir(const char *base, const char *vm, const char *file)
93 {
94     char *dir = str_printf("%s/%s/%s/%s", base, BDPLUS_DIR, vm, file);
95     FILE *fp  = fopen(dir, "r");
96 
97     if (fp) {
98         fclose(fp);
99         *(strrchr(dir, '/') + 1) = 0;
100         BD_DEBUG(DBG_BDPLUS, "Found VM config from %s\n", dir);
101         return dir;
102     }
103 
104     BD_DEBUG(DBG_BDPLUS, "VM config not found from  %s\n", dir);
105     free(dir);
106     return NULL;
107 }
108 
file_get_config_dir(const char * file)109 char *file_get_config_dir(const char *file)
110 {
111     char *dir = NULL;
112     const char *vm;
113     char *config_home;
114     const char *base;
115 
116     vm = getenv("BDPLUS_VM_ID");
117     if (!vm) {
118         vm = "vm0";
119     }
120 
121     /* try home directory */
122     config_home = file_get_config_home();
123     dir = _probe_config_dir(config_home, vm, file);
124     X_FREE(config_home);
125     if (dir) {
126         return dir;
127     }
128 
129     /* try system config dirs */
130     base = file_get_config_system(NULL);
131     while (base) {
132         dir = _probe_config_dir(base, vm, file);
133         if (dir) {
134             return dir;
135         }
136         base = file_get_config_system(base);
137     }
138 
139     return NULL;
140 }
141 
_load_fp(FILE * fp,uint32_t * p_size)142 static char *_load_fp(FILE *fp, uint32_t *p_size)
143 {
144     char *data = NULL;
145     long file_size, read_size;
146 
147     fseek(fp, 0, SEEK_END);
148     file_size = ftell(fp);
149     fseek(fp, 0, SEEK_SET);
150 
151     if (file_size < MIN_FILE_SIZE || file_size > MAX_FILE_SIZE) {
152         BD_DEBUG(DBG_FILE, "Invalid file size\n");
153         return NULL;
154     }
155 
156     data      = malloc(file_size + 1);
157     read_size = fread(data, 1, file_size, fp);
158 
159     if (read_size != file_size) {
160         BD_DEBUG(DBG_FILE, "Error reading file\n");
161         free(data);
162         return NULL;
163     }
164 
165     data[file_size] = 0;
166 
167     if (p_size) {
168         *p_size = file_size;
169     }
170 
171     return data;
172 }
173 
file_load(const char * path,uint32_t * p_size)174 char *file_load(const char *path, uint32_t *p_size)
175 {
176     char *mem;
177     FILE *fp;
178 
179     fp = fopen(path, "rb");
180 
181     if (!fp) {
182         BD_DEBUG(DBG_FILE | DBG_CRIT, "Error loading %s\n", path);
183         return NULL;
184     }
185 
186     mem = _load_fp(fp, p_size);
187 
188     fclose(fp);
189 
190     return mem;
191 }
192