Exemple #1
0
/* close a directory stream */
int closedir(DIR *dirp)
{
    int rc;

    file_internal_lock_WRITER();

    /* needs to work even if marked "nonexistant" */
    struct dirstr_desc * const dir = (struct dirstr_desc *)dirp;
    if (!PTR_IN_ARRAY(open_streams, dir, MAX_OPEN_DIRS))
        FILE_ERROR(EFAULT, -1);

    if (!dir->stream.flags)
    {
        DEBUGF("dir #%d: dir not open\n", (int)(dir - open_streams));
        FILE_ERROR(EBADF, -2);
    }

    rc = close_stream_internal(&dir->stream);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

file_error:
    file_internal_unlock_WRITER();
    return rc;
}
Exemple #2
0
/* make a directory */
int mkdir(const char *path)
{
    DEBUGF("mkdir(path=\"%s\")\n", path);

    int rc;

    file_internal_lock_WRITER();

    struct filestr_base stream;
    struct path_component_info compinfo;
    rc = open_stream_internal(path, FF_DIR, &stream, &compinfo);
    if (rc < 0)
    {
        DEBUGF("Can't open parent dir or path is not a directory\n");
        FILE_ERROR(ERRNO, rc * 10 - 1);
    }
    else if (rc > 0)
    {
        DEBUGF("File exists\n");
        FILE_ERROR(EEXIST, -2);
    }

    rc = create_stream_internal(&compinfo.parentinfo, compinfo.name,
                                compinfo.length, ATTR_NEW_DIRECTORY,
                                FO_DIRECTORY, &stream);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

    rc = 0;
file_error:
    close_stream_internal(&stream);
    file_internal_unlock_WRITER();
    return rc;
}
Exemple #3
0
/* truncate a file to a specified length */
int ftruncate(int fildes, off_t length)
{
    DEBUGF("ftruncate(fd=%d,len=%ld)\n", fildes, (long)length);

    struct filestr_desc * const file = GET_FILESTR(READER, fildes);
    if (!file)
        FILE_ERROR_RETURN(ERRNO, -1);

    int rc;

    if (!(file->stream.flags & FD_WRITE))
    {
        DEBUGF("Descriptor is read-only mode\n");
        FILE_ERROR(EBADF, -2);
    }

    if (length < 0)
    {
        DEBUGF("Length %ld is invalid\n", (long)length);
        FILE_ERROR(EINVAL, -3);
    }

    rc = ftruncate_internal(file, length, true);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 4);

