diff options
Diffstat (limited to 'erts/emulator/nifs')
-rw-r--r-- | erts/emulator/nifs/common/prim_file_nif.c | 3 | ||||
-rw-r--r-- | erts/emulator/nifs/common/prim_file_nif.h | 2 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_nif.c | 130 | ||||
-rw-r--r-- | erts/emulator/nifs/unix/unix_prim_file.c | 49 | ||||
-rw-r--r-- | erts/emulator/nifs/win32/win_prim_file.c | 30 |
5 files changed, 129 insertions, 85 deletions
diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c index 3df04e42e2..9e9a14844e 100644 --- a/erts/emulator/nifs/common/prim_file_nif.c +++ b/erts/emulator/nifs/common/prim_file_nif.c @@ -231,6 +231,7 @@ static int load(ErlNifEnv *env, void** priv_data, ERL_NIF_TERM prim_file_pid) am_append = enif_make_atom(env, "append"); am_sync = enif_make_atom(env, "sync"); am_skip_type_check = enif_make_atom(env, "skip_type_check"); + am_directory = enif_make_atom(env, "directory"); am_read_write = enif_make_atom(env, "read_write"); am_none = enif_make_atom(env, "none"); @@ -447,6 +448,8 @@ static enum efile_modes_t efile_translate_modelist(ErlNifEnv *env, ERL_NIF_TERM modes |= EFILE_MODE_SYNC; } else if(enif_is_identical(head, am_skip_type_check)) { modes |= EFILE_MODE_SKIP_TYPE_CHECK; + } else if (enif_is_identical(head, am_directory)) { + modes |= EFILE_MODE_DIRECTORY; } else { /* Modes like 'raw', 'ram', 'delayed_writes' etc are handled * further up the chain. */ diff --git a/erts/emulator/nifs/common/prim_file_nif.h b/erts/emulator/nifs/common/prim_file_nif.h index b2e30c59dd..020714a03b 100644 --- a/erts/emulator/nifs/common/prim_file_nif.h +++ b/erts/emulator/nifs/common/prim_file_nif.h @@ -30,6 +30,8 @@ enum efile_modes_t { EFILE_MODE_SKIP_TYPE_CHECK = (1 << 5), /* Special for device files on Unix. */ EFILE_MODE_NO_TRUNCATE = (1 << 6), /* Special for reopening on VxWorks. */ + EFILE_MODE_DIRECTORY = (1 << 7), + EFILE_MODE_READ_WRITE = EFILE_MODE_READ | EFILE_MODE_WRITE }; diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index 211f21cb40..7ab712530c 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -1077,10 +1077,10 @@ static ERL_NIF_TERM nconnect(ErlNifEnv* env, static ERL_NIF_TERM nlisten(ErlNifEnv* env, ESockDescriptor* descP, int backlog); -static ERL_NIF_TERM naccept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref); +static ERL_NIF_TERM naccept_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM ref); static ERL_NIF_TERM naccept_listening(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sockRef, @@ -1144,31 +1144,31 @@ static ERL_NIF_TERM nsendto(ErlNifEnv* env, int flags, ESockAddress* toAddrP, unsigned int toAddrLen); -static ERL_NIF_TERM nsendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsgHdr, - int flags); +static ERL_NIF_TERM nsendmsg_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsgHdr, + int flags); static ERL_NIF_TERM nrecv(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM sendRef, ERL_NIF_TERM recvRef, int len, int flags); -static ERL_NIF_TERM nrecvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - Uint16 bufSz, - int flags); -static ERL_NIF_TERM nrecvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - Uint16 bufLen, - Uint16 ctrlLen, - int flags); +static ERL_NIF_TERM nrecvfrom_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + Uint16 bufSz, + int flags); +static ERL_NIF_TERM nrecvmsg_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + Uint16 bufLen, + Uint16 ctrlLen, + int flags); static ERL_NIF_TERM nclose(ErlNifEnv* env, ESockDescriptor* descP); static BOOLEAN_T nclose_check(ErlNifEnv* env, @@ -5677,7 +5677,7 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, descP->currentAcceptor.env, descP->currentAcceptor.ref) ); - res = naccept(env, descP, sockRef, ref); + res = naccept_erts(env, descP, sockRef, ref); MUNLOCK(descP->accMtx); @@ -5689,10 +5689,10 @@ ERL_NIF_TERM nif_accept(ErlNifEnv* env, #if !defined(__WIN32__) static -ERL_NIF_TERM naccept(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM ref) +ERL_NIF_TERM naccept_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM ref) { ERL_NIF_TERM res; @@ -6489,7 +6489,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, MLOCK(descP->writeMtx); - res = nsendmsg(env, descP, sockRef, sendRef, eMsgHdr, flags); + res = nsendmsg_erts(env, descP, sockRef, sendRef, eMsgHdr, flags); MUNLOCK(descP->writeMtx); @@ -6506,12 +6506,12 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env, #if !defined(__WIN32__) static -ERL_NIF_TERM nsendmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM sendRef, - ERL_NIF_TERM eMsgHdr, - int flags) +ERL_NIF_TERM nsendmsg_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM sendRef, + ERL_NIF_TERM eMsgHdr, + int flags) { ERL_NIF_TERM res, eAddr, eIOV, eCtrl; ESockAddress addr; @@ -6540,7 +6540,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env, /* We don't need the address */ - SSDBG( descP, ("SOCKET", "nsendmsg -> connected: no address\r\n") ); + SSDBG( descP, ("SOCKET", "nsendmsg_erts -> connected: no address\r\n") ); msgHdr.msg_name = NULL; msgHdr.msg_namelen = 0; @@ -6555,7 +6555,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env, if (!GET_MAP_VAL(env, eMsgHdr, esock_atom_addr, &eAddr)) return esock_make_error(env, esock_atom_einval); - SSDBG( descP, ("SOCKET", "nsendmsg -> not connected: " + SSDBG( descP, ("SOCKET", "nsendmsg_erts -> not connected: " "\r\n address: %T" "\r\n", eAddr) ); @@ -6575,7 +6575,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env, if (!GET_LIST_LEN(env, eIOV, &iovLen) && (iovLen > 0)) return esock_make_error(env, esock_atom_einval); - SSDBG( descP, ("SOCKET", "nsendmsg -> iov length: %d\r\n", iovLen) ); + SSDBG( descP, ("SOCKET", "nsendmsg_erts -> iov length: %d\r\n", iovLen) ); iovBins = MALLOC(iovLen * sizeof(ErlNifBinary)); ESOCK_ASSERT( (iovBins != NULL) ); @@ -6593,7 +6593,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env, ctrlBufLen = 0; ctrlBuf = NULL; } - SSDBG( descP, ("SOCKET", "nsendmsg -> optional ctrl: " + SSDBG( descP, ("SOCKET", "nsendmsg_erts -> optional ctrl: " "\r\n ctrlBuf: 0x%lX" "\r\n ctrlBufLen: %d" "\r\n eCtrl: %T\r\n", ctrlBuf, ctrlBufLen, eCtrl) ); @@ -6611,7 +6611,7 @@ ERL_NIF_TERM nsendmsg(ErlNifEnv* env, SSDBG( descP, ("SOCKET", - "nsendmsg -> total (iov) data size: %d\r\n", dataSize) ); + "nsendmsg_erts -> total (iov) data size: %d\r\n", dataSize) ); /* Decode the ctrl and initiate that part of the msghdr. @@ -6951,7 +6951,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, * </KOLLA> */ - res = nrecvfrom(env, descP, sockRef, recvRef, bufSz, flags); + res = nrecvfrom_erts(env, descP, sockRef, recvRef, bufSz, flags); MUNLOCK(descP->readMtx); @@ -6967,12 +6967,12 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, */ #if !defined(__WIN32__) static -ERL_NIF_TERM nrecvfrom(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - Uint16 len, - int flags) +ERL_NIF_TERM nrecvfrom_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + Uint16 len, + int flags) { ESockAddress fromAddr; unsigned int addrLen; @@ -6982,7 +6982,7 @@ ERL_NIF_TERM nrecvfrom(ErlNifEnv* env, ERL_NIF_TERM readerCheck; int bufSz = (len ? len : descP->rBufSz); - SSDBG( descP, ("SOCKET", "nrecvfrom -> entry with" + SSDBG( descP, ("SOCKET", "nrecvfrom_erts -> entry with" "\r\n len: %d (%d)" "\r\n flags: %d" "\r\n", len, bufSz, flags) ); @@ -7121,7 +7121,7 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, * </KOLLA> */ - res = nrecvmsg(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); + res = nrecvmsg_erts(env, descP, sockRef, recvRef, bufSz, ctrlSz, flags); MUNLOCK(descP->readMtx); @@ -7137,13 +7137,13 @@ ERL_NIF_TERM nif_recvmsg(ErlNifEnv* env, */ #if !defined(__WIN32__) static -ERL_NIF_TERM nrecvmsg(ErlNifEnv* env, - ESockDescriptor* descP, - ERL_NIF_TERM sockRef, - ERL_NIF_TERM recvRef, - Uint16 bufLen, - Uint16 ctrlLen, - int flags) +ERL_NIF_TERM nrecvmsg_erts(ErlNifEnv* env, + ESockDescriptor* descP, + ERL_NIF_TERM sockRef, + ERL_NIF_TERM recvRef, + Uint16 bufLen, + Uint16 ctrlLen, + int flags) { unsigned int addrLen; ssize_t read; @@ -7157,7 +7157,7 @@ ERL_NIF_TERM nrecvmsg(ErlNifEnv* env, ERL_NIF_TERM readerCheck; ESockAddress addr; - SSDBG( descP, ("SOCKET", "nrecvmsg -> entry with" + SSDBG( descP, ("SOCKET", "nrecvmsg_erts -> entry with" "\r\n bufSz: %d (%d)" "\r\n ctrlSz: %d (%d)" "\r\n flags: %d" @@ -9721,8 +9721,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_addrform(ErlNifEnv* env, domain) ); res = socket_setopt(descP->sock, - SOL_IPV6, IPV6_ADDRFORM, - &domain, sizeof(domain)); +#if defined(SOL_IPV6) + SOL_IPV6, +#else + IPPROTO_IPV6, +#endif + IPV6_ADDRFORM, &domain, sizeof(domain)); if (res != 0) result = esock_make_error_errno(env, sock_errno()); @@ -9752,7 +9756,13 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_authhdr(ErlNifEnv* env, ESockDescriptor* descP, ERL_NIF_TERM eVal) { - return nsetopt_bool_opt(env, descP, SOL_IPV6, IPV6_AUTHHDR, eVal); + return nsetopt_bool_opt(env, descP, +#if defined(SOL_IPV6) + SOL_IPV6, +#else + IPPROTO_IPV6, +#endif + IPV6_AUTHHDR, eVal); } #endif diff --git a/erts/emulator/nifs/unix/unix_prim_file.c b/erts/emulator/nifs/unix/unix_prim_file.c index 169b193993..20021b9358 100644 --- a/erts/emulator/nifs/unix/unix_prim_file.c +++ b/erts/emulator/nifs/unix/unix_prim_file.c @@ -107,7 +107,7 @@ ERL_NIF_TERM efile_get_handle(ErlNifEnv *env, efile_data_t *d) { return result; } -static int open_file_type_check(const efile_path_t *path, int fd) { +static int open_file_is_dir(const efile_path_t *path, int fd) { struct stat file_info; int error; @@ -119,27 +119,14 @@ static int open_file_type_check(const efile_path_t *path, int fd) { (void)path; #endif - if(error < 0) { - /* If we failed to stat assume success and let the next call handle the - * error. The old driver checked whether the file was to be used - * immediately in a read within the call, but the new implementation - * never does that. */ - return 1; - } - - /* Allow everything that isn't a directory, and error out on the next call - * if it's unsupported. */ - if(S_ISDIR(file_info.st_mode)) { - return 0; - } - - return 1; + /* Assume not a directory on error. */ + return error == 0 && S_ISDIR(file_info.st_mode); } posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, ErlNifResourceType *nif_type, efile_data_t **d) { - int flags, fd; + int mode, flags, fd; flags = 0; @@ -174,18 +161,38 @@ posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, #endif } + if(modes & EFILE_MODE_DIRECTORY) { + mode = DIR_MODE; +#ifdef O_DIRECTORY + flags |= O_DIRECTORY; +#endif + } else { + mode = FILE_MODE; + } + do { - fd = open((const char*)path->data, flags, FILE_MODE); + fd = open((const char*)path->data, flags, mode); } while(fd == -1 && errno == EINTR); if(fd != -1) { efile_unix_t *u; - if(!(modes & EFILE_MODE_SKIP_TYPE_CHECK) && !open_file_type_check(path, fd)) { +#ifndef O_DIRECTORY + /* On platforms without O_DIRECTORY support, ensure that using the + * directory flag to open a file fails. */ + if(!(modes & EFILE_MODE_SKIP_TYPE_CHECK) && + (modes & EFILE_MODE_DIRECTORY) && !open_file_is_dir(path, fd)) { close(fd); + return ENOTDIR; + } +#endif - /* This is blatantly incorrect, but we're documented as returning - * this for everything that isn't a file. */ + /* open() works on directories without the O_DIRECTORY flag but for + * consistency across platforms we require that the user has requested + * directory mode. */ + if(!(modes & EFILE_MODE_SKIP_TYPE_CHECK) && + !(modes & EFILE_MODE_DIRECTORY) && open_file_is_dir(path, fd)) { + close(fd); return EISDIR; } diff --git a/erts/emulator/nifs/win32/win_prim_file.c b/erts/emulator/nifs/win32/win_prim_file.c index e7d3924240..13306104c0 100644 --- a/erts/emulator/nifs/win32/win_prim_file.c +++ b/erts/emulator/nifs/win32/win_prim_file.c @@ -270,6 +270,17 @@ static int normalize_path_result(ErlNifBinary *path) { } /* @brief Checks whether all the given attributes are set on the object at the + * given handle. Note that it assumes false on errors. */ +static int handle_has_file_attributes(HANDLE handle, DWORD mask) { + BY_HANDLE_FILE_INFORMATION native_file_info; + if(!GetFileInformationByHandle(handle, &native_file_info)) { + return 0; + } + + return !!((native_file_info.dwFileAttributes & mask) == mask); +} + +/* @brief Checks whether all the given attributes are set on the object at the * given path. Note that it assumes false on errors. */ static int has_file_attributes(const efile_path_t *path, DWORD mask) { DWORD attributes = GetFileAttributesW((WCHAR*)path->data); @@ -412,10 +423,15 @@ posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, ASSERT_PATH_FORMAT(path); + attributes = 0; access_flags = 0; open_mode = 0; - if(modes & EFILE_MODE_READ && !(modes & EFILE_MODE_WRITE)) { + if(modes & EFILE_MODE_DIRECTORY) { + attributes = FILE_FLAG_BACKUP_SEMANTICS; + access_flags = GENERIC_READ; + open_mode = OPEN_EXISTING; + } else if(modes & EFILE_MODE_READ && !(modes & EFILE_MODE_WRITE)) { access_flags = GENERIC_READ; open_mode = OPEN_EXISTING; } else if(modes & EFILE_MODE_WRITE && !(modes & EFILE_MODE_READ)) { @@ -438,9 +454,9 @@ posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, } if(modes & EFILE_MODE_SYNC) { - attributes = FILE_FLAG_WRITE_THROUGH; + attributes |= FILE_FLAG_WRITE_THROUGH; } else { - attributes = FILE_ATTRIBUTE_NORMAL; + attributes |= FILE_ATTRIBUTE_NORMAL; } handle = CreateFileW((WCHAR*)path->data, access_flags, @@ -449,6 +465,12 @@ posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, if(handle != INVALID_HANDLE_VALUE) { efile_win_t *w; + /* Directory mode specified, but path is not a directory. */ + if((modes & EFILE_MODE_DIRECTORY) && !handle_has_file_attributes(handle, FILE_ATTRIBUTE_DIRECTORY)) { + CloseHandle(handle); + return ENOTDIR; + } + w = (efile_win_t*)enif_alloc_resource(nif_type, sizeof(efile_win_t)); w->handle = handle; @@ -461,7 +483,7 @@ posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes, /* Rewrite all failures on directories to EISDIR to match the old * driver. */ - if(has_file_attributes(path, FILE_ATTRIBUTE_DIRECTORY)) { + if(!(modes & EFILE_MODE_DIRECTORY) && has_file_attributes(path, FILE_ATTRIBUTE_DIRECTORY)) { return EISDIR; } |