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
|
/* Access to file layout information
Copyright (C) 1996 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <string.h>
#include <netinet/in.h> /* htonl */
#include <hurd/store.h>
#include "ext2fs.h"
error_t
diskfs_S_file_get_storage_info (struct protid *cred,
mach_port_t **ports,
mach_msg_type_name_t *ports_type,
mach_msg_type_number_t *num_ports,
int **ints, mach_msg_type_number_t *num_ints,
off_t **offsets,
mach_msg_type_number_t *num_offsets,
char **data, mach_msg_type_number_t *data_len)
{
error_t err = 0;
unsigned num_fs_blocks;
struct store *file_store;
struct store_run *runs, *run = 0;
block_t index = 0;
size_t num_runs = 0, runs_alloced = 10;
struct node *node = cred->po->np;
runs = malloc (runs_alloced * sizeof (struct store_run));
if (! runs)
return ENOMEM;
mutex_lock (&node->lock);
/* NUM_FS_BLOCKS counts down the blocks in the file that we've not
enumerated yet; when it hits zero, we can stop. */
num_fs_blocks = node->dn_stat.st_blocks >> log2_stat_blocks_per_fs_block;
while (num_fs_blocks-- > 0)
{
block_t block;
err = ext2_getblk (node, index++, 0, &block);
if (err == EINVAL)
/* Either a hole, or past the end of the file. */
{
block = 0;
err = 0;
}
else if (err)
break;
block <<= log2_dev_blocks_per_fs_block;
if (num_runs == 0
|| ((block && run->start >= 0) /* Neither is a hole and... */
? (block != run->start + run->length) /* BLOCK doesn't follow RUN */
: (block || run->start >= 0))) /* or one is, but not both */
/* Add a new run. */
{
if (num_runs == runs_alloced)
/* Make some more space in RUNS. */
{
struct store_run *new;
runs_alloced *= 2;
new = realloc (runs, runs_alloced * sizeof (struct store_run));
if (! new)
{
err = ENOMEM;
break;
}
runs = new;
}
run = runs + num_runs++;
run->start = block ?: -1; /* -1 means a hole in OFFSETS */
run->length = 0; /* will get extended just below */
}
/* Increase the size of the current run by one filesystem block. */
run->length += 1 << log2_dev_blocks_per_fs_block;
}
mutex_unlock (&node->lock);
if (! err)
err = store_clone (store, &file_store);
if (! err)
{
err = store_remap (file_store, runs, num_runs, &file_store);
if (! err)
err = store_return (file_store, ports, num_ports, ints, num_ints,
offsets, num_offsets, data, data_len);
store_free (file_store);
}
free (runs);
return err;
}
|