several net bugfixes and improvements and fix some memory leaks

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-13 18:31:53 +02:00
parent da1b289afc
commit bd40efbf0b
8 changed files with 365 additions and 180 deletions

View file

@ -35,6 +35,7 @@ struct grub_bufio
grub_file_t file;
grub_size_t block_size;
grub_size_t buffer_len;
grub_off_t buffer_at;
char buffer[0];
};
typedef struct grub_bufio *grub_bufio_t;
@ -70,6 +71,7 @@ grub_bufio_open (grub_file_t io, int size)
bufio->file = io;
bufio->block_size = size;
bufio->buffer_len = 0;
bufio->buffer_at = 0;
file->device = io->device;
file->offset = 0;
@ -104,83 +106,87 @@ grub_buffile_open (const char *name, int size)
static grub_ssize_t
grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
{
grub_size_t res = len;
grub_size_t res = 0;
grub_bufio_t bufio = file->data;
grub_uint64_t pos;
if ((file->offset >= bufio->file->offset) &&
(file->offset < bufio->file->offset + bufio->buffer_len))
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
file->size = bufio->file->size;
/* First part: use whatever we already have in the buffer. */
if ((file->offset >= bufio->buffer_at) &&
(file->offset < bufio->buffer_at + bufio->buffer_len))
{
grub_size_t n;
grub_uint64_t pos;
pos = file->offset - bufio->file->offset;
pos = file->offset - bufio->buffer_at;
n = bufio->buffer_len - pos;
if (n > len)
n = len;
grub_memcpy (buf, &bufio->buffer[pos], n);
len -= n;
if (! len)
return res;
res += n;
buf += n;
bufio->file->offset += bufio->buffer_len;
pos = 0;
}
if (! len)
return res;
/* Need to read some more. */
bufio->buffer_at = grub_divmod64 (file->offset + res + len, bufio->block_size,
0) * bufio->block_size;
/* Now read between file->offset + res and bufio->buffer_at. */
if (file->offset + res < bufio->buffer_at)
{
grub_size_t read_now;
grub_ssize_t really_read;
read_now = bufio->buffer_at - (file->offset + res);
grub_file_seek (bufio->file, file->offset + res);
really_read = grub_file_read (bufio->file, buf, read_now);
if (grub_errno)
return -1;
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
file->size = bufio->file->size;
len -= really_read;
buf += really_read;
res += really_read;
/* Partial read. File ended unexpectedly. Save the last chunk in buffer.
*/
if (really_read != (grub_ssize_t) read_now)
{
bufio->buffer_len = really_read;
if (bufio->buffer_len > bufio->block_size)
bufio->buffer_len = bufio->block_size;
bufio->buffer_at = file->offset + res - bufio->buffer_len;
grub_memcpy (&bufio->buffer[0], buf - bufio->buffer_len,
bufio->buffer_len);
return res;
}
}
/* Read into buffer. */
grub_file_seek (bufio->file, bufio->buffer_at);
bufio->buffer_len = grub_file_read (bufio->file, bufio->buffer,
bufio->block_size);
if (grub_errno)
return -1;
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
file->size = bufio->file->size;
if (len < bufio->buffer_len)
{
grub_memcpy (buf, &bufio->buffer[0], len);
res += len;
}
else
{
bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size,
&pos);
bufio->file->offset *= bufio->block_size;
grub_memcpy (buf, &bufio->buffer[0], bufio->buffer_len);
res += bufio->buffer_len;
}
if (pos + len >= bufio->block_size)
{
if (pos)
{
grub_size_t n;
bufio->file->fs->read (bufio->file, bufio->buffer,
bufio->block_size);
if (grub_errno)
return -1;
n = bufio->block_size - pos;
grub_memcpy (buf, &bufio->buffer[pos], n);
len -= n;
buf += n;
bufio->file->offset += bufio->block_size;
pos = 0;
}
while (len >= bufio->block_size)
{
bufio->file->fs->read (bufio->file, buf, bufio->block_size);
if (grub_errno)
return -1;
len -= bufio->block_size;
buf += bufio->block_size;
bufio->file->offset += bufio->block_size;
}
if (! len)
{
bufio->buffer_len = 0;
return res;
}
}
bufio->buffer_len = bufio->file->size - bufio->file->offset;
if (bufio->buffer_len > bufio->block_size)
bufio->buffer_len = bufio->block_size;
bufio->file->fs->read (bufio->file, bufio->buffer, bufio->buffer_len);
if (grub_errno)
return -1;
grub_memcpy (buf, &bufio->buffer[pos], len);
return res;
}