xref: /dragonfly/bin/cpdup/hcproto.c (revision 235099c3)
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(struct stat *, struct HCHead *);
14 static int rc_encode_stat(hctransaction_t trans, struct stat *);
15 
16 static int rc_hello(hctransaction_t trans, struct HCHead *);
17 static int rc_stat(hctransaction_t trans, struct HCHead *);
18 static int rc_lstat(hctransaction_t trans, struct HCHead *);
19 static int rc_opendir(hctransaction_t trans, struct HCHead *);
20 static int rc_readdir(hctransaction_t trans, struct HCHead *);
21 static int rc_closedir(hctransaction_t trans, struct HCHead *);
22 static int rc_open(hctransaction_t trans, struct HCHead *);
23 static int rc_close(hctransaction_t trans, struct HCHead *);
24 static int rc_read(hctransaction_t trans, struct HCHead *);
25 static int rc_write(hctransaction_t trans, struct HCHead *);
26 static int rc_remove(hctransaction_t trans, struct HCHead *);
27 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
28 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
29 static int rc_chown(hctransaction_t trans, struct HCHead *);
30 static int rc_lchown(hctransaction_t trans, struct HCHead *);
31 static int rc_chmod(hctransaction_t trans, struct HCHead *);
32 static int rc_mknod(hctransaction_t trans, struct HCHead *);
33 static int rc_link(hctransaction_t trans, struct HCHead *);
34 #ifdef _ST_FLAGS_PRESENT_
35 static int rc_chflags(hctransaction_t trans, struct HCHead *);
36 #endif
37 static int rc_readlink(hctransaction_t trans, struct HCHead *);
38 static int rc_umask(hctransaction_t trans, struct HCHead *);
39 static int rc_symlink(hctransaction_t trans, struct HCHead *);
40 static int rc_rename(hctransaction_t trans, struct HCHead *);
41 static int rc_utimes(hctransaction_t trans, struct HCHead *);
42 
43 struct HCDesc HCDispatchTable[] = {
44     { HC_HELLO,		rc_hello },
45     { HC_STAT,		rc_stat },
46     { HC_LSTAT,		rc_lstat },
47     { HC_OPENDIR,	rc_opendir },
48     { HC_READDIR,	rc_readdir },
49     { HC_CLOSEDIR,	rc_closedir },
50     { HC_OPEN,		rc_open },
51     { HC_CLOSE,		rc_close },
52     { HC_READ,		rc_read },
53     { HC_WRITE,		rc_write },
54     { HC_REMOVE,	rc_remove },
55     { HC_MKDIR,		rc_mkdir },
56     { HC_RMDIR,		rc_rmdir },
57     { HC_CHOWN,		rc_chown },
58     { HC_LCHOWN,	rc_lchown },
59     { HC_CHMOD,		rc_chmod },
60     { HC_MKNOD,		rc_mknod },
61     { HC_LINK,		rc_link },
62 #ifdef _ST_FLAGS_PRESENT_
63     { HC_CHFLAGS,	rc_chflags },
64 #endif
65     { HC_READLINK,	rc_readlink },
66     { HC_UMASK,		rc_umask },
67     { HC_SYMLINK,	rc_symlink },
68     { HC_RENAME,	rc_rename },
69     { HC_UTIMES,	rc_utimes },
70 };
71 
72 static int chown_warning;
73 static int chflags_warning;
74 
75 /*
76  * If not running as root generate a silent warning and return no error.
77  *
78  * If running as root return an error.
79  */
80 static int
81 silentwarning(int *didwarn, const char *ctl, ...)
82 {
83     va_list va;
84 
85     if (RunningAsRoot)
86 	return(-1);
87     if (*didwarn == 0) {
88 	*didwarn = 1;
89 	fprintf(stderr, "WARNING: Not running as root, ");
90 	va_start(va, ctl);
91 	vfprintf(stderr, ctl, va);
92 	va_end(va);
93     }
94     return(0);
95 }
96 
97 int
98 hc_connect(struct HostConf *hc)
99 {
100     if (hcc_connect(hc) < 0) {
101 	fprintf(stderr, "Unable to connect to %s\n", hc->host);
102 	return(-1);
103     }
104     return(hc_hello(hc));
105 }
106 
107 void
108 hc_slave(int fdin, int fdout)
109 {
110     hcc_slave(fdin, fdout, HCDispatchTable,
111 	      sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
112 
113 }
114 
115 /*
116  * A HELLO RPC is sent on the initial connect.
117  */
118 int
119 hc_hello(struct HostConf *hc)
120 {
121     struct HCHead *head;
122     struct HCLeaf *item;
123     hctransaction_t trans;
124     char hostbuf[256];
125     int error;
126 
127     bzero(hostbuf, sizeof(hostbuf));
128     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
129         return(-1);
130     if (hostbuf[0] == 0)
131 	hostbuf[0] = '?';
132 
133     trans = hcc_start_command(hc, HC_HELLO);
134     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
135     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
136     if ((head = hcc_finish_command(trans)) == NULL) {
137 	fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
138 		hc->host);
139 	return(-1);
140     }
141 
142     if (head->error) {
143 	fprintf(stderr, "Connected to %s but remote returned error %d\n",
144 		hc->host, head->error);
145 	return(-1);
146     }
147 
148     error = -1;
149     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
150 	switch(item->leafid) {
151 	case LC_HELLOSTR:
152 	    fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
153 	    error = 0;
154 	    break;
155 	case LC_VERSION:
156 	    hc->version = HCC_INT32(item);
157 	    break;
158 	}
159     }
160     if (hc->version < HCPROTO_VERSION_COMPAT) {
161 	fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
162 		hc->host);
163 	error = -1;
164     }
165     if (error < 0)
166 	fprintf(stderr, "Handshake failed with %s\n", hc->host);
167     return (error);
168 }
169 
170 static int
171 rc_hello(hctransaction_t trans, struct HCHead *head __unused)
172 {
173     char hostbuf[256];
174 
175     bzero(hostbuf, sizeof(hostbuf));
176     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
177         return(-1);
178     if (hostbuf[0] == 0)
179 	hostbuf[0] = '?';
180 
181     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
182     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
183     return(0);
184 }
185 
186 /*
187  * STAT, LSTAT
188  */
189 int
190 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
191 {
192     struct HCHead *head;
193     hctransaction_t trans;
194 
195     if (hc == NULL || hc->host == NULL)
196 	return(stat(path, st));
197 
198     trans = hcc_start_command(hc, HC_STAT);
199     hcc_leaf_string(trans, LC_PATH1, path);
200     if ((head = hcc_finish_command(trans)) == NULL)
201 	return(-1);
202     if (head->error)
203 	return(-1);
204     return(hc_decode_stat(st, head));
205 }
206 
207 int
208 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
209 {
210     struct HCHead *head;
211     hctransaction_t trans;
212 
213     if (hc == NULL || hc->host == NULL)
214 	return(lstat(path, st));
215 
216     trans = hcc_start_command(hc, HC_LSTAT);
217     hcc_leaf_string(trans, LC_PATH1, path);
218     if ((head = hcc_finish_command(trans)) == NULL)
219 	return(-1);
220     if (head->error)
221 	return(-1);
222     return(hc_decode_stat(st, head));
223 }
224 
225 static int
226 hc_decode_stat(struct stat *st, struct HCHead *head)
227 {
228     struct HCLeaf *item;
229 
230     bzero(st, sizeof(*st));
231     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
232 	switch(item->leafid) {
233 	case LC_DEV:
234 		st->st_dev = HCC_INT32(item);
235 		break;
236 	case LC_INO:
237 		st->st_ino = HCC_INT64(item);
238 		break;
239 	case LC_MODE:
240 		st->st_mode = HCC_INT32(item);
241 		break;
242 	case LC_NLINK:
243 		st->st_nlink = HCC_INT32(item);
244 		break;
245 	case LC_UID:
246 		st->st_uid = HCC_INT32(item);
247 		break;
248 	case LC_GID:
249 		st->st_gid = HCC_INT32(item);
250 		break;
251 	case LC_RDEV:
252 		st->st_rdev = HCC_INT32(item);
253 		break;
254 	case LC_ATIME:
255 		st->st_atime = (time_t)HCC_INT64(item);
256 		break;
257 	case LC_MTIME:
258 		st->st_mtime = (time_t)HCC_INT64(item);
259 		break;
260 	case LC_CTIME:
261 		st->st_ctime = (time_t)HCC_INT64(item);
262 		break;
263 	case LC_FILESIZE:
264 		st->st_size = HCC_INT64(item);
265 		break;
266 	case LC_FILEBLKS:
267 		st->st_blocks = HCC_INT64(item);
268 		break;
269 	case LC_BLKSIZE:
270 		st->st_blksize = HCC_INT32(item);
271 		break;
272 #ifdef _ST_FSMID_PRESENT_
273 	case LC_FSMID:
274 		st->st_fsmid = HCC_INT64(item);
275 		break;
276 #endif
277 #ifdef _ST_FLAGS_PRESENT_
278 	case LC_FILEFLAGS:
279 		st->st_flags = (u_int32_t)HCC_INT64(item);
280 		break;
281 #endif
282 	}
283     }
284     return(0);
285 }
286 
287 static int
288 rc_stat(hctransaction_t trans, struct HCHead *head)
289 {
290     struct HCLeaf *item;
291     struct stat st;
292     const char *path = NULL;
293 
294     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
295 	switch(item->leafid) {
296 	case LC_PATH1:
297 	    path = HCC_STRING(item);
298 	    break;
299 	}
300     }
301     if (path == NULL)
302 	return(-2);
303     if (stat(path, &st) < 0)
304 	return(-1);
305     return (rc_encode_stat(trans, &st));
306 }
307 
308 static int
309 rc_lstat(hctransaction_t trans, struct HCHead *head)
310 {
311     struct HCLeaf *item;
312     struct stat st;
313     const char *path = NULL;
314 
315     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
316 	switch(item->leafid) {
317 	case LC_PATH1:
318 	    path = HCC_STRING(item);
319 	    break;
320 	}
321     }
322     if (path == NULL)
323 	return(-2);
324     if (lstat(path, &st) < 0)
325 	return(-1);
326     return (rc_encode_stat(trans, &st));
327 }
328 
329 static int
330 rc_encode_stat(hctransaction_t trans, struct stat *st)
331 {
332     hcc_leaf_int32(trans, LC_DEV, st->st_dev);
333     hcc_leaf_int64(trans, LC_INO, st->st_ino);
334     hcc_leaf_int32(trans, LC_MODE, st->st_mode);
335     hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
336     hcc_leaf_int32(trans, LC_UID, st->st_uid);
337     hcc_leaf_int32(trans, LC_GID, st->st_gid);
338     hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
339     hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
340     hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
341     hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
342     hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
343     hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
344     hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
345 #ifdef _ST_FSMID_PRESENT_
346     hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
347 #endif
348 #ifdef _ST_FLAGS_PRESENT_
349     hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
350 #endif
351     return(0);
352 }
353 
354 /*
355  * OPENDIR
356  */
357 DIR *
358 hc_opendir(struct HostConf *hc, const char *path)
359 {
360     hctransaction_t trans;
361     struct HCHead *head;
362     struct HCLeaf *item;
363     struct dirent *den;
364     intptr_t desc = 0;
365 
366     if (hc == NULL || hc->host == NULL)
367 	return(opendir(path));
368 
369     trans = hcc_start_command(hc, HC_OPENDIR);
370     hcc_leaf_string(trans, LC_PATH1, path);
371     if ((head = hcc_finish_command(trans)) == NULL)
372 	return(NULL);
373     if (head->error)
374 	return(NULL);
375     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
376 	switch(item->leafid) {
377 	case LC_DESCRIPTOR:
378 	    desc = HCC_INT32(item);
379 	    break;
380 	}
381     }
382     if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
383 	    fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
384 		(intmax_t)desc);
385 	return(NULL);
386     }
387     den = malloc(sizeof(*den));
388     bzero(den, sizeof(*den));
389     hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
390     return((void *)desc);
391 }
392 
393 static int
394 rc_opendir(hctransaction_t trans, struct HCHead *head)
395 {
396     struct HCLeaf *item;
397     const char *path = NULL;
398     DIR *dir;
399     int desc;
400 
401     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
402 	switch(item->leafid) {
403 	case LC_PATH1:
404 	    path = HCC_STRING(item);
405 	    break;
406 	}
407     }
408     if (path == NULL)
409 	return(-2);
410     if ((dir = opendir(path)) == NULL) {
411 	head->error = errno;
412     } else {
413 	desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
414 	hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
415     }
416     return(0);
417 }
418 
419 /*
420  * READDIR
421  */
422 struct dirent *
423 hc_readdir(struct HostConf *hc, DIR *dir)
424 {
425     hctransaction_t trans;
426     struct HCHead *head;
427     struct HCLeaf *item;
428     struct dirent *den;
429 
430     if (hc == NULL || hc->host == NULL)
431 	return(readdir(dir));
432 
433     trans = hcc_start_command(hc, HC_READDIR);
434     hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
435     if ((head = hcc_finish_command(trans)) == NULL)
436 	return(NULL);
437     if (head->error)
438 	return(NULL);	/* XXX errno */
439     den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
440     if (den == NULL)
441 	return(NULL);	/* XXX errno */
442     if (den->d_name)
443 	den->d_name[0] = 0;
444     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
445 	switch(item->leafid) {
446 	case LC_PATH1:
447 	    snprintf(den->d_name, sizeof(den->d_name), "%s", HCC_STRING(item));
448 	    break;
449 	case LC_INO:
450 	    den->d_fileno = HCC_INT64(item);
451 	    break;
452 	case LC_TYPE:
453 	    den->d_type = HCC_INT32(item);
454 	    break;
455 	}
456     }
457     if (den->d_name[0]) {
458 #ifdef _DIRENT_HAVE_D_NAMLEN
459 	den->d_namlen = strlen(den->d_name);
460 #endif
461 	return(den);
462     }
463     return(NULL);	/* XXX errno */
464 }
465 
466 static int
467 rc_readdir(hctransaction_t trans, struct HCHead *head)
468 {
469     struct HCLeaf *item;
470     struct dirent *den;
471     DIR *dir = NULL;
472 
473     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
474 	switch(item->leafid) {
475 	case LC_DESCRIPTOR:
476 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
477 	    break;
478 	}
479     }
480     if (dir == NULL)
481 	return(-2);
482     if ((den = readdir(dir)) != NULL) {
483 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
484 	hcc_leaf_int64(trans, LC_INO, den->d_fileno);
485 	hcc_leaf_int32(trans, LC_TYPE, den->d_type);
486     }
487     return(0);
488 }
489 
490 /*
491  * CLOSEDIR
492  *
493  * XXX cpdup needs to check error code to avoid truncated dirs?
494  */
495 int
496 hc_closedir(struct HostConf *hc, DIR *dir)
497 {
498     hctransaction_t trans;
499     struct HCHead *head;
500     struct dirent *den;
501 
502     if (hc == NULL || hc->host == NULL)
503 	return(closedir(dir));
504     den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
505     if (den) {
506 	free(den);
507 	hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
508 
509 	trans = hcc_start_command(hc, HC_CLOSEDIR);
510 	hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
511 	if ((head = hcc_finish_command(trans)) == NULL)
512 	    return(-1);
513 	if (head->error)
514 	    return(-1);		/* XXX errno */
515 	return(0);
516     } else {
517 	/* errno */
518 	return(-1);
519     }
520 }
521 
522 static int
523 rc_closedir(hctransaction_t trans, struct HCHead *head)
524 {
525     struct HCLeaf *item;
526     DIR *dir = NULL;
527 
528     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
529 	switch(item->leafid) {
530 	case LC_DESCRIPTOR:
531 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
532 	    if (dir != NULL)
533 		    hcc_set_descriptor(trans->hc, HCC_INT32(item), NULL, HC_DESC_DIR);
534 	    break;
535 	}
536     }
537     if (dir == NULL)
538 	return(-2);
539     return(closedir(dir));
540 }
541 
542 /*
543  * OPEN
544  */
545 int
546 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
547 {
548     hctransaction_t trans;
549     struct HCHead *head;
550     struct HCLeaf *item;
551     int *fdp;
552     int desc = 0;
553     int nflags;
554 
555     if (hc == NULL || hc->host == NULL) {
556 #ifdef O_LARGEFILE
557 	flags |= O_LARGEFILE;
558 #endif
559 	return(open(path, flags, mode));
560     }
561 
562     nflags = flags & XO_NATIVEMASK;
563     if (flags & O_CREAT)
564 	nflags |= XO_CREAT;
565     if (flags & O_EXCL)
566 	nflags |= XO_EXCL;
567     if (flags & O_TRUNC)
568 	nflags |= XO_TRUNC;
569 
570     trans = hcc_start_command(hc, HC_OPEN);
571     hcc_leaf_string(trans, LC_PATH1, path);
572     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
573     hcc_leaf_int32(trans, LC_MODE, mode);
574 
575     if ((head = hcc_finish_command(trans)) == NULL)
576 	return(-1);
577     if (head->error)
578 	return(-1);
579     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
580 	switch(item->leafid) {
581 	case LC_DESCRIPTOR:
582 	    desc = HCC_INT32(item);
583 	    break;
584 	}
585     }
586     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
587 	fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
588 		desc);
589 	return(-1);
590     }
591     fdp = malloc(sizeof(int));
592     *fdp = desc;	/* really just a dummy */
593     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
594     return(desc);
595 }
596 
597 static int
598 rc_open(hctransaction_t trans, struct HCHead *head)
599 {
600     struct HCLeaf *item;
601     const char *path = NULL;
602     int nflags = 0;
603     int flags;
604     mode_t mode = 0666;
605     int desc;
606     int *fdp;
607     int fd;
608 
609     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
610 	switch(item->leafid) {
611 	case LC_PATH1:
612 	    path = HCC_STRING(item);
613 	    break;
614 	case LC_OFLAGS:
615 	    nflags = HCC_INT32(item);
616 	    break;
617 	case LC_MODE:
618 	    mode = HCC_INT32(item);
619 	    break;
620 	}
621     }
622     if (path == NULL)
623 	return(-2);
624 
625     flags = nflags & XO_NATIVEMASK;
626     if (nflags & XO_CREAT)
627 	flags |= O_CREAT;
628     if (nflags & XO_EXCL)
629 	flags |= O_EXCL;
630     if (nflags & XO_TRUNC)
631 	flags |= O_TRUNC;
632 
633 #ifdef O_LARGEFILE
634     flags |= O_LARGEFILE;
635 #endif
636     if ((fd = open(path, flags, mode)) < 0) {
637 	head->error = errno;
638 	return(0);
639     }
640     fdp = malloc(sizeof(int));
641     *fdp = fd;
642     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
643     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
644     return(0);
645 }
646 
647 /*
648  * CLOSE
649  */
650 int
651 hc_close(struct HostConf *hc, int fd)
652 {
653     hctransaction_t trans;
654     struct HCHead *head;
655     int *fdp;
656 
657     if (hc == NULL || hc->host == NULL)
658 	return(close(fd));
659 
660     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
661     if (fdp) {
662 	free(fdp);
663 	hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
664 
665 	trans = hcc_start_command(hc, HC_CLOSE);
666 	hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
667 	if ((head = hcc_finish_command(trans)) == NULL)
668 	    return(-1);
669 	if (head->error)
670 	    return(-1);
671 	return(0);
672     } else {
673 	return(-1);
674     }
675 }
676 
677 static int
678 rc_close(hctransaction_t trans, struct HCHead *head)
679 {
680     struct HCLeaf *item;
681     int *fdp = NULL;
682     int fd;
683     int desc = -1;
684 
685     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
686 	switch(item->leafid) {
687 	case LC_DESCRIPTOR:
688 	    desc = HCC_INT32(item);
689 	    break;
690 	}
691     }
692     if (desc < 0)
693 	return(-2);
694     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
695 	return(-2);
696     fd = *fdp;
697     free(fdp);
698     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
699     return(close(fd));
700 }
701 
702 static int
703 getiolimit(void)
704 {
705 #if USE_PTHREADS
706     if (CurParallel < 2)
707 	return(32768);
708     if (CurParallel < 4)
709 	return(16384);
710     if (CurParallel < 8)
711 	return(8192);
712     return(4096);
713 #else
714     return(32768);
715 #endif
716 }
717 
718 /*
719  * READ
720  */
721 ssize_t
722 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
723 {
724     hctransaction_t trans;
725     struct HCHead *head;
726     struct HCLeaf *item;
727     int *fdp;
728     int r;
729 
730     if (hc == NULL || hc->host == NULL)
731 	return(read(fd, buf, bytes));
732 
733     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
734     if (fdp) {
735 	r = 0;
736 	while (bytes) {
737 	    size_t limit = getiolimit();
738 	    int n = (bytes > limit) ? limit : bytes;
739 	    int x = 0;
740 
741 	    trans = hcc_start_command(hc, HC_READ);
742 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
743 	    hcc_leaf_int32(trans, LC_BYTES, n);
744 	    if ((head = hcc_finish_command(trans)) == NULL)
745 		return(-1);
746 	    if (head->error)
747 		return(-1);
748 	    for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
749 		switch(item->leafid) {
750 		case LC_DATA:
751 		    x = item->bytes - sizeof(*item);
752 		    if (x > (int)bytes)
753 			x = (int)bytes;
754 		    bcopy(HCC_BINARYDATA(item), buf, x);
755 		    buf = (char *)buf + x;
756 		    bytes -= (size_t)x;
757 		    r += x;
758 		    break;
759 		}
760 	    }
761 	    if (x < n)
762 		break;
763 	}
764 	return(r);
765     } else {
766 	return(-1);
767     }
768 }
769 
770 static int
771 rc_read(hctransaction_t trans, struct HCHead *head)
772 {
773     struct HCLeaf *item;
774     int *fdp = NULL;
775     char buf[32768];
776     int bytes = -1;
777     int n;
778 
779     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
780 	switch(item->leafid) {
781 	case LC_DESCRIPTOR:
782 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
783 	    break;
784 	case LC_BYTES:
785 	    bytes = HCC_INT32(item);
786 	    break;
787 	}
788     }
789     if (fdp == NULL)
790 	return(-2);
791     if (bytes < 0 || bytes > 32768)
792 	return(-2);
793     n = read(*fdp, buf, bytes);
794     if (n < 0) {
795 	head->error = errno;
796 	return(0);
797     }
798     hcc_leaf_data(trans, LC_DATA, buf, n);
799     return(0);
800 }
801 
802 /*
803  * WRITE
804  */
805 ssize_t
806 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
807 {
808     hctransaction_t trans;
809     struct HCHead *head;
810     struct HCLeaf *item;
811     int *fdp;
812     int r;
813 
814     if (hc == NULL || hc->host == NULL)
815 	return(write(fd, buf, bytes));
816 
817     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
818     if (fdp) {
819 	r = 0;
820 	while (bytes) {
821 	    size_t limit = getiolimit();
822 	    int n = (bytes > limit) ? limit : bytes;
823 	    int x = 0;
824 
825 	    trans = hcc_start_command(hc, HC_WRITE);
826 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
827 	    hcc_leaf_data(trans, LC_DATA, buf, n);
828 	    if ((head = hcc_finish_command(trans)) == NULL)
829 		return(-1);
830 	    if (head->error)
831 		return(-1);
832 	    for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
833 		switch(item->leafid) {
834 		case LC_BYTES:
835 		    x = HCC_INT32(item);
836 		    break;
837 		}
838 	    }
839 	    if (x < 0 || x > n)
840 		return(-1);
841 	    r += x;
842 	    buf = (const char *)buf + x;
843 	    bytes -= x;
844 	    if (x < n)
845 		break;
846 	}
847 	return(r);
848     } else {
849 	return(-1);
850     }
851 }
852 
853 static int
854 rc_write(hctransaction_t trans, struct HCHead *head)
855 {
856     struct HCLeaf *item;
857     int *fdp = NULL;
858     void *buf = NULL;
859     int n = -1;
860 
861     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
862 	switch(item->leafid) {
863 	case LC_DESCRIPTOR:
864 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
865 	    break;
866 	case LC_DATA:
867 	    buf = HCC_BINARYDATA(item);
868 	    n = item->bytes - sizeof(*item);
869 	    break;
870 	}
871     }
872     if (fdp == NULL)
873 	return(-2);
874     if (n < 0 || n > 32768)
875 	return(-2);
876     n = write(*fdp, buf, n);
877     if (n < 0) {
878 	head->error = errno;
879     } else {
880 	hcc_leaf_int32(trans, LC_BYTES, n);
881     }
882     return(0);
883 }
884 
885 /*
886  * REMOVE
887  *
888  * NOTE: This function returns -errno if an error occured.
889  */
890 int
891 hc_remove(struct HostConf *hc, const char *path)
892 {
893     hctransaction_t trans;
894     struct HCHead *head;
895     int res;
896 
897     if (hc == NULL || hc->host == NULL) {
898 	res = remove(path);
899 	if (res < 0)
900 		res = -errno;
901 	return(res);
902     }
903 
904     trans = hcc_start_command(hc, HC_REMOVE);
905     hcc_leaf_string(trans, LC_PATH1, path);
906     if ((head = hcc_finish_command(trans)) == NULL)
907 	return(-EIO);
908     if (head->error)
909 	return(-(int)head->error);
910     return(0);
911 }
912 
913 static int
914 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
915 {
916     struct HCLeaf *item;
917     const char *path = NULL;
918 
919     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
920 	switch(item->leafid) {
921 	case LC_PATH1:
922 	    path = HCC_STRING(item);
923 	    break;
924 	}
925     }
926     if (path == NULL)
927 	return(-2);
928     return(remove(path));
929 }
930 
931 /*
932  * MKDIR
933  */
934 int
935 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
936 {
937     hctransaction_t trans;
938     struct HCHead *head;
939 
940     if (hc == NULL || hc->host == NULL)
941 	return(mkdir(path, mode));
942 
943     trans = hcc_start_command(hc, HC_MKDIR);
944     hcc_leaf_string(trans, LC_PATH1, path);
945     hcc_leaf_int32(trans, LC_MODE, mode);
946     if ((head = hcc_finish_command(trans)) == NULL)
947 	return(-1);
948     if (head->error)
949 	return(-1);
950     return(0);
951 }
952 
953 static int
954 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
955 {
956     struct HCLeaf *item;
957     const char *path = NULL;
958     mode_t mode = 0777;
959 
960     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
961 	switch(item->leafid) {
962 	case LC_PATH1:
963 	    path = HCC_STRING(item);
964 	    break;
965 	case LC_MODE:
966 	    mode = HCC_INT32(item);
967 	    break;
968 	}
969     }
970     if (path == NULL)
971 	return(-1);
972     return(mkdir(path, mode));
973 }
974 
975 /*
976  * RMDIR
977  */
978 int
979 hc_rmdir(struct HostConf *hc, const char *path)
980 {
981     hctransaction_t trans;
982     struct HCHead *head;
983 
984     if (hc == NULL || hc->host == NULL)
985 	return(rmdir(path));
986 
987     trans = hcc_start_command(hc, HC_RMDIR);
988     hcc_leaf_string(trans, LC_PATH1, path);
989     if ((head = hcc_finish_command(trans)) == NULL)
990 	return(-1);
991     if (head->error)
992 	return(-1);
993     return(0);
994 }
995 
996 static int
997 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
998 {
999     struct HCLeaf *item;
1000     const char *path = NULL;
1001 
1002     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1003 	switch(item->leafid) {
1004 	case LC_PATH1:
1005 	    path = HCC_STRING(item);
1006 	    break;
1007 	}
1008     }
1009     if (path == NULL)
1010 	return(-1);
1011     return(rmdir(path));
1012 }
1013 
1014 /*
1015  * CHOWN
1016  *
1017  * Almost silently ignore chowns that fail if we are not root.
1018  */
1019 int
1020 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1021 {
1022     hctransaction_t trans;
1023     struct HCHead *head;
1024     int rc;
1025 
1026     if (hc == NULL || hc->host == NULL) {
1027 	rc = chown(path, owner, group);
1028 	if (rc < 0)
1029 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1030 	return(rc);
1031     }
1032 
1033     trans = hcc_start_command(hc, HC_CHOWN);
1034     hcc_leaf_string(trans, LC_PATH1, path);
1035     hcc_leaf_int32(trans, LC_UID, owner);
1036     hcc_leaf_int32(trans, LC_GID, group);
1037     if ((head = hcc_finish_command(trans)) == NULL)
1038 	return(-1);
1039     if (head->error)
1040 	return(-1);
1041     return(0);
1042 }
1043 
1044 static int
1045 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1046 {
1047     struct HCLeaf *item;
1048     const char *path = NULL;
1049     uid_t uid = (uid_t)-1;
1050     gid_t gid = (gid_t)-1;
1051     int rc;
1052 
1053     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1054 	switch(item->leafid) {
1055 	case LC_PATH1:
1056 	    path = HCC_STRING(item);
1057 	    break;
1058 	case LC_UID:
1059 	    uid = HCC_INT32(item);
1060 	    break;
1061 	case LC_GID:
1062 	    gid = HCC_INT32(item);
1063 	    break;
1064 	}
1065     }
1066     if (path == NULL)
1067 	return(-1);
1068     rc = chown(path, uid, gid);
1069     if (rc < 0)
1070 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1071     return(rc);
1072 }
1073 
1074 /*
1075  * LCHOWN
1076  */
1077 int
1078 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1079 {
1080     hctransaction_t trans;
1081     struct HCHead *head;
1082     int rc;
1083 
1084     if (hc == NULL || hc->host == NULL) {
1085 	rc = lchown(path, owner, group);
1086 	if (rc < 0)
1087 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1088 	return(rc);
1089     }
1090 
1091     trans = hcc_start_command(hc, HC_LCHOWN);
1092     hcc_leaf_string(trans, LC_PATH1, path);
1093     hcc_leaf_int32(trans, LC_UID, owner);
1094     hcc_leaf_int32(trans, LC_GID, group);
1095     if ((head = hcc_finish_command(trans)) == NULL)
1096 	return(-1);
1097     if (head->error)
1098 	return(-1);
1099     return(0);
1100 }
1101 
1102 static int
1103 rc_lchown(hctransaction_t trans __unused, struct HCHead *head)
1104 {
1105     struct HCLeaf *item;
1106     const char *path = NULL;
1107     uid_t uid = (uid_t)-1;
1108     gid_t gid = (gid_t)-1;
1109     int rc;
1110 
1111     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1112 	switch(item->leafid) {
1113 	case LC_PATH1:
1114 	    path = HCC_STRING(item);
1115 	    break;
1116 	case LC_UID:
1117 	    uid = HCC_INT32(item);
1118 	    break;
1119 	case LC_GID:
1120 	    gid = HCC_INT32(item);
1121 	    break;
1122 	}
1123     }
1124     if (path == NULL)
1125 	return(-1);
1126     rc = lchown(path, uid, gid);
1127     if (rc < 0)
1128 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1129     return(rc);
1130 }
1131 
1132 /*
1133  * CHMOD
1134  */
1135 int
1136 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1137 {
1138     hctransaction_t trans;
1139     struct HCHead *head;
1140 
1141     if (hc == NULL || hc->host == NULL)
1142 	return(chmod(path, mode));
1143 
1144     trans = hcc_start_command(hc, HC_CHMOD);
1145     hcc_leaf_string(trans, LC_PATH1, path);
1146     hcc_leaf_int32(trans, LC_MODE, mode);
1147     if ((head = hcc_finish_command(trans)) == NULL)
1148 	return(-1);
1149     if (head->error)
1150 	return(-1);
1151     return(0);
1152 }
1153 
1154 static int
1155 rc_chmod(hctransaction_t trans __unused, struct HCHead *head)
1156 {
1157     struct HCLeaf *item;
1158     const char *path = NULL;
1159     mode_t mode = 0666;
1160 
1161     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1162 	switch(item->leafid) {
1163 	case LC_PATH1:
1164 	    path = HCC_STRING(item);
1165 	    break;
1166 	case LC_MODE:
1167 	    mode = HCC_INT32(item);
1168 	    break;
1169 	}
1170     }
1171     if (path == NULL)
1172 	return(-1);
1173     return(chmod(path, mode));
1174 }
1175 
1176 /*
1177  * MKNOD
1178  */
1179 int
1180 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1181 {
1182     hctransaction_t trans;
1183     struct HCHead *head;
1184 
1185     if (hc == NULL || hc->host == NULL)
1186 	return(mknod(path, mode, rdev));
1187 
1188     trans = hcc_start_command(hc, HC_MKNOD);
1189     hcc_leaf_string(trans, LC_PATH1, path);
1190     hcc_leaf_int32(trans, LC_MODE, mode);
1191     hcc_leaf_int32(trans, LC_RDEV, rdev);
1192     if ((head = hcc_finish_command(trans)) == NULL)
1193 	return(-1);
1194     if (head->error)
1195 	return(-1);
1196     return(0);
1197 }
1198 
1199 static int
1200 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1201 {
1202     struct HCLeaf *item;
1203     const char *path = NULL;
1204     mode_t mode = 0666;
1205     dev_t rdev = 0;
1206 
1207     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1208 	switch(item->leafid) {
1209 	case LC_PATH1:
1210 	    path = HCC_STRING(item);
1211 	    break;
1212 	case LC_MODE:
1213 	    mode = HCC_INT32(item);
1214 	    break;
1215 	case LC_RDEV:
1216 	    rdev = HCC_INT32(item);
1217 	    break;
1218 	}
1219     }
1220     if (path == NULL)
1221 	return(-1);
1222     return(mknod(path, mode, rdev));
1223 }
1224 
1225 /*
1226  * LINK
1227  */
1228 int
1229 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1230 {
1231     hctransaction_t trans;
1232     struct HCHead *head;
1233 
1234     if (hc == NULL || hc->host == NULL)
1235 	return(link(name1, name2));
1236 
1237     trans = hcc_start_command(hc, HC_LINK);
1238     hcc_leaf_string(trans, LC_PATH1, name1);
1239     hcc_leaf_string(trans, LC_PATH2, name2);
1240     if ((head = hcc_finish_command(trans)) == NULL)
1241 	return(-1);
1242     if (head->error)
1243 	return(-1);
1244     return(0);
1245 }
1246 
1247 static int
1248 rc_link(hctransaction_t trans __unused, struct HCHead *head)
1249 {
1250     struct HCLeaf *item;
1251     const char *name1 = NULL;
1252     const char *name2 = NULL;
1253 
1254     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1255 	switch(item->leafid) {
1256 	case LC_PATH1:
1257 	    name1 = HCC_STRING(item);
1258 	    break;
1259 	case LC_PATH2:
1260 	    name2 = HCC_STRING(item);
1261 	    break;
1262 	}
1263     }
1264     if (name1 == NULL || name2 == NULL)
1265 	return(-2);
1266     return(link(name1, name2));
1267 }
1268 
1269 #ifdef _ST_FLAGS_PRESENT_
1270 /*
1271  * CHFLAGS
1272  */
1273 int
1274 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1275 {
1276     hctransaction_t trans;
1277     struct HCHead *head;
1278     int rc;
1279 
1280     if (hc == NULL || hc->host == NULL) {
1281 	rc = chflags(path, flags);
1282 	if (rc < 0) {
1283 	    if (RunningAsUser) {
1284 		flags &= UF_SETTABLE;
1285 		rc = chflags(path, flags);
1286 	    }
1287 	    if (rc < 0)
1288 		rc = silentwarning(&chflags_warning, "file flags may differ\n");
1289 	}
1290 	return (rc);
1291     }
1292 
1293     trans = hcc_start_command(hc, HC_CHFLAGS);
1294     hcc_leaf_string(trans, LC_PATH1, path);
1295     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1296     if ((head = hcc_finish_command(trans)) == NULL)
1297 	return(-1);
1298     if (head->error)
1299 	return(-1);
1300     return(0);
1301 }
1302 
1303 static int
1304 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1305 {
1306     struct HCLeaf *item;
1307     const char *path = NULL;
1308     u_long flags = 0;
1309     int rc;
1310 
1311     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1312 	switch(item->leafid) {
1313 	case LC_PATH1:
1314 	    path = HCC_STRING(item);
1315 	    break;
1316 	case LC_FILEFLAGS:
1317 	    flags = (u_long)HCC_INT64(item);
1318 	    break;
1319 	}
1320     }
1321     if (path == NULL)
1322 	return(-2);
1323     rc = chflags(path, flags);
1324     if (rc < 0) {
1325 	if (RunningAsUser) {
1326 	    flags &= UF_SETTABLE;
1327 	    rc = chflags(path, flags);
1328 	}
1329 	if (rc < 0)
1330 	    rc = silentwarning(&chflags_warning, "file flags may differ\n");
1331     }
1332     return(rc);
1333 }
1334 
1335 #endif
1336 
1337 /*
1338  * READLINK
1339  */
1340 int
1341 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1342 {
1343     hctransaction_t trans;
1344     struct HCHead *head;
1345     struct HCLeaf *item;
1346     int r;
1347 
1348     if (hc == NULL || hc->host == NULL)
1349 	return(readlink(path, buf, bufsiz));
1350 
1351     trans = hcc_start_command(hc, HC_READLINK);
1352     hcc_leaf_string(trans, LC_PATH1, path);
1353     if ((head = hcc_finish_command(trans)) == NULL)
1354 	return(-1);
1355     if (head->error)
1356 	return(-1);
1357 
1358     r = 0;
1359     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1360 	switch(item->leafid) {
1361 	case LC_DATA:
1362 	    r = item->bytes - sizeof(*item);
1363 	    if (r < 0)
1364 		r = 0;
1365 	    if (r > bufsiz)
1366 		r = bufsiz;
1367 	    bcopy(HCC_BINARYDATA(item), buf, r);
1368 	    break;
1369 	}
1370     }
1371     return(r);
1372 }
1373 
1374 static int
1375 rc_readlink(hctransaction_t trans, struct HCHead *head)
1376 {
1377     struct HCLeaf *item;
1378     const char *path = NULL;
1379     char buf[1024];
1380     int r;
1381 
1382     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1383 	switch(item->leafid) {
1384 	case LC_PATH1:
1385 	    path = HCC_STRING(item);
1386 	    break;
1387 	}
1388     }
1389     if (path == NULL)
1390 	return(-2);
1391     r = readlink(path, buf, sizeof(buf));
1392     if (r < 0)
1393 	return(-1);
1394     hcc_leaf_data(trans, LC_DATA, buf, r);
1395     return(0);
1396 }
1397 
1398 /*
1399  * UMASK
1400  */
1401 mode_t
1402 hc_umask(struct HostConf *hc, mode_t numask)
1403 {
1404     hctransaction_t trans;
1405     struct HCHead *head;
1406     struct HCLeaf *item;
1407 
1408     if (hc == NULL || hc->host == NULL)
1409 	return(umask(numask));
1410 
1411     trans = hcc_start_command(hc, HC_UMASK);
1412     hcc_leaf_int32(trans, LC_MODE, numask);
1413     if ((head = hcc_finish_command(trans)) == NULL)
1414 	return((mode_t)-1);
1415     if (head->error)
1416 	return((mode_t)-1);
1417 
1418     numask = ~0666;
1419     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1420 	switch(item->leafid) {
1421 	case LC_MODE:
1422 	    numask = HCC_INT32(item);
1423 	    break;
1424 	}
1425     }
1426     return(numask);
1427 }
1428 
1429 static int
1430 rc_umask(hctransaction_t trans, struct HCHead *head)
1431 {
1432     struct HCLeaf *item;
1433     mode_t numask = ~0666;
1434 
1435     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1436 	switch(item->leafid) {
1437 	case LC_MODE:
1438 	    numask = HCC_INT32(item);
1439 	    break;
1440 	}
1441     }
1442     numask = umask(numask);
1443     hcc_leaf_int32(trans, LC_MODE, numask);
1444     return(0);
1445 }
1446 
1447 /*
1448  * SYMLINK
1449  */
1450 int
1451 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1452 {
1453     hctransaction_t trans;
1454     struct HCHead *head;
1455 
1456     if (hc == NULL || hc->host == NULL)
1457 	return(symlink(name1, name2));
1458 
1459     trans = hcc_start_command(hc, HC_SYMLINK);
1460     hcc_leaf_string(trans, LC_PATH1, name1);
1461     hcc_leaf_string(trans, LC_PATH2, name2);
1462     if ((head = hcc_finish_command(trans)) == NULL)
1463 	return(-1);
1464     if (head->error)
1465 	return(-1);
1466     return(0);
1467 }
1468 
1469 static int
1470 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1471 {
1472     struct HCLeaf *item;
1473     const char *name1 = NULL;
1474     const char *name2 = NULL;
1475 
1476     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1477 	switch(item->leafid) {
1478 	case LC_PATH1:
1479 	    name1 = HCC_STRING(item);
1480 	    break;
1481 	case LC_PATH2:
1482 	    name2 = HCC_STRING(item);
1483 	    break;
1484 	}
1485     }
1486     if (name1 == NULL || name2 == NULL)
1487 	return(-2);
1488     return(symlink(name1, name2));
1489 }
1490 
1491 /*
1492  * RENAME
1493  */
1494 int
1495 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1496 {
1497     hctransaction_t trans;
1498     struct HCHead *head;
1499 
1500     if (hc == NULL || hc->host == NULL)
1501 	return(rename(name1, name2));
1502 
1503     trans = hcc_start_command(hc, HC_RENAME);
1504     hcc_leaf_string(trans, LC_PATH1, name1);
1505     hcc_leaf_string(trans, LC_PATH2, name2);
1506     if ((head = hcc_finish_command(trans)) == NULL)
1507 	return(-1);
1508     if (head->error)
1509 	return(-1);
1510     return(0);
1511 }
1512 
1513 static int
1514 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1515 {
1516     struct HCLeaf *item;
1517     const char *name1 = NULL;
1518     const char *name2 = NULL;
1519 
1520     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1521 	switch(item->leafid) {
1522 	case LC_PATH1:
1523 	    name1 = HCC_STRING(item);
1524 	    break;
1525 	case LC_PATH2:
1526 	    name2 = HCC_STRING(item);
1527 	    break;
1528 	}
1529     }
1530     if (name1 == NULL || name2 == NULL)
1531 	return(-2);
1532     return(rename(name1, name2));
1533 }
1534 
1535 /*
1536  * UTIMES
1537  */
1538 int
1539 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1540 {
1541     hctransaction_t trans;
1542     struct HCHead *head;
1543 
1544     if (hc == NULL || hc->host == NULL)
1545 	return(utimes(path, times));
1546 
1547     trans = hcc_start_command(hc, HC_UTIMES);
1548     hcc_leaf_string(trans, LC_PATH1, path);
1549     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1550     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1551     if ((head = hcc_finish_command(trans)) == NULL)
1552 	return(-1);
1553     if (head->error)
1554 	return(-1);
1555     return(0);
1556 }
1557 
1558 static int
1559 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1560 {
1561     struct HCLeaf *item;
1562     struct timeval times[2];
1563     const char *path;
1564 
1565     bzero(times, sizeof(times));
1566     path = NULL;
1567 
1568     for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1569 	switch(item->leafid) {
1570 	case LC_PATH1:
1571 	    path = HCC_STRING(item);
1572 	    break;
1573 	case LC_ATIME:
1574 	    times[0].tv_sec = HCC_INT64(item);
1575 	    break;
1576 	case LC_MTIME:
1577 	    times[1].tv_sec = HCC_INT64(item);
1578 	    break;
1579 	}
1580     }
1581     if (path == NULL)
1582 	return(-2);
1583     return(utimes(path, times));
1584 }
1585