PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/emulator/drivers/unix/unix_efile.c

https://github.com/notarf/otp
C | 1511 lines | 1148 code | 140 blank | 223 comment | 312 complexity | 14ceac292d7805262271185a5ec5141e MD5 | raw file
Possible License(s): BSD-2-Clause
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1997-2011. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. /*
  20. * Purpose: Provides file and directory operations for Unix.
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. # include "config.h"
  24. #endif
  25. #include "sys.h"
  26. #include "erl_driver.h"
  27. #include "erl_efile.h"
  28. #include <utime.h>
  29. #ifdef HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. #ifdef HAVE_SYS_UIO_H
  33. #include <sys/types.h>
  34. #include <sys/uio.h>
  35. #endif
  36. #if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4)))
  37. #include <sys/sendfile.h>
  38. #endif
  39. #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
  40. #define DARWIN 1
  41. #endif
  42. #ifdef DARWIN
  43. #include <fcntl.h>
  44. #endif /* DARWIN */
  45. #ifdef VXWORKS
  46. #include <ioLib.h>
  47. #include <dosFsLib.h>
  48. #include <nfsLib.h>
  49. #include <sys/stat.h>
  50. /*
  51. ** Not nice to include usrLib.h as MANY normal variable names get reported
  52. ** as shadowing globals, like 'i' for example.
  53. ** Instead we declare the only function we use here
  54. */
  55. /*
  56. * #include <usrLib.h>
  57. */
  58. extern STATUS copy(char *, char *);
  59. #include <errno.h>
  60. #endif
  61. #ifdef SUNOS4
  62. # define getcwd(buf, size) getwd(buf)
  63. #endif
  64. /* Find a definition of MAXIOV, that is used in the code later. */
  65. #if defined IOV_MAX
  66. #define MAXIOV IOV_MAX
  67. #elif defined UIO_MAXIOV
  68. #define MAXIOV UIO_MAXIOV
  69. #else
  70. #define MAXIOV 16
  71. #endif
  72. /*
  73. * Macros for testing file types.
  74. */
  75. #define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR)
  76. #define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG)
  77. #define ISDEV(st) \
  78. (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
  79. #define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK)
  80. #ifdef NO_UMASK
  81. #define FILE_MODE 0644
  82. #define DIR_MODE 0755
  83. #else
  84. #define FILE_MODE 0666
  85. #define DIR_MODE 0777
  86. #endif
  87. #ifdef VXWORKS /* Currently only used on vxworks */
  88. #define EF_ALLOC(S) driver_alloc((S))
  89. #define EF_REALLOC(P, S) driver_realloc((P), (S))
  90. #define EF_SAFE_ALLOC(S) ef_safe_alloc((S))
  91. #define EF_SAFE_REALLOC(P, S) ef_safe_realloc((P), (S))
  92. #define EF_FREE(P) do { if((P)) driver_free((P)); } while(0)
  93. void erl_exit(int n, char *fmt, ...);
  94. static void *ef_safe_alloc(Uint s)
  95. {
  96. void *p = EF_ALLOC(s);
  97. if (!p) erl_exit(1,
  98. "unix efile drv: Can't allocate %d bytes of memory\n",
  99. s);
  100. return p;
  101. }
  102. #if 0 /* Currently not used */
  103. static void *ef_safe_realloc(void *op, Uint s)
  104. {
  105. void *p = EF_REALLOC(op, s);
  106. if (!p) erl_exit(1,
  107. "unix efile drv: Can't reallocate %d bytes of memory\n",
  108. s);
  109. return p;
  110. }
  111. #endif /* #if 0 */
  112. #endif /* #ifdef VXWORKS */
  113. #define IS_DOT_OR_DOTDOT(s) \
  114. (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')))
  115. #ifdef VXWORKS
  116. static int vxworks_to_posix(int vx_errno);
  117. #endif
  118. /*
  119. ** VxWorks (not) strikes again. Too long RESULTING paths
  120. ** may give the infamous bus error. Have to check ALL
  121. ** filenames and pathnames. No wonder the emulator is slow on
  122. ** these cards...
  123. */
  124. #ifdef VXWORKS
  125. #define CHECK_PATHLEN(Name, ErrInfo) \
  126. if (path_size(Name) > PATH_MAX) { \
  127. errno = ENAMETOOLONG; \
  128. return check_error(-1, ErrInfo); \
  129. }
  130. #else
  131. #define CHECK_PATHLEN(X,Y) /* Nothing */
  132. #endif
  133. static int check_error(int result, Efile_error* errInfo);
  134. static int
  135. check_error(int result, Efile_error *errInfo)
  136. {
  137. if (result < 0) {
  138. #ifdef VXWORKS
  139. errInfo->posix_errno = errInfo->os_errno = vxworks_to_posix(errno);
  140. #else
  141. errInfo->posix_errno = errInfo->os_errno = errno;
  142. #endif
  143. return 0;
  144. }
  145. return 1;
  146. }
  147. #ifdef VXWORKS
  148. /*
  149. * VxWorks has different error codes for different file systems.
  150. * We map those to POSIX ones.
  151. */
  152. static int
  153. vxworks_to_posix(int vx_errno)
  154. {
  155. DEBUGF(("[vxworks_to_posix] vx_errno: %08x\n", vx_errno));
  156. switch (vx_errno) {
  157. /* dosFsLib mapping */
  158. #ifdef S_dosFsLib_FILE_ALREADY_EXISTS
  159. case S_dosFsLib_FILE_ALREADY_EXISTS: return EEXIST;
  160. #else
  161. case S_dosFsLib_FILE_EXISTS: return EEXIST;
  162. #endif
  163. #ifdef S_dosFsLib_BAD_DISK
  164. case S_dosFsLib_BAD_DISK: return EIO;
  165. #endif
  166. #ifdef S_dosFsLib_CANT_CHANGE_ROOT
  167. case S_dosFsLib_CANT_CHANGE_ROOT: return EINVAL;
  168. #endif
  169. #ifdef S_dosFsLib_NO_BLOCK_DEVICE
  170. case S_dosFsLib_NO_BLOCK_DEVICE: return ENOTBLK;
  171. #endif
  172. #ifdef S_dosFsLib_BAD_SEEK
  173. case S_dosFsLib_BAD_SEEK: return ESPIPE;
  174. #endif
  175. case S_dosFsLib_VOLUME_NOT_AVAILABLE: return ENXIO;
  176. case S_dosFsLib_DISK_FULL: return ENOSPC;
  177. case S_dosFsLib_FILE_NOT_FOUND: return ENOENT;
  178. case S_dosFsLib_NO_FREE_FILE_DESCRIPTORS: return ENFILE;
  179. case S_dosFsLib_INVALID_NUMBER_OF_BYTES: return EINVAL;
  180. case S_dosFsLib_ILLEGAL_NAME: return EINVAL;
  181. case S_dosFsLib_CANT_DEL_ROOT: return EACCES;
  182. case S_dosFsLib_NOT_FILE: return EISDIR;
  183. case S_dosFsLib_NOT_DIRECTORY: return ENOTDIR;
  184. case S_dosFsLib_NOT_SAME_VOLUME: return EXDEV;
  185. case S_dosFsLib_READ_ONLY: return EACCES;
  186. case S_dosFsLib_ROOT_DIR_FULL: return ENOSPC;
  187. case S_dosFsLib_DIR_NOT_EMPTY: return EEXIST;
  188. case S_dosFsLib_NO_LABEL: return ENXIO;
  189. case S_dosFsLib_INVALID_PARAMETER: return EINVAL;
  190. case S_dosFsLib_NO_CONTIG_SPACE: return ENOSPC;
  191. case S_dosFsLib_FD_OBSOLETE: return EBADF;
  192. case S_dosFsLib_DELETED: return EINVAL;
  193. case S_dosFsLib_INTERNAL_ERROR: return EIO;
  194. case S_dosFsLib_WRITE_ONLY: return EACCES;
  195. /* nfsLib mapping - is needed since Windriver has used */
  196. /* inconsistent error codes (errno.h/nfsLib.h). */
  197. case S_nfsLib_NFS_OK: return 0;
  198. case S_nfsLib_NFSERR_PERM: return EPERM;
  199. case S_nfsLib_NFSERR_NOENT: return ENOENT;
  200. case S_nfsLib_NFSERR_IO: return EIO;
  201. case S_nfsLib_NFSERR_NXIO: return ENXIO;
  202. #ifdef S_nfsLib_NFSERR_ACCES
  203. case S_nfsLib_NFSERR_ACCES: return EACCES;
  204. #else
  205. case S_nfsLib_NFSERR_ACCESS: return EACCES;
  206. #endif
  207. case S_nfsLib_NFSERR_EXIST: return EEXIST;
  208. case S_nfsLib_NFSERR_NODEV: return ENODEV;
  209. case S_nfsLib_NFSERR_NOTDIR: return ENOTDIR;
  210. case S_nfsLib_NFSERR_ISDIR: return EISDIR;
  211. case S_nfsLib_NFSERR_FBIG: return EFBIG;
  212. case S_nfsLib_NFSERR_NOSPC: return ENOSPC;
  213. case S_nfsLib_NFSERR_ROFS: return EROFS;
  214. case S_nfsLib_NFSERR_NAMETOOLONG: return ENAMETOOLONG;
  215. case S_nfsLib_NFSERR_NOTEMPTY: return EEXIST;
  216. case S_nfsLib_NFSERR_DQUOT: return ENOSPC;
  217. case S_nfsLib_NFSERR_STALE: return EINVAL;
  218. case S_nfsLib_NFSERR_WFLUSH: return ENXIO;
  219. /* And sometimes (...) the error codes are from ioLib (as in the */
  220. /* case of the (for nfsLib) unimplemented rename function) */
  221. case S_ioLib_DISK_NOT_PRESENT: return EIO;
  222. #if S_ioLib_DISK_NOT_PRESENT != S_ioLib_NO_DRIVER
  223. case S_ioLib_NO_DRIVER: return ENXIO;
  224. #endif
  225. case S_ioLib_UNKNOWN_REQUEST: return ENOSYS;
  226. case S_ioLib_DEVICE_TIMEOUT: return EIO;
  227. #ifdef S_ioLib_UNFORMATED
  228. /* Added (VxWorks 5.2 -> 5.3.1) */
  229. #if S_ioLib_UNFORMATED != S_ioLib_DEVICE_TIMEOUT
  230. case S_ioLib_UNFORMATED: return EIO;
  231. #endif
  232. #endif
  233. #if S_ioLib_DEVICE_TIMEOUT != S_ioLib_DEVICE_ERROR
  234. case S_ioLib_DEVICE_ERROR: return ENXIO;
  235. #endif
  236. case S_ioLib_WRITE_PROTECTED: return EACCES;
  237. case S_ioLib_NO_FILENAME: return EINVAL;
  238. case S_ioLib_CANCELLED: return EINTR;
  239. case S_ioLib_NO_DEVICE_NAME_IN_PATH: return EINVAL;
  240. case S_ioLib_NAME_TOO_LONG: return ENAMETOOLONG;
  241. #ifdef S_objLib_OBJ_UNAVAILABLE
  242. case S_objLib_OBJ_UNAVAILABLE: return ENOENT;
  243. #endif
  244. /* Temporary workaround for a weird error in passFs
  245. (VxWorks Simsparc only). File operation fails because of
  246. ENOENT, but errno is not set. */
  247. #ifdef SIMSPARCSOLARIS
  248. case 0: return ENOENT;
  249. #endif
  250. }
  251. /* If the error code matches none of the above, assume */
  252. /* it is a POSIX one already. The upper bits (>=16) are */
  253. /* cleared since VxWorks uses those bits to indicate in */
  254. /* what module the error occured. */
  255. return vx_errno & 0xffff;
  256. }
  257. static int
  258. vxworks_enotsup(Efile_error *errInfo)
  259. {
  260. errInfo->posix_errno = errInfo->os_errno = ENOTSUP;
  261. return 0;
  262. }
  263. static int
  264. count_path_length(char *pathname, char *pathname2)
  265. {
  266. static int stack[PATH_MAX / 2 + 1];
  267. int sp = 0;
  268. char *tmp;
  269. char *cpy = NULL;
  270. int i;
  271. int sum;
  272. for(i = 0;i < 2;++i) {
  273. if (!i) {
  274. cpy = EF_SAFE_ALLOC(strlen(pathname)+1);
  275. strcpy(cpy, pathname);
  276. } else if (pathname2 != NULL) {
  277. EF_FREE(cpy);
  278. cpy = EF_SAFE_ALLOC(strlen(pathname2)+1);
  279. strcpy(cpy, pathname2);
  280. } else
  281. break;
  282. for (tmp = strtok(cpy,"/"); tmp != NULL; tmp = strtok(NULL,"/")) {
  283. if (!strcmp(tmp,"..") && sp > 0)
  284. --sp;
  285. else if (strcmp(tmp,"."))
  286. stack[sp++] = strlen(tmp);
  287. }
  288. }
  289. if (cpy != NULL)
  290. EF_FREE(cpy);
  291. sum = 0;
  292. for(i = 0;i < sp; ++i)
  293. sum += stack[i]+1;
  294. return (sum) ? sum : 1;
  295. }
  296. static int
  297. path_size(char *pathname)
  298. {
  299. static char currdir[PATH_MAX+2];
  300. if (*pathname == '/')
  301. return count_path_length(pathname,NULL);
  302. ioDefPathGet(currdir);
  303. strcat(currdir,"/");
  304. return count_path_length(currdir,pathname);
  305. }
  306. #endif /* VXWORKS */
  307. int
  308. efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */
  309. char* name) /* Name of directory to create. */
  310. {
  311. CHECK_PATHLEN(name,errInfo);
  312. #ifdef NO_MKDIR_MODE
  313. #ifdef VXWORKS
  314. /* This is a VxWorks/nfs workaround for erl_tar to create
  315. * non-existant directories. (of some reason (...) VxWorks
  316. * returns, the *non-module-prefixed*, 0xd code when
  317. * trying to create a directory in a directory that doesn't exist).
  318. * (see efile_openfile)
  319. */
  320. if (mkdir(name) < 0) {
  321. struct stat sb;
  322. if (name[0] == '\0') {
  323. /* Return the correct error code enoent */
  324. errno = S_nfsLib_NFSERR_NOENT;
  325. } else if (stat(name, &sb) == OK) {
  326. errno = S_nfsLib_NFSERR_EXIST;
  327. } else if((strchr(name, '/') != NULL) && (errno == 0xd)) {
  328. /* Return the correct error code enoent */
  329. errno = S_nfsLib_NFSERR_NOENT;
  330. }
  331. return check_error(-1, errInfo);
  332. } else return 1;
  333. #else
  334. return check_error(mkdir(name), errInfo);
  335. #endif
  336. #else
  337. return check_error(mkdir(name, DIR_MODE), errInfo);
  338. #endif
  339. }
  340. int
  341. efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */
  342. char* name) /* Name of directory to delete. */
  343. {
  344. CHECK_PATHLEN(name, errInfo);
  345. if (rmdir(name) == 0) {
  346. return 1;
  347. }
  348. #ifdef VXWORKS
  349. if (name[0] == '\0') {
  350. /* Return the correct error code enoent */
  351. errno = S_nfsLib_NFSERR_NOENT;
  352. }
  353. #else
  354. if (errno == ENOTEMPTY) {
  355. errno = EEXIST;
  356. }
  357. if (errno == EEXIST) {
  358. int saved_errno = errno;
  359. struct stat file_stat;
  360. struct stat cwd_stat;
  361. /*
  362. * The error code might be wrong if this is the current directory.
  363. */
  364. if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 &&
  365. file_stat.st_ino == cwd_stat.st_ino &&
  366. file_stat.st_dev == cwd_stat.st_dev) {
  367. saved_errno = EINVAL;
  368. }
  369. errno = saved_errno;
  370. }
  371. #endif
  372. return check_error(-1, errInfo);
  373. }
  374. int
  375. efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */
  376. char* name) /* Name of file to delete. */
  377. {
  378. CHECK_PATHLEN(name,errInfo);
  379. if (unlink(name) == 0) {
  380. return 1;
  381. }
  382. if (errno == EISDIR) { /* Linux sets the wrong error code. */
  383. errno = EPERM;
  384. }
  385. return check_error(-1, errInfo);
  386. }
  387. /*
  388. *---------------------------------------------------------------------------
  389. *
  390. * Changes the name of an existing file or directory, from src to dst.
  391. * If src and dst refer to the same file or directory, does nothing
  392. * and returns success. Otherwise if dst already exists, it will be
  393. * deleted and replaced by src subject to the following conditions:
  394. * If src is a directory, dst may be an empty directory.
  395. * If src is a file, dst may be a file.
  396. * In any other situation where dst already exists, the rename will
  397. * fail.
  398. *
  399. * Results:
  400. * If the directory was successfully created, returns 1.
  401. * Otherwise the return value is 0 and errno is set to
  402. * indicate the error. Some possible values for errno are:
  403. *
  404. * EACCES: src or dst parent directory can't be read and/or written.
  405. * EEXIST: dst is a non-empty directory.
  406. * EINVAL: src is a root directory or dst is a subdirectory of src.
  407. * EISDIR: dst is a directory, but src is not.
  408. * ENOENT: src doesn't exist, or src or dst is "".
  409. * ENOTDIR: src is a directory, but dst is not.
  410. * EXDEV: src and dst are on different filesystems.
  411. *
  412. * Side effects:
  413. * The implementation of rename may allow cross-filesystem renames,
  414. * but the caller should be prepared to emulate it with copy and
  415. * delete if errno is EXDEV.
  416. *
  417. *---------------------------------------------------------------------------
  418. */
  419. int
  420. efile_rename(Efile_error* errInfo, /* Where to return error codes. */
  421. char* src, /* Original name. */
  422. char* dst) /* New name. */
  423. {
  424. CHECK_PATHLEN(src,errInfo);
  425. CHECK_PATHLEN(dst,errInfo);
  426. #ifdef VXWORKS
  427. /* First check if src == dst, if so, just return. */
  428. /* VxWorks dos file system destroys the file otherwise, */
  429. /* VxWorks nfs file system rename doesn't work at all. */
  430. if(strcmp(src, dst) == 0)
  431. return 1;
  432. #endif
  433. if (rename(src, dst) == 0) {
  434. return 1;
  435. }
  436. #ifdef VXWORKS
  437. /* nfs for VxWorks doesn't support rename. We try to emulate it */
  438. /* (by first copying src to dst and then deleting src). */
  439. if(errno == S_ioLib_UNKNOWN_REQUEST && /* error code returned
  440. by ioLib (!) */
  441. copy(src, dst) == OK &&
  442. unlink(src) == OK)
  443. return 1;
  444. #endif
  445. if (errno == ENOTEMPTY) {
  446. errno = EEXIST;
  447. }
  448. #if defined (sparc) && !defined(VXWORKS)
  449. /*
  450. * SunOS 4.1.4 reports overwriting a non-empty directory with a
  451. * directory as EINVAL instead of EEXIST (first rule out the correct
  452. * EINVAL result code for moving a directory into itself). Must be
  453. * conditionally compiled because realpath() is only defined on SunOS.
  454. */
  455. if (errno == EINVAL) {
  456. char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN];
  457. DIR *dirPtr;
  458. struct dirent *dirEntPtr;
  459. #ifdef PURIFY
  460. memset(srcPath, '\0', sizeof(srcPath));
  461. memset(dstPath, '\0', sizeof(dstPath));
  462. #endif
  463. if ((realpath(src, srcPath) != NULL)
  464. && (realpath(dst, dstPath) != NULL)
  465. && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) {
  466. dirPtr = opendir(dst);
  467. if (dirPtr != NULL) {
  468. while ((dirEntPtr = readdir(dirPtr)) != NULL) {
  469. if ((strcmp(dirEntPtr->d_name, ".") != 0) &&
  470. (strcmp(dirEntPtr->d_name, "..") != 0)) {
  471. errno = EEXIST;
  472. closedir(dirPtr);
  473. return check_error(-1, errInfo);
  474. }
  475. }
  476. closedir(dirPtr);
  477. }
  478. }
  479. errno = EINVAL;
  480. }
  481. #endif /* sparc */
  482. if (strcmp(src, "/") == 0) {
  483. /*
  484. * Alpha reports renaming / as EBUSY and Linux reports it as EACCES,
  485. * instead of EINVAL.
  486. */
  487. errno = EINVAL;
  488. }
  489. /*
  490. * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a
  491. * file across filesystems and the parent directory of that file is
  492. * not writable. Most other systems return EXDEV. Does nothing to
  493. * correct this behavior.
  494. */
  495. return check_error(-1, errInfo);
  496. }
  497. int
  498. efile_chdir(Efile_error* errInfo, /* Where to return error codes. */
  499. char* name) /* Name of directory to make current. */
  500. {
  501. CHECK_PATHLEN(name, errInfo);
  502. return check_error(chdir(name), errInfo);
  503. }
  504. int
  505. efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */
  506. int drive, /* 0 - current, 1 - A, 2 - B etc. */
  507. char* buffer, /* Where to return the current
  508. directory. */
  509. size_t size) /* Size of buffer. */
  510. {
  511. if (drive == 0) {
  512. if (getcwd(buffer, size) == NULL)
  513. return check_error(-1, errInfo);
  514. #ifdef SIMSPARCSOLARIS
  515. /* We get "host:" prepended to the dirname - remove!. */
  516. {
  517. int i = 0;
  518. int j = 0;
  519. while ((buffer[i] != ':') && (buffer[i] != '\0')) i++;
  520. if (buffer[i] == ':') {
  521. i++;
  522. while ((buffer[j++] = buffer[i++]) != '\0');
  523. }
  524. }
  525. #endif
  526. return 1;
  527. }
  528. /*
  529. * Drives other than 0 is not supported on Unix.
  530. */
  531. errno = ENOTSUP;
  532. return check_error(-1, errInfo);
  533. }
  534. int
  535. efile_readdir(Efile_error* errInfo, /* Where to return error codes. */
  536. char* name, /* Name of directory to open. */
  537. EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory
  538. handle of
  539. open directory.*/
  540. char* buffer, /* Pointer to buffer for
  541. one filename. */
  542. size_t *size) /* in-out Size of buffer, length
  543. of name. */
  544. {
  545. DIR *dp; /* Pointer to directory structure. */
  546. struct dirent* dirp; /* Pointer to directory entry. */
  547. /*
  548. * If this is the first call, we must open the directory.
  549. */
  550. CHECK_PATHLEN(name, errInfo);
  551. if (*p_dir_handle == NULL) {
  552. dp = opendir(name);
  553. if (dp == NULL)
  554. return check_error(-1, errInfo);
  555. *p_dir_handle = (EFILE_DIR_HANDLE) dp;
  556. }
  557. /*
  558. * Retrieve the name of the next file using the directory handle.
  559. */
  560. dp = *((DIR **)((void *)p_dir_handle));
  561. for (;;) {
  562. dirp = readdir(dp);
  563. if (dirp == NULL) {
  564. closedir(dp);
  565. return 0;
  566. }
  567. if (IS_DOT_OR_DOTDOT(dirp->d_name))
  568. continue;
  569. buffer[0] = '\0';
  570. strncat(buffer, dirp->d_name, (*size)-1);
  571. *size = strlen(dirp->d_name);
  572. return 1;
  573. }
  574. }
  575. int
  576. efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
  577. char* name, /* Name of directory to open. */
  578. int flags, /* Flags to user for opening. */
  579. int* pfd, /* Where to store the file
  580. descriptor. */
  581. Sint64 *pSize) /* Where to store the size of the
  582. file. */
  583. {
  584. struct stat statbuf;
  585. int fd;
  586. int mode; /* Open mode. */
  587. #ifdef VXWORKS
  588. char pathbuff[PATH_MAX+2];
  589. char sbuff[PATH_MAX*2];
  590. char *totbuff = sbuff;
  591. int nameneed;
  592. #endif
  593. CHECK_PATHLEN(name, errInfo);
  594. #ifdef VXWORKS
  595. /* Have to check that it's not a directory. */
  596. if (stat(name,&statbuf) != ERROR && ISDIR(statbuf)) {
  597. errno = EISDIR;
  598. return check_error(-1, errInfo);
  599. }
  600. #endif
  601. if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) {
  602. #if !defined(VXWORKS) && !defined(OSE)
  603. /*
  604. * For UNIX only, here is some ugly code to allow
  605. * /dev/null to be opened as a file.
  606. *
  607. * Assumption: The i-node number for /dev/null cannot be zero.
  608. */
  609. static ino_t dev_null_ino = 0;
  610. if (dev_null_ino == 0) {
  611. struct stat nullstatbuf;
  612. if (stat("/dev/null", &nullstatbuf) >= 0) {
  613. dev_null_ino = nullstatbuf.st_ino;
  614. }
  615. }
  616. if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) {
  617. #endif
  618. errno = EISDIR;
  619. return check_error(-1, errInfo);
  620. #if !defined(VXWORKS) && !defined(OSE)
  621. }
  622. #endif
  623. }
  624. switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
  625. case EFILE_MODE_READ:
  626. mode = O_RDONLY;
  627. break;
  628. case EFILE_MODE_WRITE:
  629. if (flags & EFILE_NO_TRUNCATE)
  630. mode = O_WRONLY | O_CREAT;
  631. else
  632. mode = O_WRONLY | O_CREAT | O_TRUNC;
  633. break;
  634. case EFILE_MODE_READ_WRITE:
  635. mode = O_RDWR | O_CREAT;
  636. break;
  637. default:
  638. errno = EINVAL;
  639. return check_error(-1, errInfo);
  640. }
  641. if (flags & EFILE_MODE_APPEND) {
  642. mode &= ~O_TRUNC;
  643. #ifndef VXWORKS
  644. mode |= O_APPEND; /* Dont make VxWorks think things it shouldn't */
  645. #endif
  646. }
  647. if (flags & EFILE_MODE_EXCL) {
  648. mode |= O_EXCL;
  649. }
  650. #ifdef VXWORKS
  651. if (*name != '/') {
  652. /* Make sure it is an absolute pathname, because ftruncate needs it */
  653. ioDefPathGet(pathbuff);
  654. strcat(pathbuff,"/");
  655. nameneed = strlen(pathbuff) + strlen(name) + 1;
  656. if (nameneed > PATH_MAX*2)
  657. totbuff = EF_SAFE_ALLOC(nameneed);
  658. strcpy(totbuff,pathbuff);
  659. strcat(totbuff,name);
  660. fd = open(totbuff, mode, FILE_MODE);
  661. if (totbuff != sbuff)
  662. EF_FREE(totbuff);
  663. } else {
  664. fd = open(name, mode, FILE_MODE);
  665. }
  666. #else
  667. fd = open(name, mode, FILE_MODE);
  668. #endif
  669. #ifdef VXWORKS
  670. /* This is a VxWorks/nfs workaround for erl_tar to create
  671. * non-existant directories. (of some reason (...) VxWorks
  672. * returns, the *non-module-prefixed*, 0xd code when
  673. * trying to write a file in a directory that doesn't exist).
  674. * (see efile_mkdir)
  675. */
  676. if ((fd < 0) && (strchr(name, '/') != NULL) && (errno == 0xd)) {
  677. /* Return the correct error code enoent */
  678. errno = S_nfsLib_NFSERR_NOENT;
  679. return check_error(-1, errInfo);
  680. }
  681. #endif
  682. if (!check_error(fd, errInfo))
  683. return 0;
  684. *pfd = fd;
  685. if (pSize) {
  686. *pSize = statbuf.st_size;
  687. }
  688. return 1;
  689. }
  690. int
  691. efile_may_openfile(Efile_error* errInfo, char *name) {
  692. struct stat statbuf; /* Information about the file */
  693. int result;
  694. result = stat(name, &statbuf);
  695. if (!check_error(result, errInfo))
  696. return 0;
  697. if (!ISREG(statbuf)) {
  698. errno = EISDIR;
  699. return check_error(-1, errInfo);
  700. }
  701. return 1;
  702. }
  703. void
  704. efile_closefile(int fd)
  705. {
  706. close(fd);
  707. }
  708. int
  709. efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */
  710. int fd) /* File descriptor for file to sync data. */
  711. {
  712. #ifdef HAVE_FDATASYNC
  713. return check_error(fdatasync(fd), errInfo);
  714. #else
  715. return efile_fsync(errInfo, fd);
  716. #endif
  717. }
  718. int
  719. efile_fsync(Efile_error *errInfo, /* Where to return error codes. */
  720. int fd) /* File descriptor for file to sync. */
  721. {
  722. #ifdef NO_FSYNC
  723. #ifdef VXWORKS
  724. return check_error(ioctl(fd, FIOSYNC, 0), errInfo);
  725. #else
  726. undefined fsync
  727. #endif /* VXWORKS */
  728. #else
  729. #if defined(DARWIN) && defined(F_FULLFSYNC)
  730. return check_error(fcntl(fd, F_FULLFSYNC), errInfo);
  731. #else
  732. return check_error(fsync(fd), errInfo);
  733. #endif /* DARWIN */
  734. #endif /* NO_FSYNC */
  735. }
  736. int
  737. efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
  738. char* name, int info_for_link)
  739. {
  740. struct stat statbuf; /* Information about the file */
  741. int result;
  742. #ifdef VXWORKS
  743. if (*name == '\0') {
  744. errInfo->posix_errno = errInfo->os_errno = ENOENT;
  745. return 0;
  746. }
  747. #endif
  748. CHECK_PATHLEN(name, errInfo);
  749. if (info_for_link) {
  750. #if (defined(VXWORKS))
  751. result = stat(name, &statbuf);
  752. #else
  753. result = lstat(name, &statbuf);
  754. #endif
  755. } else {
  756. result = stat(name, &statbuf);
  757. }
  758. if (!check_error(result, errInfo)) {
  759. return 0;
  760. }
  761. #if SIZEOF_OFF_T == 4
  762. pInfo->size_high = 0;
  763. #else
  764. pInfo->size_high = (Uint32)(statbuf.st_size >> 32);
  765. #endif
  766. pInfo->size_low = (Uint32)statbuf.st_size;
  767. #ifdef NO_ACCESS
  768. /* Just look at read/write access for owner. */
  769. #ifdef VXWORKS
  770. pInfo->access = FA_NONE;
  771. if(statbuf.st_mode & S_IRUSR)
  772. pInfo->access |= FA_READ;
  773. if(statbuf.st_mode & S_IWUSR)
  774. pInfo->access |= FA_WRITE;
  775. #else
  776. pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1;
  777. #endif /* VXWORKS */
  778. #else
  779. pInfo->access = FA_NONE;
  780. if (access(name, R_OK) == 0)
  781. pInfo->access |= FA_READ;
  782. if (access(name, W_OK) == 0)
  783. pInfo->access |= FA_WRITE;
  784. #endif
  785. if (ISDEV(statbuf))
  786. pInfo->type = FT_DEVICE;
  787. else if (ISDIR(statbuf))
  788. pInfo->type = FT_DIRECTORY;
  789. else if (ISREG(statbuf))
  790. pInfo->type = FT_REGULAR;
  791. else if (ISLNK(statbuf))
  792. pInfo->type = FT_SYMLINK;
  793. else
  794. pInfo->type = FT_OTHER;
  795. pInfo->accessTime = statbuf.st_atime;
  796. pInfo->modifyTime = statbuf.st_mtime;
  797. pInfo->cTime = statbuf.st_ctime;
  798. pInfo->mode = statbuf.st_mode;
  799. pInfo->links = statbuf.st_nlink;
  800. pInfo->major_device = statbuf.st_dev;
  801. pInfo->minor_device = statbuf.st_rdev;
  802. pInfo->inode = statbuf.st_ino;
  803. pInfo->uid = statbuf.st_uid;
  804. pInfo->gid = statbuf.st_gid;
  805. return 1;
  806. }
  807. int
  808. efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name)
  809. {
  810. struct utimbuf tval;
  811. CHECK_PATHLEN(name, errInfo);
  812. #ifdef VXWORKS
  813. if (pInfo->mode != -1) {
  814. int fd;
  815. struct stat statbuf;
  816. fd = open(name, O_RDONLY, 0);
  817. if (!check_error(fd, errInfo))
  818. return 0;
  819. if (fstat(fd, &statbuf) < 0) {
  820. close(fd);
  821. return check_error(-1, errInfo);
  822. }
  823. if (pInfo->mode & S_IWUSR) {
  824. /* clear read only bit */
  825. statbuf.st_attrib &= ~DOS_ATTR_RDONLY;
  826. } else {
  827. /* set read only bit */
  828. statbuf.st_attrib |= DOS_ATTR_RDONLY;
  829. }
  830. /* This should work for dos files but not for nfs ditos, so don't
  831. * report errors (to avoid problems when running e.g. erl_tar)
  832. */
  833. ioctl(fd, FIOATTRIBSET, statbuf.st_attrib);
  834. close(fd);
  835. }
  836. #else
  837. /*
  838. * On some systems chown will always fail for a non-root user unless
  839. * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as
  840. * you don't try to chown a file to someone besides youself.
  841. */
  842. if (chown(name, pInfo->uid, pInfo->gid) && errno != EPERM) {
  843. return check_error(-1, errInfo);
  844. }
  845. if (pInfo->mode != -1) {
  846. mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID |
  847. S_IRWXU | S_IRWXG | S_IRWXO);
  848. if (chmod(name, newMode)) {
  849. newMode &= ~(S_ISUID | S_ISGID);
  850. if (chmod(name, newMode)) {
  851. return check_error(-1, errInfo);
  852. }
  853. }
  854. }
  855. #endif /* !VXWORKS */
  856. tval.actime = pInfo->accessTime;
  857. tval.modtime = pInfo->modifyTime;
  858. #ifdef VXWORKS
  859. /* VxWorks' utime doesn't work when the file is a nfs mounted
  860. * one, don't report error if utime fails.
  861. */
  862. utime(name, &tval);
  863. return 1;
  864. #else
  865. return check_error(utime(name, &tval), errInfo);
  866. #endif
  867. }
  868. int
  869. efile_write(Efile_error* errInfo, /* Where to return error codes. */
  870. int flags, /* Flags given when file was
  871. opened. */
  872. int fd, /* File descriptor to write to. */
  873. char* buf, /* Buffer to write. */
  874. size_t count) /* Number of bytes to write. */
  875. {
  876. ssize_t written; /* Bytes written in last operation. */
  877. #ifdef VXWORKS
  878. if (flags & EFILE_MODE_APPEND) {
  879. lseek(fd, 0, SEEK_END); /* Naive append emulation on VXWORKS */
  880. }
  881. #endif
  882. while (count > 0) {
  883. if ((written = write(fd, buf, count)) < 0) {
  884. if (errno != EINTR)
  885. return check_error(-1, errInfo);
  886. else
  887. written = 0;
  888. }
  889. ASSERT(written <= count);
  890. buf += written;
  891. count -= written;
  892. }
  893. return 1;
  894. }
  895. int
  896. efile_writev(Efile_error* errInfo, /* Where to return error codes */
  897. int flags, /* Flags given when file was
  898. * opened */
  899. int fd, /* File descriptor to write to */
  900. SysIOVec* iov, /* Vector of buffer structs.
  901. * The structs may be changed i.e.
  902. * due to incomplete writes */
  903. int iovcnt) /* Number of structs in vector */
  904. {
  905. int cnt = 0; /* Buffers so far written */
  906. ASSERT(iovcnt >= 0);
  907. #ifdef VXWORKS
  908. if (flags & EFILE_MODE_APPEND) {
  909. lseek(fd, 0, SEEK_END); /* Naive append emulation on VXWORKS */
  910. }
  911. #endif
  912. while (cnt < iovcnt) {
  913. if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) {
  914. /* Empty buffer - skip */
  915. cnt++;
  916. } else { /* Non-empty buffer */
  917. ssize_t w; /* Bytes written in this call */
  918. #ifdef HAVE_WRITEV
  919. int b = iovcnt - cnt; /* Buffers to write */
  920. /* Use as many buffers as MAXIOV allows */
  921. if (b > MAXIOV)
  922. b = MAXIOV;
  923. if (b > 1) {
  924. do {
  925. w = writev(fd, &iov[cnt], b);
  926. } while (w < 0 && errno == EINTR);
  927. } else
  928. /* Degenerated io vector - use regular write */
  929. #endif
  930. {
  931. do {
  932. w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len);
  933. } while (w < 0 && errno == EINTR);
  934. ASSERT(w <= iov[cnt].iov_len);
  935. }
  936. if (w < 0) return check_error(-1, errInfo);
  937. /* Move forward to next buffer to write */
  938. for (; cnt < iovcnt && w > 0; cnt++) {
  939. if (iov[cnt].iov_base && iov[cnt].iov_len > 0) {
  940. if (w < iov[cnt].iov_len) {
  941. /* Adjust the buffer for next write */
  942. iov[cnt].iov_len -= w;
  943. iov[cnt].iov_base += w;
  944. w = 0;
  945. break;
  946. } else {
  947. w -= iov[cnt].iov_len;
  948. }
  949. }
  950. }
  951. ASSERT(w == 0);
  952. } /* else Non-empty buffer */
  953. } /* while (cnt< iovcnt) */
  954. return 1;
  955. }
  956. int
  957. efile_read(Efile_error* errInfo, /* Where to return error codes. */
  958. int flags, /* Flags given when file was opened. */
  959. int fd, /* File descriptor to read from. */
  960. char* buf, /* Buffer to read into. */
  961. size_t count, /* Number of bytes to read. */
  962. size_t *pBytesRead) /* Where to return number of
  963. bytes read. */
  964. {
  965. ssize_t n;
  966. for (;;) {
  967. if ((n = read(fd, buf, count)) >= 0)
  968. break;
  969. else if (errno != EINTR)
  970. return check_error(-1, errInfo);
  971. }
  972. *pBytesRead = (size_t) n;
  973. return 1;
  974. }
  975. /* pread() and pwrite() */
  976. /* Some unix systems, notably Solaris has these syscalls */
  977. /* It is especially nice for i.e. the dets module to have support */
  978. /* for this, even if the underlying OS dosn't support it, it is */
  979. /* reasonably easy to work around by first calling seek, and then */
  980. /* calling read(). */
  981. /* This later strategy however changes the file pointer, which pread() */
  982. /* does not do. We choose to ignore this and say that the location */
  983. /* of the file pointer is undefined after a call to any of the p functions*/
  984. int
  985. efile_pread(Efile_error* errInfo, /* Where to return error codes. */
  986. int fd, /* File descriptor to read from. */
  987. Sint64 offset, /* Offset in bytes from BOF. */
  988. char* buf, /* Buffer to read into. */
  989. size_t count, /* Number of bytes to read. */
  990. size_t *pBytesRead) /* Where to return
  991. number of bytes read. */
  992. {
  993. #if defined(HAVE_PREAD) && defined(HAVE_PWRITE)
  994. ssize_t n;
  995. off_t off = (off_t) offset;
  996. if (off != offset) {
  997. errno = EINVAL;
  998. return check_error(-1, errInfo);
  999. }
  1000. for (;;) {
  1001. if ((n = pread(fd, buf, count, offset)) >= 0)
  1002. break;
  1003. else if (errno != EINTR)
  1004. return check_error(-1, errInfo);
  1005. }
  1006. *pBytesRead = (size_t) n;
  1007. return 1;
  1008. #else
  1009. {
  1010. int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
  1011. if (res) {
  1012. return efile_read(errInfo, 0, fd, buf, count, pBytesRead);
  1013. } else {
  1014. return res;
  1015. }
  1016. }
  1017. #endif
  1018. }
  1019. int
  1020. efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */
  1021. int fd, /* File descriptor to write to. */
  1022. char* buf, /* Buffer to write. */
  1023. size_t count, /* Number of bytes to write. */
  1024. Sint64 offset) /* where to write it */
  1025. {
  1026. #if defined(HAVE_PREAD) && defined(HAVE_PWRITE)
  1027. ssize_t written; /* Bytes written in last operation. */
  1028. off_t off = (off_t) offset;
  1029. if (off != offset) {
  1030. errno = EINVAL;
  1031. return check_error(-1, errInfo);
  1032. }
  1033. while (count > 0) {
  1034. if ((written = pwrite(fd, buf, count, offset)) < 0) {
  1035. if (errno != EINTR)
  1036. return check_error(-1, errInfo);
  1037. else
  1038. written = 0;
  1039. }
  1040. ASSERT(written <= count);
  1041. buf += written;
  1042. count -= written;
  1043. offset += written;
  1044. }
  1045. return 1;
  1046. #else /* For unix systems that don't support pread() and pwrite() */
  1047. {
  1048. int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL);
  1049. if (res) {
  1050. return efile_write(errInfo, 0, fd, buf, count);
  1051. } else {
  1052. return res;
  1053. }
  1054. }
  1055. #endif
  1056. }
  1057. int
  1058. efile_seek(Efile_error* errInfo, /* Where to return error codes. */
  1059. int fd, /* File descriptor to do the seek on. */
  1060. Sint64 offset, /* Offset in bytes from the given
  1061. origin. */
  1062. int origin, /* Origin of seek (SEEK_SET, SEEK_CUR,
  1063. SEEK_END). */
  1064. Sint64 *new_location) /* Resulting new location in file. */
  1065. {
  1066. off_t off, result;
  1067. switch (origin) {
  1068. case EFILE_SEEK_SET: origin = SEEK_SET; break;
  1069. case EFILE_SEEK_CUR: origin = SEEK_CUR; break;
  1070. case EFILE_SEEK_END: origin = SEEK_END; break;
  1071. default:
  1072. errno = EINVAL;
  1073. return check_error(-1, errInfo);
  1074. }
  1075. off = (off_t) offset;
  1076. if (off != offset) {
  1077. errno = EINVAL;
  1078. return check_error(-1, errInfo);
  1079. }
  1080. errno = 0;
  1081. result = lseek(fd, off, origin);
  1082. /*
  1083. * Note that the man page for lseek (on SunOs 5) says:
  1084. *
  1085. * "if fildes is a remote file descriptor and offset is
  1086. * negative, lseek() returns the file pointer even if it is
  1087. * negative."
  1088. */
  1089. if (result < 0 && errno == 0)
  1090. errno = EINVAL;
  1091. if (result < 0)
  1092. return check_error(-1, errInfo);
  1093. if (new_location) {
  1094. *new_location = result;
  1095. }
  1096. return 1;
  1097. }
  1098. int
  1099. efile_truncate_file(Efile_error* errInfo, int *fd, int flags)
  1100. {
  1101. #ifdef VXWORKS
  1102. off_t offset;
  1103. char namebuf[PATH_MAX+1];
  1104. char namebuf2[PATH_MAX+10];
  1105. int new;
  1106. int dummy;
  1107. int i;
  1108. int left;
  1109. static char buff[1024];
  1110. struct stat st;
  1111. Efile_error tmperr;
  1112. if ((offset = lseek(*fd, 0, 1)) < 0) {
  1113. return check_error((int) offset,errInfo);
  1114. }
  1115. if (ftruncate(*fd, offset) < 0) {
  1116. if (vxworks_to_posix(errno) != EINVAL) {
  1117. return check_error(-1, errInfo);
  1118. }
  1119. /*
  1120. ** Kludge
  1121. */
  1122. if(ioctl(*fd,FIOGETNAME,(int) namebuf) < 0) {
  1123. return check_error(-1, errInfo);
  1124. }
  1125. for(i=0;i<1000;++i) {
  1126. sprintf(namebuf2,"%s%d",namebuf,i);
  1127. CHECK_PATHLEN(namebuf2,errInfo);
  1128. if (stat(namebuf2,&st) < 0) {
  1129. break;
  1130. }
  1131. }
  1132. if (i > 1000) {
  1133. errno = EINVAL;
  1134. return check_error(-1, errInfo);
  1135. }
  1136. if (close(*fd) < 0) {
  1137. return check_error(-1, errInfo);
  1138. }
  1139. if (efile_rename(&tmperr,namebuf,namebuf2) < 0) {
  1140. i = check_error(-1,&tmperr);
  1141. if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,
  1142. fd,&dummy)) {
  1143. *fd = -1;
  1144. } else {
  1145. *errInfo = tmperr;
  1146. }
  1147. return i;
  1148. }
  1149. if ((*fd = open(namebuf2, O_RDONLY, 0)) < 0) {
  1150. i = check_error(-1,errInfo);
  1151. efile_rename(&tmperr,namebuf2,namebuf); /* at least try */
  1152. if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,
  1153. fd,&dummy)) {
  1154. *fd = -1;
  1155. } else {
  1156. lseek(*fd,offset,SEEK_SET);
  1157. }
  1158. return i;
  1159. }
  1160. /* Point of no return... */
  1161. if ((new = open(namebuf,O_RDWR | O_CREAT, FILE_MODE)) < 0) {
  1162. close(*fd);
  1163. *fd = -1;
  1164. return 0;
  1165. }
  1166. left = offset;
  1167. while (left) {
  1168. if ((i = read(*fd,buff,(left > 1024) ? 1024 : left)) < 0) {
  1169. i = check_error(-1,errInfo);
  1170. close(new);
  1171. close(*fd);
  1172. unlink(namebuf);
  1173. efile_rename(&tmperr,namebuf2,namebuf); /* at least try */
  1174. if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,
  1175. fd,&dummy)) {
  1176. *fd = -1;
  1177. } else {
  1178. lseek(*fd,offset,SEEK_SET);
  1179. }
  1180. return i;
  1181. }
  1182. left -= i;
  1183. if (write(new,buff,i) < 0) {
  1184. i = check_error(-1,errInfo);
  1185. close(new);
  1186. close(*fd);
  1187. unlink(namebuf);
  1188. rename(namebuf2,namebuf); /* at least try */
  1189. if (!efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,
  1190. fd,&dummy)) {
  1191. *fd = -1;
  1192. } else {
  1193. lseek(*fd,offset,SEEK_SET);
  1194. }
  1195. return i;
  1196. }
  1197. }
  1198. close(*fd);
  1199. unlink(namebuf2);
  1200. close(new);
  1201. i = efile_openfile(errInfo,namebuf,flags | EFILE_NO_TRUNCATE,fd,
  1202. &dummy);
  1203. if (i) {
  1204. lseek(*fd,offset,SEEK_SET);
  1205. }
  1206. return i;
  1207. }
  1208. return 1;
  1209. #else
  1210. #ifndef NO_FTRUNCATE
  1211. off_t offset;
  1212. return check_error((offset = lseek(*fd, 0, 1)) >= 0 &&
  1213. ftruncate(*fd, offset) == 0 ? 1 : -1,
  1214. errInfo);
  1215. #else
  1216. return 1;
  1217. #endif
  1218. #endif
  1219. }
  1220. int
  1221. efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size)
  1222. {
  1223. #ifdef VXWORKS
  1224. return vxworks_enotsup(errInfo);
  1225. #else
  1226. int len;
  1227. ASSERT(size > 0);
  1228. len = readlink(name, buffer, size-1);
  1229. if (len == -1) {
  1230. return check_error(-1, errInfo);
  1231. }
  1232. buffer[len] = '\0';
  1233. return 1;
  1234. #endif
  1235. }
  1236. int
  1237. efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size)
  1238. {
  1239. errno = ENOTSUP;
  1240. return check_error(-1, errInfo);
  1241. }
  1242. int
  1243. efile_link(Efile_error* errInfo, char* old, char* new)
  1244. {
  1245. #ifdef VXWORKS
  1246. return vxworks_enotsup(errInfo);
  1247. #else
  1248. return check_error(link(old, new), errInfo);
  1249. #endif
  1250. }
  1251. int
  1252. efile_symlink(Efile_error* errInfo, char* old, char* new)
  1253. {
  1254. #ifdef VXWORKS
  1255. return vxworks_enotsup(errInfo);
  1256. #else
  1257. return check_error(symlink(old, new), errInfo);
  1258. #endif
  1259. }
  1260. int
  1261. efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
  1262. Sint64 length, int advise)
  1263. {
  1264. #ifdef HAVE_POSIX_FADVISE
  1265. return check_error(posix_fadvise(fd, offset, length, advise), errInfo);
  1266. #else
  1267. return check_error(0, errInfo);
  1268. #endif
  1269. }
  1270. #ifdef HAVE_SENDFILE
  1271. // For some reason the maximum size_t cannot be used as the max size
  1272. // 3GB seems to work on all platforms
  1273. #define SENDFILE_CHUNK_SIZE ((1UL << 30) -1)
  1274. /*
  1275. * sendfile: The implementation of the sendfile system call varies
  1276. * a lot on different *nix platforms so to make the api similar in all
  1277. * we have to emulate some things in linux and play with variables on
  1278. * bsd/darwin.
  1279. *
  1280. * All of the calls will split a command which tries to send more than
  1281. * SENDFILE_CHUNK_SIZE of data at once.
  1282. *
  1283. * On platforms where *nbytes of 0 does not mean the entire file, this is
  1284. * simulated.
  1285. *
  1286. * It could be possible to implement header/trailer in sendfile. Though
  1287. * you would have to emulate it in linux and on BSD/Darwin some complex
  1288. * calculations have to be made when using a non blocking socket to figure
  1289. * out how much of the header/file/trailer was sent in each command.
  1290. */
  1291. int
  1292. efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
  1293. off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl* hdtl)
  1294. {
  1295. Uint64 written = 0;
  1296. #if defined(__linux__)
  1297. ssize_t retval;
  1298. do {
  1299. // check if *nbytes is 0 or greater than chunk size
  1300. if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
  1301. retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE);
  1302. else
  1303. retval = sendfile(out_fd, in_fd, offset, *nbytes);
  1304. if (retval > 0) {
  1305. written += retval;
  1306. *nbytes -= retval;
  1307. }
  1308. } while (retval == SENDFILE_CHUNK_SIZE);
  1309. *nbytes = written;
  1310. return check_error(retval == -1 ? -1 : 0, errInfo);
  1311. #elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV)
  1312. ssize_t retval;
  1313. size_t len;
  1314. sendfilevec_t fdrec;
  1315. fdrec.sfv_fd = in_fd;
  1316. fdrec.sfv_flag = 0;
  1317. do {
  1318. fdrec.sfv_off = *offset;
  1319. len = 0;
  1320. // check if *nbytes is 0 or greater than chunk size
  1321. if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE)
  1322. fdrec.sfv_len = SENDFILE_CHUNK_SIZE;
  1323. else
  1324. fdrec.sfv_len = *nbytes;
  1325. retval = sendfilev(out_fd, &fdrec, 1, &len);
  1326. if (retval != -1 || errno == EAGAIN || errno == EINTR) {
  1327. *offset += len;
  1328. *nbytes -= len;
  1329. written += len;
  1330. }
  1331. } while (len == SENDFILE_CHUNK_SIZE);
  1332. *nbytes = written;
  1333. return check_error(retval == -1 ? -1 : 0, errInfo);
  1334. #elif defined(DARWIN)
  1335. int retval;
  1336. off_t len;
  1337. do {
  1338. // check if *nbytes is 0 or greater than chunk size
  1339. if(*nbytes > SENDFILE_CHUNK_SIZE)
  1340. len = SENDFILE_CHUNK_SIZE;
  1341. else
  1342. len = *nbytes;
  1343. retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
  1344. if (retval != -1 || errno == EAGAIN || errno == EINTR) {
  1345. *offset += len;
  1346. *nbytes -= len;
  1347. written += len;
  1348. }
  1349. } while (len == SENDFILE_CHUNK_SIZE);
  1350. *nbytes = written;
  1351. return check_error(retval, errInfo);
  1352. #elif defined(__FreeBSD__) || defined(__DragonFly__)
  1353. off_t len;
  1354. int retval;
  1355. do {
  1356. if (*nbytes > SENDFILE_CHUNK_SIZE)
  1357. retval = sendfile(in_fd, out_fd, *offset, SENDFILE_CHUNK_SIZE,
  1358. NULL, &len, 0);
  1359. else
  1360. retval = sendfile(in_fd, out_fd, *offset, *nbytes, NULL, &len, 0);
  1361. if (retval != -1 || errno == EAGAIN || errno == EINTR) {
  1362. *offset += len;
  1363. *nbytes -= len;
  1364. written += len;
  1365. }
  1366. } while(len == SENDFILE_CHUNK_SIZE);
  1367. *nbytes = written;
  1368. return check_error(retval, errInfo);
  1369. #endif
  1370. }
  1371. #endif /* HAVE_SENDFILE */