Annotation of libwww/Library/src/HTFile.c, revision 1.61
1.1 timbl 1: /* File Access HTFile.c
2: ** ===========
3: **
4: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 5: ** These are routines for file access used by browsers.
1.1 timbl 6: **
7: ** History:
8: ** Feb 91 Written Tim Berners-Lee CERN/CN
9: ** Apr 91 vms-vms access included using DECnet syntax
10: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
11: ** Fixed access bug for relative names on VMS.
1.28 duns 12: ** Sep 93 (MD) Access to VMS files allows sharing.
13: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 14: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 ! frystyk 15: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
! 16: ** error messages introduced etc.
1.1 timbl 17: **
18: ** Bugs:
1.2 timbl 19: ** FTP: Cannot access VMS files from a unix machine.
20: ** How can we know that the
1.1 timbl 21: ** target machine runs VMS?
22: */
23:
1.2 timbl 24: #include "HTFile.h" /* Implemented here */
25:
1.61 ! frystyk 26: #ifdef VMS
! 27: #define NO_GROUPS /* MOVE TO tcp.html */
1.1 timbl 28: #define INFINITY 512 /* file name length @@ FIXME */
1.52 duns 29: PRIVATE char * suffix_separators = "._";
1.36 luotonen 30: #else
1.49 luotonen 31: PRIVATE char * suffix_separators = ".,_";
1.61 ! frystyk 32: #endif /* VMS */
1.1 timbl 33:
34: #include "HTUtils.h"
35:
1.28 duns 36: #ifdef VMS
37: #include "HTVMSUtils.h"
38: #endif /* VMS */
39:
1.61 ! frystyk 40: #include "tcp.h"
1.1 timbl 41: #include "HTParse.h"
42: #include "HTTCP.h"
1.61 ! frystyk 43: #ifndef DECNET /* Temporary ? */
1.1 timbl 44: #include "HTFTP.h"
45: #endif
46: #include "HTAnchor.h"
1.2 timbl 47: #include "HTAtom.h"
48: #include "HTWriter.h"
49: #include "HTFWriter.h"
50: #include "HTInit.h"
1.7 secret 51: #include "HTBTree.h"
1.52 duns 52: #include "HTFormat.h"
1.54 luotonen 53: #include "HTMulti.h"
1.61 ! frystyk 54: #include "HTError.h"
1.37 luotonen 55:
1.2 timbl 56: typedef struct _HTSuffix {
57: char * suffix;
1.36 luotonen 58: HTAtom * rep; /* Content-Type */
59: HTAtom * encoding; /* Content-Encoding */
60: HTAtom * language; /* Content-Language */
1.2 timbl 61: float quality;
62: } HTSuffix;
63:
64:
65: /* Controlling globals
66: **
67: */
68:
1.33 timbl 69: PUBLIC BOOL HTTakeBackup = YES;
1.47 luotonen 70: PUBLIC BOOL HTSuffixCaseSense = NO; /* Are suffixes case sensitive */
1.1 timbl 71:
72: PRIVATE char *HTMountRoot = "/Net/"; /* Where to find mounts */
1.23 duns 73: #ifdef VMS
1.28 duns 74: PRIVATE char *HTCacheRoot = "/WWW$SCRATCH"; /* Where to cache things */
1.1 timbl 75: #else
76: PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */
77: #endif
78:
79: /* PRIVATE char *HTSaveRoot = "$(HOME)/WWW/";*/ /* Where to save things */
80:
1.2 timbl 81:
82: /* Suffix registration
83: */
84:
85: PRIVATE HTList * HTSuffixes = 0;
1.36 luotonen 86: PRIVATE HTSuffix no_suffix = { "*", NULL, NULL, NULL, 1.0 };
87: PRIVATE HTSuffix unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0};
1.2 timbl 88:
1.61 ! frystyk 89: /* ------------------------------------------------------------------------- */
1.11 timbl 90:
1.2 timbl 91: /* Define the representation associated with a file suffix
92: ** -------------------------------------------------------
1.11 timbl 93: **
94: ** Calling this with suffix set to "*" will set the default
95: ** representation.
96: ** Calling this with suffix set to "*.*" will set the default
97: ** representation for unknown suffix files which contain a ".".
1.25 luotonen 98: **
99: ** If filename suffix is already defined its previous
100: ** definition is overridden.
1.2 timbl 101: */
1.36 luotonen 102: PUBLIC void HTAddType ARGS4(CONST char *, suffix,
103: CONST char *, representation,
104: CONST char *, encoding,
105: float, value)
106: {
107: HTSetSuffix(suffix, representation, encoding, NULL, value);
108: }
109:
110:
111: PUBLIC void HTAddEncoding ARGS3(CONST char *, suffix,
112: CONST char *, encoding,
113: float, value)
114: {
115: HTSetSuffix(suffix, NULL, encoding, NULL, value);
116: }
117:
118:
119: PUBLIC void HTAddLanguage ARGS3(CONST char *, suffix,
120: CONST char *, language,
121: float, value)
122: {
123: HTSetSuffix(suffix, NULL, NULL, language, value);
124: }
125:
126:
127: PUBLIC void HTSetSuffix ARGS5(CONST char *, suffix,
128: CONST char *, representation,
129: CONST char *, encoding,
130: CONST char *, language,
131: float, value)
1.2 timbl 132: {
1.11 timbl 133: HTSuffix * suff;
1.25 luotonen 134:
1.19 timbl 135: if (strcmp(suffix, "*")==0) suff = &no_suffix;
136: else if (strcmp(suffix, "*.*")==0) suff = &unknown_suffix;
137: else {
1.25 luotonen 138: HTList *cur = HTSuffixes;
139:
140: while (NULL != (suff = (HTSuffix*)HTList_nextObject(cur))) {
141: if (suff->suffix && 0==strcmp(suff->suffix, suffix))
142: break;
143: }
144: if (!suff) { /* Not found -- create a new node */
145: suff = (HTSuffix*) calloc(1, sizeof(HTSuffix));
146: if (suff == NULL) outofmem(__FILE__, "HTSetSuffix");
1.36 luotonen 147:
1.25 luotonen 148: if (!HTSuffixes) HTSuffixes = HTList_new();
149: HTList_addObject(HTSuffixes, suff);
1.36 luotonen 150:
1.25 luotonen 151: StrAllocCopy(suff->suffix, suffix);
152: }
1.11 timbl 153: }
1.19 timbl 154:
1.36 luotonen 155: if (representation)
156: suff->rep = HTAtom_for(representation);
157: if (language)
158: suff->language = HTAtom_for(language);
159: if (encoding) {
1.38 luotonen 160: char * enc = NULL;
1.19 timbl 161: char * p;
162: StrAllocCopy(enc, encoding);
163: for (p=enc; *p; p++) *p = TOLOWER(*p);
1.38 luotonen 164: suff->encoding = HTAtom_for(enc);
165: free(enc); /* Leak fixed AL 6 Feb 1994 */
1.11 timbl 166: }
1.36 luotonen 167:
1.2 timbl 168: suff->quality = value;
169: }
170:
171:
1.36 luotonen 172: PRIVATE BOOL is_separator ARGS1(char, ch)
173: {
174: if (strchr(suffix_separators, ch)) return YES;
175: else return NO;
176: }
177:
178:
1.53 luotonen 179: /* PUBLIC HTSplitFilename()
1.36 luotonen 180: **
181: ** Split the filename to an array of suffixes.
182: ** Return the number of parts placed to the array.
183: ** Array should have MAX_SUFF+1 items.
184: */
1.53 luotonen 185: PUBLIC int HTSplitFilename ARGS2(char *, s_str,
1.36 luotonen 186: char **, s_arr)
187: {
188: char * start = s_str;
189: char * end;
190: char save;
191: int i;
192:
193: if (!s_str || !s_arr) return 0;
194:
195: for (i=0; i < MAX_SUFF && *start; i++) {
196: for(end=start+1; *end && !is_separator(*end); end++);
197: save = *end;
198: *end = 0;
1.38 luotonen 199: StrAllocCopy(s_arr[i], start); /* Frees the previous value */
1.36 luotonen 200: *end = save;
201: start = end;
202: }
203: FREE(s_arr[i]); /* Terminating NULL */
204: return i;
205: }
206:
207:
208:
1.53 luotonen 209: PUBLIC HTContentDescription * HTGetContentDescription ARGS2(char **, actual,
210: int, n)
1.36 luotonen 211: {
212: HTContentDescription * cd;
213: int i;
214:
215: #ifndef NO_INIT
216: if (!HTSuffixes) HTFileInit();
217: #endif
218:
1.47 luotonen 219: if (n < 2) return NULL; /* No suffix */
220:
1.36 luotonen 221: cd = (HTContentDescription*)calloc(1, sizeof(HTContentDescription));
222: if (!cd) outofmem(__FILE__, "HTContentDescription");
223:
224: cd->quality = 1.0;
225:
226: for (i=n-1; i>0; i--) {
227: HTList * cur = HTSuffixes;
228: HTSuffix * suff;
229: BOOL found = NO;
230:
1.47 luotonen 231: CTRACE(stderr, "Searching... for suffix %d: \"%s\"\n", i, actual[i]);
1.36 luotonen 232:
233: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
1.47 luotonen 234: if ((HTSuffixCaseSense && !strcmp(suff->suffix, actual[i])) ||
235: (!HTSuffixCaseSense && !strcasecomp(suff->suffix, actual[i]))){
1.36 luotonen 236:
237: if (!cd->content_type)
238: cd->content_type = suff->rep;
239: if (!cd->content_encoding)
240: cd->content_encoding = suff->encoding;
241: if (!cd->content_language)
242: cd->content_language = suff->language;
1.47 luotonen 243: if (suff->quality > 0.0000001)
244: cd->quality *= suff->quality;
1.36 luotonen 245:
246: found = YES;
247: break;
248: }
249: }
250: if (!found) {
251: if (i < n-1)
252: break;
253: else {
254: free(cd);
255: return NULL;
256: }
257: }
258: }
259: return cd;
260: }
261:
1.2 timbl 262:
263:
1.1 timbl 264: /* Make the cache file name for a W3 document
265: ** ------------------------------------------
266: ** Make up a suitable name for saving the node in
267: **
268: ** E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch
269: ** /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
270: **
271: ** On exit,
272: ** returns a malloc'ed string which must be freed by the caller.
273: */
274: PUBLIC char * HTCacheFileName ARGS1(CONST char *,name)
275: {
276: char * access = HTParse(name, "", PARSE_ACCESS);
277: char * host = HTParse(name, "", PARSE_HOST);
278: char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
279:
280: char * result;
281: result = (char *)malloc(
282: strlen(HTCacheRoot)+strlen(access)
283: +strlen(host)+strlen(path)+6+1);
284: if (result == NULL) outofmem(__FILE__, "HTCacheFileName");
285: sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, access, host, path);
286: free(path);
287: free(access);
288: free(host);
289: return result;
290: }
291:
1.2 timbl 292:
1.1 timbl 293: /* Open a file for write, creating the path
294: ** ----------------------------------------
295: */
296: #ifdef NOT_IMPLEMENTED
297: PRIVATE int HTCreatePath ARGS1(CONST char *,path)
298: {
299: return -1;
300: }
301: #endif
302:
303: /* Convert filenames between local and WWW formats
304: ** -----------------------------------------------
305: ** Make up a suitable name for saving the node in
306: **
307: ** E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch
308: ** $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
309: **
310: ** On exit,
311: ** returns a malloc'ed string which must be freed by the caller.
1.61 ! frystyk 312: **
! 313: ** BUG: FILENAME IS NOT UNESCAPED!!!!!!
! 314: **
1.1 timbl 315: */
316: PUBLIC char * HTLocalName ARGS1(CONST char *,name)
317: {
318: char * access = HTParse(name, "", PARSE_ACCESS);
319: char * host = HTParse(name, "", PARSE_HOST);
320: char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
321:
1.6 timbl 322: HTUnEscape(path); /* Interpret % signs */
1.36 luotonen 323:
1.60 luotonen 324: /*
325: * CERN httpd has it's own enhanced rule system which has already
326: * done the mappings, and the local filename ("physical address")
327: * is stored in HTImServer.
328: */
1.49 luotonen 329: if (HTImServer && !*access) {
1.47 luotonen 330: free(access);
331: free(host);
1.60 luotonen 332: StrAllocCopy(path, HTImServer);
333: HTUnEscape(path);
1.47 luotonen 334: CTRACE(stderr, "Local filename is \"%s\"\n", path);
335: return(path);
336: }
337:
1.27 duns 338: if (0==strcmp(access, "file")) { /* local file */
1.1 timbl 339: free(access);
1.9 timbl 340: if ((0==strcasecomp(host, HTHostName())) ||
341: (0==strcasecomp(host, "localhost")) || !*host) {
1.1 timbl 342: free(host);
1.61 ! frystyk 343: if (TRACE) fprintf(stderr, "Node........ `%s' means path `%s'\n", name, path);
1.1 timbl 344: return(path);
345: } else {
346: char * result = (char *)malloc(
347: strlen("/Net/")+strlen(host)+strlen(path)+1);
348: if (result == NULL) outofmem(__FILE__, "HTLocalName");
349: sprintf(result, "%s%s%s", "/Net/", host, path);
350: free(host);
351: free(path);
1.61 ! frystyk 352: if (TRACE) fprintf(stderr, "Node........ `%s' means file `%s'\n", name, result);
1.1 timbl 353: return result;
354: }
355: } else { /* other access */
356: char * result;
357: CONST char * home = (CONST char*)getenv("HOME");
1.28 duns 358: #ifdef VMS
359: if (!home)
360: home = HTCacheRoot;
361: else
362: home = HTVMS_wwwName(home);
363: #else /* not VMS */
1.1 timbl 364: if (!home) home = "/tmp";
1.28 duns 365: #endif /* not VMS */
1.1 timbl 366: result = (char *)malloc(
367: strlen(home)+strlen(access)+strlen(host)+strlen(path)+6+1);
368: if (result == NULL) outofmem(__FILE__, "HTLocalName");
369: sprintf(result, "%s/WWW/%s/%s%s", home, access, host, path);
370: free(path);
371: free(access);
372: free(host);
373: return result;
374: }
375: }
376:
377:
378: /* Make a WWW name from a full local path name
379: **
380: ** Bugs:
381: ** At present, only the names of two network root nodes are hand-coded
382: ** in and valid for the NeXT only. This should be configurable in
383: ** the general case.
384: */
385:
386: PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name)
387: {
388: char * result;
389: #ifdef NeXT
390: if (0==strncmp("/private/Net/", name, 13)) {
391: result = (char *)malloc(7+strlen(name+13)+1);
392: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
393: sprintf(result, "file://%s", name+13);
394: } else
395: #endif
396: if (0==strncmp(HTMountRoot, name, 5)) {
397: result = (char *)malloc(7+strlen(name+5)+1);
398: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
399: sprintf(result, "file://%s", name+5);
400: } else {
401: result = (char *)malloc(7+strlen(HTHostName())+strlen(name)+1);
402: if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
403: sprintf(result, "file://%s%s", HTHostName(), name);
404: }
405: if (TRACE) fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result);
406: return result;
407: }
408:
409:
1.2 timbl 410: /* Determine a suitable suffix, given the representation
411: ** -----------------------------------------------------
412: **
413: ** On entry,
414: ** rep is the atomized MIME style representation
415: **
416: ** On exit,
417: ** returns a pointer to a suitable suffix string if one has been
418: ** found, else "".
419: */
420: PUBLIC CONST char * HTFileSuffix ARGS1(HTAtom*, rep)
421: {
422: HTSuffix * suff;
1.35 luotonen 423: HTList * cur;
1.2 timbl 424:
425: #ifndef NO_INIT
426: if (!HTSuffixes) HTFileInit();
427: #endif
1.35 luotonen 428: cur = HTSuffixes;
429: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
1.2 timbl 430: if (suff->rep == rep) {
431: return suff->suffix; /* OK -- found */
432: }
433: }
434: return ""; /* Dunno */
435: }
436:
437:
1.1 timbl 438: /* Determine file format from file name
439: ** ------------------------------------
440: **
1.19 timbl 441: ** This version will return the representation and also set
442: ** a variable for the encoding.
443: **
444: ** It will handle for example x.txt, x.txt,Z, x.Z
1.2 timbl 445: */
446:
1.47 luotonen 447: PUBLIC HTFormat HTFileFormat ARGS3(CONST char *, filename,
448: HTAtom **, pencoding,
449: HTAtom **, planguage)
450: {
451: char * actual[MAX_SUFF+1];
452: int n;
453: HTContentDescription * cd;
454: HTFormat content_type = NULL;
455:
456: if (!filename) return WWW_BINARY;
457:
458: #ifndef NO_INIT
459: if (!HTSuffixes) HTFileInit();
460: #endif
461:
462: for (n=0; n<MAX_SUFF+1; n++) actual[n] = NULL;
1.53 luotonen 463: n = HTSplitFilename((char*)filename, actual);
464: cd = HTGetContentDescription(actual, n);
1.47 luotonen 465: while(n-- > 0) if (actual[n]) free(actual[n]);
466:
467: if (cd) {
468: if (pencoding) *pencoding = cd->content_encoding;
469: if (planguage) *planguage = cd->content_language;
470: content_type = cd->content_type;
471: free(cd);
472: }
473: else {
474: HTSuffix * suff = strchr(filename,'.') ?
475: (unknown_suffix.rep ? &unknown_suffix : &no_suffix) :
476: &no_suffix;
477:
478: if (pencoding) *pencoding = suff->encoding;
479: if (planguage) *planguage = suff->language;
480: content_type = suff->rep;
481: }
482:
483: if (pencoding && !*pencoding)
484: *pencoding = HTAtom_for("binary");
485: return content_type ? content_type : WWW_BINARY;
486: }
1.2 timbl 487:
488:
489: /* Determine value from file name
490: ** ------------------------------
1.1 timbl 491: **
492: */
493:
1.2 timbl 494: PUBLIC float HTFileValue ARGS1 (CONST char *,filename)
495:
1.1 timbl 496: {
1.2 timbl 497: HTSuffix * suff;
1.35 luotonen 498: HTList * cur;
1.2 timbl 499: int lf = strlen(filename);
500:
501: #ifndef NO_INIT
502: if (!HTSuffixes) HTFileInit();
503: #endif
1.35 luotonen 504: cur = HTSuffixes;
505: while ((suff = (HTSuffix*)HTList_nextObject(cur))) {
506: int ls = strlen(suff->suffix);
1.2 timbl 507: if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
1.61 ! frystyk 508: if (TRACE) fprintf(stderr, "File Value.. Value of %s is %.3f\n",
1.2 timbl 509: filename, suff->quality);
510: return suff->quality; /* OK -- found */
511: }
512: }
513: return 0.3; /* Dunno! */
1.1 timbl 514: }
515:
516:
517: /* Determine write access to a file
1.2 timbl 518: ** --------------------------------
519: **
520: ** On exit,
521: ** return value YES if file can be accessed and can be written to.
522: **
523: ** Bugs:
524: ** 1. No code for non-unix systems.
525: ** 2. Isn't there a quicker way?
1.1 timbl 526: */
1.61 ! frystyk 527: #ifndef NO_UNIX_IO
1.1 timbl 528: PUBLIC BOOL HTEditable ARGS1 (CONST char *,filename)
529: {
530: #ifdef NO_GROUPS
531: return NO; /* Safe answer till we find the correct algorithm */
532: #else
1.44 frystyk 533: #ifdef NeXT
534: int groups[NGROUPS];
535: #else
536: gid_t groups[NGROUPS];
537: #endif
1.1 timbl 538: uid_t myUid;
539: int ngroups; /* The number of groups */
540: struct stat fileStatus;
541: int i;
542:
543: if (stat(filename, &fileStatus)) /* Get details of filename */
544: return NO; /* Can't even access file! */
545:
546: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
547: myUid = geteuid(); /* Get my user identifier */
548:
549: if (TRACE) {
550: int i;
1.19 timbl 551: fprintf(stderr,
552: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.5 timbl 553: (unsigned int) fileStatus.st_mode, fileStatus.st_uid,
554: fileStatus.st_gid,
1.1 timbl 555: myUid, ngroups);
1.19 timbl 556: for (i=0; i<ngroups; i++) fprintf(stderr, " %d", groups[i]);
557: fprintf(stderr, ")\n");
1.1 timbl 558: }
559:
560: if (fileStatus.st_mode & 0002) /* I can write anyway? */
561: return YES;
562:
563: if ((fileStatus.st_mode & 0200) /* I can write my own file? */
564: && (fileStatus.st_uid == myUid))
565: return YES;
566:
567: if (fileStatus.st_mode & 0020) /* Group I am in can write? */
568: {
569: for (i=0; i<ngroups; i++) {
570: if (groups[i] == fileStatus.st_gid)
571: return YES;
572: }
573: }
574: if (TRACE) fprintf(stderr, "\tFile is not editable.\n");
575: return NO; /* If no excuse, can't do */
576: #endif
577: }
1.61 ! frystyk 578: #endif /* NO_UNIX_IO */
1.1 timbl 579:
1.2 timbl 580: /* Make a save stream
581: ** ------------------
582: **
583: ** The stream must be used for writing back the file.
584: ** @@@ no backup done
585: */
1.29 timbl 586: PUBLIC HTStream * HTFileSaveStream ARGS1(HTRequest *, request)
1.2 timbl 587: {
588:
1.29 timbl 589: CONST char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.33 timbl 590: char * filename = HTLocalName(addr);
591: FILE* fp;
592:
593: /* @ Introduce CVS handling here one day
594: */
595: /* Take a backup before we do anything silly 931205
596: */
597: if (HTTakeBackup) {
598: char * backup_filename = 0;
599: char * p = backup_filename;
600: backup_filename = malloc(strlen(filename)+2);
601: if (!backup_filename) outofmem(__FILE__, "taking backup");
602: strcpy(backup_filename, filename);
1.34 timbl 603: for(p=backup_filename+strlen(backup_filename);; p--) {
1.33 timbl 604: if ((*p=='/') || (p<backup_filename)) {
605: p[1]=','; /* Insert comma after slash */
606: break;
607: }
608: p[1] = p[0]; /* Move up everything to the right of it */
609: }
610:
1.35 luotonen 611: if ((fp=fopen(filename, "r"))) { /* File exists */
1.33 timbl 612: fclose(fp);
1.56 frystyk 613: if (TRACE) fprintf(stderr, "File `%s' exists\n", filename);
1.33 timbl 614: if (remove(backup_filename)) {
1.56 frystyk 615: if (TRACE) fprintf(stderr, "Backup file `%s' removed\n",
616: backup_filename);
1.33 timbl 617: }
618: if (rename(filename, backup_filename)) { /* != 0 => Failure */
1.56 frystyk 619: if (TRACE) fprintf(stderr, "Rename `%s' to `%s' FAILED!\n",
620: filename, backup_filename);
1.33 timbl 621: } else { /* Success */
1.56 frystyk 622: if (TRACE) fprintf(stderr, "Renamed `%s' to `%s'\n", filename,
623: backup_filename);
1.33 timbl 624: }
625: }
626: free(backup_filename);
627: } /* if take backup */
1.2 timbl 628:
1.61 ! frystyk 629: if ((fp = fopen(filename, "w")) == NULL) {
! 630: HTErrorSysAdd(request, ERR_FATAL, NO, "fopen");
! 631: return NULL;
! 632: } else
1.40 frystyk 633: return HTFWriter_new(fp, NO);
1.2 timbl 634: }
635:
1.10 secret 636:
1.1 timbl 637: /* Load a document
638: ** ---------------
639: **
640: ** On entry,
641: ** addr must point to the fully qualified hypertext reference.
642: ** This is the physsical address of the file
643: **
644: ** On exit,
1.2 timbl 645: ** returns <0 Error has occured.
646: ** HTLOADED OK
1.1 timbl 647: **
648: */
1.36 luotonen 649: PUBLIC int HTLoadFile ARGS1 (HTRequest *, request)
1.1 timbl 650: {
1.61 ! frystyk 651: int status = -1;
! 652: char *url;
1.45 luotonen 653:
1.61 ! frystyk 654: if (!request || !request->anchor) {
! 655: if (TRACE) fprintf(stderr, "HTLoadFile.. Called with bad argument\n");
1.46 luotonen 656: return HT_INTERNAL;
1.50 frystyk 657: }
1.61 ! frystyk 658: url = HTAnchor_physical(request->anchor);
! 659: HTSimplify(url);
! 660: if (TRACE) fprintf(stderr, "LoadFile.... Looking for `%s\'\n", url);
1.16 secret 661:
1.23 duns 662: #ifdef VMS
1.1 timbl 663: /* Assume that the file is in Unix-style syntax if it contains a '/'
664: after the leading one @@ */
665: {
1.61 ! frystyk 666: /* CHECK THIS - IT DIDN'T WORK BEFORE :-(
! 667: What about checking for secure mode??? */
! 668: HTFormat format;
! 669: char unescaped = HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION);
1.23 duns 670: FILE * fp;
1.61 ! frystyk 671: char * nodename = NULL;
! 672: HTSimplify(unescaped);
! 673: HTUnEscape(unescaped);
! 674: nodename = HTParse(url, "", PARSE_HOST);
! 675: format = HTFileFormat(unescaped, &request->content_encoding,
! 676: &request->content_language);
! 677: /* END */
! 678: char * vmsname = strchr(unescaped + 1, '/') ?
! 679: HTVMS_name(nodename, unescaped) : unescaped + 1;
1.23 duns 680: fp = fopen(vmsname, "r", "shr=put", "shr=upd");
1.1 timbl 681:
682: /* If the file wasn't VMS syntax, then perhaps it is ultrix
683: */
1.23 duns 684: if (!fp) {
1.1 timbl 685: char ultrixname[INFINITY];
686: if (TRACE) fprintf(stderr, "HTFile: Can't open as %s\n", vmsname);
1.61 ! frystyk 687: sprintf(ultrixname, "%s::\"%s\"", nodename, unescaped);
1.23 duns 688: fp = fopen(ultrixname, "r", "shr=put", "shr=upd");
689: if (!fp) {
1.1 timbl 690: if (TRACE) fprintf(stderr,
691: "HTFile: Can't open as %s\n", ultrixname);
692: }
693: }
1.23 duns 694: if (fp)
695: {
696: if (HTEditable(vmsname)) {
697: HTAtom * put = HTAtom_for("PUT");
1.29 timbl 698: HTList * methods = HTAnchor_methods(request->anchor);
1.23 duns 699: if (HTList_indexOf(methods, put) == (-1)) {
700: HTList_addObject(methods, put);
701: }
702: }
1.52 duns 703: HTParseFile(format, fp, request);
1.23 duns 704: fclose(fp);
1.61 ! frystyk 705: free(nodename); /* HENRIK */
! 706: free(unescaped); /* HENRIK */
1.23 duns 707: return HT_LOADED;
708: } /* If successfull open */
1.1 timbl 709: }
710: #else
711:
712: /* For unix, we try to translate the name into the name of a transparently
713: ** mounted file.
714: **
1.61 ! frystyk 715: ** Not allowed in secure (HTClientHost) situations TBL 921019
1.1 timbl 716: */
717: #ifndef NO_UNIX_IO
1.17 timbl 718: /* Need protection here for telnet server but not httpd server */
1.2 timbl 719:
1.61 ! frystyk 720: if (!HTSecure) {
! 721: char * localname = HTLocalName(url); /* Does unescape! */
! 722: struct stat stat_info;
1.36 luotonen 723: char * multi;
1.61 ! frystyk 724: HTFormat format = HTFileFormat(localname, &request->content_encoding,
! 725: &request->content_language);
! 726: if (TRACE) fprintf(stderr, "HTLoadFile.. As we are NOT in secure mode, we can access the local file system.\n");
1.36 luotonen 727:
1.1 timbl 728: #ifdef GOT_READ_DIR
1.2 timbl 729:
1.61 ! frystyk 730: /* Multiformat handling. If suffix matches MULTI_SUFFIX then scan
! 731: ** directory to find a good file.
1.2 timbl 732: **
1.61 ! frystyk 733: ** Bug: we don't stat the file to find the length
1.2 timbl 734: */
1.47 luotonen 735: multi = strrchr(localname, MULTI_SUFFIX[0]);
1.36 luotonen 736: if (multi && !strcmp(multi, MULTI_SUFFIX)) {
1.47 luotonen 737: char * new_path = HTMulti(request, localname, &stat_info);
738: if (new_path) {
739: FREE(localname);
740: localname = new_path;
741: HTAnchor_setPhysical(request->anchor, localname);
1.36 luotonen 742: goto open_file;
1.2 timbl 743: }
1.61 ! frystyk 744: else { /* If not found suitable file */
1.47 luotonen 745: FREE(localname);
1.61 ! frystyk 746: goto cleanup;
1.2 timbl 747: }
1.61 ! frystyk 748: }
! 749:
! 750: /* Check to see if the 'localname' is in fact a directory. If it is
1.1 timbl 751: ** create a new hypertext object containing a list of files and
752: ** subdirectories contained in the directory. All of these are links
753: ** to the directories or files listed.
754: */
1.61 ! frystyk 755: if (stat(localname, &stat_info) == -1) {
! 756: if (TRACE)
! 757: fprintf(stderr, "HTLoadFile.. Can't stat %s\n", localname);
! 758: } else {
! 759: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR) {
! 760: status = HTBrowseDirectory(request, localname);
! 761: FREE(localname);
! 762: goto cleanup;
! 763: }
! 764: }
1.2 timbl 765:
1.61 ! frystyk 766: #endif /* GOT_READ_DIR */
1.2 timbl 767:
768: open_file:
1.16 secret 769: {
1.47 luotonen 770: FILE * fp = fopen(localname,"r");
1.61 ! frystyk 771: if (fp) {
! 772: if(TRACE) fprintf (stderr, "HTLoadFile.. Opened `%s' on local file system\n", localname);
1.47 luotonen 773: if (HTEditable(localname)) {
1.16 secret 774: HTAtom * put = HTAtom_for("PUT");
1.29 timbl 775: HTList * methods = HTAnchor_methods(request->anchor);
1.16 secret 776: if (HTList_indexOf(methods, put) == (-1)) {
777: HTList_addObject(methods, put);
778: }
1.2 timbl 779: }
1.61 ! frystyk 780: status = HTParseFile(format, fp, request);
! 781: fclose(fp);
1.47 luotonen 782: FREE(localname);
1.61 ! frystyk 783: goto cleanup;
! 784: } else
! 785: HTErrorSysAdd(request, ERR_FATAL, NO, "fopen");
! 786: }
! 787: FREE(localname);
! 788: } /* End of local file system */
! 789: #endif /* NO_UNIX_IO */
! 790: #endif /* VMS */
1.1 timbl 791:
792: #ifndef DECNET
1.61 ! frystyk 793: /* Now, as transparently mounted access has failed, we try FTP. */
1.16 secret 794: {
1.61 ! frystyk 795: char *nodename = HTParse(url, "", PARSE_HOST);
1.58 frystyk 796: if (nodename && *nodename && strcmp(nodename, HTHostName())!=0) {
797: char * newname = NULL;
1.61 ! frystyk 798: if (TRACE) fprintf(stderr, "HTLoadFile.. Couldn't find file on local file system, let's try via FTP\n");
1.58 frystyk 799: StrAllocCopy(newname, "ftp:");
1.61 ! frystyk 800: if (!strncmp(url, "file:", 5))
! 801: StrAllocCat(newname, url+5);
1.58 frystyk 802: else
1.61 ! frystyk 803: StrAllocCat(newname, url);
1.58 frystyk 804: HTAnchor_setPhysical(request->anchor, newname);
805: free(newname);
1.61 ! frystyk 806: free(nodename);
! 807: HTErrorFree(request); /* Free error stack */
! 808: return HTLoad(request); /* Jump directly to FTP module */
1.58 frystyk 809: }
1.61 ! frystyk 810: free(nodename);
1.1 timbl 811: }
812: #endif
813:
1.61 ! frystyk 814: cleanup:
! 815: if (status < 0 && status != HT_INTERRUPTED) {
! 816: char *unescaped = NULL;
! 817: StrAllocCopy(unescaped, url);
! 818: HTUnEscape(unescaped);
! 819: HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_FOUND, (void *) unescaped,
! 820: (int) strlen(unescaped), "HTLoadFile");
! 821: free(unescaped);
1.2 timbl 822: }
1.61 ! frystyk 823: return status;
1.1 timbl 824: }
825:
826: /* Protocol descriptors
827: */
1.29 timbl 828: GLOBALDEF PUBLIC HTProtocol HTFile = { "file", HTLoadFile,
829: HTFileSaveStream, 0 };
Webmaster