ioutil.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include <stdint.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "types.h"
  5. #include "ioutil.h"
  6. #include "vec.h"
  7. #include <stdio.h>
  8. #ifndef _WIN32
  9. #include <errno.h>
  10. #include <sys/stat.h>
  11. #include <fcntl.h>
  12. #include <unistd.h>
  13. int writeall(FH fd,const u8 *data,size_t len)
  14. {
  15. ssize_t wrote;
  16. while (len) {
  17. wrote = write(fd,data,len);
  18. if (wrote == -1) {
  19. if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  20. continue;
  21. return -1;
  22. }
  23. len -= (size_t) wrote;
  24. data += wrote;
  25. }
  26. return 0;
  27. }
  28. FH createfile(const char *path,int secret)
  29. {
  30. int fd;
  31. do {
  32. fd = open(path,O_WRONLY | O_CREAT | O_TRUNC,secret ? 0600 : 0666);
  33. if (fd < 0) {
  34. if (errno == EINTR)
  35. continue;
  36. return -1;
  37. }
  38. } while (0);
  39. return fd;
  40. }
  41. int closefile(FH fd)
  42. {
  43. int cret;
  44. do {
  45. cret = close(fd);
  46. if (cret < 0) {
  47. if (errno == EINTR)
  48. continue;
  49. return -1;
  50. }
  51. } while (0);
  52. return 0;
  53. }
  54. int createdir(const char *path,int secret)
  55. {
  56. return mkdir(path,secret ? 0700 : 0777);
  57. }
  58. static int syncwritefile(const char *filename,const char *tmpname,int secret,const u8 *data,size_t datalen)
  59. {
  60. FH f = createfile(tmpname,secret);
  61. if (f == FH_invalid)
  62. return -1;
  63. if (writeall(f,data,datalen) < 0) {
  64. goto failclose;
  65. }
  66. int sret;
  67. do {
  68. sret = fsync(f);
  69. if (sret < 0) {
  70. if (errno == EINTR)
  71. continue;
  72. goto failclose;
  73. }
  74. } while (0);
  75. if (closefile(f) < 0) {
  76. goto failrm;
  77. }
  78. if (rename(tmpname,filename) < 0) {
  79. goto failrm;
  80. }
  81. return 0;
  82. failclose:
  83. (void) closefile(f);
  84. failrm:
  85. remove(tmpname);
  86. return -1;
  87. }
  88. int syncwrite(const char *filename,int secret,const u8 *data,size_t datalen)
  89. {
  90. //fprintf(stderr,"filename = %s\n",filename);
  91. size_t fnlen = strlen(filename);
  92. VEC_STRUCT(,char) tmpnamebuf;
  93. VEC_INIT(tmpnamebuf);
  94. VEC_ADDN(tmpnamebuf,fnlen + 4 /* ".tmp" */ + 1 /* "\0" */);
  95. memcpy(&VEC_BUF(tmpnamebuf,0),filename,fnlen);
  96. strcpy(&VEC_BUF(tmpnamebuf,fnlen),".tmp");
  97. const char *tmpname = &VEC_BUF(tmpnamebuf,0);
  98. //fprintf(stderr,"tmpname = %s\n",tmpname);
  99. int r = syncwritefile(filename,tmpname,secret,data,datalen);
  100. VEC_FREE(tmpnamebuf);
  101. if (r < 0)
  102. return r;
  103. VEC_STRUCT(,char) dirnamebuf;
  104. VEC_INIT(dirnamebuf);
  105. const char *dirname;
  106. for (ssize_t x = ((ssize_t)fnlen) - 1;x >= 0;--x) {
  107. if (filename[x] == '/') {
  108. if (x)
  109. --x;
  110. ++x;
  111. VEC_ADDN(dirnamebuf,x + 1);
  112. memcpy(&VEC_BUF(dirnamebuf,0),filename,x);
  113. VEC_BUF(dirnamebuf,x) = '\0';
  114. dirname = &VEC_BUF(dirnamebuf,0);
  115. goto foundslash;
  116. }
  117. }
  118. /* not found slash, fall back to "." */
  119. dirname = ".";
  120. foundslash:
  121. //fprintf(stderr,"dirname = %s\n",dirname);
  122. ;
  123. int dirf;
  124. do {
  125. dirf = open(dirname,O_RDONLY);
  126. if (dirf < 0) {
  127. if (errno == EINTR)
  128. continue;
  129. // failed for non-eintr reasons
  130. goto skipdsync; // don't really care enough
  131. }
  132. } while (0);
  133. int sret;
  134. do {
  135. sret = fsync(dirf);
  136. if (sret < 0) {
  137. if (errno == EINTR)
  138. continue;
  139. // failed for non-eintr reasons
  140. break; // don't care
  141. }
  142. } while (0);
  143. (void) closefile(dirf); // don't care
  144. skipdsync:
  145. VEC_FREE(dirnamebuf);
  146. return 0;
  147. }
  148. #else
  149. int writeall(FH fd,const u8 *data,size_t len)
  150. {
  151. DWORD wrote;
  152. BOOL success;
  153. while (len) {
  154. success = WriteFile(fd,data,
  155. len <= (DWORD)-1 ? (DWORD)len : (DWORD)-1,&wrote,0);
  156. if (!success)
  157. return -1;
  158. data += wrote;
  159. if (len >= wrote)
  160. len -= wrote;
  161. else
  162. len = 0;
  163. }
  164. return 0;
  165. }
  166. FH createfile(const char *path,int secret)
  167. {
  168. // XXX no support for non-ascii chars
  169. // XXX don't know how to handle secret argument
  170. (void) secret;
  171. return CreateFileA(path,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,0);
  172. }
  173. int closefile(FH fd)
  174. {
  175. return CloseHandle(fd) ? 0 : -1;
  176. }
  177. int createdir(const char *path,int secret)
  178. {
  179. // XXX don't know how to handle secret argument
  180. (void) secret;
  181. return CreateDirectoryA(path,0) ? 0 : -1;
  182. }
  183. static int syncwritefile(const char *filename,const char *tmpname,int secret,const u8 *data,size_t datalen)
  184. {
  185. FH f = createfile(tmpname,secret);
  186. if (f == FH_invalid) {
  187. //fprintf(stderr,"!failed to create\n");
  188. return -1;
  189. }
  190. if (writeall(f,data,datalen) < 0) {
  191. //fprintf(stderr,"!failed to write\n");
  192. goto failclose;
  193. }
  194. if (FlushFileBuffers(f) == 0) {
  195. //fprintf(stderr,"!failed to flush\n");
  196. goto failclose;
  197. }
  198. if (closefile(f) < 0) {
  199. //fprintf(stderr,"!failed to close\n");
  200. goto failrm;
  201. }
  202. if (MoveFileExA(tmpname,filename,MOVEFILE_REPLACE_EXISTING) == 0) {
  203. //fprintf(stderr,"!failed to move\n");
  204. goto failrm;
  205. }
  206. return 0;
  207. failclose:
  208. (void) closefile(f);
  209. failrm:
  210. remove(tmpname);
  211. return -1;
  212. }
  213. int syncwrite(const char *filename,int secret,const u8 *data,size_t datalen)
  214. {
  215. size_t fnlen = strlen(filename);
  216. VEC_STRUCT(,char) tmpnamebuf;
  217. VEC_INIT(tmpnamebuf);
  218. VEC_ADDN(tmpnamebuf,fnlen + 4 /* ".tmp" */ + 1 /* "\0" */);
  219. memcpy(&VEC_BUF(tmpnamebuf,0),filename,fnlen);
  220. strcpy(&VEC_BUF(tmpnamebuf,fnlen),".tmp");
  221. const char *tmpname = &VEC_BUF(tmpnamebuf,0);
  222. int r = syncwritefile(filename,tmpname,secret,data,datalen);
  223. VEC_FREE(tmpnamebuf);
  224. if (r < 0)
  225. return r;
  226. // can't fsync parent dir on windows so just end here
  227. return 0;
  228. }
  229. #endif
  230. int writetofile(const char *path,const u8 *data,size_t len,int secret)
  231. {
  232. FH fd = createfile(path,secret);
  233. int wret = writeall(fd,data,len);
  234. int cret = closefile(fd);
  235. if (cret == -1)
  236. return -1;
  237. return wret;
  238. }