diff --git a/src/barebox-state.c b/src/barebox-state.c index 3e3cb41..fd4f165 100644 --- a/src/barebox-state.c +++ b/src/barebox-state.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -1156,6 +1157,54 @@ return ret; } +#ifdef __BAREBOX__ +#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode) || S_ISCHR(s.st_mode)) +#else +#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode)) +#endif + +int get_size(const char *path, size_t *out_size) +{ + struct mtd_info_user meminfo; + struct stat s; + int ret; + int fd; + + ret = stat(path, &s); + if (ret) + return -errno; + + /* + * under Linux, stat() gives the size only on regular files + * under barebox, it works on char dev, too + */ + if (STAT_GIVES_SIZE(s)) { + *out_size = s.st_size; + return 0; + } + + /* this works under Linux on block devs */ + if (S_ISBLK(s.st_mode)) { + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + ret = ioctl(fd, BLKGETSIZE64, out_size); + close(fd); + if (!ret) + return 0; + } + + /* try mtd next */ + ret = mtd_get_meminfo(path, &meminfo); + if (!ret) { + *out_size = meminfo.size; + return 0; + } + + return ret; +} + /* * state_backend_raw_file - create a raw file backend store for a state instance * @@ -1179,20 +1228,21 @@ struct state_backend_raw *backend_raw; struct state_backend *backend; struct state_variable *sv; - int ret; - struct stat s; struct mtd_info_user meminfo; + size_t path_size; + int ret; if (state->backend) return -EBUSY; - ret = stat(path, &s); - if (!ret && S_ISCHR(s.st_mode)) { - if (size == 0) - size = s.st_size; - else if (offset + size > s.st_size) - return -EINVAL; - } + ret = get_size(path, &path_size); + if (ret) + return ret; + + if (size == 0) + size = path_size; + else if (offset + size > path_size) + return -EINVAL; backend_raw = xzalloc(sizeof(*backend_raw)); backend = &backend_raw->backend;