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