SQLite Forum

Possible bug in .read when a directory is specified?
Login

Possible bug in .read when a directory is specified?

(1) By L Carl (lcarlp) on 2020-07-16 17:50:47 [source]

I have a file named v3_port.sql with some SQL statements in it, and also a directory named v3_port.  Maybe not the best idea, but that’s what I had.

I entered the command:

   .read v3_port

I meant to say v3_port.sql, but I left off the extension due to a habit formed when I was working with Oracle.  Strangely, it appeared to do nothing at all when I specified the directory.  There were no error messages and as far as I can tell it did not try to read any of the files in that directory.

Is this expected behavior?  I would have preferred an error message, “Hey!  Wake up!  That’s a directory!”.  But, maybe there’s a good reason why it doesn’t do that.

(2) By Stephan Beal (stephan) on 2020-07-16 17:58:15 [link] [source] in reply to 1

Strangely, it appeared to do nothing at all when I specified the directory.

On Unix systems, at least, directories can be fopen()ed just like files, and they contain binary content. It sounds like perhaps yours started with a NUL byte which ended the "sql" the shell thought it was reading. That's actually correct behavior, but the shell could arguably check whether it's a directory before opening it. (The same thing bit me in another piece of software a few years ago.)

(3) By anonymous on 2020-07-17 13:42:08 [link] [source] in reply to 2

On Unix systems, at least, directories can be fopen()ed just like files, and they contain binary content.

Not sure what does POSIX specify about this, but trying to fread() (but not fopen()!) a directory on GNU/Linux results in an error:

#include <errno.h>
#include <stdio.h>
#include <string.h>

char buf[256];

int main() {
	int e;
	size_t i;

	FILE * f = fopen(".", "r");
	printf("%p\n", f);
	if (!f) return -1;

	i = fread(buf, 1, sizeof buf, f);
	e = errno;
	printf("%llu %d %s\n", (unsigned long long)i, e, strerror(e));

	fclose(f);
	return 0;
}
0x55b11dfd7010
0 21 Is a directory

(4) By Warren Young (wyoung) on 2020-07-17 17:19:56 [link] [source] in reply to 3

Those are the C library interfaces. Try the POSIX ones, without the leading “f”. I assume the Unix VFS uses the latter.

(5) By Stephan Beal (stephan) on 2020-07-17 17:37:05 and edited on 2020-07-17 17:48:20 [history] [link] [source] in reply to 4

Those are the C library interfaces. Try the POSIX ones, without the leading “f”. I assume the Unix VFS uses the latter.

open() and read() do the same on my system (Mint Linux 20):

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
	int e;
	size_t i;
  char buf[256];
	int fd = open(".", O_RDONLY);
	printf("%d\n", fd);
	if (!fd<0) return -1;

	i = (ssize_t) read(fd, buf, sizeof(buf));
	e = errno;
	printf("%llu %d %s\n", (unsigned long long)i, e, strerror(e));

	close(fd);
	return 0;
}

Output:

3
18446744073709551615 21 Is a directory

Whether or not that's a standard behaviour, i don't know. It was a good 5 or 6 years ago that i had a piece of software simply open/fopen and read/fread a directory handle - perhaps that was specific to those C libs. No man pages i've found make any mention of it being an error to open/fopen a directory.

IEEE fopen() lists only one error case which sounds relevant:

[EISDIR]
    [CX] [Option Start] The named file is a directory and mode requires write access.

strongly implying that opening a directory is acceptable in read-only mode.

Edit: in any case, the opening is succeeding, both with open() and fopen(), but the reading, both with read() and fread(), on my current system. This StackOverflow answer says that the ability to read() a directory entry existed historically but was eventually removed.

Edit: IBM's z/OS docs say that fread() returns 0 when used to read a directory, which differs from how Linux does it. Insofar as i can determine, this capability lives in the realm of implementation-defined behaviour.

/shrugs shoulders

(10) By Rowan Worth (sqweek) on 2020-07-20 05:35:39 [link] [source] in reply to 2

Historically I recall observing the same thing, that you could even cat a directory and get garbage printed to your terminal. However I think it was widely regarded as a misfeature and there's generally been a move towards the read syscall itself returning EISDIR as noted elsewhere in the thread. I've just tested linux (3.10.0-693.5.2.el7) and OpenBSD (6.4) and they both display this behaviour.

OSX (Darwin kernel 19.5.0) reports "Operation not supported" trying to cat a directory but I'm not sure how to check the syscalls here.

(8) By luuk on 2020-07-18 07:52:55 [link] [source] in reply to 1

On both tests there is a directory 'test' and a file 'test.sql'.

Windows:

D:\TEMP>sqlite3 test.db
SQLite version 3.32.3 2020-06-18 14:00:33
Enter ".help" for usage hints.
sqlite> .read test
Error: cannot open "test"
sqlite> .q

Linux (WSL):

/mnt/d/TEMP$ sqlite3 test.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .read test
sqlite> .q

It could be the difference in versions, but it's different.

(9) By anonymous on 2020-07-19 14:18:48 [link] [source] in reply to 8

IMHO reading a directory as SQL doesn't make sense, even if it were technically possible. It would be good style to warn the user about this with an error message. W. Oertl

(11) By luuk on 2020-07-20 13:36:41 [link] [source] in reply to 9

Indeed, and error message seems to be missing on Linux.

(12) By TripeHound on 2020-07-23 19:49:45 [link] [source] in reply to 9

For info, the bottom of this post on the Fossil forum is possibly the "same sort of thing"... reading a directory as though it were a normal file.