Merge branch 'vendor/GMP' into gcc441
[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(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 }