file_error:
    RELEASE_FILESTR(READER, file);
    return rc;
}
Exemple #4
0
/* open a directory */
DIR * opendir(const char *dirname)
{
    DEBUGF("opendir(dirname=\"%s\"\n", dirname);

    DIR *dirp = NULL;

    file_internal_lock_WRITER();

    int rc;

    struct dirstr_desc * const dir = alloc_dirstr();
    if (!dir)
        FILE_ERROR(EMFILE, RC);

    rc = open_stream_internal(dirname, FF_DIR, &dir->stream, NULL);
    if (rc < 0)
    {
        DEBUGF("Open failed: %d\n", rc);
        FILE_ERROR(ERRNO, RC);
    }

#ifdef HAVE_MULTIVOLUME
    /* volume counter is relevant only to the system root */
    dir->volumecounter = rc > 1 ? 0 : INT_MAX;
#endif /* HAVE_MULTIVOLUME */

    fat_rewind(&dir->stream.fatstr);
    rewinddir_dirent(&dir->scan);

    dirp = (DIR *)dir;
file_error:
    file_internal_unlock_WRITER();
    return dirp;
}
Exemple #5
0
/* flush a dirty cache buffer */
static int flush_cache(struct filestr_desc *file)
{
    int rc;
    struct filestr_cache *cachep = file->stream.cachep;

    DEBUGF("Flushing dirty sector cache (%lu)\n", cachep->sector);

    if (fat_query_sectornum(&file->stream.fatstr) != cachep->sector)
    {
        /* get on the correct sector */
        rc = fat_seek(&file->stream.fatstr, cachep->sector);
        if (rc < 0)
            FILE_ERROR(EIO, rc * 10 - 1);
    }

    rc = fat_readwrite(&file->stream.fatstr, 1, cachep->buffer, true);
    if (rc < 0)
    {
        if (rc == FAT_RC_ENOSPC)
            FILE_ERROR(ENOSPC, RC);
        else
            FILE_ERROR(EIO, rc * 10 - 2);
    }

    cachep->flags = 0;
    return 1;
file_error:
    DEBUGF("Failed flushing cache: %d\n", rc);
    return rc;
}
Exemple #6
0
/* truncate the file to the specified length */
static int ftruncate_internal(struct filestr_desc *file, file_size_t size,
                              bool write_now)
{
    int rc = 0, rc2 = 1;

    file_size_t cursize = *file->sizep;
    file_size_t truncsize = MIN(size, cursize);

    if (write_now)
    {
        unsigned long sector = filesize_sectors(truncsize);
        struct filestr_cache *const cachep = file->stream.cachep;

        if (cachep->flags == (FSC_NEW|FSC_DIRTY) &&
            cachep->sector + 1 == sector)
        {
            /* sector created but may have never been added to the cluster
               chain; flush it now or the subsequent may fail */
            rc2 = flush_cache(file);
            if (rc2 == FAT_RC_ENOSPC)
            {
                /* no space left on device; further truncation needed */
                discard_cache(file);
                truncsize = ALIGN_DOWN(truncsize - 1, SECTOR_SIZE);
                sector--;
                rc = rc2;
            }
            else if (rc2 < 0)
                FILE_ERROR(ERRNO, rc2 * 10 - 1);
        }

        rc2 = fat_seek(&file->stream.fatstr, sector);
        if (rc2 < 0)
            FILE_ERROR(EIO, rc2 * 10 - 2);

        rc2 = fat_truncate(&file->stream.fatstr);
        if (rc2 < 0)
            FILE_ERROR(EIO, rc2 * 10 - 3);
    }
    /* else just change the cached file size */

    if (truncsize < cursize)
    {
        *file->sizep = truncsize;
        fileop_ontruncate_internal(&file->stream);
    }

    /* if truncation was partially successful, it effectively destroyed
       everything after the truncation point; still, indicate failure
       after adjusting size */
    if (rc2 == 0)
        FILE_ERROR(EIO, -4);
    else if (rc2 < 0)
        FILE_ERROR(ERRNO, rc2);

file_error:
    return rc;
}
Exemple #7
0
/* allocate a file descriptor, if needed, assemble stream flags and open
   a new stream */
