8 static string get_string(FILE *f,const char *fn,const char *what) {
10 char *got=fgets(buf,sizeof(buf),f);
12 fatal("Error reading %s from %s: %m",what,fn);
13 char *s(strchr(buf,'\n'));
15 fatal("Stored %s in %s is not newline-terminated",what,fn);
21 static void last_stored_write(const char *last_stored_fn,const string &filename,uint64_t offset) {
22 std::string last_tmp_fn(std::string(last_stored_fn)+".new");
23 int last_tmp_fd(open(last_tmp_fn.c_str(),O_WRONLY|O_CREAT|O_TRUNC,0644));
25 fatal("Error storing filename to %s: %m",last_tmp_fn.c_str());
26 write_safe(last_tmp_fd,filename.c_str(),filename.length());
27 write_safe(last_tmp_fd,'\n');
28 string offsetstr(stringf("%zu",(size_t)offset));
29 write_safe(last_tmp_fd,offsetstr.c_str(),offsetstr.length());
30 write_safe(last_tmp_fd,'\n');
31 if (close(last_tmp_fd))
32 fatal("Error closing %s: %m",last_tmp_fn.c_str());
33 if (rename(last_tmp_fn.c_str(),last_stored_fn))
34 fatal("Error renaming %s->%s: %m",last_tmp_fn.c_str(),last_stored_fn);
37 static string my_basename(const string &path) {
38 size_t slash(path.find_last_of('/'));
39 if (slash!=string::npos)
40 return path.substr(slash+1);
44 int main(int argc,char **argv) {
46 fatal("streamfer-client <host>:<port> <pattern> <last storage file>");
47 int server_fd(socket_connect(string(argv[1]),0/*retries*/));
48 string pattern(argv[2]);
49 write_safe(server_fd,pattern);
51 const char *last_stored_fn(argv[3]);
52 FILE *last_stored_f(fopen(last_stored_fn,"r"));
56 fatal("Error opening filename from %s: %m",last_stored_fn);
58 last_found= get_string(last_stored_f,last_stored_fn,"filename") ;
59 string offsetstr(get_string(last_stored_f,last_stored_fn,"offset" ));
62 unsigned long ul(strtoul(offsetstr.c_str(),&end,0));
63 if (errno||(end&&*end))
64 fatal("Error converting offset from %s: %s",last_stored_fn,offsetstr.c_str());
66 int gotint(fgetc(last_stored_f));
68 fatal("Stored filename in %s has excessive data after filename %s and offset %s",last_stored_fn,last_found.c_str(),offsetstr.c_str());
69 int err(fclose(last_stored_f));
72 write_safe(server_fd,last_found);
73 write_safe(server_fd,offset);
74 { struct stat statbuf;
75 string last_found_basename(my_basename(last_found));
76 if (stat(last_found_basename.c_str(),&statbuf)) {
77 static const struct timespec mtim_zero{};
78 write_safe(server_fd,mtim_zero);
80 write_safe(server_fd,statbuf.st_mtim);
84 read_safe(server_fd,last_got);
85 } catch (SafeIOError) {
86 fatal("SafeIOError reading from the server %s",argv[1]);
88 if (last_got.empty()) {
89 warning("No more files to transfer");
93 read_safe(server_fd,mtim);
95 string file_name(my_basename(last_got));;
96 if (last_found==last_got) {
97 file_fd=open(file_name.c_str(),O_WRONLY);
99 fatal("Error opening for write %s: %m",file_name.c_str());
100 off_t got(lseek(file_fd,offset,SEEK_SET));
101 if ((uint64_t)got!=offset)
102 fatal("Error seeking in %s to %zu, got: %zu",file_name.c_str(),(size_t)offset,(size_t)got);
105 file_fd=open(file_name.c_str(),O_WRONLY|O_CREAT,0644);
107 fatal("Error creating %s: %m",file_name.c_str());
109 last_stored_write(last_stored_fn,last_got,offset);
110 uint64_t transferred(transfer(server_fd,"server fd",file_fd,file_name.c_str()));
113 int err(fstat(file_fd,&statbuf));
115 if (memcmp(&mtim,&statbuf.st_mtim,sizeof(mtim))==0)
119 struct timespec mtim2[2];
120 mtim2[0]=mtim; // atime
121 mtim2[1]=mtim; // mtime
122 if (futimens(file_fd,mtim2))
123 fatal("Error setting timestamp of %s: %m",file_name.c_str());
125 fatal("Error closing %s: %m",file_name.c_str());
126 last_stored_write(last_stored_fn,last_got,offset);