mirror of https://github.com/ARMmbed/mbed-os.git
Tighten mbed_retarget.cpp error handling
* Don't set errno when calls are successful (will slightly alleviate the problem of errno not being thread-safe yet). * Transfer errors returned from size() and seek() into errno. * Fix isatty() - could never return 1 from a FileHandle. * Use more appropriate errors than EBADF in some places (eg ENOENT for non-existant path).pull/4119/head
parent
533910cb87
commit
fb7cbdf356
|
@ -30,6 +30,7 @@
|
|||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#if DEVICE_STDIO_MESSAGES
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -120,6 +121,17 @@ static void init_serial() {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets errno when file opening fails.
|
||||
* Wipes out the filehandle too.
|
||||
*/
|
||||
static int handle_open_errors(int error, unsigned filehandle_idx) {
|
||||
errno = -error;
|
||||
// Free file handle
|
||||
filehandles[filehandle_idx] = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if MBED_CONF_FILESYSTEM_PRESENT
|
||||
static inline int openmode_to_posix(int openmode) {
|
||||
int posix = openmode;
|
||||
|
@ -189,7 +201,7 @@ public:
|
|||
* @return
|
||||
* On success, a valid FILEHANDLE is returned.
|
||||
* On failure, -1 is returned and errno is set to an appropriate value e.g.
|
||||
* EBADF a bad file descriptor was found (default errno setting)
|
||||
* ENOENT file not found (default errno setting)
|
||||
* EMFILE the maximum number of open files was exceeded.
|
||||
*
|
||||
* */
|
||||
|
@ -219,9 +231,6 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/* if something goes wrong and errno is not explicly set, errno will be set to EBADF */
|
||||
errno = EBADF;
|
||||
|
||||
// find the first empty slot in filehandles
|
||||
filehandle_mutex->lock();
|
||||
unsigned int fh_i;
|
||||
|
@ -253,41 +262,30 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
|
|||
if (!path.exists()) {
|
||||
/* The first part of the filename (between first 2 '/') is not a
|
||||
* registered mount point in the namespace.
|
||||
* Free file handle.
|
||||
*/
|
||||
filehandles[fh_i] = NULL;
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
} else if (path.isFile()) {
|
||||
return handle_open_errors(-ENOENT, fh_i);
|
||||
}
|
||||
|
||||
if (path.isFile()) {
|
||||
res = path.file();
|
||||
#if MBED_CONF_FILESYSTEM_PRESENT
|
||||
} else {
|
||||
FileSystem *fs = path.fileSystem();
|
||||
if (fs == NULL) {
|
||||
/* The filesystem instance managing the namespace under the mount point
|
||||
* has not been found. Free file handle */
|
||||
errno = ENOENT;
|
||||
filehandles[fh_i] = NULL;
|
||||
return -1;
|
||||
return handle_open_errors(-ENOENT, fh_i);
|
||||
}
|
||||
int posix_mode = openmode_to_posix(openmode);
|
||||
File *file = new ManagedFile;
|
||||
int err = file->open(fs, path.fileName(), posix_mode);
|
||||
if (err < 0) {
|
||||
errno = -err;
|
||||
delete file;
|
||||
} else {
|
||||
res = file;
|
||||
return handle_open_errors(err, fh_i);
|
||||
}
|
||||
res = file;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (res == NULL) {
|
||||
// Free file handle
|
||||
filehandles[fh_i] = NULL;
|
||||
return -1;
|
||||
}
|
||||
filehandles[fh_i] = res;
|
||||
|
||||
return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
|
||||
|
@ -296,10 +294,12 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
|
|||
extern "C" int PREFIX(_close)(FILEHANDLE fh) {
|
||||
if (fh < 3) return 0;
|
||||
|
||||
errno = EBADF;
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
filehandles[fh-3] = NULL;
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = fhc->close();
|
||||
if (err < 0) {
|
||||
|
@ -317,7 +317,6 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
|
|||
#endif
|
||||
int n; // n is the number of bytes written
|
||||
|
||||
errno = EBADF;
|
||||
if (fh < 3) {
|
||||
#if DEVICE_SERIAL
|
||||
if (!stdio_uart_inited) init_serial();
|
||||
|
@ -338,7 +337,10 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
|
|||
n = length;
|
||||
} else {
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = fhc->write(buffer, length);
|
||||
if (n < 0) {
|
||||
|
@ -359,7 +361,6 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
|
|||
#endif
|
||||
int n; // n is the number of bytes read
|
||||
|
||||
errno = EBADF;
|
||||
if (fh < 3) {
|
||||
// only read a character at a time from stdin
|
||||
#if DEVICE_SERIAL
|
||||
|
@ -390,7 +391,10 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
|
|||
n = 1;
|
||||
} else {
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = fhc->read(buffer, length);
|
||||
if (n < 0) {
|
||||
|
@ -410,51 +414,69 @@ extern "C" int PREFIX(_istty)(FILEHANDLE fh)
|
|||
extern "C" int _isatty(FILEHANDLE fh)
|
||||
#endif
|
||||
{
|
||||
errno = EBADF;
|
||||
/* stdin, stdout and stderr should be tty */
|
||||
if (fh < 3) return 1;
|
||||
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
|
||||
int err = fhc->isatty();
|
||||
if (err < 0) {
|
||||
errno = -err;
|
||||
return -1;
|
||||
} else {
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty = fhc->isatty();
|
||||
if (tty < 0) {
|
||||
errno = -tty;
|
||||
return 0;
|
||||
} else {
|
||||
return tty;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
#if defined(__ARMCC_VERSION)
|
||||
int _sys_seek(FILEHANDLE fh, long position)
|
||||
int _sys_seek(FILEHANDLE fh, long offset)
|
||||
#elif defined(__ICCARM__)
|
||||
long __lseek(int fh, long offset, int whence)
|
||||
#else
|
||||
int _lseek(FILEHANDLE fh, int offset, int whence)
|
||||
#endif
|
||||
{
|
||||
errno = EBADF;
|
||||
if (fh < 3) return 0;
|
||||
#if defined(__ARMCC_VERSION)
|
||||
int whence = SEEK_SET;
|
||||
#endif
|
||||
if (fh < 3) {
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__ARMCC_VERSION)
|
||||
return fhc->seek(position, SEEK_SET);
|
||||
#else
|
||||
return fhc->seek(offset, whence);
|
||||
#endif
|
||||
off_t off = fhc->seek(offset, whence);
|
||||
if (off < 0) {
|
||||
errno = -off;
|
||||
return -1;
|
||||
}
|
||||
// Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference
|
||||
if (off > INT_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
#ifdef __ARMCC_VERSION
|
||||
extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
|
||||
errno = EBADF;
|
||||
if (fh < 3) return 0;
|
||||
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = fhc->sync();
|
||||
if (err < 0) {
|
||||
|
@ -466,13 +488,27 @@ extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
|
|||
}
|
||||
|
||||
extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
|
||||
errno = EBADF;
|
||||
if (fh < 3) return 0;
|
||||
if (fh < 3) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FileHandle* fhc = filehandles[fh-3];
|
||||
if (fhc == NULL) return -1;
|
||||
if (fhc == NULL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fhc->size();
|
||||
off_t size = fhc->size();
|
||||
if (size < 0) {
|
||||
errno = -size;
|
||||
return -1;
|
||||
}
|
||||
if (size > LONG_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -491,10 +527,12 @@ extern "C" int _fstat(int fd, struct stat *st) {
|
|||
namespace std {
|
||||
extern "C" int remove(const char *path) {
|
||||
#if MBED_CONF_FILESYSTEM_PRESENT
|
||||
errno = EBADF;
|
||||
FilePath fp(path);
|
||||
FileSystem *fs = fp.fileSystem();
|
||||
if (fs == NULL) return -1;
|
||||
if (fs == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = fs->remove(fp.fileName());
|
||||
if (err < 0) {
|
||||
|
@ -511,14 +549,21 @@ extern "C" int remove(const char *path) {
|
|||
|
||||
extern "C" int rename(const char *oldname, const char *newname) {
|
||||
#if MBED_CONF_FILESYSTEM_PRESENT
|
||||
errno = EBADF;
|
||||
FilePath fpOld(oldname);
|
||||
FilePath fpNew(newname);
|
||||
FileSystem *fsOld = fpOld.fileSystem();
|
||||
FileSystem *fsNew = fpNew.fileSystem();
|
||||
|
||||
if (fsOld == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* rename only if both files are on the same FS */
|
||||
if (fsOld != fsNew || fsOld == NULL) return -1;
|
||||
if (fsOld != fsNew) {
|
||||
errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int err = fsOld->rename(fpOld.fileName(), fpNew.fileName());
|
||||
if (err < 0) {
|
||||
|
@ -552,11 +597,12 @@ extern "C" char *_sys_command_string(char *cmd, int len) {
|
|||
|
||||
extern "C" DIR *opendir(const char *path) {
|
||||
#if MBED_CONF_FILESYSTEM_PRESENT
|
||||
errno = EBADF;
|
||||
|
||||
FilePath fp(path);
|
||||
FileSystem* fs = fp.fileSystem();
|
||||
if (fs == NULL) return NULL;
|
||||
if (fs == NULL) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dir *dir = new ManagedDir;
|
||||
int err = dir->open(fs, fp.fileName());
|
||||
|
@ -903,7 +949,25 @@ void mbed_set_unbuffered_stream(FILE *_file) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int mbed_getc(FILE *_file){
|
||||
/* Applications are expected to use fdopen()
|
||||
* not this function directly. This code had to live here because FILE and FileHandle
|
||||
* processes are all linked together here.
|
||||
*/
|
||||
std::FILE *mbed_fdopen(FileHandle *fh, const char *mode)
|
||||
{
|
||||
char buf[12]; /* :0x12345678 + null byte */
|
||||
std::sprintf(buf, ":%p", fh);
|
||||
std::FILE *stream = std::fopen(buf, mode);
|
||||
/* newlib-nano doesn't appear to ever call _isatty itself, so
|
||||
* happily fully buffers an interactive stream. Deal with that here.
|
||||
*/
|
||||
if (stream && fh->isatty()) {
|
||||
mbed_set_unbuffered_stream(stream);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
int mbed_getc(std::FILE *_file){
|
||||
#if defined (__ICCARM__)
|
||||
/*This is only valid for unbuffered streams*/
|
||||
int res = std::fgetc(_file);
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#ifndef RETARGET_H
|
||||
#define RETARGET_H
|
||||
|
||||
#if __cplusplus
|
||||
#include <cstdio>
|
||||
#endif //__cplusplus
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -48,7 +51,11 @@ typedef int mode_t; ///< Mode for opening files
|
|||
|
||||
/* DIR declarations must also be here */
|
||||
#if __cplusplus
|
||||
namespace mbed { class Dir; }
|
||||
namespace mbed {
|
||||
class Dir;
|
||||
class FileHandle;
|
||||
std::FILE *mbed_fdopen(FileHandle *fh, const char *mode);
|
||||
}
|
||||
typedef mbed::Dir DIR;
|
||||
#else
|
||||
typedef struct Dir DIR;
|
||||
|
@ -77,71 +84,54 @@ extern "C" {
|
|||
* Note also that ARMCC errno.h defines some symbol values differently from
|
||||
* the GCC_ARM/IAR/standard POSIX definitions. The definitions guard against
|
||||
* this and future changes by changing the symbol definition as shown below. */
|
||||
#ifdef ENOENT
|
||||
#undef ENOENT
|
||||
#endif
|
||||
#define ENOENT 2 /* No such file or directory. */
|
||||
|
||||
#ifdef EIO
|
||||
#undef EIO
|
||||
#endif
|
||||
#define EIO 5 /* I/O error */
|
||||
|
||||
#ifdef ENXIO
|
||||
#undef ENXIO
|
||||
#endif
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
|
||||
#ifdef ENOEXEC
|
||||
#undef ENOEXEC
|
||||
#endif
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
|
||||
#ifdef EBADF
|
||||
#undef EBADF
|
||||
#endif
|
||||
#define EBADF 9 /* Bad file number */
|
||||
|
||||
#ifdef ENOMEM
|
||||
#undef ENOMEM
|
||||
#endif
|
||||
#define ENOMEM 12 /* Not enough space */
|
||||
|
||||
#ifdef EACCES
|
||||
#undef EACCES
|
||||
#endif
|
||||
#define EACCES 13 /* Permission denied */
|
||||
|
||||
#ifdef EFAULT
|
||||
#undef EFAULT
|
||||
#endif
|
||||
#define EFAULT 14 /* Bad address */
|
||||
|
||||
#ifdef EEXIST
|
||||
#undef EEXIST
|
||||
#endif
|
||||
#define EEXIST 17 /* File exists */
|
||||
|
||||
#ifdef EINVAL
|
||||
#undef EXDEV
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
|
||||
#undef EINVAL
|
||||
#endif
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
|
||||
#ifdef ENFILE
|
||||
#undef ENFILE
|
||||
#endif
|
||||
#define ENFILE 23 /* Too many open files in system */
|
||||
|
||||
#ifdef EMFILE
|
||||
#undef EMFILE
|
||||
#endif
|
||||
#define EMFILE 24 /* File descriptor value too large */
|
||||
|
||||
#ifdef ENOSYS
|
||||
#undef ESPIPE
|
||||
#define ESPIPE 29 /* Invalid seek */
|
||||
|
||||
#undef ENOSYS
|
||||
#endif
|
||||
#define ENOSYS 38 /* Function not implemented */
|
||||
|
||||
#undef EOVERFLOW
|
||||
#define EOVERFLOW 75 /* Value too large to be stored in data type */
|
||||
|
||||
/* Missing stat.h defines.
|
||||
* The following are sys/stat.h definitions not currently present in the ARMCC
|
||||
* errno.h. Note, ARMCC errno.h defines some symbol values differing from
|
||||
|
@ -187,5 +177,4 @@ enum {
|
|||
DT_SOCK, // This is a UNIX domain socket.
|
||||
};
|
||||
|
||||
|
||||
#endif /* RETARGET_H */
|
||||
|
|
Loading…
Reference in New Issue