Merge branch 'vendor/TCSH'
[dragonfly.git] / bin / cpdup / hcproto.c
1 /*
2  * HCPROTO.C
3  *
4  * This module implements a simple remote control protocol
5  *
6  * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 dillon Exp $
7  */
8
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
12
13 static int hc_decode_stat(hctransaction_t trans, struct stat *, struct HCHead *);
14 static int hc_decode_stat_item(struct stat *st, struct HCLeaf *item);
15 static int rc_encode_stat(hctransaction_t trans, struct stat *);
16
17 static int rc_hello(hctransaction_t trans, struct HCHead *);
18 static int rc_stat(hctransaction_t trans, struct HCHead *);
19 static int rc_lstat(hctransaction_t trans, struct HCHead *);
20 static int rc_opendir(hctransaction_t trans, struct HCHead *);
21 static int rc_readdir(hctransaction_t trans, struct HCHead *);
22 static int rc_closedir(hctransaction_t trans, struct HCHead *);
23 static int rc_scandir(hctransaction_t trans, struct HCHead *);
24 static int rc_open(hctransaction_t trans, struct HCHead *);
25 static int rc_close(hctransaction_t trans, struct HCHead *);
26 static int rc_read(hctransaction_t trans, struct HCHead *);
27 static int rc_readfile(hctransaction_t trans, struct HCHead *);
28 static int rc_write(hctransaction_t trans, struct HCHead *);
29 static int rc_remove(hctransaction_t trans, struct HCHead *);
30 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
31 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
32 static int rc_chown(hctransaction_t trans, struct HCHead *);
33 static int rc_lchown(hctransaction_t trans, struct HCHead *);
34 static int rc_chmod(hctransaction_t trans, struct HCHead *);
35 static int rc_mknod(hctransaction_t trans, struct HCHead *);
36 static int rc_link(hctransaction_t trans, struct HCHead *);
37 #ifdef _ST_FLAGS_PRESENT_
38 static int rc_chflags(hctransaction_t trans, struct HCHead *);
39 #endif
40 static int rc_readlink(hctransaction_t trans, struct HCHead *);
41 static int rc_umask(hctransaction_t trans, struct HCHead *);
42 static int rc_symlink(hctransaction_t trans, struct HCHead *);
43 static int rc_rename(hctransaction_t trans, struct HCHead *);
44 static int rc_utimes(hctransaction_t trans, struct HCHead *);
45 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
46 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
47
48 static int getmygroups(gid_t **gidlist);
49
50 static int silentwarning(int *, const char *, ...) __printflike(2, 3);
51
52 static struct HCDesc HCDispatchTable[] = {
53     { HC_HELLO,         rc_hello },
54     { HC_STAT,          rc_stat },
55     { HC_LSTAT,         rc_lstat },
56     { HC_OPENDIR,       rc_opendir },
57     { HC_READDIR,       rc_readdir },
58     { HC_CLOSEDIR,      rc_closedir },
59     { HC_OPEN,          rc_open },
60     { HC_CLOSE,         rc_close },
61     { HC_READ,          rc_read },
62     { HC_WRITE,         rc_write },
63     { HC_REMOVE,        rc_remove },
64     { HC_MKDIR,         rc_mkdir },
65     { HC_RMDIR,         rc_rmdir },
66     { HC_CHOWN,         rc_chown },
67     { HC_LCHOWN,        rc_lchown },
68     { HC_CHMOD,         rc_chmod },
69     { HC_MKNOD,         rc_mknod },
70     { HC_LINK,          rc_link },
71 #ifdef _ST_FLAGS_PRESENT_
72     { HC_CHFLAGS,       rc_chflags },
73 #endif
74     { HC_READLINK,      rc_readlink },
75     { HC_UMASK,         rc_umask },
76     { HC_SYMLINK,       rc_symlink },
77     { HC_RENAME,        rc_rename },
78     { HC_UTIMES,        rc_utimes },
79     { HC_GETEUID,       rc_geteuid },
80     { HC_GETGROUPS,     rc_getgroups },
81     { HC_SCANDIR,       rc_scandir },
82     { HC_READFILE,      rc_readfile },
83 };
84
85 static int chown_warning;
86 static int chflags_warning;
87
88 /*
89  * If not running as root generate a silent warning and return no error.
90  *
91  * If running as root return an error.
92  */
93 static int
94 silentwarning(int *didwarn, const char *ctl, ...)
95 {
96     va_list va;
97
98     if (DstRootPrivs)
99         return(-1);
100     if (*didwarn == 0 && QuietOpt == 0) {
101         *didwarn = 1;
102         fprintf(stderr, "WARNING: Not running as root, ");
103         va_start(va, ctl);
104         vfprintf(stderr, ctl, va);
105         va_end(va);
106     }
107     return(0);
108 }
109
110 int
111 hc_connect(struct HostConf *hc, int readonly)
112 {
113     if (hcc_connect(hc, readonly) < 0) {
114         fprintf(stderr, "Unable to connect to %s\n", hc->host);
115         return(-1);
116     }
117     return(hc_hello(hc));
118 }
119
120 void
121 hc_slave(int fdin, int fdout)
122 {
123     hcc_slave(fdin, fdout, HCDispatchTable,
124               sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
125 }
126
127 /*
128  * A HELLO RPC is sent on the initial connect.
129  */
130 int
131 hc_hello(struct HostConf *hc)
132 {
133     struct HCHead *head;
134     struct HCLeaf *item;
135     hctransaction_t trans;
136     char hostbuf[256];
137     int error;
138
139     bzero(hostbuf, sizeof(hostbuf));
140     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
141         return(-1);
142     if (hostbuf[0] == 0)
143         hostbuf[0] = '?';
144
145     trans = hcc_start_command(hc, HC_HELLO);
146     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
147     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
148     if (UseCpFile)
149         hcc_leaf_string(trans, LC_PATH1, UseCpFile);
150     if ((head = hcc_finish_command(trans)) == NULL) {
151         fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
152                 hc->host);
153         return(-1);
154     }
155
156     if (head->error) {
157         fprintf(stderr, "Connected to %s but remote returned error %d\n",
158                 hc->host, head->error);
159         return(-1);
160     }
161
162     error = -1;
163     FOR_EACH_ITEM(item, trans, head) {
164         switch(item->leafid) {
165         case LC_HELLOSTR:
166             if (QuietOpt == 0)
167                 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
168             error = 0;
169             break;
170         case LC_VERSION:
171             hc->version = HCC_INT32(item);
172             break;
173         }
174     }
175     if (hc->version < HCPROTO_VERSION_COMPAT) {
176         fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
177                 hc->host);
178         error = -1;
179     } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
180         fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
181                 "expect reduced speed\n", hc->host);
182     }
183     if (error < 0)
184         fprintf(stderr, "Handshake failed with %s\n", hc->host);
185     return (error);
186 }
187
188 static int
189 rc_hello(hctransaction_t trans, struct HCHead *head)
190 {
191     struct HCLeaf *item;
192     char hostbuf[256];
193
194     FOR_EACH_ITEM(item, trans, head) {
195         if (item->leafid == LC_PATH1)
196             UseCpFile = strdup(HCC_STRING(item));
197     }
198
199     bzero(hostbuf, sizeof(hostbuf));
200     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
201         return(-1);
202     if (hostbuf[0] == 0)
203         hostbuf[0] = '?';
204
205     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
206     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
207     return(0);
208 }
209
210 /*
211  * STAT, LSTAT
212  */
213 int
214 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
215 {
216     struct HCHead *head;
217     hctransaction_t trans;
218
219     if (hc == NULL || hc->host == NULL)
220         return(stat(path, st));
221
222     trans = hcc_start_command(hc, HC_STAT);
223     hcc_leaf_string(trans, LC_PATH1, path);
224     if ((head = hcc_finish_command(trans)) == NULL)
225         return(-1);
226     if (head->error)
227         return(-1);
228     return(hc_decode_stat(trans, st, head));
229 }
230
231 int
232 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
233 {
234     struct HCHead *head;
235     hctransaction_t trans;
236
237     if (hc == NULL || hc->host == NULL)
238         return(lstat(path, st));
239
240     trans = hcc_start_command(hc, HC_LSTAT);
241     hcc_leaf_string(trans, LC_PATH1, path);
242     if ((head = hcc_finish_command(trans)) == NULL)
243         return(-1);
244     if (head->error)
245         return(-1);
246     return(hc_decode_stat(trans, st, head));
247 }
248
249 static int
250 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
251 {
252     struct HCLeaf *item;
253
254     bzero(st, sizeof(*st));
255     FOR_EACH_ITEM(item, trans, head)
256         hc_decode_stat_item(st, item);
257     return(0);
258 }
259
260 static int
261 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
262 {
263     switch(item->leafid) {
264     case LC_DEV:
265         st->st_dev = HCC_INT32(item);
266         break;
267     case LC_INO:
268         st->st_ino = HCC_INT64(item);
269         break;
270     case LC_MODE:
271         st->st_mode = HCC_INT32(item);
272         break;
273     case LC_NLINK:
274         st->st_nlink = HCC_INT32(item);
275         break;
276     case LC_UID:
277         st->st_uid = HCC_INT32(item);
278         break;
279     case LC_GID:
280         st->st_gid = HCC_INT32(item);
281         break;
282     case LC_RDEV:
283         st->st_rdev = HCC_INT32(item);
284         break;
285     case LC_ATIME:
286         st->st_atime = (time_t)HCC_INT64(item);
287         break;
288     case LC_MTIME:
289         st->st_mtime = (time_t)HCC_INT64(item);
290         break;
291     case LC_CTIME:
292         st->st_ctime = (time_t)HCC_INT64(item);
293         break;
294     case LC_FILESIZE:
295         st->st_size = HCC_INT64(item);
296         break;
297     case LC_FILEBLKS:
298         st->st_blocks = HCC_INT64(item);
299         break;
300     case LC_BLKSIZE:
301         st->st_blksize = HCC_INT32(item);
302         break;
303 #ifdef _ST_FSMID_PRESENT_
304     case LC_FSMID:
305         st->st_fsmid = HCC_INT64(item);
306         break;
307 #endif
308 #ifdef _ST_FLAGS_PRESENT_
309     case LC_FILEFLAGS:
310         st->st_flags = (uint32_t)HCC_INT64(item);
311         break;
312 #endif
313     }
314     return(0);
315 }
316
317 static int
318 rc_stat(hctransaction_t trans, struct HCHead *head)
319 {
320     struct HCLeaf *item;
321     struct stat st;
322     const char *path = NULL;
323
324     FOR_EACH_ITEM(item, trans, head) {
325         if (item->leafid == LC_PATH1)
326             path = HCC_STRING(item);
327     }
328     if (path == NULL)
329         return(-2);
330     if (stat(path, &st) < 0)
331         return(-1);
332     return (rc_encode_stat(trans, &st));
333 }
334
335 static int
336 rc_lstat(hctransaction_t trans, struct HCHead *head)
337 {
338     struct HCLeaf *item;
339     struct stat st;
340     const char *path = NULL;
341
342     FOR_EACH_ITEM(item, trans, head) {
343         if (item->leafid == LC_PATH1)
344             path = HCC_STRING(item);
345     }
346     if (path == NULL)
347         return(-2);
348     if (lstat(path, &st) < 0)
349         return(-1);
350     return (rc_encode_stat(trans, &st));
351 }
352
353 /*
354  * Encode all entries of a stat structure.
355  *
356  * CAUTION:  If you add any more entries here, be sure to
357  *           increase the STAT_MAX_NUM_ENTRIES value!
358  */
359 #define STAT_MAX_NUM_ENTRIES 18
360 static int
361 rc_encode_stat(hctransaction_t trans, struct stat *st)
362 {
363     hcc_leaf_int32(trans, LC_DEV, st->st_dev);
364     hcc_leaf_int64(trans, LC_INO, st->st_ino);
365     hcc_leaf_int32(trans, LC_MODE, st->st_mode);
366     hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
367     hcc_leaf_int32(trans, LC_UID, st->st_uid);
368     hcc_leaf_int32(trans, LC_GID, st->st_gid);
369     hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
370     hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
371     hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
372     hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
373     hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
374     hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
375     hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
376 #ifdef _ST_FSMID_PRESENT_
377     hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
378 #endif
379 #ifdef _ST_FLAGS_PRESENT_
380     hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
381 #endif
382     return(0);
383 }
384
385 /*
386  * OPENDIR
387  */
388 DIR *
389 hc_opendir(struct HostConf *hc, const char *path)
390 {
391     hctransaction_t trans;
392     struct HCHead *head;
393
394     if (hc == NULL || hc->host == NULL)
395         return(opendir(path));
396
397     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
398         struct HCLeaf *item;
399         struct HCDirEntry *den;
400         intptr_t desc = 0;
401
402         trans = hcc_start_command(hc, HC_OPENDIR);
403         hcc_leaf_string(trans, LC_PATH1, path);
404         if ((head = hcc_finish_command(trans)) == NULL)
405             return (NULL);
406         if (head->error)
407             return (NULL);
408         FOR_EACH_ITEM(item, trans, head) {
409             if (item->leafid == LC_DESCRIPTOR)
410                 desc = HCC_INT32(item);
411         }
412         if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
413             fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
414                 (intmax_t)desc);
415             return (NULL);
416         }
417         den = malloc(sizeof(*den));
418         hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
419         return ((void *)desc);
420     }
421
422     /* hc->version >= 4: use HC_SCANDIR */
423     trans = hcc_start_command(hc, HC_SCANDIR);
424     hcc_leaf_string(trans, LC_PATH1, path);
425     if ((head = hcc_finish_command(trans)) == NULL || head->error)
426         return (NULL);
427     return ((void *)head);
428 }
429
430 static int
431 rc_opendir(hctransaction_t trans, struct HCHead *head)
432 {
433     struct HCLeaf *item;
434     const char *path = NULL;
435     DIR *dir;
436     int desc;
437
438     FOR_EACH_ITEM(item, trans, head) {
439         if (item->leafid == LC_PATH1)
440             path = HCC_STRING(item);
441     }
442     if (path == NULL)
443         return(-2);
444     if ((dir = opendir(path)) == NULL) {
445         head->error = errno;
446     } else {
447         desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
448         hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
449     }
450     return(0);
451 }
452
453 /*
454  * READDIR
455  */
456 struct HCDirEntry *
457 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
458 {
459     int stat_ok = 0;
460     struct HCHead *head;
461     struct HCLeaf *item;
462     static struct HCDirEntry denbuf;
463
464     *statpp = NULL;
465     if (hc == NULL || hc->host == NULL) {
466         struct dirent *sysden;
467
468         if ((sysden = readdir(dir)) == NULL)
469             return (NULL);
470         strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
471         return (&denbuf);
472     }
473
474     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
475         hctransaction_t trans;
476         struct HCDirEntry *den;
477
478         trans = hcc_start_command(hc, HC_READDIR);
479         hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
480         if ((head = hcc_finish_command(trans)) == NULL)
481             return (NULL);
482         if (head->error)
483             return (NULL);      /* XXX errno */
484         den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
485         if (den == NULL)
486             return (NULL);      /* XXX errno */
487         den->d_name[0] = 0;
488         FOR_EACH_ITEM(item, trans, head) {
489             if (item->leafid == LC_PATH1)
490                 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
491         }
492         return (den->d_name[0] ? den : NULL);
493     }
494
495     /* hc->version >= 4: using HC_SCANDIR */
496     denbuf.d_name[0] = 0;
497     head = (void *)dir;
498     *statpp = malloc(sizeof(struct stat));
499     bzero(*statpp, sizeof(struct stat));
500     while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
501         if (item->leafid == LC_PATH1) {  /* this must be the last item */
502             strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
503             break;
504         } else {
505             stat_ok = 1;
506             hc_decode_stat_item(*statpp, item);
507         }
508     }
509     if (!stat_ok) {
510         free(*statpp);
511         *statpp = NULL;
512     }
513     return (denbuf.d_name[0] ? &denbuf : NULL);
514 }
515
516 static int
517 rc_readdir(hctransaction_t trans, struct HCHead *head)
518 {
519     struct HCLeaf *item;
520     struct dirent *den;
521     DIR *dir = NULL;
522
523     FOR_EACH_ITEM(item, trans, head) {
524         if (item->leafid == LC_DESCRIPTOR)
525             dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
526     }
527     if (dir == NULL)
528         return(-2);
529     if ((den = readdir(dir)) != NULL)
530         hcc_leaf_string(trans, LC_PATH1, den->d_name);
531     return(0);
532 }
533
534 /*
535  * CLOSEDIR
536  *
537  * XXX cpdup needs to check error code to avoid truncated dirs?
538  */
539 int
540 hc_closedir(struct HostConf *hc, DIR *dir)
541 {
542     struct HCHead *head;
543
544     if (hc == NULL || hc->host == NULL)
545         return(closedir(dir));
546
547     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
548         hctransaction_t trans;
549         struct dirent *den;
550
551         if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
552             free(den);
553             hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
554             trans = hcc_start_command(hc, HC_CLOSEDIR);
555             hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
556             if ((head = hcc_finish_command(trans)) == NULL)
557                 return (-1);
558             if (head->error)
559                 return (-1);            /* XXX errno */
560             return (0);
561         } else {
562             /* errno */
563             return(-1);
564         }
565     }
566
567     /* hc->version >= 4: using HC_SCANDIR */
568     head = (void *)dir;
569     /* skip any remaining items if the directory is closed prematurely */
570     while (hcc_nextchaineditem(hc, head) != NULL)
571         /*nothing*/ ;
572     if (head->error)
573         return (-1);
574     return (0);
575 }
576
577 static int
578 rc_closedir(hctransaction_t trans, struct HCHead *head)
579 {
580     struct HCLeaf *item;
581     DIR *dir = NULL;
582
583     FOR_EACH_ITEM(item, trans, head) {
584         if (item->leafid == LC_DESCRIPTOR) {
585             dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
586             if (dir != NULL) {
587                     hcc_set_descriptor(trans->hc, HCC_INT32(item),
588                                        NULL, HC_DESC_DIR);
589             }
590         }
591     }
592     if (dir == NULL)
593         return(-2);
594     return(closedir(dir));
595 }
596
597 /*
598  * SCANDIR
599  */
600 static int
601 rc_scandir(hctransaction_t trans, struct HCHead *head)
602 {
603     struct HCLeaf *item;
604     const char *path = NULL;
605     struct dirent *den;
606     DIR *dir;
607     char *fpath;
608     struct stat st;
609
610     FOR_EACH_ITEM(item, trans, head) {
611         if (item->leafid == LC_PATH1)
612             path = HCC_STRING(item);
613     }
614     if (path == NULL)
615         return (-2);
616     if ((dir = opendir(path)) == NULL)
617         return (-1);
618     while ((den = readdir(dir)) != NULL) {
619         if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
620                 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
621             continue;   /* skip "." and ".." */
622         /*
623          * Check if there's enough space left in the current packet.
624          * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
625          * one is a string, so we use strlen() + 1 (terminating zero).
626          * The remaining ones are numbers; we assume sizeof(int64_t) so
627          * we're on the safe side.
628          */
629         if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
630                 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
631                 strlen(den->d_name) + 1)) {
632             closedir(dir);
633             return (-1);
634         }
635         fpath = mprintf("%s/%s", path, den->d_name);
636         if (lstat(fpath, &st) == 0)
637             rc_encode_stat(trans, &st);
638         /* The name must be the last item! */
639         hcc_leaf_string(trans, LC_PATH1, den->d_name);
640         free(fpath);
641     }
642     return (closedir(dir));
643 }
644
645 /*
646  * OPEN
647  */
648 int
649 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
650 {
651     hctransaction_t trans;
652     struct HCHead *head;
653     struct HCLeaf *item;
654     int *fdp;
655     int desc = 0;
656     int nflags;
657
658     if (NotForRealOpt && (flags & O_CREAT))
659         return(0x7FFFFFFF);
660
661     if (hc == NULL || hc->host == NULL) {
662 #ifdef O_LARGEFILE
663         flags |= O_LARGEFILE;
664 #endif
665         return(open(path, flags, mode));
666     }
667
668     if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
669         trans = hcc_start_command(hc, HC_READFILE);
670         hcc_leaf_string(trans, LC_PATH1, path);
671         if ((head = hcc_finish_command(trans)) == NULL || head->error)
672             return (-1);
673         head->magic = 0; /* used to indicate offset within buffer */
674         return (1); /* dummy */
675     }
676
677     nflags = flags & XO_NATIVEMASK;
678     if (flags & O_CREAT)
679         nflags |= XO_CREAT;
680     if (flags & O_EXCL)
681         nflags |= XO_EXCL;
682     if (flags & O_TRUNC)
683         nflags |= XO_TRUNC;
684
685     trans = hcc_start_command(hc, HC_OPEN);
686     hcc_leaf_string(trans, LC_PATH1, path);
687     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
688     hcc_leaf_int32(trans, LC_MODE, mode);
689
690     if ((head = hcc_finish_command(trans)) == NULL)
691         return(-1);
692     if (head->error)
693         return(-1);
694     FOR_EACH_ITEM(item, trans, head) {
695         if (item->leafid == LC_DESCRIPTOR)
696             desc = HCC_INT32(item);
697     }
698     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
699         fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
700                 desc);
701         return(-1);
702     }
703     fdp = malloc(sizeof(int));
704     *fdp = desc;        /* really just a dummy */
705     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
706     return(desc);
707 }
708
709 static int
710 rc_open(hctransaction_t trans, struct HCHead *head)
711 {
712     struct HCLeaf *item;
713     const char *path = NULL;
714     int nflags = 0;
715     int flags;
716     mode_t mode = 0666;
717     int desc;
718     int *fdp;
719     int fd;
720
721     FOR_EACH_ITEM(item, trans, head) {
722         switch(item->leafid) {
723         case LC_PATH1:
724             path = HCC_STRING(item);
725             break;
726         case LC_OFLAGS:
727             nflags = HCC_INT32(item);
728             break;
729         case LC_MODE:
730             mode = HCC_INT32(item);
731             break;
732         }
733     }
734     if (path == NULL)
735         return(-2);
736
737     flags = nflags & XO_NATIVEMASK;
738     if (nflags & XO_CREAT)
739         flags |= O_CREAT;
740     if (nflags & XO_EXCL)
741         flags |= O_EXCL;
742     if (nflags & XO_TRUNC)
743         flags |= O_TRUNC;
744
745     if (ReadOnlyOpt) {
746         if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
747             head->error = EACCES;
748             return (0);
749         }
750         flags |= O_RDONLY;
751     }
752
753 #ifdef O_LARGEFILE
754     flags |= O_LARGEFILE;
755 #endif
756     if ((fd = open(path, flags, mode)) < 0)
757         return(-1);
758     fdp = malloc(sizeof(int));
759     *fdp = fd;
760     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
761     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
762     return(0);
763 }
764
765 /*
766  * CLOSE
767  */
768 int
769 hc_close(struct HostConf *hc, int fd)
770 {
771     hctransaction_t trans;
772     struct HCHead *head;
773     int *fdp;
774
775     if (NotForRealOpt && fd == 0x7FFFFFFF)
776         return(0);
777     if (hc == NULL || hc->host == NULL)
778         return(close(fd));
779
780     if (fd == 1 && hc->version >= 4) {  /* using HC_READFILE */
781         head = (void *)hc->trans.rbuf;
782         /* skip any remaining items if the file is closed prematurely */
783         while (hcc_nextchaineditem(hc, head) != NULL)
784             /*nothing*/ ;
785         if (head->error)
786             return (-1);
787         return (0);
788     }
789
790     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
791     if (fdp) {
792         free(fdp);
793         hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
794
795         trans = hcc_start_command(hc, HC_CLOSE);
796         hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
797         if ((head = hcc_finish_command(trans)) == NULL)
798             return(-1);
799         if (head->error)
800             return(-1);
801         return(0);
802     } else {
803         return(-1);
804     }
805 }
806
807 static int
808 rc_close(hctransaction_t trans, struct HCHead *head)
809 {
810     struct HCLeaf *item;
811     int *fdp = NULL;
812     int fd;
813     int desc = -1;
814
815     FOR_EACH_ITEM(item, trans, head) {
816         if (item->leafid == LC_DESCRIPTOR)
817             desc = HCC_INT32(item);
818     }
819     if (desc < 0)
820         return(-2);
821     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
822         return(-2);
823     fd = *fdp;
824     free(fdp);
825     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
826     return(close(fd));
827 }
828
829 static int
830 getiolimit(void)
831 {
832     return(32768);
833 }
834
835 /*
836  * READ
837  */
838 ssize_t
839 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
840 {
841     hctransaction_t trans;
842     struct HCHead *head;
843     struct HCLeaf *item;
844     int *fdp;
845     int offset;
846     int r = 0;
847     int x = 0;
848
849     if (hc == NULL || hc->host == NULL)
850         return(read(fd, buf, bytes));
851
852     if (fd == 1 && hc->version >= 4) {  /* using HC_READFILE */
853         head = (void *)hc->trans.rbuf;
854         while (bytes) {
855             if ((offset = head->magic) != 0)
856                 item = hcc_currentchaineditem(hc, head);
857             else
858                 item = hcc_nextchaineditem(hc, head);
859             if (item == NULL)
860                 return (r);
861             if (item->leafid != LC_DATA)
862                 return (-1);
863             x = item->bytes - sizeof(*item) - offset;
864             if (x > (int)bytes) {
865                 x = (int)bytes;
866                 head->magic += x;  /* leave bytes in the buffer */
867             }
868             else
869                 head->magic = 0;  /* all bytes used up */
870             bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
871             buf = (char *)buf + x;
872             bytes -= (size_t)x;
873             r += x;
874         }
875         return (r);
876     }
877
878     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
879     if (fdp) {
880         while (bytes) {
881             size_t limit = getiolimit();
882             int n = (bytes > limit) ? limit : bytes;
883
884             trans = hcc_start_command(hc, HC_READ);
885             hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
886             hcc_leaf_int32(trans, LC_BYTES, n);
887             if ((head = hcc_finish_command(trans)) == NULL)
888                 return(-1);
889             if (head->error)
890                 return(-1);
891             FOR_EACH_ITEM(item, trans, head) {
892                 if (item->leafid == LC_DATA) {
893                     x = item->bytes - sizeof(*item);
894                     if (x > (int)bytes)
895                         x = (int)bytes;
896                     bcopy(HCC_BINARYDATA(item), buf, x);
897                     buf = (char *)buf + x;
898                     bytes -= (size_t)x;
899                     r += x;
900                 }
901             }
902             if (x < n)
903                 break;
904         }
905         return(r);
906     } else {
907         return(-1);
908     }
909 }
910
911 static int
912 rc_read(hctransaction_t trans, struct HCHead *head)
913 {
914     struct HCLeaf *item;
915     int *fdp = NULL;
916     char buf[32768];
917     int bytes = -1;
918     int n;
919
920     FOR_EACH_ITEM(item, trans, head) {
921         switch(item->leafid) {
922         case LC_DESCRIPTOR:
923             fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
924             break;
925         case LC_BYTES:
926             bytes = HCC_INT32(item);
927             break;
928         }
929     }
930     if (fdp == NULL)
931         return(-2);
932     if (bytes < 0 || bytes > 32768)
933         return(-2);
934     n = read(*fdp, buf, bytes);
935     if (n < 0)
936         return(-1);
937     hcc_leaf_data(trans, LC_DATA, buf, n);
938     return(0);
939 }
940
941 /*
942  * READFILE
943  */
944 static int
945 rc_readfile(hctransaction_t trans, struct HCHead *head)
946 {
947     struct HCLeaf *item;
948     const char *path = NULL;
949     char buf[32768];
950     int n;
951     int fd;
952
953     FOR_EACH_ITEM(item, trans, head) {
954         if (item->leafid == LC_PATH1)
955             path = HCC_STRING(item);
956     }
957     if (path == NULL)
958         return (-2);
959     if ((fd = open(path, O_RDONLY)) < 0)
960         return(-1);
961     while ((n = read(fd, buf, 32768)) >= 0) {
962         if (!hcc_check_space(trans, head, 1, n)) {
963             close(fd);
964             return (-1);
965         }
966         hcc_leaf_data(trans, LC_DATA, buf, n);
967         if (n == 0)
968                 break;
969     }
970     if (n < 0) {
971         close(fd);
972         return (-1);
973     }
974     return (close(fd));
975 }
976
977 /*
978  * WRITE
979  */
980 ssize_t
981 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
982 {
983     hctransaction_t trans;
984     struct HCHead *head;
985     struct HCLeaf *item;
986     int *fdp;
987     int r;
988
989     if (NotForRealOpt)
990         return(bytes);
991
992     if (hc == NULL || hc->host == NULL)
993         return(write(fd, buf, bytes));
994
995     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
996     if (fdp) {
997         r = 0;
998         while (bytes) {
999             size_t limit = getiolimit();
1000             int n = (bytes > limit) ? limit : bytes;
1001             int x = 0;
1002
1003             trans = hcc_start_command(hc, HC_WRITE);
1004             hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1005             hcc_leaf_data(trans, LC_DATA, buf, n);
1006             if ((head = hcc_finish_command(trans)) == NULL)
1007                 return(-1);
1008             if (head->error)
1009                 return(-1);
1010             FOR_EACH_ITEM(item, trans, head) {
1011                 if (item->leafid == LC_BYTES)
1012                     x = HCC_INT32(item);
1013             }
1014             if (x < 0 || x > n)
1015                 return(-1);
1016             r += x;
1017             buf = (const char *)buf + x;
1018             bytes -= x;
1019             if (x < n)
1020                 break;
1021         }
1022         return(r);
1023     } else {
1024         return(-1);
1025     }
1026 }
1027
1028 static int
1029 rc_write(hctransaction_t trans, struct HCHead *head)
1030 {
1031     struct HCLeaf *item;
1032     int *fdp = NULL;
1033     void *buf = NULL;
1034     int n = -1;
1035
1036     FOR_EACH_ITEM(item, trans, head) {
1037         switch(item->leafid) {
1038         case LC_DESCRIPTOR:
1039             fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1040             break;
1041         case LC_DATA:
1042             buf = HCC_BINARYDATA(item);
1043             n = item->bytes - sizeof(*item);
1044             break;
1045         }
1046     }
1047     if (ReadOnlyOpt) {
1048         head->error = EACCES;
1049         return (0);
1050     }
1051     if (fdp == NULL)
1052         return(-2);
1053     if (n < 0 || n > 32768)
1054         return(-2);
1055     n = write(*fdp, buf, n);
1056     if (n < 0)
1057         return (-1);
1058     hcc_leaf_int32(trans, LC_BYTES, n);
1059     return(0);
1060 }
1061
1062 /*
1063  * REMOVE
1064  *
1065  * NOTE: This function returns -errno if an error occured.
1066  */
1067 int
1068 hc_remove(struct HostConf *hc, const char *path)
1069 {
1070     hctransaction_t trans;
1071     struct HCHead *head;
1072     int res;
1073
1074     if (NotForRealOpt)
1075         return(0);
1076     if (hc == NULL || hc->host == NULL) {
1077         res = remove(path);
1078         if (res < 0)
1079                 res = -errno;
1080         return(res);
1081     }
1082
1083     trans = hcc_start_command(hc, HC_REMOVE);
1084     hcc_leaf_string(trans, LC_PATH1, path);
1085     if ((head = hcc_finish_command(trans)) == NULL)
1086         return(-EIO);
1087     if (head->error)
1088         return(-(int)head->error);
1089     return(0);
1090 }
1091
1092 static int
1093 rc_remove(hctransaction_t trans, struct HCHead *head)
1094 {
1095     struct HCLeaf *item;
1096     const char *path = NULL;
1097
1098     FOR_EACH_ITEM(item, trans, head) {
1099         if (item->leafid == LC_PATH1)
1100             path = HCC_STRING(item);
1101     }
1102     if (path == NULL)
1103         return(-2);
1104     if (ReadOnlyOpt) {
1105         head->error = EACCES;
1106         return (0);
1107     }
1108     return(remove(path));
1109 }
1110
1111 /*
1112  * MKDIR
1113  */
1114 int
1115 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1116 {
1117     hctransaction_t trans;
1118     struct HCHead *head;
1119
1120     if (NotForRealOpt)
1121         return(0);
1122     if (hc == NULL || hc->host == NULL)
1123         return(mkdir(path, mode));
1124
1125     trans = hcc_start_command(hc, HC_MKDIR);
1126     hcc_leaf_string(trans, LC_PATH1, path);
1127     hcc_leaf_int32(trans, LC_MODE, mode);
1128     if ((head = hcc_finish_command(trans)) == NULL)
1129         return(-1);
1130     if (head->error)
1131         return(-1);
1132     return(0);
1133 }
1134
1135 static int
1136 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1137 {
1138     struct HCLeaf *item;
1139     const char *path = NULL;
1140     mode_t mode = 0777;
1141
1142     FOR_EACH_ITEM(item, trans, head) {
1143         switch(item->leafid) {
1144         case LC_PATH1:
1145             path = HCC_STRING(item);
1146             break;
1147         case LC_MODE:
1148             mode = HCC_INT32(item);
1149             break;
1150         }
1151     }
1152     if (ReadOnlyOpt) {
1153         head->error = EACCES;
1154         return (0);
1155     }
1156     if (path == NULL)
1157         return(-2);
1158     return(mkdir(path, mode));
1159 }
1160
1161 /*
1162  * RMDIR
1163  */
1164 int
1165 hc_rmdir(struct HostConf *hc, const char *path)
1166 {
1167     hctransaction_t trans;
1168     struct HCHead *head;
1169
1170     if (NotForRealOpt)
1171         return(0);
1172     if (hc == NULL || hc->host == NULL)
1173         return(rmdir(path));
1174
1175     trans = hcc_start_command(hc, HC_RMDIR);
1176     hcc_leaf_string(trans, LC_PATH1, path);
1177     if ((head = hcc_finish_command(trans)) == NULL)
1178         return(-1);
1179     if (head->error)
1180         return(-1);
1181     return(0);
1182 }
1183
1184 static int
1185 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1186 {
1187     struct HCLeaf *item;
1188     const char *path = NULL;
1189
1190     FOR_EACH_ITEM(item, trans, head) {
1191         if (item->leafid == LC_PATH1)
1192             path = HCC_STRING(item);
1193     }
1194     if (ReadOnlyOpt) {
1195         head->error = EACCES;
1196         return (0);
1197     }
1198     if (path == NULL)
1199         return(-2);
1200     return(rmdir(path));
1201 }
1202
1203 /*
1204  * CHOWN
1205  *
1206  * Almost silently ignore chowns that fail if we are not root.
1207  */
1208 int
1209 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1210 {
1211     hctransaction_t trans;
1212     struct HCHead *head;
1213     int rc;
1214
1215     if (NotForRealOpt)
1216         return(0);
1217     if (!DstRootPrivs)
1218         owner = -1;
1219
1220     if (hc == NULL || hc->host == NULL) {
1221         rc = chown(path, owner, group);
1222         if (rc < 0)
1223             rc = silentwarning(&chown_warning, "file ownership may differ\n");
1224         return(rc);
1225     }
1226
1227     trans = hcc_start_command(hc, HC_CHOWN);
1228     hcc_leaf_string(trans, LC_PATH1, path);
1229     hcc_leaf_int32(trans, LC_UID, owner);
1230     hcc_leaf_int32(trans, LC_GID, group);
1231     if ((head = hcc_finish_command(trans)) == NULL)
1232         return(-1);
1233     if (head->error)
1234         return(-1);
1235     return(0);
1236 }
1237
1238 static int
1239 rc_chown(hctransaction_t trans, struct HCHead *head)
1240 {
1241     struct HCLeaf *item;
1242     const char *path = NULL;
1243     uid_t uid = (uid_t)-1;
1244     gid_t gid = (gid_t)-1;
1245     int rc;
1246
1247     FOR_EACH_ITEM(item, trans, head) {
1248         switch(item->leafid) {
1249         case LC_PATH1:
1250             path = HCC_STRING(item);
1251             break;
1252         case LC_UID:
1253             uid = HCC_INT32(item);
1254             break;
1255         case LC_GID:
1256             gid = HCC_INT32(item);
1257             break;
1258         }
1259     }
1260     if (ReadOnlyOpt) {
1261         head->error = EACCES;
1262         return (0);
1263     }
1264     if (path == NULL)
1265         return(-2);
1266     rc = chown(path, uid, gid);
1267     if (rc < 0)
1268         rc = silentwarning(&chown_warning, "file ownership may differ\n");
1269     return(rc);
1270 }
1271
1272 /*
1273  * LCHOWN
1274  */
1275 int
1276 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1277 {
1278     hctransaction_t trans;
1279     struct HCHead *head;
1280     int rc;
1281
1282     if (NotForRealOpt)
1283         return(0);
1284     if (!DstRootPrivs)
1285         owner = -1;
1286
1287     if (hc == NULL || hc->host == NULL) {
1288         rc = lchown(path, owner, group);
1289         if (rc < 0)
1290             rc = silentwarning(&chown_warning, "file ownership may differ\n");
1291         return(rc);
1292     }
1293
1294     trans = hcc_start_command(hc, HC_LCHOWN);
1295     hcc_leaf_string(trans, LC_PATH1, path);
1296     hcc_leaf_int32(trans, LC_UID, owner);
1297     hcc_leaf_int32(trans, LC_GID, group);
1298     if ((head = hcc_finish_command(trans)) == NULL)
1299         return(-1);
1300     if (head->error)
1301         return(-1);
1302     return(0);
1303 }
1304
1305 static int
1306 rc_lchown(hctransaction_t trans, struct HCHead *head)
1307 {
1308     struct HCLeaf *item;
1309     const char *path = NULL;
1310     uid_t uid = (uid_t)-1;
1311     gid_t gid = (gid_t)-1;
1312     int rc;
1313
1314     FOR_EACH_ITEM(item, trans, head) {
1315         switch(item->leafid) {
1316         case LC_PATH1:
1317             path = HCC_STRING(item);
1318             break;
1319         case LC_UID:
1320             uid = HCC_INT32(item);
1321             break;
1322         case LC_GID:
1323             gid = HCC_INT32(item);
1324             break;
1325         }
1326     }
1327     if (ReadOnlyOpt) {
1328         head->error = EACCES;
1329         return (0);
1330     }
1331     if (path == NULL)
1332         return(-2);
1333     rc = lchown(path, uid, gid);
1334     if (rc < 0)
1335         rc = silentwarning(&chown_warning, "file ownership may differ\n");
1336     return(rc);
1337 }
1338
1339 /*
1340  * CHMOD
1341  */
1342 int
1343 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1344 {
1345     hctransaction_t trans;
1346     struct HCHead *head;
1347
1348     if (NotForRealOpt)
1349         return(0);
1350     if (hc == NULL || hc->host == NULL)
1351         return(chmod(path, mode));
1352
1353     trans = hcc_start_command(hc, HC_CHMOD);
1354     hcc_leaf_string(trans, LC_PATH1, path);
1355     hcc_leaf_int32(trans, LC_MODE, mode);
1356     if ((head = hcc_finish_command(trans)) == NULL)
1357         return(-1);
1358     if (head->error)
1359         return(-1);
1360     return(0);
1361 }
1362
1363 static int
1364 rc_chmod(hctransaction_t trans, struct HCHead *head)
1365 {
1366     struct HCLeaf *item;
1367     const char *path = NULL;
1368     mode_t mode = 0666;
1369
1370     FOR_EACH_ITEM(item, trans, head) {
1371         switch(item->leafid) {
1372         case LC_PATH1:
1373             path = HCC_STRING(item);
1374             break;
1375         case LC_MODE:
1376             mode = HCC_INT32(item);
1377             break;
1378         }
1379     }
1380     if (ReadOnlyOpt) {
1381         head->error = EACCES;
1382         return (0);
1383     }
1384     if (path == NULL)
1385         return(-2);
1386     return(chmod(path, mode));
1387 }
1388
1389 /*
1390  * MKNOD
1391  */
1392 int
1393 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1394 {
1395     hctransaction_t trans;
1396     struct HCHead *head;
1397
1398     if (NotForRealOpt)
1399         return(0);
1400     if (!DstRootPrivs) {
1401         /* mknod() requires root privs, so don't bother. */
1402         errno = EPERM;
1403         return (-1);
1404     }
1405
1406     if (hc == NULL || hc->host == NULL)
1407         return(mknod(path, mode, rdev));
1408
1409     trans = hcc_start_command(hc, HC_MKNOD);
1410     hcc_leaf_string(trans, LC_PATH1, path);
1411     hcc_leaf_int32(trans, LC_MODE, mode);
1412     hcc_leaf_int32(trans, LC_RDEV, rdev);
1413     if ((head = hcc_finish_command(trans)) == NULL)
1414         return(-1);
1415     if (head->error)
1416         return(-1);
1417     return(0);
1418 }
1419
1420 static int
1421 rc_mknod(hctransaction_t trans, struct HCHead *head)
1422 {
1423     struct HCLeaf *item;
1424     const char *path = NULL;
1425     mode_t mode = 0666;
1426     dev_t rdev = 0;
1427
1428     FOR_EACH_ITEM(item, trans, head) {
1429         switch(item->leafid) {
1430         case LC_PATH1:
1431             path = HCC_STRING(item);
1432             break;
1433         case LC_MODE:
1434             mode = HCC_INT32(item);
1435             break;
1436         case LC_RDEV:
1437             rdev = HCC_INT32(item);
1438             break;
1439         }
1440     }
1441     if (ReadOnlyOpt) {
1442         head->error = EACCES;
1443         return (0);
1444     }
1445     if (path == NULL)
1446         return(-2);
1447     return(mknod(path, mode, rdev));
1448 }
1449
1450 /*
1451  * LINK
1452  */
1453 int
1454 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1455 {
1456     hctransaction_t trans;
1457     struct HCHead *head;
1458
1459     if (NotForRealOpt)
1460         return(0);
1461     if (hc == NULL || hc->host == NULL)
1462         return(link(name1, name2));
1463
1464     trans = hcc_start_command(hc, HC_LINK);
1465     hcc_leaf_string(trans, LC_PATH1, name1);
1466     hcc_leaf_string(trans, LC_PATH2, name2);
1467     if ((head = hcc_finish_command(trans)) == NULL)
1468         return(-1);
1469     if (head->error)
1470         return(-1);
1471     return(0);
1472 }
1473
1474 static int
1475 rc_link(hctransaction_t trans, struct HCHead *head)
1476 {
1477     struct HCLeaf *item;
1478     const char *name1 = NULL;
1479     const char *name2 = NULL;
1480
1481     FOR_EACH_ITEM(item, trans, head) {
1482         switch(item->leafid) {
1483         case LC_PATH1:
1484             name1 = HCC_STRING(item);
1485             break;
1486         case LC_PATH2:
1487             name2 = HCC_STRING(item);
1488             break;
1489         }
1490     }
1491     if (ReadOnlyOpt) {
1492         head->error = EACCES;
1493         return (-0);
1494     }
1495     if (name1 == NULL || name2 == NULL)
1496         return(-2);
1497     return(link(name1, name2));
1498 }
1499
1500 #ifdef _ST_FLAGS_PRESENT_
1501 /*
1502  * CHFLAGS
1503  */
1504 int
1505 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1506 {
1507     hctransaction_t trans;
1508     struct HCHead *head;
1509     int rc;
1510
1511     if (NotForRealOpt)
1512         return(0);
1513     if (!DstRootPrivs)
1514         flags &= UF_SETTABLE;
1515
1516     if (hc == NULL || hc->host == NULL) {
1517         if ((rc = chflags(path, flags)) < 0)
1518             rc = silentwarning(&chflags_warning, "file flags may differ\n");
1519         return (rc);
1520     }
1521
1522     trans = hcc_start_command(hc, HC_CHFLAGS);
1523     hcc_leaf_string(trans, LC_PATH1, path);
1524     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1525     if ((head = hcc_finish_command(trans)) == NULL)
1526         return(-1);
1527     if (head->error)
1528         return(-1);
1529     return(0);
1530 }
1531
1532 static int
1533 rc_chflags(hctransaction_t trans, struct HCHead *head)
1534 {
1535     struct HCLeaf *item;
1536     const char *path = NULL;
1537     u_long flags = 0;
1538     int rc;
1539
1540     FOR_EACH_ITEM(item, trans, head) {
1541         switch(item->leafid) {
1542         case LC_PATH1:
1543             path = HCC_STRING(item);
1544             break;
1545         case LC_FILEFLAGS:
1546             flags = (u_long)HCC_INT64(item);
1547             break;
1548         }
1549     }
1550     if (ReadOnlyOpt) {
1551         head->error = EACCES;
1552         return (0);
1553     }
1554     if (path == NULL)
1555         return(-2);
1556     if ((rc = chflags(path, flags)) < 0)
1557         rc = silentwarning(&chflags_warning, "file flags may differ\n");
1558     return(rc);
1559 }
1560
1561 #endif
1562
1563 /*
1564  * READLINK
1565  */
1566 int
1567 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1568 {
1569     hctransaction_t trans;
1570     struct HCHead *head;
1571     struct HCLeaf *item;
1572     int r;
1573
1574     if (hc == NULL || hc->host == NULL)
1575         return(readlink(path, buf, bufsiz));
1576
1577     trans = hcc_start_command(hc, HC_READLINK);
1578     hcc_leaf_string(trans, LC_PATH1, path);
1579     if ((head = hcc_finish_command(trans)) == NULL)
1580         return(-1);
1581     if (head->error)
1582         return(-1);
1583
1584     r = 0;
1585     FOR_EACH_ITEM(item, trans, head) {
1586         if (item->leafid == LC_DATA) {
1587             r = item->bytes - sizeof(*item);
1588             if (r < 0)
1589                 r = 0;
1590             if (r > bufsiz)
1591                 r = bufsiz;
1592             bcopy(HCC_BINARYDATA(item), buf, r);
1593         }
1594     }
1595     return(r);
1596 }
1597
1598 static int
1599 rc_readlink(hctransaction_t trans, struct HCHead *head)
1600 {
1601     struct HCLeaf *item;
1602     const char *path = NULL;
1603     char buf[1024];
1604     int r;
1605
1606     FOR_EACH_ITEM(item, trans, head) {
1607         if (item->leafid == LC_PATH1)
1608             path = HCC_STRING(item);
1609     }
1610     if (path == NULL)
1611         return(-2);
1612     r = readlink(path, buf, sizeof(buf));
1613     if (r < 0)
1614         return(-1);
1615     hcc_leaf_data(trans, LC_DATA, buf, r);
1616     return(0);
1617 }
1618
1619 /*
1620  * UMASK
1621  */
1622 mode_t
1623 hc_umask(struct HostConf *hc, mode_t numask)
1624 {
1625     hctransaction_t trans;
1626     struct HCHead *head;
1627     struct HCLeaf *item;
1628
1629     if (NotForRealOpt)
1630         return(umask(numask));
1631     if (hc == NULL || hc->host == NULL)
1632         return(umask(numask));
1633
1634     trans = hcc_start_command(hc, HC_UMASK);
1635     hcc_leaf_int32(trans, LC_MODE, numask);
1636     if ((head = hcc_finish_command(trans)) == NULL)
1637         return((mode_t)-1);
1638     if (head->error)
1639         return((mode_t)-1);
1640
1641     numask = (mode_t) ~0666U;
1642     FOR_EACH_ITEM(item, trans, head) {
1643         if (item->leafid == LC_MODE)
1644             numask = HCC_INT32(item);
1645     }
1646     return(numask);
1647 }
1648
1649 static int
1650 rc_umask(hctransaction_t trans, struct HCHead *head)
1651 {
1652     struct HCLeaf *item;
1653     mode_t numask = (mode_t) ~0666U;
1654
1655     FOR_EACH_ITEM(item, trans, head) {
1656         if (item->leafid == LC_MODE)
1657             numask = HCC_INT32(item);
1658     }
1659     numask = umask(numask);
1660     hcc_leaf_int32(trans, LC_MODE, numask);
1661     return(0);
1662 }
1663
1664 /*
1665  * SYMLINK
1666  */
1667 int
1668 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1669 {
1670     hctransaction_t trans;
1671     struct HCHead *head;
1672
1673     if (NotForRealOpt)
1674         return(0);
1675     if (hc == NULL || hc->host == NULL)
1676         return(symlink(name1, name2));
1677
1678     trans = hcc_start_command(hc, HC_SYMLINK);
1679     hcc_leaf_string(trans, LC_PATH1, name1);
1680     hcc_leaf_string(trans, LC_PATH2, name2);
1681     if ((head = hcc_finish_command(trans)) == NULL)
1682         return(-1);
1683     if (head->error)
1684         return(-1);
1685     return(0);
1686 }
1687
1688 static int
1689 rc_symlink(hctransaction_t trans, struct HCHead *head)
1690 {
1691     struct HCLeaf *item;
1692     const char *name1 = NULL;
1693     const char *name2 = NULL;
1694
1695     FOR_EACH_ITEM(item, trans, head) {
1696         switch(item->leafid) {
1697         case LC_PATH1:
1698             name1 = HCC_STRING(item);
1699             break;
1700         case LC_PATH2:
1701             name2 = HCC_STRING(item);
1702             break;
1703         }
1704     }
1705     if (ReadOnlyOpt) {
1706         head->error = EACCES;
1707         return (0);
1708     }
1709     if (name1 == NULL || name2 == NULL)
1710         return(-2);
1711     return(symlink(name1, name2));
1712 }
1713
1714 /*
1715  * RENAME
1716  */
1717 int
1718 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1719 {
1720     hctransaction_t trans;
1721     struct HCHead *head;
1722
1723     if (NotForRealOpt)
1724         return(0);
1725     if (hc == NULL || hc->host == NULL)
1726         return(rename(name1, name2));
1727
1728     trans = hcc_start_command(hc, HC_RENAME);
1729     hcc_leaf_string(trans, LC_PATH1, name1);
1730     hcc_leaf_string(trans, LC_PATH2, name2);
1731     if ((head = hcc_finish_command(trans)) == NULL)
1732         return(-1);
1733     if (head->error)
1734         return(-1);
1735     return(0);
1736 }
1737
1738 static int
1739 rc_rename(hctransaction_t trans, struct HCHead *head)
1740 {
1741     struct HCLeaf *item;
1742     const char *name1 = NULL;
1743     const char *name2 = NULL;
1744
1745     FOR_EACH_ITEM(item, trans, head) {
1746         switch(item->leafid) {
1747         case LC_PATH1:
1748             name1 = HCC_STRING(item);
1749             break;
1750         case LC_PATH2:
1751             name2 = HCC_STRING(item);
1752             break;
1753         }
1754     }
1755     if (ReadOnlyOpt) {
1756         head->error = EACCES;
1757         return (0);
1758     }
1759     if (name1 == NULL || name2 == NULL)
1760         return(-2);
1761     return(rename(name1, name2));
1762 }
1763
1764 /*
1765  * UTIMES
1766  */
1767 int
1768 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1769 {
1770     hctransaction_t trans;
1771     struct HCHead *head;
1772
1773     if (NotForRealOpt)
1774         return(0);
1775     if (hc == NULL || hc->host == NULL)
1776         return(utimes(path, times));
1777
1778     trans = hcc_start_command(hc, HC_UTIMES);
1779     hcc_leaf_string(trans, LC_PATH1, path);
1780     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1781     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1782     if ((head = hcc_finish_command(trans)) == NULL)
1783         return(-1);
1784     if (head->error)
1785         return(-1);
1786     return(0);
1787 }
1788
1789 static int
1790 rc_utimes(hctransaction_t trans, struct HCHead *head)
1791 {
1792     struct HCLeaf *item;
1793     struct timeval times[2];
1794     const char *path;
1795
1796     bzero(times, sizeof(times));
1797     path = NULL;
1798
1799     FOR_EACH_ITEM(item, trans, head) {
1800         switch(item->leafid) {
1801         case LC_PATH1:
1802             path = HCC_STRING(item);
1803             break;
1804         case LC_ATIME:
1805             times[0].tv_sec = HCC_INT64(item);
1806             break;
1807         case LC_MTIME:
1808             times[1].tv_sec = HCC_INT64(item);
1809             break;
1810         }
1811     }
1812     if (ReadOnlyOpt) {
1813         head->error = EACCES;
1814         return (0);
1815     }
1816     if (path == NULL)
1817         return(-2);
1818     return(utimes(path, times));
1819 }
1820
1821 uid_t
1822 hc_geteuid(struct HostConf *hc)
1823 {
1824     hctransaction_t trans;
1825     struct HCHead *head;
1826     struct HCLeaf *item;
1827
1828     if (hc == NULL || hc->host == NULL)
1829         return (geteuid());
1830
1831     if (hc->version < 3) {
1832         fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1833         /* Return 0 on error, so the caller assumes root privileges. */
1834         return (0);
1835     }
1836
1837     trans = hcc_start_command(hc, HC_GETEUID);
1838     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1839         return(0);
1840     FOR_EACH_ITEM(item, trans, head) {
1841         if (item->leafid == LC_UID)
1842             return (HCC_INT32(item));
1843     }
1844     return(0); /* shouldn't happen */
1845 }
1846
1847 static int
1848 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1849 {
1850     hcc_leaf_int32(trans, LC_UID, geteuid());
1851     return (0);
1852 }
1853
1854 static int
1855 getmygroups(gid_t **gidlist)
1856 {
1857     int count;
1858
1859     if ((count = getgroups(0, *gidlist)) > 0) {
1860         if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1861             if ((count = getgroups(count, *gidlist)) <= 0)
1862                 free(*gidlist);
1863         }
1864         else
1865             count = -1;
1866     }
1867     else
1868         *gidlist = NULL;
1869     return (count);
1870 }
1871
1872 int
1873 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1874 {
1875     int count, i;
1876     hctransaction_t trans;
1877     struct HCHead *head;
1878     struct HCLeaf *item;
1879
1880     if (hc == NULL || hc->host == NULL)
1881         return (getmygroups(gidlist));
1882
1883     i = 0;
1884     count = 0;
1885     *gidlist = NULL;
1886
1887     if (hc->version < 3) {
1888         fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1889         return (-1);
1890     }
1891
1892     trans = hcc_start_command(hc, HC_GETGROUPS);
1893     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1894         return(-1);
1895     FOR_EACH_ITEM(item, trans, head) {
1896         switch(item->leafid) {
1897         case LC_COUNT:
1898             count = HCC_INT32(item);
1899             if (*gidlist != NULL) { /* protocol error */
1900                 free(*gidlist);
1901                 *gidlist = NULL;
1902                 return (-1);
1903             }
1904             if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1905                 return (-1);
1906             break;
1907         case LC_GID:
1908             if (*gidlist == NULL || i >= count) { /* protocol error */
1909                 if (*gidlist != NULL)
1910                     free(*gidlist);
1911                 *gidlist = NULL;
1912                 return (-1);
1913             }
1914             (*gidlist)[i++] = HCC_INT32(item);
1915             break;
1916         }
1917     }
1918     return (count);
1919 }
1920
1921 static int
1922 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1923 {
1924     int count, i;
1925     gid_t *gidlist;
1926
1927     if ((count = getmygroups(&gidlist)) < 0)
1928         return (-1);
1929     hcc_leaf_int32(trans, LC_COUNT, count);
1930     for (i = 0; i < count; i++)
1931         hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1932     if (gidlist != NULL)
1933         free(gidlist);
1934     return (0);
1935 }