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