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 + -
显示快捷键?