]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hgfs/patch.c
hgfs: various improvements
[plan9front.git] / sys / src / cmd / hgfs / patch.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 int
8 fcopy(int dfd, int sfd, vlong off, vlong len)
9 {
10         uchar buf[BUFSZ];
11         int n;
12
13         while(len != 0){
14                 n = BUFSZ;
15                 if(len > 0 && n > len)
16                         n = len;
17                 if((n = pread(sfd, buf, n, off)) < 0)
18                         return -1;
19                 if(n == 0)
20                         return len > 0 ? -1 : 0;
21                 if(write(dfd, buf, n) != n)
22                         return -1;
23                 if(off >= 0)
24                         off += n;
25                 if(len > 0)
26                         len -= n;
27         }
28         return 0;
29 }
30
31 static uchar patchmark[12] = {
32         0xff, 0xff, 0xff, 0xff,
33         0xff, 0xff, 0xff, 0xff,
34         0xff, 0xff, 0xff, 0xff,
35 };
36
37 int
38 fpatchmark(int pfd, char *)
39 {
40         if(write(pfd, patchmark, 12) != 12)
41                 return -1;
42         return 0;
43 }
44
45 typedef struct Frag Frag;
46 struct Frag
47 {
48         Frag    *next;
49         int     fd;
50         vlong   len;
51         vlong   off;
52 };
53
54 int
55 fpatch(int ofd, int bfd, int pfd)
56 {
57         vlong off, fstart, fend, start, end, len;
58         int err, front, back;
59         Frag *h, *f, *p;
60         uchar buf[12];
61
62         h = nil;
63         err = -1;
64
65         if(bfd >= 0){
66                 h = malloc(sizeof(Frag));
67                 if(h == nil)
68                         goto errout;
69                 h->next = nil;
70                 h->off = 0;
71                 h->fd = bfd;
72                 h->len = seek(h->fd, 0, 2);
73                 if(h->len < 0)
74                         goto errout;
75         }
76
77         off = 0;
78         while(pfd >= 0){
79                 if(readn(pfd, buf, 12) != 12)
80                         break;
81
82                 if(memcmp(buf, patchmark, 12) == 0){
83                         off = 0;
84                         continue;
85                 }
86
87                 start = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
88                 end = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
89                 len = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
90
91                 if(start > end){
92                         werrstr("bad patch: start > end");
93                         goto errout;
94                 }
95
96                 start += off;
97                 end += off;
98                 off += start + len - end;
99
100                 fstart = 0;
101                 for(f = h; f; f = f->next, fstart = fend){
102                         fend = fstart + f->len;
103                         if(fend <= start)
104                                 continue;
105                         if(fstart >= end)
106                                 break;
107
108                         front = start > fstart;
109                         back = end < fend;
110                         if(front && back){
111                                 p = malloc(sizeof(Frag));
112                                 if(p == nil)
113                                         goto errout;
114                                 *p = *f;
115                                 f->next = p;
116                                 f->len = start - fstart;
117                                 p->off += end - fstart;
118                                 p->len -= end - fstart;
119                                 break;
120                         } else if(back){
121                                 f->off += end - fstart;
122                                 f->len -= end - fstart;
123                                 break;
124                         } else if(front){
125                                 f->len = start - fstart;
126                         } else {
127                                 f->len = 0;
128                         }
129                 }
130
131                 fstart = 0;
132                 for(p = nil, f = h; f && fstart < start; p = f, f = f->next)
133                         fstart += f->len;
134
135                 f = malloc(sizeof(Frag));
136                 if(f == nil)
137                         goto errout;
138                 f->fd = pfd;
139                 f->len = len;
140                 f->off = seek(f->fd, 0, 1);
141
142                 if(p){
143                         f->next = p->next;
144                         p->next = f;
145                 } else {
146                         f->next = h;
147                         h = f;
148                 }
149
150                 if(f->off < 0)
151                         goto errout;
152                 if(seek(pfd, f->len, 1) < 0)
153                         goto errout;
154         }
155
156         for(f = h; f; f = f->next)
157                 if(fcopy(ofd, f->fd, f->off, f->len) < 0)
158                         goto errout;
159         err = 0;
160
161 errout:
162         while(f = h){
163                 h = f->next;
164                 free(f);
165         }
166
167         return err;
168 }