Merge from vendor branch LESS:
[dragonfly.git] / sbin / jscan / dump_mirror.c
CommitLineData
712e03b0
MD
1/*
2 * Copyright (c) 2005 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
c0c3e80b 34 * $DragonFly: src/sbin/jscan/dump_mirror.c,v 1.8 2005/11/06 12:32:56 swildner Exp $
712e03b0
MD
35 */
36
37#include "jscan.h"
36456e49 38#include <sys/vfscache.h>
712e03b0 39
36456e49
MD
40static void dump_mirror_stream(struct jsession *ss, struct jstream *js);
41static int dump_mirror_toprecord(struct jsession *ss, struct jstream *js,
42 off_t *off, off_t recsize, int level);
43static int dump_mirror_subrecord(enum jdirection direction, struct jstream *js,
44 off_t *off, off_t recsize, int level,
45 struct jattr *jattr);
712e03b0
MD
46static int dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
47 int recsize, int level, struct jattr *jattr);
36456e49
MD
48static int dump_mirror_rebuild_redo(u_int16_t rectype,
49 struct jstream *js, struct jattr *jattr);
50static int dump_mirror_rebuild_undo(u_int16_t rectype,
51 struct jstream *js, struct jattr *jattr);
52static void undo_recreate(const char *filename,
53 struct jstream *js, struct jattr *jattr);
54static void dosetattr(const char *filename, int fd, struct jattr *jattr);
712e03b0
MD
55
56void
bb406b71 57dump_mirror(struct jsession *ss, struct jdata *jd)
712e03b0
MD
58{
59 struct jstream *js;
60
36456e49
MD
61 if ((js = jaddrecord(ss, jd)) != NULL) {
62 dump_mirror_stream(ss, js);
63 jscan_dispose(js);
712e03b0 64 }
36456e49 65 jsession_update_transid(ss, jd->jd_transid);
712e03b0
MD
66}
67
68static void
36456e49 69dump_mirror_stream(struct jsession *ss, struct jstream *js)
712e03b0
MD
70{
71 struct journal_rawrecbeg head;
72 int16_t sid;
73 mode_t save_umask;
74
75 save_umask = umask(0);
76 jsread(js, 0, &head, sizeof(head));
77
78 sid = head.streamid & JREC_STREAMID_MASK;
712e03b0
MD
79 if (sid >= JREC_STREAMID_JMIN && sid < JREC_STREAMID_JMAX) {
80 off_t off = sizeof(head);
36456e49
MD
81 dump_mirror_toprecord(ss, js, &off,
82 js->js_normalized_total -
83 sizeof(struct journal_rawrecbeg),
712e03b0
MD
84 1);
85 } else {
86 switch(head.streamid & JREC_STREAMID_MASK) {
87 case JREC_STREAMID_SYNCPT & JREC_STREAMID_MASK:
712e03b0
MD
88 break;
89 case JREC_STREAMID_PAD & JREC_STREAMID_MASK:
712e03b0
MD
90 break;
91 case JREC_STREAMID_DISCONT & JREC_STREAMID_MASK:
712e03b0
MD
92 break;
93 case JREC_STREAMID_ANNOTATE & JREC_STREAMID_MASK:
712e03b0
MD
94 break;
95 default:
712e03b0
MD
96 break;
97 }
98 }
99 umask(save_umask);
712e03b0
MD
100}
101
36456e49
MD
102/*
103 * Execute a meta-transaction, e.g. something like 'WRITE'. Meta-transactions
104 * are almost universally nested.
105 */
712e03b0 106static int
36456e49
MD
107dump_mirror_toprecord(struct jsession *ss, struct jstream *js,
108 off_t *off, off_t recsize, int level)
712e03b0
MD
109{
110 struct journal_subrecord sub;
111 struct jattr jattr;
112 int payload;
113 int subsize;
114 int error;
115 off_t base = *off;
116
117 error = 0;
118 bzero(&jattr, sizeof(jattr));
119 jattr_reset(&jattr);
120
121 while (recsize > 0) {
122 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
123 break;
712e03b0
MD
124 if (sub.recsize == -1) {
125 if ((sub.rectype & JMASK_NESTED) == 0) {
126 printf("Record size of -1 only works for nested records\n");
127 error = -1;
128 break;
129 }
130 payload = 0x7FFFFFFF;
131 subsize = 0x7FFFFFFF;
132 } else {
133 payload = sub.recsize - sizeof(sub);
134 subsize = (sub.recsize + 7) & ~7;
135 }
136 if (sub.rectype & JMASK_NESTED) {
712e03b0 137 *off = base + sizeof(sub);
36456e49 138 error = dump_mirror_subrecord(ss->ss_direction, js, off,
712e03b0 139 payload, level + 1, &jattr);
712e03b0 140 } else if (sub.rectype & JMASK_SUBRECORD) {
712e03b0 141 *off = base + sizeof(sub) + payload;
36d6bdee 142 } else if ((sub.rectype & JTYPE_MASK) == JLEAF_PAD) {
712e03b0 143 } else {
712e03b0 144 }
36456e49
MD
145 if (ss->ss_direction == JD_FORWARDS)
146 dump_mirror_rebuild_redo(sub.rectype, js, &jattr);
147 else
148 dump_mirror_rebuild_undo(sub.rectype, js, &jattr);
712e03b0
MD
149 jattr_reset(&jattr);
150 if (error)
151 break;
152 if (sub.recsize == -1) {
153 if ((sub.rectype & JMASK_NESTED) == 0) {
154 printf("Record size of -1 only works for nested records\n");
155 error = -1;
156 break;
157 }
158 recsize -= ((*off + 7) & ~7) - base;
159 base = (*off + 7) & ~7;
160 } else {
161 if (subsize == 0)
162 subsize = sizeof(sub);
163 recsize -= subsize;
164 base += subsize;
165 }
166 if (sub.rectype & JMASK_LAST)
167 break;
168 }
169 *off = base;
170 return(error);
171}
172
36456e49
MD
173/*
174 * Parse a meta-transaction's nested records. The highest subrecord layer
175 * starts at layer = 2 (the top layer specifying the command is layer = 1).
176 *
177 * The nested subrecord contains informational records containing primarily
178 * namespace data, and further subrecords containing nested
179 * audit, undo, and redo data.
180 */
712e03b0 181static int
36456e49
MD
182dump_mirror_subrecord(enum jdirection direction, struct jstream *js,
183 off_t *off, off_t recsize, int level,
712e03b0
MD
184 struct jattr *jattr)
185{
186 struct journal_subrecord sub;
187 int payload;
188 int subsize;
189 int error;
36456e49 190 int skip;
712e03b0
MD
191 u_int16_t rectype;
192 off_t base = *off;
193
194 error = 0;
195 while (recsize > 0) {
196 if ((error = jsread(js, base, &sub, sizeof(sub))) != 0)
197 break;
36456e49 198 rectype = sub.rectype & JTYPE_MASK; /* includes the nested bit */
712e03b0
MD
199 if (sub.recsize == -1) {
200 payload = 0x7FFFFFFF;
201 subsize = 0x7FFFFFFF;
202 } else {
203 payload = sub.recsize - sizeof(sub);
204 subsize = (sub.recsize + 7) & ~7;
205 }
36456e49
MD
206
207 skip = 1;
208 *off = base + sizeof(sub);
209
210 switch(rectype) {
211 case JTYPE_REDO: /* NESTED */
712e03b0 212 /*
36456e49 213 * Process redo information when scanning forwards.
712e03b0 214 */
36456e49
MD
215 if (direction == JD_FORWARDS) {
216 error = dump_mirror_subrecord(direction, js, off, payload,
217 level + 1, jattr);
218 skip = 0;
712e03b0 219 }
36456e49
MD
220 break;
221 case JTYPE_UNDO: /* NESTED */
222 /*
223 * Process undo information when scanning backwards.
224 */
225 if (direction == JD_BACKWARDS) {
226 error = dump_mirror_subrecord(direction, js, off, payload,
227 level + 1, jattr);
228 skip = 0;
229 }
230 break;
231 case JTYPE_CRED: /* NESTED */
232 /*
233 * Ignore audit information
234 */
235 break;
236 default: /* NESTED or non-NESTED */
237 /*
238 * Execute these. Nested records might contain attribute
239 * information under an UNDO or REDO parent, for example.
240 */
241 if (rectype & JMASK_NESTED) {
242 error = dump_mirror_subrecord(direction, js, off, payload,
243 level + 1, jattr);
244 skip = 0;
245 } else if (rectype & JMASK_SUBRECORD) {
246 error = dump_mirror_payload(sub.rectype, js, *off, payload,
247 level, jattr);
248 }
249 break;
712e03b0
MD
250 }
251 if (error)
252 break;
36456e49
MD
253
254 /*
255 * skip only applies to nested subrecords. If the record size
256 * is unknown the record MUST be a nested record, and if we have
257 * not processed it we must recurse to figure out the actual size.
258 */
712e03b0 259 if (sub.recsize == -1) {
36456e49
MD
260 assert(sub.rectype & JMASK_NESTED);
261 if (skip) {
262 error = dump_mirror_subrecord(direction, js, off, payload,
263 level + 1, NULL);
264 }
712e03b0
MD
265 recsize -= ((*off + 7) & ~7) - base;
266 base = (*off + 7) & ~7;
267 } else {
268 if (subsize == 0)
269 subsize = sizeof(sub);
270 recsize -= subsize;
271 base += subsize;
272 }
36456e49
MD
273 if (error)
274 break;
712e03b0
MD
275 if (sub.rectype & JMASK_LAST)
276 break;
277 }
278 *off = base;
279 return(error);
280}
281
282static int
283dump_mirror_payload(int16_t rectype, struct jstream *js, off_t off,
284 int recsize, int level __unused, struct jattr *jattr)
285{
286 const char *buf;
36d6bdee 287 struct jattr_data *data;
712e03b0
MD
288 int error;
289
290 if (jattr == NULL)
291 return (0);
292
36d6bdee
MD
293 if ((rectype & ~JMASK_LAST) != JLEAF_FILEDATA) {
294 error = jsreadp(js, off, (const void **)&buf, recsize);
295 if (error)
296 return (error);
297 } else {
298 buf = NULL;
299 error = 0;
300 }
712e03b0
MD
301
302 switch(rectype & ~JMASK_LAST) {
303 case JLEAF_PAD:
304 case JLEAF_ABORT:
305 break;
36d6bdee 306 case JLEAF_SYMLINKDATA:
fa8f36eb
MD
307 jattr->symlinkdata = dupdatastr(buf, recsize);
308 jattr->symlinklen = recsize;
309 break;
712e03b0 310 case JLEAF_FILEDATA:
36d6bdee
MD
311 if ((data = jattr->last_data) == NULL) {
312 jattr->data.off = off;
313 jattr->data.bytes = recsize;
314 jattr->last_data = &jattr->data;
315 } else {
316 data->next = malloc(sizeof(jattr->data));
317 data = data->next;
318 data->off = off;
319 data->bytes = recsize;
320 data->next = NULL;
321 jattr->last_data = data;
322 }
712e03b0
MD
323 break;
324 case JLEAF_PATH1:
325 jattr->path1 = dupdatapath(buf, recsize);
326 break;
327 case JLEAF_PATH2:
328 jattr->path2 = dupdatapath(buf, recsize);
329 break;
330 case JLEAF_PATH3:
331 jattr->path3 = dupdatapath(buf, recsize);
332 break;
333 case JLEAF_PATH4:
334 jattr->path4 = dupdatapath(buf, recsize);
335 break;
336 case JLEAF_UID:
337 jattr->uid = buf_to_int64(buf, recsize);
338 break;
339 case JLEAF_GID:
340 jattr->gid = buf_to_int64(buf, recsize);
341 break;
342 case JLEAF_VTYPE:
343 jattr->vtype = buf_to_int64(buf, recsize);
344 break;
345 case JLEAF_MODES:
346 jattr->modes = buf_to_int64(buf, recsize);
347 break;
348 case JLEAF_FFLAGS:
349 jattr->fflags = buf_to_int64(buf, recsize);
350 break;
351 case JLEAF_PID:
352 jattr->pid = buf_to_int64(buf, recsize);
353 break;
354 case JLEAF_PPID:
355 jattr->ppid = buf_to_int64(buf, recsize);
356 break;
357 case JLEAF_COMM:
358 jattr->comm = dupdatastr(buf, recsize);
359 break;
360 case JLEAF_ATTRNAME:
361 jattr->attrname = dupdatastr(buf, recsize);
362 break;
363 case JLEAF_PATH_REF:
364 jattr->pathref = dupdatapath(buf, recsize);
365 break;
366 case JLEAF_RESERVED_0F:
367 break;
712e03b0
MD
368 case JLEAF_SEEKPOS:
369 jattr->seekpos = buf_to_int64(buf, recsize);
370 break;
371 case JLEAF_INUM:
372 jattr->inum = buf_to_int64(buf, recsize);
373 break;
374 case JLEAF_NLINK:
375 jattr->nlink = buf_to_int64(buf, recsize);
376 break;
377 case JLEAF_FSID:
378 jattr->fsid = buf_to_int64(buf, recsize);
379 break;
380 case JLEAF_SIZE:
381 jattr->size = buf_to_int64(buf, recsize);
382 break;
383 case JLEAF_ATIME:
384 jattr->atime = *(const struct timeval *)buf;
385 break;
386 case JLEAF_MTIME:
387 jattr->mtime = *(const struct timeval *)buf;
388 break;
389 case JLEAF_CTIME:
390 jattr->ctime = *(const struct timeval *)buf;
391 break;
392 case JLEAF_GEN:
393 jattr->gen = buf_to_int64(buf, recsize);
394 break;
395 case JLEAF_FLAGS:
396 jattr->flags = buf_to_int64(buf, recsize);
397 break;
398 case JLEAF_UDEV:
399 jattr->udev = buf_to_int64(buf, recsize);
400 break;
401 case JLEAF_FILEREV:
402 jattr->filerev = buf_to_int64(buf, recsize);
403 break;
404 default:
405 break;
406 }
407 return (0);
408}
409
410static int
36456e49
MD
411dump_mirror_rebuild_redo(u_int16_t rectype, struct jstream *js,
412 struct jattr *jattr)
712e03b0 413{
36d6bdee 414 struct jattr_data *data;
712e03b0
MD
415 int error = 0;
416 int fd;
417
36456e49
MD
418 if (verbose_opt > 2) {
419 fprintf(stderr, "REDO %04x %s %s\n",
420 js->js_head->streamid, type_to_name(rectype),
421 jattr->pathref ? jattr->pathref : jattr->path1);
422 }
712e03b0
MD
423 switch(rectype) {
424 case JTYPE_SETATTR:
425 if (jattr->pathref) {
426 if (jattr->uid != (uid_t)-1)
427 chown(jattr->pathref, jattr->uid, -1);
428 if (jattr->gid != (gid_t)-1)
429 chown(jattr->pathref, -1, jattr->gid);
430 if (jattr->modes != (mode_t)-1)
431 chmod(jattr->pathref, jattr->modes);
432 if (jattr->fflags != -1)
433 chflags(jattr->pathref, jattr->fflags);
434 if (jattr->size != -1)
435 truncate(jattr->pathref, jattr->size);
436 }
437 break;
438 case JTYPE_WRITE:
439 case JTYPE_PUTPAGES:
36d6bdee 440 if (jattr->pathref && jattr->seekpos != -1) {
712e03b0
MD
441 if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
442 lseek(fd, jattr->seekpos, 0);
36d6bdee 443 for (data = &jattr->data; data; data = data->next) {
36d6bdee
MD
444 if (data->bytes)
445 jsreadcallback(js, write, fd, data->off, data->bytes);
446 }
712e03b0
MD
447 close(fd);
448 }
449 }
450 break;
451 case JTYPE_SETACL:
452 break;
453 case JTYPE_SETEXTATTR:
454 break;
455 case JTYPE_CREATE:
456 /*
457 * note: both path1 and pathref will exist.
458 */
459 if (jattr->path1 && jattr->modes != (mode_t)-1) {
460 if ((fd = open(jattr->path1, O_CREAT, jattr->modes)) >= 0) {
36456e49 461 dosetattr(jattr->path1, fd, jattr);
712e03b0 462 close(fd);
712e03b0
MD
463 }
464 }
465 break;
466 case JTYPE_MKNOD:
36456e49 467 /* XXX */
712e03b0
MD
468 break;
469 case JTYPE_LINK:
fa8f36eb
MD
470 if (jattr->pathref && jattr->path1) {
471 link(jattr->pathref, jattr->path1);
472 }
712e03b0
MD
473 break;
474 case JTYPE_SYMLINK:
fa8f36eb
MD
475 if (jattr->symlinkdata && jattr->path1) {
476 symlink(jattr->symlinkdata, jattr->path1);
477 }
712e03b0
MD
478 break;
479 case JTYPE_WHITEOUT:
480 break;
481 case JTYPE_REMOVE:
482 if (jattr->path1) {
483 remove(jattr->path1);
484 }
485 break;
486 case JTYPE_MKDIR:
487 if (jattr->path1 && jattr->modes != (mode_t)-1) {
488 mkdir(jattr->path1, jattr->modes);
489 }
490 break;
491 case JTYPE_RMDIR:
492 if (jattr->path1) {
493 rmdir(jattr->path1);
494 }
495 break;
496 case JTYPE_RENAME:
497 if (jattr->path1 && jattr->path2) {
498 rename(jattr->path1, jattr->path2);
499 }
500 break;
501 }
502 return(error);
503}
504
36456e49
MD
505/*
506 * UNDO function using parsed primary data and parsed UNDO data. This
507 * must typically
508 */
509static int
510dump_mirror_rebuild_undo(u_int16_t rectype, struct jstream *js,
511 struct jattr *jattr)
512{
513 struct jattr_data *data;
514 int error = 0;
515 int fd;
516
517 if (verbose_opt > 2) {
518 fprintf(stderr, "UNDO %04x %s %s\n",
519 js->js_head->streamid, type_to_name(rectype),
520 jattr->pathref ? jattr->pathref : jattr->path1);
521 }
522 switch(rectype) {
523 case JTYPE_SETATTR:
524 if (jattr->pathref)
525 dosetattr(jattr->pathref, -1, jattr);
526 break;
527 case JTYPE_WRITE:
528 case JTYPE_PUTPAGES:
529 if (jattr->pathref && jattr->seekpos != -1) {
530 if ((fd = open(jattr->pathref, O_RDWR)) >= 0) {
531 lseek(fd, jattr->seekpos, 0);
532 for (data = &jattr->data; data; data = data->next) {
533 if (data->bytes)
534 jsreadcallback(js, write, fd, data->off, data->bytes);
535 }
536 close(fd);
537 }
538 }
539 if (jattr->size != -1)
540 truncate(jattr->pathref, jattr->size);
541 break;
542 case JTYPE_SETACL:
543 break;
544 case JTYPE_SETEXTATTR:
545 break;
546 case JTYPE_CREATE:
547 /*
548 * note: both path1 and pathref will exist.
549 */
550 if (jattr->path1)
551 remove(jattr->path1);
552 break;
553 case JTYPE_MKNOD:
554 if (jattr->path1)
555 remove(jattr->path1);
556 break;
557 case JTYPE_LINK:
558 if (jattr->path1) {
559 undo_recreate(jattr->path1, js, jattr);
560 }
561 break;
562 case JTYPE_SYMLINK:
563 if (jattr->symlinkdata && jattr->path1) {
564 undo_recreate(jattr->path1, js, jattr);
565 }
566 break;
567 case JTYPE_WHITEOUT:
568 /* XXX */
569 break;
570 case JTYPE_REMOVE:
571 if (jattr->path1) {
572 undo_recreate(jattr->path1, js, jattr);
573 }
574 break;
575 case JTYPE_MKDIR:
576 if (jattr->path1) {
577 rmdir(jattr->path1);
578 }
579 break;
580 case JTYPE_RMDIR:
581 if (jattr->path1 && jattr->modes != (mode_t)-1) {
582 mkdir(jattr->path1, jattr->modes);
583 }
584 break;
585 case JTYPE_RENAME:
586 if (jattr->path2) {
587 undo_recreate(jattr->path2, js, jattr);
588 }
589 break;
590 }
591 return(error);
592}
593
594/*
595 * This is a helper function for undoing operations which completely destroy
596 * the file that had existed previously. The caller will clean up the
597 * attributes (including file truncations/extensions) after the fact.
598 */
c0c3e80b 599static void
36456e49
MD
600undo_recreate(const char *filename, struct jstream *js, struct jattr *jattr)
601{
602 struct jattr_data *data;
603 int fd;
604
605 if (verbose_opt > 2)
606 fprintf(stderr, "RECREATE %s (type %d)\n", filename, jattr->vtype);
607
608 remove(filename);
609 switch(jattr->vtype) {
610 case VREG:
611 if (jattr->size != -1) {
612 if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) >= 0) {
613 if (jattr->seekpos != -1) {
614 lseek(fd, jattr->seekpos, 0);
615 for (data = &jattr->data; data; data = data->next) {
616 if (data->bytes)
617 jsreadcallback(js, write, fd, data->off, data->bytes);
618 }
619 }
620 dosetattr(filename, fd, jattr);
621 close(fd);
622 }
623 }
624 break;
625 case VDIR:
626 mkdir(filename, 0600);
627 dosetattr(filename, -1, jattr);
628 break;
629 case VBLK:
630 case VCHR:
631 if (jattr->udev) {
632 mknod(filename, S_IFBLK|0666, jattr->udev);
633 dosetattr(filename, -1, jattr);
634 }
635 break;
636 case VLNK:
637 if (jattr->symlinkdata) {
638 symlink(jattr->symlinkdata, filename);
639 dosetattr(filename, -1, jattr);
640 }
641 break;
642 default:
643 break;
644 }
645}
646
c0c3e80b 647static void
36456e49
MD
648dosetattr(const char *filename, int fd, struct jattr *jattr)
649{
650 if (fd >= 0) {
651 if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1)
652 fchown(fd, jattr->uid, jattr->gid);
653 else if (jattr->uid != (uid_t)-1)
654 fchown(fd, jattr->uid, -1);
655 else if (jattr->gid != (gid_t)-1)
656 fchown(fd, -1, jattr->gid);
657
658 if (jattr->modes != (mode_t)-1)
659 fchmod(fd, jattr->modes);
660 if (jattr->fflags != -1)
661 fchflags(fd, jattr->fflags);
662 if (jattr->size != -1)
663 ftruncate(fd, jattr->size);
664 } else {
665 if (jattr->uid != (uid_t)-1 && jattr->gid != (gid_t)-1)
666 lchown(filename, jattr->uid, jattr->gid);
667 else if (jattr->uid != (uid_t)-1)
668 lchown(filename, jattr->uid, -1);
669 else if (jattr->gid != (gid_t)-1)
670 lchown(filename, -1, jattr->gid);
671
672 if (jattr->modes != (mode_t)-1)
673 lchmod(filename, jattr->modes);
674 if (jattr->fflags != -1)
675 chflags(filename, jattr->fflags);
676 if (jattr->size != -1)
677 truncate(filename, jattr->size);
678 }
679}
680