home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam    

Writing Apache Modules with Perl and C
By:   Lincoln Stein and Doug MacEachern
Published:   O'Reilly & Associates, Inc.  - March 1999

Copyright © 1999 by O'Reilly & Associates, Inc.


 


   Show Contents   Previous Page   Next Page

Chapter 11 - C API Reference Guide, Part II
File and Directory Management

In this section...

Introduction
Pathname Manipulation
Working with Files and Directories

Introduction

   Show Contents   Go to Top   Previous Page   Next Page

Apache provides routines for opening files, reading and writing to them, and closing them. Some of these routines are wrappers around the standard operating system calls in order to provide a compatibility layer for the Unix, Win32, and other ports. Other functions are an improvement over their operating system equivalents because they take advantage of Apache's memory management system.

Pathname Manipulation

   Show Contents   Go to Top   Previous Page   Next Page

These routines are handy for parsing strings that contain filenames and paths. See the next section, "Working with Files and Directories," for functions that operate on files and directories themselves.

These functions are all declared in httpd.h:

void ap_chdir_file (const char *file)

Given a pathname in file, this peculiar little function identifies the directory part and invokes chdir() to make it the current working directory. Here's an example of calling the function on the request record's filename field in order to chdir() to the directory that contains the requested file:

ap_chdir_file(r->filename);

int ap_os_is_path_absolute (const char *filename)

This function provides a portable test as to whether a filename is absolute or not. On Unix systems, an absolute filename begins with a /, whereas under Win32 systems, an absolute filename may begin with a drive letter, a colon delimiter, and a / or \.

