[fix] - vs2010 project for libnfs
[deb_libnfs.git] / lib / libnfs-sync.c
CommitLineData
84004dbf
RS
1/*
2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
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.
8
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.
13
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/>.
16*/
17/*
18 * High level api to nfs filesystems
19 */
a8a1b858
M
20#ifdef WIN32
21#include "win32_compat.h"
eecdc4f3
RS
22#define DllExport
23#else
24#include <strings.h>
25#include <unistd.h>
26#include <sys/statvfs.h>
27#include <poll.h>
28#include <sys/ioctl.h>
29#include <netdb.h>
30#include <sys/socket.h>
31#include <net/if.h>
32#endif
33
34#ifdef HAVE_CONFIG_H
9a96dd46 35#include "config.h"
eecdc4f3
RS
36#endif
37
84004dbf
RS
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
84004dbf
RS
41#include <sys/types.h>
42#include <sys/stat.h>
84004dbf
RS
43#include <fcntl.h>
44#include <errno.h>
a8a1b858 45
647d2ea1
RS
46#ifdef HAVE_SYS_SOCKIO_H
47#include <sys/sockio.h>
48#endif
a8a1b858
M
49
50#include <fcntl.h>
51#include <errno.h>
84004dbf
RS
52#include "libnfs.h"
53#include "libnfs-raw.h"
54#include "libnfs-raw-mount.h"
55#include "libnfs-raw-nfs.h"
1896d37b 56#include "libnfs-private.h"
84004dbf
RS
57
58struct sync_cb_data {
59 int is_finished;
60 int status;
61 off_t offset;
62 void *return_data;
63 int return_int;
64};
65
66
df5af25f 67static void wait_for_reply(struct rpc_context *rpc, struct sync_cb_data *cb_data)
84004dbf
RS
68{
69 struct pollfd pfd;
70
b077fdeb
RS
71 while (!cb_data->is_finished) {
72
df5af25f
RS
73 pfd.fd = rpc_get_fd(rpc);
74 pfd.events = rpc_which_events(rpc);
84004dbf 75 if (poll(&pfd, 1, -1) < 0) {
df5af25f 76 rpc_set_error(rpc, "Poll failed");
84004dbf
RS
77 cb_data->status = -EIO;
78 break;
79 }
df5af25f
RS
80 if (rpc_service(rpc, pfd.revents) < 0) {
81 rpc_set_error(rpc, "rpc_service failed");
84004dbf
RS
82 cb_data->status = -EIO;
83 break;
84 }
b077fdeb
RS
85 if (rpc_get_fd(rpc) == -1) {
86 rpc_set_error(rpc, "Socket closed\n");
87 break;
88 }
89 }
90}
91
92static void wait_for_nfs_reply(struct nfs_context *nfs, struct sync_cb_data *cb_data)
93{
94 struct pollfd pfd;
95
96 while (!cb_data->is_finished) {
97
98 pfd.fd = nfs_get_fd(nfs);
99 pfd.events = nfs_which_events(nfs);
100 if (poll(&pfd, 1, -1) < 0) {
101 nfs_set_error(nfs, "Poll failed");
102 cb_data->status = -EIO;
103 break;
104 }
105 if (nfs_service(nfs, pfd.revents) < 0) {
106 nfs_set_error(nfs, "nfs_service failed");
107 cb_data->status = -EIO;
108 break;
109 }
110 if (nfs_get_fd(nfs) == -1) {
111 char *server = strdup(nfs_get_server(nfs));
112 char *export = strdup(nfs_get_export(nfs));
113
114 if (nfs_mount(nfs, server, export) != 0) {
115 nfs_set_error(nfs, "Failed to reconnect to nfs server %s", nfs_get_error(nfs));
116 free(server);
117 free(export);
118 break;
119 }
120 free(server);
121 free(export);
122 }
84004dbf
RS
123 }
124}
125
126
127
128
129
130
131/*
132 * connect to the server and mount the export
133 */
1896d37b 134static void mount_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
135{
136 struct sync_cb_data *cb_data = private_data;
137
138 cb_data->is_finished = 1;
139 cb_data->status = status;
140
141 if (status < 0) {
1896d37b 142 nfs_set_error(nfs, "mount/mnt call failed with \"%s\"", (char *)data);
84004dbf
RS
143 return;
144 }
145}
146
e2ba5764 147int nfs_mount(struct nfs_context *nfs, const char *server, const char *export)
84004dbf
RS
148{
149 struct sync_cb_data cb_data;
150
151 cb_data.is_finished = 0;
152
153 if (nfs_mount_async(nfs, server, export, mount_cb, &cb_data) != 0) {
1896d37b 154 nfs_set_error(nfs, "nfs_mount_async failed");
84004dbf
RS
155 return -1;
156 }
157
b077fdeb 158 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
159
160 return cb_data.status;
161}
162
163
164/*
165 * stat()
166 */
1896d37b 167static void stat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
168{
169 struct sync_cb_data *cb_data = private_data;
170
171 cb_data->is_finished = 1;
172 cb_data->status = status;
173
174 if (status < 0) {
1896d37b 175 nfs_set_error(nfs, "stat call failed with \"%s\"", (char *)data);
84004dbf
RS
176 return;
177 }
178
179 memcpy(cb_data->return_data, data, sizeof(struct stat));
180}
181
e2ba5764 182int nfs_stat(struct nfs_context *nfs, const char *path, struct stat *st)
84004dbf
RS
183{
184 struct sync_cb_data cb_data;
185
186 cb_data.is_finished = 0;
187 cb_data.return_data = st;
188
189 if (nfs_stat_async(nfs, path, stat_cb, &cb_data) != 0) {
1896d37b 190 nfs_set_error(nfs, "nfs_stat_async failed");
84004dbf
RS
191 return -1;
192 }
193
b077fdeb 194 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
195
196 return cb_data.status;
197}
198
199
200
201
202/*
203 * open()
204 */
1896d37b 205static void open_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
206{
207 struct sync_cb_data *cb_data = private_data;
208 struct nfsfh *fh, **nfsfh;
209
210 cb_data->is_finished = 1;
211 cb_data->status = status;
212
213 if (status < 0) {
1896d37b 214 nfs_set_error(nfs, "open call failed with \"%s\"", (char *)data);
84004dbf
RS
215 return;
216 }
217
218 fh = data;
219 nfsfh = cb_data->return_data;
220 *nfsfh = fh;
221}
222
e2ba5764 223int nfs_open(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
84004dbf
RS
224{
225 struct sync_cb_data cb_data;
226
227 cb_data.is_finished = 0;
228 cb_data.return_data = nfsfh;
229
230 if (nfs_open_async(nfs, path, mode, open_cb, &cb_data) != 0) {
1896d37b 231 nfs_set_error(nfs, "nfs_open_async failed");
84004dbf
RS
232 return -1;
233 }
234
b077fdeb 235 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
236
237 return cb_data.status;
238}
239
240
241
242
243/*
244 * pread()
245 */
1896d37b 246static void pread_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
247{
248 struct sync_cb_data *cb_data = private_data;
249 char *buffer;
250 cb_data->is_finished = 1;
251 cb_data->status = status;
252
253 if (status < 0) {
1896d37b 254 nfs_set_error(nfs, "pread call failed with \"%s\"", (char *)data);
84004dbf
RS
255 return;
256 }
257
258 buffer = cb_data->return_data;
259 memcpy(buffer, (char *)data, status);
260}
261
e2ba5764 262int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buffer)
84004dbf
RS
263{
264 struct sync_cb_data cb_data;
265
266 cb_data.is_finished = 0;
267 cb_data.return_data = buffer;
268
269 if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
1896d37b 270 nfs_set_error(nfs, "nfs_pread_async failed");
84004dbf
RS
271 return -1;
272 }
273
b077fdeb 274 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
275
276 return cb_data.status;
277}
278
279/*
280 * read()
281 */
e2ba5764 282int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buffer)
84004dbf 283{
e2ba5764 284 return nfs_pread(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
84004dbf
RS
285}
286
287/*
288 * close()
289 */
1896d37b 290static void close_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
291{
292 struct sync_cb_data *cb_data = private_data;
293 cb_data->is_finished = 1;
294 cb_data->status = status;
295
296 if (status < 0) {
1896d37b 297 nfs_set_error(nfs, "close call failed with \"%s\"", (char *)data);
84004dbf
RS
298 return;
299 }
300}
301
e2ba5764 302int nfs_close(struct nfs_context *nfs, struct nfsfh *nfsfh)
84004dbf
RS
303{
304 struct sync_cb_data cb_data;
305
306 cb_data.is_finished = 0;
307
308 if (nfs_close_async(nfs, nfsfh, close_cb, &cb_data) != 0) {
1896d37b 309 nfs_set_error(nfs, "nfs_close_async failed");
84004dbf
RS
310 return -1;
311 }
312
b077fdeb 313 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
314
315 return cb_data.status;
316}
317
318
319
320
321/*
322 * fstat()
323 */
e2ba5764 324int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st)
84004dbf
RS
325{
326 struct sync_cb_data cb_data;
327
328 cb_data.is_finished = 0;
329 cb_data.return_data = st;
330
331 if (nfs_fstat_async(nfs, nfsfh, stat_cb, &cb_data) != 0) {
1896d37b 332 nfs_set_error(nfs, "nfs_fstat_async failed");
84004dbf
RS
333 return -1;
334 }
335
b077fdeb 336 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
337
338 return cb_data.status;
339}
340
341
342/*
343 * pwrite()
344 */
1896d37b 345static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
346{
347 struct sync_cb_data *cb_data = private_data;
348 cb_data->is_finished = 1;
349 cb_data->status = status;
350
351 if (status < 0) {
1896d37b 352 nfs_set_error(nfs, "pwrite call failed with \"%s\"", (char *)data);
84004dbf
RS
353 return;
354 }
355}
356
e2ba5764 357int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf)
84004dbf
RS
358{
359 struct sync_cb_data cb_data;
360
361 cb_data.is_finished = 0;
362
363 if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
1896d37b 364 nfs_set_error(nfs, "nfs_pwrite_async failed");
84004dbf
RS
365 return -1;
366 }
367
b077fdeb 368 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
369
370 return cb_data.status;
371}
372
373/*
374 * write()
375 */
e2ba5764 376int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf)
84004dbf 377{
e2ba5764 378 return nfs_pwrite(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
84004dbf
RS
379}
380
381
382/*
383 * fsync()
384 */
1896d37b 385static void fsync_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
386{
387 struct sync_cb_data *cb_data = private_data;
388 cb_data->is_finished = 1;
389 cb_data->status = status;
390
391 if (status < 0) {
1896d37b 392 nfs_set_error(nfs, "fsync call failed with \"%s\"", (char *)data);
84004dbf
RS
393 return;
394 }
395}
396
e2ba5764 397int nfs_fsync(struct nfs_context *nfs, struct nfsfh *nfsfh)
84004dbf
RS
398{
399 struct sync_cb_data cb_data;
400
401 cb_data.is_finished = 0;
402
403 if (nfs_fsync_async(nfs, nfsfh, fsync_cb, &cb_data) != 0) {
1896d37b 404 nfs_set_error(nfs, "nfs_fsync_async failed");
84004dbf
RS
405 return -1;
406 }
407
b077fdeb 408 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
409
410 return cb_data.status;
411}
412
413
414
415
416/*
417 * ftruncate()
418 */
1896d37b 419static void ftruncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
420{
421 struct sync_cb_data *cb_data = private_data;
422 cb_data->is_finished = 1;
423 cb_data->status = status;
424
425 if (status < 0) {
1896d37b 426 nfs_set_error(nfs, "ftruncate call failed with \"%s\"", (char *)data);
84004dbf
RS
427 return;
428 }
429}
430
e2ba5764 431int nfs_ftruncate(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length)
84004dbf
RS
432{
433 struct sync_cb_data cb_data;
434
435 cb_data.is_finished = 0;
436
437 if (nfs_ftruncate_async(nfs, nfsfh, length, ftruncate_cb, &cb_data) != 0) {
1896d37b 438 nfs_set_error(nfs, "nfs_ftruncate_async failed");
84004dbf
RS
439 return -1;
440 }
441
b077fdeb 442 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
443
444 return cb_data.status;
445}
446
447
448
449/*
450 * truncate()
451 */
1896d37b 452static void truncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
453{
454 struct sync_cb_data *cb_data = private_data;
455 cb_data->is_finished = 1;
456 cb_data->status = status;
457
458 if (status < 0) {
1896d37b 459 nfs_set_error(nfs, "truncate call failed with \"%s\"", (char *)data);
84004dbf
RS
460 return;
461 }
462}
463
e2ba5764 464int nfs_truncate(struct nfs_context *nfs, const char *path, off_t length)
84004dbf
RS
465{
466 struct sync_cb_data cb_data;
467
468 cb_data.is_finished = 0;
469
470 if (nfs_truncate_async(nfs, path, length, truncate_cb, &cb_data) != 0) {
1896d37b 471 nfs_set_error(nfs, "nfs_ftruncate_async failed");
84004dbf
RS
472 return -1;
473 }
474
b077fdeb 475 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
476
477 return cb_data.status;
478}
479
480
481
482
483
484/*
485 * mkdir()
486 */
1896d37b 487static void mkdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
488{
489 struct sync_cb_data *cb_data = private_data;
490 cb_data->is_finished = 1;
491 cb_data->status = status;
492
493 if (status < 0) {
1896d37b 494 nfs_set_error(nfs, "mkdir call failed with \"%s\"", (char *)data);
84004dbf
RS
495 return;
496 }
497}
498
e2ba5764 499int nfs_mkdir(struct nfs_context *nfs, const char *path)
84004dbf
RS
500{
501 struct sync_cb_data cb_data;
502
503 cb_data.is_finished = 0;
504
505 if (nfs_mkdir_async(nfs, path, mkdir_cb, &cb_data) != 0) {
1896d37b 506 nfs_set_error(nfs, "nfs_mkdir_async failed");
84004dbf
RS
507 return -1;
508 }
509
b077fdeb 510 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
511
512 return cb_data.status;
513}
514
515
516
517
518
519/*
520 * rmdir()
521 */
1896d37b 522static void rmdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
523{
524 struct sync_cb_data *cb_data = private_data;
525 cb_data->is_finished = 1;
526 cb_data->status = status;
527
528 if (status < 0) {
1896d37b 529 nfs_set_error(nfs, "rmdir call failed with \"%s\"", (char *)data);
84004dbf
RS
530 return;
531 }
532}
533
e2ba5764 534int nfs_rmdir(struct nfs_context *nfs, const char *path)
84004dbf
RS
535{
536 struct sync_cb_data cb_data;
537
538 cb_data.is_finished = 0;
539
540 if (nfs_rmdir_async(nfs, path, rmdir_cb, &cb_data) != 0) {
1896d37b 541 nfs_set_error(nfs, "nfs_rmdir_async failed");
84004dbf
RS
542 return -1;
543 }
544
b077fdeb 545 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
546
547 return cb_data.status;
548}
549
550
551
552/*
553 * creat()
554 */
1896d37b 555static void creat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
556{
557 struct sync_cb_data *cb_data = private_data;
558 struct nfsfh *fh, **nfsfh;
559
560 cb_data->is_finished = 1;
561 cb_data->status = status;
562
563 if (status < 0) {
1896d37b 564 nfs_set_error(nfs, "creat call failed with \"%s\"", (char *)data);
84004dbf
RS
565 return;
566 }
567
568 fh = data;
569 nfsfh = cb_data->return_data;
570 *nfsfh = fh;
571}
572
e2ba5764 573int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
84004dbf
RS
574{
575 struct sync_cb_data cb_data;
576
577 cb_data.is_finished = 0;
578 cb_data.return_data = nfsfh;
579
580 if (nfs_creat_async(nfs, path, mode, creat_cb, &cb_data) != 0) {
1896d37b 581 nfs_set_error(nfs, "nfs_creat_async failed");
84004dbf
RS
582 return -1;
583 }
584
b077fdeb 585 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
586
587 return cb_data.status;
588}
589
590
591
592
593/*
594 * unlink()
595 */
1896d37b 596static void unlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
597{
598 struct sync_cb_data *cb_data = private_data;
599
600 cb_data->is_finished = 1;
601 cb_data->status = status;
602
603 if (status < 0) {
1896d37b 604 nfs_set_error(nfs, "unlink call failed with \"%s\"", (char *)data);
84004dbf
RS
605 return;
606 }
607}
608
e2ba5764 609int nfs_unlink(struct nfs_context *nfs, const char *path)
84004dbf
RS
610{
611 struct sync_cb_data cb_data;
612
613 cb_data.is_finished = 0;
614
615 if (nfs_unlink_async(nfs, path, unlink_cb, &cb_data) != 0) {
1896d37b 616 nfs_set_error(nfs, "nfs_unlink_async failed");
84004dbf
RS
617 return -1;
618 }
619
b077fdeb 620 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
621
622 return cb_data.status;
623}
624
625
626
627/*
628 * opendir()
629 */
1896d37b 630static void opendir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
631{
632 struct sync_cb_data *cb_data = private_data;
633 struct nfsdir *dir, **nfsdir;
634
635 cb_data->is_finished = 1;
636 cb_data->status = status;
637
638 if (status < 0) {
1896d37b 639 nfs_set_error(nfs, "opendir call failed with \"%s\"", (char *)data);
84004dbf
RS
640 return;
641 }
642
643 dir = data;
644 nfsdir = cb_data->return_data;
645 *nfsdir = dir;
646}
647
e2ba5764 648int nfs_opendir(struct nfs_context *nfs, const char *path, struct nfsdir **nfsdir)
84004dbf
RS
649{
650 struct sync_cb_data cb_data;
651
652 cb_data.is_finished = 0;
653 cb_data.return_data = nfsdir;
654
655 if (nfs_opendir_async(nfs, path, opendir_cb, &cb_data) != 0) {
1896d37b 656 nfs_set_error(nfs, "nfs_opendir_async failed");
84004dbf
RS
657 return -1;
658 }
659
b077fdeb 660 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
661
662 return cb_data.status;
663}
664
665
666/*
667 * lseek()
668 */
1896d37b 669static void lseek_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
670{
671 struct sync_cb_data *cb_data = private_data;
672
673 cb_data->is_finished = 1;
674 cb_data->status = status;
675
676 if (status < 0) {
1896d37b 677 nfs_set_error(nfs, "lseek call failed with \"%s\"", (char *)data);
84004dbf
RS
678 return;
679 }
680
681 if (cb_data->return_data != NULL) {
682 memcpy(cb_data->return_data, data, sizeof(off_t));
683 }
684}
685
e2ba5764 686int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, off_t *current_offset)
84004dbf
RS
687{
688 struct sync_cb_data cb_data;
689
690 cb_data.is_finished = 0;
691 cb_data.return_data = current_offset;
692
693 if (nfs_lseek_async(nfs, nfsfh, offset, whence, lseek_cb, &cb_data) != 0) {
1896d37b 694 nfs_set_error(nfs, "nfs_lseek_async failed");
84004dbf
RS
695 return -1;
696 }
697
b077fdeb 698 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
699
700 return cb_data.status;
701}
702
703
704
705/*
706 * statvfs()
707 */
1896d37b 708static void statvfs_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
709{
710 struct sync_cb_data *cb_data = private_data;
711
712 cb_data->is_finished = 1;
713 cb_data->status = status;
714
715 if (status < 0) {
1896d37b 716 nfs_set_error(nfs, "statvfs call failed with \"%s\"", (char *)data);
84004dbf
RS
717 return;
718 }
a8a1b858 719#ifndef WIN32
84004dbf 720 memcpy(cb_data->return_data, data, sizeof(struct statvfs));
a8a1b858
M
721#else
722 cb_data->return_data=NULL;
723#endif/**/
84004dbf
RS
724}
725
e2ba5764 726int nfs_statvfs(struct nfs_context *nfs, const char *path, struct statvfs *svfs)
84004dbf
RS
727{
728 struct sync_cb_data cb_data;
729
730 cb_data.is_finished = 0;
731 cb_data.return_data = svfs;
732
733 if (nfs_statvfs_async(nfs, path, statvfs_cb, &cb_data) != 0) {
1896d37b 734 nfs_set_error(nfs, "nfs_statvfs_async failed");
84004dbf
RS
735 return -1;
736 }
737
b077fdeb 738 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
739
740 return cb_data.status;
741}
742
743
744
745
746
747/*
748 * readlink()
749 */
1896d37b 750static void readlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
751{
752 struct sync_cb_data *cb_data = private_data;
753
754 cb_data->is_finished = 1;
755 cb_data->status = status;
756
757 if (status < 0) {
1896d37b 758 nfs_set_error(nfs, "readlink call failed with \"%s\"", (char *)data);
84004dbf
RS
759 return;
760 }
761
762 if (strlen(data) > (size_t)cb_data->return_int) {
1896d37b 763 nfs_set_error(nfs, "Too small buffer for readlink");
84004dbf
RS
764 cb_data->status = -ENAMETOOLONG;
765 return;
766 }
767
768 memcpy(cb_data->return_data, data, strlen(data)+1);
769}
770
e2ba5764 771int nfs_readlink(struct nfs_context *nfs, const char *path, char *buf, int bufsize)
84004dbf
RS
772{
773 struct sync_cb_data cb_data;
774
775 cb_data.is_finished = 0;
776 cb_data.return_data = buf;
777 cb_data.return_int = bufsize;
778
779 if (nfs_readlink_async(nfs, path, readlink_cb, &cb_data) != 0) {
1896d37b 780 nfs_set_error(nfs, "nfs_readlink_async failed");
84004dbf
RS
781 return -1;
782 }
783
b077fdeb 784 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
785
786 return cb_data.status;
787}
788
789
790
791/*
792 * chmod()
793 */
1896d37b 794static void chmod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
795{
796 struct sync_cb_data *cb_data = private_data;
797
798 cb_data->is_finished = 1;
799 cb_data->status = status;
800
801 if (status < 0) {
1896d37b 802 nfs_set_error(nfs, "chmod call failed with \"%s\"", (char *)data);
84004dbf
RS
803 return;
804 }
805}
806
e2ba5764 807int nfs_chmod(struct nfs_context *nfs, const char *path, int mode)
84004dbf
RS
808{
809 struct sync_cb_data cb_data;
810
811 cb_data.is_finished = 0;
812
813 if (nfs_chmod_async(nfs, path, mode, chmod_cb, &cb_data) != 0) {
1896d37b 814 nfs_set_error(nfs, "nfs_chmod_async failed");
84004dbf
RS
815 return -1;
816 }
817
b077fdeb 818 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
819
820 return cb_data.status;
821}
822
823
824
825
826/*
827 * fchmod()
828 */
1896d37b 829static void fchmod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
830{
831 struct sync_cb_data *cb_data = private_data;
832
833 cb_data->is_finished = 1;
834 cb_data->status = status;
835
836 if (status < 0) {
1896d37b 837 nfs_set_error(nfs, "fchmod call failed with \"%s\"", (char *)data);
84004dbf
RS
838 return;
839 }
840}
841
e2ba5764 842int nfs_fchmod(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode)
84004dbf
RS
843{
844 struct sync_cb_data cb_data;
845
846 cb_data.is_finished = 0;
847
848 if (nfs_fchmod_async(nfs, nfsfh, mode, fchmod_cb, &cb_data) != 0) {
1896d37b 849 nfs_set_error(nfs, "nfs_fchmod_async failed");
84004dbf
RS
850 return -1;
851 }
852
b077fdeb 853 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
854
855 return cb_data.status;
856}
857
858
859
860
861/*
862 * chown()
863 */
1896d37b 864static void chown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
865{
866 struct sync_cb_data *cb_data = private_data;
867
868 cb_data->is_finished = 1;
869 cb_data->status = status;
870
871 if (status < 0) {
1896d37b 872 nfs_set_error(nfs, "chown call failed with \"%s\"", (char *)data);
84004dbf
RS
873 return;
874 }
875}
876
e2ba5764 877int nfs_chown(struct nfs_context *nfs, const char *path, int uid, int gid)
84004dbf
RS
878{
879 struct sync_cb_data cb_data;
880
881 cb_data.is_finished = 0;
882
883 if (nfs_chown_async(nfs, path, uid, gid, chown_cb, &cb_data) != 0) {
1896d37b 884 nfs_set_error(nfs, "nfs_chown_async failed");
84004dbf
RS
885 return -1;
886 }
887
b077fdeb 888 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
889
890 return cb_data.status;
891}
892
893/*
894 * fchown()
895 */
1896d37b 896static void fchown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
897{
898 struct sync_cb_data *cb_data = private_data;
899
900 cb_data->is_finished = 1;
901 cb_data->status = status;
902
903 if (status < 0) {
1896d37b 904 nfs_set_error(nfs, "fchown call failed with \"%s\"", (char *)data);
84004dbf
RS
905 return;
906 }
907}
908
e2ba5764 909int nfs_fchown(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid)
84004dbf
RS
910{
911 struct sync_cb_data cb_data;
912
913 cb_data.is_finished = 0;
914
915 if (nfs_fchown_async(nfs, nfsfh, uid, gid, fchown_cb, &cb_data) != 0) {
1896d37b 916 nfs_set_error(nfs, "nfs_fchown_async failed");
84004dbf
RS
917 return -1;
918 }
919
b077fdeb 920 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
921
922 return cb_data.status;
923}
924
925
926
927/*
928 * utimes()
929 */
1896d37b 930static void utimes_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
931{
932 struct sync_cb_data *cb_data = private_data;
933
934 cb_data->is_finished = 1;
935 cb_data->status = status;
936
937 if (status < 0) {
1896d37b 938 nfs_set_error(nfs, "utimes call failed with \"%s\"", (char *)data);
84004dbf
RS
939 return;
940 }
941}
942
e2ba5764 943int nfs_utimes(struct nfs_context *nfs, const char *path, struct timeval *times)
84004dbf
RS
944{
945 struct sync_cb_data cb_data;
946
947 cb_data.is_finished = 0;
948
949 if (nfs_utimes_async(nfs, path, times, utimes_cb, &cb_data) != 0) {
1896d37b 950 nfs_set_error(nfs, "nfs_utimes_async failed");
84004dbf
RS
951 return -1;
952 }
953
b077fdeb 954 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
955
956 return cb_data.status;
957}
958
959
960
961/*
962 * utime()
963 */
1896d37b 964static void utime_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
965{
966 struct sync_cb_data *cb_data = private_data;
967
968 cb_data->is_finished = 1;
969 cb_data->status = status;
970
971 if (status < 0) {
1896d37b 972 nfs_set_error(nfs, "utime call failed with \"%s\"", (char *)data);
84004dbf
RS
973 return;
974 }
975}
976
e2ba5764 977int nfs_utime(struct nfs_context *nfs, const char *path, struct utimbuf *times)
84004dbf
RS
978{
979 struct sync_cb_data cb_data;
980
981 cb_data.is_finished = 0;
982
983 if (nfs_utime_async(nfs, path, times, utime_cb, &cb_data) != 0) {
1896d37b 984 nfs_set_error(nfs, "nfs_utimes_async failed");
84004dbf
RS
985 return -1;
986 }
987
b077fdeb 988 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
989
990 return cb_data.status;
991}
992
993
994
995
996/*
997 * access()
998 */
1896d37b 999static void access_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1000{
1001 struct sync_cb_data *cb_data = private_data;
1002
1003 cb_data->is_finished = 1;
1004 cb_data->status = status;
1005
1006 if (status < 0) {
1896d37b 1007 nfs_set_error(nfs, "access call failed with \"%s\"", (char *)data);
84004dbf
RS
1008 return;
1009 }
1010}
1011
e2ba5764 1012int nfs_access(struct nfs_context *nfs, const char *path, int mode)
84004dbf
RS
1013{
1014 struct sync_cb_data cb_data;
1015
1016 cb_data.is_finished = 0;
1017
1018 if (nfs_access_async(nfs, path, mode, access_cb, &cb_data) != 0) {
1896d37b 1019 nfs_set_error(nfs, "nfs_access_async failed");
84004dbf
RS
1020 return -1;
1021 }
1022
b077fdeb 1023 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
1024
1025 return cb_data.status;
1026}
1027
1028
1029
1030/*
1031 * symlink()
1032 */
1896d37b 1033static void symlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1034{
1035 struct sync_cb_data *cb_data = private_data;
1036
1037 cb_data->is_finished = 1;
1038 cb_data->status = status;
1039
1040 if (status < 0) {
1896d37b 1041 nfs_set_error(nfs, "symlink call failed with \"%s\"", (char *)data);
84004dbf
RS
1042 return;
1043 }
1044}
1045
e2ba5764 1046int nfs_symlink(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
1047{
1048 struct sync_cb_data cb_data;
1049
1050 cb_data.is_finished = 0;
1051
1052 if (nfs_symlink_async(nfs, oldpath, newpath, symlink_cb, &cb_data) != 0) {
1896d37b 1053 nfs_set_error(nfs, "nfs_symlink_async failed");
84004dbf
RS
1054 return -1;
1055 }
1056
b077fdeb 1057 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
1058
1059 return cb_data.status;
1060}
1061
1062
1063
1064/*
1065 * rename()
1066 */
1896d37b 1067static void rename_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1068{
1069 struct sync_cb_data *cb_data = private_data;
1070
1071 cb_data->is_finished = 1;
1072 cb_data->status = status;
1073
1074 if (status < 0) {
1896d37b 1075 nfs_set_error(nfs, "rename call failed with \"%s\"", (char *)data);
84004dbf
RS
1076 return;
1077 }
1078}
1079
e2ba5764 1080int nfs_rename(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
1081{
1082 struct sync_cb_data cb_data;
1083
1084 cb_data.is_finished = 0;
1085
1086 if (nfs_rename_async(nfs, oldpath, newpath, rename_cb, &cb_data) != 0) {
1896d37b 1087 nfs_set_error(nfs, "nfs_rename_async failed");
84004dbf
RS
1088 return -1;
1089 }
1090
b077fdeb 1091 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
1092
1093 return cb_data.status;
1094}
1095
1096
1097
1098/*
1099 * link()
1100 */
1896d37b 1101static void link_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1102{
1103 struct sync_cb_data *cb_data = private_data;
1104
1105 cb_data->is_finished = 1;
1106 cb_data->status = status;
1107
1108 if (status < 0) {
1896d37b 1109 nfs_set_error(nfs, "link call failed with \"%s\"", (char *)data);
84004dbf
RS
1110 return;
1111 }
1112}
1113
e2ba5764 1114int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
1115{
1116 struct sync_cb_data cb_data;
1117
1118 cb_data.is_finished = 0;
1119
1120 if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
1896d37b 1121 nfs_set_error(nfs, "nfs_link_async failed");
84004dbf
RS
1122 return -1;
1123 }
1124
b077fdeb 1125 wait_for_nfs_reply(nfs, &cb_data);
84004dbf
RS
1126
1127 return cb_data.status;
1128}
df5af25f 1129
739df145 1130void mount_getexports_cb(struct rpc_context *mount_context, int status, void *data, void *private_data)
df5af25f
RS
1131{
1132 struct sync_cb_data *cb_data = private_data;
1133 exports export = *(exports *)data;
1134
df5af25f
RS
1135 cb_data->is_finished = 1;
1136 cb_data->status = status;
1137 cb_data->return_data = NULL;
1138
739df145
RS
1139 if (status != 0) {
1140 rpc_set_error(mount_context, "mount/export call failed with \"%s\"", (char *)data);
1141 return;
1142 }
1143
df5af25f
RS
1144 while (export != NULL) {
1145 exports new_export;
1146
1147 new_export = malloc(sizeof(*new_export));
1148 memset(new_export, 0, sizeof(*new_export));
1149 new_export->ex_dir = strdup(export->ex_dir);
1150 new_export->ex_next = cb_data->return_data;
1151
1152 cb_data->return_data = new_export;
1153
1154 export = export->ex_next;
1155 }
1156}
1157
e210bd2a 1158struct exportnode *mount_getexports(const char *server)
df5af25f
RS
1159{
1160 struct sync_cb_data cb_data;
e210bd2a
RS
1161 struct rpc_context *rpc;
1162
df5af25f
RS
1163
1164 cb_data.is_finished = 0;
1165 cb_data.return_data = NULL;
1166
e210bd2a 1167 rpc = rpc_init_context();
df5af25f 1168 if (mount_getexports_async(rpc, server, mount_getexports_cb, &cb_data) != 0) {
e210bd2a 1169 rpc_destroy_context(rpc);
df5af25f
RS
1170 return NULL;
1171 }
1172
1173 wait_for_reply(rpc, &cb_data);
e210bd2a 1174 rpc_destroy_context(rpc);
df5af25f
RS
1175
1176 return cb_data.return_data;
1177}
1178
1179void mount_free_export_list(struct exportnode *exports)
1180{
1181 struct exportnode *tmp;
1182
1183 while ((tmp = exports)) {
1184 exports = exports->ex_next;
1185 free(tmp->ex_dir);
1186 free(tmp);
1187 }
1188}
1189
552c7665
RS
1190
1191
eecdc4f3 1192#if !defined(WIN32)
552c7665
RS
1193void free_nfs_srvr_list(struct nfs_server_list *srv)
1194{
1195 while (srv != NULL) {
1196 struct nfs_server_list *next = srv->next;
1197
1198 free(srv->addr);
1199 free(srv);
1200 srv = next;
1201 }
1202}
1203
1204struct nfs_list_data {
1205 int status;
1206 struct nfs_server_list *srvrs;
1207};
1208
1209void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data)
1210{
1211 struct nfs_list_data *srv_data = private_data;
1212 struct sockaddr *sin;
1213 char hostdd[16];
1214 struct nfs_server_list *srvr;
1215
1216 if (status == RPC_STATUS_CANCEL) {
1217 return;
1218 }
1219 if (status != 0) {
1220 srv_data->status = -1;
1221 return;
1222 }
1223
1224 sin = rpc_get_recv_sockaddr(rpc);
1225 if (sin == NULL) {
1226 rpc_set_error(rpc, "failed to get sockaddr in CALLIT callback");
1227 srv_data->status = -1;
1228 return;
1229 }
1230
1231 if (getnameinfo(sin, sizeof(struct sockaddr_in), &hostdd[0], sizeof(hostdd), NULL, 0, NI_NUMERICHOST) < 0) {
1232 rpc_set_error(rpc, "getnameinfo failed in CALLIT callback");
1233 srv_data->status = -1;
1234 return;
1235 }
552c7665 1236
8c27363e
RS
1237 /* check for dupes */
1238 for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) {
1239 if (!strcmp(hostdd, srvr->addr)) {
11ef53a2 1240 return;
8c27363e
RS
1241 }
1242 }
1243
552c7665
RS
1244 srvr = malloc(sizeof(struct nfs_server_list));
1245 if (srvr == NULL) {
1246 rpc_set_error(rpc, "Malloc failed when allocating server structure");
1247 srv_data->status = -1;
1248 return;
1249 }
1250
1251 srvr->addr = strdup(hostdd);
1252 if (srvr->addr == NULL) {
1253 rpc_set_error(rpc, "Strdup failed when allocating server structure");
1254 free(srvr);
1255 srv_data->status = -1;
1256 return;
1257 }
1258
1259 srvr->next = srv_data->srvrs;
1260 srv_data->srvrs = srvr;
1261}
1262
a8a1b858 1263#ifndef WIN32
e5964ef9 1264static int send_nfsd_probes(struct rpc_context *rpc, struct ifconf *ifc, struct nfs_list_data *data)
552c7665 1265{
1be803ce 1266 char *ptr;
552c7665 1267
e5964ef9 1268 for (ptr =(char *)(ifc->ifc_buf); ptr < (char *)(ifc->ifc_buf) + ifc->ifc_len; ) {
1be803ce 1269 struct ifreq *ifr;
552c7665
RS
1270 char bcdd[16];
1271
1be803ce 1272 ifr = (struct ifreq *)ptr;
9a96dd46 1273#ifdef HAVE_SOCKADDR_LEN
1be803ce
RS
1274 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
1275 ptr += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
1276 } else {
1277 ptr += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
1278 }
1279#else
1280 ptr += sizeof(struct ifreq);
1281#endif
1282
1283 if (ifr->ifr_addr.sa_family != AF_INET) {
552c7665
RS
1284 continue;
1285 }
1be803ce 1286 if (ioctl(rpc_get_fd(rpc), SIOCGIFFLAGS, ifr) < 0) {
e5964ef9 1287 return -1;
552c7665 1288 }
1be803ce 1289 if (!(ifr->ifr_flags & IFF_UP)) {
552c7665
RS
1290 continue;
1291 }
1be803ce 1292 if (ifr->ifr_flags & IFF_LOOPBACK) {
552c7665
RS
1293 continue;
1294 }
1be803ce 1295 if (!(ifr->ifr_flags & IFF_BROADCAST)) {
552c7665
RS
1296 continue;
1297 }
1be803ce 1298 if (ioctl(rpc_get_fd(rpc), SIOCGIFBRDADDR, ifr) < 0) {
1ad6f931 1299 continue;
552c7665 1300 }
1be803ce 1301 if (getnameinfo(&ifr->ifr_broadaddr, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) {
1ad6f931 1302 continue;
552c7665
RS
1303 }
1304 if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) {
e5964ef9
RS
1305 return -1;
1306 }
1307
1308 if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0) {
1309 return -1;
552c7665 1310 }
e5964ef9
RS
1311 }
1312
1313 return 0;
1314}
a8a1b858 1315#endif/*WIN32 TODO implement this with win32api FIXME*/
e5964ef9
RS
1316
1317struct nfs_server_list *nfs_find_local_servers(void)
1318{
1319 struct rpc_context *rpc;
1320 struct nfs_list_data data = {0, NULL};
a8a1b858 1321#ifndef WIN32
e5964ef9
RS
1322 struct timeval tv_start, tv_current;
1323 struct ifconf ifc;
8c27363e 1324 int size, loop;
e5964ef9
RS
1325 struct pollfd pfd;
1326
1327 rpc = rpc_init_udp_context();
1328 if (rpc == NULL) {
1329 return NULL;
1330 }
1331
1332 if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0) {
1333 rpc_destroy_context(rpc);
1334 return NULL;
1335 }
1336
552c7665 1337
e5964ef9
RS
1338 /* get list of all interfaces */
1339 size = sizeof(struct ifreq);
1340 ifc.ifc_buf = NULL;
1341 ifc.ifc_len = size;
1342
1343 while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
1344 size *= 2;
1345
1346 free(ifc.ifc_buf);
1347 ifc.ifc_len = size;
1348 ifc.ifc_buf = malloc(size);
1349 memset(ifc.ifc_buf, 0, size);
1350 if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
552c7665
RS
1351 rpc_destroy_context(rpc);
1352 free(ifc.ifc_buf);
1353 return NULL;
1354 }
e5964ef9
RS
1355 }
1356
8c27363e
RS
1357 for (loop=0; loop<3; loop++) {
1358 if (send_nfsd_probes(rpc, &ifc, &data) != 0) {
552c7665 1359 rpc_destroy_context(rpc);
8c27363e 1360 free(ifc.ifc_buf);
552c7665
RS
1361 return NULL;
1362 }
8c27363e
RS
1363
1364 gettimeofday(&tv_start, NULL);
1365 for(;;) {
1366 int mpt;
1367
1368 pfd.fd = rpc_get_fd(rpc);
1369 pfd.events = rpc_which_events(rpc);
1370
1371 gettimeofday(&tv_current, NULL);
1372 mpt = 1000
1373 - (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
1374 + (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
1375
1376 if (poll(&pfd, 1, mpt) < 0) {
1377 free_nfs_srvr_list(data.srvrs);
1378 rpc_destroy_context(rpc);
1379 return NULL;
1380 }
1381 if (pfd.revents == 0) {
1382 break;
1383 }
552c7665 1384
8c27363e
RS
1385 if (rpc_service(rpc, pfd.revents) < 0) {
1386 break;
1387 }
552c7665
RS
1388 }
1389 }
1390
e5964ef9 1391 free(ifc.ifc_buf);
552c7665
RS
1392 rpc_destroy_context(rpc);
1393
1394 if (data.status != 0) {
1395 free_nfs_srvr_list(data.srvrs);
1396 return NULL;
1397 }
a8a1b858 1398#endif/*WIN32 - FIXME redef it when send_nfsd_probes is implemented for win32*/
552c7665
RS
1399 return data.srvrs;
1400}
eecdc4f3 1401#endif