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>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
diff --git a/include/git/os/unix.h b/include/git/os/unix.h
index dd58389..56f77b9 100644
--- a/include/git/os/unix.h
+++ b/include/git/os/unix.h
@@ -54,58 +54,55 @@ typedef int git_file;
* - O_WRONLY: Open the file for 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 flags bitmask of access requested to the file.
- * @return the opened file descriptor; <0 if the open failed.
- */
-static inline git_file git_fopen(const char *path, int flags)
-{
- return open(path, flags);
-}
-
-/**
- * Close an open file descriptor.
- * @param fd descriptor to close.
- * @return 0 on success; <0 if the descriptor close failed.
+ * @return
+ * - On success, GIT_SUCCESS.
+ * - On error, <0.
*/
-static inline int git_fclose(git_file fd)
-{
- return close(fd);
-}
+GIT_EXTERN(int) git_fopen(git_file *out, const char *path, int flags);
/**
* Read from an open file descriptor at the current position.
*
- * Less than the number of requested bytes may be read. The
- * read is automatically restarted if it fails due to a signal
- * being delivered to the calling thread.
+ * Exactly the requested number of bytes is read. If the stream
+ * ends early, an error is indicated, and the exact number of bytes
+ * transferred is unspecified.
*
* @param fd open descriptor.
* @param buf buffer to store the read data into.
* @param cnt number of bytes to transfer.
* @return
- * - On success, actual number of bytes read.
- * - On EOF, 0.
- * - On failure, <0.
+ * - On success, GIT_SUCCESS.
+ * - On error, <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.
*
- * Less than the number of requested bytes may be written. The
- * write is automatically restarted if it fails due to a signal
- * being delivered to the calling thread.
+ * Exactly the requested number of bytes is written. If the stream
+ * ends early, an error is indicated, and the exact number of bytes
+ * transferred is unspecified.
*
* @param fd open descriptor.
* @param buf buffer to write data from.
* @param cnt number of bytes to transfer.
* @return
- * - On success, actual number of bytes written.
- * - On EOF, 0.
- * - On failure, <0.
+ * - On success, GIT_SUCCESS.
+ * - On error, <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
diff --git a/src/os/unix.c b/src/os/unix.c
index d132e97..767f20c 100644
--- a/src/os/unix.c
+++ b/src/os/unix.c
@@ -26,22 +26,51 @@
#include <errno.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 (;;) {
- ssize_t r = read(fd, buf, cnt);
- if (r < 0 && (errno == EINTR || errno == EAGAIN))
- continue;
- return r;
+ int r = open(path, flags);
+ if (r < 0)
+ return -1;
+ *out = 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 (;;) {
- ssize_t r = write(fd, buf, cnt);
- if (r < 0 && (errno == EINTR || errno == EAGAIN))
- continue;
- return r;
+ char *b = buf;
+ while (cnt) {
+ ssize_t r = write(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;
}