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