Annotation of libwww/Library/src/HTFile.c, revision 1.81
1.72 frystyk 1: /* HTFile.c
2: ** FILE ACCESS
3: **
1.79 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.72 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1 timbl 6: **
7: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 8: ** These are routines for file access used by browsers.
1.1 timbl 9: **
10: ** History:
11: ** Feb 91 Written Tim Berners-Lee CERN/CN
12: ** Apr 91 vms-vms access included using DECnet syntax
13: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
14: ** Fixed access bug for relative names on VMS.
1.28 duns 15: ** Sep 93 (MD) Access to VMS files allows sharing.
16: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 17: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 frystyk 18: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
19: ** error messages introduced etc.
1.1 timbl 20: **
21: ** Bugs:
1.2 timbl 22: ** FTP: Cannot access VMS files from a unix machine.
23: ** How can we know that the
1.1 timbl 24: ** target machine runs VMS?
25: */
26:
1.67 frystyk 27: /* Library Includes */
1.75 frystyk 28: #include "tcp.h"
1.67 frystyk 29: #include "HTUtils.h"
1.75 frystyk 30: #include "HTString.h"
1.1 timbl 31: #include "HTParse.h"
32: #include "HTTCP.h"
33: #include "HTAnchor.h"
1.2 timbl 34: #include "HTAtom.h"
35: #include "HTWriter.h"
1.75 frystyk 36: #include "HTFWrite.h"
1.52 duns 37: #include "HTFormat.h"
1.54 luotonen 38: #include "HTMulti.h"
1.78 frystyk 39: #include "HTDirBrw.h"
40: #include "HTBind.h"
1.80 frystyk 41: #include "HTSocket.h"
42: #include "HTThread.h"
1.61 frystyk 43: #include "HTError.h"
1.67 frystyk 44: #include "HTFile.h" /* Implemented here */
45:
1.80 frystyk 46: /* This is the local definition of HTRequest->net_info */
47: typedef enum _FileState {
48: FILE_RETRY = -4,
49: FILE_ERROR = -3,
50: FILE_NO_DATA = -2,
51: FILE_GOT_DATA = -1,
52: FILE_BEGIN = 0,
53: FILE_NEED_OPEN_FILE,
54: FILE_NEED_BODY,
55: FILE_PARSE_DIR,
56: FILE_TRY_FTP
57: } FileState;
58:
1.77 frystyk 59: typedef struct _file_info {
60: SOCKFD sockfd; /* Socket descripter */
61: SockA sock_addr; /* SockA is defined in tcp.h */
62: HTInputSocket * isoc; /* Input buffer */
63: SocAction action; /* Result of the select call */
64: HTStream * target; /* Target stream */
65: int addressCount; /* Attempts if multi-homed host */
66: time_t connecttime; /* Used on multihomed hosts */
67: struct _HTRequest * request; /* Link back to request structure */
1.80 frystyk 68:
69: FileState state; /* Current state of the connection */
70: char * localname; /* Local representation of file name */
71: FILE * fp; /* If we can't use sockets on local files */
1.77 frystyk 72: } file_info;
1.2 timbl 73:
1.80 frystyk 74: /* Local definition */
75: struct _HTStream {
76: CONST HTStreamClass * isa;
77: HTStream * target;
78: };
79:
1.77 frystyk 80: /* Controlling globals */
1.33 timbl 81: PUBLIC BOOL HTTakeBackup = YES;
1.1 timbl 82:
83: PRIVATE char *HTMountRoot = "/Net/"; /* Where to find mounts */
1.2 timbl 84:
1.61 frystyk 85: /* ------------------------------------------------------------------------- */
1.11 timbl 86:
1.80 frystyk 87: /* Convert file URLs into a local representation
88: ** ---------------------------------------------
89: ** The URL has already been translated through the rules in get_physical
90: ** in HTAccess.c and all we need to do now is to map the path to a local
91: ** representation, for example if must translate '/' to the ones that
92: ** turn the wrong way ;-)
93: **
94: ** On Entry
95: ** The full URL that's is going to be translated
96: ** On Exit,
97: ** -1 Error
98: ** 0 URL is not pointing to the local file system
99: ** 1 A local name is returned in `local' which must be freed
100: ** by caller
1.1 timbl 101: */
1.80 frystyk 102: PRIVATE int HTLocalName ARGS2(CONST char *, url, char **, local)
1.1 timbl 103: {
1.80 frystyk 104: if (url) {
105: char * access = HTParse(url, "", PARSE_ACCESS);
106: char * host = HTParse(url, "", PARSE_HOST);
107: char * path = HTParse(url, "", PARSE_PATH+PARSE_PUNCTUATION);
108: CONST char *myhost;
109:
110: /* Find out if this is a reference to the local file system */
111: if ((*access && strcmp(access, "file")) ||
112: (*host && strcasecomp(host, "localhost") &&
113: (myhost=HTGetHostName()) && strcmp(host, myhost))) {
114: if (PROT_TRACE)
115: fprintf(TDEST, "LocalName... Not on local file system\n");
116: free(access);
117: free(host);
118: free(path);
119: return 0;
120: } else {
121: /*
122: ** Do whatever translation is required here in order to fit your
123: ** platform _before_ the path is unescaped.
124: */
1.65 duns 125: #if VMS
1.80 frystyk 126: HTVMS_checkDecnet(path);
127: #endif
1.77 frystyk 128: #ifdef _WINDOWS
129: /* an absolute pathname with logical drive */
130: if (*path == '/' && path[2] == ':')
131: /* NB. need memmove because overlaps */
1.80 frystyk 132: memmove( path, path+1, strlen(path) + 1);
1.77 frystyk 133: #endif
1.80 frystyk 134:
135: HTUnEscape(path); /* Take out the escaped characters */
136: if (PROT_TRACE)
137: fprintf(TDEST, "Node........ `%s' means path `%s'\n",url,path);
138: free(access);
1.1 timbl 139: free(host);
1.80 frystyk 140: *local = path;
141: return 1;
1.1 timbl 142: }
143: }
1.80 frystyk 144: return -1;
1.1 timbl 145: }
146:
147:
148: /* Make a WWW name from a full local path name
149: **
150: ** Bugs:
151: ** At present, only the names of two network root nodes are hand-coded
152: ** in and valid for the NeXT only. This should be configurable in
153: ** the general case.
154: */
155:
156: PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name)
157: {
158: char * result;
159: #ifdef NeXT
160: if (0==strncmp("/private/Net/", name, 13)) {
161: result = (char *)malloc(7+strlen(name+13)+1);
162: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
163: sprintf(result, "file://%s", name+13);
164: } else
165: #endif
166: if (0==strncmp(HTMountRoot, name, 5)) {
167: result = (char *)malloc(7+strlen(name+5)+1);
168: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
169: sprintf(result, "file://%s", name+5);
170: } else {
1.63 frystyk 171: result = (char *)malloc(7+strlen(HTGetHostName())+strlen(name)+1);
1.1 timbl 172: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
1.63 frystyk 173: sprintf(result, "file://%s%s", HTGetHostName(), name);
1.1 timbl 174: }
1.75 frystyk 175: if (TRACE) fprintf(TDEST, "File `%s'\n\tmeans node `%s'\n", name, result);
1.1 timbl 176: return result;
177: }
178:
179:
180: /* Determine write access to a file
1.2 timbl 181: ** --------------------------------
1.80 frystyk 182: ** If stat_info is NULL then the function calls stat() on it's own,
183: ** otherwise it uses the information found in stat_info
1.2 timbl 184: ** On exit,
185: ** return value YES if file can be accessed and can be written to.
186: **
187: ** Bugs:
188: ** 1. No code for non-unix systems.
189: ** 2. Isn't there a quicker way?
1.1 timbl 190: */
1.80 frystyk 191: PUBLIC BOOL HTEditable ARGS2(CONST char *, filename, struct stat *, stat_info)
192: {
1.75 frystyk 193: #ifndef NO_UNIX_IO
194: #ifdef NO_GROUPS
1.80 frystyk 195: return NO; /* Safe answer till we find the correct algorithm */
1.1 timbl 196: #else
1.75 frystyk 197: #ifdef NeXT
1.80 frystyk 198: int groups[NGROUPS];
1.75 frystyk 199: #else
1.80 frystyk 200: gid_t groups[NGROUPS];
1.75 frystyk 201: #endif
1.80 frystyk 202: int i;
203: uid_t myUid;
204: int ngroups; /* The number of groups */
1.1 timbl 205: struct stat fileStatus;
1.80 frystyk 206: struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.1 timbl 207:
1.80 frystyk 208: if (!stat_info) {
209: if (HTStat(filename, &fileStatus))
210: return NO; /* Can't even access file! */
211: }
1.1 timbl 212: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
213: myUid = geteuid(); /* Get my user identifier */
214:
215: if (TRACE) {
216: int i;
1.75 frystyk 217: fprintf(TDEST,
1.19 timbl 218: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80 frystyk 219: (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
220: (int) fileptr->st_gid, (int) myUid, ngroups);
1.75 frystyk 221: for (i=0; i<ngroups; i++) fprintf(TDEST, " %d", (int) groups[i]);
222: fprintf(TDEST, ")\n");
1.1 timbl 223: }
224:
1.80 frystyk 225: if (fileptr->st_mode & 0002) /* I can write anyway? */
1.1 timbl 226: return YES;
227:
1.80 frystyk 228: if ((fileptr->st_mode & 0200) /* I can write my own file? */
229: && (fileptr->st_uid == myUid))
1.1 timbl 230: return YES;
231:
1.80 frystyk 232: if (fileptr->st_mode & 0020) /* Group I am in can write? */
1.1 timbl 233: {
234: for (i=0; i<ngroups; i++) {
1.80 frystyk 235: if (groups[i] == fileptr->st_gid)
1.1 timbl 236: return YES;
237: }
238: }
1.75 frystyk 239: if (TRACE) fprintf(TDEST, "\tFile is not editable.\n");
1.1 timbl 240: return NO; /* If no excuse, can't do */
241: #endif
1.80 frystyk 242: #else
243: /*
244: ** We don't know and can't find out. Can we be sure that when opening
245: ** a file in mode "a" that the file is not modified?
246: */
247: return NO;
248: #endif /* !NO_UNIX_IO */
1.1 timbl 249: }
1.80 frystyk 250:
1.1 timbl 251:
1.2 timbl 252: /* Make a save stream
253: ** ------------------
254: **
255: ** The stream must be used for writing back the file.
256: ** @@@ no backup done
257: */
1.29 timbl 258: PUBLIC HTStream * HTFileSaveStream ARGS1(HTRequest *, request)
1.2 timbl 259: {
260:
1.29 timbl 261: CONST char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.80 frystyk 262: char * filename;
1.33 timbl 263: FILE* fp;
1.80 frystyk 264: HTLocalName(addr, &filename);
1.33 timbl 265:
266: /* @ Introduce CVS handling here one day
267: */
268: /* Take a backup before we do anything silly 931205
269: */
270: if (HTTakeBackup) {
1.69 frystyk 271: char * p;
272: char * backup_filename = (char *) malloc(strlen(filename)+2);
1.33 timbl 273: if (!backup_filename) outofmem(__FILE__, "taking backup");
274: strcpy(backup_filename, filename);
1.34 timbl 275: for(p=backup_filename+strlen(backup_filename);; p--) {
1.33 timbl 276: if ((*p=='/') || (p<backup_filename)) {
277: p[1]=','; /* Insert comma after slash */
278: break;
279: }
280: p[1] = p[0]; /* Move up everything to the right of it */
281: }
282:
1.65 duns 283:
284: #ifdef VMS
285: if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) { /* File exists */
286: #else /* not VMS */
1.35 luotonen 287: if ((fp=fopen(filename, "r"))) { /* File exists */
1.65 duns 288: #endif /* not VMS */
1.33 timbl 289: fclose(fp);
1.75 frystyk 290: if (TRACE) fprintf(TDEST, "File `%s' exists\n", filename);
1.77 frystyk 291: if (REMOVE_FILE(backup_filename)) {
1.75 frystyk 292: if (TRACE) fprintf(TDEST, "Backup file `%s' removed\n",
1.56 frystyk 293: backup_filename);
1.33 timbl 294: }
295: if (rename(filename, backup_filename)) { /* != 0 => Failure */
1.75 frystyk 296: if (TRACE) fprintf(TDEST, "Rename `%s' to `%s' FAILED!\n",
1.56 frystyk 297: filename, backup_filename);
1.33 timbl 298: } else { /* Success */
1.75 frystyk 299: if (TRACE) fprintf(TDEST, "Renamed `%s' to `%s'\n", filename,
1.56 frystyk 300: backup_filename);
1.33 timbl 301: }
302: }
303: free(backup_filename);
304: } /* if take backup */
1.2 timbl 305:
1.61 frystyk 306: if ((fp = fopen(filename, "w")) == NULL) {
1.75 frystyk 307: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "fopen");
1.61 frystyk 308: return NULL;
309: } else
1.40 frystyk 310: return HTFWriter_new(fp, NO);
1.2 timbl 311: }
312:
1.10 secret 313:
1.80 frystyk 314: /* FileCleanup
315: **
316: ** This function closes the connection and frees memory.
317: **
318: ** Returns 0 on OK, else -1
319: */
320: PRIVATE int FileCleanup ARGS2(HTRequest *, req, BOOL, abort)
321: {
322: file_info *file;
323: int status = 0;
324: if (!req || !req->net_info) {
325: if (PROT_TRACE) fprintf(TDEST, "FileCleanup. Bad argument!\n");
326: status = -1;
327: } else {
328: file = (file_info *) req->net_info;
329: if (file->sockfd != INVSOC) {
330:
331: /* Free stream with data FROM local file system */
332: if (file->target) {
333: if (abort)
334: (*file->target->isa->abort)(file->target, NULL);
335: else
336: (*file->target->isa->_free)(file->target);
337: }
338:
339: if (PROT_TRACE)
340: fprintf(TDEST,"FILE........ Closing socket %d\n",file->sockfd);
341: if ((status = NETCLOSE(file->sockfd)) < 0)
342: HTErrorSysAdd(file->request, ERR_FATAL, socerrno, NO,
343: "NETCLOSE");
344: HTThreadState(file->sockfd, THD_CLOSE);
345: file->sockfd = INVSOC;
346: HTThread_clear((HTNetInfo *) file);
347: }
348: if (file->isoc)
349: HTInputSocket_free(file->isoc);
350: if (file->fp)
351: fclose(file->fp);
352: FREE(file->localname);
353: free(file);
354: req->net_info = NULL;
355: }
356: return status;
357: }
358:
359:
1.1 timbl 360: /* Load a document
361: ** ---------------
362: **
363: ** On entry,
1.80 frystyk 364: ** request This is the request structure
1.1 timbl 365: ** On exit,
1.77 frystyk 366: ** returns HT_ERROR Error has occured or interrupted
367: ** HT_WOULD_BLOCK We are using blocking I/O so this
368: ** indicates that we have a read a chunk
369: ** of data and now want to see what's up
370: ** in the eventloop.
1.80 frystyk 371: ** HT_LOADED if file has been loaded successfully
372: ** HT_NO_DATA if file is empty
373: ** HT_RETRY if file service is unavailable
1.1 timbl 374: */
1.36 luotonen 375: PUBLIC int HTLoadFile ARGS1 (HTRequest *, request)
1.1 timbl 376: {
1.80 frystyk 377: int status = HT_ERROR;
378: file_info *file; /* Specific access information */
1.45 luotonen 379:
1.61 frystyk 380: if (!request || !request->anchor) {
1.75 frystyk 381: if (TRACE) fprintf(TDEST, "HTLoadFile.. Called with bad argument\n");
1.77 frystyk 382: return HT_ERROR;
1.50 frystyk 383: }
1.1 timbl 384:
1.80 frystyk 385: /* Only do the setup first time through. This is actually state FILE_BEGIN
386: but it can't be in the state machine as we need the structure first */
387: if (!request->net_info) {
388: if (PROT_TRACE) {
389: char *url = HTAnchor_physical(request->anchor);
390: fprintf(TDEST, "LoadFile.... Looking for `%s\'\n", url);
391: }
392: if ((file = (file_info *) calloc(1, sizeof(file_info))) == NULL)
393: outofmem(__FILE__, "HTLoadFILE");
394: file->sockfd = INVSOC; /* Invalid socket number */
395: file->request = request;
396: request->net_info = (HTNetInfo *) file;
397: file->state = FILE_BEGIN;
398: HTThread_new((HTNetInfo *) file);
399: } else {
400: file = (file_info *) request->net_info; /* Get existing copy */
1.78 frystyk 401:
1.80 frystyk 402: /* @@@ NEED ALSO TO CHECK FOR ANSI FILE DESCRIPTORS @@@ */
403: if (file->sockfd != INVSOC && HTThreadIntr(file->sockfd))
404: file->state = FILE_ERROR;
405: }
1.36 luotonen 406:
1.80 frystyk 407: /* Now jump into the machine. We know the state from the previous run */
408: while (1) {
409: switch (file->state) {
410: case FILE_BEGIN:
411: if (HTSecure) {
412: if (PROT_TRACE)
413: fprintf(TDEST, "LoadFile.... No access to local file system\n");
414: file->state = FILE_TRY_FTP;
415: break;
416: }
417: if ((status = HTLocalName(HTAnchor_physical(request->anchor),
418: &file->localname)) == -1) {
419: file->state = FILE_ERROR;
420: break;
421: } else if (status == 0) {
422: file->state = FILE_TRY_FTP;
423: break;
1.2 timbl 424: }
1.80 frystyk 425: /*
426: ** If we have to do content negotiation then find the object that
427: ** fits best into either what the client has indicated in the
428: ** accept headers or what the client has registered on it own.
429: ** The object chosen can in fact be a directory! However, content
430: ** negotiation only makes sense it we can read the directory!
431: ** We stat the file in order to find the size and to see it if
432: ** exists.
433: */
434: {
435: struct stat stat_info; /* Contains actual file chosen */
436: if (request->ContentNegotiation) {
437: char *new_path=HTMulti(request,file->localname,&stat_info);
438: if (new_path) {
439: FREE(file->localname);
440: file->localname = new_path;
441: HTAnchor_setPhysical(request->anchor, new_path);
442: } else {
443: file->state = FILE_ERROR;
444: break;
445: }
446: } else {
447: if (HTStat(file->localname, &stat_info) == -1) {
448: if (PROT_TRACE)
449: fprintf(TDEST, "HTLoadFile.. Can't stat %s\n",
450: file->localname);
1.81 ! frystyk 451: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
! 452: NULL, 0, "HTLoadFile");
1.80 frystyk 453: file->state = FILE_ERROR;
454: break;
455: }
456: }
457: /* Check to see if the 'localname' is in fact a directory */
458: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
459: file->state = FILE_PARSE_DIR;
460: else {
461: /*
462: ** If empty file then only serve it if it is editable
463: */
464: BOOL editable = HTEditable(file->localname, &stat_info);
465: HTBind_getBindings(request->anchor);
466: if (editable)
467: HTAnchor_appendMethods(request->anchor, METHOD_PUT);
468: if (stat_info.st_size)
469: HTAnchor_setLength(request->anchor, stat_info.st_size);
470:
471: /* Put all relevant metainformation into the anchor */
472: request->anchor->header_parsed = YES;
473:
474: if (!editable && !stat_info.st_size) {
1.81 ! frystyk 475: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80 frystyk 476: NULL, 0, "HTLoadFile");
477: file->state = FILE_NO_DATA;
478: } else
479: file->state = FILE_NEED_OPEN_FILE;
480: }
1.2 timbl 481: }
1.80 frystyk 482: break;
1.61 frystyk 483:
1.80 frystyk 484: case FILE_NEED_OPEN_FILE:
485: /*
486: ** If we have unix file descriptors then use this otherwise use
487: ** the ANSI C file descriptors
488: */
489: #ifndef NO_UNIX_IO
490: if ((file->sockfd = open(file->localname, O_RDONLY)) == -1) {
491: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "open");
492: file->state = FILE_ERROR;
493: } else {
494: if (PROT_TRACE)
495: fprintf(TDEST,"HTLoadFile.. `%s' opened using fd %d \n",
496: file->localname, file->sockfd);
497:
498: /* If non-blocking protocol then change socket status
499: ** I use FCNTL so that I can ask the status before I set it.
500: ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
501: ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
502: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
503: ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
504: */
505: if (!HTProtocolBlocking(request)) {
506: if ((status = FCNTL(file->sockfd, F_GETFL, 0)) != -1) {
507: status |= O_NONBLOCK; /* POSIX */
508: status = FCNTL(file->sockfd, F_SETFL, status);
509: }
510: if (PROT_TRACE) {
511: if (status == -1)
512: fprintf(TDEST, "HTLoadFile.. Can't make socket non-blocking\n");
513: else
514: fprintf(TDEST, "HTLoadFile.. Using NON_BLOCKING I/O\n");
515: }
516: }
517:
518: /* Set up read buffer and streams */
519: file->isoc = HTInputSocket_new(file->sockfd);
520: file->target = HTStreamStack(HTAnchor_format(request->anchor),
521: request->output_format,
522: request->output_stream,
523: request, YES);
524: HTThreadState(file->sockfd, THD_SET_READ);
525: file->state = file->target ? FILE_NEED_BODY : FILE_ERROR;
1.61 frystyk 526: }
1.80 frystyk 527: #else
1.65 duns 528: #ifdef VMS
1.80 frystyk 529: if ((file->fp = fopen(file->localname,"r","shr=put","shr=upd")) == NULL) {
530: #else
531: if ((file->fp = fopen(file->localname,"r")) == NULL){
1.65 duns 532: #endif /* not VMS */
1.80 frystyk 533: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "fopen");
534: file->state = FILE_ERROR;
535: } else {
536: if (PROT_TRACE)
537: fprintf(TDEST,"HTLoadFile.. Open `%s'\n",file->localname);
538: file->state = FILE_NEED_BODY;
539: }
540: #endif /* !NO_UNIX_IO */
541:
542: break;
1.65 duns 543:
1.80 frystyk 544: case FILE_NEED_BODY:
545: #ifndef NO_UNIX_IO
546: status = HTSocketRead(request, file->target);
547: if (status == HT_WOULD_BLOCK)
548: return HT_WOULD_BLOCK;
549: else if (status == HT_INTERRUPTED)
550: file->state = FILE_ERROR;
551: else if (status == HT_LOADED) {
552: file->state = FILE_GOT_DATA;
1.61 frystyk 553: } else
1.80 frystyk 554: file->state = FILE_ERROR;
555: #else
556: if (HTParseFile(HTAnchor_format(request->anchor), file->fp,
557: request) < 0)
558: file->state = FILE_ERROR;
559: else
560: file->state = FILE_GOT_DATA;
561: #endif
562: break;
1.1 timbl 563:
1.80 frystyk 564: case FILE_PARSE_DIR:
565: #ifdef GOT_READ_DIR
566: file->state = HTBrowseDirectory(request, file->localname) < 0 ?
567: FILE_ERROR : FILE_GOT_DATA;
568: #else
569: file->state = FILE_ERROR;
1.1 timbl 570: #endif
1.80 frystyk 571: break;
572:
573: case FILE_TRY_FTP:
574: {
575: char *url = HTAnchor_physical(request->anchor);
576: HTAnchor *anchor;
577: char *newname = NULL;
578: StrAllocCopy(newname, "ftp:");
579: if (!strncmp(url, "file:", 5))
580: StrAllocCat(newname, url+5);
581: else
582: StrAllocCat(newname, url);
583: anchor = HTAnchor_findAddress(newname);
584: free(newname);
585: FileCleanup(request, NO);
586: return HTLoadAnchorRecursive(anchor, request);
587: }
588: break;
1.1 timbl 589:
1.80 frystyk 590: case FILE_GOT_DATA:
591: FileCleanup(request, NO);
592: return HT_LOADED;
593: break;
594:
595: case FILE_NO_DATA:
596: FileCleanup(request, NO);
597: return HT_NO_DATA;
598: break;
599:
600: case FILE_RETRY:
601: FileCleanup(request, YES);
602: return HT_RETRY;
603: break;
604:
605: case FILE_ERROR:
606: FileCleanup(request, YES);
607: return HT_ERROR;
608: break;
609: }
610: } /* End of while(1) */
1.1 timbl 611: }
612:
1.80 frystyk 613:
614: /*
615: ** Protocol descriptor
616: ** Make this non-blocking is possible
617: */
618: #ifndef NO_UNIX_IO
619: GLOBALDEF PUBLIC HTProtocol HTFile = {
620: "file", SOC_NON_BLOCK, HTLoadFile, HTFileSaveStream, NULL
621: };
622: #else
1.71 frystyk 623: GLOBALDEF PUBLIC HTProtocol HTFile = {
624: "file", SOC_BLOCK, HTLoadFile, HTFileSaveStream, NULL
625: };
1.80 frystyk 626: #endif
Webmaster