Merge branch 'vendor/TCPDUMP'
[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 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 (hc == NULL || hc->host == NULL) {
660 #ifdef O_LARGEFILE
661         flags |= O_LARGEFILE;
662 #endif
663         return(open(path, flags, mode));
664     }
665
666     if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
667         trans = hcc_start_command(hc, HC_READFILE);
668         hcc_leaf_string(trans, LC_PATH1, path);
669         if ((head = hcc_finish_command(trans)) == NULL || head->error)
670             return (-1);
671         head->magic = 0; /* used to indicate offset within buffer */
672         return (1); /* dummy */
673     }
674
675     nflags = flags & XO_NATIVEMASK;
676     if (flags & O_CREAT)
677         nflags |= XO_CREAT;
678     if (flags & O_EXCL)
679         nflags |= XO_EXCL;
680     if (flags & O_TRUNC)
681         nflags |= XO_TRUNC;
682
683     trans = hcc_start_command(hc, HC_OPEN);
684     hcc_leaf_string(trans, LC_PATH1, path);
685     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
686     hcc_leaf_int32(trans, LC_MODE, mode);
687
688     if ((head = hcc_finish_command(trans)) == NULL)
689         return(-1);
690     if (head->error)
691         return(-1);
692     FOR_EACH_ITEM(item, trans, head) {
693         if (item->leafid == LC_DESCRIPTOR)
694             desc = HCC_INT32(item);
695     }
696     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
697         fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
698                 desc);
699         return(-1);
700     }
701     fdp = malloc(sizeof(int));
702     *fdp = desc;        /* really just a dummy */
703     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
704     return(desc);
705 }
706
707 static int
708 rc_open(hctransaction_t trans, struct HCHead *head)
709 {
710     struct HCLeaf *item;
711     const char *path = NULL;
712     int nflags = 0;
713     int flags;
714     mode_t mode = 0666;
715     int desc;
716     int *fdp;
717     int fd;
718
719     FOR_EACH_ITEM(item, trans, head) {
720         switch(item->leafid) {
721         case LC_PATH1:
722             path = HCC_STRING(item);
723             break;
724         case LC_OFLAGS:
725             nflags = HCC_INT32(item);
726             break;
727         case LC_MODE:
728             mode = HCC_INT32(item);
729             break;
730         }
731     }
732     if (path == NULL)
733         return(-2);
734
735     flags = nflags & XO_NATIVEMASK;
736     if (nflags & XO_CREAT)
737         flags |= O_CREAT;
738     if (nflags & XO_EXCL)
739         flags |= O_EXCL;
740     if (nflags & XO_TRUNC)
741         flags |= O_TRUNC;
742
743     if (ReadOnlyOpt) {
744         if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
745             head->error = EACCES;
746             return (0);
747         }
748         flags |= O_RDONLY;
749     }
750
751 #ifdef O_LARGEFILE
752     flags |= O_LARGEFILE;
753 #endif
754     if ((fd = open(path, flags, mode)) < 0)
755         return(-1);
756     fdp = malloc(sizeof(int));
757     *fdp = fd;
758     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
759     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
760     return(0);
761 }
762
763 /*
764  * CLOSE
765  */
766 int
767 hc_close(struct HostConf *hc, int fd)
768 {
769     hctransaction_t trans;
770     struct HCHead *head;
771     int *fdp;
772
773     if (hc == NULL || hc->host == NULL)
774         return(close(fd));
775
776     if (fd == 1 && hc->version >= 4) {  /* using HC_READFILE */
777         head = (void *)hc->trans.rbuf;
778         /* skip any remaining items if the file is closed prematurely */
779         while (hcc_nextchaineditem(hc, head) != NULL)
780             /*nothing*/ ;
781         if (head->error)
782             return (-1);
783         return (0);
784     }
785
786     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
787     if (fdp) {
788         free(fdp);
789         hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
790
791         trans = hcc_start_command(hc, HC_CLOSE);
792         hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
793         if ((head = hcc_finish_command(trans)) == NULL)
794             return(-1);
795         if (head->error)
796             return(-1);
797         return(0);
798     } else {
799         return(-1);
800     }
801 }
802
803 static int
804 rc_close(hctransaction_t trans, struct HCHead *head)
805 {
806     struct HCLeaf *item;
807     int *fdp = NULL;
808     int fd;
809     int desc = -1;
810
811     FOR_EACH_ITEM(item, trans, head) {
812         if (item->leafid == LC_DESCRIPTOR)
813             desc = HCC_INT32(item);
814     }
815     if (desc < 0)
816         return(-2);
817     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
818         return(-2);
819     fd = *fdp;
820     free(fdp);
821     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
822     return(close(fd));
823 }
824
825 static int
826 getiolimit(void)
827 {
828     return(32768);
829 }
830
831 /*
832  * READ
833  */
834 ssize_t
835 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
836 {
837     hctransaction_t trans;
838     struct HCHead *head;
839     struct HCLeaf *item;
840     int *fdp;
841     int offset;
842     int r = 0;
843     int x = 0;
844
845     if (hc == NULL || hc->host == NULL)
846         return(read(fd, buf, bytes));
847
848     if (fd == 1 && hc->version >= 4) {  /* using HC_READFILE */
849         head = (void *)hc->trans.rbuf;
850         while (bytes) {
851             if ((offset = head->magic) != 0)
852                 item = hcc_currentchaineditem(hc, head);
853             else
854                 item = hcc_nextchaineditem(hc, head);
855             if (item == NULL)
856                 return (r);
857             if (item->leafid != LC_DATA)
858                 return (-1);
859             x = item->bytes - sizeof(*item) - offset;
860             if (x > (int)bytes) {
861                 x = (int)bytes;
862                 head->magic += x;  /* leave bytes in the buffer */
863             }
864             else
865                 head->magic = 0;  /* all bytes used up */
866             bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
867             buf = (char *)buf + x;
868             bytes -= (size_t)x;
869             r += x;
870         }
871         return (r);
872     }
873
874     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
875     if (fdp) {
876         while (bytes) {
877             size_t limit = getiolimit();
878             int n = (bytes > limit) ? limit : bytes;
879
880             trans = hcc_start_command(hc, HC_READ);
881             hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
882             hcc_leaf_int32(trans, LC_BYTES, n);
883             if ((head = hcc_finish_command(trans)) == NULL)
884                 return(-1);
885             if (head->error)
886                 return(-1);
887             FOR_EACH_ITEM(item, trans, head) {
888                 if (item->leafid == LC_DATA) {
889                     x = item->bytes - sizeof(*item);
890                     if (x > (int)bytes)
891                         x = (int)bytes;
892                     bcopy(HCC_BINARYDATA(item), buf, x);
893                     buf = (char *)buf + x;
894                     bytes -= (size_t)x;
895                     r += x;
896                 }
897             }
898             if (x < n)
899                 break;
900         }
901         return(r);
902     } else {
903         return(-1);
904     }
905 }
906
907 static int
908 rc_read(hctransaction_t trans, struct HCHead *head)
909 {
910     struct HCLeaf *item;
911     int *fdp = NULL;
912     char buf[32768];
913     int bytes = -1;
914     int n;
915
916     FOR_EACH_ITEM(item, trans, head) {
917         switch(item->leafid) {
918         case LC_DESCRIPTOR:
919             fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
920             break;
921         case LC_BYTES:
922             bytes = HCC_INT32(item);
923             break;
924         }
925     }
926     if (fdp == NULL)
927         return(-2);
928     if (bytes < 0 || bytes > 32768)
929         return(-2);
930     n = read(*fdp, buf, bytes);
931     if (n < 0)
932         return(-1);
933     hcc_leaf_data(trans, LC_DATA, buf, n);
934     return(0);
935 }
936
937 /*
938  * READFILE
939  */
940 static int
941 rc_readfile(hctransaction_t trans, struct HCHead *head)
942 {
943     struct HCLeaf *item;
944     const char *path = NULL;
945     char buf[32768];
946     int n;
947     int fd;
948
949     FOR_EACH_ITEM(item, trans, head) {
950         if (item->leafid == LC_PATH1)
951             path = HCC_STRING(item);
952     }
953     if (path == NULL)
954         return (-2);
955     if ((fd = open(path, O_RDONLY)) < 0)
956         return(-1);
957     while ((n = read(fd, buf, 32768)) >= 0) {
958         if (!hcc_check_space(trans, head, 1, n)) {
959             close(fd);
960             return (-1);
961         }
962         hcc_leaf_data(trans, LC_DATA, buf, n);
963         if (n == 0)
964                 break;
965     }
966     if (n < 0) {
967         close(fd);
968         return (-1);
969     }
970     return (close(fd));
971 }
972
973 /*
974  * WRITE
975  */
976 ssize_t
977 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
978 {
979     hctransaction_t trans;
980     struct HCHead *head;
981     struct HCLeaf *item;
982     int *fdp;
983     int r;
984
985     if (hc == NULL || hc->host == NULL)
986         return(write(fd, buf, bytes));
987
988     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
989     if (fdp) {
990         r = 0;
991         while (bytes) {
992             size_t limit = getiolimit();
993             int n = (bytes > limit) ? limit : bytes;
994             int x = 0;
995
996             trans = hcc_start_command(hc, HC_WRITE);
997             hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
998             hcc_leaf_data(trans, LC_DATA, buf, n);
999             if ((head = hcc_finish_command(trans)) == NULL)
1000                 return(-1);
1001             if (head->error)
1002                 return(-1);
1003             FOR_EACH_ITEM(item, trans, head) {
1004                 if (item->leafid == LC_BYTES)
1005                     x = HCC_INT32(item);
1006             }
1007             if (x < 0 || x > n)
1008                 return(-1);
1009             r += x;
1010             buf = (const char *)buf + x;
1011             bytes -= x;
1012             if (x < n)
1013                 break;
1014         }
1015         return(r);
1016     } else {
1017         return(-1);
1018     }
1019 }
1020
1021 static int
1022 rc_write(hctransaction_t trans, struct HCHead *head)
1023 {
1024     struct HCLeaf *item;
1025     int *fdp = NULL;
1026     void *buf = NULL;
1027     int n = -1;
1028
1029     FOR_EACH_ITEM(item, trans, head) {
1030         switch(item->leafid) {
1031         case LC_DESCRIPTOR:
1032             fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1033             break;
1034         case LC_DATA:
1035             buf = HCC_BINARYDATA(item);
1036             n = item->bytes - sizeof(*item);
1037             break;
1038         }
1039     }
1040     if (ReadOnlyOpt) {
1041         head->error = EACCES;
1042         return (0);
1043     }
1044     if (fdp == NULL)
1045         return(-2);
1046     if (n < 0 || n > 32768)
1047         return(-2);
1048     n = write(*fdp, buf, n);
1049     if (n < 0)
1050         return (-1);
1051     hcc_leaf_int32(trans, LC_BYTES, n);
1052     return(0);
1053 }
1054
1055 /*
1056  * REMOVE
1057  *
1058  * NOTE: This function returns -errno if an error occured.
1059  */
1060 int
1061 hc_remove(struct HostConf *hc, const char *path)
1062 {
1063     hctransaction_t trans;
1064     struct HCHead *head;
1065     int res;
1066
1067     if (hc == NULL || hc->host == NULL) {
1068         res = remove(path);
1069         if (res < 0)
1070                 res = -errno;
1071         return(res);
1072     }
1073
1074     trans = hcc_start_command(hc, HC_REMOVE);
1075     hcc_leaf_string(trans, LC_PATH1, path);
1076     if ((head = hcc_finish_command(trans)) == NULL)
1077         return(-EIO);
1078     if (head->error)
1079         return(-(int)head->error);
1080     return(0);
1081 }
1082
1083 static int
1084 rc_remove(hctransaction_t trans, struct HCHead *head)
1085 {
1086     struct HCLeaf *item;
1087     const char *path = NULL;
1088
1089     FOR_EACH_ITEM(item, trans, head) {
1090         if (item->leafid == LC_PATH1)
1091             path = HCC_STRING(item);
1092     }
1093     if (path == NULL)
1094         return(-2);
1095     if (ReadOnlyOpt) {
1096         head->error = EACCES;
1097         return (0);
1098     }
1099     return(remove(path));
1100 }
1101
1102 /*
1103  * MKDIR
1104  */
1105 int
1106 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1107 {
1108     hctransaction_t trans;
1109     struct HCHead *head;
1110
1111     if (hc == NULL || hc->host == NULL)
1112         return(mkdir(path, mode));
1113
1114     trans = hcc_start_command(hc, HC_MKDIR);
1115     hcc_leaf_string(trans, LC_PATH1, path);
1116     hcc_leaf_int32(trans, LC_MODE, mode);
1117     if ((head = hcc_finish_command(trans)) == NULL)
1118         return(-1);
1119     if (head->error)
1120         return(-1);
1121     return(0);
1122 }
1123
1124 static int
1125 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1126 {
1127     struct HCLeaf *item;
1128     const char *path = NULL;
1129     mode_t mode = 0777;
1130
1131     FOR_EACH_ITEM(item, trans, head) {
1132         switch(item->leafid) {
1133         case LC_PATH1:
1134             path = HCC_STRING(item);
1135             break;
1136         case LC_MODE:
1137             mode = HCC_INT32(item);
1138             break;
1139         }
1140     }
1141     if (ReadOnlyOpt) {
1142         head->error = EACCES;
1143         return (0);
1144     }
1145     if (path == NULL)
1146         return(-2);
1147     return(mkdir(path, mode));
1148 }
1149
1150 /*
1151  * RMDIR
1152  */
1153 int
1154 hc_rmdir(struct HostConf *hc, const char *path)
1155 {
1156     hctransaction_t trans;
1157     struct HCHead *head;
1158
1159     if (hc == NULL || hc->host == NULL)
1160         return(rmdir(path));
1161
1162     trans = hcc_start_command(hc, HC_RMDIR);
1163     hcc_leaf_string(trans, LC_PATH1, path);
1164     if ((head = hcc_finish_command(trans)) == NULL)
1165         return(-1);
1166     if (head->error)
1167         return(-1);
1168     return(0);
1169 }
1170
1171 static int
1172 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1173 {
1174     struct HCLeaf *item;
1175     const char *path = NULL;
1176
1177     FOR_EACH_ITEM(item, trans, head) {
1178         if (item->leafid == LC_PATH1)
1179             path = HCC_STRING(item);
1180     }
1181     if (ReadOnlyOpt) {
1182         head->error = EACCES;
1183         return (0);
1184     }
1185     if (path == NULL)
1186         return(-2);
1187     return(rmdir(path));
1188 }
1189
1190 /*
1191  * CHOWN
1192  *
1193  * Almost silently ignore chowns that fail if we are not root.
1194  */
1195 int
1196 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1197 {
1198     hctransaction_t trans;
1199     struct HCHead *head;
1200     int rc;
1201
1202     if (!DstRootPrivs)
1203         owner = -1;
1204
1205     if (hc == NULL || hc->host == NULL) {
1206         rc = chown(path, owner, group);
1207         if (rc < 0)
1208             rc = silentwarning(&chown_warning, "file ownership may differ\n");
1209         return(rc);
1210     }
1211
1212     trans = hcc_start_command(hc, HC_CHOWN);
1213     hcc_leaf_string(trans, LC_PATH1, path);
1214     hcc_leaf_int32(trans, LC_UID, owner);
1215     hcc_leaf_int32(trans, LC_GID, group);
1216     if ((head = hcc_finish_command(trans)) == NULL)
1217         return(-1);
1218     if (head->error)
1219         return(-1);
1220     return(0);
1221 }
1222
1223 static int
1224 rc_chown(hctransaction_t trans, struct HCHead *head)
1225 {
1226     struct HCLeaf *item;
1227     const char *path = NULL;
1228     uid_t uid = (uid_t)-1;
1229     gid_t gid = (gid_t)-1;
1230     int rc;
1231
1232     FOR_EACH_ITEM(item, trans, head) {
1233         switch(item->leafid) {
1234         case LC_PATH1:
1235             path = HCC_STRING(item);
1236             break;
1237         case LC_UID:
1238             uid = HCC_INT32(item);
1239             break;
1240         case LC_GID:
1241             gid = HCC_INT32(item);
1242             break;
1243         }
1244     }
1245     if (ReadOnlyOpt) {
1246         head->error = EACCES;
1247         return (0);
1248     }
1249     if (path == NULL)
1250         return(-2);
1251     rc = chown(path, uid, gid);
1252     if (rc < 0)
1253         rc = silentwarning(&chown_warning, "file ownership may differ\n");
1254     return(rc);
1255 }
1256
1257 /*
1258  * LCHOWN
1259  */
1260 int
1261 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1262 {
1263     hctransaction_t trans;
1264     struct HCHead *head;
1265     int rc;
1266
1267     if (!DstRootPrivs)
1268         owner = -1;
1269
1270     if (hc == NULL || hc->host == NULL) {
1271         rc = lchown(path, owner, group);
1272         if (rc < 0)
1273             rc = silentwarning(&chown_warning, "file ownership may differ\n");
1274         return(rc);
1275     }
1276
1277     trans = hcc_start_command(hc, HC_LCHOWN);
1278     hcc_leaf_string(trans, LC_PATH1, path);
1279     hcc_leaf_int32(trans, LC_UID, owner);
1280     hcc_leaf_int32(trans, LC_GID, group);
1281     if ((head = hcc_finish_command(trans)) == NULL)
1282         return(-1);
1283     if (head->error)
1284         return(-1);
1285     return(0);
1286 }
1287
1288 static int
1289 rc_lchown(hctransaction_t trans, struct HCHead *head)
1290 {
1291     struct HCLeaf *item;
1292     const char *path = NULL;
1293     uid_t uid = (uid_t)-1;
1294     gid_t gid = (gid_t)-1;
1295     int rc;
1296
1297     FOR_EACH_ITEM(item, trans, head) {
1298         switch(item->leafid) {
1299         case LC_PATH1:
1300             path = HCC_STRING(item);
1301             break;
1302         case LC_UID:
1303             uid = HCC_INT32(item);
1304             break;
1305         case LC_GID:
1306             gid = HCC_INT32(item);
1307             break;
1308         }
1309     }
1310     if (ReadOnlyOpt) {
1311         head->error = EACCES;
1312         return (0);
1313     }
1314     if (path == NULL)
1315         return(-2);
1316     rc = lchown(path, uid, gid);
1317     if (rc < 0)
1318         rc = silentwarning(&chown_warning, "file ownership may differ\n");
1319     return(rc);
1320 }
1321
1322 /*
1323  * CHMOD
1324  */
1325 int
1326 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1327 {
1328     hctransaction_t trans;
1329     struct HCHead *head;
1330
1331     if (hc == NULL || hc->host == NULL)
1332         return(chmod(path, mode));
1333
1334     trans = hcc_start_command(hc, HC_CHMOD);
1335     hcc_leaf_string(trans, LC_PATH1, path);
1336     hcc_leaf_int32(trans, LC_MODE, mode);
1337     if ((head = hcc_finish_command(trans)) == NULL)
1338         return(-1);
1339     if (head->error)
1340         return(-1);
1341     return(0);
1342 }
1343
1344 static int
1345 rc_chmod(hctransaction_t trans, struct HCHead *head)
1346 {
1347     struct HCLeaf *item;
1348     const char *path = NULL;
1349     mode_t mode = 0666;
1350
1351     FOR_EACH_ITEM(item, trans, head) {
1352         switch(item->leafid) {
1353         case LC_PATH1:
1354             path = HCC_STRING(item);
1355             break;
1356         case LC_MODE:
1357             mode = HCC_INT32(item);
1358             break;
1359         }
1360     }
1361     if (ReadOnlyOpt) {
1362         head->error = EACCES;
1363         return (0);
1364     }
1365     if (path == NULL)
1366         return(-2);
1367     return(chmod(path, mode));
1368 }
1369
1370 /*
1371  * MKNOD
1372  */
1373 int
1374 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1375 {
1376     hctransaction_t trans;
1377     struct HCHead *head;
1378
1379     if (!DstRootPrivs) {
1380         /* mknod() requires root privs, so don't bother. */
1381         errno = EPERM;
1382         return (-1);
1383     }
1384
1385     if (hc == NULL || hc->host == NULL)
1386         return(mknod(path, mode, rdev));
1387
1388     trans = hcc_start_command(hc, HC_MKNOD);
1389     hcc_leaf_string(trans, LC_PATH1, path);
1390     hcc_leaf_int32(trans, LC_MODE, mode);
1391     hcc_leaf_int32(trans, LC_RDEV, rdev);
1392     if ((head = hcc_finish_command(trans)) == NULL)
1393         return(-1);
1394     if (head->error)
1395         return(-1);
1396     return(0);
1397 }
1398
1399 static int
1400 rc_mknod(hctransaction_t trans, struct HCHead *head)
1401 {
1402     struct HCLeaf *item;
1403     const char *path = NULL;
1404     mode_t mode = 0666;
1405     dev_t rdev = 0;
1406
1407     FOR_EACH_ITEM(item, trans, head) {
1408         switch(item->leafid) {
1409         case LC_PATH1:
1410             path = HCC_STRING(item);
1411             break;
1412         case LC_MODE:
1413             mode = HCC_INT32(item);
1414             break;
1415         case LC_RDEV:
1416             rdev = HCC_INT32(item);
1417             break;
1418         }
1419     }
1420     if (ReadOnlyOpt) {
1421         head->error = EACCES;
1422         return (0);
1423     }
1424     if (path == NULL)
1425         return(-2);
1426     return(mknod(path, mode, rdev));
1427 }
1428
1429 /*
1430  * LINK
1431  */
1432 int
1433 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1434 {
1435     hctransaction_t trans;
1436     struct HCHead *head;
1437
1438     if (hc == NULL || hc->host == NULL)
1439         return(link(name1, name2));
1440
1441     trans = hcc_start_command(hc, HC_LINK);
1442     hcc_leaf_string(trans, LC_PATH1, name1);
1443     hcc_leaf_string(trans, LC_PATH2, name2);
1444     if ((head = hcc_finish_command(trans)) == NULL)
1445         return(-1);
1446     if (head->error)
1447         return(-1);
1448     return(0);
1449 }
1450
1451 static int
1452 rc_link(hctransaction_t trans, struct HCHead *head)
1453 {
1454     struct HCLeaf *item;
1455     const char *name1 = NULL;
1456     const char *name2 = NULL;
1457
1458     FOR_EACH_ITEM(item, trans, head) {
1459         switch(item->leafid) {
1460         case LC_PATH1:
1461             name1 = HCC_STRING(item);
1462             break;
1463         case LC_PATH2:
1464             name2 = HCC_STRING(item);
1465             break;
1466         }
1467     }
1468     if (ReadOnlyOpt) {
1469         head->error = EACCES;
1470         return (-0);
1471     }
1472     if (name1 == NULL || name2 == NULL)
1473         return(-2);
1474     return(link(name1, name2));
1475 }
1476
1477 #ifdef _ST_FLAGS_PRESENT_
1478 /*
1479  * CHFLAGS
1480  */
1481 int
1482 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1483 {
1484     hctransaction_t trans;
1485     struct HCHead *head;
1486     int rc;
1487
1488     if (!DstRootPrivs)
1489         flags &= UF_SETTABLE;
1490
1491     if (hc == NULL || hc->host == NULL) {
1492         if ((rc = chflags(path, flags)) < 0)
1493             rc = silentwarning(&chflags_warning, "file flags may differ\n");
1494         return (rc);
1495     }
1496
1497     trans = hcc_start_command(hc, HC_CHFLAGS);
1498     hcc_leaf_string(trans, LC_PATH1, path);
1499     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1500     if ((head = hcc_finish_command(trans)) == NULL)
1501         return(-1);
1502     if (head->error)
1503         return(-1);
1504     return(0);
1505 }
1506
1507 static int
1508 rc_chflags(hctransaction_t trans, struct HCHead *head)
1509 {
1510     struct HCLeaf *item;
1511     const char *path = NULL;
1512     u_long flags = 0;
1513     int rc;
1514
1515     FOR_EACH_ITEM(item, trans, head) {
1516         switch(item->leafid) {
1517         case LC_PATH1:
1518             path = HCC_STRING(item);
1519             break;
1520         case LC_FILEFLAGS:
1521             flags = (u_long)HCC_INT64(item);
1522             break;
1523         }
1524     }
1525     if (ReadOnlyOpt) {
1526         head->error = EACCES;
1527         return (0);
1528     }
1529     if (path == NULL)
1530         return(-2);
1531     if ((rc = chflags(path, flags)) < 0)
1532         rc = silentwarning(&chflags_warning, "file flags may differ\n");
1533     return(rc);
1534 }
1535
1536 #endif
1537
1538 /*
1539  * READLINK
1540  */
1541 int
1542 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1543 {
1544     hctransaction_t trans;
1545     struct HCHead *head;
1546     struct HCLeaf *item;
1547     int r;
1548
1549     if (hc == NULL || hc->host == NULL)
1550         return(readlink(path, buf, bufsiz));
1551
1552     trans = hcc_start_command(hc, HC_READLINK);
1553     hcc_leaf_string(trans, LC_PATH1, path);
1554     if ((head = hcc_finish_command(trans)) == NULL)
1555         return(-1);
1556     if (head->error)
1557         return(-1);
1558
1559     r = 0;
1560     FOR_EACH_ITEM(item, trans, head) {
1561         if (item->leafid == LC_DATA) {
1562             r = item->bytes - sizeof(*item);
1563             if (r < 0)
1564                 r = 0;
1565             if (r > bufsiz)
1566                 r = bufsiz;
1567             bcopy(HCC_BINARYDATA(item), buf, r);
1568         }
1569     }
1570     return(r);
1571 }
1572
1573 static int
1574 rc_readlink(hctransaction_t trans, struct HCHead *head)
1575 {
1576     struct HCLeaf *item;
1577     const char *path = NULL;
1578     char buf[1024];
1579     int r;
1580
1581     FOR_EACH_ITEM(item, trans, head) {
1582         if (item->leafid == LC_PATH1)
1583             path = HCC_STRING(item);
1584     }
1585     if (path == NULL)
1586         return(-2);
1587     r = readlink(path, buf, sizeof(buf));
1588     if (r < 0)
1589         return(-1);
1590     hcc_leaf_data(trans, LC_DATA, buf, r);
1591     return(0);
1592 }
1593
1594 /*
1595  * UMASK
1596  */
1597 mode_t
1598 hc_umask(struct HostConf *hc, mode_t numask)
1599 {
1600     hctransaction_t trans;
1601     struct HCHead *head;
1602     struct HCLeaf *item;
1603
1604     if (hc == NULL || hc->host == NULL)
1605         return(umask(numask));
1606
1607     trans = hcc_start_command(hc, HC_UMASK);
1608     hcc_leaf_int32(trans, LC_MODE, numask);
1609     if ((head = hcc_finish_command(trans)) == NULL)
1610         return((mode_t)-1);
1611     if (head->error)
1612         return((mode_t)-1);
1613
1614     numask = (mode_t) ~0666U;
1615     FOR_EACH_ITEM(item, trans, head) {
1616         if (item->leafid == LC_MODE)
1617             numask = HCC_INT32(item);
1618     }
1619     return(numask);
1620 }
1621
1622 static int
1623 rc_umask(hctransaction_t trans, struct HCHead *head)
1624 {
1625     struct HCLeaf *item;
1626     mode_t numask = (mode_t) ~0666U;
1627
1628     FOR_EACH_ITEM(item, trans, head) {
1629         if (item->leafid == LC_MODE)
1630             numask = HCC_INT32(item);
1631     }
1632     numask = umask(numask);
1633     hcc_leaf_int32(trans, LC_MODE, numask);
1634     return(0);
1635 }
1636
1637 /*
1638  * SYMLINK
1639  */
1640 int
1641 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1642 {
1643     hctransaction_t trans;
1644     struct HCHead *head;
1645
1646     if (hc == NULL || hc->host == NULL)
1647         return(symlink(name1, name2));
1648
1649     trans = hcc_start_command(hc, HC_SYMLINK);
1650     hcc_leaf_string(trans, LC_PATH1, name1);
1651     hcc_leaf_string(trans, LC_PATH2, name2);
1652     if ((head = hcc_finish_command(trans)) == NULL)
1653         return(-1);
1654     if (head->error)
1655         return(-1);
1656     return(0);
1657 }
1658
1659 static int
1660 rc_symlink(hctransaction_t trans, struct HCHead *head)
1661 {
1662     struct HCLeaf *item;
1663     const char *name1 = NULL;
1664     const char *name2 = NULL;
1665
1666     FOR_EACH_ITEM(item, trans, head) {
1667         switch(item->leafid) {
1668         case LC_PATH1:
1669             name1 = HCC_STRING(item);
1670             break;
1671         case LC_PATH2:
1672             name2 = HCC_STRING(item);
1673             break;
1674         }
1675     }
1676     if (ReadOnlyOpt) {
1677         head->error = EACCES;
1678         return (0);
1679     }
1680     if (name1 == NULL || name2 == NULL)
1681         return(-2);
1682     return(symlink(name1, name2));
1683 }
1684
1685 /*
1686  * RENAME
1687  */
1688 int
1689 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1690 {
1691     hctransaction_t trans;
1692     struct HCHead *head;
1693   
1694     if (hc == NULL || hc->host == NULL)
1695         return(rename(name1, name2));
1696
1697     trans = hcc_start_command(hc, HC_RENAME);
1698     hcc_leaf_string(trans, LC_PATH1, name1);
1699     hcc_leaf_string(trans, LC_PATH2, name2);
1700     if ((head = hcc_finish_command(trans)) == NULL)
1701         return(-1);
1702     if (head->error)
1703         return(-1);
1704     return(0);
1705 }
1706
1707 static int
1708 rc_rename(hctransaction_t trans, struct HCHead *head)
1709 {
1710     struct HCLeaf *item;
1711     const char *name1 = NULL;
1712     const char *name2 = NULL;
1713
1714     FOR_EACH_ITEM(item, trans, head) {
1715         switch(item->leafid) {
1716         case LC_PATH1:
1717             name1 = HCC_STRING(item);
1718             break;
1719         case LC_PATH2:
1720             name2 = HCC_STRING(item);
1721             break;
1722         }
1723     }
1724     if (ReadOnlyOpt) {
1725         head->error = EACCES;
1726         return (0);
1727     }
1728     if (name1 == NULL || name2 == NULL)
1729         return(-2);
1730     return(rename(name1, name2));
1731 }
1732
1733 /*
1734  * UTIMES
1735  */
1736 int
1737 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1738 {
1739     hctransaction_t trans;
1740     struct HCHead *head;
1741
1742     if (hc == NULL || hc->host == NULL)
1743         return(utimes(path, times));
1744
1745     trans = hcc_start_command(hc, HC_UTIMES);
1746     hcc_leaf_string(trans, LC_PATH1, path);
1747     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1748     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1749     if ((head = hcc_finish_command(trans)) == NULL)
1750         return(-1);
1751     if (head->error)
1752         return(-1);
1753     return(0);
1754 }
1755
1756 static int
1757 rc_utimes(hctransaction_t trans, struct HCHead *head)
1758 {
1759     struct HCLeaf *item;
1760     struct timeval times[2];
1761     const char *path;
1762
1763     bzero(times, sizeof(times));
1764     path = NULL;
1765
1766     FOR_EACH_ITEM(item, trans, head) {
1767         switch(item->leafid) {
1768         case LC_PATH1:
1769             path = HCC_STRING(item);
1770             break;
1771         case LC_ATIME:
1772             times[0].tv_sec = HCC_INT64(item);
1773             break;
1774         case LC_MTIME:
1775             times[1].tv_sec = HCC_INT64(item);
1776             break;
1777         }
1778     }
1779     if (ReadOnlyOpt) {
1780         head->error = EACCES;
1781         return (0);
1782     }
1783     if (path == NULL)
1784         return(-2);
1785     return(utimes(path, times));
1786 }
1787
1788 uid_t
1789 hc_geteuid(struct HostConf *hc)
1790 {
1791     hctransaction_t trans;
1792     struct HCHead *head;
1793     struct HCLeaf *item;
1794
1795     if (hc == NULL || hc->host == NULL)
1796         return (geteuid());
1797
1798     if (hc->version < 3) {
1799         fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1800         /* Return 0 on error, so the caller assumes root privileges. */
1801         return (0);
1802     }
1803
1804     trans = hcc_start_command(hc, HC_GETEUID);
1805     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1806         return(0);
1807     FOR_EACH_ITEM(item, trans, head) {
1808         if (item->leafid == LC_UID)
1809             return (HCC_INT32(item));
1810     }
1811     return(0); /* shouldn't happen */
1812 }
1813
1814 static int
1815 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1816 {
1817     hcc_leaf_int32(trans, LC_UID, geteuid());
1818     return (0);
1819 }
1820
1821 static int
1822 getmygroups(gid_t **gidlist)
1823 {
1824     int count;
1825
1826     if ((count = getgroups(0, *gidlist)) > 0) {
1827         if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1828             if ((count = getgroups(count, *gidlist)) <= 0)
1829                 free(*gidlist);
1830         }
1831         else
1832             count = -1;
1833     }
1834     else
1835         *gidlist = NULL;
1836     return (count);
1837 }
1838
1839 int
1840 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1841 {
1842     int count, i;
1843     hctransaction_t trans;
1844     struct HCHead *head;
1845     struct HCLeaf *item;
1846
1847     if (hc == NULL || hc->host == NULL)
1848         return (getmygroups(gidlist));
1849
1850     i = 0;
1851     count = 0;
1852     *gidlist = NULL;
1853
1854     if (hc->version < 3) {
1855         fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1856         return (-1);
1857     }
1858
1859     trans = hcc_start_command(hc, HC_GETGROUPS);
1860     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1861         return(-1);
1862     FOR_EACH_ITEM(item, trans, head) {
1863         switch(item->leafid) {
1864         case LC_COUNT:
1865             count = HCC_INT32(item);
1866             if (*gidlist != NULL) { /* protocol error */
1867                 free(*gidlist);
1868                 *gidlist = NULL;
1869                 return (-1);
1870             }
1871             if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1872                 return (-1);
1873             break;
1874         case LC_GID:
1875             if (*gidlist == NULL || i >= count) { /* protocol error */
1876                 if (*gidlist != NULL)
1877                     free(*gidlist);
1878                 *gidlist = NULL;
1879                 return (-1);
1880             }
1881             (*gidlist)[i++] = HCC_INT32(item);
1882             break;
1883         }
1884     }
1885     return (count);
1886 }
1887
1888 static int
1889 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1890 {
1891     int count, i;
1892     gid_t *gidlist;
1893
1894     if ((count = getmygroups(&gidlist)) < 0)
1895         return (-1);
1896     hcc_leaf_int32(trans, LC_COUNT, count);
1897     for (i = 0; i < count; i++)
1898         hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1899     if (gidlist != NULL)
1900         free(gidlist);
1901     return (0);
1902 }