Commit 3e9e6909 by Shawn O. Pearce

Redefine git_fread, git_fwrite to transfer the whole unit

We never want to accept a short read or a short write when
transferring data to or from a local file.

Either the entire read (or write) completes or the operation
failed and we will not recover gracefully from it.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
parent b7c891c6
...@@ -54,58 +54,55 @@ typedef int git_file; ...@@ -54,58 +54,55 @@ typedef int git_file;
* - O_WRONLY: Open the file for writing. * - O_WRONLY: Open the file for writing.
* - O_RDWR: Open the file for both reading and writing. * - O_RDWR: Open the file for both reading and writing.
* *
* @param out descriptor storage to populate on success.
* @param path path name of the file to open. * @param path path name of the file to open.
* @param flags bitmask of access requested to the file. * @param flags bitmask of access requested to the file.
* @return the opened file descriptor; <0 if the open failed. * @return
*/ * - On success, GIT_SUCCESS.
static inline git_file git_fopen(const char *path, int flags) * - On error, <0.
{
return open(path, flags);
}
/**
* Close an open file descriptor.
* @param fd descriptor to close.
* @return 0 on success; <0 if the descriptor close failed.
*/ */
static inline int git_fclose(git_file fd) GIT_EXTERN(int) git_fopen(git_file *out, const char *path, int flags);
{
return close(fd);
}
/** /**
* Read from an open file descriptor at the current position. * Read from an open file descriptor at the current position.
* *
* Less than the number of requested bytes may be read. The * Exactly the requested number of bytes is read. If the stream
* read is automatically restarted if it fails due to a signal * ends early, an error is indicated, and the exact number of bytes
* being delivered to the calling thread. * transferred is unspecified.
* *
* @param fd open descriptor. * @param fd open descriptor.
* @param buf buffer to store the read data into. * @param buf buffer to store the read data into.
* @param cnt number of bytes to transfer. * @param cnt number of bytes to transfer.
* @return * @return
* - On success, actual number of bytes read. * - On success, GIT_SUCCESS.
* - On EOF, 0. * - On error, <0.
* - On failure, <0.
*/ */
GIT_EXTERN(ssize_t) git_fread(git_file fd, void *buf, size_t cnt); GIT_EXTERN(int) git_fread(git_file fd, void *buf, size_t cnt);
/** /**
* Write to an open file descriptor at the current position. * Write to an open file descriptor at the current position.
* *
* Less than the number of requested bytes may be written. The * Exactly the requested number of bytes is written. If the stream
* write is automatically restarted if it fails due to a signal * ends early, an error is indicated, and the exact number of bytes
* being delivered to the calling thread. * transferred is unspecified.
* *
* @param fd open descriptor. * @param fd open descriptor.
* @param buf buffer to write data from. * @param buf buffer to write data from.
* @param cnt number of bytes to transfer. * @param cnt number of bytes to transfer.
* @return * @return
* - On success, actual number of bytes written. * - On success, GIT_SUCCESS.
* - On EOF, 0. * - On error, <0.
* - On failure, <0. */
GIT_EXTERN(int) git_fwrite(git_file fd, void *buf, size_t cnt);
/**
* Close an open file descriptor.
* @param fd descriptor to close.
* @return
* - On success, GIT_SUCCESS.
* - On error, <0.
*/ */
GIT_EXTERN(ssize_t) git_fwrite(git_file fd, void *buf, size_t cnt); #define git_fclose(fd) close(fd)
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -26,22 +26,51 @@ ...@@ -26,22 +26,51 @@
#include <errno.h> #include <errno.h>
#include "git/common.h" #include "git/common.h"
ssize_t git_fread(git_file fd, void *buf, size_t cnt) int git_fopen(git_file *out, const char *path, int flags)
{ {
for (;;) { int r = open(path, flags);
ssize_t r = read(fd, buf, cnt); if (r < 0)
if (r < 0 && (errno == EINTR || errno == EAGAIN)) return -1;
continue; *out = r;
return r; return GIT_SUCCESS;
}
int git_fread(git_file fd, void *buf, size_t cnt)
{
char *b = buf;
while (cnt) {
ssize_t r = read(fd, b, cnt);
if (r < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
return -1;
}
if (!r) {
errno = EPIPE;
return -1;
}
cnt -= r;
b += r;
} }
return GIT_SUCCESS;
} }
ssize_t git_fwrite(git_file fd, void *buf, size_t cnt) int git_fwrite(git_file fd, void *buf, size_t cnt)
{ {
for (;;) { char *b = buf;
ssize_t r = write(fd, buf, cnt); while (cnt) {
if (r < 0 && (errno == EINTR || errno == EAGAIN)) ssize_t r = write(fd, b, cnt);
continue; if (r < 0) {
return r; if (errno == EINTR || errno == EAGAIN)
continue;
return -1;
}
if (!r) {
errno = EPIPE;
return -1;
}
cnt -= r;
b += r;
} }
return GIT_SUCCESS;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment