summaryrefslogtreecommitdiff
path: root/minix/fs/isofs/read.c
blob: b286500652a79c50fe06aab606fef310daf880f3 (plain)
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
#include "inc.h"

static char getdents_buf[GETDENTS_BUFSIZ];

ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
	off_t pos, int __unused call)
{
	size_t off, chunk, block_size, cum_io;
	off_t f_size;
	struct inode *i_node;
	struct buf *bp;
	int r;

	/* Try to get inode according to its index. */
	if ((i_node = get_inode(ino_nr)) == NULL)
		return EINVAL; /* No inode found. */

	f_size = i_node->i_stat.st_size;
	if (pos >= f_size)
		return 0; /* EOF */

	/* Limit the request to the remainder of the file size. */
	if ((off_t)bytes > f_size - pos)
		bytes = (size_t)(f_size - pos);

	block_size = v_pri.logical_block_size_l;
	cum_io = 0;

	r = OK;

	/* Split the transfer into chunks that don't span two blocks. */
	while (bytes > 0) {
		off = pos % block_size;

		chunk = block_size - off;
		if (chunk > bytes)
			chunk = bytes;

		/* Read 'chunk' bytes. */
		bp = read_extent_block(&i_node->extent, pos);
		if (bp == NULL)
			panic("bp not valid in rw_chunk; this can't happen");

		r = fsdriver_copyout(data, cum_io, b_data(bp)+off, chunk);

		lmfs_put_block(bp);

		if (r != OK)
			break;

		/* Update counters and pointers. */
		bytes -= chunk;		/* Bytes yet to be read. */
		cum_io += chunk;	/* Bytes read so far. */
		pos += chunk;		/* Position within the file. */
	}

	return (r == OK) ? cum_io : r;
}

ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
	off_t *pos)
{
	struct fsdriver_dentry fsdentry;
	struct inode *i_node;
	off_t cur_pos;
	int r, len;
	char *cp;

	if ((i_node = get_inode(ino_nr)) == NULL)
		return EINVAL;

	if (*pos < 0 || *pos > SSIZE_MAX)
		return EINVAL;

	r = read_directory(i_node);
	if (r != OK)
		return r;

	fsdriver_dentry_init(&fsdentry, data, bytes, getdents_buf,
	    sizeof(getdents_buf));

	r = OK;

	for (cur_pos = *pos; cur_pos < i_node->dir_size; cur_pos++) {
		/* Compute the length of the name */
		cp = memchr(i_node->dir_contents[cur_pos].name, '\0', NAME_MAX);
		if (cp == NULL)
			len = NAME_MAX;
		else
			len = cp - i_node->dir_contents[cur_pos].name;

		r = fsdriver_dentry_add(&fsdentry,
		    i_node->dir_contents[cur_pos].i_node->i_stat.st_ino,
		    i_node->dir_contents[cur_pos].name, len,
		    IFTODT(i_node->dir_contents[cur_pos].i_node->i_stat.st_mode));

		if (r <= 0)
			break;
	}

	if (r >= 0 && (r = fsdriver_dentry_finish(&fsdentry)) >= 0)
		*pos = cur_pos;

	return r;
}