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);
246 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
248 result.status = NFS3ERR_NOENT;
249 g_mutex_unlock(dir->lock);
250 async_rpc_send_reply(req, &result);
253 g_mutex_lock(inode->lock);
254 schedule_inode_unref(req, inode);
256 result.status = NFS3_OK;
257 result.lookup3res_u.resok.dir_attributes.present = TRUE;
258 encode_fattr3(&result.lookup3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
259 result.lookup3res_u.resok.obj_attributes.present = TRUE;
260 encode_fattr3(&result.lookup3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
263 fh_bytes = GUINT64_TO_BE(inum);
264 result.lookup3res_u.resok.object.data.data_len = 8;
265 result.lookup3res_u.resok.object.data.data_val = (char *)&fh_bytes;
267 g_mutex_unlock(inode->lock);
268 g_mutex_unlock(dir->lock);
269 async_rpc_send_reply(req, &result);
272 void nfsproc3_access_3_svc(access3args *argp, RPCRequest *req)
275 memset(&result, 0, sizeof(result));
277 BlueSkyInode *inode = lookup_fh(req, &argp->object);
279 result.status = NFS3ERR_STALE;
280 result.access3res_u.resfail.present = FALSE;
281 async_rpc_send_reply(req, &result);
285 g_mutex_lock(inode->lock);
286 result.status = NFS3_OK;
287 result.access3res_u.resok.obj_attributes.present = TRUE;
288 encode_fattr3(&result.access3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
289 result.access3res_u.resok.access = argp->access;
290 g_mutex_unlock(inode->lock);
292 async_rpc_send_reply(req, &result);
295 void nfsproc3_readlink_3_svc(nfs_fh3 *argp, RPCRequest *req)
298 memset(&result, 0, sizeof(result));
300 BlueSkyInode *inode = lookup_fh(req, argp);
302 g_mutex_lock(inode->lock);
303 if (inode->type == BLUESKY_SYMLINK) {
304 result.status = NFS3_OK;
305 result.readlink3res_u.resok.symlink_attributes.present = TRUE;
306 encode_fattr3(&result.readlink3res_u.resok.symlink_attributes.post_op_attr_u.attributes, inode);
307 result.readlink3res_u.resok.data = inode->symlink_contents;
309 result.status = NFS3ERR_INVAL;
310 result.readlink3res_u.resfail.present = TRUE;
311 encode_fattr3(&result.readlink3res_u.resfail.post_op_attr_u.attributes, inode);
313 g_mutex_unlock(inode->lock);
315 result.status = NFS3ERR_STALE;
318 async_rpc_send_reply(req, &result);
321 void nfsproc3_read_3_svc(read3args *argp, RPCRequest *req)
324 memset(&result, 0, sizeof(result));
327 BlueSkyInode *inode = lookup_fh(req, &argp->file);
329 result.status = NFS3ERR_STALE;
330 result.read3res_u.resfail.present = FALSE;
331 async_rpc_send_reply(req, &result);
335 g_mutex_lock(inode->lock);
337 int count = argp->count;
338 if (argp->offset >= inode->size) {
340 result.read3res_u.resok.eof = TRUE;
342 count = MIN(count, inode->size - argp->offset);
343 if (argp->offset + count == inode->size)
344 result.read3res_u.resok.eof = TRUE;
346 result.read3res_u.resok.eof = FALSE;
348 bluesky_file_read(inode, argp->offset, buf, count);
351 result.status = NFS3_OK;
352 result.read3res_u.resok.file_attributes.present = TRUE;
353 encode_fattr3(&result.read3res_u.resok.file_attributes.post_op_attr_u.attributes, inode);
354 result.read3res_u.resok.count = count;
355 result.read3res_u.resok.data.data_val = buf;
356 result.read3res_u.resok.data.data_len = count;
358 g_mutex_unlock(inode->lock);
360 async_rpc_send_reply(req, &result);
363 void nfsproc3_write_3_svc(write3args *argp, RPCRequest *req)
366 memset(&result, 0, sizeof(result));
368 memset(&wcc, 0, sizeof(wcc));
370 BlueSkyInode *inode = lookup_fh(req, &argp->file);
372 result.status = NFS3ERR_STALE;
373 result.write3res_u.resfail = wcc;
374 async_rpc_send_reply(req, &result);
378 g_mutex_lock(inode->lock);
380 encode_pre_wcc(&wcc, inode);
381 if (inode->type != BLUESKY_REGULAR) {
382 result.status = NFS3ERR_INVAL;
383 result.write3res_u.resfail = wcc;
384 g_mutex_unlock(inode->lock);
385 async_rpc_send_reply(req, &result);
389 uint64_t lastbyte = argp->offset + argp->count;
390 if (lastbyte > inode->size) {
391 bluesky_file_truncate(inode, lastbyte);
394 if (argp->data.data_len < argp->count) {
397 bluesky_file_write(inode, argp->offset,
398 argp->data.data_val, argp->count);
401 wcc.after.present = TRUE;
402 encode_fattr3(&wcc.after.post_op_attr_u.attributes, inode);
403 result.write3res_u.resok.file_wcc = wcc;
404 result.write3res_u.resok.count = argp->count;
405 result.write3res_u.resok.committed = FILE_SYNC;
407 g_mutex_unlock(inode->lock);
409 async_rpc_send_reply(req, &result);
412 void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
415 memset(&result, 0, sizeof(result));
417 memset(&wcc, 0, sizeof(wcc));
419 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
421 result.status = NFS3ERR_STALE;
422 result.diropres3_u.resfail = wcc;
423 async_rpc_send_reply(req, &result);
427 g_mutex_lock(dir->lock);
429 encode_pre_wcc(&wcc, dir);
430 if (dir->type != BLUESKY_DIRECTORY) {
431 result.status = NFS3ERR_NOTDIR;
432 result.diropres3_u.resfail = wcc;
433 g_mutex_unlock(dir->lock);
434 async_rpc_send_reply(req, &result);
438 if (!validate_filename(argp->where.name)
439 || strcmp(argp->where.name, ".") == 0
440 || strcmp(argp->where.name, "..") == 0)
442 result.status = NFS3ERR_EXIST;
443 result.diropres3_u.resfail = wcc;
444 g_mutex_unlock(dir->lock);
445 async_rpc_send_reply(req, &result);
450 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_REGULAR);
453 int64_t time = bluesky_get_current_time();
454 printf("time: %"PRIi64"\n", time);
459 g_mutex_lock(file->lock);
460 bluesky_insert_inode(fs, file);
461 bluesky_directory_insert(dir, argp->where.name, file->inum);
463 bluesky_inode_update_ctime(dir, TRUE);
465 wcc.after.present = TRUE;
466 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
467 result.diropres3_u.resok.obj_attributes.present = TRUE;
468 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
469 result.diropres3_u.resok.dir_wcc = wcc;
472 fh_bytes = GUINT64_TO_BE(file->inum);
473 result.diropres3_u.resok.obj.present = TRUE;
474 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
475 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
477 g_mutex_unlock(file->lock);
478 g_mutex_unlock(dir->lock);
480 async_rpc_send_reply(req, &result);
483 void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
486 memset(&result, 0, sizeof(result));
488 memset(&wcc, 0, sizeof(wcc));
490 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
492 result.status = NFS3ERR_STALE;
493 result.diropres3_u.resfail = wcc;
494 async_rpc_send_reply(req, &result);
498 g_mutex_lock(dir->lock);
500 encode_pre_wcc(&wcc, dir);
501 if (dir->type != BLUESKY_DIRECTORY) {
502 result.status = NFS3ERR_NOTDIR;
503 result.diropres3_u.resfail = wcc;
504 g_mutex_unlock(dir->lock);
505 async_rpc_send_reply(req, &result);
509 if (!validate_filename(argp->where.name)
510 || strcmp(argp->where.name, ".") == 0
511 || strcmp(argp->where.name, "..") == 0)
513 result.status = NFS3ERR_EXIST;
514 result.diropres3_u.resfail = wcc;
515 g_mutex_unlock(dir->lock);
516 async_rpc_send_reply(req, &result);
521 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_DIRECTORY);
524 int64_t time = bluesky_get_current_time();
529 g_mutex_lock(file->lock);
530 bluesky_insert_inode(fs, file);
531 bluesky_directory_insert(dir, argp->where.name, file->inum);
532 set_attributes(file, &argp->attributes);
534 bluesky_inode_update_ctime(dir, TRUE);
536 wcc.after.present = TRUE;
537 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
538 result.diropres3_u.resok.obj_attributes.present = TRUE;
539 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
540 result.diropres3_u.resok.dir_wcc = wcc;
543 fh_bytes = GUINT64_TO_BE(file->inum);
544 result.diropres3_u.resok.obj.present = TRUE;
545 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
546 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
548 g_mutex_unlock(file->lock);
549 g_mutex_unlock(dir->lock);
550 async_rpc_send_reply(req, &result);
553 void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
556 memset(&result, 0, sizeof(result));
558 memset(&wcc, 0, sizeof(wcc));
560 BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
562 result.status = NFS3ERR_STALE;
563 result.diropres3_u.resfail = wcc;
564 async_rpc_send_reply(req, &result);
567 g_mutex_lock(dir->lock);
569 encode_pre_wcc(&wcc, dir);
570 if (dir->type != BLUESKY_DIRECTORY) {
571 result.status = NFS3ERR_NOTDIR;
572 result.diropres3_u.resfail = wcc;
573 g_mutex_unlock(dir->lock);
574 async_rpc_send_reply(req, &result);
578 if (!validate_filename(argp->where.name)
579 || strcmp(argp->where.name, ".") == 0
580 || strcmp(argp->where.name, "..") == 0)
582 result.status = NFS3ERR_EXIST;
583 result.diropres3_u.resfail = wcc;
584 g_mutex_unlock(dir->lock);
585 async_rpc_send_reply(req, &result);
590 file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
593 int64_t time = bluesky_get_current_time();
598 file->symlink_contents = g_strdup(argp->symlink.symlink_data);
599 g_mutex_lock(file->lock);
600 bluesky_insert_inode(fs, file);
601 bluesky_directory_insert(dir, argp->where.name, file->inum);
603 bluesky_inode_update_ctime(dir, TRUE);
605 wcc.after.present = TRUE;
606 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
607 result.diropres3_u.resok.obj_attributes.present = TRUE;
608 encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
609 result.diropres3_u.resok.dir_wcc = wcc;
612 fh_bytes = GUINT64_TO_BE(file->inum);
613 result.diropres3_u.resok.obj.present = TRUE;
614 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
615 result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
617 g_mutex_unlock(file->lock);
618 g_mutex_unlock(dir->lock);
619 async_rpc_send_reply(req, &result);
622 void nfsproc3_mknod_3_svc(mknod3args *argp, RPCRequest *req)
625 memset(&result, 0, sizeof(result));
627 result.status = NFS3ERR_NOTSUPP;
629 async_rpc_send_reply(req, &result);
632 void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
635 memset(&result, 0, sizeof(result));
637 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
639 result.status = NFS3ERR_STALE;
640 async_rpc_send_reply(req, &result);
644 g_mutex_lock(dir->lock);
646 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
648 if (!validate_filename(argp->name)
649 || strcmp(argp->name, ".") == 0
650 || strcmp(argp->name, "..") == 0)
652 result.status = NFS3ERR_NOENT;
653 g_mutex_unlock(dir->lock);
654 async_rpc_send_reply(req, &result);
658 /* TODO: Decrement link count, deallocate inode if needed. */
660 bluesky_directory_remove(dir, argp->name);
662 result.status = NFS3_OK;
663 result.wccstat3_u.wcc.after.present = TRUE;
664 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
667 g_mutex_unlock(dir->lock);
668 async_rpc_send_reply(req, &result);
671 void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
674 memset(&result, 0, sizeof(result));
676 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
678 result.status = NFS3ERR_STALE;
679 async_rpc_send_reply(req, &result);
683 g_mutex_lock(dir->lock);
685 encode_pre_wcc(&result.wccstat3_u.wcc, dir);
687 if (!validate_filename(argp->name)
688 || strcmp(argp->name, ".") == 0
689 || strcmp(argp->name, "..") == 0)
691 result.status = NFS3ERR_NOENT;
692 g_mutex_unlock(dir->lock);
693 async_rpc_send_reply(req, &result);
697 uint64_t inum = bluesky_directory_lookup(dir, argp->name);
698 BlueSkyInode *inode = bluesky_get_inode(fs, inum);
700 result.status = NFS3ERR_NOENT;
701 g_mutex_unlock(dir->lock);
702 async_rpc_send_reply(req, &result);
705 g_mutex_lock(inode->lock);
706 schedule_inode_unref(req, inode);
708 if (inode->type != BLUESKY_DIRECTORY) {
709 result.status = NFS3ERR_NOTDIR;
710 g_mutex_unlock(inode->lock);
711 g_mutex_unlock(dir->lock);
712 async_rpc_send_reply(req, &result);
715 if (g_sequence_get_length(inode->dirents) > 0) {
716 printf("Directory not empty: %d entries\n",
717 g_sequence_get_length(inode->dirents));
718 result.status = NFS3ERR_NOTEMPTY;
719 g_mutex_unlock(inode->lock);
720 g_mutex_unlock(dir->lock);
721 async_rpc_send_reply(req, &result);
725 /* TODO: Decrement link count, deallocate inode if needed. */
727 bluesky_directory_remove(dir, argp->name);
729 result.status = NFS3_OK;
730 result.wccstat3_u.wcc.after.present = TRUE;
731 encode_fattr3(&result.wccstat3_u.wcc.after.post_op_attr_u.attributes,
734 g_mutex_unlock(inode->lock);
735 g_mutex_unlock(dir->lock);
736 async_rpc_send_reply(req, &result);
739 void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
742 memset(&result, 0, sizeof(result));
743 wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
744 wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
746 BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
748 result.status = NFS3ERR_STALE;
749 async_rpc_send_reply(req, &result);
752 g_mutex_lock(dir1->lock);
753 encode_pre_wcc(wcc1, dir1);
755 BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
757 result.status = NFS3ERR_STALE;
758 g_mutex_unlock(dir1->lock);
759 async_rpc_send_reply(req, &result);
762 g_mutex_lock(dir2->lock);
763 encode_pre_wcc(wcc2, dir1);
765 gboolean status = bluesky_rename(dir1, argp->from.name,
769 wcc1->after.present = TRUE;
770 encode_fattr3(&wcc1->after.post_op_attr_u.attributes, dir1);
771 wcc2->after.present = TRUE;
772 encode_fattr3(&wcc2->after.post_op_attr_u.attributes, dir2);
774 result.status = NFS3_OK;
776 result.status = NFS3ERR_PERM;
778 g_mutex_unlock(dir2->lock);
779 g_mutex_unlock(dir1->lock);
780 async_rpc_send_reply(req, &result);
783 void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
786 memset(&result, 0, sizeof(result));
788 memset(&wcc, 0, sizeof(wcc));
790 BlueSkyInode *inode = lookup_fh(req, &argp->file);
792 result.status = NFS3ERR_STALE;
793 result.link3res_u.res.linkdir_wcc = wcc;
794 async_rpc_send_reply(req, &result);
797 g_mutex_lock(inode->lock);
799 BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
801 result.status = NFS3ERR_STALE;
802 result.link3res_u.res.linkdir_wcc = wcc;
803 g_mutex_unlock(inode->lock);
804 async_rpc_send_reply(req, &result);
807 g_mutex_lock(dir->lock);
809 encode_pre_wcc(&wcc, dir);
810 if (dir->type != BLUESKY_DIRECTORY) {
811 result.status = NFS3ERR_NOTDIR;
812 result.link3res_u.res.linkdir_wcc = wcc;
813 g_mutex_unlock(inode->lock);
814 g_mutex_unlock(dir->lock);
815 async_rpc_send_reply(req, &result);
819 if (!validate_filename(argp->link.name)
820 || strcmp(argp->link.name, ".") == 0
821 || strcmp(argp->link.name, "..") == 0
822 || bluesky_directory_lookup(dir, argp->link.name) != 0)
824 result.status = NFS3ERR_EXIST;
825 result.link3res_u.res.linkdir_wcc = wcc;
826 g_mutex_unlock(inode->lock);
827 g_mutex_unlock(dir->lock);
828 async_rpc_send_reply(req, &result);
832 if (!bluesky_directory_insert(dir, argp->link.name, inode->inum)) {
833 result.status = NFS3ERR_EXIST;
834 result.link3res_u.res.linkdir_wcc = wcc;
835 g_mutex_unlock(inode->lock);
836 g_mutex_unlock(dir->lock);
837 async_rpc_send_reply(req, &result);
841 bluesky_inode_update_ctime(inode, FALSE);
842 bluesky_inode_update_ctime(dir, TRUE);
844 result.status = NFS3_OK;
845 wcc.after.present = TRUE;
846 encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
847 result.link3res_u.res.file_attributes.present = TRUE;
848 encode_fattr3(&result.link3res_u.res.file_attributes.post_op_attr_u.attributes, inode);
849 result.link3res_u.res.linkdir_wcc = wcc;
851 g_mutex_unlock(inode->lock);
852 g_mutex_unlock(dir->lock);
853 async_rpc_send_reply(req, &result);
856 gint bluesky_dirent_compare(gconstpointer a, gconstpointer b,
859 #define MAX_READDIR_DIRENTS 64
860 void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
863 memset(&result, 0, sizeof(result));
865 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
867 result.status = NFS3ERR_STALE;
868 result.readdir3res_u.resfail.present = FALSE;
869 async_rpc_send_reply(req, &result);
872 g_mutex_lock(dir->lock);
874 result.status = NFS3_OK;
875 result.readdir3res_u.resok.dir_attributes.present = TRUE;
876 encode_fattr3(&result.readdir3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
877 memset(result.readdir3res_u.resok.cookieverf, 0,
878 sizeof(result.readdir3res_u.resok.cookieverf));
880 entry3 dirents[MAX_READDIR_DIRENTS];
883 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
884 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
885 bluesky_dirent_compare, NULL);
887 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
888 BlueSkyDirent *d = g_sequence_get(i);
889 dirents[count].fileid = d->inum;
890 dirents[count].name = d->name;
891 dirents[count].cookie = d->cookie;
892 dirents[count].nextentry = NULL;
894 dirents[count - 1].nextentry = &dirents[count];
895 i = g_sequence_iter_next(i);
900 result.readdir3res_u.resok.reply.entries = &dirents[0];
902 result.readdir3res_u.resok.reply.entries = NULL;
903 result.readdir3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
905 g_mutex_unlock(dir->lock);
906 async_rpc_send_reply(req, &result);
909 void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
911 /* XDR-encoded sizes:
912 * post_op_attr: 88 bytes
913 * base readdirplus3resok: 88 + 16 bytes
914 * base directory entry: 24 bytes + filename
915 * attributes/fh3: 88 + 8 + filehandle size
917 size_t dircount = 88 + 16, attrcount = 0;
918 readdirplus3res result;
919 memset(&result, 0, sizeof(result));
921 BlueSkyInode *dir = lookup_fh(req, &argp->dir);
923 result.status = NFS3ERR_STALE;
924 result.readdirplus3res_u.resfail.present = FALSE;
925 async_rpc_send_reply(req, &result);
928 g_mutex_lock(dir->lock);
930 result.status = NFS3_OK;
931 result.readdirplus3res_u.resok.dir_attributes.present = TRUE;
932 encode_fattr3(&result.readdirplus3res_u.resok.dir_attributes.post_op_attr_u.attributes, dir);
933 memset(result.readdirplus3res_u.resok.cookieverf, 0,
934 sizeof(result.readdirplus3res_u.resok.cookieverf));
936 entryplus3 dirents[MAX_READDIR_DIRENTS];
937 uint64_t fh_bytes[MAX_READDIR_DIRENTS];
940 /* TODO: Handle dircount, maxcount arguments from client. */
942 BlueSkyDirent start = {NULL, NULL, argp->cookie, 0};
943 GSequenceIter *i = g_sequence_search(dir->dirents, &start,
944 bluesky_dirent_compare, NULL);
946 while (count < MAX_READDIR_DIRENTS && !g_sequence_iter_is_end(i)) {
947 BlueSkyDirent *d = g_sequence_get(i);
948 BlueSkyInode *inode = bluesky_get_inode(fs, d->inum);
949 g_mutex_lock(inode->lock);
951 dircount += 24 + ((strlen(d->name) + 3) & ~3);
952 attrcount += 88 + 8 + 8;
953 if (dircount > argp->dircount
954 || dircount + attrcount > argp->maxcount)
956 g_mutex_unlock(inode->lock);
957 bluesky_inode_unref(inode);
960 dirents[count].fileid = d->inum;
961 dirents[count].name = d->name;
962 dirents[count].cookie = d->cookie;
963 dirents[count].nextentry = NULL;
964 dirents[count].name_attributes.present = TRUE;
965 encode_fattr3(&dirents[count].name_attributes.post_op_attr_u.attributes, inode);
966 fh_bytes[count] = GUINT64_TO_BE(d->inum);
967 dirents[count].name_handle.present = TRUE;
968 dirents[count].name_handle.post_op_fh3_u.handle.data.data_len = 8;
969 dirents[count].name_handle.post_op_fh3_u.handle.data.data_val
970 = (char *)&fh_bytes[count];
972 dirents[count - 1].nextentry = &dirents[count];
974 g_mutex_unlock(inode->lock);
975 bluesky_inode_unref(inode);
977 i = g_sequence_iter_next(i);
981 result.readdirplus3res_u.resok.reply.entries = &dirents[0];
983 result.readdirplus3res_u.resok.reply.entries = NULL;
984 result.readdirplus3res_u.resok.reply.eof = g_sequence_iter_is_end(i);
986 g_mutex_unlock(dir->lock);
987 async_rpc_send_reply(req, &result);
990 void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
993 memset(&result, 0, sizeof(result));
995 BlueSkyInode *inode = lookup_fh(req, argp);
997 result.status = NFS3ERR_STALE;
998 result.fsstat3res_u.resfail.present = FALSE;
999 async_rpc_send_reply(req, &result);
1002 g_mutex_lock(inode->lock);
1004 result.status = NFS3_OK;
1005 result.fsstat3res_u.resok.obj_attributes.present = TRUE;
1006 encode_fattr3(&result.fsstat3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1008 result.fsstat3res_u.resok.tbytes = (1 << 30);
1009 result.fsstat3res_u.resok.fbytes = (1 << 30);
1010 result.fsstat3res_u.resok.abytes = (1 << 30);
1011 result.fsstat3res_u.resok.tfiles = 0;
1012 result.fsstat3res_u.resok.ffiles = 0;
1013 result.fsstat3res_u.resok.afiles = 0;
1014 result.fsstat3res_u.resok.invarsec = 0;
1016 g_mutex_unlock(inode->lock);
1017 async_rpc_send_reply(req, &result);
1020 void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
1023 memset(&result, 0, sizeof(result));
1025 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1026 g_mutex_lock(inode->lock);
1027 result.status = NFS3_OK;
1028 result.fsinfo3res_u.resok.obj_attributes.present = TRUE;
1029 encode_fattr3(&result.fsinfo3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1030 result.fsinfo3res_u.resok.rtmax = 32768;
1031 result.fsinfo3res_u.resok.rtpref = 32768;
1032 result.fsinfo3res_u.resok.rtmult = 4096;
1033 result.fsinfo3res_u.resok.wtmax = 32768;
1034 result.fsinfo3res_u.resok.wtpref = 32768;
1035 result.fsinfo3res_u.resok.wtmult = 4096;
1036 result.fsinfo3res_u.resok.dtpref = 4096;
1037 result.fsinfo3res_u.resok.maxfilesize = 0x7fffffffffffffffULL;
1038 result.fsinfo3res_u.resok.time_delta.seconds = 0;
1039 result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
1040 result.fsinfo3res_u.resok.properties
1041 = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
1043 g_mutex_unlock(inode->lock);
1044 bluesky_inode_unref(inode);
1045 async_rpc_send_reply(req, &result);
1048 void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
1050 pathconf3res result;
1051 memset(&result, 0, sizeof(result));
1053 BlueSkyInode *inode = bluesky_get_inode(fs, 1);
1054 g_mutex_lock(inode->lock);
1055 result.status = NFS3_OK;
1056 result.pathconf3res_u.resok.obj_attributes.present = TRUE;
1057 encode_fattr3(&result.pathconf3res_u.resok.obj_attributes.post_op_attr_u.attributes, inode);
1058 result.pathconf3res_u.resok.linkmax = 0xffffffff;
1059 result.pathconf3res_u.resok.name_max = 255;
1060 result.pathconf3res_u.resok.no_trunc = TRUE;
1061 result.pathconf3res_u.resok.chown_restricted = TRUE;
1062 result.pathconf3res_u.resok.case_insensitive = FALSE;
1063 result.pathconf3res_u.resok.case_preserving = TRUE;
1065 g_mutex_unlock(inode->lock);
1066 bluesky_inode_unref(inode);
1067 async_rpc_send_reply(req, &result);
1070 void nfsproc3_commit_3_svc(commit3args *argp, RPCRequest *req)
1073 memset(&result, 0, sizeof(result));
1075 result.status = NFS3ERR_NOTSUPP;
1077 async_rpc_send_reply(req, &result);