diff options
Diffstat (limited to 'src/fuse/readdir.c')
-rw-r--r-- | src/fuse/readdir.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/fuse/readdir.c b/src/fuse/readdir.c new file mode 100644 index 0000000..17145ae --- /dev/null +++ b/src/fuse/readdir.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /* | ||
2 | * reddir.c - FUSE read directory function | ||
3 | * | ||
4 | * Created on: Mar 14, 2012 | ||
5 | * Author: MG, Christian Grothoff, Matthias Wachs, | ||
6 | * Krista Bennett, James Blackwell, Igor Wronsky | ||
7 | * | ||
8 | * Read directory | ||
9 | * | ||
10 | * This supersedes the old getdir() interface. New applications | ||
11 | * should use this. | ||
12 | * | ||
13 | * The filesystem may choose between two modes of operation: | ||
14 | * | ||
15 | * 1) The readdir implementation ignores the offset parameter, and | ||
16 | * passes zero to the filler function's offset. The filler | ||
17 | * function will not return '1' (unless an error happens), so the | ||
18 | * whole directory is read in a single readdir operation. This | ||
19 | * works just like the old getdir() method. | ||
20 | * | ||
21 | * 2) The readdir implementation keeps track of the offsets of the | ||
22 | * directory entries. It uses the offset parameter and always | ||
23 | * passes non-zero offset to the filler function. When the buffer | ||
24 | * is full (or an error happens) the filler function will return | ||
25 | * '1'. | ||
26 | * | ||
27 | * Introduced in version 2.3 | ||
28 | */ | ||
29 | |||
30 | #include <sys/types.h> | ||
31 | #include <sys/mman.h> | ||
32 | #include <fcntl.h> | ||
33 | #include <unistd.h> | ||
34 | #include <gnunet-fuse.h> | ||
35 | #include <gnunet/gnunet_fs_service.h> | ||
36 | #include <gnunet/gnunet_container_lib.h> | ||
37 | #include "gnunet/gnunet_crypto_lib.h" | ||
38 | #include <fuse.h> | ||
39 | |||
40 | static int ret; | ||
41 | |||
42 | static int verbose; | ||
43 | |||
44 | static int delete_incomplete; | ||
45 | |||
46 | static struct GNUNET_FS_DownloadContext *dc; | ||
47 | |||
48 | static unsigned int parallelism = 16; | ||
49 | |||
50 | static unsigned int request_parallelism = 4092; | ||
51 | |||
52 | static int do_recursive; | ||
53 | |||
54 | static int local_only; | ||
55 | |||
56 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
57 | |||
58 | static unsigned int anonymity = 1; | ||
59 | |||
60 | struct GNUNET_FS_Handle *fs; | ||
61 | |||
62 | static struct GNUNET_FS_Handle *ctx; | ||
63 | |||
64 | struct GNUNET_CONTAINER_MultiHashMap *map; | ||
65 | |||
66 | struct GNUNET_FS_Uri *uri; | ||
67 | |||
68 | char *emsg; | ||
69 | |||
70 | struct GNUNET_FUSE_path_info *r; | ||
71 | |||
72 | |||
73 | |||
74 | |||
75 | static void | ||
76 | cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
77 | { | ||
78 | GNUNET_FS_stop (ctx); | ||
79 | ctx = NULL; | ||
80 | } | ||
81 | |||
82 | static void | ||
83 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
84 | { | ||
85 | struct GNUNET_FS_DownloadContext *d; | ||
86 | |||
87 | if (dc != NULL) | ||
88 | { | ||
89 | d = dc; | ||
90 | dc = NULL; | ||
91 | GNUNET_FS_download_stop (d, delete_incomplete); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | /* callback function */ | ||
97 | void *progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo * info) | ||
98 | { | ||
99 | |||
100 | char *s; | ||
101 | char*s2; | ||
102 | char *t; | ||
103 | |||
104 | switch (info->status) | ||
105 | { | ||
106 | case GNUNET_FS_STATUS_DOWNLOAD_START: | ||
107 | if (verbose > 1) | ||
108 | FPRINTF (stderr, _("Starting download `%s'.\n"), | ||
109 | info->value.download.filename); | ||
110 | break; | ||
111 | case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS: | ||
112 | if (verbose) | ||
113 | { | ||
114 | s = GNUNET_STRINGS_relative_time_to_string (info->value.download.eta); | ||
115 | if (info->value.download.specifics.progress.block_download_duration.rel_value | ||
116 | == GNUNET_TIME_UNIT_FOREVER_REL.rel_value) | ||
117 | s2 = GNUNET_strdup (_("<unknown time>")); | ||
118 | else | ||
119 | s2 = GNUNET_STRINGS_relative_time_to_string ( | ||
120 | info->value.download.specifics.progress.block_download_duration); | ||
121 | t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * | ||
122 | 1000LL / | ||
123 | (info->value.download. | ||
124 | duration.rel_value + 1)); | ||
125 | FPRINTF (stdout, | ||
126 | _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"), | ||
127 | info->value.download.filename, | ||
128 | (unsigned long long) info->value.download.completed, | ||
129 | (unsigned long long) info->value.download.size, s, t, s2); | ||
130 | GNUNET_free (s); | ||
131 | GNUNET_free (s2); | ||
132 | GNUNET_free (t); | ||
133 | } | ||
134 | break; | ||
135 | case GNUNET_FS_STATUS_DOWNLOAD_ERROR: | ||
136 | FPRINTF (stderr, _("Error downloading: %s.\n"), | ||
137 | info->value.download.specifics.error.message); | ||
138 | GNUNET_SCHEDULER_shutdown (); | ||
139 | break; | ||
140 | case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED: | ||
141 | s = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000 / | ||
142 | (info->value.download. | ||
143 | duration.rel_value + 1)); | ||
144 | FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"), | ||
145 | info->value.download.filename, s); | ||
146 | GNUNET_free (s); | ||
147 | if (info->value.download.dc == dc) | ||
148 | GNUNET_SCHEDULER_shutdown (); | ||
149 | break; | ||
150 | case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: | ||
151 | if (info->value.download.dc == dc) | ||
152 | GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL, | ||
153 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
154 | break; | ||
155 | case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE: | ||
156 | case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE: | ||
157 | break; | ||
158 | default: | ||
159 | FPRINTF (stderr, _("Unexpected status: %d\n"), info->status); | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | |||
167 | void readdir_task (void *cls, | ||
168 | const struct GNUNET_SCHEDULER_TaskContext* tc) | ||
169 | { | ||
170 | enum GNUNET_FS_DownloadOptions options; | ||
171 | |||
172 | if (NULL == uri) | ||
173 | { | ||
174 | FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg); | ||
175 | GNUNET_free (emsg); | ||
176 | GNUNET_FS_stop (ctx); // ?? hmmm....stop before start ?? | ||
177 | } | ||
178 | |||
179 | |||
180 | fs = GNUNET_FS_start (cfg, "gnunet-fuse", &progress_cb, NULL, | ||
181 | GNUNET_FS_FLAGS_NONE, | ||
182 | GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, parallelism, | ||
183 | GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, request_parallelism, | ||
184 | GNUNET_FS_OPTIONS_END); | ||
185 | |||
186 | if (NULL == fs) | ||
187 | { | ||
188 | FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS"); | ||
189 | GNUNET_FS_uri_destroy (uri); | ||
190 | ret = 1; | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | options = GNUNET_FS_DOWNLOAD_OPTION_NONE; | ||
195 | if (do_recursive) | ||
196 | options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE; | ||
197 | if (local_only) | ||
198 | options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY; | ||
199 | |||
200 | struct GNUNET_FS_DownloadContext* dc; | ||
201 | dc = GNUNET_FS_download_start (fs, uri, NULL, r->tmpfile, NULL, 0, | ||
202 | GNUNET_FS_uri_chk_get_file_size(uri), | ||
203 | anonymity, options, NULL, NULL); | ||
204 | |||
205 | GNUNET_FS_uri_destroy (uri); | ||
206 | if (dc == NULL) | ||
207 | { | ||
208 | GNUNET_FS_stop (ctx); | ||
209 | ctx = NULL; | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); | ||
214 | |||
215 | } | ||
216 | |||
217 | |||
218 | int gn_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | ||
219 | off_t offset, struct fuse_file_info *fi) | ||
220 | { | ||
221 | struct GNUNET_FUSE_path_info * path_info = NULL; | ||
222 | printf("FUSE PATH gives me: `%s'\n", path); | ||
223 | (void) fi; | ||
224 | (void) offset; | ||
225 | |||
226 | GNUNET_HashCode path_hash; | ||
227 | GNUNET_CRYPTO_hash (path, strlen (path), &path_hash); | ||
228 | /* NOTE: Path can be like /.Trash/1000/files for the trash directory */ | ||
229 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(map, &path_hash)) | ||
230 | { | ||
231 | /* new path */ | ||
232 | //path_info = create_path_info (path, NULL); | ||
233 | //GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(map, &path_hash, path_info, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | /* existing path */ | ||
238 | path_info = GNUNET_CONTAINER_multihashmap_get (map, &path_hash); | ||
239 | } | ||
240 | |||
241 | //GNUNET_assert (path_info != NULL); | ||
242 | |||
243 | #if 0 | ||
244 | r = GNUNET_malloc (sizeof (struct GNUNET_FUSE_path_info)); | ||
245 | |||
246 | int len = strlen(path); | ||
247 | int exist = 0; | ||
248 | r->path = path; | ||
249 | |||
250 | /* compute key */ | ||
251 | |||
252 | GNUNET_CRYPTO_hash (r->path, len, r->hash); | ||
253 | |||
254 | |||
255 | exist = GNUNET_CONTAINER_multihashmap_contains (map, r->hash); | ||
256 | if ( exist == GNUNET_NO) | ||
257 | { | ||
258 | |||
259 | |||
260 | /* Store a key-value pair in the map */ | ||
261 | GNUNET_CONTAINER_multihashmap_put (map, r->hash, r->path, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
262 | |||
263 | /* store to temporary file */ | ||
264 | r->tmpfile = GNUNET_DISK_mktemp("gnunet-fuse-tempfile"); | ||
265 | |||
266 | /* find value with given key */ | ||
267 | r->source = GNUNET_CONTAINER_multihashmap_get (map, r->hash); | ||
268 | |||
269 | /* parse uri from given source */ | ||
270 | uri = GNUNET_FS_uri_parse(r->source, &emsg); | ||
271 | GNUNET_SCHEDULER_run(&readdir_task, NULL); | ||
272 | |||
273 | filler(buf, ".", NULL, 0); | ||
274 | filler(buf, "..", NULL, 0); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | else | ||
280 | { | ||
281 | uri = GNUNET_FS_uri_parse(r->source, &emsg); | ||
282 | GNUNET_SCHEDULER_run(&readdir_task, NULL); | ||
283 | |||
284 | filler(buf, ".", NULL, 0); | ||
285 | filler(buf, "..", NULL, 0); | ||
286 | return 0; | ||
287 | } | ||
288 | #endif | ||
289 | |||
290 | filler(buf, ".", NULL, 0); | ||
291 | filler(buf, "..", NULL, 0); | ||
292 | return 0; | ||
293 | } | ||