static int open_internal_inner1(const char *path, int oflag,
                                unsigned int callflags)
{
    DEBUGF("%s(path=\"%s\",oflag=%X,callflags=%X)\n", __func__,
           path, oflag, callflags);

    int rc;

    struct filestr_desc *file;
    int fildes = alloc_filestr(&file);
    if (fildes < 0)
        FILE_ERROR(EMFILE, -1);

    callflags &= ~FDO_MASK;

    if (oflag & O_ACCMODE)
    {
        callflags |= FD_WRITE;

        if ((oflag & O_ACCMODE) == O_WRONLY)
            callflags |= FD_WRONLY;

        if (oflag & O_APPEND)
            callflags |= FD_APPEND;

        if (oflag & O_TRUNC)
            callflags |= FO_TRUNC;
    }
    else if (oflag & O_TRUNC)
    {
        /* O_TRUNC requires write mode */
        DEBUGF("No write mode but have O_TRUNC\n");
        FILE_ERROR(EINVAL, -2);
    }

    /* O_CREAT and O_APPEND are fine without write mode
     * for the former, an empty file is created but no data may be written
     * for the latter, no append will be allowed anyway */
    if (oflag & O_CREAT)
    {
        callflags |= FF_CREAT;

        if (oflag & O_EXCL)
            callflags |= FF_EXCL;
    }

    rc = open_internal_inner2(path, file, callflags);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

    return fildes;

file_error:
    return rc;
}
Exemple #8
0
/* flush back all outstanding writes to the file */
static int fsync_internal(struct filestr_desc *file)
{
    /* call only when holding WRITER lock (updates directory entries) */
    int rc = 0;

    file_size_t size = *file->sizep;
    unsigned int foflags = fileobj_get_flags(&file->stream);

    /* flush sector cache? */
    struct filestr_cache *const cachep = file->stream.cachep;
    if (cachep->flags & FSC_DIRTY)
    {
        int rc2 = flush_cache(file);
        if (rc2 == FAT_RC_ENOSPC && (cachep->flags & FSC_NEW))
        {
            /* no space left on device so this must be dropped */
            discard_cache(file);
            size = ALIGN_DOWN(size - 1, SECTOR_SIZE);
            foflags |= FO_TRUNC;
            rc = rc2;
        }
        else if (rc2 < 0)
            FILE_ERROR(ERRNO, rc2 * 10 - 1);
    }

    /* truncate? */
    if (foflags & FO_TRUNC)
    {
        int rc2 = ftruncate_internal(file, size, rc == 0);
        if (rc2 < 0)
            FILE_ERROR(ERRNO, rc2 * 10 - 2);

        /* never needs to be done this way again since any data beyond the
           cached size is now gone */
        fileobj_change_flags(&file->stream, 0, FO_TRUNC);
    }

file_error:;
    /* tie up all loose ends (try to close the file even if failing) */
    int rc2 = fat_closewrite(&file->stream.fatstr, size,
                             get_dir_fatent_dircache());
    if (rc2 >= 0)
        fileop_onsync_internal(&file->stream); /* dir_fatent is implicit arg */

    if (rc2 < 0 && rc >= 0)
    {
        errno = EIO;
        rc = rc2 * 10 - 3;
    }

    return rc;
}
Exemple #9
0
/* read a directory */
struct dirent * readdir(DIR *dirp)
{
    struct dirstr_desc * const dir = GET_DIRSTR(READER, dirp);
    if (!dir)
        FILE_ERROR_RETURN(ERRNO, NULL);

    struct dirent *res = NULL;

    int rc = readdir_volume(dir, &dir->entry);
    if (rc == 0)
    {
        rc = readdir_dirent(&dir->stream, &dir->scan, &dir->entry);
        if (rc < 0)
            FILE_ERROR(EIO, RC);
    }

    if (rc > 0)
        res = &dir->entry;

file_error:
    RELEASE_DIRSTR(READER, dir);

    if (rc > 1)
        iso_decode_d_name(res->d_name);

