2 * This is sample code generated by rpcgen.
3 * These are only templates and you can use them
4 * as a guideline for developing your own functions.
12 /* Check that a string is a valid file name. We require that it be valid
13 * UTF-8, that it not be empty, and that it not contain embedded forward
14 * slashes. Also checks that the length of the string is not more than the
15 * maximum allowed length. This function does allow the names "." and "..".
16 * Returns TRUE if the string is allowed as a filename. */
17 gboolean validate_filename(const char *filename)
19 if (filename == NULL || filename[0] == '\0')
21 if (strlen(filename) > 255)
23 if (!g_utf8_validate(filename, -1, NULL))
25 if (strchr(filename, '/') != NULL)
30 /* Arrange for a reference to an inode to be dropped when the RPC request
32 void schedule_inode_unref(RPCRequest *req, BlueSkyInode *inode)
34 struct cleanup_list *c = g_new(struct cleanup_list, 1);
35 c->func = (void (*)(void *))bluesky_inode_unref;
37 c->next = req->cleanup;
41 /* Look up a BlueSkyInode given an NFS filehandle. Returns NULL if the
42 * filehandle is invalid. */
43 BlueSkyInode *lookup_fh(RPCRequest *req, nfs_fh3 *fh)
45 BlueSkyInode *inode = NULL;
46 if (fh->data.data_len == 8) {
47 uint64_t inum = GUINT64_FROM_BE(*(uint64_t *)(fh->data.data_val));
48 inode = bluesky_get_inode(fs, inum);
50 schedule_inode_unref(req, inode);
55 int64_t decode_nfstime3(nfstime3 *time)
57 int64_t result = (int64_t)time->seconds * 1000000;
58 result += time->nseconds / 1000;
62 void set_attributes(BlueSkyInode *inode, sattr3 *attributes)
64 int64_t now = bluesky_get_current_time();
66 if (attributes->mode.set) {
67 inode->mode = attributes->mode.set_uint32_u.val;
70 if (attributes->uid.set) {
71 inode->uid = attributes->uid.set_uint32_u.val;
74 if (attributes->gid.set) {
75 inode->gid = attributes->gid.set_uint32_u.val;
78 if (attributes->size.set) {
79 if (inode->type == BLUESKY_REGULAR) {
80 bluesky_file_truncate(inode, attributes->size.set_uint64_u.val);
85 switch (attributes->atime.set) {
88 case SET_TO_SERVER_TIME:
91 case SET_TO_CLIENT_TIME:
92 inode->atime = decode_nfstime3(&attributes->atime.set_time_u.time);
96 switch (attributes->mtime.set) {
99 case SET_TO_SERVER_TIME:
102 case SET_TO_CLIENT_TIME:
103 inode->mtime = decode_nfstime3(&attributes->mtime.set_time_u.time);
107 bluesky_inode_update_ctime(inode, FALSE);
110 /* Copy inode attributes into NFS response. The BlueSkyInode should be locked
112 void encode_fattr3(struct fattr3 *result, BlueSkyInode *inode)
114 result->type = inode->type;
115 result->mode = inode->mode;
116 result->nlink = inode->nlink;
117 result->uid = inode->uid;
118 result->gid = inode->gid;
119 result->size = inode->size;
121 result->rdev.major = 0;
122 result->rdev.minor = 0;
124 result->fileid = inode->inum;
125 result->atime.seconds = inode->atime / 1000000;
126 result->atime.nseconds = (inode->atime % 1000000) * 1000;
127 result->mtime.seconds = inode->mtime / 1000000;
128 result->mtime.nseconds = (inode->mtime % 1000000) * 1000;
129 result->ctime.seconds = inode->ctime / 1000000;
130 result->ctime.nseconds = (inode->ctime % 1000000) * 1000;
132 switch (inode->type) {
133 case BLUESKY_SYMLINK:
134 result->size = strlen(inode->symlink_contents);
141 void encode_pre_wcc(struct wcc_data *wcc, BlueSkyInode *inode)
143 wcc->before.present = TRUE;
144 wcc->before.pre_op_attr_u.attributes.size = inode->size;
145 wcc->before.pre_op_attr_u.attributes.mtime.seconds = inode->mtime / 1000000;
146 wcc->before.pre_op_attr_u.attributes.mtime.nseconds = (inode->mtime % 1000000) * 1000;
147 wcc->before.pre_op_attr_u.attributes.ctime.seconds = inode->ctime / 1000000;
148 wcc->before.pre_op_attr_u.attributes.ctime.nseconds = (inode->ctime % 1000000) * 1000;
151 void nfsproc3_null_3_svc(void *argp, RPCRequest *req)
153 async_rpc_send_reply(req, NULL);
156 void nfsproc3_getattr_3_svc(nfs_fh3 *argp, RPCRequest *req)
159 memset(&result, 0, sizeof(result));
161 BlueSkyInode *inode = lookup_fh(req, argp);
163 result.status = NFS3_OK;
164 g_mutex_lock(inode->lock);
165 encode_fattr3(&result.getattr3res_u.attributes, inode);
166 g_mutex_unlock(inode->lock);
168 result.status = NFS3ERR_STALE;
171 async_rpc_send_reply(req, &result);
174 void nfsproc3_setattr_3_svc(setattr3args *argp, RPCRequest *req)
177 memset(&result, 0, sizeof(result));
179 result.wccstat3_u.wcc.before.present = FALSE;
180 result.wccstat3_u.wcc.after.present = FALSE;
181 BlueSkyInode *inode = lookup_fh(req, &argp->object);
183 result.status = NFS3ERR_STALE;
184 async_rpc_send_reply(req, &result);
188 g_mutex_lock(inode->lock);
189 encode_pre_wcc(&result.wccstat3_u.wcc, inode);
190 if (argp->guard.check) {
191 if (inode->ctime != decode_nfstime3(&argp->guard.sattrguard3_u.ctime)) {
192 result.status = NFS3ERR_NOT_SYNC;
193 result.wccstat3_u.wcc.after.present = TRUE;
194 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes, inode);
195 g_mutex_unlock(inode->lock);
196 async_rpc_send_reply(req, &result);
201 set_attributes(inode, &argp->new_attributes);
203 result.wccstat3_u.wcc.after.present = TRUE;
204 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
206 result.status = NFS3_OK;
208 g_mutex_unlock(inode->lock);
209 async_rpc_send_reply(req, &result);
212 void nfsproc3_lookup_3_svc(diropargs3 *argp, RPCRequest *req)
215 memset(&result, 0, sizeof(result));
217 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
219 result.status = NFS3ERR_STALE;
220 result.lookup3res_u.resfail.present = FALSE;
221 async_rpc_send_reply(req, &result);
225 g_mutex_lock(dir->lock);
226 result.lookup3res_u.resfail.present = TRUE;
227 encode_fattr3(&result.lookup3res_u.resfail.post_op_attr_u.attributes, dir);
228 if (!validate_filename(argp->name)) {
229 if (strlen(argp->name) > 255)
230 result.status = NFS3ERR_NAMETOOLONG;
232 result.status = NFS3ERR_NOENT;
233 g_mutex_unlock(dir->lock);
234 async_rpc_send_reply(req, &result);
238 /* TODO: Special-case "." and "..". */
239 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
241 result.status = NFS3ERR_NOENT;
242 g_mutex_unlock(dir->lock);
243 async_rpc_send_reply(req, &result);
247 result.lookup3res_u.resok.dir_attributes.present = TRUE;
248 encode_fattr3(&result.lookup3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
249 g_mutex_unlock(dir->lock);
251 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
253 result.status = NFS3ERR_NOENT;
254 async_rpc_send_reply(req, &result);
257 g_mutex_lock(inode->lock);
258 schedule_inode_unref(req, inode);
260 result.status = NFS3_OK;
261 result.lookup3res_u.resok.obj_attributes.present = TRUE;
262 encode_fattr3(&result.lookup3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
265 fh_bytes = GUINT64_TO_BE(inum);
266 result.lookup3res_u.resok.object.data.data_len = 8;
267 result.lookup3res_u.resok.object.data.data_val = (char *)&fh_bytes;
269 g_mutex_unlock(inode->lock);
270 async_rpc_send_reply(req, &result);
273 void nfsproc3_access_3_svc(access3args *argp, RPCRequest *req)
276 memset(&result, 0, sizeof(result));
278 BlueSkyInode *inode = lookup_fh(req, &argp->object);
280 result.status = NFS3ERR_STALE;
281 result.access3res_u.resfail.present = FALSE;
282 async_rpc_send_reply(req, &result);
286 g_mutex_lock(inode->lock);
287 result.status = NFS3_OK;
288 result.access3res_u.resok.obj_attributes.present = TRUE;
289 encode_fattr3(&result.access3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
290 result.access3res_u.resok.access = argp->access;
291 g_mutex_unlock(inode->lock);
293 async_rpc_send_reply(req, &result);
296 void nfsproc3_readlink_3_svc(nfs_fh3 *argp, RPCRequest *req)
299 memset(&result, 0, sizeof(result));
301 BlueSkyInode *inode = lookup_fh(req, argp);
303 g_mutex_lock(inode->lock);
304 if (inode->type == BLUESKY_SYMLINK) {
305 result.status = NFS3_OK;
306 result.readlink3res_u.resok.symlink_attributes.present = TRUE;
307 encode_fattr3(&result.readlink3res_u.resok.symlink_attributes.post_op_attr_u.attributes, inode);
308 result.readlink3res_u.resok.data = inode->symlink_contents;
310 result.status = NFS3ERR_INVAL;
311 result.readlink3res_u.resfail.present = TRUE;
312 encode_fattr3(&result.readlink3res_u.resfail.post_op_attr_u.attributes, inode);
314 g_mutex_unlock(inode->lock);
316 result.status = NFS3ERR_STALE;
319 async_rpc_send_reply(req, &result);
322 void nfsproc3_read_3_svc(read3args *argp, RPCRequest *req)
325 memset(&result, 0, sizeof(result));
328 BlueSkyInode *inode = lookup_fh(req, &argp->file);
330 result.status = NFS3ERR_STALE;
331 result.read3res_u.resfail.present = FALSE;
332 async_rpc_send_reply(req, &result);
336 g_mutex_lock(inode->lock);
338 int count = argp->count;
339 if (argp->offset >= inode->size) {
341 result.read3res_u.resok.eof = TRUE;
343 count = MIN(count, inode->size - argp->offset);
344 if (argp->offset + count == inode->size)
345 result.read3res_u.resok.eof = TRUE;
347 result.read3res_u.resok.eof = FALSE;
349 bluesky_file_read(inode, argp->offset, buf, count);
352 result.status = NFS3_OK;
353 result.read3res_u.resok.file_attributes.present = TRUE;
354 encode_fattr3(&result.read3res_u.resok.file_attributes.post_op_attr_u.attributes, inode);
355 result.read3res_u.resok.count = count;
356 result.read3res_u.resok.data.data_val = buf;
357 result.read3res_u.resok.data.data_len = count;
359 g_mutex_unlock(inode->lock);
361 async_rpc_send_reply(req, &result);
364 void nfsproc3_write_3_svc(write3args *argp, RPCRequest *req)
367 memset(&result, 0, sizeof(result));
369 memset(&wcc, 0, sizeof(wcc));
371 BlueSkyInode *inode = lookup_fh(req, &argp->file);
373 result.status = NFS3ERR_STALE;
374 result.write3res_u.resfail = wcc;
375 async_rpc_send_reply(req, &result);
379 g_mutex_lock(inode->lock);
381 encode_pre_wcc(&wcc, inode);
382 if (inode->type != BLUESKY_REGULAR) {
383 result.status = NFS3ERR_INVAL;
384 result.write3res_u.resfail = wcc;
385 g_mutex_unlock(inode->lock);
386 async_rpc_send_reply(req, &result);
390 uint64_t lastbyte = argp->offset + argp->count;
391 if (lastbyte > inode->size) {
392 bluesky_file_truncate(inode, lastbyte);
395 if (argp->data.data_len < argp->count) {
398 bluesky_file_write(inode, argp->offset,
399 argp->data.data_val, argp->count);
402 wcc.after.present = TRUE;
403 encode_fattr3(&wcc.after.post_op_attr_u.attributes, inode);
404 result.write3res_u.resok.file_wcc = wcc;
405 result.write3res_u.resok.count = argp->count;
406 result.write3res_u.resok.committed = FILE_SYNC;
408 g_mutex_unlock(inode->lock);
410 async_rpc_send_reply(req, &result);
413 void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
416 memset(&result, 0, sizeof(result));
418 memset(&wcc, 0, sizeof(wcc));
420 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
422 result.status = NFS3ERR_STALE;
423 result.diropres3_u.resfail = wcc;
424 async_rpc_send_reply(req, &result);
428 g_mutex_lock(dir->lock);
430 encode_pre_wcc(&wcc, dir);
431 if (dir->type != BLUESKY_DIRECTORY) {
432 result.status = NFS3ERR_NOTDIR;
433 result.diropres3_u.resfail = wcc;
434 g_mutex_unlock(dir->lock);
435 async_rpc_send_reply(req, &result);
439 if (!validate_filename(argp->where.name)
440 || strcmp(argp->where.name, ".") == 0
441 || strcmp(argp->where.name, "..") == 0)
443 result.status = NFS3ERR_EXIST;
444 result.diropres3_u.resfail = wcc;
445 g_mutex_unlock(dir->lock);
446 async_rpc_send_reply(req, &result);
451 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
454 int64_t time = bluesky_get_current_time();
455 printf("time: %"PRIi64"\n", time);
460 g_mutex_lock(file->lock);
461 bluesky_insert_inode(fs, file);
462 bluesky_directory_insert(dir, argp->where.name, file->inum);
464 bluesky_inode_update_ctime(dir, TRUE);
466 wcc.after.present = TRUE;
467 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
468 result.diropres3_u.resok.obj_attributes.present = TRUE;
469 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
470 result.diropres3_u.resok.dir_wcc = wcc;
473 fh_bytes = GUINT64_TO_BE(file->inum);
474 result.diropres3_u.resok.obj.present = TRUE;
475 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
476 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
478 g_mutex_unlock(file->lock);
479 g_mutex_unlock(dir->lock);
481 async_rpc_send_reply(req, &result);
484 void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
487 memset(&result, 0, sizeof(result));
489 memset(&wcc, 0, sizeof(wcc));
491 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
493 result.status = NFS3ERR_STALE;
494 result.diropres3_u.resfail = wcc;
495 async_rpc_send_reply(req, &result);
499 g_mutex_lock(dir->lock);
501 encode_pre_wcc(&wcc, dir);
502 if (dir->type != BLUESKY_DIRECTORY) {
503 result.status = NFS3ERR_NOTDIR;
504 result.diropres3_u.resfail = wcc;
505 g_mutex_unlock(dir->lock);
506 async_rpc_send_reply(req, &result);
510 if (!validate_filename(argp->where.name)
511 || strcmp(argp->where.name, ".") == 0
512 || strcmp(argp->where.name, "..") == 0)
514 result.status = NFS3ERR_EXIST;
515 result.diropres3_u.resfail = wcc;
516 g_mutex_unlock(dir->lock);
517 async_rpc_send_reply(req, &result);
522 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_DIRECTORY);
525 int64_t time = bluesky_get_current_time();
530 g_mutex_lock(file->lock);
531 bluesky_insert_inode(fs, file);
532 bluesky_directory_insert(dir, argp->where.name, file->inum);
533 set_attributes(file, &argp->attributes);
535 bluesky_inode_update_ctime(dir, TRUE);
537 wcc.after.present = TRUE;
538 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
539 result.diropres3_u.resok.obj_attributes.present = TRUE;
540 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
541 result.diropres3_u.resok.dir_wcc = wcc;
544 fh_bytes = GUINT64_TO_BE(file->inum);
545 result.diropres3_u.resok.obj.present = TRUE;
546 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
547 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
549 g_mutex_unlock(file->lock);
550 g_mutex_unlock(dir->lock);
551 async_rpc_send_reply(req, &result);
554 void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
557 memset(&result, 0, sizeof(result));
559 memset(&wcc, 0, sizeof(wcc));
561 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
563 result.status = NFS3ERR_STALE;
564 result.diropres3_u.resfail = wcc;
565 async_rpc_send_reply(req, &result);
568 g_mutex_lock(dir->lock);
570 encode_pre_wcc(&wcc, dir);
571 if (dir->type != BLUESKY_DIRECTORY) {
572 result.status = NFS3ERR_NOTDIR;
573 result.diropres3_u.resfail = wcc;
574 g_mutex_unlock(dir->lock);
575 async_rpc_send_reply(req, &result);
579 if (!validate_filename(argp->where.name)
580 || strcmp(argp->where.name, ".") == 0
581 || strcmp(argp->where.name, "..") == 0)
583 result.status = NFS3ERR_EXIST;
584 result.diropres3_u.resfail = wcc;
585 g_mutex_unlock(dir->lock);
586 async_rpc_send_reply(req, &result);
591 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
594 int64_t time = bluesky_get_current_time();
599 file->symlink_contents = g_strdup(argp->symlink.symlink_data);
600 g_mutex_lock(file->lock);
601 bluesky_insert_inode(fs, file);
602 bluesky_directory_insert(dir, argp->where.name, file->inum);
604 bluesky_inode_update_ctime(dir, TRUE);
606 wcc.after.present = TRUE;
607 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
608 result.diropres3_u.resok.obj_attributes.present = TRUE;
609 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
610 result.diropres3_u.resok.dir_wcc = wcc;
613 fh_bytes = GUINT64_TO_BE(file->inum);
614 result.diropres3_u.resok.obj.present = TRUE;
615 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
616 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
618 g_mutex_unlock(file->lock);
619 g_mutex_unlock(dir->lock);
620 async_rpc_send_reply(req, &result);
623 void nfsproc3_mknod_3_svc(mknod3args *argp, RPCRequest *req)
626 memset(&result, 0, sizeof(result));
628 result.status = NFS3ERR_NOTSUPP;
630 async_rpc_send_reply(req, &result);
633 void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
636 memset(&result, 0, sizeof(result));
638 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
640 result.status = NFS3ERR_STALE;
641 async_rpc_send_reply(req, &result);
645 g_mutex_lock(dir->lock);
647 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
649 if (!validate_filename(argp->name)
650 || strcmp(argp->name, ".") == 0
651 || strcmp(argp->name, "..") == 0)
653 result.status = NFS3ERR_NOENT;
654 g_mutex_unlock(dir->lock);
655 async_rpc_send_reply(req, &result);
659 /* TODO: Decrement link count, deallocate inode if needed. */
661 bluesky_directory_remove(dir, argp->name);
663 result.status = NFS3_OK;
664 result.wccstat3_u.wcc.after.present = TRUE;
665 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
668 g_mutex_unlock(dir->lock);
669 async_rpc_send_reply(req, &result);
672 void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
675 memset(&result, 0, sizeof(result));
677 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
679 result.status = NFS3ERR_STALE;
680 async_rpc_send_reply(req, &result);
684 g_mutex_lock(dir->lock);
686 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
688 if (!validate_filename(argp->name)
689 || strcmp(argp->name, ".") == 0
690 || strcmp(argp->name, "..") == 0)
692 result.status = NFS3ERR_NOENT;
693 g_mutex_unlock(dir->lock);
694 async_rpc_send_reply(req, &result);
698 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
699 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
701 result.status = NFS3ERR_NOENT;
702 g_mutex_unlock(dir->lock);
703 async_rpc_send_reply(req, &result);
706 g_mutex_lock(inode->lock);
707 schedule_inode_unref(req, inode);
709 if (inode->type != BLUESKY_DIRECTORY) {
710 result.status = NFS3ERR_NOTDIR;
711 g_mutex_unlock(inode->lock);
712 g_mutex_unlock(dir->lock);
713 async_rpc_send_reply(req, &result);
716 if (g_sequence_get_length(inode->dirents) > 0) {
717 printf("Directory not empty: %d entries\n",
718 g_sequence_get_length(inode->dirents));
719 result.status = NFS3ERR_NOTEMPTY;
720 g_mutex_unlock(inode->lock);
721 g_mutex_unlock(dir->lock);
722 async_rpc_send_reply(req, &result);
726 /* TODO: Decrement link count, deallocate inode if needed. */
728 bluesky_directory_remove(dir, argp->name);
730 result.status = NFS3_OK;
731 result.wccstat3_u.wcc.after.present = TRUE;
732 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
735 g_mutex_unlock(inode->lock);
736 g_mutex_unlock(dir->lock);
737 async_rpc_send_reply(req, &result);
740 void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
743 memset(&result, 0, sizeof(result));
744 wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
745 wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
747 BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
749 result.status = NFS3ERR_STALE;
750 async_rpc_send_reply(req, &result);
753 g_mutex_lock(dir1->lock);
754 encode_pre_wcc(wcc1, dir1);
756 BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
758 result.status = NFS3ERR_STALE;
759 g_mutex_unlock(dir1->lock);
760 async_rpc_send_reply(req, &result);
763 g_mutex_lock(dir2->lock);
764 encode_pre_wcc(wcc2, dir1);
766 gboolean status = bluesky_rename(dir1, argp->from.name,
770 wcc1->after.present = TRUE;
771 encode_fattr3(&wcc1->after.post_op_attr_u.attributes, dir1);
772 wcc2->after.present = TRUE;
773 encode_fattr3(&wcc2->after.post_op_attr_u.attributes, dir2);
775 result.status = NFS3_OK;
777 result.status = NFS3ERR_PERM;
779 g_mutex_unlock(dir2->lock);
780 g_mutex_unlock(dir1->lock);
781 async_rpc_send_reply(req, &result);
784 void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
787 memset(&result, 0, sizeof(result));
789 memset(&wcc, 0, sizeof(wcc));
791 BlueSkyInode *inode = lookup_fh(req, &argp->file);
793 result.status = NFS3ERR_STALE;
794 result.link3res_u.res.linkdir_wcc = wcc;
795 async_rpc_send_reply(req, &result);
798 g_mutex_lock(inode->lock);
800 BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
802 result.status = NFS3ERR_STALE;
803 result.link3res_u.res.linkdir_wcc = wcc;
804 g_mutex_unlock(inode->lock);
805 async_rpc_send_reply(req, &result);
808 g_mutex_lock(dir->lock);
810 encode_pre_wcc(&wcc, dir);
811 if (dir->type != BLUESKY_DIRECTORY) {
812 result.status = NFS3ERR_NOTDIR;
813 result.link3res_u.res.linkdir_wcc = wcc;
814 g_mutex_unlock(inode->lock);
815 g_mutex_unlock(dir->lock);
816 async_rpc_send_reply(req, &result);
820 if (!validate_filename(argp->link.name)
821 || strcmp(argp->link.name, ".") == 0
822 || strcmp(argp->link.name, "..") == 0
823 || bluesky_directory_lookup(dir, argp->link.name) != 0)
825 result.status = NFS3ERR_EXIST;
826 result.link3res_u.res.linkdir_wcc = wcc;
827 g_mutex_unlock(inode->lock);
828 g_mutex_unlock(dir->lock);
829 async_rpc_send_reply(req, &result);
833 if (!bluesky_directory_insert(dir, argp->link.name, inode->inum)) {
834 result.status = NFS3ERR_EXIST;
835 result.link3res_u.res.linkdir_wcc = wcc;
836 g_mutex_unlock(inode->lock);
837 g_mutex_unlock(dir->lock);
838 async_rpc_send_reply(req, &result);
842 bluesky_inode_update_ctime(inode, FALSE);
843 bluesky_inode_update_ctime(dir, TRUE);
845 result.status = NFS3_OK;
846 wcc.after.present = TRUE;
847 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
848 result.link3res_u.res.file_attributes.present = TRUE;
849 encode_fattr3(&result.link3res_u.res.file_attributes.post_op_attr_u.attributes, inode);
850 result.link3res_u.res.linkdir_wcc = wcc;
852 g_mutex_unlock(inode->lock);
853 g_mutex_unlock(dir->lock);
854 async_rpc_send_reply(req, &result);
857 gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
860 #define MAX_READDIR_DIRENTS 64
861 void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
864 memset(&result, 0, sizeof(result));
866 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
868 result.status = NFS3ERR_STALE;
869 result.readdir3res_u.resfail.present = FALSE;
870 async_rpc_send_reply(req, &result);
873 g_mutex_lock(dir->lock);
875 result.status = NFS3_OK;
876 result.readdir3res_u.resok.dir_attributes.present = TRUE;
877 encode_fattr3(&result.readdir3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
878 memset(result.readdir3res_u.resok.cookieverf, 0,
879 sizeof(result.readdir3res_u.resok.cookieverf));
881 entry3 dirents[MAX_READDIR_DIRENTS];
884 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
885 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
886 bluesky_dirent_compare, NULL);
888 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
889 BlueSkyDirent *d = g_sequence_get(i);
890 dirents[count].fileid = d->inum;
891 dirents[count].name = d->name;
892 dirents[count].cookie = d->cookie;
893 dirents[count].nextentry = NULL;
895 dirents[count - 1].nextentry = &dirents[count];
896 i = g_sequence_iter_next(i);
901 result.readdir3res_u.resok.reply.entries = &dirents[0];
903 result.readdir3res_u.resok.reply.entries = NULL;
904 result.readdir3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
906 g_mutex_unlock(dir->lock);
907 async_rpc_send_reply(req, &result);
910 void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
912 /* XDR-encoded sizes:
913 * post_op_attr: 88 bytes
914 * base readdirplus3resok: 88 + 16 bytes
915 * base directory entry: 24 bytes + filename
916 * attributes/fh3: 88 + 8 + filehandle size
918 size_t dircount = 88 + 16, attrcount = 0;
919 readdirplus3res result;
920 memset(&result, 0, sizeof(result));
922 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
924 result.status = NFS3ERR_STALE;
925 result.readdirplus3res_u.resfail.present = FALSE;
926 async_rpc_send_reply(req, &result);
929 g_mutex_lock(dir->lock);
931 result.status = NFS3_OK;
932 result.readdirplus3res_u.resok.dir_attributes.present = TRUE;
933 encode_fattr3(&result.readdirplus3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
934 memset(result.readdirplus3res_u.resok.cookieverf, 0,
935 sizeof(result.readdirplus3res_u.resok.cookieverf));
937 entryplus3 dirents[MAX_READDIR_DIRENTS];
938 uint64_t fh_bytes[MAX_READDIR_DIRENTS];
942 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
944 /* Perform a prefetch pass on inodes: for all the inodes we think we will
945 * return information about, try to load each one but don't wait. This
946 * should let multiple inodes be fetched in parallel, instead of
947 * sequentially in the loop that follows. */
948 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
949 while (count < MAX_READDIR_DIRENTS
950 && !g_sequence_iter_is_end(i)
951 && dircount <= argp->dircount
952 && dircount + attrcount <= argp->maxcount)
954 BlueSkyDirent *d = g_sequence_get(i);
955 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
957 bluesky_inode_unref(inode);
958 dircount += 24 + ((strlen(d->name) + 3) & ~3);
959 attrcount += 88 + 8 + 8;
960 i = g_sequence_iter_next(i);
963 i = g_sequence_search(dir->dirents, &start, bluesky_dirent_compare, NULL);
967 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
968 BlueSkyDirent *d = g_sequence_get(i);
969 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
970 g_mutex_lock(inode->lock);
972 dircount += 24 + ((strlen(d->name) + 3) & ~3);
973 attrcount += 88 + 8 + 8;
974 if (dircount > argp->dircount
975 || dircount + attrcount > argp->maxcount)
977 g_mutex_unlock(inode->lock);
978 bluesky_inode_unref(inode);
981 dirents[count].fileid = d->inum;
982 dirents[count].name = d->name;
983 dirents[count].cookie = d->cookie;
984 dirents[count].nextentry = NULL;
985 dirents[count].name_attributes.present = TRUE;
986 encode_fattr3(&dirents[count].name_attributes.post_op_attr_u.attributes, inode);
987 fh_bytes[count] = GUINT64_TO_BE(d->inum);
988 dirents[count].name_handle.present = TRUE;
989 dirents[count].name_handle.post_op_fh3_u.handle.data.data_len = 8;
990 dirents[count].name_handle.post_op_fh3_u.handle.data.data_val
991 = (char *)&fh_bytes[count];
993 dirents[count - 1].nextentry = &dirents[count];
995 g_mutex_unlock(inode->lock);
996 bluesky_inode_unref(inode);
998 i = g_sequence_iter_next(i);
1002 result.readdirplus3res_u.resok.reply.entries = &dirents[0];
1004 result.readdirplus3res_u.resok.reply.entries = NULL;
1005 result.readdirplus3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
1007 g_mutex_unlock(dir->lock);
1008 async_rpc_send_reply(req, &result);
1011 void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
1014 memset(&result, 0, sizeof(result));
1016 BlueSkyInode *inode = lookup_fh(req, argp);
1017 if (inode == NULL) {
1018 result.status = NFS3ERR_STALE;
1019 result.fsstat3res_u.resfail.present = FALSE;
1020 async_rpc_send_reply(req, &result);
1023 g_mutex_lock(inode->lock);
1025 result.status = NFS3_OK;
1026 result.fsstat3res_u.resok.obj_attributes.present = TRUE;
1027 encode_fattr3(&result.fsstat3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1029 result.fsstat3res_u.resok.tbytes = (1 << 30);
1030 result.fsstat3res_u.resok.fbytes = (1 << 30);
1031 result.fsstat3res_u.resok.abytes = (1 << 30);
1032 result.fsstat3res_u.resok.tfiles = 0;
1033 result.fsstat3res_u.resok.ffiles = 0;
1034 result.fsstat3res_u.resok.afiles = 0;
1035 result.fsstat3res_u.resok.invarsec = 0;
1037 g_mutex_unlock(inode->lock);
1038 async_rpc_send_reply(req, &result);
1041 void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
1044 memset(&result, 0, sizeof(result));
1046 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1047 g_mutex_lock(inode->lock);
1048 result.status = NFS3_OK;
1049 result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
1050 encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1051 result.fsinfo3res_u.resok.rtmax = 32768;
1052 result.fsinfo3res_u.resok.rtpref = 32768;
1053 result.fsinfo3res_u.resok.rtmult = 4096;
1054 result.fsinfo3res_u.resok.wtmax = 32768;
1055 result.fsinfo3res_u.resok.wtpref = 32768;
1056 result.fsinfo3res_u.resok.wtmult = 4096;
1057 result.fsinfo3res_u.resok.dtpref = 4096;
1058 result.fsinfo3res_u.resok.maxfilesize = 0x7fffffffffffffffULL;
1059 result.fsinfo3res_u.resok.time_delta.seconds = 0;
1060 result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
1061 result.fsinfo3res_u.resok.properties
1062 = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
1064 g_mutex_unlock(inode->lock);
1065 bluesky_inode_unref(inode);
1066 async_rpc_send_reply(req, &result);
1069 void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
1071 pathconf3res result;
1072 memset(&result, 0, sizeof(result));
1074 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1075 g_mutex_lock(inode->lock);
1076 result.status = NFS3_OK;
1077 result.pathconf3res_u.resok.obj_attributes.present = TRUE;
1078 encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1079 result.pathconf3res_u.resok.linkmax = 0xffffffff;
1080 result.pathconf3res_u.resok.name_max = 255;
1081 result.pathconf3res_u.resok.no_trunc = TRUE;
1082 result.pathconf3res_u.resok.chown_restricted = TRUE;
1083 result.pathconf3res_u.resok.case_insensitive = FALSE;
1084 result.pathconf3res_u.resok.case_preserving = TRUE;
1086 g_mutex_unlock(inode->lock);
1087 bluesky_inode_unref(inode);
1088 async_rpc_send_reply(req, &result);
1091 void nfsproc3_commit_3_svc(commit3args *argp, RPCRequest *req)
1094 memset(&result, 0, sizeof(result));
1096 result.status = NFS3ERR_NOTSUPP;
1098 BlueSkyInode *inode = lookup_fh(req, &argp->file);
1099 if (inode == NULL) {
1100 result.status = NFS3ERR_STALE;
1101 async_rpc_send_reply(req, &result);
1105 g_mutex_lock(inode->lock);
1106 encode_pre_wcc(&result.commit3res_u.resok.file_wcc, inode);
1108 bluesky_inode_do_sync(inode);
1110 result.commit3res_u.resok.file_wcc.after.present = TRUE;
1111 encode_fattr3(&result.commit3res_u.resok.file_wcc.after.post_op_attr_u.attributes, inode);
1113 g_mutex_unlock(inode->lock);
1115 async_rpc_send_reply(req, &result);