if(!ap_os_is_path_absolute(filename)) {
   ... must resolve the relative filename somehow ...

char *ap_make_full_path (pool *p, const char *directory, const char *filename)

ap_make_full_path() will concatenate directory and filename and return the result. The function is smart about checking the directory string for a terminating slash and automatically inserting one if needed.

int ap_is_directory (const char *path)

This function returns true if path exists and is a directory, false otherwise.

int ap_count_dirs (const char *path)

Given a pathname path, ap_count_dirs() counts the number of directories contained in the path. This function merely counts the number of occurrences of the slash character in the path. It doesn't actually check that any of the directories exist.

void ap_no2slash (char *path)

It is easy to inadvertently introduce multiple slashes into pathnames when concatenating directories and filenames. Although both the filesystem and URIs are resistant to repeated slashes, you can use this function to make constructed paths more aesthetic by folding multiple slashes into a single one. It changes the provided pathname in place and does not return a function result.

The following example will remove the double-slash from the path /home/httpd/docs// oops.html.

char *oops = ap_pstrdup(r->pool, "home/httpd/docs//oops.html");
ap_no2slash(oops);

char *ap_make_dirstr_prefix (char *prefix, const char *path, int n)

This highly specialized function will copy, at most, n leading directories found in path into the character array at prefix, ensuring that prefix will terminate in a slash. You must ensure that prefix is large enough to hold the resulting data--potentially the length of path plus one extra byte for the string terminator. The function returns a pointer to the end of prefix, in anticipation of your appending more data (typically a filename) onto the end of the string.

The following example shows one way to make a copy of the path to the parent directory of the currently requested file:

char* path = r->filename;
char* prefix = (char*)ap_palloc(r->pool, strlen(path)+1);
ap_make_dirstr_prefix(prefix, path, ap_count_dirs(path)-1);

In case this was less than crystal clear, here is an example input/output table:

path n prefix
/a/b/c
1
/
/a/b/c
2
/a/
/a/b/c
3
/a/b/
/a/b/c
4
/a/b/c
/a/b/c
5
/a/b/c

char *ap_make_dirstr_parent (pool *p, const char *filename)

This function returns a new string containing the parent directory in which filename lives. This is a much easier way to accomplish the same thing as the example given in the previous section, and probably a little faster as well. ap_make_dirstr_parent() operates entirely on the string level. It doesn't actually check that any of the directories exist.

char *dirname = ap_make_dirstr_parent(r->pool, r->filename);

void ap_getparents (char *filename)

Passed a file path in filename, the ap_getparents() function strips out any relative path components by removing references to the .. and . directories. The stripping method follows the four parsing phases described in RFC 1808. The operation is performed in place just like ap_no2slash().

You should perform this operation before opening files based on user-provided input. Otherwise, it might be possible for a malicious user to trick your module into opening a file in a directory outside the document root. (Microsoft Internet Information Server has been bitten by this bug several times.)

By the time your handler finds the requested URI in the request record, Apache has already passed it through ap_getparents(), so there is no need to call the function a second time. However, you will still need to run the function on any paths passed in fill-out forms and possibly on paths entered in configuration variables as well.

Working with Files and Directories

   Show Contents   Go to Top   Previous Page   Next Page

Apache provides a series of wrappers around the C library routines that open and close files and directories. The main purpose of these routines is to take advantage of the resource pool API. Any files and directories that you open using the API calls will be automatically closed and their data structures deallocated when the current resource pool is destroyed.

These routines all live in alloc.h:

FILE *ap_pfopen (pool *p, const char *name, const char *fmode)

ap_pfopen() is a wrapper around the standard fopen() call. In addition to ensuring that the FILE* is closed when the pool is destroyed, it provides some internal compatibility code that ensures that the append (a) mode works the same on all platforms.

In this example, the file indicated in r->filename is opened for reading:

FILE *fh = ap_pfopen(r->pool, r->filename, "r");

int ap_pfclose (pool *p, FILE *fh)

Although files opened with ap_pfopen() will be closed automatically for you when the transaction is finished, you may close them sooner using ap_pfclose(). Be sure to use this call rather than the standard fclose() so that Apache will know to cancel the scheduled cleanup.

ap_pfclose(r->pool, fh);

FILE *ap_pfdopen (pool *p, int fd, const char *fmode)

This function works like the standard fdopen() call to create a new FILE* attached to the indicated file descriptor. Like ap_pfopen(), the file is automatically closed when the pool is cleaned up.

FILE *fh = ap_pfdopen(r->pool, fd, "r");

int ap_popenf (pool *p, const char *name, int flags, int mode)
int ap_pclosef (struct pool *p, int fd)

These calls are equivalent to the standard open() and close() calls. ap_popenf() opens the indicated file and returns a file descriptor, or -1 if the file could not be opened. ap_ pclosef() closes the file and cancels the scheduled cleanup before pool destruction.

int fd = ap_popenf(r->pool, r->filename, O_RDONLY, 0600);
read(fd, buffer, 1024);
ap_pclosef(fd);

void ap_note_cleanups_for_file (pool *p, FILE *fp)

If a module has opened a FILE* stream with a function other than ap_pfopen(), it can use this function to ensure the file will be closed when the given pool is destroyed.

FILE *fp = tmpfile();
ap_note_cleanups_for_file(r->pool, fp);

void ap_note_cleanups_for_fd (pool *p, int fd)

If a module has opened a file descriptor with a function other than ap_pfdopen(), it can use this function to ensure the descriptor will be closed when the given pool is destroyed.

int fd = open(tempfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0622);
if (fd == -1) {
   ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                "error creating temporary file %s", tempfile);
   return HTTP_INTERNAL_SERVER_ERROR;
}
ap_note_cleanups_for_fd(r->pool, fd);

void ap_kill_cleanups_for_fd (pool *p, int fd)

If a file descriptor has been registered to be closed with ap_note_cleanups_for_fd(), this function can be used to unregister the cleanup.

ap_kill_cleanups_for_fd(r->pool, fd);

DIR *ap_popendir (pool *p, const char *name)
void ap_pclosedir (pool *p, DIR *d)

These functions correspond to the opendir() and closedir() calls. Like the other functions in this section, directory handles allocated with ap_popendir() are automatically closed and cleaned up for you when the pool is destroyed. You can close the directory earlier with ap_pclosedir().

In this example, we check to see whether the requested filename is a directory. If so, we open it as a directory rather than as a file.

if(S_ISDIR(r->finfo.st_mode)) {
   DIR *dh = ap_popendir(r->pool, r->filename);
  ...
  ap_pclosedir(r->pool, dh);
}

int ap_psocket (pool *p, int domain, int type, int protocol)
int ap_pclosesocket (pool *p, int sock)

ap_psocket() is a wrapper around the socket() system call. The socket is closed when the pool is destroyed. The ap_pclosesocket() function closes a socket previously opened with ap_psocket(), canceling the scheduled cleanup.

int sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
...
ap_pclosesocket(p, sock);
   Show Contents   Go to Top   Previous Page   Next Page
Copyright © 1999 by O'Reilly & Associates, Inc.










??????????????@Mail.ru