diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2010-06-08 15:47:34 -0400 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2010-06-10 10:17:38 -0400 |
commit | 06247775aa9c49ffce72827921eb45e2d04c6aa1 (patch) | |
tree | c3e53abf07faa3c8e161cff30746d54af6a78791 /src/tools | |
parent | e5196fd7da44e4ae04ab8b5d2e7191167762cf0b (diff) | |
download | sssd-06247775aa9c49ffce72827921eb45e2d04c6aa1.tar.gz sssd-06247775aa9c49ffce72827921eb45e2d04c6aa1.tar.bz2 sssd-06247775aa9c49ffce72827921eb45e2d04c6aa1.zip |
Properly handle read() and write() throughout the SSSD
We need to guarantee at all times that reads and writes complete
successfully. This means that they must be checked for returning
EINTR and EAGAIN, and all writes must be wrapped in a loop to
ensure that they do not truncate their output.
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/files.c | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/src/tools/files.c b/src/tools/files.c index b3b516ea..27ebf72d 100644 --- a/src/tools/files.c +++ b/src/tools/files.c @@ -402,7 +402,7 @@ static int copy_file(const char *src, int ifd = -1; int ofd = -1; char buf[1024]; - ssize_t cnt, written, offset; + ssize_t cnt, written, res; struct stat fstatbuf; ifd = open(src, O_RDONLY); @@ -454,27 +454,44 @@ static int copy_file(const char *src, goto fail; } - while ((cnt = read(ifd, buf, sizeof(buf))) > 0) { - offset = 0; - while (cnt > 0) { - written = write(ofd, buf+offset, (size_t)cnt); - if (written == -1) { - ret = errno; - DEBUG(1, ("Cannot write() to source file '%s': [%d][%s].\n", - dst, ret, strerror(ret))); - goto fail; + while ((cnt = read(ifd, buf, sizeof(buf))) != 0) { + if (cnt == -1) { + if (errno == EINTR || errno == EAGAIN) { + continue; } - offset += written; - cnt -= written; + + DEBUG(1, ("Cannot read() from source file '%s': [%d][%s].\n", + src, ret, strerror(ret))); + goto fail; + } + else if (cnt > 0) { + /* Copy the buffer to the new file */ + written = 0; + while (written < cnt) { + res = write(ofd, buf+written, (size_t)cnt-written); + if (res == -1) { + ret = errno; + if (ret == EINTR || ret == EAGAIN) { + /* retry the write */ + continue; + } + DEBUG(1, ("Cannot write() to destination file '%s': [%d][%s].\n", + dst, ret, strerror(ret))); + goto fail; + } + else if (res <= 0) { + DEBUG(1, ("Unexpected result from write(): [%d]\n", res)); + goto fail; + } + + written += res; + } + } + else { + DEBUG(1, ("Unexpected return code of read [%d]\n", cnt)); + goto fail; } } - if (cnt == -1) { - ret = errno; - DEBUG(1, ("Cannot read() from source file '%s': [%d][%s].\n", - dst, ret, strerror(ret))); - goto fail; - } - ret = close(ifd); ifd = -1; |