2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * High level api to nfs filesystems
25 #include <sys/types.h>
27 #include <sys/statvfs.h>
33 #include "libnfs-raw.h"
34 #include "libnfs-raw-mount.h"
35 #include "libnfs-raw-nfs.h"
46 static void wait_for_reply(struct nfs_context
*nfs
, struct sync_cb_data
*cb_data
)
51 if (cb_data
->is_finished
) {
54 pfd
.fd
= nfs_get_fd(nfs
);
55 pfd
.events
= nfs_which_events(nfs
);
57 if (poll(&pfd
, 1, -1) < 0) {
58 printf("Poll failed");
59 cb_data
->status
= -EIO
;
62 if (nfs_service(nfs
, pfd
.revents
) < 0) {
63 printf("nfs_service failed\n");
64 cb_data
->status
= -EIO
;
76 * connect to the server and mount the export
78 static void mount_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
80 struct sync_cb_data
*cb_data
= private_data
;
82 cb_data
->is_finished
= 1;
83 cb_data
->status
= status
;
86 printf("mount/mnt call failed with \"%s\"\n", (char *)data
);
91 int nfs_mount_sync(struct nfs_context
*nfs
, const char *server
, const char *export
)
93 struct sync_cb_data cb_data
;
95 cb_data
.is_finished
= 0;
97 if (nfs_mount_async(nfs
, server
, export
, mount_cb
, &cb_data
) != 0) {
98 printf("nfs_mount_async failed\n");
102 wait_for_reply(nfs
, &cb_data
);
104 return cb_data
.status
;
111 static void stat_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
113 struct sync_cb_data
*cb_data
= private_data
;
115 cb_data
->is_finished
= 1;
116 cb_data
->status
= status
;
119 printf("stat call failed with \"%s\"\n", (char *)data
);
123 memcpy(cb_data
->return_data
, data
, sizeof(struct stat
));
126 int nfs_stat_sync(struct nfs_context
*nfs
, const char *path
, struct stat
*st
)
128 struct sync_cb_data cb_data
;
130 cb_data
.is_finished
= 0;
131 cb_data
.return_data
= st
;
133 if (nfs_stat_async(nfs
, path
, stat_cb
, &cb_data
) != 0) {
134 printf("nfs_stat_async failed\n");
138 wait_for_reply(nfs
, &cb_data
);
140 return cb_data
.status
;
149 static void open_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
151 struct sync_cb_data
*cb_data
= private_data
;
152 struct nfsfh
*fh
, **nfsfh
;
154 cb_data
->is_finished
= 1;
155 cb_data
->status
= status
;
158 printf("open call failed with \"%s\"\n", (char *)data
);
163 nfsfh
= cb_data
->return_data
;
167 int nfs_open_sync(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
169 struct sync_cb_data cb_data
;
171 cb_data
.is_finished
= 0;
172 cb_data
.return_data
= nfsfh
;
174 if (nfs_open_async(nfs
, path
, mode
, open_cb
, &cb_data
) != 0) {
175 printf("nfs_open_async failed\n");
179 wait_for_reply(nfs
, &cb_data
);
181 return cb_data
.status
;
190 static void pread_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
192 struct sync_cb_data
*cb_data
= private_data
;
194 cb_data
->is_finished
= 1;
195 cb_data
->status
= status
;
198 printf("pread call failed with \"%s\"\n", (char *)data
);
202 buffer
= cb_data
->return_data
;
203 memcpy(buffer
, (char *)data
, status
);
206 int nfs_pread_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buffer
)
208 struct sync_cb_data cb_data
;
210 cb_data
.is_finished
= 0;
211 cb_data
.return_data
= buffer
;
213 if (nfs_pread_async(nfs
, nfsfh
, offset
, count
, pread_cb
, &cb_data
) != 0) {
214 printf("nfs_pread_async failed\n");
218 wait_for_reply(nfs
, &cb_data
);
220 return cb_data
.status
;
226 int nfs_read_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buffer
)
228 return nfs_pread_sync(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buffer
);
234 static void close_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
236 struct sync_cb_data
*cb_data
= private_data
;
237 cb_data
->is_finished
= 1;
238 cb_data
->status
= status
;
241 printf("close call failed with \"%s\"\n", (char *)data
);
246 int nfs_close_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
248 struct sync_cb_data cb_data
;
250 cb_data
.is_finished
= 0;
252 if (nfs_close_async(nfs
, nfsfh
, close_cb
, &cb_data
) != 0) {
253 printf("nfs_close_async failed\n");
257 wait_for_reply(nfs
, &cb_data
);
259 return cb_data
.status
;
268 int nfs_fstat_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, struct stat
*st
)
270 struct sync_cb_data cb_data
;
272 cb_data
.is_finished
= 0;
273 cb_data
.return_data
= st
;
275 if (nfs_fstat_async(nfs
, nfsfh
, stat_cb
, &cb_data
) != 0) {
276 printf("nfs_fstat_async failed\n");
280 wait_for_reply(nfs
, &cb_data
);
282 return cb_data
.status
;
289 static void pwrite_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
291 struct sync_cb_data
*cb_data
= private_data
;
292 cb_data
->is_finished
= 1;
293 cb_data
->status
= status
;
296 printf("pwrite call failed with \"%s\"\n", (char *)data
);
301 int nfs_pwrite_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buf
)
303 struct sync_cb_data cb_data
;
305 cb_data
.is_finished
= 0;
307 if (nfs_pwrite_async(nfs
, nfsfh
, offset
, count
, buf
, pwrite_cb
, &cb_data
) != 0) {
308 printf("nfs_pwrite_async failed\n");
312 wait_for_reply(nfs
, &cb_data
);
314 return cb_data
.status
;
320 int nfs_write_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buf
)
322 return nfs_pwrite_sync(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buf
);
329 static void fsync_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
331 struct sync_cb_data
*cb_data
= private_data
;
332 cb_data
->is_finished
= 1;
333 cb_data
->status
= status
;
336 printf("fsync call failed with \"%s\"\n", (char *)data
);
341 int nfs_fsync_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
343 struct sync_cb_data cb_data
;
345 cb_data
.is_finished
= 0;
347 if (nfs_fsync_async(nfs
, nfsfh
, fsync_cb
, &cb_data
) != 0) {
348 printf("nfs_fsync_async failed\n");
352 wait_for_reply(nfs
, &cb_data
);
354 return cb_data
.status
;
363 static void ftruncate_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
365 struct sync_cb_data
*cb_data
= private_data
;
366 cb_data
->is_finished
= 1;
367 cb_data
->status
= status
;
370 printf("ftruncate call failed with \"%s\"\n", (char *)data
);
375 int nfs_ftruncate_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t length
)
377 struct sync_cb_data cb_data
;
379 cb_data
.is_finished
= 0;
381 if (nfs_ftruncate_async(nfs
, nfsfh
, length
, ftruncate_cb
, &cb_data
) != 0) {
382 printf("nfs_ftruncate_async failed\n");
386 wait_for_reply(nfs
, &cb_data
);
388 return cb_data
.status
;
396 static void truncate_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
398 struct sync_cb_data
*cb_data
= private_data
;
399 cb_data
->is_finished
= 1;
400 cb_data
->status
= status
;
403 printf("truncate call failed with \"%s\"\n", (char *)data
);
408 int nfs_truncate_sync(struct nfs_context
*nfs
, const char *path
, off_t length
)
410 struct sync_cb_data cb_data
;
412 cb_data
.is_finished
= 0;
414 if (nfs_truncate_async(nfs
, path
, length
, truncate_cb
, &cb_data
) != 0) {
415 printf("nfs_ftruncate_async failed\n");
419 wait_for_reply(nfs
, &cb_data
);
421 return cb_data
.status
;
431 static void mkdir_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
433 struct sync_cb_data
*cb_data
= private_data
;
434 cb_data
->is_finished
= 1;
435 cb_data
->status
= status
;
438 printf("mkdir call failed with \"%s\"\n", (char *)data
);
443 int nfs_mkdir_sync(struct nfs_context
*nfs
, const char *path
)
445 struct sync_cb_data cb_data
;
447 cb_data
.is_finished
= 0;
449 if (nfs_mkdir_async(nfs
, path
, mkdir_cb
, &cb_data
) != 0) {
450 printf("nfs_mkdir_async failed\n");
454 wait_for_reply(nfs
, &cb_data
);
456 return cb_data
.status
;
466 static void rmdir_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
468 struct sync_cb_data
*cb_data
= private_data
;
469 cb_data
->is_finished
= 1;
470 cb_data
->status
= status
;
473 printf("rmdir call failed with \"%s\"\n", (char *)data
);
478 int nfs_rmdir_sync(struct nfs_context
*nfs
, const char *path
)
480 struct sync_cb_data cb_data
;
482 cb_data
.is_finished
= 0;
484 if (nfs_rmdir_async(nfs
, path
, rmdir_cb
, &cb_data
) != 0) {
485 printf("nfs_rmdir_async failed\n");
489 wait_for_reply(nfs
, &cb_data
);
491 return cb_data
.status
;
499 static void creat_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
501 struct sync_cb_data
*cb_data
= private_data
;
502 struct nfsfh
*fh
, **nfsfh
;
504 cb_data
->is_finished
= 1;
505 cb_data
->status
= status
;
508 printf("creat call failed with \"%s\"\n", (char *)data
);
513 nfsfh
= cb_data
->return_data
;
517 int nfs_creat_sync(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
519 struct sync_cb_data cb_data
;
521 cb_data
.is_finished
= 0;
522 cb_data
.return_data
= nfsfh
;
524 if (nfs_creat_async(nfs
, path
, mode
, creat_cb
, &cb_data
) != 0) {
525 printf("nfs_creat_async failed\n");
529 wait_for_reply(nfs
, &cb_data
);
531 return cb_data
.status
;
540 static void unlink_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
542 struct sync_cb_data
*cb_data
= private_data
;
544 cb_data
->is_finished
= 1;
545 cb_data
->status
= status
;
548 printf("unlink call failed with \"%s\"\n", (char *)data
);
553 int nfs_unlink_sync(struct nfs_context
*nfs
, const char *path
)
555 struct sync_cb_data cb_data
;
557 cb_data
.is_finished
= 0;
559 if (nfs_unlink_async(nfs
, path
, unlink_cb
, &cb_data
) != 0) {
560 printf("nfs_unlink_async failed\n");
564 wait_for_reply(nfs
, &cb_data
);
566 return cb_data
.status
;
574 static void opendir_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
576 struct sync_cb_data
*cb_data
= private_data
;
577 struct nfsdir
*dir
, **nfsdir
;
579 cb_data
->is_finished
= 1;
580 cb_data
->status
= status
;
583 printf("opendir call failed with \"%s\"\n", (char *)data
);
588 nfsdir
= cb_data
->return_data
;
592 int nfs_opendir_sync(struct nfs_context
*nfs
, const char *path
, struct nfsdir
**nfsdir
)
594 struct sync_cb_data cb_data
;
596 cb_data
.is_finished
= 0;
597 cb_data
.return_data
= nfsdir
;
599 if (nfs_opendir_async(nfs
, path
, opendir_cb
, &cb_data
) != 0) {
600 printf("nfs_opendir_async failed\n");
604 wait_for_reply(nfs
, &cb_data
);
606 return cb_data
.status
;
613 static void lseek_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
615 struct sync_cb_data
*cb_data
= private_data
;
617 cb_data
->is_finished
= 1;
618 cb_data
->status
= status
;
621 printf("lseek call failed with \"%s\"\n", (char *)data
);
625 if (cb_data
->return_data
!= NULL
) {
626 memcpy(cb_data
->return_data
, data
, sizeof(off_t
));
630 int nfs_lseek_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, int whence
, off_t
*current_offset
)
632 struct sync_cb_data cb_data
;
634 cb_data
.is_finished
= 0;
635 cb_data
.return_data
= current_offset
;
637 if (nfs_lseek_async(nfs
, nfsfh
, offset
, whence
, lseek_cb
, &cb_data
) != 0) {
638 printf("nfs_lseek_async failed\n");
642 wait_for_reply(nfs
, &cb_data
);
644 return cb_data
.status
;
652 static void statvfs_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
654 struct sync_cb_data
*cb_data
= private_data
;
656 cb_data
->is_finished
= 1;
657 cb_data
->status
= status
;
660 printf("statvfs call failed with \"%s\"\n", (char *)data
);
664 memcpy(cb_data
->return_data
, data
, sizeof(struct statvfs
));
667 int nfs_statvfs_sync(struct nfs_context
*nfs
, const char *path
, struct statvfs
*svfs
)
669 struct sync_cb_data cb_data
;
671 cb_data
.is_finished
= 0;
672 cb_data
.return_data
= svfs
;
674 if (nfs_statvfs_async(nfs
, path
, statvfs_cb
, &cb_data
) != 0) {
675 printf("nfs_statvfs_async failed\n");
679 wait_for_reply(nfs
, &cb_data
);
681 return cb_data
.status
;
691 static void readlink_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
693 struct sync_cb_data
*cb_data
= private_data
;
695 cb_data
->is_finished
= 1;
696 cb_data
->status
= status
;
699 printf("readlink call failed with \"%s\"\n", (char *)data
);
703 if (strlen(data
) > (size_t)cb_data
->return_int
) {
704 printf("Too small buffer for readlink\n");
705 cb_data
->status
= -ENAMETOOLONG
;
709 memcpy(cb_data
->return_data
, data
, strlen(data
)+1);
712 int nfs_readlink_sync(struct nfs_context
*nfs
, const char *path
, char *buf
, int bufsize
)
714 struct sync_cb_data cb_data
;
716 cb_data
.is_finished
= 0;
717 cb_data
.return_data
= buf
;
718 cb_data
.return_int
= bufsize
;
720 if (nfs_readlink_async(nfs
, path
, readlink_cb
, &cb_data
) != 0) {
721 printf("nfs_readlink_async failed\n");
725 wait_for_reply(nfs
, &cb_data
);
727 return cb_data
.status
;
735 static void chmod_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
737 struct sync_cb_data
*cb_data
= private_data
;
739 cb_data
->is_finished
= 1;
740 cb_data
->status
= status
;
743 printf("chmod call failed with \"%s\"\n", (char *)data
);
748 int nfs_chmod_sync(struct nfs_context
*nfs
, const char *path
, int mode
)
750 struct sync_cb_data cb_data
;
752 cb_data
.is_finished
= 0;
754 if (nfs_chmod_async(nfs
, path
, mode
, chmod_cb
, &cb_data
) != 0) {
755 printf("nfs_chmod_async failed\n");
759 wait_for_reply(nfs
, &cb_data
);
761 return cb_data
.status
;
770 static void fchmod_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
772 struct sync_cb_data
*cb_data
= private_data
;
774 cb_data
->is_finished
= 1;
775 cb_data
->status
= status
;
778 printf("fchmod call failed with \"%s\"\n", (char *)data
);
783 int nfs_fchmod_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int mode
)
785 struct sync_cb_data cb_data
;
787 cb_data
.is_finished
= 0;
789 if (nfs_fchmod_async(nfs
, nfsfh
, mode
, fchmod_cb
, &cb_data
) != 0) {
790 printf("nfs_fchmod_async failed\n");
794 wait_for_reply(nfs
, &cb_data
);
796 return cb_data
.status
;
805 static void chown_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
807 struct sync_cb_data
*cb_data
= private_data
;
809 cb_data
->is_finished
= 1;
810 cb_data
->status
= status
;
813 printf("chown call failed with \"%s\"\n", (char *)data
);
818 int nfs_chown_sync(struct nfs_context
*nfs
, const char *path
, int uid
, int gid
)
820 struct sync_cb_data cb_data
;
822 cb_data
.is_finished
= 0;
824 if (nfs_chown_async(nfs
, path
, uid
, gid
, chown_cb
, &cb_data
) != 0) {
825 printf("nfs_chown_async failed\n");
829 wait_for_reply(nfs
, &cb_data
);
831 return cb_data
.status
;
837 static void fchown_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
839 struct sync_cb_data
*cb_data
= private_data
;
841 cb_data
->is_finished
= 1;
842 cb_data
->status
= status
;
845 printf("fchown call failed with \"%s\"\n", (char *)data
);
850 int nfs_fchown_sync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int uid
, int gid
)
852 struct sync_cb_data cb_data
;
854 cb_data
.is_finished
= 0;
856 if (nfs_fchown_async(nfs
, nfsfh
, uid
, gid
, fchown_cb
, &cb_data
) != 0) {
857 printf("nfs_fchown_async failed\n");
861 wait_for_reply(nfs
, &cb_data
);
863 return cb_data
.status
;
871 static void utimes_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
873 struct sync_cb_data
*cb_data
= private_data
;
875 cb_data
->is_finished
= 1;
876 cb_data
->status
= status
;
879 printf("utimes call failed with \"%s\"\n", (char *)data
);
884 int nfs_utimes_sync(struct nfs_context
*nfs
, const char *path
, struct timeval
*times
)
886 struct sync_cb_data cb_data
;
888 cb_data
.is_finished
= 0;
890 if (nfs_utimes_async(nfs
, path
, times
, utimes_cb
, &cb_data
) != 0) {
891 printf("nfs_utimes_async failed\n");
895 wait_for_reply(nfs
, &cb_data
);
897 return cb_data
.status
;
905 static void utime_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
907 struct sync_cb_data
*cb_data
= private_data
;
909 cb_data
->is_finished
= 1;
910 cb_data
->status
= status
;
913 printf("utime call failed with \"%s\"\n", (char *)data
);
918 int nfs_utime_sync(struct nfs_context
*nfs
, const char *path
, struct utimbuf
*times
)
920 struct sync_cb_data cb_data
;
922 cb_data
.is_finished
= 0;
924 if (nfs_utime_async(nfs
, path
, times
, utime_cb
, &cb_data
) != 0) {
925 printf("nfs_utimes_async failed\n");
929 wait_for_reply(nfs
, &cb_data
);
931 return cb_data
.status
;
940 static void access_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
942 struct sync_cb_data
*cb_data
= private_data
;
944 cb_data
->is_finished
= 1;
945 cb_data
->status
= status
;
948 printf("access call failed with \"%s\"\n", (char *)data
);
953 int nfs_access_sync(struct nfs_context
*nfs
, const char *path
, int mode
)
955 struct sync_cb_data cb_data
;
957 cb_data
.is_finished
= 0;
959 if (nfs_access_async(nfs
, path
, mode
, access_cb
, &cb_data
) != 0) {
960 printf("nfs_access_async failed\n");
964 wait_for_reply(nfs
, &cb_data
);
966 return cb_data
.status
;
974 static void symlink_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
976 struct sync_cb_data
*cb_data
= private_data
;
978 cb_data
->is_finished
= 1;
979 cb_data
->status
= status
;
982 printf("symlink call failed with \"%s\"\n", (char *)data
);
987 int nfs_symlink_sync(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
989 struct sync_cb_data cb_data
;
991 cb_data
.is_finished
= 0;
993 if (nfs_symlink_async(nfs
, oldpath
, newpath
, symlink_cb
, &cb_data
) != 0) {
994 printf("nfs_symlink_async failed\n");
998 wait_for_reply(nfs
, &cb_data
);
1000 return cb_data
.status
;
1008 static void rename_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
1010 struct sync_cb_data
*cb_data
= private_data
;
1012 cb_data
->is_finished
= 1;
1013 cb_data
->status
= status
;
1016 printf("rename call failed with \"%s\"\n", (char *)data
);
1021 int nfs_rename_sync(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1023 struct sync_cb_data cb_data
;
1025 cb_data
.is_finished
= 0;
1027 if (nfs_rename_async(nfs
, oldpath
, newpath
, rename_cb
, &cb_data
) != 0) {
1028 printf("nfs_rename_async failed\n");
1032 wait_for_reply(nfs
, &cb_data
);
1034 return cb_data
.status
;
1042 static void link_cb(int status
, struct nfs_context
*nfs _U_
, void *data
, void *private_data
)
1044 struct sync_cb_data
*cb_data
= private_data
;
1046 cb_data
->is_finished
= 1;
1047 cb_data
->status
= status
;
1050 printf("link call failed with \"%s\"\n", (char *)data
);
1055 int nfs_link_sync(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1057 struct sync_cb_data cb_data
;
1059 cb_data
.is_finished
= 0;
1061 if (nfs_link_async(nfs
, oldpath
, newpath
, link_cb
, &cb_data
) != 0) {
1062 printf("nfs_link_async failed\n");
1066 wait_for_reply(nfs
, &cb_data
);
1068 return cb_data
.status
;