Test whether requested resource is a file or directory
This commit is contained in:
parent
a3cdde2c34
commit
543858d01d
171
main.c
171
main.c
@ -157,7 +157,6 @@ int main(int argc, char *argv[])
|
||||
socklen_t paddr_size = sizeof(paddr);
|
||||
int cfd;
|
||||
ssize_t n, slen;
|
||||
DIR *rdir;
|
||||
while (!exit_requested) {
|
||||
/*
|
||||
* Accept incoming connection.
|
||||
@ -236,97 +235,127 @@ int main(int argc, char *argv[])
|
||||
goto close_client_socket;
|
||||
ppos += n;
|
||||
|
||||
// UNSAFE!
|
||||
pbuf[ppos] = '\0';
|
||||
printf("Requested path: %s\n", pbuf);
|
||||
|
||||
/*
|
||||
* Determine the resource's type.
|
||||
* Determine whether the resource is a file or a directory.
|
||||
*
|
||||
* The path passed to stat() has to be null-terminated, which
|
||||
* pbuf is not, so a trailing null byte must first be added
|
||||
* there.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Open the resource.
|
||||
*/
|
||||
if (srvroot_len + 1 > PBUF_SIZE) {
|
||||
if (ppos + 1 > PBUF_SIZE) {
|
||||
fprintf(stderr, "Path buffer is too small\n");
|
||||
goto close_client_socket;
|
||||
}
|
||||
pbuf[srvroot_len] = '\0';
|
||||
do {
|
||||
errno = 0;
|
||||
rdir = opendir(pbuf);
|
||||
} while (errno == EINTR);
|
||||
if (rdir == NULL) {
|
||||
fprintf(stderr, "Failed to open %s\n", pbuf);
|
||||
pbuf[ppos] = '\0';
|
||||
struct stat rstat;
|
||||
if (stat(pbuf, &rstat) == -1) {
|
||||
fprintf(stderr, "Failed to stat() path \"%s\"\n", pbuf);
|
||||
goto close_client_socket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a line for each entry in the directory to the client.
|
||||
*/
|
||||
struct dirent *ent;
|
||||
struct stat rstat;
|
||||
unsigned namelen;
|
||||
while ((ent = readdir(rdir)) != NULL) {
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
if (S_ISREG(rstat.st_mode)) {
|
||||
/*
|
||||
* Construct full path to entry in pbuf.
|
||||
*
|
||||
* This is needed in order to pass it to stat() later. The
|
||||
* path must be null-terminated.
|
||||
* Send hard-coded response for files for now.
|
||||
*/
|
||||
namelen = strlen(ent->d_name);
|
||||
if (srvroot_len + namelen + 2 > PBUF_SIZE) {
|
||||
fprintf(stderr, "Path buffer is too small\n");
|
||||
const char *resp = "Files don't work yet\r\n.\r\n";
|
||||
if (retrying_write(cfd, resp, strlen(resp)) == -1) {
|
||||
fprintf(stderr, "Couldn't write to client socket\n");
|
||||
goto close_client_socket;
|
||||
}
|
||||
} else if (S_ISDIR(rstat.st_mode)) {
|
||||
/*
|
||||
* Open the directory.
|
||||
*
|
||||
* The path is already null-terminated from the earlier call
|
||||
* to stat().
|
||||
*/
|
||||
DIR *rdir;
|
||||
do {
|
||||
errno = 0;
|
||||
rdir = opendir(pbuf);
|
||||
} while (errno == EINTR);
|
||||
if (rdir == NULL) {
|
||||
fprintf(stderr, "Failed to open %s\n", pbuf);
|
||||
goto close_client_socket;
|
||||
}
|
||||
pbuf[srvroot_len] = '/';
|
||||
memcpy(&pbuf[srvroot_len + 1], ent->d_name, namelen);
|
||||
pbuf[srvroot_len + 1 + namelen] = '\0';
|
||||
|
||||
/*
|
||||
* Identify entry type from file inode information.
|
||||
* Write a line for each entry in the directory to the client.
|
||||
*/
|
||||
if (stat(pbuf, &rstat) == -1) {
|
||||
fprintf(stderr,
|
||||
"Failed to stat() path \"%s\", skipping entry\n", pbuf);
|
||||
continue;
|
||||
struct dirent *ent;
|
||||
unsigned namelen;
|
||||
while ((ent = readdir(rdir)) != NULL) {
|
||||
/*
|
||||
* Skip . and .. entries.
|
||||
*/
|
||||
if (strcmp(ent->d_name, ".") == 0
|
||||
|| strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Construct full path to entry in pbuf.
|
||||
*
|
||||
* This is needed in order to pass it to stat() later. The
|
||||
* path must be null-terminated.
|
||||
*/
|
||||
namelen = strlen(ent->d_name);
|
||||
if (srvroot_len + namelen + 2 > PBUF_SIZE) {
|
||||
fprintf(stderr, "Path buffer is too small\n");
|
||||
goto close_client_socket;
|
||||
}
|
||||
pbuf[srvroot_len] = '/';
|
||||
memcpy(&pbuf[srvroot_len + 1], ent->d_name, namelen);
|
||||
pbuf[srvroot_len + 1 + namelen] = '\0';
|
||||
|
||||
/*
|
||||
* Identify entry type from file inode information.
|
||||
*/
|
||||
if (stat(pbuf, &rstat) == -1) {
|
||||
fprintf(stderr,
|
||||
"Failed to stat() path \"%s\", skipping entry\n",
|
||||
pbuf);
|
||||
continue;
|
||||
}
|
||||
enum etype type;
|
||||
if (S_ISREG(rstat.st_mode))
|
||||
type = ETYPE_FILE;
|
||||
else if (S_ISDIR(rstat.st_mode))
|
||||
type = ETYPE_DIR;
|
||||
else
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Format and send response line for current entry.
|
||||
*/
|
||||
n = snprintf(rbuf, RBUF_SIZE, "%1u%s\t%s\t%s\t%u\r\n", type,
|
||||
ent->d_name, &pbuf[srvroot_len], HOST, PORT);
|
||||
if (n >= RBUF_SIZE) {
|
||||
fprintf(stderr,
|
||||
"Response buffer was too small, skipping entry\n");
|
||||
continue;
|
||||
}
|
||||
if (retrying_write(cfd, rbuf, n) != n) {
|
||||
fprintf(stderr, "Error sending respose line to client\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (retrying_write(cfd, ".\r\n", 3) != 3) {
|
||||
fprintf(stderr,
|
||||
"Error sending response terminator to client\n");
|
||||
goto close_client_socket;
|
||||
}
|
||||
enum etype type;
|
||||
if (S_ISREG(rstat.st_mode))
|
||||
type = ETYPE_FILE;
|
||||
else if (S_ISDIR(rstat.st_mode))
|
||||
type = ETYPE_DIR;
|
||||
else
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Format and send response line for current entry.
|
||||
* Close the resource.
|
||||
*/
|
||||
n = snprintf(rbuf, RBUF_SIZE, "%1u%s\t%s\t%s\t%u\r\n", type,
|
||||
ent->d_name, &pbuf[srvroot_len], HOST, PORT);
|
||||
if (n >= RBUF_SIZE) {
|
||||
fprintf(stderr,
|
||||
"Response buffer was too small, skipping entry\n");
|
||||
continue;
|
||||
}
|
||||
if (retrying_write(cfd, rbuf, n) != n) {
|
||||
fprintf(stderr, "Error sending respose line to client\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (retrying_write(cfd, ".\r\n", 3) != 3) {
|
||||
fprintf(stderr, "Error sending response terminator to client\n");
|
||||
closedir(rdir);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Requested resource \"%s\" was not a directory or a "
|
||||
"regular file\n",
|
||||
pbuf);
|
||||
goto close_client_socket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the resource.
|
||||
*/
|
||||
closedir(rdir);
|
||||
|
||||
close_client_socket:
|
||||
close(cfd);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user