    return res;
}
void write_appointments(Appointment_t appointments[], int size, 
														const Files_t* files)
{
    int i;
    FILE *read_file_p;
    read_file_p = fopen(files->readable_records_file_n,"w");
    if(read_file_p==NULL)
    {
        FILE_ERROR(files->readable_records_file_n);
        exit(1);
    }
	/* appoint icerigi dosyaya yazildi */
    fprintf(read_file_p,"<Size>%d</Size>\n",size);
    fprintf(read_file_p,"<Records>\n");
    for(i=0;i<size;i++)
    {
        fprintf(read_file_p,"\t<Appointment>\n");
        fprintf(read_file_p,"\t\t<app_id>%d</app_id>\n",appointments[i].app_id);
        fprintf(read_file_p,"\t\t<patient_id>%d</patient_id>\n",
													appointments[i].patient_id);
        fprintf(read_file_p,"\t\t<hour>%d</hour>\n",appointments[i].hour);
        fprintf(read_file_p,"\t</Appointment>\n");
    }
    fprintf(read_file_p,"</Records>\n");

    fclose(read_file_p); /* dosya kapandi */
}
Exemple #11
0
/* fill a cache buffer with a new sector */
static int readwrite_fill_cache(struct filestr_desc *file, unsigned long sector,
                                unsigned long filesectors, bool write)
{
    /* sector != cachep->sector should have been checked by now */

    int rc;
    struct filestr_cache *cachep = filestr_get_cache(&file->stream);

    if (cachep->flags & FSC_DIRTY)
    {
        rc = flush_cache(file);
        if (rc < 0)
            FILE_ERROR(ERRNO, rc * 10 - 1);
    }

    if (fat_query_sectornum(&file->stream.fatstr) != sector)
    {
        /* get on the correct sector */
        rc = fat_seek(&file->stream.fatstr, sector);
        if (rc < 0)
            FILE_ERROR(EIO, rc * 10 - 2);
    }

    if (!write || sector < filesectors)
    {
        /* only reading or this sector would have been flushed if the cache
           was previously needed for a different sector */
        rc = fat_readwrite(&file->stream.fatstr, 1, cachep->buffer, false);
        if (rc < 0)
            FILE_ERROR(rc == FAT_RC_ENOSPC ? ENOSPC : EIO, rc * 10 - 3);
    }
    else
    {
        /* create a fresh, shiny, new sector with that new sector smell */
        cachep->flags = FSC_NEW;
    }

    cachep->sector = sector;
    return 1;
file_error:
    DEBUGF("Failed caching sector: %d\n", rc);
    return rc;
}
Exemple #12
0
/* set the file pointer */
static off_t lseek_internal(struct filestr_desc *file, off_t offset,
                            int whence)
{
    off_t rc;
    file_size_t pos;

    file_size_t size = MIN(*file->sizep, FILE_SIZE_MAX);

    switch (whence)
    {
    case SEEK_SET:
        if (offset < 0 || (file_size_t)offset > size)
            FILE_ERROR(EINVAL, -1);

        pos = offset;
        break;

    case SEEK_CUR:
        if ((offset < 0 && (file_size_t)-offset > file->offset) ||
            (offset > 0 && (file_size_t)offset > size - file->offset))
            FILE_ERROR(EINVAL, -1);

        pos = file->offset + offset;
        break;

    case SEEK_END:
        if (offset > 0 || (file_size_t)-offset > size)
            FILE_ERROR(EINVAL, -1);

        pos = size + offset;
        break;

    default:
        FILE_ERROR(EINVAL, -1);
    }

    file->offset = pos;

    return pos;
file_error:
    return rc;
}
Exemple #13
0
/* get the portable info from the native entry */
struct dirinfo dir_get_info(DIR *dirp, struct dirent *entry)
{
    int rc;
    if (!dirp || !entry)
        FILE_ERROR(EFAULT, RC);

    if (entry->d_name[0] == '\0')
        FILE_ERROR(ENOENT, RC);

    if ((file_size_t)entry->info.size > FILE_SIZE_MAX)
        FILE_ERROR(EOVERFLOW, RC);

    return (struct dirinfo)
    {
        .attribute = entry->info.attr,
        .size      = entry->info.size,
        .mtime     = fattime_mktime(entry->info.wrtdate, entry->info.wrttime),
    };

file_error:
    return (struct dirinfo){ .attribute = 0 };
}
int delete_appointments(node_t** head, const Files_t* files)
{
    int del_app;
	int count=0;
    FILE *del_file;
    node_t* del;
    node_t* clear; /* bir onceki nodun yerini tutmak icin */

    del_file=fopen(files->delete_file_n,"r");


    if(del_file==NULL){
        FILE_ERROR(files->delete_file_n);
        exit(1);
    }

/* http://geeksquiz.com/linked-list-set-3-deleting-node/ */
/* KAYNAK OLARAK CALISILDI */
    while(fscanf(del_file,"%d",&del_app)!=EOF)
    {
		printf("%d-",del_app);
        del=(*head);

		/*ilk elemanda ise direk sil ve listeyi guncelle */
		if(del!=NULL && del->app_id==del_app)
		{
			*head=del->next;
			free(del);
			count++; /* silince sayaci arttir */
		}
		else
		{
			/* sayiyi bulana kadar git*/
		    while(del!=NULL && del->app_id!=del_app)
		    {
		        clear=del;
		        del=del->next;
		    }
			/* sayi bulundu ise silinecek */
		    if(del!=NULL)

		        {
		            clear->next=del->next;
		            free(del);
					count++;
		        }
		}
}
    return count;
}
Exemple #15
0
/* write on a file */
ssize_t write(int fildes, const void *buf, size_t nbyte)
{
    struct filestr_desc * const file = GET_FILESTR(READER, fildes);
    if (!file)
        FILE_ERROR_RETURN(ERRNO, -1);

    ssize_t rc;

    if (!(file->stream.flags & FD_WRITE))
    {
        DEBUGF("write(fd=%d,buf=%p,nb=%lu) - "
               "descriptor is read-only mode\n",
               fildes, buf, (unsigned long)nbyte);
        FILE_ERROR(EBADF, -2);
    }

    rc = readwrite(file, (void *)buf, nbyte, true);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

file_error:
    RELEASE_FILESTR(READER, file);
    return rc;
}
Exemple #16
0
/* synchronize changes to a file */
int fsync(int fildes)
{
    DEBUGF("fsync(fd=%d)\n", fildes);

    struct filestr_desc * const file = GET_FILESTR(WRITER, fildes);
    if (!file)
        FILE_ERROR_RETURN(ERRNO, -1);

    int rc;

    if (!(file->stream.flags & FD_WRITE))
    {
        DEBUGF("Descriptor is read-only mode\n");
        FILE_ERROR(EINVAL, -2);
    }

    rc = fsync_internal(file);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

file_error:
    RELEASE_FILESTR(WRITER, file);
    return rc;
}
Exemple #17
0
/* close a file descriptor */
int close(int fildes)
{
    DEBUGF("close(fd=%d)\n", fildes);

    int rc;

    file_internal_lock_WRITER();

    /* needs to work even if marked "nonexistant" */
    struct filestr_desc *file = &open_streams[fildes];
    if ((unsigned int)fildes >= MAX_OPEN_FILES || !file->stream.flags)
    {
        DEBUGF("filedes %d not open\n", fildes);
        FILE_ERROR(EBADF, -2);
    }

    rc = close_internal(file);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 3);

