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