Skip to content
Commits on Source (2)
- Fix config path charset issues in Win32
- Use BDPLUS_DEBUG_FILE environment variable for log file.
- Export API functions automatically when creating Windows dll.
- Improve Windows compatibility.
- Improve error resilience and stability.
......
......@@ -40,8 +40,8 @@ libbdplus_la_SOURCES=\
src/libbdplus/bdsvm/sha1.c \
src/file/dirs.h \
src/file/file.h \
src/file/file.c \
src/file/filesystem.h \
src/file/file_default.c \
src/file/file_default.h \
src/file/configfile.c \
src/file/configfile.h \
......@@ -67,6 +67,14 @@ libbdplus_la_SOURCES+= \
endif
endif
if HAVE_WIN32
libbdplus_la_SOURCES+= \
src/file/file_win32.c
else
libbdplus_la_SOURCES+= \
src/file/file_posix.c
endif
pkginclude_HEADERS = \
src/libbdplus/bdplus.h \
src/libbdplus/bdplus-version.h
......
......@@ -23,22 +23,17 @@
#include "configfile.h"
#include "file.h"
#include "dirs.h"
#include "util/logging.h"
#include "util/macro.h"
#include "util/strutl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _WIN32
# define mkdir(p,m) win32_mkdir(p)
#endif
#define BDPLUS_DIR "bdplus"
......@@ -46,41 +41,6 @@
#define MAX_FILE_SIZE 0xffffff
int file_mkpath(const char *path)
{
struct stat s;
int result = 1;
char *dir = str_dup(path);
char *end = dir;
if (!dir) {
return -1;
}
while (*end == '/')
end++;
while ((end = strchr(end, '/'))) {
*end = 0;
if (stat(dir, &s) != 0 || !S_ISDIR(s.st_mode)) {
BD_DEBUG(DBG_FILE, "Creating directory %s\n", dir);
if (mkdir(dir, S_IRWXU|S_IRWXG|S_IRWXO) == -1) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Error creating directory %s\n", dir);
result = 0;
break;
}
}
*end++ = '/';
}
free(dir);
return result;
}
char *file_get_cache_dir(void)
{
char *cache = file_get_cache_home();
......@@ -90,9 +50,9 @@ char *file_get_cache_dir(void)
return NULL;
}
dir = str_printf("%s/%s", cache, BDPLUS_DIR);
dir = str_printf("%s/%s/", cache, BDPLUS_DIR);
X_FREE(cache);
file_mkpath(dir);
file_mkdirs(dir);
return dir;
}
......@@ -100,16 +60,16 @@ char *file_get_cache_dir(void)
static char *_probe_config_dir(const char *base, const char *vm, const char *file)
{
char *dir = str_printf("%s/%s/%s/%s", base, BDPLUS_DIR, vm, file);
FILE *fp;
BDPLUS_FILE_H *fp;
if (!dir) {
return NULL;
}
fp = fopen(dir, "r");
fp = file_open_default()(NULL, dir);
if (fp) {
fclose(fp);
file_close(fp);
*(strrchr(dir, '/') + 1) = 0;
BD_DEBUG(DBG_BDPLUS, "Found VM config from %s\n", dir);
return dir;
......@@ -156,38 +116,36 @@ char *file_get_config_dir(const char *file)
return NULL;
}
static char *_load_fp(FILE *fp, uint32_t *p_size)
static char *_load_fp(BDPLUS_FILE_H *fp, uint32_t *p_size)
{
char *data = NULL;
long file_size, read_size;
int64_t size, read_size;
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
size = file_size(fp);
if (file_size < MIN_FILE_SIZE || file_size > MAX_FILE_SIZE) {
if (size < MIN_FILE_SIZE || size > MAX_FILE_SIZE) {
BD_DEBUG(DBG_FILE, "Invalid file size\n");
return NULL;
}
data = malloc(file_size + 1);
data = malloc(size + 1);
if (!data) {
BD_DEBUG(DBG_FILE, "Out of memory\n");
return NULL;
}
read_size = fread(data, 1, file_size, fp);
read_size = file_read(fp, (void *)data, size);
if (read_size != file_size) {
if (read_size != size) {
BD_DEBUG(DBG_FILE, "Error reading file\n");
free(data);
return NULL;
}
data[file_size] = 0;
data[size] = 0;
if (p_size) {
*p_size = file_size;
*p_size = size;
}
return data;
......@@ -196,13 +154,13 @@ static char *_load_fp(FILE *fp, uint32_t *p_size)
char *file_load(const char *path, uint32_t *p_size)
{
char *mem;
FILE *fp;
BDPLUS_FILE_H *fp;
if (!path) {
return NULL;
}
fp = fopen(path, "rb");
fp = file_open_default()(NULL, path);
if (!fp) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Error loading %s\n", path);
......@@ -211,7 +169,7 @@ char *file_load(const char *path, uint32_t *p_size)
mem = _load_fp(fp, p_size);
fclose(fp);
file_close(fp);
return mem;
}
......@@ -25,8 +25,6 @@
#include <stdint.h>
#include <stdio.h>
BD_PRIVATE int file_mkpath(const char *path);
BD_PRIVATE char * file_get_cache_dir(void) BD_ATTR_MALLOC;
BD_PRIVATE char * file_get_config_dir(const char *file) BD_ATTR_MALLOC;
......
/*
* This file is part of libaacs
* Copyright (C) 2015 VideoLAN
* This file is part of libbluray
* Copyright (C) 2014 Petri Hintukainen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -21,72 +21,73 @@
#include "config.h"
#endif
#include "file_default.h"
#include "file.h"
#include "util/logging.h"
#include "util/macro.h"
#include "util/strutl.h"
#include "util/logging.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h> // SEEK_*
#include <string.h> // strchr
#if defined(__MINGW32__)
/* fseeko64() prototypes from stdio.h */
# undef __STRICT_ANSI__
# define fseeko fseeko64
#endif
static void _file_close(BDPLUS_FILE_H *file)
int64_t file_size(BD_FILE_H *fp)
{
if (file) {
fclose((FILE *)file->internal);
X_FREE(file);
int64_t pos = file_tell(fp);
int64_t res1 = file_seek(fp, 0, SEEK_END);
int64_t length = file_tell(fp);
int64_t res2 = file_seek(fp, pos, SEEK_SET);
if (res1 < 0 || res2 < 0 || pos < 0 || length < 0) {
return -1;
}
}
static int64_t _file_seek(BDPLUS_FILE_H *file, int64_t offset, int32_t origin)
{
return fseeko((FILE *)file->internal, offset, origin);
return length;
}
static int64_t _file_read(BDPLUS_FILE_H *file, uint8_t *buf, int64_t size)
int file_mkdirs(const char *path)
{
return fread(buf, 1, size, (FILE *)file->internal);
}
int result = 0;
char *dir = str_dup(path);
char *end = dir;
char *p;
BDPLUS_FILE_H *file_open_default(void *handle, const char* file_name)
{
const char *device_root = handle;
char *file_path;
BDPLUS_FILE_H *file;
FILE *fp;
file_path = str_printf("%s"DIR_SEP"%s", device_root, file_name);
if (!file_path) {
BD_DEBUG(DBG_CRIT, "out of memory\n");
return NULL;
if (!dir) {
return -1;
}
fp = fopen(file_path, "rb");
X_FREE(file_path);
if (!fp) {
return NULL;
/* strip file name */
if (!(end = strrchr(end, DIR_SEP_CHAR))) {
X_FREE(dir);
return -1;
}
file = calloc(1, sizeof(BDPLUS_FILE_H));
if (!file) {
BD_DEBUG(DBG_CRIT, "out of memory\n");
fclose(fp);
return NULL;
*end = 0;
/* tokenize, stop to first existing dir */
while ((p = strrchr(dir, DIR_SEP_CHAR))) {
if (!file_path_exists(dir)) {
break;
}
*p = 0;
}
file->internal = fp;
file->close = _file_close;
file->seek = _file_seek;
file->read = _file_read;
/* create missing dirs */
p = dir;
while (p < end) {
/* concatenate next non-existing dir */
while (*p) p++;
if (p >= end) break;
*p = DIR_SEP_CHAR;
result = file_mkdir(dir);
if (result < 0) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Error creating directory %s\n", dir);
break;
}
BD_DEBUG(DBG_FILE, " created directory %s\n", dir);
}
return file;
X_FREE(dir);
return result;
}
......@@ -35,25 +35,45 @@
# define DIR_SEP_CHAR '/'
#endif
typedef BDPLUS_FILE_H BD_FILE_H;
typedef BDPLUS_FILE_OPEN BD_FILE_OPEN;
/*
* file access
*/
static inline void file_close(BDPLUS_FILE_H *fp)
static inline void file_close(BD_FILE_H *fp)
{
fp->close(fp);
}
static inline BD_USED int64_t file_seek(BDPLUS_FILE_H *fp, int64_t offset, int32_t origin)
static inline int64_t file_tell(BD_FILE_H *fp)
{
return fp->tell(fp);
}
static inline BD_USED int64_t file_seek(BD_FILE_H *fp, int64_t offset, int32_t origin)
{
return fp->seek(fp, offset, origin);
}
static inline BD_USED size_t file_read(BDPLUS_FILE_H *fp, uint8_t *buf, size_t size)
static inline BD_USED size_t file_read(BD_FILE_H *fp, uint8_t *buf, size_t size)
{
return (size_t)fp->read(fp, buf, (int64_t)size);
}
#define file_open(cfg, fname) (cfg->fopen(cfg->fopen_handle, fname))
BD_PRIVATE int64_t file_size(BD_FILE_H *fp);
BD_PRIVATE BDPLUS_FILE_OPEN file_open_default(void);
/*
* local filesystem
*/
BD_PRIVATE int file_path_exists(const char *path);
BD_PRIVATE int file_mkdir(const char *dir);
BD_PRIVATE int file_mkdirs(const char *path);
#endif /* FILE_H_ */
/*
* This file is part of libbdplus
* Copyright (C) 2015 VideoLAN
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef FILE_DEFAULT_H_
#define FILE_DEFAULT_H_
#include "util/attributes.h"
struct bdplus_file;
BD_PRIVATE struct bdplus_file *file_open_default(void *root_path, const char *file_name);
#endif /* FILE_DEFAULT_H_ */
/*
* This file is part of libbluray
* Copyright (C) 2009-2010 Obliter0n
* Copyright (C) 2009-2010 John Stebbins
* Copyright (C) 2010-2015 Petri Hintukainen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "file.h"
#include "util/macro.h"
#include "util/logging.h"
#include <errno.h>
#include <inttypes.h>
#include <stdio.h> // remove()
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef __ANDROID__
# undef lseek
# define lseek lseek64
# undef off_t
# define off_t off64_t
#endif
static void _file_close(BD_FILE_H *file)
{
if (file) {
if (close((int)(intptr_t)file->internal)) {
BD_DEBUG(DBG_CRIT | DBG_FILE, "Error closing POSIX file (%p)\n", (void*)file);
}
BD_DEBUG(DBG_FILE, "Closed POSIX file (%p)\n", (void*)file);
X_FREE(file);
}
}
static int64_t _file_seek(BD_FILE_H *file, int64_t offset, int32_t origin)
{
off_t result = lseek((int)(intptr_t)file->internal, offset, origin);
if (result == (off_t)-1) {
BD_DEBUG(DBG_FILE, "lseek() failed (%p)\n", (void*)file);
return -1;
}
return (int64_t)result;
}
static int64_t _file_tell(BD_FILE_H *file)
{
return _file_seek(file, 0, SEEK_CUR);
}
static int64_t _file_read(BD_FILE_H *file, uint8_t *buf, int64_t size)
{
ssize_t got, result;
if (size <= 0 || size >= BD_MAX_SSIZE) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Ignoring invalid read of size %"PRId64" (%p)\n", size, (void*)file);
return 0;
}
for (got = 0; got < (ssize_t)size; got += result) {
result = read((int)(intptr_t)file->internal, buf + got, size - got);
if (result < 0) {
if (errno != EINTR) {
BD_DEBUG(DBG_FILE, "read() failed (%p)\n", (void*)file);
break;
}
result = 0;
} else if (result == 0) {
// hit EOF.
break;
}
}
return (int64_t)got;
}
static BD_FILE_H *_file_open(void *handle, const char* filename)
{
BD_FILE_H *file;
int fd = -1;
int flags = 0;
int mode = 0;
(void)handle;
flags = O_RDONLY;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
#ifdef O_BINARY
flags |= O_BINARY;
#endif
if ((fd = open(filename, flags, mode)) < 0) {
BD_DEBUG(DBG_FILE, "Error opening file %s\n", filename);
return NULL;
}
file = calloc(1, sizeof(BD_FILE_H));
if (!file) {
close(fd);
BD_DEBUG(DBG_FILE, "Error opening file %s (out of memory)\n", filename);
return NULL;
}
file->close = _file_close;
file->seek = _file_seek;
file->read = _file_read;
file->tell = _file_tell;
file->internal = (void*)(intptr_t)fd;
BD_DEBUG(DBG_FILE, "Opened POSIX file %s (%p)\n", filename, (void*)file);
return file;
}
BD_FILE_H* (*file_open)(void *handle, const char* filename) = _file_open;
BD_FILE_OPEN file_open_default(void)
{
return _file_open;
}
int file_path_exists(const char *path)
{
struct stat s;
return stat(path, &s);
}
int file_mkdir(const char *dir)
{
return mkdir(dir, S_IRWXU);
}
/*
* This file is part of libbluray
* Copyright (C) 2009-2010 Obliter0n
* Copyright (C) 2009-2010 John Stebbins
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(__MINGW32__)
/* ftello64() and fseeko64() prototypes from stdio.h */
# undef __STRICT_ANSI__
#endif
#include "file.h"
#include "util/macro.h"
#include "util/logging.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <windows.h>
static void _file_close(BD_FILE_H *file)
{
if (file) {
if (fclose((FILE *)file->internal)) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Error closing WIN32 file (%p)\n", (void*)file);
}
BD_DEBUG(DBG_FILE, "Closed WIN32 file (%p)\n", (void*)file);
X_FREE(file);
}
}
static int64_t _file_seek(BD_FILE_H *file, int64_t offset, int32_t origin)
{
#if defined(__MINGW32__)
return fseeko64((FILE *)file->internal, offset, origin);
#else
return _fseeki64((FILE *)file->internal, offset, origin);
#endif
}
static int64_t _file_tell(BD_FILE_H *file)
{
#if defined(__MINGW32__)
return ftello64((FILE *)file->internal);
#else
return _ftelli64((FILE *)file->internal);
#endif
}
static int64_t _file_read(BD_FILE_H *file, uint8_t *buf, int64_t size)
{
if (size > 0 && size < BD_MAX_SSIZE) {
return (int64_t)fread(buf, 1, (size_t)size, (FILE *)file->internal);
}
BD_DEBUG(DBG_FILE | DBG_CRIT, "Ignoring invalid read of size %"PRId64" (%p)\n", size, (void*)file);
return 0;
}
static BD_FILE_H *_file_open(void *handle, const char* filename)
{
BD_FILE_H *file;
FILE *fp;
wchar_t wfilename[MAX_PATH], wmode[8];
const char *mode = "rb";
(void)handle;
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, wfilename, MAX_PATH) ||
!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, 8)) {
BD_DEBUG(DBG_FILE, "Error opening file %s\n", filename);
return NULL;
}
fp = _wfopen(wfilename, wmode);
if (!fp) {
BD_DEBUG(DBG_FILE, "Error opening file %s\n", filename);
return NULL;
}
file = calloc(1, sizeof(BD_FILE_H));
if (!file) {
BD_DEBUG(DBG_FILE | DBG_CRIT, "Error opening file %s (out of memory)\n", filename);
fclose(fp);
return NULL;
}
file->internal = fp;
file->close = _file_close;
file->seek = _file_seek;
file->read = _file_read;
file->tell = _file_tell;
BD_DEBUG(DBG_FILE, "Opened WIN32 file %s (%p)\n", filename, (void*)file);
return file;
}
BD_FILE_H* (*file_open)(void *handle, const char* filename) = _file_open;
BD_FILE_OPEN file_open_default(void)
{
return _file_open;
}
int file_path_exists(const char *path)
{
wchar_t wpath[MAX_PATH];
if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH)) {
return -1;
}
DWORD dwAttrib = GetFileAttributesW(wpath);
if (dwAttrib != INVALID_FILE_ATTRIBUTES) {
return 0;
}
return -1;
}
int file_mkdir(const char *dir)
{
wchar_t wdir[MAX_PATH];
if (!MultiByteToWideChar(CP_UTF8, 0, dir, -1, wdir, MAX_PATH)) {
return -1;
}
if (!CreateDirectoryW(wdir, NULL))
return -1;
return 0;
}
......@@ -36,7 +36,7 @@
#include "util/mutex.h"
#include "util/strutl.h"
#include "file/configfile.h"
#include "file/file_default.h"
#include "file/file.h"
#include <string.h>
#include <stdlib.h>
......@@ -114,7 +114,7 @@ static void _save_slots(bdplus_t *plus)
{
char *file_name = _slots_file();
if (file_name) {
file_mkpath(file_name);
file_mkdirs(file_name);
bdplus_save_slots(plus, file_name);
X_FREE(file_name);
}
......@@ -164,7 +164,7 @@ bdplus_t *bdplus_init(const char *path, const char *config_path, const uint8_t *
return NULL;
}
plus->config->fopen_handle = plus->device_path;
plus->config->fopen = file_open_default;
plus->config->fopen = file_open_default();
}
plus->mutex = calloc(1, sizeof(BD_MUTEX));
......
......@@ -1129,6 +1129,8 @@ uint32_t TRAP_Discovery(bdplus_config_t *config, uint32_t dev, uint32_t qID, uin
break;
} // qID
break;
default:
BD_DEBUG(DBG_CRIT, "[TRAP] unknown DeviceDiscovery for unknown dev %d: %d\n", dev, qID);
break;
......
......@@ -74,7 +74,7 @@ char *bdplus_disc_cache_file(bdplus_t *plus, const char *file)
str_print_hex(vid_str, plus->volumeID, 16);
result = str_printf("%s/%s/%s", base ? base : "/tmp/", vid_str, file);
X_FREE(base);
file_mkpath(result);
file_mkdirs(result);
return result;
}
......