/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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 */ }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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; }
/* 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); }
/* 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; } }
/* 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'*/ }
/* 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; }
/* 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; }