blob: 111cb348c0dc66c98cb41af24c5810d16cea2edc [file] [log] [blame]
William Juulc051bbe2007-11-15 11:13:05 +01001/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
Wolfgang Denk74e0dde2008-08-14 14:41:06 +020013
William Juule24ebad2007-11-15 12:23:57 +010014/* XXX U-BOOT XXX */
15#include <common.h>
16#include <malloc.h>
17
William Juulc051bbe2007-11-15 11:13:05 +010018#include "yaffsfs.h"
19#include "yaffs_guts.h"
20#include "yaffscfg.h"
William Juulc051bbe2007-11-15 11:13:05 +010021#include "yportenv.h"
22
William Juule24ebad2007-11-15 12:23:57 +010023/* XXX U-BOOT XXX */
24#if 0
25#include <string.h> // for memset
26#endif
27
William Juulc051bbe2007-11-15 11:13:05 +010028#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
29
30#ifndef NULL
31#define NULL ((void *)0)
32#endif
33
34
35const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $";
36
37// configurationList is the list of devices that are supported
38static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
39
40
41/* Some forward references */
42static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
43static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
44
45
46// Handle management.
Wolfgang Denk74e0dde2008-08-14 14:41:06 +020047//
William Juulc051bbe2007-11-15 11:13:05 +010048
49
50unsigned int yaffs_wr_attempts;
51
52typedef struct
53{
54 __u8 inUse:1; // this handle is in use
55 __u8 readOnly:1; // this handle is read only
56 __u8 append:1; // append only
57 __u8 exclusive:1; // exclusive
58 __u32 position; // current position in file
59 yaffs_Object *obj; // the object
60}yaffsfs_Handle;
61
62
63static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
64
65// yaffsfs_InitHandle
66/// Inilitalise handles on start-up.
67//
68static int yaffsfs_InitHandles(void)
69{
70 int i;
71 for(i = 0; i < YAFFSFS_N_HANDLES; i++)
72 {
73 yaffsfs_handle[i].inUse = 0;
74 yaffsfs_handle[i].obj = NULL;
75 }
76 return 0;
77}
78
79yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
80{
81 if(h < 0 || h >= YAFFSFS_N_HANDLES)
82 {
83 return NULL;
84 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +020085
William Juulc051bbe2007-11-15 11:13:05 +010086 return &yaffsfs_handle[h];
87}
88
89yaffs_Object *yaffsfs_GetHandleObject(int handle)
90{
91 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
92
93 if(h && h->inUse)
94 {
95 return h->obj;
96 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +020097
William Juulc051bbe2007-11-15 11:13:05 +010098 return NULL;
99}
100
101
102//yaffsfs_GetHandle
103// Grab a handle (when opening a file)
104//
105
106static int yaffsfs_GetHandle(void)
107{
108 int i;
109 yaffsfs_Handle *h;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200110
William Juulc051bbe2007-11-15 11:13:05 +0100111 for(i = 0; i < YAFFSFS_N_HANDLES; i++)
112 {
113 h = yaffsfs_GetHandlePointer(i);
114 if(!h)
115 {
116 // todo bug: should never happen
117 }
118 if(!h->inUse)
119 {
120 memset(h,0,sizeof(yaffsfs_Handle));
121 h->inUse=1;
122 return i;
123 }
124 }
125 return -1;
126}
127
128// yaffs_PutHandle
129// Let go of a handle (when closing a file)
130//
131static int yaffsfs_PutHandle(int handle)
132{
133 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200134
William Juulc051bbe2007-11-15 11:13:05 +0100135 if(h)
136 {
137 h->inUse = 0;
138 h->obj = NULL;
139 }
140 return 0;
141}
142
143
144
145// Stuff to search for a directory from a path
146
147
148int yaffsfs_Match(char a, char b)
149{
150 // case sensitive
151 return (a == b);
152}
153
154// yaffsfs_FindDevice
155// yaffsfs_FindRoot
156// Scan the configuration list to find the root.
157// Curveballs: Should match paths that end in '/' too
158// Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
159static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
160{
161 yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
162 const char *leftOver;
163 const char *p;
164 yaffs_Device *retval = NULL;
165 int thisMatchLength;
166 int longestMatch = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200167
William Juulc051bbe2007-11-15 11:13:05 +0100168 // Check all configs, choose the one that:
169 // 1) Actually matches a prefix (ie /a amd /abc will not match
170 // 2) Matches the longest.
171 while(cfg && cfg->prefix && cfg->dev)
172 {
173 leftOver = path;
174 p = cfg->prefix;
175 thisMatchLength = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200176
177 while(*p && //unmatched part of prefix
William Juulc051bbe2007-11-15 11:13:05 +0100178 strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200179 *leftOver &&
William Juulc051bbe2007-11-15 11:13:05 +0100180 yaffsfs_Match(*p,*leftOver))
181 {
182 p++;
183 leftOver++;
184 thisMatchLength++;
185 }
186 if((!*p || strcmp(p,"/") == 0) && // end of prefix
187 (!*leftOver || *leftOver == '/') && // no more in this path name part
188 (thisMatchLength > longestMatch))
189 {
190 // Matched prefix
191 *restOfPath = (char *)leftOver;
192 retval = cfg->dev;
193 longestMatch = thisMatchLength;
194 }
195 cfg++;
196 }
197 return retval;
198}
199
200static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
201{
202
203 yaffs_Device *dev;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200204
William Juulc051bbe2007-11-15 11:13:05 +0100205 dev= yaffsfs_FindDevice(path,restOfPath);
206 if(dev && dev->isMounted)
207 {
208 return dev->rootDir;
209 }
210 return NULL;
211}
212
213static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
214{
215
216 while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
217 {
218 char *alias = obj->variant.symLinkVariant.alias;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200219
William Juulc051bbe2007-11-15 11:13:05 +0100220 if(*alias == '/')
221 {
222 // Starts with a /, need to scan from root up
223 obj = yaffsfs_FindObject(NULL,alias,symDepth++);
224 }
225 else
226 {
227 // Relative to here, so use the parent of the symlink as a start
228 obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
229 }
230 }
231 return obj;
232}
233
234
235// yaffsfs_FindDirectory
236// Parse a path to determine the directory and the name within the directory.
237//
238// eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
239static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth)
240{
241 yaffs_Object *dir;
242 char *restOfPath;
243 char str[YAFFS_MAX_NAME_LENGTH+1];
244 int i;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200245
William Juulc051bbe2007-11-15 11:13:05 +0100246 if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
247 {
248 return NULL;
249 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200250
William Juulc051bbe2007-11-15 11:13:05 +0100251 if(startDir)
252 {
253 dir = startDir;
254 restOfPath = (char *)path;
255 }
256 else
257 {
258 dir = yaffsfs_FindRoot(path,&restOfPath);
259 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200260
William Juulc051bbe2007-11-15 11:13:05 +0100261 while(dir)
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200262 {
William Juulc051bbe2007-11-15 11:13:05 +0100263 // parse off /.
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200264 // curve ball: also throw away surplus '/'
William Juulc051bbe2007-11-15 11:13:05 +0100265 // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
266 while(*restOfPath == '/')
267 {
268 restOfPath++; // get rid of '/'
269 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200270
William Juulc051bbe2007-11-15 11:13:05 +0100271 *name = restOfPath;
272 i = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200273
William Juulc051bbe2007-11-15 11:13:05 +0100274 while(*restOfPath && *restOfPath != '/')
275 {
276 if (i < YAFFS_MAX_NAME_LENGTH)
277 {
278 str[i] = *restOfPath;
279 str[i+1] = '\0';
280 i++;
281 }
282 restOfPath++;
283 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200284
William Juulc051bbe2007-11-15 11:13:05 +0100285 if(!*restOfPath)
286 {
287 // got to the end of the string
288 return dir;
289 }
290 else
291 {
292 if(strcmp(str,".") == 0)
293 {
294 // Do nothing
295 }
296 else if(strcmp(str,"..") == 0)
297 {
298 dir = dir->parent;
299 }
300 else
301 {
302 dir = yaffs_FindObjectByName(dir,str);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200303
William Juulc051bbe2007-11-15 11:13:05 +0100304 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
305 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200306
William Juulc051bbe2007-11-15 11:13:05 +0100307 dir = yaffsfs_FollowLink(dir,symDepth);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200308
William Juulc051bbe2007-11-15 11:13:05 +0100309 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200310
William Juulc051bbe2007-11-15 11:13:05 +0100311 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
312 {
313 dir = NULL;
314 }
315 }
316 }
317 }
318 // directory did not exist.
319 return NULL;
320}
321
322static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth)
323{
324 return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
325}
326
327// yaffsfs_FindObject turns a path for an existing object into the object
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200328//
William Juulc051bbe2007-11-15 11:13:05 +0100329static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth)
330{
331 yaffs_Object *dir;
332 char *name;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200333
William Juulc051bbe2007-11-15 11:13:05 +0100334 dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200335
William Juulc051bbe2007-11-15 11:13:05 +0100336 if(dir && *name)
337 {
338 return yaffs_FindObjectByName(dir,name);
339 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200340
William Juulc051bbe2007-11-15 11:13:05 +0100341 return dir;
342}
343
344
345
346int yaffs_open(const char *path, int oflag, int mode)
347{
348 yaffs_Object *obj = NULL;
349 yaffs_Object *dir = NULL;
350 char *name;
351 int handle = -1;
352 yaffsfs_Handle *h = NULL;
353 int alreadyOpen = 0;
354 int alreadyExclusive = 0;
355 int openDenied = 0;
356 int symDepth = 0;
357 int errorReported = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200358
William Juulc051bbe2007-11-15 11:13:05 +0100359 int i;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200360
361
William Juulc051bbe2007-11-15 11:13:05 +0100362 // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200363
364
William Juulc051bbe2007-11-15 11:13:05 +0100365 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200366
William Juulc051bbe2007-11-15 11:13:05 +0100367 handle = yaffsfs_GetHandle();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200368
William Juulc051bbe2007-11-15 11:13:05 +0100369 if(handle >= 0)
370 {
371
372 h = yaffsfs_GetHandlePointer(handle);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200373
374
William Juulc051bbe2007-11-15 11:13:05 +0100375 // try to find the exisiting object
376 obj = yaffsfs_FindObject(NULL,path,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200377
William Juulc051bbe2007-11-15 11:13:05 +0100378 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
379 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200380
William Juulc051bbe2007-11-15 11:13:05 +0100381 obj = yaffsfs_FollowLink(obj,symDepth++);
382 }
383
384 if(obj)
385 {
386 // Check if the object is already in use
387 alreadyOpen = alreadyExclusive = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200388
William Juulc051bbe2007-11-15 11:13:05 +0100389 for(i = 0; i <= YAFFSFS_N_HANDLES; i++)
390 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200391
William Juulc051bbe2007-11-15 11:13:05 +0100392 if(i != handle &&
393 yaffsfs_handle[i].inUse &&
394 obj == yaffsfs_handle[i].obj)
395 {
396 alreadyOpen = 1;
397 if(yaffsfs_handle[i].exclusive)
398 {
399 alreadyExclusive = 1;
400 }
401 }
402 }
403
404 if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
405 {
406 openDenied = 1;
407 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200408
William Juulc051bbe2007-11-15 11:13:05 +0100409 // Open should fail if O_CREAT and O_EXCL are specified
410 if((oflag & O_EXCL) && (oflag & O_CREAT))
411 {
412 openDenied = 1;
413 yaffsfs_SetError(-EEXIST);
414 errorReported = 1;
415 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200416
William Juulc051bbe2007-11-15 11:13:05 +0100417 // Check file permissions
418 if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY
419 !(obj->yst_mode & S_IREAD))
420 {
421 openDenied = 1;
422 }
423
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200424 if( (oflag & O_RDWR) &&
William Juulc051bbe2007-11-15 11:13:05 +0100425 !(obj->yst_mode & S_IREAD))
426 {
427 openDenied = 1;
428 }
429
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200430 if( (oflag & (O_RDWR | O_WRONLY)) &&
William Juulc051bbe2007-11-15 11:13:05 +0100431 !(obj->yst_mode & S_IWRITE))
432 {
433 openDenied = 1;
434 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200435
William Juulc051bbe2007-11-15 11:13:05 +0100436 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200437
William Juulc051bbe2007-11-15 11:13:05 +0100438 else if((oflag & O_CREAT))
439 {
440 // Let's see if we can create this file
441 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
442 if(dir)
443 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200444 obj = yaffs_MknodFile(dir,name,mode,0,0);
William Juulc051bbe2007-11-15 11:13:05 +0100445 }
446 else
447 {
448 yaffsfs_SetError(-ENOTDIR);
449 }
450 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200451
William Juulc051bbe2007-11-15 11:13:05 +0100452 if(obj && !openDenied)
453 {
454 h->obj = obj;
455 h->inUse = 1;
456 h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
457 h->append = (oflag & O_APPEND) ? 1 : 0;
458 h->exclusive = (oflag & O_EXCL) ? 1 : 0;
459 h->position = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200460
William Juulc051bbe2007-11-15 11:13:05 +0100461 obj->inUse++;
462 if((oflag & O_TRUNC) && !h->readOnly)
463 {
464 //todo truncate
465 yaffs_ResizeFile(obj,0);
466 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200467
William Juulc051bbe2007-11-15 11:13:05 +0100468 }
469 else
470 {
471 yaffsfs_PutHandle(handle);
472 if(!errorReported)
473 {
474 yaffsfs_SetError(-EACCESS);
475 errorReported = 1;
476 }
477 handle = -1;
478 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200479
William Juulc051bbe2007-11-15 11:13:05 +0100480 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200481
William Juulc051bbe2007-11-15 11:13:05 +0100482 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200483
484 return handle;
William Juulc051bbe2007-11-15 11:13:05 +0100485}
486
487int yaffs_close(int fd)
488{
489 yaffsfs_Handle *h = NULL;
490 int retVal = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200491
William Juulc051bbe2007-11-15 11:13:05 +0100492 yaffsfs_Lock();
493
494 h = yaffsfs_GetHandlePointer(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200495
William Juulc051bbe2007-11-15 11:13:05 +0100496 if(h && h->inUse)
497 {
498 // clean up
499 yaffs_FlushFile(h->obj,1);
500 h->obj->inUse--;
501 if(h->obj->inUse <= 0 && h->obj->unlinked)
502 {
503 yaffs_DeleteFile(h->obj);
504 }
505 yaffsfs_PutHandle(fd);
506 retVal = 0;
507 }
508 else
509 {
510 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200511 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100512 retVal = -1;
513 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200514
William Juulc051bbe2007-11-15 11:13:05 +0100515 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200516
William Juulc051bbe2007-11-15 11:13:05 +0100517 return retVal;
518}
519
520int yaffs_read(int fd, void *buf, unsigned int nbyte)
521{
522 yaffsfs_Handle *h = NULL;
523 yaffs_Object *obj = NULL;
524 int pos = 0;
525 int nRead = -1;
526 int maxRead;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200527
William Juulc051bbe2007-11-15 11:13:05 +0100528 yaffsfs_Lock();
529 h = yaffsfs_GetHandlePointer(fd);
530 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200531
William Juulc051bbe2007-11-15 11:13:05 +0100532 if(!h || !obj)
533 {
534 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200535 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100536 }
537 else if( h && obj)
538 {
539 pos= h->position;
540 if(yaffs_GetObjectFileLength(obj) > pos)
541 {
542 maxRead = yaffs_GetObjectFileLength(obj) - pos;
543 }
544 else
545 {
546 maxRead = 0;
547 }
548
549 if(nbyte > maxRead)
550 {
551 nbyte = maxRead;
552 }
553
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200554
William Juulc051bbe2007-11-15 11:13:05 +0100555 if(nbyte > 0)
556 {
557 nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
558 if(nRead >= 0)
559 {
560 h->position = pos + nRead;
561 }
562 else
563 {
564 //todo error
565 }
566 }
567 else
568 {
569 nRead = 0;
570 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200571
William Juulc051bbe2007-11-15 11:13:05 +0100572 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200573
William Juulc051bbe2007-11-15 11:13:05 +0100574 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200575
576
William Juulc051bbe2007-11-15 11:13:05 +0100577 return (nRead >= 0) ? nRead : -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200578
William Juulc051bbe2007-11-15 11:13:05 +0100579}
580
581int yaffs_write(int fd, const void *buf, unsigned int nbyte)
582{
583 yaffsfs_Handle *h = NULL;
584 yaffs_Object *obj = NULL;
585 int pos = 0;
586 int nWritten = -1;
587 int writeThrough = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200588
William Juulc051bbe2007-11-15 11:13:05 +0100589 yaffsfs_Lock();
590 h = yaffsfs_GetHandlePointer(fd);
591 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200592
William Juulc051bbe2007-11-15 11:13:05 +0100593 if(!h || !obj)
594 {
595 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200596 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100597 }
598 else if( h && obj && h->readOnly)
599 {
600 // todo error
601 }
602 else if( h && obj)
603 {
604 if(h->append)
605 {
606 pos = yaffs_GetObjectFileLength(obj);
607 }
608 else
609 {
610 pos = h->position;
611 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200612
William Juulc051bbe2007-11-15 11:13:05 +0100613 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200614
William Juulc051bbe2007-11-15 11:13:05 +0100615 if(nWritten >= 0)
616 {
617 h->position = pos + nWritten;
618 }
619 else
620 {
621 //todo error
622 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200623
William Juulc051bbe2007-11-15 11:13:05 +0100624 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200625
William Juulc051bbe2007-11-15 11:13:05 +0100626 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200627
628
William Juulc051bbe2007-11-15 11:13:05 +0100629 return (nWritten >= 0) ? nWritten : -1;
630
631}
632
633int yaffs_truncate(int fd, off_t newSize)
634{
635 yaffsfs_Handle *h = NULL;
636 yaffs_Object *obj = NULL;
637 int result = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200638
William Juulc051bbe2007-11-15 11:13:05 +0100639 yaffsfs_Lock();
640 h = yaffsfs_GetHandlePointer(fd);
641 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200642
William Juulc051bbe2007-11-15 11:13:05 +0100643 if(!h || !obj)
644 {
645 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200646 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100647 }
648 else
649 {
650 // resize the file
651 result = yaffs_ResizeFile(obj,newSize);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200652 }
William Juulc051bbe2007-11-15 11:13:05 +0100653 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200654
655
William Juulc051bbe2007-11-15 11:13:05 +0100656 return (result) ? 0 : -1;
657
658}
659
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200660off_t yaffs_lseek(int fd, off_t offset, int whence)
William Juulc051bbe2007-11-15 11:13:05 +0100661{
662 yaffsfs_Handle *h = NULL;
663 yaffs_Object *obj = NULL;
664 int pos = -1;
665 int fSize = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200666
William Juulc051bbe2007-11-15 11:13:05 +0100667 yaffsfs_Lock();
668 h = yaffsfs_GetHandlePointer(fd);
669 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200670
William Juulc051bbe2007-11-15 11:13:05 +0100671 if(!h || !obj)
672 {
673 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200674 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100675 }
676 else if(whence == SEEK_SET)
677 {
678 if(offset >= 0)
679 {
680 pos = offset;
681 }
682 }
683 else if(whence == SEEK_CUR)
684 {
685 if( (h->position + offset) >= 0)
686 {
687 pos = (h->position + offset);
688 }
689 }
690 else if(whence == SEEK_END)
691 {
692 fSize = yaffs_GetObjectFileLength(obj);
693 if(fSize >= 0 && (fSize + offset) >= 0)
694 {
695 pos = fSize + offset;
696 }
697 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200698
William Juulc051bbe2007-11-15 11:13:05 +0100699 if(pos >= 0)
700 {
701 h->position = pos;
702 }
703 else
704 {
705 // todo error
706 }
707
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200708
William Juulc051bbe2007-11-15 11:13:05 +0100709 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200710
William Juulc051bbe2007-11-15 11:13:05 +0100711 return pos;
712}
713
714
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200715int yaffsfs_DoUnlink(const char *path,int isDirectory)
William Juulc051bbe2007-11-15 11:13:05 +0100716{
717 yaffs_Object *dir = NULL;
718 yaffs_Object *obj = NULL;
719 char *name;
720 int result = YAFFS_FAIL;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200721
William Juulc051bbe2007-11-15 11:13:05 +0100722 yaffsfs_Lock();
723
724 obj = yaffsfs_FindObject(NULL,path,0);
725 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
726 if(!dir)
727 {
728 yaffsfs_SetError(-ENOTDIR);
729 }
730 else if(!obj)
731 {
732 yaffsfs_SetError(-ENOENT);
733 }
734 else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
735 {
736 yaffsfs_SetError(-EISDIR);
737 }
738 else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
739 {
740 yaffsfs_SetError(-ENOTDIR);
741 }
742 else
743 {
744 result = yaffs_Unlink(dir,name);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200745
William Juulc051bbe2007-11-15 11:13:05 +0100746 if(result == YAFFS_FAIL && isDirectory)
747 {
748 yaffsfs_SetError(-ENOTEMPTY);
749 }
750 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200751
William Juulc051bbe2007-11-15 11:13:05 +0100752 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200753
William Juulc051bbe2007-11-15 11:13:05 +0100754 // todo error
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200755
William Juulc051bbe2007-11-15 11:13:05 +0100756 return (result == YAFFS_FAIL) ? -1 : 0;
757}
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200758int yaffs_rmdir(const char *path)
William Juulc051bbe2007-11-15 11:13:05 +0100759{
760 return yaffsfs_DoUnlink(path,1);
761}
762
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200763int yaffs_unlink(const char *path)
William Juulc051bbe2007-11-15 11:13:05 +0100764{
765 return yaffsfs_DoUnlink(path,0);
766}
767
768int yaffs_rename(const char *oldPath, const char *newPath)
769{
770 yaffs_Object *olddir = NULL;
771 yaffs_Object *newdir = NULL;
772 yaffs_Object *obj = NULL;
773 char *oldname;
774 char *newname;
775 int result= YAFFS_FAIL;
776 int renameAllowed = 1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200777
William Juulc051bbe2007-11-15 11:13:05 +0100778 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200779
William Juulc051bbe2007-11-15 11:13:05 +0100780 olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
781 newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
782 obj = yaffsfs_FindObject(NULL,oldPath,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200783
William Juulc051bbe2007-11-15 11:13:05 +0100784 if(!olddir || !newdir || !obj)
785 {
786 // bad file
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200787 yaffsfs_SetError(-EBADF);
788 renameAllowed = 0;
William Juulc051bbe2007-11-15 11:13:05 +0100789 }
790 else if(olddir->myDev != newdir->myDev)
791 {
792 // oops must be on same device
793 // todo error
794 yaffsfs_SetError(-EXDEV);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200795 renameAllowed = 0;
William Juulc051bbe2007-11-15 11:13:05 +0100796 }
797 else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
798 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200799 // It is a directory, check that it is not being renamed to
William Juulc051bbe2007-11-15 11:13:05 +0100800 // being its own decendent.
801 // Do this by tracing from the new directory back to the root, checking for obj
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200802
William Juulc051bbe2007-11-15 11:13:05 +0100803 yaffs_Object *xx = newdir;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200804
William Juulc051bbe2007-11-15 11:13:05 +0100805 while( renameAllowed && xx)
806 {
807 if(xx == obj)
808 {
809 renameAllowed = 0;
810 }
811 xx = xx->parent;
812 }
813 if(!renameAllowed) yaffsfs_SetError(-EACCESS);
814 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200815
William Juulc051bbe2007-11-15 11:13:05 +0100816 if(renameAllowed)
817 {
818 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
819 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200820
William Juulc051bbe2007-11-15 11:13:05 +0100821 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200822
823 return (result == YAFFS_FAIL) ? -1 : 0;
William Juulc051bbe2007-11-15 11:13:05 +0100824}
825
826
827static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
828{
829 int retVal = -1;
830
831 if(obj)
832 {
833 obj = yaffs_GetEquivalentObject(obj);
834 }
835
836 if(obj && buf)
837 {
838 buf->st_dev = (int)obj->myDev->genericDevice;
839 buf->st_ino = obj->objectId;
840 buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200841
842 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
William Juulc051bbe2007-11-15 11:13:05 +0100843 {
844 buf->st_mode |= S_IFDIR;
845 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200846 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
William Juulc051bbe2007-11-15 11:13:05 +0100847 {
848 buf->st_mode |= S_IFLNK;
849 }
850 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
851 {
852 buf->st_mode |= S_IFREG;
853 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200854
William Juulc051bbe2007-11-15 11:13:05 +0100855 buf->st_nlink = yaffs_GetObjectLinkCount(obj);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200856 buf->st_uid = 0;
857 buf->st_gid = 0;;
William Juulc051bbe2007-11-15 11:13:05 +0100858 buf->st_rdev = obj->yst_rdev;
859 buf->st_size = yaffs_GetObjectFileLength(obj);
860 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
861 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200862 buf->yst_atime = obj->yst_atime;
863 buf->yst_ctime = obj->yst_ctime;
864 buf->yst_mtime = obj->yst_mtime;
William Juulc051bbe2007-11-15 11:13:05 +0100865 retVal = 0;
866 }
867 return retVal;
868}
869
870static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat)
871{
872 yaffs_Object *obj;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200873
William Juulc051bbe2007-11-15 11:13:05 +0100874 int retVal = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200875
William Juulc051bbe2007-11-15 11:13:05 +0100876 yaffsfs_Lock();
877 obj = yaffsfs_FindObject(NULL,path,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200878
William Juulc051bbe2007-11-15 11:13:05 +0100879 if(!doLStat && obj)
880 {
881 obj = yaffsfs_FollowLink(obj,0);
882 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200883
William Juulc051bbe2007-11-15 11:13:05 +0100884 if(obj)
885 {
886 retVal = yaffsfs_DoStat(obj,buf);
887 }
888 else
889 {
890 // todo error not found
891 yaffsfs_SetError(-ENOENT);
892 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200893
William Juulc051bbe2007-11-15 11:13:05 +0100894 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200895
William Juulc051bbe2007-11-15 11:13:05 +0100896 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200897
William Juulc051bbe2007-11-15 11:13:05 +0100898}
899
900int yaffs_stat(const char *path, struct yaffs_stat *buf)
901{
902 return yaffsfs_DoStatOrLStat(path,buf,0);
903}
904
905int yaffs_lstat(const char *path, struct yaffs_stat *buf)
906{
907 return yaffsfs_DoStatOrLStat(path,buf,1);
908}
909
910int yaffs_fstat(int fd, struct yaffs_stat *buf)
911{
912 yaffs_Object *obj;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200913
William Juulc051bbe2007-11-15 11:13:05 +0100914 int retVal = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200915
William Juulc051bbe2007-11-15 11:13:05 +0100916 yaffsfs_Lock();
917 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200918
William Juulc051bbe2007-11-15 11:13:05 +0100919 if(obj)
920 {
921 retVal = yaffsfs_DoStat(obj,buf);
922 }
923 else
924 {
925 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200926 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100927 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200928
William Juulc051bbe2007-11-15 11:13:05 +0100929 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200930
William Juulc051bbe2007-11-15 11:13:05 +0100931 return retVal;
932}
933
934static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
935{
William Juule24ebad2007-11-15 12:23:57 +0100936 int result = YAFFS_FAIL;
William Juulc051bbe2007-11-15 11:13:05 +0100937
938 if(obj)
939 {
940 obj = yaffs_GetEquivalentObject(obj);
941 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200942
William Juulc051bbe2007-11-15 11:13:05 +0100943 if(obj)
944 {
945 obj->yst_mode = mode;
946 obj->dirty = 1;
947 result = yaffs_FlushFile(obj,0);
948 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200949
William Juulc051bbe2007-11-15 11:13:05 +0100950 return result == YAFFS_OK ? 0 : -1;
951}
952
953
954int yaffs_chmod(const char *path, mode_t mode)
955{
956 yaffs_Object *obj;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200957
William Juulc051bbe2007-11-15 11:13:05 +0100958 int retVal = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200959
William Juulc051bbe2007-11-15 11:13:05 +0100960 yaffsfs_Lock();
961 obj = yaffsfs_FindObject(NULL,path,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200962
William Juulc051bbe2007-11-15 11:13:05 +0100963 if(obj)
964 {
965 retVal = yaffsfs_DoChMod(obj,mode);
966 }
967 else
968 {
969 // todo error not found
970 yaffsfs_SetError(-ENOENT);
971 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200972
William Juulc051bbe2007-11-15 11:13:05 +0100973 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200974
William Juulc051bbe2007-11-15 11:13:05 +0100975 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200976
William Juulc051bbe2007-11-15 11:13:05 +0100977}
978
979
980int yaffs_fchmod(int fd, mode_t mode)
981{
982 yaffs_Object *obj;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200983
William Juulc051bbe2007-11-15 11:13:05 +0100984 int retVal = -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200985
William Juulc051bbe2007-11-15 11:13:05 +0100986 yaffsfs_Lock();
987 obj = yaffsfs_GetHandleObject(fd);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200988
William Juulc051bbe2007-11-15 11:13:05 +0100989 if(obj)
990 {
991 retVal = yaffsfs_DoChMod(obj,mode);
992 }
993 else
994 {
995 // bad handle
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200996 yaffsfs_SetError(-EBADF);
William Juulc051bbe2007-11-15 11:13:05 +0100997 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +0200998
William Juulc051bbe2007-11-15 11:13:05 +0100999 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001000
William Juulc051bbe2007-11-15 11:13:05 +01001001 return retVal;
1002}
1003
1004
1005int yaffs_mkdir(const char *path, mode_t mode)
1006{
1007 yaffs_Object *parent = NULL;
1008 yaffs_Object *dir = NULL;
1009 char *name;
1010 int retVal= -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001011
William Juulc051bbe2007-11-15 11:13:05 +01001012 yaffsfs_Lock();
1013 parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1014 if(parent)
1015 dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1016 if(dir)
1017 {
1018 retVal = 0;
1019 }
1020 else
1021 {
1022 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1023 retVal = -1;
1024 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001025
William Juulc051bbe2007-11-15 11:13:05 +01001026 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001027
William Juulc051bbe2007-11-15 11:13:05 +01001028 return retVal;
1029}
1030
1031int yaffs_mount(const char *path)
1032{
1033 int retVal=-1;
1034 int result=YAFFS_FAIL;
1035 yaffs_Device *dev=NULL;
1036 char *dummy;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001037
William Juulc051bbe2007-11-15 11:13:05 +01001038 T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path));
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001039
William Juulc051bbe2007-11-15 11:13:05 +01001040 yaffsfs_Lock();
1041 dev = yaffsfs_FindDevice(path,&dummy);
1042 if(dev)
1043 {
1044 if(!dev->isMounted)
1045 {
1046 result = yaffs_GutsInitialise(dev);
1047 if(result == YAFFS_FAIL)
1048 {
1049 // todo error - mount failed
1050 yaffsfs_SetError(-ENOMEM);
1051 }
1052 retVal = result ? 0 : -1;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001053
William Juulc051bbe2007-11-15 11:13:05 +01001054 }
1055 else
1056 {
1057 //todo error - already mounted.
1058 yaffsfs_SetError(-EBUSY);
1059 }
1060 }
1061 else
1062 {
1063 // todo error - no device
1064 yaffsfs_SetError(-ENODEV);
1065 }
1066 yaffsfs_Unlock();
1067 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001068
William Juulc051bbe2007-11-15 11:13:05 +01001069}
1070
1071int yaffs_unmount(const char *path)
1072{
1073 int retVal=-1;
1074 yaffs_Device *dev=NULL;
1075 char *dummy;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001076
William Juulc051bbe2007-11-15 11:13:05 +01001077 yaffsfs_Lock();
1078 dev = yaffsfs_FindDevice(path,&dummy);
1079 if(dev)
1080 {
1081 if(dev->isMounted)
1082 {
1083 int i;
1084 int inUse;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001085
William Juulc051bbe2007-11-15 11:13:05 +01001086 yaffs_FlushEntireDeviceCache(dev);
1087 yaffs_CheckpointSave(dev);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001088
William Juulc051bbe2007-11-15 11:13:05 +01001089 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
1090 {
1091 if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
1092 {
1093 inUse = 1; // the device is in use, can't unmount
1094 }
1095 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001096
William Juulc051bbe2007-11-15 11:13:05 +01001097 if(!inUse)
1098 {
1099 yaffs_Deinitialise(dev);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001100
William Juulc051bbe2007-11-15 11:13:05 +01001101 retVal = 0;
1102 }
1103 else
1104 {
1105 // todo error can't unmount as files are open
1106 yaffsfs_SetError(-EBUSY);
1107 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001108
William Juulc051bbe2007-11-15 11:13:05 +01001109 }
1110 else
1111 {
1112 //todo error - not mounted.
1113 yaffsfs_SetError(-EINVAL);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001114
William Juulc051bbe2007-11-15 11:13:05 +01001115 }
1116 }
1117 else
1118 {
1119 // todo error - no device
1120 yaffsfs_SetError(-ENODEV);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001121 }
William Juulc051bbe2007-11-15 11:13:05 +01001122 yaffsfs_Unlock();
1123 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001124
William Juulc051bbe2007-11-15 11:13:05 +01001125}
1126
1127loff_t yaffs_freespace(const char *path)
1128{
1129 loff_t retVal=-1;
1130 yaffs_Device *dev=NULL;
1131 char *dummy;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001132
William Juulc051bbe2007-11-15 11:13:05 +01001133 yaffsfs_Lock();
1134 dev = yaffsfs_FindDevice(path,&dummy);
1135 if(dev && dev->isMounted)
1136 {
1137 retVal = yaffs_GetNumberOfFreeChunks(dev);
1138 retVal *= dev->nDataBytesPerChunk;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001139
William Juulc051bbe2007-11-15 11:13:05 +01001140 }
1141 else
1142 {
1143 yaffsfs_SetError(-EINVAL);
1144 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001145
William Juulc051bbe2007-11-15 11:13:05 +01001146 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001147 return retVal;
William Juulc051bbe2007-11-15 11:13:05 +01001148}
1149
1150
1151
1152void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1153{
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001154
William Juulc051bbe2007-11-15 11:13:05 +01001155 yaffsfs_DeviceConfiguration *cfg;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001156
William Juulc051bbe2007-11-15 11:13:05 +01001157 yaffsfs_configurationList = cfgList;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001158
William Juulc051bbe2007-11-15 11:13:05 +01001159 yaffsfs_InitHandles();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001160
William Juulc051bbe2007-11-15 11:13:05 +01001161 cfg = yaffsfs_configurationList;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001162
William Juulc051bbe2007-11-15 11:13:05 +01001163 while(cfg && cfg->prefix && cfg->dev)
1164 {
1165 cfg->dev->isMounted = 0;
1166 cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
1167 cfg++;
1168 }
William Juulc051bbe2007-11-15 11:13:05 +01001169}
1170
1171
1172//
1173// Directory search stuff.
1174
1175//
1176// Directory search context
1177//
1178// NB this is an opaque structure.
1179
1180
1181typedef struct
1182{
1183 __u32 magic;
1184 yaffs_dirent de; /* directory entry being used by this dsc */
1185 char name[NAME_MAX+1]; /* name of directory being searched */
1186 yaffs_Object *dirObj; /* ptr to directory being searched */
1187 yaffs_Object *nextReturn; /* obj to be returned by next readddir */
1188 int offset;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001189 struct list_head others;
William Juulc051bbe2007-11-15 11:13:05 +01001190} yaffsfs_DirectorySearchContext;
1191
1192
1193
1194static struct list_head search_contexts;
1195
1196
1197static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1198{
1199 if(dsc &&
1200 dsc->dirObj &&
1201 dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001202
William Juulc051bbe2007-11-15 11:13:05 +01001203 dsc->offset = 0;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001204
William Juulc051bbe2007-11-15 11:13:05 +01001205 if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1206 dsc->nextReturn = NULL;
1207 } else {
1208 dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next,
1209 yaffs_Object,siblings);
1210 }
1211 } else {
1212 /* Hey someone isn't playing nice! */
1213 }
1214}
1215
1216static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1217{
1218 if(dsc &&
1219 dsc->dirObj &&
1220 dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001221
William Juulc051bbe2007-11-15 11:13:05 +01001222 if( dsc->nextReturn == NULL ||
1223 list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1224 dsc->nextReturn = NULL;
1225 } else {
1226 struct list_head *next = dsc->nextReturn->siblings.next;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001227
William Juulc051bbe2007-11-15 11:13:05 +01001228 if( next == &dsc->dirObj->variant.directoryVariant.children)
1229 dsc->nextReturn = NULL; /* end of list */
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001230 else
William Juulc051bbe2007-11-15 11:13:05 +01001231 dsc->nextReturn = list_entry(next,yaffs_Object,siblings);
1232 }
1233 } else {
1234 /* Hey someone isn't playing nice! */
1235 }
1236}
1237
1238static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1239{
1240
1241 struct list_head *i;
1242 yaffsfs_DirectorySearchContext *dsc;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001243
William Juulc051bbe2007-11-15 11:13:05 +01001244 /* if search contexts not initilised then skip */
1245 if(!search_contexts.next)
1246 return;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001247
William Juulc051bbe2007-11-15 11:13:05 +01001248 /* Iteratethrough the directory search contexts.
1249 * If any are the one being removed, then advance the dsc to
1250 * the next one to prevent a hanging ptr.
1251 */
1252 list_for_each(i, &search_contexts) {
1253 if (i) {
1254 dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
1255 if(dsc->nextReturn == obj)
1256 yaffsfs_DirAdvance(dsc);
1257 }
1258 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001259
William Juulc051bbe2007-11-15 11:13:05 +01001260}
1261
1262yaffs_DIR *yaffs_opendir(const char *dirname)
1263{
1264 yaffs_DIR *dir = NULL;
1265 yaffs_Object *obj = NULL;
1266 yaffsfs_DirectorySearchContext *dsc = NULL;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001267
William Juulc051bbe2007-11-15 11:13:05 +01001268 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001269
William Juulc051bbe2007-11-15 11:13:05 +01001270 obj = yaffsfs_FindObject(NULL,dirname,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001271
William Juulc051bbe2007-11-15 11:13:05 +01001272 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1273 {
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001274
William Juulc051bbe2007-11-15 11:13:05 +01001275 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1276 dir = (yaffs_DIR *)dsc;
1277 if(dsc)
1278 {
1279 memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1280 dsc->magic = YAFFS_MAGIC;
1281 dsc->dirObj = obj;
1282 strncpy(dsc->name,dirname,NAME_MAX);
1283 INIT_LIST_HEAD(&dsc->others);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001284
William Juulc051bbe2007-11-15 11:13:05 +01001285 if(!search_contexts.next)
1286 INIT_LIST_HEAD(&search_contexts);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001287
1288 list_add(&dsc->others,&search_contexts);
William Juulc051bbe2007-11-15 11:13:05 +01001289 yaffsfs_SetDirRewound(dsc); }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001290
William Juulc051bbe2007-11-15 11:13:05 +01001291 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001292
William Juulc051bbe2007-11-15 11:13:05 +01001293 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001294
William Juulc051bbe2007-11-15 11:13:05 +01001295 return dir;
1296}
1297
1298struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1299{
1300 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1301 struct yaffs_dirent *retVal = NULL;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001302
William Juulc051bbe2007-11-15 11:13:05 +01001303 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001304
William Juulc051bbe2007-11-15 11:13:05 +01001305 if(dsc && dsc->magic == YAFFS_MAGIC){
1306 yaffsfs_SetError(0);
1307 if(dsc->nextReturn){
1308 dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1309 dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1310 dsc->de.d_off = dsc->offset++;
1311 yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1312 if(strlen(dsc->de.d_name) == 0)
1313 {
1314 // this should not happen!
1315 strcpy(dsc->de.d_name,"zz");
1316 }
1317 dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1318 retVal = &dsc->de;
1319 yaffsfs_DirAdvance(dsc);
1320 } else
1321 retVal = NULL;
1322 }
1323 else
1324 {
1325 yaffsfs_SetError(-EBADF);
1326 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001327
William Juulc051bbe2007-11-15 11:13:05 +01001328 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001329
William Juulc051bbe2007-11-15 11:13:05 +01001330 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001331
William Juulc051bbe2007-11-15 11:13:05 +01001332}
1333
1334
1335void yaffs_rewinddir(yaffs_DIR *dirp)
1336{
1337 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001338
William Juulc051bbe2007-11-15 11:13:05 +01001339 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001340
William Juulc051bbe2007-11-15 11:13:05 +01001341 yaffsfs_SetDirRewound(dsc);
1342
1343 yaffsfs_Unlock();
1344}
1345
1346
1347int yaffs_closedir(yaffs_DIR *dirp)
1348{
1349 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001350
William Juulc051bbe2007-11-15 11:13:05 +01001351 yaffsfs_Lock();
1352 dsc->magic = 0;
1353 list_del(&dsc->others); /* unhook from list */
1354 YFREE(dsc);
1355 yaffsfs_Unlock();
1356 return 0;
1357}
1358
1359// end of directory stuff
1360
1361
1362int yaffs_symlink(const char *oldpath, const char *newpath)
1363{
1364 yaffs_Object *parent = NULL;
1365 yaffs_Object *obj;
1366 char *name;
1367 int retVal= -1;
1368 int mode = 0; // ignore for now
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001369
William Juulc051bbe2007-11-15 11:13:05 +01001370 yaffsfs_Lock();
1371 parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1372 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1373 if(obj)
1374 {
1375 retVal = 0;
1376 }
1377 else
1378 {
1379 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1380 retVal = -1;
1381 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001382
William Juulc051bbe2007-11-15 11:13:05 +01001383 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001384
William Juulc051bbe2007-11-15 11:13:05 +01001385 return retVal;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001386
William Juulc051bbe2007-11-15 11:13:05 +01001387}
1388
1389int yaffs_readlink(const char *path, char *buf, int bufsiz)
1390{
1391 yaffs_Object *obj = NULL;
1392 int retVal;
1393
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001394
William Juulc051bbe2007-11-15 11:13:05 +01001395 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001396
William Juulc051bbe2007-11-15 11:13:05 +01001397 obj = yaffsfs_FindObject(NULL,path,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001398
William Juulc051bbe2007-11-15 11:13:05 +01001399 if(!obj)
1400 {
1401 yaffsfs_SetError(-ENOENT);
1402 retVal = -1;
1403 }
1404 else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK)
1405 {
1406 yaffsfs_SetError(-EINVAL);
1407 retVal = -1;
1408 }
1409 else
1410 {
1411 char *alias = obj->variant.symLinkVariant.alias;
1412 memset(buf,0,bufsiz);
1413 strncpy(buf,alias,bufsiz - 1);
1414 retVal = 0;
1415 }
1416 yaffsfs_Unlock();
1417 return retVal;
1418}
1419
1420int yaffs_link(const char *oldpath, const char *newpath)
1421{
1422 // Creates a link called newpath to existing oldpath
1423 yaffs_Object *obj = NULL;
1424 yaffs_Object *target = NULL;
1425 int retVal = 0;
1426
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001427
William Juulc051bbe2007-11-15 11:13:05 +01001428 yaffsfs_Lock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001429
William Juulc051bbe2007-11-15 11:13:05 +01001430 obj = yaffsfs_FindObject(NULL,oldpath,0);
1431 target = yaffsfs_FindObject(NULL,newpath,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001432
William Juulc051bbe2007-11-15 11:13:05 +01001433 if(!obj)
1434 {
1435 yaffsfs_SetError(-ENOENT);
1436 retVal = -1;
1437 }
1438 else if(target)
1439 {
1440 yaffsfs_SetError(-EEXIST);
1441 retVal = -1;
1442 }
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001443 else
William Juulc051bbe2007-11-15 11:13:05 +01001444 {
1445 yaffs_Object *newdir = NULL;
1446 yaffs_Object *link = NULL;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001447
William Juulc051bbe2007-11-15 11:13:05 +01001448 char *newname;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001449
William Juulc051bbe2007-11-15 11:13:05 +01001450 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001451
William Juulc051bbe2007-11-15 11:13:05 +01001452 if(!newdir)
1453 {
1454 yaffsfs_SetError(-ENOTDIR);
1455 retVal = -1;
1456 }
1457 else if(newdir->myDev != obj->myDev)
1458 {
1459 yaffsfs_SetError(-EXDEV);
1460 retVal = -1;
1461 }
1462 if(newdir && strlen(newname) > 0)
1463 {
1464 link = yaffs_Link(newdir,newname,obj);
1465 if(link)
1466 retVal = 0;
1467 else
1468 {
1469 yaffsfs_SetError(-ENOSPC);
1470 retVal = -1;
1471 }
1472
1473 }
1474 }
1475 yaffsfs_Unlock();
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001476
William Juulc051bbe2007-11-15 11:13:05 +01001477 return retVal;
1478}
1479
1480int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
1481
1482int yaffs_DumpDevStruct(const char *path)
1483{
1484 char *rest;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001485
William Juulc051bbe2007-11-15 11:13:05 +01001486 yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001487
William Juulc051bbe2007-11-15 11:13:05 +01001488 if(obj)
1489 {
1490 yaffs_Device *dev = obj->myDev;
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001491
William Juulc051bbe2007-11-15 11:13:05 +01001492 printf("\n"
1493 "nPageWrites.......... %d\n"
1494 "nPageReads........... %d\n"
1495 "nBlockErasures....... %d\n"
1496 "nGCCopies............ %d\n"
1497 "garbageCollections... %d\n"
1498 "passiveGarbageColl'ns %d\n"
1499 "\n",
1500 dev->nPageWrites,
1501 dev->nPageReads,
1502 dev->nBlockErasures,
1503 dev->nGCCopies,
1504 dev->garbageCollections,
1505 dev->passiveGarbageCollections
1506 );
Wolfgang Denk74e0dde2008-08-14 14:41:06 +02001507
William Juulc051bbe2007-11-15 11:13:05 +01001508 }
1509 return 0;
1510}