unix_efile.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,511 行 · 第 1/3 页
C
1,511 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Purpose: Provides file and directory operations for Unix. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include "erl_driver.h"#include "erl_efile.h"#include <utime.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_SYS_UIO_H#include <sys/types.h>#include <sys/uio.h>#endif#ifdef _OSE_#include "efs.h"#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#ifdef _OSE_SFK_#include <string.h>#endif#endif /* _OSE_ */#ifdef VXWORKS#include <ioLib.h>#include <dosFsLib.h>#include <nfsLib.h>#include <sys/stat.h>/*** Not nice to include usrLib.h as MANY normal variable names get reported** as shadowing globals, like 'i' for example.** Instead we declare the only function we use here*//* * #include <usrLib.h> */extern STATUS copy(char *, char *);#include <errno.h>#else /* UNIX */# if defined(HAVE_FCNTL_H) && defined(HAVE_F_DUPFD)# include <fcntl.h> static int try_dup = -1;# if defined(NO_SYSCONF)# include <sys/param.h># define MAX_FILES() NOFILE# else# define MAX_FILES() sysconf(_SC_OPEN_MAX)# endif# endif#endif /* !VXWORKS */#ifdef SUNOS4# define getcwd(buf, size) getwd(buf)#endif/* Find a definition of MAXIOV, that is used in the code later. */#if defined IOV_MAX#define MAXIOV IOV_MAX#elif defined UIO_MAXIOV#define MAXIOV UIO_MAXIOV#else#define MAXIOV 16#endif/* * Macros for testing file types. */#ifdef _OSE_#define ISDIR(st) S_ISDIR(((st).st_mode))#define ISREG(st) S_ISREG(((st).st_mode))#define ISDEV(st) (S_ISCHR(((st).st_mode)) || S_ISBLK(((st).st_mode)))#define ISLNK(st) S_ISLNK(((st).st_mode))#ifdef NO_UMASK#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)#define DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)#else#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)#define DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | \ S_IWOTH | S_IXOTH)#endif #else /* !_OSE_ */#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR)#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG)#define ISDEV(st) \ (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK)#ifdef NO_UMASK#define FILE_MODE 0644#define DIR_MODE 0755#else#define FILE_MODE 0666#define DIR_MODE 0777#endif#endif /* _OSE_ */#ifdef VXWORKS /* Currently only used on vxworks */#define EF_ALLOC(S) driver_alloc((S))#define EF_REALLOC(P, S) driver_realloc((P), (S))#define EF_SAFE_ALLOC(S) ef_safe_alloc((S))#define EF_SAFE_REALLOC(P, S) ef_safe_realloc((P), (S))#define EF_FREE(P) do { if((P)) driver_free((P)); } while(0)extern void erl_exit(int n, char *fmt, _DOTS_);static void *ef_safe_alloc(Uint s){ void *p = EF_ALLOC(s); if (!p) erl_exit(1, "unix efile drv: Can't allocate %d bytes of memory\n", s); return p;}#if 0 /* Currently not used */static void *ef_safe_realloc(void *op, Uint s){ void *p = EF_REALLOC(op, s); if (!p) erl_exit(1, "unix efile drv: Can't reallocate %d bytes of memory\n", s); return p;}#endif /* #if 0 */#endif /* #ifdef VXWORKS */#define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')))#ifdef VXWORKSstatic FUNCTION(int, vxworks_to_posix, (int vx_errno));#endif/*** VxWorks (not) strikes again. Too long RESULTING paths** may give the infamous bus error. Have to check ALL** filenames and pathnames. No wonder the emulator is slow on** these cards...*/#ifdef VXWORKS#define CHECK_PATHLEN(Name, ErrInfo) \ if (path_size(Name) > PATH_MAX) { \ errno = ENAMETOOLONG; \ return check_error(-1, ErrInfo); \ }#else#define CHECK_PATHLEN(X,Y) /* Nothing */#endifstatic FUNCTION(int, check_error, (int result, Efile_error* errInfo));static intcheck_error(int result, Efile_error *errInfo){ if (result < 0) {#ifdef VXWORKS errInfo->posix_errno = errInfo->os_errno = vxworks_to_posix(errno);#else errInfo->posix_errno = errInfo->os_errno = errno;#endif return 0; } return 1;}#ifdef VXWORKS/* * VxWorks has different error codes for different file systems. * We map those to POSIX ones. */static intvxworks_to_posix(int vx_errno){ DEBUGF(("[vxworks_to_posix] vx_errno: %08x\n", vx_errno)); switch (vx_errno) { /* dosFsLib mapping */#ifdef S_dosFsLib_FILE_ALREADY_EXISTS case S_dosFsLib_FILE_ALREADY_EXISTS: return EEXIST;#else case S_dosFsLib_FILE_EXISTS: return EEXIST;#endif#ifdef S_dosFsLib_BAD_DISK case S_dosFsLib_BAD_DISK: return EIO;#endif#ifdef S_dosFsLib_CANT_CHANGE_ROOT case S_dosFsLib_CANT_CHANGE_ROOT: return EINVAL;#endif#ifdef S_dosFsLib_NO_BLOCK_DEVICE case S_dosFsLib_NO_BLOCK_DEVICE: return ENOTBLK;#endif#ifdef S_dosFsLib_BAD_SEEK case S_dosFsLib_BAD_SEEK: return ESPIPE;#endif case S_dosFsLib_VOLUME_NOT_AVAILABLE: return ENXIO; case S_dosFsLib_DISK_FULL: return ENOSPC; case S_dosFsLib_FILE_NOT_FOUND: return ENOENT; case S_dosFsLib_NO_FREE_FILE_DESCRIPTORS: return ENFILE; case S_dosFsLib_INVALID_NUMBER_OF_BYTES: return EINVAL; case S_dosFsLib_ILLEGAL_NAME: return EINVAL; case S_dosFsLib_CANT_DEL_ROOT: return EACCES; case S_dosFsLib_NOT_FILE: return EISDIR; case S_dosFsLib_NOT_DIRECTORY: return ENOTDIR; case S_dosFsLib_NOT_SAME_VOLUME: return EXDEV; case S_dosFsLib_READ_ONLY: return EACCES; case S_dosFsLib_ROOT_DIR_FULL: return ENOSPC; case S_dosFsLib_DIR_NOT_EMPTY: return EEXIST; case S_dosFsLib_NO_LABEL: return ENXIO; case S_dosFsLib_INVALID_PARAMETER: return EINVAL; case S_dosFsLib_NO_CONTIG_SPACE: return ENOSPC; case S_dosFsLib_FD_OBSOLETE: return EBADF; case S_dosFsLib_DELETED: return EINVAL; case S_dosFsLib_INTERNAL_ERROR: return EIO; case S_dosFsLib_WRITE_ONLY: return EACCES; /* nfsLib mapping - is needed since Windriver has used */ /* inconsistent error codes (errno.h/nfsLib.h). */ case S_nfsLib_NFS_OK: return 0; case S_nfsLib_NFSERR_PERM: return EPERM; case S_nfsLib_NFSERR_NOENT: return ENOENT; case S_nfsLib_NFSERR_IO: return EIO; case S_nfsLib_NFSERR_NXIO: return ENXIO; case S_nfsLib_NFSERR_ACCES: return EACCES; case S_nfsLib_NFSERR_EXIST: return EEXIST; case S_nfsLib_NFSERR_NODEV: return ENODEV; case S_nfsLib_NFSERR_NOTDIR: return ENOTDIR; case S_nfsLib_NFSERR_ISDIR: return EISDIR; case S_nfsLib_NFSERR_FBIG: return EFBIG; case S_nfsLib_NFSERR_NOSPC: return ENOSPC; case S_nfsLib_NFSERR_ROFS: return EROFS; case S_nfsLib_NFSERR_NAMETOOLONG: return ENAMETOOLONG; case S_nfsLib_NFSERR_NOTEMPTY: return EEXIST; case S_nfsLib_NFSERR_DQUOT: return ENOSPC; case S_nfsLib_NFSERR_STALE: return EINVAL; case S_nfsLib_NFSERR_WFLUSH: return ENXIO; /* And sometimes (...) the error codes are from ioLib (as in the */ /* case of the (for nfsLib) unimplemented rename function) */ case S_ioLib_NO_DRIVER: return ENXIO; case S_ioLib_UNKNOWN_REQUEST: return ENOSYS; case S_ioLib_DEVICE_ERROR: return ENXIO; case S_ioLib_DEVICE_TIMEOUT: return EIO; case S_ioLib_WRITE_PROTECTED: return EACCES; case S_ioLib_DISK_NOT_PRESENT: return EIO; case S_ioLib_NO_FILENAME: return EINVAL; case S_ioLib_CANCELLED: return EINTR; case S_ioLib_NO_DEVICE_NAME_IN_PATH: return EINVAL; case S_ioLib_NAME_TOO_LONG: return ENAMETOOLONG;#ifdef S_ioLib_UNFORMATED /* Added (VxWorks 5.2 -> 5.3.1) */ case S_ioLib_UNFORMATED: return EIO;#endif#ifdef S_objLib_OBJ_UNAVAILABLE case S_objLib_OBJ_UNAVAILABLE: return ENOENT;#endif /* Temporary workaround for a weird error in passFs (VxWorks Simsparc only). File operation fails because of ENOENT, but errno is not set. */#ifdef SIMSPARCSOLARIS case 0: return ENOENT;#endif } /* If the error code matches none of the above, assume */ /* it is a POSIX one already. The upper bits (>=16) are */ /* cleared since VxWorks uses those bits to indicate in */ /* what module the error occured. */ return vx_errno & 0xffff;}static int vxworks_enotsup(Efile_error *errInfo) { errInfo->posix_errno = errInfo->os_errno = ENOTSUP; return 0;}static int count_path_length(char *pathname, char *pathname2){ static int stack[PATH_MAX / 2 + 1]; int sp = 0; char *tmp; char *cpy = NULL; int i; int sum; for(i = 0;i < 2;++i) { if (!i) { cpy = EF_SAFE_ALLOC(strlen(pathname)+1); strcpy(cpy, pathname); } else if (pathname2 != NULL) { EF_FREE(cpy); cpy = EF_SAFE_ALLOC(strlen(pathname2)+1); strcpy(cpy, pathname2); } else break; for (tmp = strtok(cpy,"/"); tmp != NULL; tmp = strtok(NULL,"/")) { if (!strcmp(tmp,"..") && sp > 0) --sp; else if (strcmp(tmp,".")) stack[sp++] = strlen(tmp); } } if (cpy != NULL) EF_FREE(cpy); sum = 0; for(i = 0;i < sp; ++i) sum += stack[i]+1; return (sum) ? sum : 1;}static int path_size(char *pathname) { static char currdir[PATH_MAX+2]; if (*pathname == '/') return count_path_length(pathname,NULL); ioDefPathGet(currdir); strcat(currdir,"/"); return count_path_length(currdir,pathname);} #endif /* VXWORKS */#ifdef _OSE_static int ose_enotsup(Efile_error *errInfo) { errInfo->posix_errno = errInfo->os_errno = ENOTSUP; return 0;}#endif /* _OSE_ */intefile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */{ CHECK_PATHLEN(name,errInfo);#ifdef NO_MKDIR_MODE#ifdef VXWORKS /* This is a VxWorks/nfs workaround for erl_tar to create * non-existant directories. (of some reason (...) VxWorks * returns, the *non-module-prefixed*, 0xd code when * trying to create a directory in a directory that doesn't exist). * (see efile_openfile) */ if (mkdir(name) < 0) { struct stat sb; if (name[0] == '\0') { /* Return the correct error code enoent */ errno = S_nfsLib_NFSERR_NOENT; } else if (stat(name, &sb) == OK) { errno = S_nfsLib_NFSERR_EXIST; } else if((strchr(name, '/') != NULL) && (errno == 0xd)) { /* Return the correct error code enoent */ errno = S_nfsLib_NFSERR_NOENT; } return check_error(-1, errInfo); } else return 1;#else return check_error(mkdir(name), errInfo);#endif#else return check_error(mkdir(name, DIR_MODE), errInfo);#endif}intefile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to delete. */{ CHECK_PATHLEN(name, errInfo); if (rmdir(name) == 0) { return 1; }#ifdef VXWORKS if (name[0] == '\0') { /* Return the correct error code enoent */ errno = S_nfsLib_NFSERR_NOENT; }#else if (errno == ENOTEMPTY) { errno = EEXIST; } if (errno == EEXIST) { int saved_errno = errno; struct stat file_stat; struct stat cwd_stat; /* * The error code might be wrong if this is the current directory. */ if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && file_stat.st_ino == cwd_stat.st_ino && file_stat.st_dev == cwd_stat.st_dev) { saved_errno = EINVAL; } errno = saved_errno; }#endif return check_error(-1, errInfo);}intefile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of file to delete. */{ CHECK_PATHLEN(name,errInfo);#ifdef _OSE_ if (remove(name) == 0) { return 1; }#else if (unlink(name) == 0) { return 1; } if (errno == EISDIR) { /* Linux sets the wrong error code. */ errno = EPERM; }#endif return check_error(-1, errInfo);}/* *--------------------------------------------------------------------------- * * Changes the name of an existing file or directory, from src to dst. * If src and dst refer to the same file or directory, does nothing * and returns success. Otherwise if dst already exists, it will be * deleted and replaced by src subject to the following conditions: * If src is a directory, dst may be an empty directory. * If src is a file, dst may be a file. * In any other situation where dst already exists, the rename will * fail. * * Results: * If the directory was successfully created, returns 1. * Otherwise the return value is 0 and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. * ENOENT: src doesn't exist, or src or dst is "". * ENOTDIR: src is a directory, but dst is not. * EXDEV: src and dst are on different filesystems. * * Side effects: * The implementation of rename may allow cross-filesystem renames, * but the caller should be prepared to emulate it with copy and * delete if errno is EXDEV. * *--------------------------------------------------------------------------- */intefile_rename(Efile_error* errInfo, /* Where to return error codes. */ char* src, /* Original name. */ char* dst) /* New name. */{ CHECK_PATHLEN(src,errInfo); CHECK_PATHLEN(dst,errInfo);#ifdef VXWORKS /* First check if src == dst, if so, just return. */ /* VxWorks dos file system destroys the file otherwise, */ /* VxWorks nfs file system rename doesn't work at all. */ if(strcmp(src, dst) == 0) return 1;#endif if (rename(src, dst) == 0) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?