diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 1178c203c..0fe6b7947 100755 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -295,3 +295,6 @@ configuration variable CONFIG_USER_ENTRYPOINT that may be used to change the default entry from user_start to some other symbol. Contributed by Kate. + * apps/netutils/webserver/httpd/c: Fix a typo that as introduced in + version r4402: 'lese' instead of 'else' (Noted by Max Holtzberg). + diff --git a/apps/netutils/webserver/httpd.c b/apps/netutils/webserver/httpd.c index 0d8386bc5..434cfec5a 100644 --- a/apps/netutils/webserver/httpd.c +++ b/apps/netutils/webserver/httpd.c @@ -380,7 +380,7 @@ static inline int httpd_cmd(struct httpd_state *pstate) ndbg("[%d] recv failed: %d\n", pstate->ht_sockfd, errno); return ERROR; } - lese if (recvlen == 0) + else if (recvlen == 0) { ndbg("[%d] connection lost\n", pstate->ht_sockfd); return ERROR; diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 9cf8f14be..3e17ffe7c 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3224,4 +3224,14 @@ * sched/os_bring.c, configs/*/defconfig, tools/mkconfig.c, and others: Added configuration variable CONFIG_USER_ENTRYPOINT that may be used to change the default entry from user_start to some other symbol. Contributed by - Kate. + Kate. NOTE: This change does introduce a minor backward incompatibility. + For example, if your application uses NSH as its start-up program, then your + code will not fail because it will be unable to find "user_start". The fix + for this link failure is to add the following to your configuration file: + CONFIG_USER_ENTRYPOINT="nsh_main". + * libs/stdio/lib_libfread.c and lib_*flush*.c: Correct a couple of + error cases where the lib semaphore was not be released on error + exits (thanks Ronen Vainish). Also, improved some error reporting: + the generic ERROR was being used instead of the specific errno + value; the errno variable was not always set correctly. + diff --git a/nuttx/lib/stdio/lib_fflush.c b/nuttx/lib/stdio/lib_fflush.c index e0278d0d2..d0b5e0185 100644 --- a/nuttx/lib/stdio/lib_fflush.c +++ b/nuttx/lib/stdio/lib_fflush.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fflush.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -97,22 +97,36 @@ int fflush(FAR FILE *stream) { + int ret; + /* Is the stream argument NULL? */ if (!stream) { /* Yes... then this is a request to flush all streams */ - return lib_flushall(sched_getstreams()); + ret = lib_flushall(sched_getstreams()); } - else if (lib_fflush(stream, true) != 0) + else { - /* An error occurred during the flush AND/OR we were unable to flush all - * of the buffered write data. Return EOF on failure. + ret = lib_fflush(stream, true); + } + + /* Check the return value */ + + if (ret < 0) + { + /* An error occurred during the flush AND/OR we were unable to flush + * all of the buffered write data. Set the errno value. */ + set_errno(-ret); + + /* And return EOF on failure. */ + return EOF; } + return OK; } diff --git a/nuttx/lib/stdio/lib_fgetc.c b/nuttx/lib/stdio/lib_fgetc.c index 4e521e840..4b3d0ec44 100644 --- a/nuttx/lib/stdio/lib_fgetc.c +++ b/nuttx/lib/stdio/lib_fgetc.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fgetc.c * * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fgetpos.c b/nuttx/lib/stdio/lib_fgetpos.c index af07f7387..e9e9f4d10 100644 --- a/nuttx/lib/stdio/lib_fgetpos.c +++ b/nuttx/lib/stdio/lib_fgetpos.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fgetpos.c * * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fileno.c b/nuttx/lib/stdio/lib_fileno.c index ec25ce6d0..ff18cc33d 100644 --- a/nuttx/lib/stdio/lib_fileno.c +++ b/nuttx/lib/stdio/lib_fileno.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fileno.c * * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fread.c b/nuttx/lib/stdio/lib_fread.c index cc652fab7..4a4b29256 100644 --- a/nuttx/lib/stdio/lib_fread.c +++ b/nuttx/lib/stdio/lib_fread.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fread.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fseek.c b/nuttx/lib/stdio/lib_fseek.c index a68de79fe..7380f83b3 100644 --- a/nuttx/lib/stdio/lib_fseek.c +++ b/nuttx/lib/stdio/lib_fseek.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fseek.c * * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fsetpos.c b/nuttx/lib/stdio/lib_fsetpos.c index ad3e67230..13d556521 100644 --- a/nuttx/lib/stdio/lib_fsetpos.c +++ b/nuttx/lib/stdio/lib_fsetpos.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fsetpos.c * * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_ftell.c b/nuttx/lib/stdio/lib_ftell.c index cd0e48368..947648152 100644 --- a/nuttx/lib/stdio/lib_ftell.c +++ b/nuttx/lib/stdio/lib_ftell.c @@ -2,7 +2,7 @@ * lib/stdio/lib_ftell.c * * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_fwrite.c b/nuttx/lib/stdio/lib_fwrite.c index 1b7be2ce5..60e001746 100644 --- a/nuttx/lib/stdio/lib_fwrite.c +++ b/nuttx/lib/stdio/lib_fwrite.c @@ -2,7 +2,7 @@ * lib/stdio/lib_fwrite.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_libfflush.c b/nuttx/lib/stdio/lib_libfflush.c index fb5a8768e..c2b887b2e 100644 --- a/nuttx/lib/stdio/lib_libfflush.c +++ b/nuttx/lib/stdio/lib_libfflush.c @@ -98,8 +98,8 @@ * bforce - flush must be complete. * * Return: - * ERROR on failure, otherwise the number of bytes remaining in the buffer. - * If bforce is set, then only the values ERROR and 0 will be returned. + * A negated errno value on failure, otherwise the number of bytes remaining + * in the buffer. * ****************************************************************************/ @@ -109,13 +109,13 @@ ssize_t lib_fflush(FAR FILE *stream, bool bforce) FAR const unsigned char *src; ssize_t bytes_written; ssize_t nbuffer; + int ret; /* Return EBADF if the file is not opened for writing */ if (stream->fs_filedes < 0 || (stream->fs_oflags & O_WROK) == 0) { - set_errno(EBADF); - return ERROR; + return -EBADF; } /* Make sure that we have exclusive access to the stream */ @@ -132,8 +132,11 @@ ssize_t lib_fflush(FAR FILE *stream, bool bforce) if (stream->fs_bufread != stream->fs_bufstart) { - /* The buffer holds read data... just return zero */ + /* The buffer holds read data... just return zero meaning "no bytes + * remaining in the buffer." + */ + lib_give_semaphore(stream); return 0; } @@ -151,8 +154,12 @@ ssize_t lib_fflush(FAR FILE *stream, bool bforce) bytes_written = write(stream->fs_filedes, src, nbuffer); if (bytes_written < 0) { + /* Write failed. The cause of the failure is in 'errno'. + * returned the negated errno value. + */ + lib_give_semaphore(stream); - return ERROR; + return -get_errno(); } /* Handle partial writes. fflush() must either return with diff --git a/nuttx/lib/stdio/lib_libflushall.c b/nuttx/lib/stdio/lib_libflushall.c index 8de0c3309..9d0a89e9c 100644 --- a/nuttx/lib/stdio/lib_libflushall.c +++ b/nuttx/lib/stdio/lib_libflushall.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_libflushall.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -91,7 +91,7 @@ int lib_flushall(FAR struct streamlist *list) { int lasterrno = OK; - int ret = OK; + int ret; /* Make sure that there are streams associated with this thread */ @@ -115,25 +115,23 @@ int lib_flushall(FAR struct streamlist *list) { /* Flush the writable FILE */ - if (lib_fflush(stream, true) != 0) + ret = lib_fflush(stream, true); + if (ret < 0) { /* An error occurred during the flush AND/OR we were unable - * to flush all of the buffered write data. Return EOF on failure. + * to flush all of the buffered write data. Remember the + * last errcode. */ - lasterrno = get_errno(); - ret = ERROR; + lasterrno = ret; } } } + stream_semgive(list); } - /* If any flush failed, return that last failed flush */ + /* If any flush failed, return the errorcode of the last failed flush */ - if (ret != OK) - { - set_errno(lasterrno); - } - return ret; + return lasterrno; } diff --git a/nuttx/lib/stdio/lib_libfread.c b/nuttx/lib/stdio/lib_libfread.c index 4d402a42b..03b47eda6 100644 --- a/nuttx/lib/stdio/lib_libfread.c +++ b/nuttx/lib/stdio/lib_libfread.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_libfread.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2007-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -88,6 +88,7 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) { unsigned char *dest = (unsigned char*)ptr; ssize_t bytes_read; + int ret; /* Make sure that reading from this stream is allowed */ @@ -127,9 +128,11 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) * buffered read/write access. */ - if (lib_wrflush(stream) != 0) + ret = lib_wrflush(stream); + if (ret < 0) { - return ERROR; + lib_give_semaphore(stream); + return ret; } /* Now get any other needed chars from the buffer or the file. */ @@ -176,15 +179,17 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) bytes_read = read(stream->fs_filedes, dest, count); if (bytes_read < 0) { - /* An error occurred on the read */ + /* An error occurred on the read. The error code is + * in the 'errno' variable. + */ - goto err_out; + goto errout_with_errno; } else if (bytes_read == 0) { /* We are at the end of the file */ - goto short_read; + goto shortread; } else { @@ -198,7 +203,7 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) { /* No. We must be at the end of file. */ - goto short_read; + goto shortread; } else { @@ -219,15 +224,17 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) bytes_read = read(stream->fs_filedes, stream->fs_bufread, buffer_available); if (bytes_read < 0) { - /* An error occurred on the read */ + /* An error occurred on the read. The error code is + * in the 'errno' variable. + */ - goto err_out; + goto errout_with_errno; } else if (bytes_read == 0) { /* We are at the end of the file */ - goto short_read; + goto shortread; } else { @@ -246,7 +253,11 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) bytes_read = read(stream->fs_filedes, dest, count); if (bytes_read < 0) { - goto err_out; + /* An error occurred on the read. The error code is + * in the 'errno' variable. + */ + + goto errout_with_errno; } else if (bytes_read == 0) { @@ -259,13 +270,21 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) } } #endif + /* Here after a successful (but perhaps short) read */ + #if CONFIG_STDIO_BUFFER_SIZE > 0 - short_read: + shortread: #endif bytes_read = dest - (unsigned char*)ptr; - err_out: - lib_give_semaphore(stream); } - return bytes_read; + + lib_give_semaphore(stream); + return bytes_read; + +/* Error exits */ + +errout_with_errno: + lib_give_semaphore(stream); + return -get_errno(); } diff --git a/nuttx/lib/stdio/lib_libsprintf.c b/nuttx/lib/stdio/lib_libsprintf.c index 04d547754..2474a6f01 100644 --- a/nuttx/lib/stdio/lib_libsprintf.c +++ b/nuttx/lib/stdio/lib_libsprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_libsprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_rdflush.c b/nuttx/lib/stdio/lib_rdflush.c index 948dcce5d..35c5495c1 100644 --- a/nuttx/lib/stdio/lib_rdflush.c +++ b/nuttx/lib/stdio/lib_rdflush.c @@ -2,7 +2,7 @@ * lib/stdio/lib_rdflush.c * * Copyright (C) 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_snprintf.c b/nuttx/lib/stdio/lib_snprintf.c index a4dcd399b..e5ce7b0f0 100644 --- a/nuttx/lib/stdio/lib_snprintf.c +++ b/nuttx/lib/stdio/lib_snprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_snprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_sprintf.c b/nuttx/lib/stdio/lib_sprintf.c index 6de019cc5..89fd61033 100644 --- a/nuttx/lib/stdio/lib_sprintf.c +++ b/nuttx/lib/stdio/lib_sprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_sprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_sscanf.c b/nuttx/lib/stdio/lib_sscanf.c index 3430aa0a0..c77907711 100644 --- a/nuttx/lib/stdio/lib_sscanf.c +++ b/nuttx/lib/stdio/lib_sscanf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_sscanf.c * * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_syslogstream.c b/nuttx/lib/stdio/lib_syslogstream.c index 7e47d794a..21151b43a 100644 --- a/nuttx/lib/stdio/lib_syslogstream.c +++ b/nuttx/lib/stdio/lib_syslogstream.c @@ -2,7 +2,7 @@ * lib/stdio/lib_syslogstream.c * * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_ungetc.c b/nuttx/lib/stdio/lib_ungetc.c index 73e591729..c10d4fba1 100644 --- a/nuttx/lib/stdio/lib_ungetc.c +++ b/nuttx/lib/stdio/lib_ungetc.c @@ -2,7 +2,7 @@ * lib/stdio/lib_ungetc.c * * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_vfprintf.c b/nuttx/lib/stdio/lib_vfprintf.c index 25c3954c0..1c3a2d7fc 100644 --- a/nuttx/lib/stdio/lib_vfprintf.c +++ b/nuttx/lib/stdio/lib_vfprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_vfprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_vprintf.c b/nuttx/lib/stdio/lib_vprintf.c index a2e31fa05..d085d5886 100644 --- a/nuttx/lib/stdio/lib_vprintf.c +++ b/nuttx/lib/stdio/lib_vprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_vprintf.c * * Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_vsnprintf.c b/nuttx/lib/stdio/lib_vsnprintf.c index da885977c..c6f52092d 100644 --- a/nuttx/lib/stdio/lib_vsnprintf.c +++ b/nuttx/lib/stdio/lib_vsnprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_vsnprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_vsprintf.c b/nuttx/lib/stdio/lib_vsprintf.c index 72a829a79..5db46664e 100644 --- a/nuttx/lib/stdio/lib_vsprintf.c +++ b/nuttx/lib/stdio/lib_vsprintf.c @@ -2,7 +2,7 @@ * lib/stdio/lib_vsprintf.c * * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/nuttx/lib/stdio/lib_wrflush.c b/nuttx/lib/stdio/lib_wrflush.c index c16109515..5ef129d3f 100644 --- a/nuttx/lib/stdio/lib_wrflush.c +++ b/nuttx/lib/stdio/lib_wrflush.c @@ -1,8 +1,8 @@ /**************************************************************************** * lib/stdio/lib_wrflush.c * - * Copyright (C) 2008-2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2008-2009, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -88,29 +88,49 @@ int lib_wrflush(FAR FILE *stream) { +#if CONFIG_STDIO_BUFFER_SIZE > 0 + int ret; + /* Verify that we were passed a valid (i.e., non-NULL) stream */ -#if CONFIG_STDIO_BUFFER_SIZE > 0 - if (stream) +#ifdef CONFIG_DEBUG + if (!stream) { - /* Verify that the stream is opened for writing... lib_fflush will - * return an error if it is called for a stream that is not opened for - * writing. + return -EINVAL; + } +#endif + + /* Verify that the stream is opened for writing... lib_fflush will + * return an error if it is called for a stream that is not opened for + * writing. Check that first so that this function will not fail in + * that case. + */ + + if ((stream->fs_oflags & O_WROK) == 0) + { + /* Report that the success was successful if we attempt to flush a + * read-only stream. */ - if ((stream->fs_oflags & O_WROK) == 0 || - lib_fflush(stream, true) == 0) - { - /* Return success if there is no buffered write data -- i.e., that - * the stream is not opened for writing or, if it is, that all of - * the buffered write data was successfully flushed. - */ - - return OK; - } + return OK; } - return ERROR; + + /* Flush the stream. Return success if there is no buffered write data + * -- i.e., that the stream is opened for writing and that all of the + * buffered write data was successfully flushed by lib_fflush(). + */ + + return lib_fflush(stream, true); #else - return stream ? OK : ERROR; + /* Verify that we were passed a valid (i.e., non-NULL) stream */ + +#ifdef CONFIG_DEBUG + if (!stream) + { + return -EINVAL; + } +#endif + + return OK; #endif } diff --git a/nuttx/lib/stdio/lib_zeroinstream.c b/nuttx/lib/stdio/lib_zeroinstream.c index 27655b547..39a6c22ef 100644 --- a/nuttx/lib/stdio/lib_zeroinstream.c +++ b/nuttx/lib/stdio/lib_zeroinstream.c @@ -2,7 +2,7 @@ * lib/stdio/lib_zeroinstream.c * * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions