Annotation of libwww/Library/src/HTFile.c, revision 1.80
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);
! 451: file->state = FILE_ERROR;
! 452: break;
! 453: }
! 454: }
! 455: /* Check to see if the 'localname' is in fact a directory */
! 456: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
! 457: file->state = FILE_PARSE_DIR;
! 458: else {
! 459: /*
! 460: ** If empty file then only serve it if it is editable
! 461: */
! 462: BOOL editable = HTEditable(file->localname, &stat_info);
! 463: HTBind_getBindings(request->anchor);
! 464: if (editable)
! 465: HTAnchor_appendMethods(request->anchor, METHOD_PUT);
! 466: if (stat_info.st_size)
! 467: HTAnchor_setLength(request->anchor, stat_info.st_size);
! 468:
! 469: /* Put all relevant metainformation into the anchor */
! 470: request->anchor->header_parsed = YES;
! 471:
! 472: if (!editable && !stat_info.st_size) {
! 473: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NO_RESPONSE,
! 474: NULL, 0, "HTLoadFile");
! 475: file->state = FILE_NO_DATA;
! 476: } else
! 477: file->state = FILE_NEED_OPEN_FILE;
! 478: }
1.2 timbl 479: }
1.80 ! frystyk 480: break;
1.61 frystyk 481:
1.80 ! frystyk 482: case FILE_NEED_OPEN_FILE:
! 483: /*
! 484: ** If we have unix file descriptors then use this otherwise use
! 485: ** the ANSI C file descriptors
! 486: */
! 487: #ifndef NO_UNIX_IO
! 488: if ((file->sockfd = open(file->localname, O_RDONLY)) == -1) {
! 489: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "open");
! 490: file->state = FILE_ERROR;
! 491: } else {
! 492: if (PROT_TRACE)
! 493: fprintf(TDEST,"HTLoadFile.. `%s' opened using fd %d \n",
! 494: file->localname, file->sockfd);
! 495:
! 496: /* If non-blocking protocol then change socket status
! 497: ** I use FCNTL so that I can ask the status before I set it.
! 498: ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
! 499: ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
! 500: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
! 501: ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
! 502: */
! 503: if (!HTProtocolBlocking(request)) {
! 504: if ((status = FCNTL(file->sockfd, F_GETFL, 0)) != -1) {
! 505: status |= O_NONBLOCK; /* POSIX */
! 506: status = FCNTL(file->sockfd, F_SETFL, status);
! 507: }
! 508: if (PROT_TRACE) {
! 509: if (status == -1)
! 510: fprintf(TDEST, "HTLoadFile.. Can't make socket non-blocking\n");
! 511: else
! 512: fprintf(TDEST, "HTLoadFile.. Using NON_BLOCKING I/O\n");
! 513: }
! 514: }
! 515:
! 516: /* Set up read buffer and streams */
! 517: file->isoc = HTInputSocket_new(file->sockfd);
! 518: file->target = HTStreamStack(HTAnchor_format(request->anchor),
! 519: request->output_format,
! 520: request->output_stream,
! 521: request, YES);
! 522: HTThreadState(file->sockfd, THD_SET_READ);
! 523: file->state = file->target ? FILE_NEED_BODY : FILE_ERROR;
1.61 frystyk 524: }
1.80 ! frystyk 525: #else
1.65 duns 526: #ifdef VMS
1.80 ! frystyk 527: if ((file->fp = fopen(file->localname,"r","shr=put","shr=upd")) == NULL) {
! 528: #else
! 529: if ((file->fp = fopen(file->localname,"r")) == NULL){
1.65 duns 530: #endif /* not VMS */
1.80 ! frystyk 531: HTErrorSysAdd(request, ERR_FATAL, errno, NO, "fopen");
! 532: file->state = FILE_ERROR;
! 533: } else {
! 534: if (PROT_TRACE)
! 535: fprintf(TDEST,"HTLoadFile.. Open `%s'\n",file->localname);
! 536: file->state = FILE_NEED_BODY;
! 537: }
! 538: #endif /* !NO_UNIX_IO */
! 539:
! 540: break;
1.65 duns 541:
1.80 ! frystyk 542: case FILE_NEED_BODY:
! 543: #ifndef NO_UNIX_IO
! 544: status = HTSocketRead(request, file->target);
! 545: if (status == HT_WOULD_BLOCK)
! 546: return HT_WOULD_BLOCK;
! 547: else if (status == HT_INTERRUPTED)
! 548: file->state = FILE_ERROR;
! 549: else if (status == HT_LOADED) {
! 550: file->state = FILE_GOT_DATA;
1.61 frystyk 551: } else
1.80 ! frystyk 552: file->state = FILE_ERROR;
! 553: #else
! 554: if (HTParseFile(HTAnchor_format(request->anchor), file->fp,
! 555: request) < 0)
! 556: file->state = FILE_ERROR;
! 557: else
! 558: file->state = FILE_GOT_DATA;
! 559: #endif
! 560: break;
1.1 timbl 561:
1.80 ! frystyk 562: case FILE_PARSE_DIR:
! 563: #ifdef GOT_READ_DIR
! 564: file->state = HTBrowseDirectory(request, file->localname) < 0 ?
! 565: FILE_ERROR : FILE_GOT_DATA;
! 566: #else
! 567: file->state = FILE_ERROR;
1.1 timbl 568: #endif
1.80 ! frystyk 569: break;
! 570:
! 571: case FILE_TRY_FTP:
! 572: {
! 573: char *url = HTAnchor_physical(request->anchor);
! 574: HTAnchor *anchor;
! 575: char *newname = NULL;
! 576: StrAllocCopy(newname, "ftp:");
! 577: if (!strncmp(url, "file:", 5))
! 578: StrAllocCat(newname, url+5);
! 579: else
! 580: StrAllocCat(newname, url);
! 581: anchor = HTAnchor_findAddress(newname);
! 582: free(newname);
! 583: FileCleanup(request, NO);
! 584: return HTLoadAnchorRecursive(anchor, request);
! 585: }
! 586: break;
1.1 timbl 587:
1.80 ! frystyk 588: case FILE_GOT_DATA:
! 589: FileCleanup(request, NO);
! 590: return HT_LOADED;
! 591: break;
! 592:
! 593: case FILE_NO_DATA:
! 594: FileCleanup(request, NO);
! 595: return HT_NO_DATA;
! 596: break;
! 597:
! 598: case FILE_RETRY:
! 599: FileCleanup(request, YES);
! 600: return HT_RETRY;
! 601: break;
! 602:
! 603: case FILE_ERROR:
! 604: FileCleanup(request, YES);
! 605: return HT_ERROR;
! 606: break;
! 607: }
! 608: } /* End of while(1) */
1.1 timbl 609: }
610:
1.80 ! frystyk 611:
! 612: /*
! 613: ** Protocol descriptor
! 614: ** Make this non-blocking is possible
! 615: */
! 616: #ifndef NO_UNIX_IO
! 617: GLOBALDEF PUBLIC HTProtocol HTFile = {
! 618: "file", SOC_NON_BLOCK, HTLoadFile, HTFileSaveStream, NULL
! 619: };
! 620: #else
1.71 frystyk 621: GLOBALDEF PUBLIC HTProtocol HTFile = {
622: "file", SOC_BLOCK, HTLoadFile, HTFileSaveStream, NULL
623: };
1.80 ! frystyk 624: #endif
Webmaster