fileio.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. /* fileio.c - layer to adjust EOL to use DOS format via PR_Read/Write on NT */
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <sys/types.h>
  42. #include <errno.h>
  43. #include <stdlib.h>
  44. #ifndef _WIN32
  45. #include <sys/param.h>
  46. #include <unistd.h>
  47. #include <pwd.h>
  48. #endif
  49. #include "slap.h"
  50. #include "pw.h"
  51. #include <prio.h>
  52. #if defined( XP_WIN32 )
  53. #include <prinit.h> /* PR_CallOnce */
  54. #include <string.h> /* memmove, memcpy */
  55. #define g_EOF (-1)
  56. static PRInt32 PR_CALLBACK readText(PRFileDesc *f, void *buf, PRInt32 amount)
  57. {
  58. auto PRInt32 size = *(signed char*)&(f->secret);
  59. auto char* readAhead = ((char*)&(f->secret)) + 1;
  60. if ( size == g_EOF ) {
  61. f->secret = NULL;
  62. return 0;
  63. }
  64. if ( size > amount ) {
  65. return 0;
  66. }
  67. if ( size > 0 ) {
  68. memcpy( buf, readAhead, size );
  69. }
  70. f->secret = NULL;
  71. while (1) {
  72. auto PRInt32 len = amount - size;
  73. auto char* head;
  74. auto PRInt32 rval;
  75. if (len > 0) {
  76. head = (char*)buf + size;
  77. } else if (size > 0 && '\r' == ((char*)buf)[size-1]) {
  78. head = readAhead;
  79. len = 1;
  80. } else {
  81. break;
  82. }
  83. rval = PR_Read( f->lower, head, len );
  84. if ( rval < 0 ) { /* error */
  85. return rval;
  86. }
  87. if ( rval == 0 ) { /* EOF */
  88. if ( size ) {
  89. *(signed char*)&(f->secret) = g_EOF;
  90. }
  91. return size;
  92. }
  93. if (head == readAhead) {
  94. if ( '\n' == *readAhead ) {
  95. ((char*)buf)[size-1] = '\n';
  96. } else {
  97. *(signed char*)&(f->secret) = rval;
  98. }
  99. break;
  100. } else {
  101. auto char* tail = head + rval;
  102. auto char* dest = NULL;
  103. auto char* p;
  104. for ( p = head; p < tail; p++ ) {
  105. if ( *p == '\n' && p > (char*)buf && *(p - 1) == '\r' )
  106. {
  107. if ( dest == NULL ) { /* first CRLF */
  108. dest = p - 1;
  109. } else {
  110. auto size_t len = (p - 1) - head;
  111. memmove( dest, head, len );
  112. dest += len;
  113. }
  114. head = p; /* '\n' */
  115. --rval; /* ignore '\r' */
  116. }
  117. }
  118. if ( dest != NULL ) {
  119. auto size_t len = tail - head;
  120. memmove( dest, head, len );
  121. }
  122. size += rval;
  123. }
  124. }
  125. return size;
  126. }
  127. static PRInt32 PR_CALLBACK seekText(PRFileDesc *f, PRInt32 offset, PRSeekWhence how)
  128. {
  129. f->secret = NULL;
  130. return PR_Seek(f->lower, offset, how);
  131. }
  132. static PRInt64 PR_CALLBACK seek64Text(PRFileDesc *f, PRInt64 offset, PRSeekWhence how)
  133. {
  134. f->secret = NULL;
  135. return PR_Seek64(f->lower, offset, how);
  136. }
  137. static PRInt32 PR_CALLBACK writeText(PRFileDesc *f, const void *buf, PRInt32 amount)
  138. {
  139. /* note: buf might not be null-terminated */
  140. auto PRInt32 size = 0;
  141. auto char* head = (char*)buf;
  142. auto char* tail = head + amount;
  143. auto char* p;
  144. for ( p = head; p <= tail; ++p ) {
  145. if ( p == tail || *p == '\n' ) {
  146. auto PRInt32 len = p - head;
  147. auto PRInt32 rval;
  148. if ( len > 0 ) {
  149. rval = PR_Write( f->lower, head, len );
  150. if ( rval < 0 ) {
  151. return rval;
  152. }
  153. size += rval;
  154. if ( rval < len ) {
  155. break;
  156. }
  157. }
  158. if ( p == tail ) {
  159. break;
  160. }
  161. rval = PR_Write( f->lower, "\r", 1 );
  162. if ( rval < 0 ) {
  163. return rval;
  164. }
  165. if ( rval < 1 ) {
  166. break;
  167. }
  168. head = p;
  169. }
  170. }
  171. return size;
  172. }
  173. static PRInt32 PR_CALLBACK writevText(PRFileDesc *fd, const PRIOVec *iov, PRInt32 size, PRIntervalTime timeout)
  174. {
  175. auto PRInt32 i;
  176. auto size_t total = 0;
  177. for (i = 0; i < size; ++i) {
  178. register PRInt32 rval = PR_Write(fd, iov[i].iov_base, iov[i].iov_len);
  179. if (rval < 0) return rval;
  180. total += rval;
  181. if (rval < iov[i].iov_len) break;
  182. }
  183. return total;
  184. }
  185. /* ONREPL - this is bad because it allows only one thread to use this functionality.
  186. Noriko said she would fix this before 5.0 ships.
  187. */
  188. static const char* const g_LayerName = "MdsTextIO";
  189. static PRDescIdentity g_LayerID;
  190. static PRIOMethods g_IoMethods;
  191. static PRStatus PR_CALLBACK closeLayer(PRFileDesc* stack)
  192. {
  193. auto PRFileDesc* layer = PR_PopIOLayer(stack, g_LayerID);
  194. if (!layer)
  195. return PR_FAILURE;
  196. if (layer->dtor) {
  197. layer->secret = NULL;
  198. layer->dtor(layer);
  199. }
  200. return PR_Close(stack);
  201. }
  202. static PRStatus PR_CALLBACK initialize(void)
  203. {
  204. g_LayerID = PR_GetUniqueIdentity(g_LayerName);
  205. if (PR_INVALID_IO_LAYER == g_LayerID) {
  206. return PR_FAILURE;
  207. } else {
  208. auto const PRIOMethods* defaults = PR_GetDefaultIOMethods();
  209. if (!defaults) {
  210. return PR_FAILURE;
  211. } else {
  212. memcpy (&g_IoMethods, defaults, sizeof(g_IoMethods));
  213. }
  214. }
  215. /* Customize methods: */
  216. g_IoMethods.read = readText;
  217. g_IoMethods.seek = seekText;
  218. g_IoMethods.seek64 = seek64Text;
  219. g_IoMethods.write = writeText;
  220. g_IoMethods.writev = writevText; /* ??? Is this necessary? */
  221. g_IoMethods.close = closeLayer; /* ??? Is this necessary? */
  222. return PR_SUCCESS;
  223. }
  224. static PRCallOnceType g_callOnce = {0,0};
  225. /* Push a layer that converts from "\n" to the local filesystem's
  226. * end-of-line sequence on output, and vice-versa on input.
  227. * The layer pops itself (if necessary) when the file is closed.
  228. *
  229. * This layer does not affect the behavior of PR_Seek or PR_Seek64;
  230. * their parameters still measure bytes in the lower-level file,
  231. * and consequently will not add up with the results of PR_Read
  232. * or PR_Write. For example, if you add up PR_Read return values,
  233. * and seek backward in the file that many bytes, the cursor will
  234. * *not* be restored to its original position (unless the data you
  235. * read didn't require conversion; that is, they didn't contain
  236. * any newlines, or you're running on Unix).
  237. *
  238. * Likewise, the results of PR_Read or PR_Write won't add up to
  239. * the 'size' field in the result of PRFileInfo or PRFileInfo64.
  240. */
  241. static PRStatus pushTextIOLayer(PRFileDesc* stack)
  242. {
  243. auto PRStatus rv = PR_CallOnce(&g_callOnce, initialize);
  244. if (PR_SUCCESS == rv) {
  245. auto PRFileDesc* layer = PR_CreateIOLayerStub(g_LayerID, &g_IoMethods);
  246. layer->secret = NULL;
  247. rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, layer);
  248. }
  249. return rv;
  250. }
  251. static PRFileDesc *popTextIOLayer(PRFileDesc* stack)
  252. {
  253. PRFileDesc *layer;
  254. layer = PR_PopIOLayer(stack, g_LayerID);
  255. if (layer && layer->dtor) {
  256. layer->secret = NULL;
  257. layer->dtor(layer);
  258. }
  259. return layer;
  260. }
  261. #endif /* XP_WIN32 */
  262. PRInt32
  263. slapi_read_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
  264. {
  265. PRInt32 rval = 0;
  266. #if defined( XP_WIN32 )
  267. PRStatus rv;
  268. rv = pushTextIOLayer( fd );
  269. if ( PR_SUCCESS != rv ) {
  270. return -1;
  271. }
  272. #endif
  273. rval = PR_Read( fd, buf, amount );
  274. #if defined( XP_WIN32 )
  275. popTextIOLayer( fd );
  276. #endif
  277. return rval;
  278. }
  279. /*
  280. * slapi_write_buffer -- same as PR_Write
  281. * except '\r' is added before '\n'.
  282. * Return value: written bytes not including '\r' characters.
  283. */
  284. PRInt32
  285. slapi_write_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
  286. {
  287. PRInt32 rval = 0;
  288. #if defined( XP_WIN32 )
  289. PRStatus rv;
  290. rv = pushTextIOLayer( fd );
  291. if ( PR_SUCCESS != rv ) {
  292. return -1;
  293. }
  294. #endif
  295. rval = PR_Write( fd, buf, amount );
  296. #if defined( XP_WIN32 )
  297. popTextIOLayer( fd );
  298. #endif
  299. return rval;
  300. }
  301. /*
  302. * This function renames a file to a new name. Unlike PR_Rename or NT rename, this
  303. * function can be used if the destfilename exists, and it will overwrite the dest
  304. * file name
  305. */
  306. int
  307. slapi_destructive_rename(const char *srcfilename, const char *destfilename)
  308. {
  309. int rv = 0;
  310. #if defined( XP_WIN32 )
  311. if (!MoveFileEx(srcfilename, destfilename, MOVEFILE_REPLACE_EXISTING)) {
  312. rv = GetLastError();
  313. }
  314. #else
  315. if ( rename(srcfilename, destfilename) < 0 ) {
  316. rv = errno;
  317. }
  318. #endif
  319. return rv;
  320. }
  321. /*
  322. * This function copies the source into the dest
  323. */
  324. int
  325. slapi_copy(const char *srcfilename, const char *destfilename)
  326. {
  327. int rv = 0;
  328. #if defined( XP_WIN32 )
  329. if (!CopyFile(srcfilename, destfilename, FALSE)) {
  330. rv = GetLastError();
  331. }
  332. #else
  333. unlink(destfilename);
  334. if ( link(srcfilename, destfilename) < 0 ) {
  335. rv = errno;
  336. }
  337. #endif
  338. return rv;
  339. }