Annotation of libwww/Library/src/HTFile.c, revision 1.82
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;
1.82 ! frystyk 329: if (file->sockfd != INVSOC || file->fp) {
1.80 frystyk 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:
1.82 ! frystyk 339: #ifndef NO_UNIX_IO
1.80 frystyk 340: if (PROT_TRACE)
341: fprintf(TDEST,"FILE........ Closing socket %d\n",file->sockfd);
342: if ((status = NETCLOSE(file->sockfd)) < 0)
343: HTErrorSysAdd(file->request, ERR_FATAL, socerrno, NO,
344: "NETCLOSE");
345: HTThreadState(file->sockfd, THD_CLOSE);
346: file->sockfd = INVSOC;
1.82 ! frystyk 347: #else
! 348: if (PROT_TRACE)
! 349: fprintf(TDEST,"FILE........ Closing file %p\n", file->fp);
! 350: fclose(file->fp);
! 351: file->fp = NULL;
! 352: #endif
1.80 frystyk 353: HTThread_clear((HTNetInfo *) file);
354: }
355: if (file->isoc)
356: HTInputSocket_free(file->isoc);
357: FREE(file->localname);
358: free(file);
359: req->net_info = NULL;
360: }
361: return status;
362: }
363:
364:
1.1 timbl 365: /* Load a document
366: ** ---------------
367: **
368: ** On entry,
1.80 frystyk 369: ** request This is the request structure
1.1 timbl 370: ** On exit,
1.77 frystyk 371: ** returns HT_ERROR Error has occured or interrupted
372: ** HT_WOULD_BLOCK We are using blocking I/O so this
373: ** indicates that we have a read a chunk
374: ** of data and now want to see what's up
375: ** in the eventloop.
1.80 frystyk 376: ** HT_LOADED if file has been loaded successfully
377: ** HT_NO_DATA if file is empty
378: ** HT_RETRY if file service is unavailable
1.1 timbl 379: */
1.36 luotonen 380: PUBLIC int HTLoadFile ARGS1 (HTRequest *, request)
1.1 timbl 381: {
1.80 frystyk 382: int status = HT_ERROR;
383: file_info *file; /* Specific access information */
1.45 luotonen 384:
1.61 frystyk 385: if (!request || !request->anchor) {
1.75 frystyk 386: if (TRACE) fprintf(TDEST, "HTLoadFile.. Called with bad argument\n");
1.77 frystyk 387: return HT_ERROR;
1.50 frystyk 388: }
1.1 timbl 389:
1.80 frystyk 390: /* Only do the setup first time through. This is actually state FILE_BEGIN
391: but it can't be in the state machine as we need the structure first */
392: if (!request->net_info) {
393: if (PROT_TRACE) {
394: char *url = HTAnchor_physical(request->anchor);
395: fprintf(TDEST, "LoadFile.... Looking for `%s\'\n", url);
396: }
397: if ((file = (file_info *) calloc(1, sizeof(file_info))) == NULL)
398: outofmem(__FILE__, "HTLoadFILE");
399: file->sockfd = INVSOC; /* Invalid socket number */
400: file->request = request;
401: request->net_info = (HTNetInfo *) file;
402: file->state = FILE_BEGIN;
403: HTThread_new((HTNetInfo *) file);
404: } else {
405: file = (file_info *) request->net_info; /* Get existing copy */
1.78 frystyk 406:
1.80 frystyk 407: /* @@@ NEED ALSO TO CHECK FOR ANSI FILE DESCRIPTORS @@@ */
1.82 ! frystyk 408: if ((file->sockfd != INVSOC && HTThreadIntr(file->sockfd)) || file->fp)
1.80 frystyk 409: file->state = FILE_ERROR;
410: }
1.36 luotonen 411:
1.80 frystyk 412: /* Now jump into the machine. We know the state from the previous run */
413: while (1) {
414: switch (file->state) {
415: case FILE_BEGIN:
416: if (HTSecure) {
417: if (PROT_TRACE)
418: fprintf(TDEST, "LoadFile.... No access to local file system\n");
419: file->state = FILE_TRY_FTP;
420: break;
421: }
422: if ((status = HTLocalName(HTAnchor_physical(request->anchor),
423: &file->localname)) == -1) {
424: file->state = FILE_ERROR;
425: break;
426: } else if (status == 0) {
427: file->state = FILE_TRY_FTP;
428: break;
1.2 timbl 429: }
1.80 frystyk 430: /*
431: ** If we have to do content negotiation then find the object that
432: ** fits best into either what the client has indicated in the
433: ** accept headers or what the client has registered on it own.
434: ** The object chosen can in fact be a directory! However, content
435: ** negotiation only makes sense it we can read the directory!
436: ** We stat the file in order to find the size and to see it if
437: ** exists.
438: */
439: {
440: struct stat stat_info; /* Contains actual file chosen */
441: if (request->ContentNegotiation) {
442: char *new_path=HTMulti(request,file->localname,&stat_info);
443: if (new_path) {
444: FREE(file->localname);
445: file->localname = new_path;
446: HTAnchor_setPhysical(request->anchor, new_path);
447: } else {
448: file->state = FILE_ERROR;
449: break;
450: }
451: } else {
452: if (HTStat(file->localname, &stat_info) == -1) {
453: if (PROT_TRACE)
454: fprintf(TDEST, "HTLoadFile.. Can't stat %s\n",
455: file->localname);
1.81 frystyk 456: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
457: NULL, 0, "HTLoadFile");
1.80 frystyk 458: file->state = FILE_ERROR;
459: break;
460: }
461: }
462: /* Check to see if the 'localname' is in fact a directory */
463: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
464: file->state = FILE_PARSE_DIR;
465: else {
466: /*
467: ** If empty file then only serve it if it is editable
468: */
469: BOOL editable = HTEditable(file->localname, &stat_info);
470: HTBind_getBindings(request->anchor);
471: if (editable)
472: HTAnchor_appendMethods(request->anchor, METHOD_PUT);
473: if (stat_info.st_size)
474: HTAnchor_setLength(request->anchor, stat_info.st_size);
475:
476: /* Put all relevant metainformation into the anchor */
477: request->anchor->header_parsed = YES;
478:
479: if (!editable && !stat_info.st_size) {
1.81 frystyk 480: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80 frystyk 481: NULL, 0, "HTLoadFile");
482: file->state = FILE_NO_DATA;
483: } else
484: file->state = FILE_NEED_OPEN_FILE;
485: }
1.2 timbl 486: }
1.80 frystyk 487: break;
1.61 frystyk 488:
1.80 frystyk 489: case FILE_NEED_OPEN_FILE:
490: /*
491: ** If we have unix file descriptors then use this otherwise use
492: ** the ANSI C file descriptors
493: */
494: #ifndef NO_UNIX_IO
495: if ((file->sockfd = open(file->localname, O_RDONLY)) == -1) {
496: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "open");
497: file->state = FILE_ERROR;
1.82 ! frystyk 498: break;
! 499: }
! 500: if (PROT_TRACE)
! 501: fprintf(TDEST,"HTLoadFile.. `%s' opened using fd %d \n",
! 502: file->localname, file->sockfd);
1.80 frystyk 503:
1.82 ! frystyk 504: /* If non-blocking protocol then change socket status
! 505: ** I use FCNTL so that I can ask the status before I set it.
! 506: ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
! 507: ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
! 508: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
! 509: ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
! 510: */
! 511: if (!HTProtocolBlocking(request)) {
! 512: if ((status = FCNTL(file->sockfd, F_GETFL, 0)) != -1) {
! 513: status |= O_NONBLOCK; /* POSIX */
! 514: status = FCNTL(file->sockfd, F_SETFL, status);
! 515: }
! 516: if (PROT_TRACE) {
! 517: if (status == -1)
! 518: fprintf(TDEST, "HTLoadFile.. Can't make socket non-blocking\n");
! 519: else
! 520: fprintf(TDEST,"HTLoadFile.. Using NON_BLOCKING I/O\n");
1.80 frystyk 521: }
1.61 frystyk 522: }
1.82 ! frystyk 523: HTThreadState(file->sockfd, THD_SET_READ);
1.80 frystyk 524: #else
1.65 duns 525: #ifdef VMS
1.82 ! frystyk 526: if (!(file->fp = fopen(file->localname,"r","shr=put","shr=upd"))) {
1.80 frystyk 527: #else
1.82 ! frystyk 528: if ((file->fp = fopen(file->localname,"r")) == NULL) {
! 529: #endif /* !VMS */
1.80 frystyk 530: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "fopen");
531: file->state = FILE_ERROR;
1.82 ! frystyk 532: break;
1.80 frystyk 533: }
1.82 ! frystyk 534: if (PROT_TRACE)
! 535: fprintf(TDEST,"HTLoadFile.. `%s' opened using FILE %p\n",
! 536: file->localname, file->fp);
1.80 frystyk 537: #endif /* !NO_UNIX_IO */
1.82 ! frystyk 538:
! 539: /* Set up read buffer and streams. If ANSI then sockfd=INVSOC */
! 540: file->isoc = HTInputSocket_new(file->sockfd);
! 541: file->target = HTStreamStack(HTAnchor_format(request->anchor),
! 542: request->output_format,
! 543: request->output_stream, request, YES);
! 544: file->state = file->target ? FILE_NEED_BODY : FILE_ERROR;
1.80 frystyk 545: break;
1.65 duns 546:
1.80 frystyk 547: case FILE_NEED_BODY:
548: #ifndef NO_UNIX_IO
549: status = HTSocketRead(request, file->target);
1.82 ! frystyk 550: #else
! 551: status = HTFileRead(file->fp, request, file->target);
! 552: #endif
1.80 frystyk 553: if (status == HT_WOULD_BLOCK)
554: return HT_WOULD_BLOCK;
555: else if (status == HT_INTERRUPTED)
556: file->state = FILE_ERROR;
557: else if (status == HT_LOADED) {
558: file->state = FILE_GOT_DATA;
1.61 frystyk 559: } else
1.80 frystyk 560: file->state = FILE_ERROR;
561: break;
1.1 timbl 562:
1.80 frystyk 563: case FILE_PARSE_DIR:
564: #ifdef GOT_READ_DIR
565: file->state = HTBrowseDirectory(request, file->localname) < 0 ?
566: FILE_ERROR : FILE_GOT_DATA;
567: #else
568: file->state = FILE_ERROR;
1.1 timbl 569: #endif
1.80 frystyk 570: break;
571:
572: case FILE_TRY_FTP:
573: {
574: char *url = HTAnchor_physical(request->anchor);
575: HTAnchor *anchor;
576: char *newname = NULL;
577: StrAllocCopy(newname, "ftp:");
578: if (!strncmp(url, "file:", 5))
579: StrAllocCat(newname, url+5);
580: else
581: StrAllocCat(newname, url);
582: anchor = HTAnchor_findAddress(newname);
583: free(newname);
584: FileCleanup(request, NO);
585: return HTLoadAnchorRecursive(anchor, request);
586: }
587: break;
1.1 timbl 588:
1.80 frystyk 589: case FILE_GOT_DATA:
590: FileCleanup(request, NO);
1.82 ! frystyk 591:
! 592: /* HT_OK means everything is OK, but not finished! */
! 593: return request->Source ? HT_OK : HT_LOADED;
1.80 frystyk 594: break;
595:
596: case FILE_NO_DATA:
597: FileCleanup(request, NO);
598: return HT_NO_DATA;
599: break;
600:
601: case FILE_RETRY:
602: FileCleanup(request, YES);
603: return HT_RETRY;
604: break;
605:
606: case FILE_ERROR:
607: FileCleanup(request, YES);
608: return HT_ERROR;
609: break;
610: }
611: } /* End of while(1) */
1.1 timbl 612: }
613:
1.80 frystyk 614:
615: /*
616: ** Protocol descriptor
617: ** Make this non-blocking is possible
618: */
619: #ifndef NO_UNIX_IO
620: GLOBALDEF PUBLIC HTProtocol HTFile = {
621: "file", SOC_NON_BLOCK, HTLoadFile, HTFileSaveStream, NULL
622: };
623: #else
1.71 frystyk 624: GLOBALDEF PUBLIC HTProtocol HTFile = {
625: "file", SOC_BLOCK, HTLoadFile, HTFileSaveStream, NULL
626: };
1.80 frystyk 627: #endif
Webmaster