Annotation of libwww/Library/src/HTFWrite.c, revision 2.31
2.1 frystyk 1: /* HTFWrite.c
2: ** FILE WRITER
3: **
2.6 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.1 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.31 ! frystyk 6: ** @(#) $Id: Date Author State $
2.1 frystyk 7: **
8: ** This version of the stream object just writes to a C file.
9: ** The file is assumed open and left open.
10: **
11: ** Bugs:
12: ** strings written must be less than buffer size.
13: **
14: ** History:
15: ** HFN: wrote it
16: ** HWL: converted the caching scheme to be hierachical by taking
17: ** AL code from Deamon
2.10 frystyk 18: ** HFN: moved cache code to HTCache module
2.1 frystyk 19: **
20: */
21:
22: /* Library include files */
2.28 frystyk 23: #include "sysdep.h"
2.1 frystyk 24: #include "HTUtils.h"
25: #include "HTString.h"
26: #include "HTFormat.h"
2.21 frystyk 27: #include "HTError.h"
2.1 frystyk 28: #include "HTAlert.h"
2.19 frystyk 29: #include "HTAccess.h"
2.4 frystyk 30: #include "HTBind.h"
2.1 frystyk 31: #include "HTList.h"
2.3 frystyk 32: #include "HTParse.h"
2.15 frystyk 33: #include "HTReq.h"
2.3 frystyk 34: #include "HTFWrite.h" /* Implemented here */
2.1 frystyk 35:
2.4 frystyk 36: #define HASH_SIZE 1001 /* Tunable */
37:
2.13 frystyk 38: /* The default directory for "save locally" and "save and execute" files: */
39: #ifndef HT_TMP_ROOT
40: #define HT_TMP_ROOT "/tmp"
41: #endif
42:
2.3 frystyk 43: struct _HTStream {
2.28 frystyk 44: const HTStreamClass *isa;
2.24 frystyk 45:
46: FILE * fp;
2.31 ! frystyk 47: BOOL leave_open; /* Close file when free? */
2.24 frystyk 48: char * end_command; /* Command to execute */
49: BOOL remove_on_close; /* Remove file? */
50: char * filename; /* Name of file */
51: HTRequest * request; /* saved for callback */
52: HTRequestCallback * callback;
2.3 frystyk 53: };
2.1 frystyk 54:
2.3 frystyk 55: PRIVATE char * HTTmpRoot = NULL; /* Dest for tmp files */
2.1 frystyk 56:
2.3 frystyk 57: /* ------------------------------------------------------------------------- */
2.1 frystyk 58:
2.16 frystyk 59: PRIVATE int HTFWriter_put_character (HTStream * me, char c)
2.3 frystyk 60: {
61: return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
62: }
63:
2.28 frystyk 64: PRIVATE int HTFWriter_put_string (HTStream * me, const char* s)
2.3 frystyk 65: {
66: if (*s) /* For vms :-( 10/04-94 */
67: return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
68: return HT_OK;
69: }
70:
2.16 frystyk 71: PRIVATE int HTFWriter_flush (HTStream * me)
2.3 frystyk 72: {
2.7 frystyk 73: return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
2.3 frystyk 74: }
75:
2.28 frystyk 76: PRIVATE int HTFWriter_write (HTStream * me, const char* s, int l)
2.3 frystyk 77: {
2.7 frystyk 78: int status ;
79: status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
2.24 frystyk 80: if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
2.7 frystyk 81: return status ;
2.3 frystyk 82: }
2.7 frystyk 83:
2.30 frystyk 84: PRIVATE int HTFWriter_free (HTStream * me)
2.3 frystyk 85: {
2.24 frystyk 86: if (me) {
87: if (me->leave_open != YES) fclose(me->fp);
2.28 frystyk 88: #ifdef HAVE_SYSTEM
2.24 frystyk 89: if (me->end_command) system(me->end_command); /* SECURITY HOLE!!! */
2.17 frystyk 90: #endif
2.24 frystyk 91: if (me->remove_on_close) REMOVE(me->filename);
92: if (me->callback) (*me->callback)(me->request, me->filename);
2.26 frystyk 93: HT_FREE(me->end_command);
94: HT_FREE(me->filename);
95: HT_FREE(me);
2.3 frystyk 96: }
97: return HT_OK;
98: }
99:
2.18 frystyk 100: PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
2.3 frystyk 101: {
2.27 eric 102: if (STREAM_TRACE) HTTrace("FileWriter.. ABORTING...\n");
2.24 frystyk 103: if (me) {
104: if (me->leave_open != YES) fclose(me->fp);
105: if (me->remove_on_close) REMOVE(me->filename);
2.26 frystyk 106: HT_FREE(me->end_command);
107: HT_FREE(me->filename);
108: HT_FREE(me);
2.3 frystyk 109: }
110: return HT_ERROR;
111: }
112:
2.28 frystyk 113: PRIVATE const HTStreamClass HTFWriter = /* As opposed to print etc */
2.3 frystyk 114: {
115: "FileWriter",
116: HTFWriter_flush,
2.30 frystyk 117: HTFWriter_free,
2.3 frystyk 118: HTFWriter_abort,
119: HTFWriter_put_character,
120: HTFWriter_put_string,
121: HTFWriter_write
122: };
123:
2.24 frystyk 124: PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
125: BOOL leave_open)
2.3 frystyk 126: {
2.24 frystyk 127: HTStream * me = NULL;
2.3 frystyk 128: if (!fp) {
2.27 eric 129: if (STREAM_TRACE)HTTrace("FileWriter.. Bad file descriptor\n");
2.24 frystyk 130: return HTErrorStream();
2.3 frystyk 131: }
2.26 frystyk 132: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
133: HT_OUTOFMEM("HTFWriter_new");
2.3 frystyk 134: me->isa = &HTFWriter;
135: me->fp = fp;
2.24 frystyk 136: me->leave_open = leave_open;
137: me->request = request;
2.3 frystyk 138: return me;
139: }
140:
141: /* ------------------------------------------------------------------------- */
142: /* FILE WRITER ROUTINES */
143: /* ------------------------------------------------------------------------- */
144:
145: /* Set TMP Root
146: ** --------------
147: ** If `tmp_root' is NULL use the current value (might be a define)
148: */
2.28 frystyk 149: PUBLIC BOOL HTTmp_setRoot (const char * tmp_root)
2.3 frystyk 150: {
151: StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
152: if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
153: StrAllocCat(HTTmpRoot, "/");
2.14 frystyk 154: if (STREAM_TRACE)
2.27 eric 155: HTTrace("Tmp Root.... Root set to `%s\'\n", HTTmpRoot);
2.3 frystyk 156: return YES;
157: }
158:
159:
160: /* Get Tmp Root
161: ** --------------
2.1 frystyk 162: */
2.28 frystyk 163: PUBLIC const char * HTTmp_getRoot (void)
2.3 frystyk 164: {
165: return HTTmpRoot;
166: }
2.1 frystyk 167:
168:
2.3 frystyk 169: /* Free Tmp Root
170: ** --------------
171: ** For clean up memory
172: */
2.29 eric 173: PUBLIC void HTTmp_freeRoot (void)
2.3 frystyk 174: {
2.26 frystyk 175: HT_FREE(HTTmpRoot);
2.3 frystyk 176: }
2.1 frystyk 177:
2.4 frystyk 178: /*
179: ** This function tries really hard to find a non-existent filename relative
2.31 ! frystyk 180: ** to the path given. Returns a string that must be freed by the caller or
2.4 frystyk 181: ** NULL on error. The base must be '/' terminated which!
182: */
2.28 frystyk 183: PRIVATE char *get_filename (char * base, const char * url, const char * suffix)
2.4 frystyk 184: {
185: char *path=NULL;
186: char filename[40];
187: int hash=0;
188:
189: /* Do this until we find a name that doesn't exist */
190: while (1)
191: {
2.28 frystyk 192: const char *ptr=url;
2.4 frystyk 193: for( ; *ptr; ptr++)
194: hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
195:
2.28 frystyk 196: #ifdef HAVE_GETPID
2.4 frystyk 197: sprintf(filename, "%d-%d", hash, (int) getpid());
198: #else
199: sprintf(filename, "%d-%d", hash, time(NULL));
200: #endif
201: StrAllocCopy(path, base);
202: StrAllocCat(path, filename);
203: if (suffix) StrAllocCat(path, suffix);
204:
205: {
206: FILE *fp = fopen(path, "r");
207: if (fp) /* This file does already exist */
208: fclose(fp);
209: else
210: break; /* Got the file name */
211: }
212: }
213: return path;
214: }
215:
216:
2.24 frystyk 217: /* Save Locally
218: ** ------------
219: ** Saves a file to local disk. This can for example be used to dump
220: ** date objects of unknown media types to local disk. The stream prompts
221: ** for a file name for the temporary file.
2.1 frystyk 222: */
2.24 frystyk 223: PUBLIC HTStream* HTSaveLocally (HTRequest * request,
224: void * param,
225: HTFormat input_format,
226: HTFormat output_format,
227: HTStream * output_stream)
2.1 frystyk 228: {
2.24 frystyk 229: FILE * fp = NULL;
230: char * filename = NULL;
2.19 frystyk 231: if (HTLib_secure()) {
2.21 frystyk 232: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
2.24 frystyk 233: NULL, 0, "HTSaveLocally");
234: return HTErrorStream();
2.1 frystyk 235: }
2.3 frystyk 236: if (!HTTmpRoot) {
2.27 eric 237: if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24 frystyk 238: return HTErrorStream();
2.1 frystyk 239: }
240:
2.24 frystyk 241: /* Let's prompt the user for a file name for this file */
2.4 frystyk 242: {
2.24 frystyk 243: HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
2.13 frystyk 244: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
245: char *suffix = HTBind_getSuffix(anchor);
2.24 frystyk 246: char *deflt = get_filename(HTTmpRoot,HTAnchor_physical(anchor),suffix);
247: if (cbf) {
248: HTAlertPar * reply = HTAlert_newReply();
249: if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
250: filename = HTAlert_replyMessage(reply);
251: HTAlert_deleteReply(reply);
252: }
2.26 frystyk 253: HT_FREE(suffix);
254: HT_FREE(deflt);
2.24 frystyk 255: if (filename) {
256: if ((fp = fopen(filename, "wb")) == NULL) {
257: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
258: filename, strlen(filename),"HTSaveLocally");
2.26 frystyk 259: HT_FREE(filename);
2.24 frystyk 260: return HTErrorStream();
261: }
262: } else {
2.27 eric 263: if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24 frystyk 264: return HTErrorStream();
2.4 frystyk 265: }
266: }
2.24 frystyk 267:
268: /* Now we are ready for creating the file writer stream */
269: if (fp) {
270: HTStream * me = HTFWriter_new(request, fp, NO);
271: me->filename = filename;
272: return me;
2.1 frystyk 273: }
2.26 frystyk 274: HT_FREE(filename);
2.24 frystyk 275: return HTErrorStream();
2.1 frystyk 276: }
277:
278:
2.24 frystyk 279: /* Take action using a system command
280: ** ----------------------------------
281: ** Creates temporary file, writes to it and then executes system
282: ** command (maybe an external viewer) when EOF has been reached. The
283: ** stream finds a suitable name of the temporary file which preserves the
284: ** suffix. This way, the system command can find out the file type from
285: ** the name of the temporary file name.
2.1 frystyk 286: */
2.24 frystyk 287: PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
288: void * param,
289: HTFormat input_format,
290: HTFormat output_format,
291: HTStream * output_stream)
2.1 frystyk 292: {
2.24 frystyk 293: FILE * fp = NULL;
294: char * filename = NULL;
2.19 frystyk 295: if (HTLib_secure()) {
2.21 frystyk 296: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
297: NULL, 0, "HTSaveLocally");
2.24 frystyk 298: return HTErrorStream();
2.1 frystyk 299: }
2.3 frystyk 300: if (!HTTmpRoot) {
2.27 eric 301: if (STREAM_TRACE) HTTrace("Save File... turned off");
2.24 frystyk 302: return HTErrorStream();
2.1 frystyk 303: }
304:
2.24 frystyk 305: /* Let's find a hash name for this file without asking user */
2.4 frystyk 306: {
2.13 frystyk 307: HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
308: char *suffix = HTBind_getSuffix(anchor);
2.24 frystyk 309: filename = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
2.26 frystyk 310: HT_FREE(suffix);
2.25 frystyk 311: if (filename) {
312: if ((fp = fopen(filename, "wb")) == NULL) {
313: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
314: filename, strlen(filename),"HTSaveAndExecute");
2.26 frystyk 315: HT_FREE(filename);
2.25 frystyk 316: return HTErrorStream();
317: }
318: } else {
2.27 eric 319: if (STREAM_TRACE) HTTrace("Save File... No file name\n");
2.24 frystyk 320: return HTErrorStream();
2.4 frystyk 321: }
322: }
323:
2.24 frystyk 324: /* Now we are ready for creating the file writer stream */
325: if (fp) {
326: HTStream * me = HTFWriter_new(request, fp, NO);
327: me->filename = filename;
2.31 ! frystyk 328: if (param) {
! 329: if ((me->end_command = (char *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
! 330: HT_OUTOFMEM("SaveAndExecute");
! 331: sprintf (me->end_command,
! 332: (char *)param, filename, filename, filename);
! 333: }
2.24 frystyk 334: return me;
2.1 frystyk 335: }
2.26 frystyk 336: HT_FREE(filename);
2.24 frystyk 337: return HTErrorStream();
2.1 frystyk 338: }
339:
340:
341: /* Save and Call Back
342: ** ------------------
2.24 frystyk 343: ** This stream works exactly like the TSaveAndExecute
344: ** stream but in addition when EOF has been reached, it checks whether a
345: ** callback function has been associated with the request object in which
346: ** case, this callback is being called. This can be use by the
347: ** application to do some processing after the system command
348: ** has terminated. The callback function is called with the file name of
349: ** the temporary file as parameter.
2.1 frystyk 350: */
2.16 frystyk 351: PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
352: void * param,
353: HTFormat input_format,
354: HTFormat output_format,
355: HTStream * output_stream)
2.1 frystyk 356: {
2.24 frystyk 357: HTStream * me = HTSaveAndExecute(request, param, input_format,
358: output_format, output_stream);
359: if (me) {
360: me->callback = HTRequest_callback(request);
361: return me;
362: }
363: return HTErrorStream();
2.1 frystyk 364: }
365:
Webmaster