#include "rsync.h"
extern int verbose;
+extern int am_server;
static char **exclude_list;
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
- fprintf(FERROR,"clearing exclude list\n");
+ fprintf(FINFO,"clearing exclude list\n");
while ((len)--)
free((*list)[len]);
free((*list));
out_of_memory("add_exclude");
if (verbose > 2)
- fprintf(FERROR,"add_exclude(%s)\n",pattern);
+ fprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}
extern int relative_paths;
extern int copy_links;
extern int remote_version;
+extern int io_error;
static char **local_exclude_list;
{
if (check_exclude(fname,local_exclude_list)) {
if (verbose > 2)
- fprintf(FERROR,"excluding file %s\n",fname);
+ fprintf(FINFO,"excluding file %s\n",fname);
return 0;
}
return 1;
bzero(sum,SUM_LENGTH);
if (link_stat(fname,&st) != 0) {
+ io_error = 1;
fprintf(FERROR,"%s: %s\n",
fname,strerror(errno));
return NULL;
}
if (S_ISDIR(st.st_mode) && !recurse) {
- fprintf(FERROR,"skipping directory %s\n",fname);
+ fprintf(FINFO,"skipping directory %s\n",fname);
return NULL;
}
return NULL;
if (verbose > 2)
- fprintf(FERROR,"make_file(%s)\n",fname);
+ fprintf(FINFO,"make_file(%s)\n",fname);
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("make_file");
int l;
char lnk[MAXPATHLEN];
if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) {
+ io_error=1;
fprintf(FERROR,"readlink %s : %s\n",
fname,strerror(errno));
return NULL;
d = opendir(dir);
if (!d) {
+ io_error = 1;
fprintf(FERROR,"%s: %s\n",
dir,strerror(errno));
return;
l = strlen(fname);
if (fname[l-1] != '/') {
if (l == MAXPATHLEN-1) {
+ io_error = 1;
fprintf(FERROR,"skipping long-named directory %s\n",fname);
closedir(d);
return;
strcpy(p,".cvsignore");
local_exclude_list = make_exclude_list(fname,NULL,0);
} else {
- fprintf(FERROR,"cannot cvs-exclude in long-named directory %s\n",fname);
+ io_error = 1;
+ fprintf(FINFO,"cannot cvs-exclude in long-named directory %s\n",fname);
}
}
}
if (link_stat(fname,&st) != 0) {
+ io_error=1;
fprintf(FERROR,"%s : %s\n",fname,strerror(errno));
continue;
}
if (S_ISDIR(st.st_mode) && !recurse) {
- fprintf(FERROR,"skipping directory %s\n",fname);
+ fprintf(FINFO,"skipping directory %s\n",fname);
continue;
}
exit_cleanup(1);
}
if (chdir(dir) != 0) {
+ io_error=1;
fprintf(FERROR,"chdir %s : %s\n",
dir,strerror(errno));
continue;
send_uid_list(f);
}
+ /* if protocol version is >= 17 then send the io_error flag */
+ if (f != -1 && remote_version >= 17) {
+ write_int(f, io_error);
+ }
+
return flist;
}
flist->count++;
if (verbose > 2)
- fprintf(FERROR,"recv_file_name(%s)\n",f_name(flist->files[i]));
+ fprintf(FINFO,"recv_file_name(%s)\n",f_name(flist->files[i]));
}
if (verbose > 2)
- fprintf(FERROR,"received %d names\n",flist->count);
+ fprintf(FINFO,"received %d names\n",flist->count);
clean_flist(flist);
recv_uid_list(f, flist);
}
+ /* if protocol version is >= 17 then recv the io_error flag */
+ if (f != -1 && remote_version >= 17) {
+ io_error |= read_int(f);
+ }
+
return flist;
oom:
strcmp(f_name(flist->files[i]),
f_name(flist->files[i-1])) == 0) {
if (verbose > 1 && !am_server)
- fprintf(FERROR,"removing duplicate name %s from file list %d\n",
+ fprintf(FINFO,"removing duplicate name %s from file list %d\n",
f_name(flist->files[i-1]),i-1);
free_file(flist->files[i]);
}
extern int verbose;
extern int sparse_files;
+extern int io_timeout;
int64 write_total(void)
{
}
}
+static time_t last_io;
+
+
+static void check_timeout(void)
+{
+ time_t t;
+
+ if (!io_timeout) return;
+
+ if (!last_io) {
+ last_io = time(NULL);
+ return;
+ }
+
+ t = time(NULL);
+
+ if (last_io && io_timeout && (t-last_io)>io_timeout) {
+ fprintf(FERROR,"read timeout after %d second - exiting\n",
+ (int)(t-last_io));
+ exit_cleanup(1);
+ }
+}
static int readfd(int fd,char *buffer,int N)
{
- int ret;
- int total=0;
-
- if (read_buffer_len < N)
- read_check(buffer_f_in);
-
- while (total < N)
- {
- if (read_buffer_len > 0 && buffer_f_in == fd) {
- ret = MIN(read_buffer_len,N-total);
- memcpy(buffer+total,read_buffer_p,ret);
- read_buffer_p += ret;
- read_buffer_len -= ret;
- } else {
- while ((ret = read(fd,buffer + total,N - total)) == -1) {
- fd_set fds;
-
- if (errno != EAGAIN && errno != EWOULDBLOCK)
- return -1;
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- select(fd+1, &fds, NULL, NULL, NULL);
+ int ret;
+ int total=0;
+ struct timeval tv;
+
+ if (read_buffer_len < N)
+ read_check(buffer_f_in);
+
+ while (total < N) {
+ if (read_buffer_len > 0 && buffer_f_in == fd) {
+ ret = MIN(read_buffer_len,N-total);
+ memcpy(buffer+total,read_buffer_p,ret);
+ read_buffer_p += ret;
+ read_buffer_len -= ret;
+ continue;
+ }
+
+ while ((ret = read(fd,buffer + total,N-total)) == -1) {
+ fd_set fds;
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK)
+ return -1;
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = io_timeout;
+ tv.tv_usec = 0;
+
+ if (select(fd+1, &fds, NULL, NULL, &tv) != 1) {
+ check_timeout();
+ }
+ }
+
+ if (ret <= 0)
+ return total;
+ total += ret;
}
- }
- if (ret <= 0)
+ if (io_timeout)
+ last_io = time(NULL);
return total;
- total += ret;
- }
- return total;
}
exit_cleanup(1);
}
- if (count == 0) continue;
+ if (count == 0) {
+ check_timeout();
+ continue;
+ }
if (FD_ISSET(fd, &w_fds)) {
got_select = 1;
}
}
+ if (io_timeout)
+ last_io = time(NULL);
+
return total;
}
int relative_paths=0;
int numeric_ids = 0;
int force_delete = 0;
+int io_timeout = 0;
+int io_error = 0;
extern int csum_length;
int ac = *argc;
static char argstr[50];
static char bsize[30];
+ static char iotime[30];
int i, x;
args[ac++] = "--server";
args[ac++] = bsize;
}
+ if (io_timeout) {
+ sprintf(iotime,"--timeout=%d",io_timeout);
+ args[ac++] = iotime;
+ }
+
if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
args[ac++] = "--suffix";
args[ac++] = backup_suffix;
args[argc] = NULL;
if (verbose > 3) {
- fprintf(FERROR,"cmd=");
+ fprintf(FINFO,"cmd=");
for (i=0;i<argc;i++)
- fprintf(FERROR,"%s ",args[i]);
- fprintf(FERROR,"\n");
+ fprintf(FINFO,"%s ",args[i]);
+ fprintf(FINFO,"\n");
}
ret = piped_child(args,f_in,f_out);
char *dir = argv[0];
if (verbose > 2)
- fprintf(FERROR,"server_sender starting pid=%d\n",(int)getpid());
+ fprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
if (!relative_paths && chdir(dir) != 0) {
fprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
if ((pid=do_fork()) == 0) {
recv_files(f_in,flist,local_name,recv_pipe[1]);
if (verbose > 2)
- fprintf(FERROR,"receiver read %ld\n",(long)read_total());
+ fprintf(FINFO,"receiver read %ld\n",(long)read_total());
exit_cleanup(0);
}
char *dir = NULL;
if (verbose > 2)
- fprintf(FERROR,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
+ fprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
if (argc > 0) {
dir = argv[0];
fprintf(f," --delete delete files that don't exist on the sending side\n");
fprintf(f," --force force deletion of directories even if not empty\n");
fprintf(f," --numeric-ids don't map uid/gid values by user/group name\n");
+ fprintf(f," --timeout TIME set IO timeout in seconds\n");
fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n");
fprintf(f,"-T --temp-dir DIR create temporary files in directory DIR\n");
fprintf(f,"-z, --compress compress file data\n");
}
enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
- OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,OPT_FORCE};
+ OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
+ OPT_FORCE,OPT_TIMEOUT};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
{"rsh", 1, 0, 'e'},
{"suffix", 1, 0, OPT_SUFFIX},
{"block-size", 1, 0, 'B'},
+ {"timeout", 1, 0, OPT_TIMEOUT},
{"temp-dir", 1, 0, 'T'},
{"compress", 0, 0, 'z'},
{0,0,0,0}};
block_size = atoi(optarg);
break;
+ case OPT_TIMEOUT:
+ io_timeout = atoi(optarg);
+ break;
+
case 'T':
tmpdir = optarg;
break;
}
if (verbose > 3) {
- fprintf(FERROR,"cmd=%s machine=%s user=%s path=%s\n",
+ fprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
shell_cmd?shell_cmd:"",
shell_machine?shell_machine:"",
shell_user?shell_user:"",
#endif
if (verbose > 3)
- fprintf(FERROR,"parent=%d child=%d sender=%d recurse=%d\n",
+ fprintf(FINFO,"parent=%d child=%d sender=%d recurse=%d\n",
(int)getpid(),pid,sender,recurse);
if (sender) {
send_exclude_list(f_out);
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
- fprintf(FERROR,"file list sent\n");
+ fprintf(FINFO,"file list sent\n");
send_files(flist,f_out,f_in);
if (verbose > 3)
- fprintf(FERROR,"waiting on %d\n",pid);
+ fprintf(FINFO,"waiting on %d\n",pid);
waitpid(pid, &status, 0);
report(-1);
exit_cleanup(status);
flist = recv_file_list(f_in);
if (!flist || flist->count == 0) {
- fprintf(FERROR,"nothing to do\n");
+ fprintf(FINFO,"nothing to do\n");
exit_cleanup(0);
}
int j;
if (verbose > 2 && i >= 0)
- fprintf(FERROR,"match at %d last_match=%d j=%d len=%d n=%d\n",
+ fprintf(FINFO,"match at %d last_match=%d j=%d len=%d n=%d\n",
(int)offset,(int)last_match,i,(int)s->sums[i].len,(int)n);
send_token(f,i,buf,last_match,n,i==-1?0:s->sums[i].len);
signed char *map;
if (verbose > 2)
- fprintf(FERROR,"hash search b=%d len=%d\n",s->n,(int)len);
+ fprintf(FINFO,"hash search b=%d len=%d\n",s->n,(int)len);
k = MIN(len, s->n);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
- fprintf(FERROR, "sum=%.8x k=%d\n", sum, k);
+ fprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3)
- fprintf(FERROR,"hash search s->n=%d len=%d count=%d\n",
+ fprintf(FINFO,"hash search s->n=%d len=%d count=%d\n",
s->n,(int)len,s->count);
do {
j = tag_table[t];
if (verbose > 4)
- fprintf(FERROR,"offset=%d sum=%08x\n",(int)offset,sum);
+ fprintf(FINFO,"offset=%d sum=%08x\n",(int)offset,sum);
if (j == NULL_TAG) {
goto null_tag;
if (sum != s->sums[i].sum1) continue;
if (verbose > 3)
- fprintf(FERROR,"potential match at %d target=%d %d sum=%08x\n",
+ fprintf(FINFO,"potential match at %d target=%d %d sum=%08x\n",
(int)offset,j,i,sum);
if (!done_csum2) {
build_hash_table(s);
if (verbose > 2)
- fprintf(FERROR,"built hash table\n");
+ fprintf(FINFO,"built hash table\n");
hash_search(f,s,buf,len);
if (verbose > 2)
- fprintf(FERROR,"done hash search\n");
+ fprintf(FINFO,"done hash search\n");
} else {
matched(f,s,buf,len,-1);
}
if (remote_version >= 14) {
if (verbose > 2)
- fprintf(FERROR,"sending file_sum\n");
+ fprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
}
}
if (verbose > 2)
- fprintf(FERROR, "false_alarms=%d tag_hits=%d matches=%d\n",
+ fprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
extern int cvs_exclude;
extern int am_root;
extern int relative_paths;
+extern int io_timeout;
+extern int io_error;
/*
free a sums struct
}
if (verbose > 3)
- fprintf(FERROR,"count=%d rem=%d n=%d flength=%d\n",
+ fprintf(FINFO,"count=%d rem=%d n=%d flength=%d\n",
s->count,s->remainder,s->n,(int)s->flength);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
s->sums[i].i = i;
if (verbose > 3)
- fprintf(FERROR,"chunk[%d] offset=%d len=%d sum1=%08x\n",
+ fprintf(FINFO,"chunk[%d] offset=%d len=%d sum1=%08x\n",
i,(int)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
len -= n1;
s->sums = NULL;
if (verbose > 3)
- fprintf(FERROR,"count=%d n=%d rem=%d\n",
+ fprintf(FINFO,"count=%d n=%d rem=%d\n",
s->count,s->n,s->remainder);
if (s->count == 0)
offset += s->sums[i].len;
if (verbose > 3)
- fprintf(FERROR,"chunk[%d] len=%d offset=%d sum1=%08x\n",
+ fprintf(FINFO,"chunk[%d] len=%d offset=%d sum1=%08x\n",
i,s->sums[i].len,(int)s->sums[i].offset,s->sums[i].sum1);
}
struct file_struct *file = flist->files[i];
if (verbose > 2)
- fprintf(FERROR,"recv_generator(%s,%d)\n",fname,i);
+ fprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
statret = link_stat(fname,&st);
st.st_rdev != file->rdev) {
delete_file(fname);
if (verbose > 2)
- fprintf(FERROR,"mknod(%s,0%o,0x%x)\n",
+ fprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
fname,(int)file->mode,(int)file->rdev);
if (do_mknod(fname,file->mode,file->rdev) != 0) {
fprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
}
if (!S_ISREG(file->mode)) {
- fprintf(FERROR,"skipping non-regular file %s\n",fname);
+ fprintf(FINFO,"skipping non-regular file %s\n",fname);
return;
}
if (update_only && st.st_mtime > file->modtime) {
if (verbose > 1)
- fprintf(FERROR,"%s is newer\n",fname);
+ fprintf(FINFO,"%s is newer\n",fname);
return;
}
}
if (verbose > 3)
- fprintf(FERROR,"gen mapped %s of size %d\n",fname,(int)st.st_size);
+ fprintf(FINFO,"gen mapped %s of size %d\n",fname,(int)st.st_size);
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
if (verbose > 2)
- fprintf(FERROR,"sending sums for %d\n",i);
+ fprintf(FINFO,"sending sums for %d\n",i);
write_int(f_out,i);
send_sums(s,f_out);
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
if (i > 0) {
if (verbose > 3)
- fprintf(FERROR,"data recv %d at %d\n",i,(int)offset);
+ fprintf(FINFO,"data recv %d at %d\n",i,(int)offset);
sum_update(data,i);
len = remainder;
if (verbose > 3)
- fprintf(FERROR,"chunk[%d] of size %d at %d offset=%d\n",
+ fprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
map = map_ptr(buf,offset2,len);
if (remote_version >= 14) {
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2)
- fprintf(FERROR,"got file_sum\n");
+ fprintf(FINFO,"got file_sum\n");
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0)
return 0;
}
if (do_unlink(f_name(f)) != 0) {
fprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
- fprintf(FERROR,"deleting %s\n",f_name(f));
+ fprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY)
fprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
- fprintf(FERROR,"deleting directory %s\n",f_name(f));
+ fprintf(FINFO,"deleting directory %s\n",f_name(f));
}
}
}
if (cvs_exclude)
add_cvs_excludes();
+ if (io_error) {
+ fprintf(FINFO,"IO error encountered - skipping file deletion\n");
+ return;
+ }
+
for (j=0;j<flist->count;j++) {
char *name = f_name(flist->files[j]);
int recv_ok;
if (verbose > 2) {
- fprintf(FERROR,"recv_files(%d) starting\n",flist->count);
+ fprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (recurse && delete_mode && !local_name && flist->count>0) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
- fprintf(FERROR,"recv_files phase=%d\n",phase);
+ fprintf(FINFO,"recv_files phase=%d\n",phase);
write_int(f_gen,-1);
write_flush(f_gen);
continue;
}
if (verbose > 2)
- fprintf(FERROR,"recv_files(%s)\n",fname);
+ fprintf(FINFO,"recv_files(%s)\n",fname);
/* open the file */
fd1 = open(fname,O_RDONLY);
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
- fprintf(FERROR,"recv mapped %s of size %d\n",fname,(int)st.st_size);
+ fprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size);
} else {
buf = NULL;
}
close(fd2);
if (verbose > 2)
- fprintf(FERROR,"renaming %s to %s\n",fnametmp,fname);
+ fprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
if (make_backups) {
char fnamebak[MAXPATHLEN];
fname);
} else {
if (verbose > 1)
- fprintf(FERROR,"redoing %s(%d)\n",fname,i);
+ fprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
if (verbose > 2)
- fprintf(FERROR,"recv_files finished\n");
+ fprintf(FINFO,"recv_files finished\n");
return 0;
}
int offset=0;
if (verbose > 2)
- fprintf(FERROR,"send_files starting\n");
+ fprintf(FINFO,"send_files starting\n");
setup_nonblocking(f_in,f_out);
write_int(f_out,-1);
write_flush(f_out);
if (verbose > 2)
- fprintf(FERROR,"send_files phase=%d\n",phase);
+ fprintf(FINFO,"send_files phase=%d\n",phase);
continue;
}
break;
strncpy(fname,file->basedir,MAXPATHLEN-1);
fname[MAXPATHLEN-1] = 0;
if (strlen(fname) == MAXPATHLEN-1) {
+ io_error = 1;
fprintf(FERROR, "send_files failed on long-named directory %s\n",
fname);
return;
strncat(fname,f_name(file),MAXPATHLEN-strlen(fname));
if (verbose > 2)
- fprintf(FERROR,"send_files(%d,%s)\n",i,fname);
+ fprintf(FINFO,"send_files(%d,%s)\n",i,fname);
if (dry_run) {
if (!am_server && verbose)
s = receive_sums(f_in);
if (!s) {
+ io_error = 1;
fprintf(FERROR,"receive_sums failed\n");
return;
}
fd = open(fname,O_RDONLY);
if (fd == -1) {
+ io_error = 1;
fprintf(FERROR,"send_files failed to open %s: %s\n",
fname,strerror(errno));
free_sums(s);
/* map the local file */
if (fstat(fd,&st) != 0) {
+ io_error = 1;
fprintf(FERROR,"fstat failed : %s\n",strerror(errno));
free_sums(s);
close(fd);
}
if (verbose > 2)
- fprintf(FERROR,"send_files mapped %s of size %d\n",
+ fprintf(FINFO,"send_files mapped %s of size %d\n",
fname,(int)st.st_size);
write_int(f_out,i);
write_int(f_out,s->remainder);
if (verbose > 2)
- fprintf(FERROR,"calling match_sums %s\n",fname);
+ fprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server && verbose)
printf("%s\n",fname+offset);
free_sums(s);
if (verbose > 2)
- fprintf(FERROR,"sender finished %s\n",fname);
+ fprintf(FINFO,"sender finished %s\n",fname);
}
if (verbose > 2)
- fprintf(FERROR,"send files finished\n");
+ fprintf(FINFO,"send files finished\n");
match_report();
int phase=0;
if (verbose > 2)
- fprintf(FERROR,"generator starting pid=%d count=%d\n",
+ fprintf(FINFO,"generator starting pid=%d count=%d\n",
(int)getpid(),flist->count);
for (i = 0; i < flist->count; i++) {
ignore_times=1;
if (verbose > 2)
- fprintf(FERROR,"generate_files phase=%d\n",phase);
+ fprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_flush(f);
+ /* we expect to just sit around now, so don't exit on a timeout. If we
+ really get a timeout then the other process should exit */
+ io_timeout = 0;
+
if (remote_version >= 13) {
/* in newer versions of the protocol the files can cycle through
the system more than once to catch initial checksum errors */
phase++;
if (verbose > 2)
- fprintf(FERROR,"generate_files phase=%d\n",phase);
+ fprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_flush(f);
if (verbose > 2)
- fprintf(FERROR,"generator wrote %ld\n",(long)write_total());
+ fprintf(FINFO,"generator wrote %ld\n",(long)write_total());
}
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
-#define PROTOCOL_VERSION 16
+#define PROTOCOL_VERSION 17
#define MIN_PROTOCOL_VERSION 11
-#define MAX_PROTOCOL_VERSION 20
+#define MAX_PROTOCOL_VERSION 30
#define SPARSE_WRITE_SIZE (4*1024)
#define WRITE_SIZE (32*1024)