+2013-09-10 Keith Marshall <keithmarshall@users.sourceforge.net>
+
+ Fix MinGW-Bug #2026.
+
+ * src/dmhguix.cpp (DMH_PTY_GUARDBYTES): New manifest constant.
+ (dmhTypePTY::printf) [buffer full]: Use it; it defines a reserved byte
+ count, at end of buffer, where expansion or scroll out is triggered;
+ use memcpy() for scroll out, but avoid overlapping regions.
+ (dmhTypePTY::printf) [output == '\r']: Handle it.
+
+ * src/tarproc.cpp (create_output_stream): Improve diagnostic messages;
+ discriminate between file collision and other privilege violations.
+ (pkgArchiveProcessor::ExtractFile): Don't return a zero status code,
+ when the output stream could not be successfully opened, so that...
+ (pkgTarArchiveInstaller::ProcessDataStream): ...we may avoid writing a
+ spurious manifest entry here.
+
2013-09-06 Keith Marshall <keithmarshall@users.sourceforge.net>
Update version, pre-empting subsequent release.
*/
#define DMH_PTY_MIN_BUFSIZ 4096
#define DMH_PTY_MAX_BUFSIZ 32768
+#define DMH_PTY_GUARDBYTES 1
class dmhTypePTY
{
{
/* An explicit '\r' in the data stream should return the
* caret to the start of the current PHYSICAL line in the
- * EDITTEXT display
- *
- * FIXME: must implement this; ignore, (and discount), it
- * for now.
+ * EDITTEXT display.
+ */
+ char *mark = caret;
+ while( (mark > console_buffer) && (*--mark != '\n') )
+ caret = mark;
+
+ /* The '\r' character isn't actually written to the
+ * output buffer; discount it.
*/
--retval;
}
{
/* Helper method for appending a single character to the PTY "device"
* buffer; this will allocate an expanding buffer, (up to the maximum
- * specified size limit), as may be required.
+ * specified size limit, with reservation of sufficient guard bytes to
+ * ensure that output may be safely terminated), as may be required.
*/
size_t offset;
- if( (offset = caret - console_buffer) >= max )
+ const size_t guarded_max = max - DMH_PTY_GUARDBYTES;
+ if( (offset = caret - console_buffer) >= guarded_max )
{
/* The current "device" buffer is full; compute a new size, for
* possible buffer expansion.
caret = (console_buffer = newbuf) + offset;
}
}
- if( offset >= max )
+ if( offset >= guarded_max )
{
/* The buffer has reached its maximum permitted size, (or there
* was insufficient free memory to expand it), and there still
/* ...then copy it, and all following lines, to the start of the
* buffer, so deleting the FIRST logical line, and thus free up
* an equivalent amount of space at the end.
+ *
+ * Note: we might get away with a single memcpy() of the entire
+ * portion of the buffer, from the SECOND line onward, backwards
+ * to overwrite the FIRST line, but that would entail copying of
+ * overlapping memory regions, which is technically described as
+ * causing undefined behaviour; to avoid any possible problems,
+ * we identify a block size equal to the space occupied by the
+ * first line...
*/
- for( caret = console_buffer; mark < endptr; )
- *caret++ = *mark++;
+ size_t residual = caret - mark;
+ size_t block_size = mark - (caret = console_buffer);
+ while( residual >= block_size )
+ {
+ /* ...then copy the residual, in chunks of that size, (so that
+ * there is never any overlap), until we reduce the residual to
+ * less than the block size...
+ */
+ memcpy( caret, mark, block_size );
+ residual -= block_size; caret = mark; mark += block_size;
+ }
+ if( residual > 0 )
+ {
+ /* ...finishing up by copying any lesser sized final residual,
+ * and leaving the caret at the start of the space so freed.
+ */
+ memcpy( caret, mark, residual );
+ caret += residual;
+ }
}
}
/* Finally, store the current character into the "device" buffer, and
/* Overwrite prevention was triggered; diagnose.
*/
dmh_notify_extraction_failed( name );
- dmh_notify( DMH_ERROR, "cannot replace existing file\n" );
+ if( errno == EEXIST )
+ {
+ /* The exception was triggered by an already existing file;
+ * this likely indicates a conflict between two packages.
+ */
+ dmh_notify( DMH_ERROR,
+ "%s: probable package conflict; existing file not overwritten\n",
+ name
+ );
+ }
+ else
+ { /* Otherwise, the user isn't allowed to write the extracted
+ * file, in the location designated for installation.
+ */
+ dmh_notify( DMH_ERROR,
+ "%s: permission denied; cannot store file\n", name
+ );
+ }
}
return fd;
}
}
}
}
- /* Finally, we pass the original status value back to the caller.
+ /* Finally, we pass either the original status value, or the
+ * failing file descriptor as an effective status, if no file
+ * could be extracted, back to the caller.
*/
- return status;
+ return (fd == -1) ? fd : status;
}
/*******************