diff --git a/funcs/func_env.c b/funcs/func_env.c
index c56c50d7140236b3bd06297c25296b711bc7ebf6..707e96a12fd52d4e2d28b8947b17e38759548cdb 100644
--- a/funcs/func_env.c
+++ b/funcs/func_env.c
@@ -74,11 +74,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 		<syntax>
 			<parameter name="filename" required="true" />
 			<parameter name="offset" required="true">
-				<para>Maybe specified as any number. if negative <replaceable>offset</replaceable> specifies the number
+				<para>Maybe specified as any number. If negative, <replaceable>offset</replaceable> specifies the number
 				of bytes back from the end of the file.</para>
 			</parameter>
 			<parameter name="length" required="true">
-				<para>If specified, will limit the length of the data read to that size.</para>
+				<para>If specified, will limit the length of the data read to that size. If negative,
+				trims <replaceable>length</replaceable> bytes from the end of the file.</para>
 			</parameter>
 		</syntax>
 		<description>
@@ -166,40 +167,59 @@ static int file_read(struct ast_channel *chan, const char *cmd, char *data, char
 		AST_APP_ARG(offset);
 		AST_APP_ARG(length);
 	);
-	int offset = 0, length;
+	int offset = 0, length, res = 0;
 	char *contents;
+	size_t contents_len;
 
 	AST_STANDARD_APP_ARGS(args, data);
-	if (args.argc > 1)
+	if (args.argc > 1) {
 		offset = atoi(args.offset);
+	}
 
 	if (args.argc > 2) {
-		if ((length = atoi(args.length)) < 1) {
-			ast_log(LOG_WARNING, "Invalid length '%s'.  Returning the max (%d)\n", args.length, (int)len);
-			length = len;
-		} else if (length > len) {
-			ast_log(LOG_WARNING, "Length %d is greater than the max (%d).  Truncating output.\n", length, (int)len);
+		/* The +1/-1 in this code section is to accomodate for the terminating NULL. */
+		if ((length = atoi(args.length) + 1) > len) {
+			ast_log(LOG_WARNING, "Length %d is greater than the max (%d).  Truncating output.\n", length - 1, (int)len - 1);
 			length = len;
 		}
-	} else
+	} else {
 		length = len;
+	}
 
-	if (!(contents = ast_read_textfile(args.filename)))
+	if (!(contents = ast_read_textfile(args.filename))) {
 		return -1;
+	}
 
-	if (offset >= 0)
-		ast_copy_string(buf, &contents[offset], length);
-	else {
-		size_t tmp = strlen(contents);
-		if (offset * -1 > tmp) {
-			ast_log(LOG_WARNING, "Offset is larger than the file size.\n");
-			offset = tmp * -1;
+	do {
+		contents_len = strlen(contents);
+		if (offset > contents_len) {
+			res = -1;
+			break;
 		}
-		ast_copy_string(buf, &contents[tmp + offset], length);
-	}
+
+		if (offset >= 0) {
+			if (length < 0) {
+				if (contents_len - offset + length < 0) {
+					/* Nothing left after trimming */
+					res = -1;
+					break;
+				}
+				ast_copy_string(buf, &contents[offset], contents_len + length);
+			} else {
+				ast_copy_string(buf, &contents[offset], length);
+			}
+		} else {
+			if (offset * -1 > contents_len) {
+				ast_log(LOG_WARNING, "Offset is larger than the file size.\n");
+				offset = contents_len * -1;
+			}
+			ast_copy_string(buf, &contents[contents_len + offset], length);
+		}
+	} while (0);
+
 	ast_free(contents);
 
-	return 0;
+	return res;
 }
 
 static struct ast_custom_function env_function = {