file_error:
    file_internal_unlock_WRITER();
    return rc;
}
Exemple #18
0
/* move the read/write file offset */
off_t lseek(int fildes, off_t offset, int whence)
{
    DEBUGF("lseek(fd=%d,ofs=%ld,wh=%d)\n", fildes, (long)offset, whence);

    struct filestr_desc * const file = GET_FILESTR(READER, fildes);
    if (!file)
        FILE_ERROR_RETURN(ERRNO, -1);

    off_t rc = lseek_internal(file, offset, whence);
    if (rc < 0)
        FILE_ERROR(ERRNO, rc * 10 - 2);

file_error:
    RELEASE_FILESTR(READER, file);
    return rc;
}
void add_personal_data(node_t* head, const Files_t* files)
{
    char temp[20];
    FILE *pt_xml_file;
    pt_xml_file=fopen(files->patient_file_n,"r");

    if(pt_xml_file==NULL)
    {
        FILE_ERROR(files->patient_file_n);
        exit(1);
    }
    /* dosya basindaki records ignore edildi */
    fscanf(pt_xml_file,"%s",temp);
    /* geri kalani okumak icin fonksiyon cagirildi */
    read_p_data(head,pt_xml_file);

    fclose(pt_xml_file);
}
Exemple #20
0
/* finish with the file and free resources */
static int close_internal(struct filestr_desc *file)
{
    /* call only when holding WRITER lock (updates directory entries) */
    int rc;

    if ((file->stream.flags & FD_WRITE) &&
        !(fileobj_get_flags(&file->stream) & FO_REMOVED))
    {
        rc = fsync_internal(file);
        if (rc < 0)
            FILE_ERROR(ERRNO, rc * 10 - 1);
    }

    rc = 0;
file_error:;
    int rc2 = close_stream_internal(&file->stream);
    if (rc2 < 0 && rc >= 0)
        rc = rc2 * 10 - 2;
    return rc;
}
void write_accepted_app(node_t* head, const Files_t* files)
{
    int i=0;
    FILE *accep_csv_file;
    accep_csv_file=fopen(files->accepted_appo_file_n,"w");
    if(accep_csv_file==NULL)    /* dosya acilmama durumunda hata */
    {
        FILE_ERROR(files->accepted_appo_file_n);
        exit(1);
    }

    /* belirtilen formatta liste elemanlari yazilir */
    fprintf(accep_csv_file,"no;id;patient_id;name;history;hour\n");
    while(head!=NULL)
    {
        fprintf(accep_csv_file,"%d;%d;%d;%s;%s;%d\n",i,head->app_id,
											head->patient_id,head->name,
                                            head->history,head->hour);
        i++;
        head=head->next;
    }
}
Exemple #22
0
/* read a directory (reentrant) */
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
{
    if (!result)
        FILE_ERROR_RETURN(EFAULT, -2);

    *result = NULL;

    if (!entry)
        FILE_ERROR_RETURN(EFAULT, -3);

    struct dirstr_desc * const dir = GET_DIRSTR(READER, dirp);
    if (!dir)
        FILE_ERROR_RETURN(ERRNO, -1);

    int rc = readdir_volume(dir, entry);
    if (rc == 0)
    {
        rc = readdir_dirent(&dir->stream, &dir->scan, entry);
        if (rc < 0)
            FILE_ERROR(EIO, rc * 10 - 4);
    }

file_error:
    RELEASE_DIRSTR(READER, dir);

    if (rc > 0)
    {
        if (rc > 1)
            iso_decode_d_name(entry->d_name);

        *result = entry;
        rc = 0;
    }

    return rc;
}
void print_parameters(const Files_t* files, const Working_hours_t* hours)
{
    FILE *param_textp;

    param_textp = fopen(files->parameters_file_n,"w");
    if(param_textp==NULL)
    {
        FILE_ERROR(files->parameters_file_n);
        exit(1);
    }
	/* files ve hour icerigi parameter dosyasina yazildi. */
    fprintf(param_textp,"Accepted Appointed File = %s\n",
												files->accepted_appo_file_n);
    fprintf(param_textp,"Delete File = %s\n",files->delete_file_n);
    fprintf(param_textp,"Parameter File = %s\n",files->parameters_file_n);
    fprintf(param_textp,"Patient  File = %s\n",files->patient_file_n);
    fprintf(param_textp,"Readable Records File = %s\n",
											files->readable_records_file_n);
    fprintf(param_textp,"Records File = %s\n",files->records_file_n);
    fprintf(param_textp,"Start WORK  = %d\n",hours->start);
    fprintf(param_textp,"End  WORK  = %d\n",hours->end);

    fclose(param_textp); /* dosya kapandi */
}
Appointment_t* getRequests(const Files_t* files, int* size)
{

    int i=0;
    FILE *rec_binp;

    /* dinamik array- hipte olusturuldu */
    Appointment_t *appoints;

    /* ilk size bulmak icin temporary array */
    Appointment_t temp[MAX_APPOINTMENT];

    rec_binp = fopen(files->records_file_n,"rb");
    if(rec_binp==NULL)
    {
        FILE_ERROR(files->records_file_n);	/* hatali dosya */
        exit(1);
    }

#ifdef DEBUG_READ_BIN
    printf("Binary file readed and appoinments saved...\n");
#endif

    /* binaryden okuma yapilip size bulunur */
    while(fread(&temp[i],sizeof(Appointment_t),1,rec_binp))
    {
#ifdef DEBUG
        PRINT_TEMP(temp[i]);	/* okumalar dogrumu diye kontrol */
#endif

        i++;
    }
    *size=i;	/* size bulundur */
#ifdef DEBUG 
	printf("Appointments size = %d\n",*size);
#endif
    fclose(rec_binp);


    /* Kapa ac yapilarak seek basa getirildi. */
	/* asil dinamic arraya doldurulacak - alan ihali olmayacak */
    rec_binp = fopen(files->records_file_n,"rb");

    if(rec_binp==NULL)
    {
        FILE_ERROR(files->records_file_n);	/* dosya acilmaz ise cikis */
        exit(1);
    }
    /* dinamic olarak yazildi - gereksiz alan kullanilmadi */

    appoints=(Appointment_t *)calloc(*size,sizeof(Appointment_t));   
	/* dynamic array yapildi */

	
    fread(appoints,sizeof(Appointment_t),*size,rec_binp);	/* array doldu */

#ifdef DEBUG_APPOINT_BIN
    DBG_MESSAGE;
    PRINT_TEMP(appoints[3]);	/* kontrol icin arrayin bi elemani basildi*/
#endif 

    fclose(rec_binp);	/* dosya kapandi */
    return appoints;/* array return edildi.'Heapte olusturuldu'*/
}
Exemple #25
0
/* read from or write to the file; back end to read() and write() */
static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
                         bool write)
{
    DEBUGF("readwrite(%p,%lx,%lu,%s)\n",
           file, (long)buf, (unsigned long)nbyte, write ? "write" : "read");

    const file_size_t size = *file->sizep;
    file_size_t filerem;

    if (write)
    {
        /* if opened in append mode, move pointer to end */
        if (file->stream.flags & FD_APPEND)
            file->offset = MIN(size, FILE_SIZE_MAX);

        filerem = FILE_SIZE_MAX - file->offset;
    }
    else
    {
        /* limit to maximum possible offset (EOF or FILE_SIZE_MAX) */
        filerem = MIN(size, FILE_SIZE_MAX) - file->offset;
    }

    if (nbyte > filerem)
    {
        nbyte = filerem;
        if (nbyte > 0)
            {}
        else if (write)
            FILE_ERROR_RETURN(EFBIG, -1);     /* would get too large */
        else if (file->offset >= FILE_SIZE_MAX)
            FILE_ERROR_RETURN(EOVERFLOW, -2); /* can't read here */
    }

    if (nbyte == 0)
        return 0;

    int rc = 0;

    struct filestr_cache * const cachep = file->stream.cachep;
    void * const bufstart = buf;

    const unsigned long filesectors = filesize_sectors(size);
    unsigned long sector = file->offset / SECTOR_SIZE;
    unsigned long sectoroffs = file->offset % SECTOR_SIZE;

    /* any head bytes? */
    if (sectoroffs)
    {
        size_t headbytes = MIN(nbyte, SECTOR_SIZE - sectoroffs);
        rc = readwrite_partial(file, cachep, sector, sectoroffs, buf, headbytes,
                               filesectors, write);
        if (rc <= 0)
        {
            if (rc < 0)
                FILE_ERROR(ERRNO, rc * 10 - 3);

            nbyte = 0; /* eof, skip the rest */
        }
        else
        {
            buf += rc;
            nbyte -= rc;
            sector++;  /* if nbyte goes to 0, the rest is skipped anyway */
        }
    }

    /* read/write whole sectors right into/from the supplied buffer */
    unsigned long sectorcount = nbyte / SECTOR_SIZE;

    while (sectorcount)
    {
        unsigned long runlen = sectorcount;

        /* if a cached sector is inside the transfer range, split the transfer
           into two parts and use the cache for that sector to keep it coherent
           without writeback */
        if (UNLIKELY(cachep->sector >= sector &&
                     cachep->sector < sector + sectorcount))
        {
            runlen = cachep->sector - sector;
        }

        if (runlen)
        {
            if (fat_query_sectornum(&file->stream.fatstr) != sector)
            {
                /* get on the correct sector */
                rc = 0;

                /* If the dirty bit isn't set, we're somehow beyond the file
                   size and you can't explain _that_ */
                if (sector >= filesectors && cachep->flags == (FSC_NEW|FSC_DIRTY))
                {
                    rc = flush_cache(file);
                    if (rc < 0)
                        FILE_ERROR(ERRNO, rc * 10 - 4);

                    if (cachep->sector + 1 == sector)
                        rc = 1; /* if now ok, don't seek */
                }

                if (rc == 0)
                {
                    rc = fat_seek(&file->stream.fatstr, sector);
                    if (rc < 0)
                        FILE_ERROR(EIO, rc * 10 - 5);
                }
            }

            rc = fat_readwrite(&file->stream.fatstr, runlen, buf, write);
            if (rc < 0)
            {
                DEBUGF("I/O error %sing %ld sectors\n",
                       write ? "writ" : "read", runlen);
                FILE_ERROR(rc == FAT_RC_ENOSPC ? ENOSPC : EIO,
                           rc * 10 - 6);
            }
            else
            {
                buf += rc * SECTOR_SIZE;
                nbyte -= rc * SECTOR_SIZE;
                sector += rc;
                sectorcount -= rc;

                /* if eof, skip tail bytes */
                if ((unsigned long)rc < runlen)
                    nbyte = 0;

                if (!nbyte)
                    break;
            }
        }

        if (UNLIKELY(sectorcount && sector == cachep->sector))
        {
            /* do this one sector with the cache */
            readwrite_cache(cachep, buf, 0, SECTOR_SIZE, write);
            buf += SECTOR_SIZE;
            nbyte -= SECTOR_SIZE;
            sector++;
            sectorcount--;
        }
    }

    /* any tail bytes? */
    if (nbyte)
    {
        /* tail bytes always start at sector offset 0 */
        rc = readwrite_partial(file, cachep, sector, 0, buf, nbyte,
                               filesectors, write);
        if (rc < 0)
            FILE_ERROR(ERRNO, rc * 10 - 7);

        buf += rc;
    }

file_error:;
#ifdef DEBUG
    if (errno == ENOSPC)
        DEBUGF("No space left on device\n");
#endif

    size_t done = buf - bufstart;
    if (done)
    {
        /* error or not, update the file offset and size if anything was
           transferred */
        file->offset += done;
        DEBUGF("file offset: %ld\n", file->offset);

        /* adjust file size to length written */
        if (write && file->offset > size)
            *file->sizep = file->offset;

        if (rc > 0)
            return done;
    }

    return rc;
}
Exemple #26
0
/* actually do the open gruntwork */
static int open_internal_inner2(const char *path,
                                struct filestr_desc *file,
                                unsigned int callflags)
{
    int rc;

    struct path_component_info compinfo;
    rc = open_stream_internal(path, callflags, &file->stream, &compinfo);
    if (rc < 0)
    {
        DEBUGF("Open failed: %d\n", rc);
        FILE_ERROR_RETURN(ERRNO, rc * 10 - 1);
    }

    bool created = false;

    if (rc > 0)
    {
        if (callflags & FF_EXCL)
        {
            DEBUGF("File exists\n");
            FILE_ERROR(EEXIST, -2);
        }

        if (compinfo.attr & ATTR_DIRECTORY)
        {
            if ((callflags & FD_WRITE) || !(callflags & FF_ANYTYPE))
            {
                DEBUGF("File is a directory\n");
                FILE_ERROR(EISDIR, -3);
            }

            compinfo.filesize = MAX_DIRECTORY_SIZE; /* allow file ops */
        }
    }
    else if (callflags & FF_CREAT)
    {
        if (compinfo.attr & ATTR_DIRECTORY)
        {
            DEBUGF("File is a directory\n");
            FILE_ERROR(EISDIR, -5);
        }

        /* not found; try to create it */

        callflags &= ~FO_TRUNC;
        rc = create_stream_internal(&compinfo.parentinfo, compinfo.name, 
                                    compinfo.length, ATTR_NEW_FILE, callflags,
                                    &file->stream);
        if (rc < 0)
            FILE_ERROR(ERRNO, rc * 10 - 6);

        created = true;
    }
    else
    {
        DEBUGF("File not found\n");
        FILE_ERROR(ENOENT, -7);
    }

    fat_rewind(&file->stream.fatstr);
    file->sizep = fileobj_get_sizep(&file->stream);
    file->offset = 0;

    if (!created)
    {
        /* size from storage applies to first stream only otherwise it's
           already up to date */
        const bool first = fileobj_get_flags(&file->stream) & FO_SINGLE;
        if (first)
            *file->sizep = compinfo.filesize;

        if (callflags & FO_TRUNC)
        {
            /* if the file is kind of "big" then free some space now */
            rc = ftruncate_internal(file, 0, *file->sizep >= O_TRUNC_THRESH);
            if (rc < 0)
            {
                DEBUGF("O_TRUNC failed: %d\n", rc);
                FILE_ERROR(ERRNO, rc * 10 - 4);
            }
        }
    }

    rc = 0;
file_error:
    if (rc < 0)
        close_stream_internal(&file->stream);

    return rc;
}