274 error: |
276 error: |
275 if ((err = fuse_reply_err(req, err))) |
277 if ((err = fuse_reply_err(req, err))) |
276 EWARNING(err, "fuse_reply_err"); |
278 EWARNING(err, "fuse_reply_err"); |
277 } |
279 } |
278 |
280 |
|
281 struct dbfs_dirop { |
|
282 struct fuse_file_info *fi; |
|
283 struct fuse_req *req; |
|
284 |
|
285 struct evsql_trans *trans; |
|
286 |
|
287 // opendir has returned and releasedir hasn't been called yet |
|
288 int open; |
|
289 }; |
|
290 |
|
291 /* |
|
292 * Free the dirop, aborting any in-progress transaction. |
|
293 * |
|
294 * req must be NULL. |
|
295 */ |
|
296 static void dbfs_dirop_free (struct dbfs_dirop *dirop) { |
|
297 assert(dirop->req == NULL); |
|
298 |
|
299 if (dirop->trans) |
|
300 evsql_trans_abort(dirop->trans); |
|
301 |
|
302 free(dirop); |
|
303 } |
|
304 |
|
305 /* |
|
306 * The opendir transaction is ready |
|
307 */ |
|
308 static void dbfs_dirop_ready (struct evsql_trans *trans, void *arg) { |
|
309 struct dbfs_dirop *dirop = arg; |
|
310 struct fuse_req *req = dirop->req; dirop->req = NULL; |
|
311 int err; |
|
312 |
|
313 INFO("[dbfs.openddir %p:%p] -> trans=%p", dirop, req, trans); |
|
314 |
|
315 // remember the transaction |
|
316 dirop->trans = trans; |
|
317 |
|
318 // send the openddir reply |
|
319 if ((err = fuse_reply_open(dirop->req, dirop->fi))) |
|
320 EERROR(err, "fuse_reply_open"); |
|
321 |
|
322 // dirop is now open |
|
323 dirop->open = 1; |
|
324 |
|
325 // ok, wait for the next fs req |
|
326 return; |
|
327 |
|
328 error: |
|
329 dbfs_dirop_free(dirop); |
|
330 |
|
331 if ((err = fuse_reply_err(req, err))) |
|
332 EWARNING(err, "fuse_reply_err"); |
|
333 } |
|
334 |
|
335 static void dbfs_dirop_done (struct evsql_trans *trans, void *arg) { |
|
336 struct dbfs_dirop *dirop = arg; |
|
337 int err; |
|
338 |
|
339 |
|
340 } |
|
341 |
|
342 static void dbfs_dirop_error (struct evsql_trans *trans, void *arg) { |
|
343 struct dbfs_dirop *dirop = arg; |
|
344 int err; |
|
345 |
|
346 INFO("[dbfs:dirop %p:%p] evsql transaction error: %s", dirop, dirop->req, evsql_trans_error(trans)); |
|
347 |
|
348 // deassociate the trans |
|
349 dirop->trans = NULL; |
|
350 |
|
351 // error out and pending req |
|
352 if (dirop->req) { |
|
353 if ((err = fuse_reply_err(dirop->req, EIO))) |
|
354 EWARNING(err, "fuse_erply_err"); |
|
355 |
|
356 dirop->req = NULL; |
|
357 |
|
358 // only free the dirop if it isn't open |
|
359 if (!dirop->open) |
|
360 dbfs_dirop_free(dirop); |
|
361 } |
|
362 } |
|
363 |
|
364 static void dbfs_opendir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { |
|
365 struct dbfs *ctx = fuse_req_userdata(req); |
|
366 struct dbfs_dirop *dirop = NULL; |
|
367 int err; |
|
368 |
|
369 // allocate it |
|
370 if ((dirop = calloc(1, sizeof(*dirop))) == NULL && (err = EIO)) |
|
371 ERROR("calloc"); |
|
372 |
|
373 INFO("[dbfs.opendir %p:%p] ino=%lu, fi=%p", dirop, req, ino, fi); |
|
374 |
|
375 // store the dirop |
|
376 fi->fh = (uint64_t) dirop; |
|
377 dirop->req = req; |
|
378 dirop->fi = fi; |
|
379 |
|
380 // start a new transaction |
|
381 if (evsql_trans(ctx->db, EVSQL_TRANS_SERIALIZABLE, dbfs_dirop_error, dbfs_dirop_ready, dbfs_dirop_done, dirop)) |
|
382 SERROR(err = EIO); |
|
383 |
|
384 // XXX: handle interrupts |
|
385 |
|
386 // wait |
|
387 return; |
|
388 |
|
389 error: |
|
390 // we handle the req |
|
391 dirop->req = NULL; |
|
392 |
|
393 dbfs_dirop_free(dirop); |
|
394 |
|
395 if ((err = fuse_reply_err(req, err))) |
|
396 EWARNING(err, "fuse_reply_err"); |
|
397 } |
|
398 |
|
399 static void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { |
|
400 struct dbfs *ctx = fuse_req_userdata(req); |
|
401 struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh; |
|
402 int err; |
|
403 |
|
404 INFO("[dbfs.readdir %p:%p] ino=%lu, size=%zu, off=%zu, fi=%p : trans=%p", dirop, req, ino, size, off, fi, dirop->trans); |
|
405 |
|
406 // update dirop |
|
407 dirop->req = req; |
|
408 assert(dirop->fi == fi); |
|
409 |
|
410 // select all relevant file entries |
|
411 const char *sql = |
|
412 "SELECT" |
|
413 " \"file_tree.offset\", file_tree.name, inodes.ino, inodes.type" |
|
414 " FROM file_tree LEFT OUTER JOIN inodes ON (file_tree.inode = inodes.ino)" |
|
415 " WHERE file_tree.parent = $1::int4 AND \"file_tree.offset\" >= $2::int4" |
|
416 " LIMIT $3::int4"; |
|
417 |
|
418 static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { |
|
419 EVSQL_PARAM ( UINT32 ), |
|
420 EVSQL_PARAM ( UINT32 ), |
|
421 EVSQL_PARAM ( UINT32 ), |
|
422 |
|
423 EVSQL_PARAMS_END |
|
424 }; |
|
425 |
|
426 // XXX: incomplete |
|
427 } |
|
428 |
|
429 static void dbfs_releasedir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { |
|
430 struct dbfs *ctx = fuse_req_userdata(req); |
|
431 struct dbfs_dirop *dirop = (struct dbfs_dirop *) fi->fh; |
|
432 int err; |
|
433 |
|
434 (void) ctx; |
|
435 |
|
436 INFO("[dbfs.releasedir %p:%p] ino=%lu, fi=%p : trans=%p", dirop, req, ino, fi, dirop->trans); |
|
437 |
|
438 // update dirop. Must keep it open so that dbfs_dirop_error won't free it |
|
439 dirop->req = req; |
|
440 assert(dirop->fi == fi); |
|
441 |
|
442 // we can commit the transaction, although we didn't make any changes |
|
443 // if this fails the transaction, then dbfs_dirop_error will take care of sending the error, and dirop->req will be |
|
444 // NULL |
|
445 if (evsql_trans_commit(dirop->trans)) |
|
446 SERROR(err = EIO); |
|
447 |
|
448 // not open anymore |
|
449 dirop->open = 0; |
|
450 |
|
451 // XXX: handle interrupts |
|
452 |
|
453 // wait |
|
454 return; |
|
455 |
|
456 error: |
|
457 if (dirop->req) { |
|
458 // we handle the req |
|
459 dirop->req = NULL; |
|
460 |
|
461 dbfs_dirop_free(dirop); |
|
462 |
|
463 if ((err = fuse_reply_err(req, err))) |
|
464 EWARNING(err, "fuse_reply_err"); |
|
465 } |
|
466 } |
|
467 |
279 struct fuse_lowlevel_ops dbfs_llops = { |
468 struct fuse_lowlevel_ops dbfs_llops = { |
280 |
469 |
281 .init = dbfs_init, |
470 .init = dbfs_init, |
282 .destroy = dbfs_destroy, |
471 .destroy = dbfs_destroy, |
283 |
472 |
284 .lookup = dbfs_lookup, |
473 .lookup = dbfs_lookup, |
285 |
474 |
286 .getattr = dbfs_getattr, |
475 .getattr = dbfs_getattr, |
|
476 |
|
477 .opendir = dbfs_opendir, |
|
478 .releasedir = dbfs_releasedir, |
287 }; |
479 }; |
288 |
480 |
289 void dbfs_sql_error (struct evsql *evsql, void *arg) { |
481 void dbfs_sql_error (struct evsql *evsql, void *arg) { |
290 struct dbfs *ctx = arg; |
482 struct dbfs *ctx = arg; |
291 |
483 |