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