diff --git a/common/startup.c b/common/startup.c index 8b07542..8940674 100644 --- a/common/startup.c +++ b/common/startup.c @@ -54,6 +54,7 @@ { mount("none", "ramfs", "/", NULL); mkdir("/dev", 0); + mkdir("/tmp", 0); mount("none", "devfs", "/dev", NULL); if (IS_ENABLED(CONFIG_FS_EFIVARFS)) { diff --git a/common/uimage.c b/common/uimage.c index b6f0f10..3273bc1 100644 --- a/common/uimage.c +++ b/common/uimage.c @@ -85,8 +85,6 @@ } EXPORT_SYMBOL(uimage_get_size); -static const char uimage_tmp[] = "/.uImage_tmp"; - /* * open a uimage. This will check the header contents and * return a handle to the uImage @@ -99,32 +97,27 @@ struct image_header *header; int i; int ret; - struct stat s; + char *copy = NULL; -again: + if (is_tftp_fs(filename)) { + ret = cache_file(filename, ©); + if (ret) + return NULL; + filename = copy; + } + fd = open(filename, O_RDONLY); if (fd < 0) { printf("could not open: %s\n", errno_str()); + free(copy); return NULL; } - /* - * Hack around tftp fs. We need lseek for uImage support, but - * this cannot be implemented in tftp fs, so we detect this - * and copy the file to ram if it fails - */ - if (IS_BUILTIN(CONFIG_FS_TFTP) && !can_lseek_backward(fd)) { - close(fd); - ret = copy_file(filename, uimage_tmp, 0); - if (ret) - return NULL; - filename = uimage_tmp; - goto again; - } - handle = xzalloc(sizeof(struct uimage_handle)); header = &handle->header; + handle->copy = copy; + if (read(fd, header, sizeof(*header)) < 0) { printf("could not read: %s\n", errno_str()); goto err_out; @@ -202,9 +195,14 @@ return handle; err_out: close(fd); + + free(handle->name); + if (handle->copy) { + unlink(handle->copy); + free(handle->copy); + } free(handle); - if (IS_BUILTIN(CONFIG_FS_TFTP) && !stat(uimage_tmp, &s)) - unlink(uimage_tmp); + return NULL; } EXPORT_SYMBOL(uimage_open); @@ -214,14 +212,15 @@ */ void uimage_close(struct uimage_handle *handle) { - struct stat s; - close(handle->fd); + + if (handle->copy) { + unlink(handle->copy); + free(handle->copy); + } + free(handle->name); free(handle); - - if (IS_BUILTIN(CONFIG_FS_TFTP) && !stat(uimage_tmp, &s)) - unlink(uimage_tmp); } EXPORT_SYMBOL(uimage_close); diff --git a/fs/fs.c b/fs/fs.c index d188fa9..88f0b14 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -1914,3 +1914,25 @@ return xstrdup(str); } + +/** + * __is_tftp_fs() - return true when path is mounted on TFTP + * @path: The path + * + * Do not use directly, use is_tftp_fs instead. + * + * Return: true when @path is on TFTP, false otherwise + */ +bool __is_tftp_fs(const char *path) +{ + struct fs_device_d *fsdev; + + fsdev = get_fsdevice_by_path(path); + if (!fsdev) + return false; + + if (strcmp(fsdev->driver->drv.name, "tftp")) + return false; + + return true; +} diff --git a/fs/uimagefs.c b/fs/uimagefs.c index c0c5750..c120944 100644 --- a/fs/uimagefs.c +++ b/fs/uimagefs.c @@ -196,7 +196,6 @@ { struct uimagefs_handle *priv = dev->priv; struct uimagefs_handle_data *d, *tmp; - struct stat s; list_for_each_entry_safe(d, tmp, &priv->list, list) { free(d->name); @@ -204,10 +203,11 @@ free(d); } - if (IS_BUILTIN(CONFIG_FS_TFTP) && !stat(priv->tmp, &s)) - unlink(priv->tmp); + if (priv->copy) { + unlink(priv->copy); + free(priv->copy); + } - free(priv->tmp); free(priv); } @@ -363,28 +363,21 @@ int ret; size_t offset = 0; size_t data_offset = 0; + const char *filename = priv->filename; -again: - fd = open(priv->filename, O_RDONLY); + if (is_tftp_fs(filename)) { + ret = cache_file(filename, &priv->copy); + if (ret) + return ret; + filename = priv->copy; + } + + fd = open(filename, O_RDONLY); if (fd < 0) { printf("could not open: %s\n", errno_str()); return fd; } - /* - * Hack around tftp fs. We need lseek for uImage support, but - * this cannot be implemented in tftp fs, so we detect this - * and copy the file to ram if it fails - */ - if (IS_BUILTIN(CONFIG_FS_TFTP) && !can_lseek_backward(fd)) { - close(fd); - ret = copy_file(priv->filename, priv->tmp, 0); - if (ret) - return ret; - priv->filename = priv->tmp; - goto again; - } - header = &priv->header; ret = read(fd, header, sizeof(*header)); @@ -514,10 +507,6 @@ priv->filename = fsdev->backingstore; dev_dbg(dev, "mount: %s\n", fsdev->backingstore); - if (IS_BUILTIN(CONFIG_FS_TFTP)) - priv->tmp = basprintf("/.uImage_tmp_%08x", - crc32(0, fsdev->path, strlen(fsdev->path))); - ret = __uimage_open(priv); if (ret) goto err; diff --git a/include/fs.h b/include/fs.h index 3d88bfa..e6fcd04 100644 --- a/include/fs.h +++ b/include/fs.h @@ -101,24 +101,14 @@ char *linux_rootarg; }; -/* - * Some filesystems i.e. tftpfs only support lseek into one direction. - * To detect this limited functionality we add this extra function. - * Additionaly we also return 0 if we even can not seek forward. - */ -static inline int can_lseek_backward(int fd) +bool __is_tftp_fs(const char *path); + +static inline bool is_tftp_fs(const char *path) { - int ret; + if (!IS_ENABLED(CONFIG_FS_TFTP)) + return false; - ret = lseek(fd, 1, SEEK_SET); - if (ret < 0) - return 0; - - ret = lseek(fd, 0, SEEK_SET); - if (ret < 0) - return 0; - - return 1; + return __is_tftp_fs(path); } #define drv_to_fs_driver(d) container_of(d, struct fs_driver_d, drv) diff --git a/include/image.h b/include/image.h index 3e75d49..add9c85 100644 --- a/include/image.h +++ b/include/image.h @@ -246,6 +246,7 @@ struct uimage_handle { struct image_header header; char *name; + char *copy; struct uimage_handle_data ihd[MAX_MULTI_IMAGE_COUNT]; int nb_data_entries; size_t data_offset; diff --git a/include/libfile.h b/include/libfile.h index eb4311d..fd2fade 100644 --- a/include/libfile.h +++ b/include/libfile.h @@ -26,4 +26,8 @@ int unlink_recursive(const char *path, char **failedpath); +char *make_temp(const char *template); + +int cache_file(const char *path, char **newpath); + #endif /* __LIBFILE_H */ diff --git a/include/uimagefs.h b/include/uimagefs.h index 81b3231..3f58589 100644 --- a/include/uimagefs.h +++ b/include/uimagefs.h @@ -45,7 +45,7 @@ struct image_header header; int nb_data_entries; char *filename; - char *tmp; + char *copy; struct list_head list; }; diff --git a/lib/libfile.c b/lib/libfile.c index 1face96..b7db22d 100644 --- a/lib/libfile.c +++ b/lib/libfile.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* @@ -485,3 +486,57 @@ return fd; } + +/** + * make_temp - create a name for a temporary file + * @template: The filename prefix + * + * This function creates a name for a temporary file. @template is used as a + * template for the name which gets appended a 8-digit hexadecimal number to + * create a unique filename. + * + * Return: This function returns a filename which can be used as a temporary + * file later on. The returned filename must be freed by the caller. + */ +char *make_temp(const char *template) +{ + char *name = NULL; + struct stat s; + int ret; + + do { + free(name); + name = basprintf("/tmp/%s-%08x", template, random32()); + ret = stat(name, &s); + } while (!ret); + + return name; +} + +/** + * cache_file - Cache a file in /tmp + * @path: The file to cache + * @newpath: The return path where the file is copied to + * + * This function copies a given file to /tmp and returns its name in @newpath. + * @newpath is dynamically allocated and must be freed by the caller. + * + * Return: 0 for success, negative error code otherwise. + */ +int cache_file(const char *path, char **newpath) +{ + char *npath; + int ret; + + npath = make_temp("filecache"); + + ret = copy_file(path, npath, 0); + if (ret) { + free(npath); + return ret; + } + + *newpath = npath; + + return 0; +}