fileio.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* fileio.c - layer to adjust EOL to use DOS format via PR_Read/Write on NT */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include <errno.h>
  46. #include <stdlib.h>
  47. #ifndef _WIN32
  48. #include <sys/param.h>
  49. #include <unistd.h>
  50. #include <pwd.h>
  51. #endif
  52. #include "slap.h"
  53. #include "pw.h"
  54. #include <prio.h>
  55. #if defined( XP_WIN32 )
  56. #include <prinit.h> /* PR_CallOnce */
  57. #include <string.h> /* memmove, memcpy */
  58. #define g_EOF (-1)
  59. static PRInt32 PR_CALLBACK readText(PRFileDesc *f, void *buf, PRInt32 amount)
  60. {
  61. auto PRInt32 size = *(signed char*)&(f->secret);
  62. auto char* readAhead = ((char*)&(f->secret)) + 1;
  63. if ( size == g_EOF ) {
  64. f->secret = NULL;
  65. return 0;
  66. }
  67. if ( size > amount ) {
  68. return 0;
  69. }
  70. if ( size > 0 ) {
  71. memcpy( buf, readAhead, size );
  72. }
  73. f->secret = NULL;
  74. while (1) {
  75. auto PRInt32 len = amount - size;
  76. auto char* head;
  77. auto PRInt32 rval;
  78. if (len > 0) {
  79. head = (char*)buf + size;
  80. } else if (size > 0 && '\r' == ((char*)buf)[size-1]) {
  81. head = readAhead;
  82. len = 1;
  83. } else {
  84. break;
  85. }
  86. rval = PR_Read( f->lower, head, len );
  87. if ( rval < 0 ) { /* error */
  88. return rval;
  89. }
  90. if ( rval == 0 ) { /* EOF */
  91. if ( size ) {
  92. *(signed char*)&(f->secret) = g_EOF;
  93. }
  94. return size;
  95. }
  96. if (head == readAhead) {
  97. if ( '\n' == *readAhead ) {
  98. ((char*)buf)[size-1] = '\n';
  99. } else {
  100. *(signed char*)&(f->secret) = rval;
  101. }
  102. break;
  103. } else {
  104. auto char* tail = head + rval;
  105. auto char* dest = NULL;
  106. auto char* p;
  107. for ( p = head; p < tail; p++ ) {
  108. if ( *p == '\n' && p > (char*)buf && *(p - 1) == '\r' )
  109. {
  110. if ( dest == NULL ) { /* first CRLF */
  111. dest = p - 1;
  112. } else {
  113. auto size_t len = (p - 1) - head;
  114. memmove( dest, head, len );
  115. dest += len;
  116. }
  117. head = p; /* '\n' */
  118. --rval; /* ignore '\r' */
  119. }
  120. }
  121. if ( dest != NULL ) {
  122. auto size_t len = tail - head;
  123. memmove( dest, head, len );
  124. }
  125. size += rval;
  126. }
  127. }
  128. return size;
  129. }
  130. static PRInt32 PR_CALLBACK seekText(PRFileDesc *f, PRInt32 offset, PRSeekWhence how)
  131. {
  132. f->secret = NULL;
  133. return PR_Seek(f->lower, offset, how);
  134. }
  135. static PRInt64 PR_CALLBACK seek64Text(PRFileDesc *f, PRInt64 offset, PRSeekWhence how)
  136. {
  137. f->secret = NULL;
  138. return PR_Seek64(f->lower, offset, how);
  139. }
  140. static PRInt32 PR_CALLBACK writeText(PRFileDesc *f, const void *buf, PRInt32 amount)
  141. {
  142. /* note: buf might not be null-terminated */
  143. auto PRInt32 size = 0;
  144. auto char* head = (char*)buf;
  145. auto char* tail = head + amount;
  146. auto char* p;
  147. for ( p = head; p <= tail; ++p ) {
  148. if ( p == tail || *p == '\n' ) {
  149. auto PRInt32 len = p - head;
  150. auto PRInt32 rval;
  151. if ( len > 0 ) {
  152. rval = PR_Write( f->lower, head, len );
  153. if ( rval < 0 ) {
  154. return rval;
  155. }
  156. size += rval;
  157. if ( rval < len ) {
  158. break;
  159. }
  160. }
  161. if ( p == tail ) {
  162. break;
  163. }
  164. rval = PR_Write( f->lower, "\r", 1 );
  165. if ( rval < 0 ) {
  166. return rval;
  167. }
  168. if ( rval < 1 ) {
  169. break;
  170. }
  171. head = p;
  172. }
  173. }
  174. return size;
  175. }
  176. static PRInt32 PR_CALLBACK writevText(PRFileDesc *fd, const PRIOVec *iov, PRInt32 size, PRIntervalTime timeout)
  177. {
  178. auto PRInt32 i;
  179. auto size_t total = 0;
  180. for (i = 0; i < size; ++i) {
  181. register PRInt32 rval = PR_Write(fd, iov[i].iov_base, iov[i].iov_len);
  182. if (rval < 0) return rval;
  183. total += rval;
  184. if (rval < iov[i].iov_len) break;
  185. }
  186. return total;
  187. }
  188. /* ONREPL - this is bad because it allows only one thread to use this functionality.
  189. Noriko said she would fix this before 5.0 ships.
  190. */
  191. static const char* const g_LayerName = "MdsTextIO";
  192. static PRDescIdentity g_LayerID;
  193. static PRIOMethods g_IoMethods;
  194. static PRStatus PR_CALLBACK closeLayer(PRFileDesc* stack)
  195. {
  196. auto PRFileDesc* layer = PR_PopIOLayer(stack, g_LayerID);
  197. if (!layer)
  198. return PR_FAILURE;
  199. if (layer->dtor) {
  200. layer->secret = NULL;
  201. layer->dtor(layer);
  202. }
  203. return PR_Close(stack);
  204. }
  205. static PRStatus PR_CALLBACK initialize(void)
  206. {
  207. g_LayerID = PR_GetUniqueIdentity(g_LayerName);
  208. if (PR_INVALID_IO_LAYER == g_LayerID) {
  209. return PR_FAILURE;
  210. } else {
  211. auto const PRIOMethods* defaults = PR_GetDefaultIOMethods();
  212. if (!defaults) {
  213. return PR_FAILURE;
  214. } else {
  215. memcpy (&g_IoMethods, defaults, sizeof(g_IoMethods));
  216. }
  217. }
  218. /* Customize methods: */
  219. g_IoMethods.read = readText;
  220. g_IoMethods.seek = seekText;
  221. g_IoMethods.seek64 = seek64Text;
  222. g_IoMethods.write = writeText;
  223. g_IoMethods.writev = writevText; /* ??? Is this necessary? */
  224. g_IoMethods.close = closeLayer; /* ??? Is this necessary? */
  225. return PR_SUCCESS;
  226. }
  227. static PRCallOnceType g_callOnce = {0,0};
  228. /* Push a layer that converts from "\n" to the local filesystem's
  229. * end-of-line sequence on output, and vice-versa on input.
  230. * The layer pops itself (if necessary) when the file is closed.
  231. *
  232. * This layer does not affect the behavior of PR_Seek or PR_Seek64;
  233. * their parameters still measure bytes in the lower-level file,
  234. * and consequently will not add up with the results of PR_Read
  235. * or PR_Write. For example, if you add up PR_Read return values,
  236. * and seek backward in the file that many bytes, the cursor will
  237. * *not* be restored to its original position (unless the data you
  238. * read didn't require conversion; that is, they didn't contain
  239. * any newlines, or you're running on Unix).
  240. *
  241. * Likewise, the results of PR_Read or PR_Write won't add up to
  242. * the 'size' field in the result of PRFileInfo or PRFileInfo64.
  243. */
  244. static PRStatus pushTextIOLayer(PRFileDesc* stack)
  245. {
  246. auto PRStatus rv = PR_CallOnce(&g_callOnce, initialize);
  247. if (PR_SUCCESS == rv) {
  248. auto PRFileDesc* layer = PR_CreateIOLayerStub(g_LayerID, &g_IoMethods);
  249. layer->secret = NULL;
  250. rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, layer);
  251. }
  252. return rv;
  253. }
  254. static PRFileDesc *popTextIOLayer(PRFileDesc* stack)
  255. {
  256. PRFileDesc *layer;
  257. layer = PR_PopIOLayer(stack, g_LayerID);
  258. if (layer && layer->dtor) {
  259. layer->secret = NULL;
  260. layer->dtor(layer);
  261. }
  262. return layer;
  263. }
  264. #endif /* XP_WIN32 */
  265. PRInt32
  266. slapi_read_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
  267. {
  268. PRInt32 rval = 0;
  269. #if defined( XP_WIN32 )
  270. PRStatus rv;
  271. rv = pushTextIOLayer( fd );
  272. if ( PR_SUCCESS != rv ) {
  273. return -1;
  274. }
  275. #endif
  276. rval = PR_Read( fd, buf, amount );
  277. #if defined( XP_WIN32 )
  278. popTextIOLayer( fd );
  279. #endif
  280. return rval;
  281. }
  282. /*
  283. * slapi_write_buffer -- same as PR_Write
  284. * except '\r' is added before '\n'.
  285. * Return value: written bytes not including '\r' characters.
  286. */
  287. PRInt32
  288. slapi_write_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
  289. {
  290. PRInt32 rval = 0;
  291. #if defined( XP_WIN32 )
  292. PRStatus rv;
  293. rv = pushTextIOLayer( fd );
  294. if ( PR_SUCCESS != rv ) {
  295. return -1;
  296. }
  297. #endif
  298. rval = PR_Write( fd, buf, amount );
  299. #if defined( XP_WIN32 )
  300. popTextIOLayer( fd );
  301. #endif
  302. return rval;
  303. }
  304. /*
  305. * This function renames a file to a new name. Unlike PR_Rename or NT rename, this
  306. * function can be used if the destfilename exists, and it will overwrite the dest
  307. * file name
  308. */
  309. int
  310. slapi_destructive_rename(const char *srcfilename, const char *destfilename)
  311. {
  312. int rv = 0;
  313. #if defined( XP_WIN32 )
  314. if (!MoveFileEx(srcfilename, destfilename, MOVEFILE_REPLACE_EXISTING)) {
  315. rv = GetLastError();
  316. }
  317. #else
  318. if ( rename(srcfilename, destfilename) < 0 ) {
  319. rv = errno;
  320. }
  321. #endif
  322. return rv;
  323. }
  324. /*
  325. * This function copies the source into the dest
  326. */
  327. int
  328. slapi_copy(const char *srcfilename, const char *destfilename)
  329. {
  330. int rv = 0;
  331. #if defined( XP_WIN32 )
  332. if (!CopyFile(srcfilename, destfilename, FALSE)) {
  333. rv = GetLastError();
  334. }
  335. #else
  336. unlink(destfilename);
  337. if ( link(srcfilename, destfilename) < 0 ) {
  338. rv = errno;
  339. }
  340. #endif
  341. return rv;
  342. }