1 #include "../burp.h"
2 #include "../action.h"
3 #include "../asfd.h"
4 #include "../async.h"
5 #include "../attribs.h"
6 #include "../cmd.h"
7 #include "../handy.h"
8 #include "../log.h"
9 #include "../times.h"
10 #include "list.h"
11
12 static int parseable_format=0;
13
14 /* Note: The chars in this function are not the same as in the CMD_ set.
15 These are for printing to the screen only. */
encode_mode(mode_t mode,char * buf)16 static char *encode_mode(mode_t mode, char *buf)
17 {
18 char *cp=buf;
19 *cp++=S_ISDIR(mode)?'d':S_ISBLK(mode)?'b':S_ISCHR(mode)?'c':
20 S_ISLNK(mode)?'l':S_ISFIFO(mode)?'p':S_ISSOCK(mode)?'s':'-';
21 *cp++=mode&S_IRUSR?'r':'-';
22 *cp++=mode&S_IWUSR?'w':'-';
23 *cp++=(mode&S_ISUID?(mode&S_IXUSR?'s':'S'):(mode&S_IXUSR?'x':'-'));
24 *cp++=mode&S_IRGRP?'r':'-';
25 *cp++=mode&S_IWGRP?'w':'-';
26 *cp++=(mode&S_ISGID?(mode&S_IXGRP?'s':'S'):(mode&S_IXGRP?'x':'-'));
27 *cp++=mode&S_IROTH?'r':'-';
28 *cp++=mode&S_IWOTH?'w':'-';
29 *cp++=(mode&S_ISVTX?(mode&S_IXOTH?'t':'T'):(mode&S_IXOTH?'x':'-'));
30 *cp='\0';
31 return cp;
32 }
33
ls_to_buf(char * lsbuf,struct sbuf * sb)34 static void ls_to_buf(char *lsbuf, struct sbuf *sb)
35 {
36 int n;
37 char *p;
38 const char *f;
39 struct stat *statp=&sb->statp;
40 *lsbuf='\0';
41
42 p=encode_mode(statp->st_mode, lsbuf);
43 n=sprintf(p, " %2d ", (uint32_t)statp->st_nlink);
44 p+=n;
45 n=sprintf(p, "%5d %5d", (uint32_t)statp->st_uid,
46 (uint32_t)statp->st_gid);
47 p+=n;
48 n=sprintf(p, " %7lu ", (unsigned long)statp->st_size);
49 p+=n;
50
51 p=encode_time(statp->st_mtime, p);
52 *p++=' ';
53 for(f=sb->path.buf; *f; ) *p++=*f++;
54 *p=0;
55 }
56
ls_long_output(struct sbuf * sb)57 static int ls_long_output(struct sbuf *sb)
58 {
59 static size_t len=128;
60 static char *lsbuf=NULL;
61
62 while(sb->path.len + 128 > len)
63 {
64 len*=2;
65 if(!(lsbuf=(char *)realloc_w(lsbuf, len, __func__)))
66 return -1;
67 }
68 ls_to_buf(lsbuf, sb);
69 printf("%s", lsbuf);
70 if(sb->link.buf) printf(" -> %s", sb->link.buf);
71 printf("\n");
72
73 return 0;
74 }
75
ls_short_output(struct sbuf * sb)76 static void ls_short_output(struct sbuf *sb)
77 {
78 if(parseable_format)
79 {
80 // Just make everything a CMD_FILE, when reading in for
81 // restore input, the type of file system entry will just
82 // be ignored.
83 printf("%c%04X%s\n",
84 CMD_FILE,
85 (unsigned int)sb->path.len,
86 sb->path.buf);
87 return;
88 }
89 printf("%s\n", sb->path.buf);
90 }
91
list_item(enum action act,struct sbuf * sb)92 static int list_item(enum action act, struct sbuf *sb)
93 {
94 if(act==ACTION_LIST_LONG)
95 return ls_long_output(sb);
96
97 ls_short_output(sb);
98 return 0;
99 }
100
do_list_client(struct asfd * asfd,enum action act,struct conf ** confs)101 int do_list_client(struct asfd *asfd, enum action act, struct conf **confs)
102 {
103 int ret=-1;
104 char msg[512]="";
105 struct sbuf *sb=NULL;
106 struct iobuf *rbuf=asfd->rbuf;
107 const char *backup=get_string(confs[OPT_BACKUP]);
108 const char *backup2=get_string(confs[OPT_BACKUP2]);
109 const char *browsedir=get_string(confs[OPT_BROWSEDIR]);
110 const char *regex=get_string(confs[OPT_REGEX]);
111
112 parseable_format=act==ACTION_LIST_PARSEABLE;
113 //logp("in do_list\n");
114
115 switch(act)
116 {
117 case ACTION_LIST:
118 case ACTION_LIST_LONG:
119 case ACTION_LIST_PARSEABLE:
120 if(browsedir && regex)
121 {
122 logp("You cannot specify both a directory and a regular expression when listing.\n");
123 goto end;
124 }
125 if(browsedir)
126 snprintf(msg, sizeof(msg), "listb %s:%s",
127 backup?backup:"", browsedir);
128 else
129 snprintf(msg, sizeof(msg), "list %s:%s",
130 backup?backup:"", regex?regex:"");
131 break;
132 case ACTION_DIFF:
133 case ACTION_DIFF_LONG:
134 snprintf(msg, sizeof(msg), "diff %s:%s",
135 backup?backup:"", backup2?backup2:"");
136 break;
137 default:
138 logp("unknown action %d\n", act);
139 goto end;
140 }
141 if(asfd->write_str(asfd, CMD_GEN, msg)
142 || asfd_read_expect(asfd, CMD_GEN, "ok"))
143 goto end;
144
145 if(!(sb=sbuf_alloc(get_protocol(confs)))) goto end;
146 iobuf_init(&sb->path);
147 iobuf_init(&sb->link);
148 iobuf_init(&sb->attr);
149
150 // This should probably should use the sbuf stuff.
151 while(1)
152 {
153 sbuf_free_content(sb);
154
155 iobuf_free_content(rbuf);
156 if(asfd->read(asfd)) break;
157 if(rbuf->cmd==CMD_MESSAGE)
158 {
159 if(!parseable_format)
160 printf("%s\n", rbuf->buf);
161 if(!strcmp(rbuf->buf, "no backups"))
162 ret=0;
163 goto end;
164 }
165 else if(rbuf->cmd==CMD_TIMESTAMP)
166 {
167 if(parseable_format)
168 continue;
169 // A backup timestamp, just print it.
170 printf("Backup: %s\n", rbuf->buf);
171 if(browsedir)
172 printf("Listing directory: %s\n",
173 browsedir);
174 if(regex)
175 printf("With regex: %s\n",
176 regex);
177 continue;
178 }
179 else if(rbuf->cmd!=CMD_ATTRIBS)
180 {
181 iobuf_log_unexpected(rbuf, __func__);
182 goto end;
183 }
184 iobuf_copy(&sb->attr, rbuf);
185 iobuf_init(rbuf);
186
187 attribs_decode(sb);
188
189 if(asfd->read(asfd))
190 {
191 logp("got stat without an object\n");
192 goto end;
193 }
194 iobuf_copy(&sb->path, rbuf);
195 iobuf_init(rbuf);
196
197 if(sb->path.cmd==CMD_DIRECTORY
198 || sb->path.cmd==CMD_FILE
199 || sb->path.cmd==CMD_ENC_FILE
200 || sb->path.cmd==CMD_EFS_FILE
201 || sb->path.cmd==CMD_SPECIAL)
202 {
203 if(list_item(act, sb))
204 goto end;
205 }
206 else if(cmd_is_link(sb->path.cmd)) // symlink or hardlink
207 {
208 if(asfd->read(asfd)
209 || rbuf->cmd!=sb->path.cmd)
210 {
211 logp("could not get link %s\n",
212 iobuf_to_printable(&sb->path));
213 goto end;
214 }
215 iobuf_copy(&sb->link, rbuf);
216 iobuf_init(rbuf);
217 list_item(act, sb);
218 }
219 else
220 {
221 logp("unlistable %s\n", iobuf_to_printable(&sb->path));
222 }
223 }
224
225 ret=0;
226 end:
227 sbuf_free(&sb);
228 if(!ret) logp("List finished ok\n");
229 return ret;
230 }
231