blob: 7c01f038171b4941d168ab6b69f974deed82f403 [file] [log] [blame]
Björn Stenberg4bd87032002-05-07 16:01:53 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Nicolas Pennequin357ffb32008-05-05 10:32:46 +000010 * Copyright (C) 2002 by Björn Stenberg
Björn Stenberg4bd87032002-05-07 16:01:53 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Björn Stenberg4bd87032002-05-07 16:01:53 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <string.h>
Björn Stenberg073ce1a2002-05-08 12:10:30 +000022#include <errno.h>
Björn Stenberg23820442002-05-13 12:29:34 +000023#include <stdbool.h>
Björn Stenberg4bd87032002-05-07 16:01:53 +000024#include "file.h"
25#include "fat.h"
Kevin Ferrare011a3252007-07-20 17:06:55 +000026#include "dir_uncached.h"
Björn Stenberg4bd87032002-05-07 16:01:53 +000027#include "debug.h"
Miika Pekkarinenab78b042005-10-07 17:38:05 +000028#include "dircache.h"
Jens Arnolda601fb82005-12-17 12:17:11 +000029#include "system.h"
Björn Stenberg4bd87032002-05-07 16:01:53 +000030
Björn Stenberg412917e2002-05-08 15:27:21 +000031/*
32 These functions provide a roughly POSIX-compatible file IO API.
33
34 Since the fat32 driver only manages sectors, we maintain a one-sector
35 cache for each open file. This way we can provide byte access without
36 having to re-read the sector each time.
37 The penalty is the RAM used for the cache and slightly more complex code.
38*/
39
Björn Stenberg4bd87032002-05-07 16:01:53 +000040struct filedesc {
Jens Arnoldef3e1292006-12-04 21:37:22 +000041 unsigned char cache[SECTOR_SIZE];
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +000042 int cacheoffset; /* invariant: 0 <= cacheoffset <= SECTOR_SIZE */
43 long fileoffset;
44 long size;
Björn Stenberg184fd552003-01-27 09:32:17 +000045 int attr;
Björn Stenberg4bd87032002-05-07 16:01:53 +000046 struct fat_file fatfile;
47 bool busy;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +000048 bool write;
Björn Stenberg228605d2002-11-11 13:57:58 +000049 bool dirty;
Björn Stenberg9f9c4952002-11-11 15:45:43 +000050 bool trunc;
Björn Stenberg4bd87032002-05-07 16:01:53 +000051};
52
53static struct filedesc openfiles[MAX_OPEN_FILES];
54
Björn Stenberg9f9c4952002-11-11 15:45:43 +000055static int flush_cache(int fd);
56
Jens Arnold67eb1542007-02-01 23:08:15 +000057int creat(const char *pathname)
Björn Stenbergb7b48fe2002-10-20 22:50:58 +000058{
Björn Stenberg7d8bbe72002-11-13 23:25:46 +000059 return open(pathname, O_WRONLY|O_CREAT|O_TRUNC);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +000060}
61
Miika Pekkarinend4893772006-04-13 21:14:13 +000062static int open_internal(const char* pathname, int flags, bool use_cache)
Björn Stenberg4bd87032002-05-07 16:01:53 +000063{
Kevin Ferrare011a3252007-07-20 17:06:55 +000064 DIR_UNCACHED* dir;
65 struct dirent_uncached* entry;
Björn Stenberg4bd87032002-05-07 16:01:53 +000066 int fd;
Jens Arnoldf68e13c2004-07-19 21:08:44 +000067 char pathnamecopy[MAX_PATH];
Björn Stenberg4bd87032002-05-07 16:01:53 +000068 char* name;
Björn Stenberg94fb95f2002-11-11 16:13:45 +000069 struct filedesc* file = NULL;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +000070 int rc;
Miika Pekkarinend4893772006-04-13 21:14:13 +000071#ifndef HAVE_DIRCACHE
72 (void)use_cache;
73#endif
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +000074
Björn Stenbergb7b48fe2002-10-20 22:50:58 +000075 LDEBUGF("open(\"%s\",%d)\n",pathname,flags);
Linus Nielsen Feltzing7fbdc362002-06-07 15:15:10 +000076
Björn Stenberg4bd87032002-05-07 16:01:53 +000077 if ( pathname[0] != '/' ) {
78 DEBUGF("'%s' is not an absolute path.\n",pathname);
79 DEBUGF("Only absolute pathnames supported at the moment\n");
Björn Stenberg073ce1a2002-05-08 12:10:30 +000080 errno = EINVAL;
Björn Stenberg4bd87032002-05-07 16:01:53 +000081 return -1;
82 }
83
84 /* find a free file descriptor */
85 for ( fd=0; fd<MAX_OPEN_FILES; fd++ )
86 if ( !openfiles[fd].busy )
87 break;
88
89 if ( fd == MAX_OPEN_FILES ) {
90 DEBUGF("Too many files open\n");
Björn Stenberg073ce1a2002-05-08 12:10:30 +000091 errno = EMFILE;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +000092 return -2;
Björn Stenberg4bd87032002-05-07 16:01:53 +000093 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +000094
95 file = &openfiles[fd];
96 memset(file, 0, sizeof(struct filedesc));
Björn Stenberg4bd87032002-05-07 16:01:53 +000097
Björn Stenberg4059ea62002-11-11 16:08:28 +000098 if (flags & (O_RDWR | O_WRONLY)) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +000099 file->write = true;
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000100
Björn Stenberg4059ea62002-11-11 16:08:28 +0000101 if (flags & O_TRUNC)
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000102 file->trunc = true;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000103 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000104 file->busy = true;
Björn Stenberg881cd232002-05-27 09:13:56 +0000105
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000106#ifdef HAVE_DIRCACHE
Miika Pekkarinend4893772006-04-13 21:14:13 +0000107 if (dircache_is_enabled() && !file->write && use_cache)
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000108 {
109 const struct dircache_entry *ce;
Miika Pekkarinend80246f2008-03-11 19:52:07 +0000110# ifdef HAVE_MULTIVOLUME
111 int volume = strip_volume(pathname, pathnamecopy);
112# endif
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000113
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000114 ce = dircache_get_entry_ptr(pathname);
115 if (!ce)
116 {
117 errno = ENOENT;
118 file->busy = false;
119 return -7;
120 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000121
Miika Pekkarinend80246f2008-03-11 19:52:07 +0000122 fat_open(IF_MV2(volume,)
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000123 ce->startcluster,
124 &(file->fatfile),
125 NULL);
126 file->size = ce->size;
127 file->attr = ce->attribute;
128 file->cacheoffset = -1;
129 file->fileoffset = 0;
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000130
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000131 return fd;
132 }
133#endif
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000134
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000135 strncpy(pathnamecopy,pathname,sizeof(pathnamecopy));
136 pathnamecopy[sizeof(pathnamecopy)-1] = 0;
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000137
Björn Stenberg4bd87032002-05-07 16:01:53 +0000138 /* locate filename */
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000139 name=strrchr(pathnamecopy+1,'/');
Björn Stenberg4bd87032002-05-07 16:01:53 +0000140 if ( name ) {
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000141 *name = 0;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000142 dir = opendir_uncached(pathnamecopy);
Björn Stenberg4bd87032002-05-07 16:01:53 +0000143 *name = '/';
144 name++;
145 }
146 else {
Kevin Ferrare011a3252007-07-20 17:06:55 +0000147 dir = opendir_uncached("/");
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000148 name = pathnamecopy+1;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000149 }
150 if (!dir) {
151 DEBUGF("Failed opening dir\n");
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000152 errno = EIO;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000153 file->busy = false;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000154 return -4;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000155 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000156
Linus Nielsen Feltzing05f1fc42004-02-11 14:37:16 +0000157 if(name[0] == 0) {
158 DEBUGF("Empty file name\n");
159 errno = EINVAL;
160 file->busy = false;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000161 closedir_uncached(dir);
Linus Nielsen Feltzing05f1fc42004-02-11 14:37:16 +0000162 return -5;
163 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000164
Björn Stenberg4bd87032002-05-07 16:01:53 +0000165 /* scan dir for name */
Kevin Ferrare011a3252007-07-20 17:06:55 +0000166 while ((entry = readdir_uncached(dir))) {
Daniel Stenberge666ce92002-08-22 20:13:21 +0000167 if ( !strcasecmp(name, entry->d_name) ) {
Jörg Hohensohnda848572004-12-28 22:16:07 +0000168 fat_open(IF_MV2(dir->fatdir.file.volume,)
169 entry->startcluster,
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000170 &(file->fatfile),
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000171 &(dir->fatdir));
Jens Arnold8537e2d2004-09-06 23:33:21 +0000172 file->size = file->trunc ? 0 : entry->size;
Björn Stenberg184fd552003-01-27 09:32:17 +0000173 file->attr = entry->attribute;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000174 break;
175 }
Björn Stenberg4bd87032002-05-07 16:01:53 +0000176 }
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000177
Björn Stenberg4bd87032002-05-07 16:01:53 +0000178 if ( !entry ) {
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000179 LDEBUGF("Didn't find file %s\n",name);
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000180 if ( file->write && (flags & O_CREAT) ) {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000181 rc = fat_create_file(name,
182 &(file->fatfile),
183 &(dir->fatdir));
184 if (rc < 0) {
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000185 DEBUGF("Couldn't create %s in %s\n",name,pathnamecopy);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000186 errno = EIO;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000187 file->busy = false;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000188 closedir_uncached(dir);
Linus Nielsen Feltzing05f1fc42004-02-11 14:37:16 +0000189 return rc * 10 - 6;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000190 }
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000191#ifdef HAVE_DIRCACHE
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000192 dircache_add_file(pathname, file->fatfile.firstcluster);
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000193#endif
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000194 file->size = 0;
Björn Stenberg184fd552003-01-27 09:32:17 +0000195 file->attr = 0;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000196 }
197 else {
Jens Arnoldf68e13c2004-07-19 21:08:44 +0000198 DEBUGF("Couldn't find %s in %s\n",name,pathnamecopy);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000199 errno = ENOENT;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000200 file->busy = false;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000201 closedir_uncached(dir);
Linus Nielsen Feltzing05f1fc42004-02-11 14:37:16 +0000202 return -7;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000203 }
Linus Nielsen Feltzing5c8e82e2004-03-10 19:47:59 +0000204 } else {
205 if(file->write && (file->attr & FAT_ATTR_DIRECTORY)) {
206 errno = EISDIR;
207 file->busy = false;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000208 closedir_uncached(dir);
Linus Nielsen Feltzing5c8e82e2004-03-10 19:47:59 +0000209 return -8;
210 }
Björn Stenberg4bd87032002-05-07 16:01:53 +0000211 }
Kevin Ferrare011a3252007-07-20 17:06:55 +0000212 closedir_uncached(dir);
Björn Stenberg4bd87032002-05-07 16:01:53 +0000213
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000214 file->cacheoffset = -1;
215 file->fileoffset = 0;
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000216
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000217 if (file->write && (flags & O_APPEND)) {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000218 rc = lseek(fd,0,SEEK_END);
219 if (rc < 0 )
Linus Nielsen Feltzing5c8e82e2004-03-10 19:47:59 +0000220 return rc * 10 - 9;
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000221 }
222
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000223#ifdef HAVE_DIRCACHE
224 if (file->write)
225 dircache_bind(fd, pathname);
226#endif
227
Björn Stenberg4bd87032002-05-07 16:01:53 +0000228 return fd;
229}
230
Miika Pekkarinend4893772006-04-13 21:14:13 +0000231int open(const char* pathname, int flags)
232{
233 /* By default, use the dircache if available. */
234 return open_internal(pathname, flags, true);
235}
236
Björn Stenberg4bd87032002-05-07 16:01:53 +0000237int close(int fd)
238{
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000239 struct filedesc* file = &openfiles[fd];
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000240 int rc = 0;
241
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000242 LDEBUGF("close(%d)\n", fd);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000243
Heikki Hannikainenadbe4ed2002-08-24 09:47:54 +0000244 if (fd < 0 || fd > MAX_OPEN_FILES-1) {
245 errno = EINVAL;
246 return -1;
247 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000248 if (!file->busy) {
Heikki Hannikainenadbe4ed2002-08-24 09:47:54 +0000249 errno = EBADF;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000250 return -2;
251 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000252 if (file->write) {
Björn Stenberga4baacd2003-06-29 13:17:19 +0000253 rc = fsync(fd);
Linus Nielsen Feltzing44e51832003-03-10 17:10:46 +0000254 if (rc < 0)
255 return rc * 10 - 3;
Hardeep Sidhu2436dba2006-05-16 06:53:41 +0000256#ifdef HAVE_DIRCACHE
257 dircache_update_filesize(fd, file->size, file->fatfile.firstcluster);
Jonathan Gordone73f2872007-09-02 13:24:51 +0000258 dircache_update_filetime(fd);
Hardeep Sidhu2436dba2006-05-16 06:53:41 +0000259#endif
Linus Nielsen Feltzing44e51832003-03-10 17:10:46 +0000260 }
261
262 file->busy = false;
263 return 0;
264}
265
Björn Stenberga4baacd2003-06-29 13:17:19 +0000266int fsync(int fd)
Linus Nielsen Feltzing44e51832003-03-10 17:10:46 +0000267{
268 struct filedesc* file = &openfiles[fd];
269 int rc = 0;
270
Björn Stenberga4baacd2003-06-29 13:17:19 +0000271 LDEBUGF("fsync(%d)\n", fd);
Linus Nielsen Feltzing44e51832003-03-10 17:10:46 +0000272
273 if (fd < 0 || fd > MAX_OPEN_FILES-1) {
274 errno = EINVAL;
275 return -1;
276 }
277 if (!file->busy) {
278 errno = EBADF;
279 return -2;
280 }
281 if (file->write) {
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000282 /* flush sector cache */
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000283 if ( file->dirty ) {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000284 rc = flush_cache(fd);
285 if (rc < 0)
Peter D'Hoye85058f52007-10-10 23:26:17 +0000286 {
287 /* when failing, try to close the file anyway */
288 fat_closewrite(&(file->fatfile), file->size, file->attr);
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000289 return rc * 10 - 3;
Peter D'Hoye85058f52007-10-10 23:26:17 +0000290 }
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000291 }
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000292
Björn Stenberg4cde17d2002-11-14 15:50:07 +0000293 /* truncate? */
294 if (file->trunc) {
Jens Arnold8537e2d2004-09-06 23:33:21 +0000295 rc = ftruncate(fd, file->size);
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000296 if (rc < 0)
Peter D'Hoye85058f52007-10-10 23:26:17 +0000297 {
298 /* when failing, try to close the file anyway */
299 fat_closewrite(&(file->fatfile), file->size, file->attr);
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000300 return rc * 10 - 4;
Peter D'Hoye85058f52007-10-10 23:26:17 +0000301 }
Björn Stenberg4cde17d2002-11-14 15:50:07 +0000302 }
303
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000304 /* tie up all loose ends */
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000305 rc = fat_closewrite(&(file->fatfile), file->size, file->attr);
306 if (rc < 0)
307 return rc * 10 - 5;
Heikki Hannikainenadbe4ed2002-08-24 09:47:54 +0000308 }
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000309 return 0;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000310}
311
Björn Stenberg307f5d82002-11-01 15:26:06 +0000312int remove(const char* name)
313{
314 int rc;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000315 struct filedesc* file;
Miika Pekkarinend4893772006-04-13 21:14:13 +0000316 /* Can't use dircache now, because we need to access the fat structures. */
317 int fd = open_internal(name, O_WRONLY, false);
Björn Stenberg307f5d82002-11-01 15:26:06 +0000318 if ( fd < 0 )
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000319 return fd * 10 - 1;
Björn Stenberg307f5d82002-11-01 15:26:06 +0000320
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000321 file = &openfiles[fd];
Miika Pekkarinen82f32e32006-03-30 10:20:44 +0000322#ifdef HAVE_DIRCACHE
323 dircache_remove(name);
324#endif
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000325 rc = fat_remove(&(file->fatfile));
Björn Stenberg11a09e62002-11-11 10:21:51 +0000326 if ( rc < 0 ) {
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000327 DEBUGF("Failed removing file: %d\n", rc);
Björn Stenberg11a09e62002-11-11 10:21:51 +0000328 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000329 return rc * 10 - 3;
Björn Stenberg11a09e62002-11-11 10:21:51 +0000330 }
331
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000332 file->size = 0;
Björn Stenberg307f5d82002-11-01 15:26:06 +0000333
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000334 rc = close(fd);
335 if (rc<0)
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000336 return rc * 10 - 4;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000337
338 return 0;
339}
340
341int rename(const char* path, const char* newpath)
342{
343 int rc, fd;
Kevin Ferrare011a3252007-07-20 17:06:55 +0000344 DIR_UNCACHED* dir;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000345 char* nameptr;
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000346 char* dirptr;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000347 struct filedesc* file;
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000348 char newpath2[MAX_PATH];
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000349
350 /* verify new path does not already exist */
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000351 /* If it is a directory, errno == EISDIR if the name exists */
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000352 fd = open(newpath, O_RDONLY);
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000353 if ( fd >= 0 || errno == EISDIR) {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000354 close(fd);
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000355 errno = EBUSY;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000356 return -1;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000357 }
Björn Stenberg307f5d82002-11-01 15:26:06 +0000358 close(fd);
359
Miika Pekkarinend4893772006-04-13 21:14:13 +0000360 fd = open_internal(path, O_RDONLY, false);
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000361 if ( fd < 0 ) {
362 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000363 return fd * 10 - 2;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000364 }
365
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000366 /* extract new file name */
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000367 nameptr = strrchr(newpath,'/');
368 if (nameptr)
369 nameptr++;
370 else
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000371 return - 3;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000372
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000373 /* Extract new path */
374 strcpy(newpath2, newpath);
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000375
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000376 dirptr = strrchr(newpath2,'/');
377 if(dirptr)
378 *dirptr = 0;
379 else
380 return - 4;
381
382 dirptr = newpath2;
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000383
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000384 if(strlen(dirptr) == 0) {
385 dirptr = "/";
386 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000387
Kevin Ferrare011a3252007-07-20 17:06:55 +0000388 dir = opendir_uncached(dirptr);
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000389 if(!dir)
390 return - 5;
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000391
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000392 file = &openfiles[fd];
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000393
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000394 rc = fat_rename(&file->fatfile, &dir->fatdir, nameptr,
395 file->size, file->attr);
Dan Evertonccd0e742006-03-02 11:03:34 +0000396#ifdef HAVE_MULTIVOLUME
397 if ( rc == -1) {
Jens Arnold7a0110e2006-03-02 22:29:53 +0000398 DEBUGF("Failed renaming file across volumnes: %d\n", rc);
399 errno = EXDEV;
400 return -6;
Dan Evertonccd0e742006-03-02 11:03:34 +0000401 }
402#endif
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000403 if ( rc < 0 ) {
404 DEBUGF("Failed renaming file: %d\n", rc);
405 errno = EIO;
Dan Evertonccd0e742006-03-02 11:03:34 +0000406 return rc * 10 - 7;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000407 }
408
Peter D'Hoyec04f49762008-02-07 22:15:13 +0000409#ifdef HAVE_DIRCACHE
410 dircache_rename(path, newpath);
411#endif
412
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000413 rc = close(fd);
414 if (rc<0) {
415 errno = EIO;
Dan Evertonccd0e742006-03-02 11:03:34 +0000416 return rc * 10 - 8;
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000417 }
418
Kevin Ferrare011a3252007-07-20 17:06:55 +0000419 rc = closedir_uncached(dir);
Linus Nielsen Feltzinge0e01402004-08-22 11:28:24 +0000420 if (rc<0) {
421 errno = EIO;
Dan Evertonccd0e742006-03-02 11:03:34 +0000422 return rc * 10 - 9;
Björn Stenbergc5f5be52002-11-19 12:48:50 +0000423 }
424
425 return 0;
Björn Stenberg307f5d82002-11-01 15:26:06 +0000426}
427
Daniel Stenbergae960a92003-12-08 21:58:38 +0000428int ftruncate(int fd, off_t size)
Björn Stenberg68640ed2002-11-11 14:40:18 +0000429{
430 int rc, sector;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000431 struct filedesc* file = &openfiles[fd];
Björn Stenberg68640ed2002-11-11 14:40:18 +0000432
Jens Arnoldef3e1292006-12-04 21:37:22 +0000433 sector = size / SECTOR_SIZE;
434 if (size % SECTOR_SIZE)
Björn Stenberg68640ed2002-11-11 14:40:18 +0000435 sector++;
436
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000437 rc = fat_seek(&(file->fatfile), sector);
Björn Stenberg68640ed2002-11-11 14:40:18 +0000438 if (rc < 0) {
439 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000440 return rc * 10 - 1;
Björn Stenberg68640ed2002-11-11 14:40:18 +0000441 }
442
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000443 rc = fat_truncate(&(file->fatfile));
Björn Stenberg68640ed2002-11-11 14:40:18 +0000444 if (rc < 0) {
445 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000446 return rc * 10 - 2;
Björn Stenberg68640ed2002-11-11 14:40:18 +0000447 }
448
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000449 file->size = size;
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000450#ifdef HAVE_DIRCACHE
451 dircache_update_filesize(fd, size, file->fatfile.firstcluster);
452#endif
Björn Stenberg68640ed2002-11-11 14:40:18 +0000453
454 return 0;
455}
456
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000457static int flush_cache(int fd)
458{
459 int rc;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000460 struct filedesc* file = &openfiles[fd];
Jens Arnoldef3e1292006-12-04 21:37:22 +0000461 long sector = file->fileoffset / SECTOR_SIZE;
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000462
Linus Nielsen Feltzing5f12c8f2003-03-10 21:55:59 +0000463 DEBUGF("Flushing dirty sector cache\n");
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000464
Hardeep Sidhue5e9bc32003-03-15 21:13:35 +0000465 /* make sure we are on correct sector */
466 rc = fat_seek(&(file->fatfile), sector);
467 if ( rc < 0 )
468 return rc * 10 - 3;
469
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000470 rc = fat_readwrite(&(file->fatfile), 1, file->cache, true );
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +0000471
472 if ( rc < 0 ) {
473 if(file->fatfile.eof)
474 errno = ENOSPC;
475
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000476 return rc * 10 - 2;
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +0000477 }
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000478
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000479 file->dirty = false;
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000480
481 return 0;
482}
483
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000484static int readwrite(int fd, void* buf, long count, bool write)
Björn Stenberg4bd87032002-05-07 16:01:53 +0000485{
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000486 long sectors;
487 long nread=0;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000488 struct filedesc* file = &openfiles[fd];
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000489 int rc;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000490
Peter D'Hoye85058f52007-10-10 23:26:17 +0000491 if (fd < 0 || fd > MAX_OPEN_FILES-1) {
492 errno = EINVAL;
493 return -1;
494 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000495 if ( !file->busy ) {
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000496 errno = EBADF;
497 return -1;
498 }
499
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000500 LDEBUGF( "readwrite(%d,%lx,%ld,%s)\n",
501 fd,(long)buf,count,write?"write":"read");
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000502
Björn Stenberg08356fb2002-10-31 19:05:25 +0000503 /* attempt to read past EOF? */
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000504 if (!write && count > file->size - file->fileoffset)
505 count = file->size - file->fileoffset;
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000506
507 /* any head bytes? */
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000508 if ( file->cacheoffset != -1 ) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000509 int offs = file->cacheoffset;
Jens Arnoldef3e1292006-12-04 21:37:22 +0000510 int headbytes = MIN(count, SECTOR_SIZE - offs);
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000511
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000512 if (write) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000513 memcpy( file->cache + offs, buf, headbytes );
Jens Arnolda601fb82005-12-17 12:17:11 +0000514 file->dirty = true;
515 }
516 else {
517 memcpy( buf, file->cache + offs, headbytes );
518 }
519
Jens Arnoldef3e1292006-12-04 21:37:22 +0000520 if (offs + headbytes == SECTOR_SIZE) {
Jens Arnolda601fb82005-12-17 12:17:11 +0000521 if (file->dirty) {
Daniel Stenberg50798122007-04-26 10:29:41 +0000522 rc = flush_cache(fd);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000523 if ( rc < 0 ) {
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000524 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000525 return rc * 10 - 2;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000526 }
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000527 }
Jens Arnolda601fb82005-12-17 12:17:11 +0000528 file->cacheoffset = -1;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000529 }
530 else {
Jens Arnolda601fb82005-12-17 12:17:11 +0000531 file->cacheoffset += headbytes;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000532 }
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000533
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000534 nread = headbytes;
535 count -= headbytes;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000536 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000537
Jens Arnoldf78524b2004-11-17 02:34:17 +0000538 /* If the buffer has been modified, either it has been flushed already
539 * (if (offs+headbytes == SECTOR_SIZE)...) or does not need to be (no
540 * more data to follow in this call). Do NOT flush here. */
Björn Stenberg228605d2002-11-11 13:57:58 +0000541
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +0000542 /* read/write whole sectors right into/from the supplied buffer */
Jens Arnoldef3e1292006-12-04 21:37:22 +0000543 sectors = count / SECTOR_SIZE;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000544 if ( sectors ) {
Daniel Stenberg50798122007-04-26 10:29:41 +0000545 rc = fat_readwrite(&(file->fatfile), sectors,
Jörg Hohensohn85c91a32004-10-01 19:45:51 +0000546 (unsigned char*)buf+nread, write );
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000547 if ( rc < 0 ) {
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000548 DEBUGF("Failed read/writing %ld sectors\n",sectors);
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000549 errno = EIO;
Linus Nielsen Feltzingc6db7872003-06-19 12:08:22 +0000550 if(write && file->fatfile.eof) {
551 DEBUGF("No space left on device\n");
552 errno = ENOSPC;
553 } else {
554 file->fileoffset += nread;
555 }
Björn Stenberg631b8d32003-04-15 08:07:50 +0000556 file->cacheoffset = -1;
Peter D'Hoyeeb947cd2007-12-13 23:36:22 +0000557 /* adjust file size to length written */
558 if ( write && file->fileoffset > file->size )
559 {
560 file->size = file->fileoffset;
561#ifdef HAVE_DIRCACHE
562 dircache_update_filesize(fd, file->size, file->fatfile.firstcluster);
563#endif
564 }
Björn Stenberg188be8e2003-03-12 15:06:57 +0000565 return nread ? nread : rc * 10 - 4;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000566 }
Björn Stenberg4bd87032002-05-07 16:01:53 +0000567 else {
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000568 if ( rc > 0 ) {
Jens Arnoldef3e1292006-12-04 21:37:22 +0000569 nread += rc * SECTOR_SIZE;
570 count -= sectors * SECTOR_SIZE;
Björn Stenberg08356fb2002-10-31 19:05:25 +0000571
572 /* if eof, skip tail bytes */
573 if ( rc < sectors )
574 count = 0;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000575 }
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000576 else {
577 /* eof */
578 count=0;
579 }
580
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000581 file->cacheoffset = -1;
Björn Stenberg4bd87032002-05-07 16:01:53 +0000582 }
583 }
584
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000585 /* any tail bytes? */
586 if ( count ) {
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000587 if (write) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000588 if ( file->fileoffset + nread < file->size ) {
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000589 /* sector is only partially filled. copy-back from disk */
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000590 LDEBUGF("Copy-back tail cache\n");
Björn Stenberg631b8d32003-04-15 08:07:50 +0000591 rc = fat_readwrite(&(file->fatfile), 1, file->cache, false );
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000592 if ( rc < 0 ) {
Linus Nielsen Feltzing490085a2003-02-22 01:54:03 +0000593 DEBUGF("Failed writing\n");
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000594 errno = EIO;
Björn Stenberg631b8d32003-04-15 08:07:50 +0000595 file->fileoffset += nread;
596 file->cacheoffset = -1;
Peter D'Hoyeeb947cd2007-12-13 23:36:22 +0000597 /* adjust file size to length written */
598 if ( file->fileoffset > file->size )
599 {
600 file->size = file->fileoffset;
601#ifdef HAVE_DIRCACHE
602 dircache_update_filesize(fd, file->size, file->fatfile.firstcluster);
603#endif
604 }
Björn Stenberg188be8e2003-03-12 15:06:57 +0000605 return nread ? nread : rc * 10 - 5;
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000606 }
607 /* seek back one sector to put file position right */
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000608 rc = fat_seek(&(file->fatfile),
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000609 (file->fileoffset + nread) /
Jens Arnoldef3e1292006-12-04 21:37:22 +0000610 SECTOR_SIZE);
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000611 if ( rc < 0 ) {
612 DEBUGF("fat_seek() failed\n");
613 errno = EIO;
Björn Stenberg631b8d32003-04-15 08:07:50 +0000614 file->fileoffset += nread;
615 file->cacheoffset = -1;
Peter D'Hoyeeb947cd2007-12-13 23:36:22 +0000616 /* adjust file size to length written */
617 if ( file->fileoffset > file->size )
618 {
619 file->size = file->fileoffset;
620#ifdef HAVE_DIRCACHE
621 dircache_update_filesize(fd, file->size, file->fatfile.firstcluster);
622#endif
623 }
Björn Stenberg188be8e2003-03-12 15:06:57 +0000624 return nread ? nread : rc * 10 - 6;
Björn Stenberg6dc77d82002-11-11 11:16:49 +0000625 }
Björn Stenberg11a09e62002-11-11 10:21:51 +0000626 }
Jörg Hohensohn85c91a32004-10-01 19:45:51 +0000627 memcpy( file->cache, (unsigned char*)buf + nread, count );
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000628 file->dirty = true;
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000629 }
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000630 else {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000631 rc = fat_readwrite(&(file->fatfile), 1, &(file->cache),false);
632 if (rc < 1 ) {
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000633 DEBUGF("Failed caching sector\n");
634 errno = EIO;
Björn Stenberg631b8d32003-04-15 08:07:50 +0000635 file->fileoffset += nread;
636 file->cacheoffset = -1;
Björn Stenberg188be8e2003-03-12 15:06:57 +0000637 return nread ? nread : rc * 10 - 7;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000638 }
Jörg Hohensohn85c91a32004-10-01 19:45:51 +0000639 memcpy( (unsigned char*)buf + nread, file->cache, count );
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000640 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000641
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000642 nread += count;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000643 file->cacheoffset = count;
Björn Stenberg073ce1a2002-05-08 12:10:30 +0000644 }
645
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000646 file->fileoffset += nread;
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000647 LDEBUGF("fileoffset: %ld\n", file->fileoffset);
Björn Stenberg08356fb2002-10-31 19:05:25 +0000648
649 /* adjust file size to length written */
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000650 if ( write && file->fileoffset > file->size )
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000651 {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000652 file->size = file->fileoffset;
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000653#ifdef HAVE_DIRCACHE
Miika Pekkarinen2d934952006-03-28 11:51:12 +0000654 dircache_update_filesize(fd, file->size, file->fatfile.firstcluster);
Miika Pekkarinenab78b042005-10-07 17:38:05 +0000655#endif
656 }
Björn Stenberg08356fb2002-10-31 19:05:25 +0000657
Björn Stenberg4bd87032002-05-07 16:01:53 +0000658 return nread;
659}
660
Daniel Stenbergae960a92003-12-08 21:58:38 +0000661ssize_t write(int fd, const void* buf, size_t count)
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000662{
Björn Stenberg228605d2002-11-11 13:57:58 +0000663 if (!openfiles[fd].write) {
664 errno = EACCES;
665 return -1;
666 }
Daniel Stenbergae960a92003-12-08 21:58:38 +0000667 return readwrite(fd, (void *)buf, count, true);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000668}
669
Daniel Stenbergae960a92003-12-08 21:58:38 +0000670ssize_t read(int fd, void* buf, size_t count)
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000671{
672 return readwrite(fd, buf, count, false);
673}
674
675
Daniel Stenbergae960a92003-12-08 21:58:38 +0000676off_t lseek(int fd, off_t offset, int whence)
Björn Stenberg1c321792002-05-08 15:16:02 +0000677{
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000678 off_t pos;
679 long newsector;
680 long oldsector;
Björn Stenberg1c321792002-05-08 15:16:02 +0000681 int sectoroffset;
682 int rc;
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000683 struct filedesc* file = &openfiles[fd];
Björn Stenberg1c321792002-05-08 15:16:02 +0000684
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000685 LDEBUGF("lseek(%d,%ld,%d)\n",fd,offset,whence);
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000686
Peter D'Hoye85058f52007-10-10 23:26:17 +0000687 if (fd < 0 || fd > MAX_OPEN_FILES-1) {
688 errno = EINVAL;
689 return -1;
690 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000691 if ( !file->busy ) {
Björn Stenberg1c321792002-05-08 15:16:02 +0000692 errno = EBADF;
693 return -1;
694 }
695
696 switch ( whence ) {
697 case SEEK_SET:
698 pos = offset;
699 break;
700
701 case SEEK_CUR:
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000702 pos = file->fileoffset + offset;
Björn Stenberg1c321792002-05-08 15:16:02 +0000703 break;
704
705 case SEEK_END:
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000706 pos = file->size + offset;
Björn Stenberg1c321792002-05-08 15:16:02 +0000707 break;
708
709 default:
710 errno = EINVAL;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000711 return -2;
Björn Stenberg1c321792002-05-08 15:16:02 +0000712 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000713 if ((pos < 0) || (pos > file->size)) {
Björn Stenberg1c321792002-05-08 15:16:02 +0000714 errno = EINVAL;
Björn Stenbergb7b48fe2002-10-20 22:50:58 +0000715 return -3;
Björn Stenberg1c321792002-05-08 15:16:02 +0000716 }
717
718 /* new sector? */
Jens Arnoldef3e1292006-12-04 21:37:22 +0000719 newsector = pos / SECTOR_SIZE;
720 oldsector = file->fileoffset / SECTOR_SIZE;
721 sectoroffset = pos % SECTOR_SIZE;
Björn Stenberg1c321792002-05-08 15:16:02 +0000722
723 if ( (newsector != oldsector) ||
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000724 ((file->cacheoffset==-1) && sectoroffset) ) {
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000725
Björn Stenberg1c321792002-05-08 15:16:02 +0000726 if ( newsector != oldsector ) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000727 if (file->dirty) {
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000728 rc = flush_cache(fd);
729 if (rc < 0)
730 return rc * 10 - 5;
Björn Stenberg9f9c4952002-11-11 15:45:43 +0000731 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000732
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000733 rc = fat_seek(&(file->fatfile), newsector);
Björn Stenberg1c321792002-05-08 15:16:02 +0000734 if ( rc < 0 ) {
735 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000736 return rc * 10 - 4;
Björn Stenberg1c321792002-05-08 15:16:02 +0000737 }
738 }
Björn Stenberg675d2582002-10-31 20:41:36 +0000739 if ( sectoroffset ) {
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000740 rc = fat_readwrite(&(file->fatfile), 1,
741 &(file->cache),false);
Björn Stenberg675d2582002-10-31 20:41:36 +0000742 if ( rc < 0 ) {
743 errno = EIO;
Linus Nielsen Feltzinga077e272003-02-26 02:08:52 +0000744 return rc * 10 - 6;
Björn Stenberg675d2582002-10-31 20:41:36 +0000745 }
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000746 file->cacheoffset = sectoroffset;
Björn Stenberg1c321792002-05-08 15:16:02 +0000747 }
Björn Stenbergc9fb0982002-11-04 14:59:46 +0000748 else
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000749 file->cacheoffset = -1;
Björn Stenberg1c321792002-05-08 15:16:02 +0000750 }
Björn Stenberg88c861e2002-06-26 14:21:25 +0000751 else
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000752 if ( file->cacheoffset != -1 )
753 file->cacheoffset = sectoroffset;
Björn Stenberg1c321792002-05-08 15:16:02 +0000754
Björn Stenberg94fb95f2002-11-11 16:13:45 +0000755 file->fileoffset = pos;
Björn Stenberg1c321792002-05-08 15:16:02 +0000756
757 return pos;
758}
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000759
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +0000760off_t filesize(int fd)
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000761{
762 struct filedesc* file = &openfiles[fd];
763
Peter D'Hoye85058f52007-10-10 23:26:17 +0000764 if (fd < 0 || fd > MAX_OPEN_FILES-1) {
765 errno = EINVAL;
766 return -1;
767 }
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000768 if ( !file->busy ) {
769 errno = EBADF;
770 return -1;
771 }
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000772
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000773 return file->size;
774}
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000775
776
777#ifdef HAVE_HOTSWAP
Peter D'Hoyebae8f4c2007-10-29 00:04:35 +0000778/* release all file handles on a given volume "by force", to avoid leaks */
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000779int release_files(int volume)
780{
781 struct filedesc* pfile = openfiles;
782 int fd;
783 int closed = 0;
784 for ( fd=0; fd<MAX_OPEN_FILES; fd++, pfile++)
785 {
786 if (pfile->fatfile.volume == volume)
787 {
788 pfile->busy = false; /* mark as available, no further action */
789 closed++;
790 }
791 }
792 return closed; /* return how many we did */
793}
794#endif /* #ifdef HAVE_HOTSWAP */
Peter D'Hoye85058f52007-10-10 23:26:17 +0000795