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