Annotation of libwww/Library/src/HTFile.c, revision 1.100
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.95 frystyk 39: #include "HTIcons.h"
40: #include "HTDir.h"
1.78 frystyk 41: #include "HTBind.h"
1.80 frystyk 42: #include "HTSocket.h"
1.92 frystyk 43: #include "HTNetMan.h"
1.61 frystyk 44: #include "HTError.h"
1.91 frystyk 45: #include "HTReqMan.h"
1.67 frystyk 46: #include "HTFile.h" /* Implemented here */
47:
1.91 frystyk 48: /* Final states have negative value */
1.80 frystyk 49: typedef enum _FileState {
1.95 frystyk 50: FS_RETRY = -4,
51: FS_ERROR = -3,
52: FS_NO_DATA = -2,
53: FS_GOT_DATA = -1,
54: FS_BEGIN = 0,
55: FS_DO_CN,
56: FS_NEED_OPEN_FILE,
57: FS_NEED_TARGET,
58: FS_NEED_BODY,
59: FS_PARSE_DIR,
60: FS_TRY_FTP
1.80 frystyk 61: } FileState;
62:
1.91 frystyk 63: /* This is the context structure for the this module */
1.77 frystyk 64: typedef struct _file_info {
1.80 frystyk 65: FileState state; /* Current state of the connection */
1.95 frystyk 66: char * local; /* Local representation of file name */
1.91 frystyk 67: #ifdef NO_UNIX_IO
1.80 frystyk 68: FILE * fp; /* If we can't use sockets on local files */
1.91 frystyk 69: #endif
1.77 frystyk 70: } file_info;
1.2 timbl 71:
1.80 frystyk 72: /* Local definition */
73: struct _HTStream {
74: CONST HTStreamClass * isa;
1.91 frystyk 75: /* ... */
1.80 frystyk 76: };
77:
1.95 frystyk 78: PRIVATE BOOL HTTakeBackup = YES;
1.1 timbl 79:
1.95 frystyk 80: PRIVATE HTDirReadme dir_readme = HT_DIR_README_TOP;
81: PRIVATE HTDirAccess dir_access = HT_DIR_OK;
82: PRIVATE HTDirShow dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
83: PRIVATE HTDirKey dir_key = HT_DK_CINS;
1.2 timbl 84:
1.61 frystyk 85: /* ------------------------------------------------------------------------- */
1.11 timbl 86:
1.95 frystyk 87: /* Directory Access
88: ** ----------------
89: */
90: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
91: {
92: dir_access = mode;
93: return YES;
94: }
95:
96: PUBLIC HTDirAccess HTFile_dirAccess (void)
97: {
98: return dir_access;
99: }
100:
101: /* Directory Readme
102: ** ----------------
103: */
104: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
105: {
106: dir_readme = mode;
107: return YES;
108: }
109:
110: PUBLIC HTDirReadme HTFile_dirReadme (void)
111: {
112: return dir_readme;
113: }
114:
115: /* HTFile_readDir
116: ** --------------
117: ** Reads the directory "path"
118: ** Returns:
119: ** HT_ERROR Error
120: ** HT_NO_ACCESS Directory reading not allowed
121: ** HT_LOADED Successfully read the directory
1.1 timbl 122: */
1.95 frystyk 123: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1 timbl 124: {
1.95 frystyk 125: #ifndef GOT_READ_DIR
126: return HT_ERROR;
127: #else
128: DIR *dp;
129: struct stat file_info;
130: char *url = HTAnchor_physical(request->anchor);
131: char fullname[HT_MAX_PATH+1];
132: char *name;
1.98 frystyk 133: if (PROT_TRACE) TTYPrint(TDEST, "Reading..... directory\n");
1.95 frystyk 134: if (dir_access == HT_DIR_FORBID) {
1.100 ! frystyk 135: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 136: NULL, 0, "HTFile_readDir");
137: return HT_NO_ACCESS;
138: }
139:
140: /* Initialize path name for stat() */
141: if (*(name = (url+strlen(url)-1)) != '/') {
142: char *newurl = NULL;
143: StrAllocCopy(newurl, url);
144: StrAllocCat(newurl, "/");
145: FREE(file->local);
146: file->local = HTWWWToLocal(newurl, "");
147: free(newurl);
148: }
149: strcpy(fullname, file->local);
150: name = fullname+strlen(fullname); /* Point to end of fullname */
151:
152: /* Check if access is enabled */
153: if (dir_access == HT_DIR_SELECTIVE) {
154: strcpy(name, DEFAULT_DIR_FILE);
155: if (HT_STAT(fullname, &file_info)) {
1.80 frystyk 156: if (PROT_TRACE)
1.98 frystyk 157: TTYPrint(TDEST,
1.95 frystyk 158: "Read dir.... `%s\' not found\n", DEFAULT_DIR_FILE);
1.100 ! frystyk 159: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 160: NULL, 0, "HTFile_readDir");
161: return HT_NO_ACCESS;
1.1 timbl 162: }
163: }
164:
1.95 frystyk 165: if ((dp = opendir(file->local))) {
166: STRUCT_DIRENT *dirbuf;
167: HTDir *dir = HTDir_new(request, dir_show, dir_key);
168: char datestr[20];
169: char sizestr[10];
170: HTFileMode mode;
171: #ifdef HT_REENTRANT
172: STRUCT_DIRENT result; /* For readdir_r */
173: while ((dirbuf = (STRUCT_DIRENT *) readdir_r(dp, &result)))
174: #else
175: while ((dirbuf = readdir(dp)))
176: #endif /* HT_REENTRANT */
177: {
178: /* Current and parent directories are never shown in list */
179: if (!dirbuf->d_ino ||
180: !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
181: continue;
182:
183: /* Make a lstat on the file */
184: strcpy(name, dirbuf->d_name);
185: if (HT_LSTAT(fullname, &file_info)) {
186: if (PROT_TRACE)
1.98 frystyk 187: TTYPrint(TDEST, "Read dir.... lstat failed: %s\n",fullname);
1.95 frystyk 188: continue;
189: }
1.1 timbl 190:
1.95 frystyk 191: /* Convert stat info to fit our setup */
192: if ((file_info.st_mode & S_IFMT) == S_IFDIR) {
193: #ifdef VMS
194: char *dot = strstr(name, ".DIR"); /* strip .DIR part... */
195: if (dot) *dot = '\0';
196: #endif /* VMS */
197: mode = HT_IS_DIR;
198: if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
199: } else {
200: mode = HT_IS_FILE;
201: if (dir_show & HT_DS_SIZE)
202: HTNumToStr(file_info.st_size, sizestr, 10);
203: }
204: if (dir_show & HT_DS_DATE)
205: HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1 timbl 206:
1.95 frystyk 207: /* Add to the list */
208: if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
209: break;
210: }
211: closedir(dp);
212: HTDir_free(dir);
1.1 timbl 213: } else
1.100 ! frystyk 214: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "opendir");
1.95 frystyk 215: return HT_LOADED;
216: #endif /* GOT_READ_DIR */
1.1 timbl 217: }
218:
219: /* Determine write access to a file
1.2 timbl 220: ** --------------------------------
1.80 frystyk 221: ** If stat_info is NULL then the function calls stat() on it's own,
222: ** otherwise it uses the information found in stat_info
1.2 timbl 223: ** On exit,
224: ** return value YES if file can be accessed and can be written to.
225: **
226: ** Bugs:
227: ** 1. No code for non-unix systems.
228: ** 2. Isn't there a quicker way?
1.1 timbl 229: */
1.95 frystyk 230: PRIVATE BOOL HTEditable (CONST char * filename, struct stat * stat_info)
1.80 frystyk 231: {
1.75 frystyk 232: #ifndef NO_UNIX_IO
233: #ifdef NO_GROUPS
1.80 frystyk 234: return NO; /* Safe answer till we find the correct algorithm */
1.1 timbl 235: #else
1.75 frystyk 236: #ifdef NeXT
1.80 frystyk 237: int groups[NGROUPS];
1.75 frystyk 238: #else
1.80 frystyk 239: gid_t groups[NGROUPS];
1.75 frystyk 240: #endif
1.80 frystyk 241: int i;
242: uid_t myUid;
243: int ngroups; /* The number of groups */
1.1 timbl 244: struct stat fileStatus;
1.80 frystyk 245: struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.1 timbl 246:
1.80 frystyk 247: if (!stat_info) {
1.90 frystyk 248: if (HT_STAT(filename, &fileStatus))
1.80 frystyk 249: return NO; /* Can't even access file! */
250: }
1.1 timbl 251: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
252: myUid = geteuid(); /* Get my user identifier */
253:
1.95 frystyk 254: if (PROT_TRACE) {
1.1 timbl 255: int i;
1.98 frystyk 256: TTYPrint(TDEST,
1.19 timbl 257: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80 frystyk 258: (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
259: (int) fileptr->st_gid, (int) myUid, ngroups);
1.98 frystyk 260: for (i=0; i<ngroups; i++) TTYPrint(TDEST, " %d", (int) groups[i]);
261: TTYPrint(TDEST, ")\n");
1.1 timbl 262: }
263:
1.80 frystyk 264: if (fileptr->st_mode & 0002) /* I can write anyway? */
1.1 timbl 265: return YES;
266:
1.80 frystyk 267: if ((fileptr->st_mode & 0200) /* I can write my own file? */
268: && (fileptr->st_uid == myUid))
1.1 timbl 269: return YES;
270:
1.80 frystyk 271: if (fileptr->st_mode & 0020) /* Group I am in can write? */
1.1 timbl 272: {
273: for (i=0; i<ngroups; i++) {
1.80 frystyk 274: if (groups[i] == fileptr->st_gid)
1.1 timbl 275: return YES;
276: }
277: }
1.98 frystyk 278: if (PROT_TRACE) TTYPrint(TDEST, "\tFile is not editable.\n");
1.1 timbl 279: return NO; /* If no excuse, can't do */
280: #endif
1.80 frystyk 281: #else
282: /*
283: ** We don't know and can't find out. Can we be sure that when opening
284: ** a file in mode "a" that the file is not modified?
285: */
286: return NO;
287: #endif /* !NO_UNIX_IO */
1.1 timbl 288: }
1.80 frystyk 289:
1.1 timbl 290:
1.2 timbl 291: /* Make a save stream
292: ** ------------------
293: **
294: ** The stream must be used for writing back the file.
295: ** @@@ no backup done
296: */
1.29 timbl 297: PUBLIC HTStream * HTFileSaveStream ARGS1(HTRequest *, request)
1.2 timbl 298: {
299:
1.29 timbl 300: CONST char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.95 frystyk 301: char * filename = HTWWWToLocal(addr, "");
1.33 timbl 302: FILE* fp;
303:
304: /* @ Introduce CVS handling here one day
305: */
306: /* Take a backup before we do anything silly 931205
307: */
308: if (HTTakeBackup) {
1.69 frystyk 309: char * p;
310: char * backup_filename = (char *) malloc(strlen(filename)+2);
1.33 timbl 311: if (!backup_filename) outofmem(__FILE__, "taking backup");
312: strcpy(backup_filename, filename);
1.34 timbl 313: for(p=backup_filename+strlen(backup_filename);; p--) {
1.33 timbl 314: if ((*p=='/') || (p<backup_filename)) {
315: p[1]=','; /* Insert comma after slash */
316: break;
317: }
318: p[1] = p[0]; /* Move up everything to the right of it */
319: }
320:
1.65 duns 321:
322: #ifdef VMS
323: if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) { /* File exists */
324: #else /* not VMS */
1.35 luotonen 325: if ((fp=fopen(filename, "r"))) { /* File exists */
1.65 duns 326: #endif /* not VMS */
1.33 timbl 327: fclose(fp);
1.98 frystyk 328: if (PROT_TRACE) TTYPrint(TDEST, "File `%s' exists\n", filename);
1.83 frystyk 329: if (REMOVE(backup_filename)) {
1.98 frystyk 330: if (PROT_TRACE) TTYPrint(TDEST, "Backup file `%s' removed\n",
1.56 frystyk 331: backup_filename);
1.33 timbl 332: }
333: if (rename(filename, backup_filename)) { /* != 0 => Failure */
1.98 frystyk 334: if (PROT_TRACE) TTYPrint(TDEST, "Rename `%s' to `%s' FAILED!\n",
1.56 frystyk 335: filename, backup_filename);
1.33 timbl 336: } else { /* Success */
1.95 frystyk 337: if (PROT_TRACE)
1.98 frystyk 338: TTYPrint(TDEST, "Renamed `%s' to `%s'\n", filename,
1.95 frystyk 339: backup_filename);
1.33 timbl 340: }
341: }
342: free(backup_filename);
343: } /* if take backup */
1.2 timbl 344:
1.89 frystyk 345: if ((fp = fopen(filename, "wb")) == NULL) {
1.100 ! frystyk 346: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.61 frystyk 347: return NULL;
348: } else
1.40 frystyk 349: return HTFWriter_new(fp, NO);
1.2 timbl 350: }
351:
1.10 secret 352:
1.91 frystyk 353: /* FileCleanup
354: ** -----------
1.80 frystyk 355: ** This function closes the connection and frees memory.
1.91 frystyk 356: ** Returns YES on OK, else NO
1.80 frystyk 357: */
1.91 frystyk 358: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80 frystyk 359: {
1.91 frystyk 360: HTNet *net = req->net;
361: file_info *file = (file_info *) net->context;
362: if (file) {
363: #ifdef NO_UNIX_IO
364: if (file->fp) {
1.80 frystyk 365: if (PROT_TRACE)
1.98 frystyk 366: TTYPrint(TDEST,"FileCleanup. Closing file %p\n", file->fp);
1.82 frystyk 367: fclose(file->fp);
1.91 frystyk 368: }
1.82 frystyk 369: #endif
1.95 frystyk 370: FREE(file->local);
1.80 frystyk 371: free(file);
372: }
1.91 frystyk 373: HTNet_delete(net, status);
374: return YES;
1.80 frystyk 375: }
376:
377:
1.1 timbl 378: /* Load a document
379: ** ---------------
380: **
381: ** On entry,
1.80 frystyk 382: ** request This is the request structure
1.1 timbl 383: ** On exit,
1.91 frystyk 384: ** returns HT_ERROR Error has occured in call back
385: ** HT_OK Call back was OK
1.1 timbl 386: */
1.91 frystyk 387: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1 timbl 388: {
1.80 frystyk 389: int status = HT_ERROR;
1.91 frystyk 390: HTNet *net = request->net; /* Generic protocol information */
1.80 frystyk 391: file_info *file; /* Specific access information */
1.99 frystyk 392: HTParentAnchor *anchor = HTRequest_anchor(request);
1.45 luotonen 393:
1.91 frystyk 394: /*
395: ** Initiate a new file structure and bind to request structure
396: ** This is actually state FILE_BEGIN, but it can't be in the state
397: ** machine as we need the structure first.
398: */
399: if (ops == FD_NONE) {
1.98 frystyk 400: if (PROT_TRACE) TTYPrint(TDEST, "HTLoadFile.. Looking for `%s\'\n",
1.99 frystyk 401: HTAnchor_physical(anchor));
1.80 frystyk 402: if ((file = (file_info *) calloc(1, sizeof(file_info))) == NULL)
403: outofmem(__FILE__, "HTLoadFILE");
1.95 frystyk 404: file->state = FS_BEGIN;
1.91 frystyk 405: net->context = file;
406: } if (ops == FD_CLOSE) { /* Interrupted */
407: if(HTRequest_isPostWeb(request)&&!HTRequest_isMainDestination(request))
408: FileCleanup(request, HT_IGNORE);
409: else
410: FileCleanup(request, HT_INTERRUPTED);
411: return HT_OK;
412: } else
413: file = (file_info *) net->context; /* Get existing copy */
1.36 luotonen 414:
1.80 frystyk 415: /* Now jump into the machine. We know the state from the previous run */
416: while (1) {
417: switch (file->state) {
1.95 frystyk 418: case FS_BEGIN:
1.80 frystyk 419: if (HTSecure) {
420: if (PROT_TRACE)
1.98 frystyk 421: TTYPrint(TDEST, "LoadFile.... No access to local file system\n");
1.95 frystyk 422: file->state = FS_TRY_FTP;
1.80 frystyk 423: break;
424: }
1.99 frystyk 425: file->local = HTWWWToLocal(HTAnchor_physical(anchor), "");
1.95 frystyk 426: if (!file->local) {
427: file->state = FS_TRY_FTP;
1.80 frystyk 428: break;
1.2 timbl 429: }
1.86 frystyk 430:
431: /* If cache element then jump directly to OPEN FILE state */
1.99 frystyk 432: file->state = HTAnchor_cacheHit(anchor) ?
1.95 frystyk 433: FS_NEED_OPEN_FILE : FS_DO_CN;
1.86 frystyk 434: break;
435:
1.95 frystyk 436: case FS_DO_CN:
1.80 frystyk 437: /*
438: ** If we have to do content negotiation then find the object that
439: ** fits best into either what the client has indicated in the
1.86 frystyk 440: ** accept headers or what the client has registered on its own.
1.80 frystyk 441: ** The object chosen can in fact be a directory! However, content
442: ** negotiation only makes sense it we can read the directory!
443: ** We stat the file in order to find the size and to see it if
444: ** exists.
445: */
446: {
447: struct stat stat_info; /* Contains actual file chosen */
448: if (request->ContentNegotiation) {
1.95 frystyk 449: char *new_path=HTMulti(request,file->local,&stat_info);
1.80 frystyk 450: if (new_path) {
1.95 frystyk 451: FREE(file->local);
452: file->local = new_path;
1.99 frystyk 453: HTAnchor_setPhysical(anchor, new_path);
1.80 frystyk 454: } else {
1.95 frystyk 455: file->state = FS_ERROR;
1.80 frystyk 456: break;
457: }
458: } else {
1.95 frystyk 459: if (HT_STAT(file->local, &stat_info) == -1) {
1.80 frystyk 460: if (PROT_TRACE)
1.98 frystyk 461: TTYPrint(TDEST, "HTLoadFile.. Can't stat %s\n",
1.95 frystyk 462: file->local);
1.100 ! frystyk 463: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.81 frystyk 464: NULL, 0, "HTLoadFile");
1.95 frystyk 465: file->state = FS_ERROR;
1.80 frystyk 466: break;
467: }
468: }
469: /* Check to see if the 'localname' is in fact a directory */
470: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
1.95 frystyk 471: file->state = FS_PARSE_DIR;
1.80 frystyk 472: else {
473: /*
474: ** If empty file then only serve it if it is editable
475: */
1.95 frystyk 476: BOOL editable = HTEditable(file->local, &stat_info);
1.99 frystyk 477: HTBind_getBindings(anchor);
1.80 frystyk 478: if (editable)
1.99 frystyk 479: HTAnchor_appendMethods(anchor, METHOD_PUT);
1.80 frystyk 480: if (stat_info.st_size)
1.99 frystyk 481: HTAnchor_setLength(anchor, stat_info.st_size);
1.80 frystyk 482:
1.83 frystyk 483: /* Done with relevant metainformation in anchor */
1.99 frystyk 484: HTAnchor_setHeaderParsed(anchor);
1.80 frystyk 485:
486: if (!editable && !stat_info.st_size) {
1.100 ! frystyk 487: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80 frystyk 488: NULL, 0, "HTLoadFile");
1.95 frystyk 489: file->state = FS_NO_DATA;
1.80 frystyk 490: } else
1.95 frystyk 491: file->state = FS_NEED_OPEN_FILE;
1.80 frystyk 492: }
1.2 timbl 493: }
1.80 frystyk 494: break;
1.61 frystyk 495:
1.95 frystyk 496: case FS_NEED_OPEN_FILE:
1.80 frystyk 497: /*
498: ** If we have unix file descriptors then use this otherwise use
499: ** the ANSI C file descriptors
500: */
501: #ifndef NO_UNIX_IO
1.95 frystyk 502: if ((net->sockfd = open(file->local, O_RDONLY)) == -1) {
1.100 ! frystyk 503: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "open");
1.95 frystyk 504: file->state = FS_ERROR;
1.82 frystyk 505: break;
506: }
507: if (PROT_TRACE)
1.98 frystyk 508: TTYPrint(TDEST,"HTLoadFile.. `%s' opened using socket %d \n",
1.95 frystyk 509: file->local, net->sockfd);
1.80 frystyk 510:
1.82 frystyk 511: /* If non-blocking protocol then change socket status
512: ** I use FCNTL so that I can ask the status before I set it.
513: ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
514: ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
515: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
516: ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
517: */
1.85 frystyk 518: #ifndef NO_FCNTL
1.91 frystyk 519: if (!request->net->preemtive) {
520: if ((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
1.82 frystyk 521: status |= O_NONBLOCK; /* POSIX */
1.91 frystyk 522: status = FCNTL(net->sockfd, F_SETFL, status);
1.82 frystyk 523: }
524: if (PROT_TRACE) {
525: if (status == -1)
1.98 frystyk 526: TTYPrint(TDEST, "HTLoadFile.. Can't make socket non-blocking\n");
1.82 frystyk 527: else
1.98 frystyk 528: TTYPrint(TDEST,"HTLoadFile.. Using NON_BLOCKING I/O\n");
1.80 frystyk 529: }
1.61 frystyk 530: }
1.85 frystyk 531: #endif /* NO_FCNTL */
1.80 frystyk 532: #else
1.83 frystyk 533: #ifdef VMS
1.95 frystyk 534: if (!(file->fp = fopen(file->local,"r","shr=put","shr=upd"))) {
1.80 frystyk 535: #else
1.95 frystyk 536: if ((file->fp = fopen(file->local,"r")) == NULL) {
1.82 frystyk 537: #endif /* !VMS */
1.100 ! frystyk 538: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.95 frystyk 539: file->state = FS_ERROR;
1.82 frystyk 540: break;
1.80 frystyk 541: }
1.82 frystyk 542: if (PROT_TRACE)
1.98 frystyk 543: TTYPrint(TDEST,"HTLoadFile.. `%s' opened using FILE %p\n",
1.95 frystyk 544: file->local, file->fp);
1.80 frystyk 545: #endif /* !NO_UNIX_IO */
1.95 frystyk 546: file->state = FS_NEED_TARGET;
1.83 frystyk 547: break;
548:
1.95 frystyk 549: case FS_NEED_TARGET:
1.83 frystyk 550: /*
551: ** We need to wait for the destinations to get ready
552: */
553: if (HTRequest_isSource(request) && !request->output_stream)
1.91 frystyk 554: return HT_OK;
1.83 frystyk 555: /*
556: ** Set up concurrent read/write if this request isn't the
557: ** source for a PUT or POST. As source we don't start reading
558: ** before all destinations are ready. If destination then
559: ** register the input stream and get ready for read
560: */
561: if (HTRequest_isPostWeb(request)) {
1.91 frystyk 562: HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
563: HTLoadFile, net->priority);
1.83 frystyk 564: HTRequest_linkDestination(request);
565: }
1.82 frystyk 566:
1.86 frystyk 567: /*
568: ** Set up read buffer and streams.
569: ** If cache element, we know that it's MIME, so call MIME parser
570: ** If ANSI then sockfd=INVSOC
571: */
1.91 frystyk 572: net->isoc = HTInputSocket_new(net->sockfd);
1.99 frystyk 573: if (HTAnchor_cacheHit(anchor))HTAnchor_setFormat(anchor, WWW_MIME);
574: net->target = HTStreamStack(HTAnchor_format(anchor),
575: request->output_format,
576: request->output_stream,
577: request, YES);
1.95 frystyk 578: file->state = net->target ? FS_NEED_BODY : FS_ERROR;
1.80 frystyk 579: break;
1.65 duns 580:
1.95 frystyk 581: case FS_NEED_BODY:
1.80 frystyk 582: #ifndef NO_UNIX_IO
1.94 frystyk 583: status = HTSocketRead(request, net);
1.82 frystyk 584: #else
1.94 frystyk 585: status = HTFileRead(request, net, file->fp);
1.82 frystyk 586: #endif
1.80 frystyk 587: if (status == HT_WOULD_BLOCK)
1.91 frystyk 588: return HT_OK;
1.80 frystyk 589: else if (status == HT_LOADED) {
1.95 frystyk 590: file->state = FS_GOT_DATA;
1.61 frystyk 591: } else
1.95 frystyk 592: file->state = FS_ERROR;
1.80 frystyk 593: break;
1.1 timbl 594:
1.95 frystyk 595: case FS_PARSE_DIR:
596: status = HTFile_readDir(request, file);
597: if (status == HT_LOADED)
598: file->state = FS_GOT_DATA;
599: else
600: file->state = FS_ERROR;
1.80 frystyk 601: break;
602:
1.95 frystyk 603: case FS_TRY_FTP:
1.80 frystyk 604: {
1.99 frystyk 605: char *url = HTAnchor_physical(anchor);
1.80 frystyk 606: HTAnchor *anchor;
607: char *newname = NULL;
608: StrAllocCopy(newname, "ftp:");
609: if (!strncmp(url, "file:", 5))
610: StrAllocCat(newname, url+5);
611: else
612: StrAllocCat(newname, url);
613: anchor = HTAnchor_findAddress(newname);
614: free(newname);
1.91 frystyk 615: FileCleanup(request, HT_IGNORE);
1.97 frystyk 616: return HTLoad(request, YES);
1.80 frystyk 617: }
618: break;
1.1 timbl 619:
1.95 frystyk 620: case FS_GOT_DATA:
1.83 frystyk 621: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 622: FileCleanup(request, HTRequest_isMainDestination(request) ?
623: HT_ERROR : HT_IGNORE);
1.87 frystyk 624: if (HTRequest_isDestination(request)) {
625: HTLink *link =
626: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 627: (HTAnchor *) anchor);
1.87 frystyk 628: HTAnchor_setLinkResult(link, HT_LINK_OK);
629: }
1.83 frystyk 630: HTRequest_removeDestination(request);
1.91 frystyk 631: } else
632: FileCleanup(request, HT_LOADED);
633: return HT_OK;
1.80 frystyk 634: break;
635:
1.95 frystyk 636: case FS_NO_DATA:
1.83 frystyk 637: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 638: FileCleanup(request, HTRequest_isMainDestination(request) ?
639: HT_ERROR : HT_IGNORE);
1.87 frystyk 640: if (HTRequest_isDestination(request)) {
641: HTLink *link =
642: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 643: (HTAnchor *) anchor);
1.87 frystyk 644: HTAnchor_setLinkResult(link, HT_LINK_OK);
645: }
1.83 frystyk 646: HTRequest_removeDestination(request);
1.91 frystyk 647: } else
648: FileCleanup(request, HT_NO_DATA);
649: return HT_OK;
1.80 frystyk 650: break;
651:
1.95 frystyk 652: case FS_RETRY:
1.83 frystyk 653: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 654: FileCleanup(request, HTRequest_isMainDestination(request) ?
655: HT_ERROR : HT_IGNORE);
1.87 frystyk 656: HTRequest_killPostWeb(request);
657: if (HTRequest_isDestination(request)) {
658: HTLink *link =
659: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 660: (HTAnchor *) anchor);
1.87 frystyk 661: HTAnchor_setLinkResult(link, HT_LINK_ERROR);
662: }
1.83 frystyk 663: HTRequest_removeDestination(request);
1.87 frystyk 664: } else
1.91 frystyk 665: FileCleanup(request, HT_RETRY);
666: return HT_OK;
1.80 frystyk 667: break;
668:
1.95 frystyk 669: case FS_ERROR:
1.83 frystyk 670: /* Clean up the other connections or just this one */
671: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 672: FileCleanup(request, HTRequest_isMainDestination(request) ?
673: HT_ERROR : HT_IGNORE);
1.83 frystyk 674: HTRequest_killPostWeb(request);
1.87 frystyk 675: if (HTRequest_isDestination(request)) {
676: HTLink *link =
677: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 678: (HTAnchor *) anchor);
1.87 frystyk 679: HTAnchor_setLinkResult(link, HT_LINK_ERROR);
680: }
681: HTRequest_removeDestination(request);
1.83 frystyk 682: } else
1.91 frystyk 683: FileCleanup(request, HT_ERROR);
684: return HT_OK;
1.80 frystyk 685: break;
686: }
687: } /* End of while(1) */
1.1 timbl 688: }
Webmaster