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 int last_stored_fd(open(last_stored_fn,O_WRONLY|O_CREAT|O_TRUNC,0644));
23 if (last_stored_fd==-1)
24 fatal("Error storing filename to %s: %m",last_stored_fn);
25 write_safe(last_stored_fd,filename.c_str(),filename.length());
26 write_safe(last_stored_fd,'\n');
27 string offsetstr(stringf("%zu",(size_t)offset));
28 write_safe(last_stored_fd,offsetstr.c_str(),offsetstr.length());
29 write_safe(last_stored_fd,'\n');
30 if (close(last_stored_fd))
31 fatal("Error closing %s: %m",last_stored_fn);
34 static string my_basename(const string &path) {
35 size_t slash(path.find_last_of('/'));
36 if (slash!=string::npos)
37 return path.substr(slash+1);
41 int main(int argc,char **argv) {
43 fatal("streamfer-client <host>:<port> <pattern> <last storage file>");
44 int server_fd(socket_connect(string(argv[1]),0/*retries*/));
45 string pattern(argv[2]);
46 write_safe(server_fd,pattern);
48 const char *last_stored_fn(argv[3]);
49 FILE *last_stored_f(fopen(last_stored_fn,"r"));
53 fatal("Error opening filename from %s: %m",last_stored_fn);
55 last_found= get_string(last_stored_f,last_stored_fn,"filename") ;
56 string offsetstr(get_string(last_stored_f,last_stored_fn,"offset" ));
59 unsigned long ul(strtoul(offsetstr.c_str(),&end,0));
60 if (errno||(end&&*end))
61 fatal("Error converting offset from %s: %s",last_stored_fn,offsetstr.c_str());
63 int gotint(fgetc(last_stored_f));
65 fatal("Stored filename in %s has excessive data after filename %s and offset %s",last_stored_fn,last_found.c_str(),offsetstr.c_str());
66 int err(fclose(last_stored_f));
69 write_safe(server_fd,last_found);
70 write_safe(server_fd,offset);
71 { struct stat statbuf;
72 string last_found_basename(my_basename(last_found));
73 if (stat(last_found_basename.c_str(),&statbuf)) {
74 static const struct timespec mtim_zero{};
75 write_safe(server_fd,mtim_zero);
77 write_safe(server_fd,statbuf.st_mtim);
81 read_safe(server_fd,last_got);
82 } catch (SafeIOError) {
83 fatal("SafeIOError reading from the server %s",argv[1]);
85 if (last_got.empty()) {
86 warning("No more files to transfer");
90 read_safe(server_fd,mtim);
92 string file_name(my_basename(last_got));;
93 if (last_found==last_got) {
94 file_fd=open(file_name.c_str(),O_WRONLY);
96 fatal("Error opening for write %s: %m",file_name.c_str());
97 off_t got(lseek(file_fd,offset,SEEK_SET));
98 if ((uint64_t)got!=offset)
99 fatal("Error seeking in %s to %zu, got: %zu",file_name.c_str(),(size_t)offset,(size_t)got);
102 file_fd=open(file_name.c_str(),O_WRONLY|O_CREAT,0644);
104 fatal("Error creating %s: %m",file_name.c_str());
106 last_stored_write(last_stored_fn,last_got,offset);
107 uint64_t transferred(transfer(server_fd,"server fd",file_fd,file_name.c_str()));
110 int err(fstat(file_fd,&statbuf));
112 if (memcmp(&mtim,&statbuf.st_mtim,sizeof(mtim))==0)
116 struct timespec mtim2[2];
117 mtim2[0]=mtim; // atime
118 mtim2[1]=mtim; // mtime
119 if (futimens(file_fd,mtim2))
120 fatal("Error setting timestamp of %s: %m",file_name.c_str());
122 fatal("Error closing %s: %m",file_name.c_str());
123 last_stored_write(last_stored_fn,last_got,offset);