DEBUG_FMT("Building structure for port %s", portname);
+#if !defined(_WIN32) && defined(HAVE_REALPATH)
+ /*
+ * get_port_details() below tries to be too smart and figure out
+ * some transport properties from the port name which breaks with
+ * symlinks. Therefore we canonicalize the portname first.
+ */
+ char pathbuf[PATH_MAX + 1];
+ char *res = realpath(portname, pathbuf);
+ if (!res)
+ RETURN_ERROR(SP_ERR_ARG, "Could not retrieve realpath behind port name");
+
+ portname = pathbuf;
+#endif
+
if (!(port = malloc(sizeof(struct sp_port))))
RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
#ifdef _WIN32
#define CHECK_PORT_HANDLE() do { \
if (port->hdl == INVALID_HANDLE_VALUE) \
- RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \
+ RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
} while (0)
#else
#define CHECK_PORT_HANDLE() do { \
if (port->fd < 0) \
- RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \
+ RETURN_ERROR(SP_ERR_ARG, "Port not open"); \
} while (0)
#endif
#define CHECK_OPEN_PORT() do { \
#endif
}
+#ifdef _WIN32
+static enum sp_return await_write_completion(struct sp_port *port)
+{
+ TRACE("%p", port);
+ DWORD bytes_written;
+ BOOL result;
+
+ /* Wait for previous non-blocking write to complete, if any. */
+ if (port->writing) {
+ DEBUG("Waiting for previous write to complete");
+ result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
+ port->writing = 0;
+ if (!result)
+ RETURN_FAIL("Previous write failed to complete");
+ DEBUG("Previous write completed");
+ }
+
+ RETURN_OK();
+}
+#endif
+
SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
size_t count, unsigned int timeout_ms)
{
#ifdef _WIN32
DWORD bytes_written = 0;
- BOOL result;
- /* Wait for previous non-blocking write to complete, if any. */
- if (port->writing) {
- DEBUG("Waiting for previous write to complete");
- result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
- port->writing = 0;
- if (!result)
- RETURN_FAIL("Previous write failed to complete");
- DEBUG("Previous write completed");
- }
+ TRY(await_write_completion(port));
/* Set timeout. */
if (port->timeouts.WriteTotalTimeoutConstant != timeout_ms) {
RETURN_INT(count);
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for write to complete");
- if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0)
- RETURN_FAIL("GetOverlappedResult() failed");
+ if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) {
+ if (GetLastError() == ERROR_SEM_TIMEOUT) {
+ DEBUG("Write timed out");
+ RETURN_INT(0);
+ } else {
+ RETURN_FAIL("GetOverlappedResult() failed");
+ }
+ }
DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count);
RETURN_INT(bytes_written);
} else {
/* Loop until we have at least one byte, or timeout is reached. */
while (bytes_read == 0) {
/* Start read. */
- if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl)) {
+ if (ReadFile(port->hdl, buf, count, &bytes_read, &port->read_ovl)) {
DEBUG("Read completed immediately");
- bytes_read = count;
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for read to complete");
if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)