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