#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/stat.h>
-static int dump(int fd, size_t len, int pgsz, char *fname)
+static int dump_or_load(int fd, size_t *len, int pgsz, char *fname, int dump)
{
- int out;
+ int cfd;
char *page;
int i, npages;
int r;
+ int ifd, ofd;
+ int rem;
page = malloc(pgsz);
if (!page)
return -ENOMEM;
- out = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0644);
- if (out < 0)
- return -errno;
- npages = (len + pgsz - 1) / pgsz;
+ if (dump)
+ cfd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ else
+ cfd = open(fname, O_RDONLY);
+ if (cfd < 0)
+ goto out;
+ if (dump) {
+ ifd = fd;
+ ofd = cfd;
+ } else {
+ struct stat s;
+ r = fstat(cfd, &s);
+ if (r < 0) {
+ goto out;
+ }
+ *len = s.st_size;
+ ifd = cfd;
+ ofd = fd;
+ }
+ npages = (*len + pgsz - 1) / pgsz;
for (i = 1; i <= npages; i++) {
if (i == npages) {
- len = len & (pgsz - 1);
- if (len > 0) {
- r = read(fd, page, len);
- if (r != len)
+ rem = *len & (pgsz - 1);
+ if (rem > 0) {
+ r = read(ifd, page, rem);
+ if (r != rem)
goto out;
- r = write(out, page, len);
- if (r != len)
+ r = write(ofd, page, rem);
+ if (r != rem)
goto out;
+ /* Write padding */
+ if (!dump) {
+ memset(page, 0, pgsz - rem);
+ write(ofd, page, pgsz - rem);
+ }
}
} else {
- r = read(fd, page, pgsz);
+ r = read(ifd, page, pgsz);
if (r != pgsz)
goto out;
- r = write(out, page, pgsz);
+ r = write(ofd, page, pgsz);
if (r != pgsz)
goto out;
}
}
free(page);
- close(out);
+ close(cfd);
return 0;
out:
free(page);
- close(out);
+ close(cfd);
if (r < 0)
return -errno;
return -EINVAL;
}
+static int dump(int fd, size_t len, int pgsz, char *fname)
+{
+ return dump_or_load(fd, &len, pgsz, fname, 1);
+}
+
+static int load(int fd, size_t *len, int pgsz, char *fname)
+{
+ return dump_or_load(fd, len, pgsz, fname, 0);
+}
+
int main(int argc, char **argv)
{
int fd;