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