Mercurial > ecos
annotate packages/fs/jffs2/current/src/fs-ecos.c @ 3292:7f8e529b4d82 default tip
Fix FREESCALE_EDMA_NBYTES_MLOFFYES_MLOFF() so it works with negative offsets.
| author | vae |
|---|---|
| date | Wed, 29 Apr 2015 23:31:48 +0000 |
| parents | 74dbf4c3f2e1 |
| children |
| rev | line source |
|---|---|
| 570 | 1 /* |
| 2 * JFFS2 -- Journalling Flash File System, Version 2. | |
| 3 * | |
|
2729
74dbf4c3f2e1
Update all copyright banners to reflect FSF ownership; fix and improve licence text.
jlarmour
parents:
2475
diff
changeset
|
4 * Copyright (C) 2001-2003 Free Software Foundation, Inc. |
| 570 | 5 * |
| 6 * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com> | |
| 7 * Contributors: David Woodhouse, Nick Garnett, Richard Panton. | |
| 8 * | |
| 9 * For licensing information, see the file 'LICENCE' in this directory. | |
| 10 * | |
| 2042 | 11 * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $ |
| 570 | 12 * |
| 13 */ | |
| 14 | |
| 15 #include <linux/kernel.h> | |
| 1871 | 16 #include "nodelist.h" |
| 570 | 17 #include <linux/pagemap.h> |
| 1443 | 18 #include <linux/crc32.h> |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
19 #include "compr.h" |
| 570 | 20 #include <errno.h> |
| 21 #include <string.h> | |
| 22 #include <cyg/io/config_keys.h> | |
| 23 | |
|
2199
9619b62d5be9
* src/fs-ecos.c: Generalise the check for broken ARM compilers
asl
parents:
2042
diff
changeset
|
24 #if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && \ |
|
9619b62d5be9
* src/fs-ecos.c: Generalise the check for broken ARM compilers
asl
parents:
2042
diff
changeset
|
25 (defined (__arm__) || defined (_mips)) |
|
1269
46534b4d0054
* src/fs-ecos.c: Added test to detect known broken ARM compiler
asl
parents:
1241
diff
changeset
|
26 #error This compiler is known to be broken. Please see: |
|
2199
9619b62d5be9
* src/fs-ecos.c: Generalise the check for broken ARM compilers
asl
parents:
2042
diff
changeset
|
27 #error "http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html" |
|
1269
46534b4d0054
* src/fs-ecos.c: Added test to detect known broken ARM compiler
asl
parents:
1241
diff
changeset
|
28 #endif |
|
46534b4d0054
* src/fs-ecos.c: Added test to detect known broken ARM compiler
asl
parents:
1241
diff
changeset
|
29 |
| 570 | 30 //========================================================================== |
| 31 // Forward definitions | |
| 32 | |
| 33 // Filesystem operations | |
| 34 static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte); | |
| 35 static int jffs2_umount(cyg_mtab_entry * mte); | |
| 36 static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 37 int mode, cyg_file * fte); |
| 38 #ifdef CYGOPT_FS_JFFS2_WRITE | |
| 570 | 39 static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, |
| 1443 | 40 const char *name); |
| 570 | 41 static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name); |
| 42 static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name); | |
| 43 static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, | |
| 1443 | 44 const char *name1, cyg_dir dir2, const char *name2); |
| 570 | 45 static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, |
| 1443 | 46 cyg_dir dir2, const char *name2, int type); |
| 47 #endif | |
| 570 | 48 static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, |
| 1443 | 49 cyg_file * fte); |
| 570 | 50 static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, |
| 1443 | 51 cyg_dir * dir_out); |
| 570 | 52 static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, |
| 1443 | 53 struct stat *buf); |
| 570 | 54 static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, |
| 1443 | 55 int key, void *buf, int len); |
| 570 | 56 static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, |
| 1443 | 57 int key, void *buf, int len); |
| 570 | 58 |
| 59 // File operations | |
| 60 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); | |
| 1443 | 61 #ifdef CYGOPT_FS_JFFS2_WRITE |
| 570 | 62 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); |
| 1443 | 63 #endif |
| 570 | 64 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence); |
| 65 static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, | |
| 1443 | 66 CYG_ADDRWORD data); |
| 570 | 67 static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode); |
| 68 static int jffs2_fo_close(struct CYG_FILE_TAG *fp); | |
| 69 static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf); | |
| 70 static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, | |
| 1443 | 71 int len); |
| 570 | 72 static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, |
| 1443 | 73 int len); |
| 570 | 74 |
| 75 // Directory operations | |
| 76 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); | |
| 77 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence); | |
| 78 | |
| 1443 | 79 |
| 80 static int jffs2_read_inode (struct _inode *inode); | |
| 81 static void jffs2_clear_inode (struct _inode *inode); | |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
82 static int jffs2_truncate_file (struct _inode *inode); |
| 1443 | 83 |
| 570 | 84 //========================================================================== |
| 85 // Filesystem table entries | |
| 86 | |
| 87 // ------------------------------------------------------------------------- | |
| 88 // Fstab entry. | |
| 89 // This defines the entry in the filesystem table. | |
| 90 // For simplicity we use _FILESYSTEM synchronization for all accesses since | |
| 91 // we should never block in any filesystem operations. | |
| 92 | |
| 1443 | 93 #ifdef CYGOPT_FS_JFFS2_WRITE |
| 570 | 94 FSTAB_ENTRY(jffs2_fste, "jffs2", 0, |
|
1856
15dd41bdd560
* src/fs-ecos.c: Use filesystem locking not file locking otherwise
asl
parents:
1834
diff
changeset
|
95 CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, |
| 1443 | 96 jffs2_mount, |
| 97 jffs2_umount, | |
| 98 jffs2_open, | |
| 99 jffs2_ops_unlink, | |
| 100 jffs2_ops_mkdir, | |
| 101 jffs2_ops_rmdir, | |
| 102 jffs2_ops_rename, | |
| 103 jffs2_ops_link, | |
| 104 jffs2_opendir, | |
| 105 jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); | |
| 106 #else | |
| 107 FSTAB_ENTRY(jffs2_fste, "jffs2", 0, | |
|
1856
15dd41bdd560
* src/fs-ecos.c: Use filesystem locking not file locking otherwise
asl
parents:
1834
diff
changeset
|
108 CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM, |
| 1443 | 109 jffs2_mount, |
| 110 jffs2_umount, | |
| 111 jffs2_open, | |
| 112 (cyg_fsop_unlink *)cyg_fileio_erofs, | |
| 113 (cyg_fsop_mkdir *)cyg_fileio_erofs, | |
| 114 (cyg_fsop_rmdir *)cyg_fileio_erofs, | |
| 115 (cyg_fsop_rename *)cyg_fileio_erofs, | |
| 116 (cyg_fsop_link *)cyg_fileio_erofs, | |
| 117 jffs2_opendir, | |
| 118 jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo); | |
| 119 #endif | |
| 570 | 120 |
| 121 // ------------------------------------------------------------------------- | |
| 122 // File operations. | |
| 123 // This set of file operations are used for normal open files. | |
| 124 | |
| 125 static cyg_fileops jffs2_fileops = { | |
| 1443 | 126 jffs2_fo_read, |
| 127 #ifdef CYGOPT_FS_JFFS2_WRITE | |
| 128 jffs2_fo_write, | |
| 129 #else | |
| 130 (cyg_fileop_write *) cyg_fileio_erofs, | |
| 131 #endif | |
| 132 jffs2_fo_lseek, | |
| 133 jffs2_fo_ioctl, | |
| 134 cyg_fileio_seltrue, | |
| 135 jffs2_fo_fsync, | |
| 136 jffs2_fo_close, | |
| 137 jffs2_fo_fstat, | |
| 138 jffs2_fo_getinfo, | |
| 139 jffs2_fo_setinfo | |
| 570 | 140 }; |
| 141 | |
| 142 // ------------------------------------------------------------------------- | |
| 143 // Directory file operations. | |
| 144 // This set of operations are used for open directories. Most entries | |
| 145 // point to error-returning stub functions. Only the read, lseek and | |
| 146 // close entries are functional. | |
| 147 | |
| 148 static cyg_fileops jffs2_dirops = { | |
| 1443 | 149 jffs2_fo_dirread, |
| 150 (cyg_fileop_write *) cyg_fileio_enosys, | |
| 151 jffs2_fo_dirlseek, | |
| 152 (cyg_fileop_ioctl *) cyg_fileio_enosys, | |
| 153 cyg_fileio_seltrue, | |
| 154 (cyg_fileop_fsync *) cyg_fileio_enosys, | |
| 155 jffs2_fo_close, | |
| 156 (cyg_fileop_fstat *) cyg_fileio_enosys, | |
| 157 (cyg_fileop_getinfo *) cyg_fileio_enosys, | |
| 158 (cyg_fileop_setinfo *) cyg_fileio_enosys | |
| 570 | 159 }; |
| 160 | |
| 161 //========================================================================== | |
| 162 // STATIC VARIABLES !!! | |
| 163 | |
| 1443 | 164 static unsigned char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure |
| 1373 | 165 static unsigned char n_fs_mounted = 0; // a counter to track the number of jffs2 instances mounted |
| 570 | 166 |
| 167 //========================================================================== | |
| 168 // Directory operations | |
| 169 | |
| 170 struct jffs2_dirsearch { | |
| 2042 | 171 struct _inode *dir; // directory to search |
| 172 const unsigned char *path; // path to follow | |
| 173 struct _inode *node; // Node found | |
| 174 const unsigned char *name; // last name fragment used | |
| 175 int namelen; // name fragment length | |
| 176 cyg_bool last; // last name in path? | |
| 570 | 177 }; |
| 178 | |
| 179 typedef struct jffs2_dirsearch jffs2_dirsearch; | |
| 180 | |
| 181 //========================================================================== | |
| 182 // Ref count and nlink management | |
| 183 | |
| 184 | |
| 185 // FIXME: This seems like real cruft. Wouldn't it be better just to do the | |
| 186 // right thing? | |
| 1443 | 187 static void icache_evict(struct _inode *root_i, struct _inode *i) |
| 570 | 188 { |
| 1443 | 189 struct _inode *this = root_i, *next; |
| 570 | 190 |
| 1443 | 191 restart: |
| 192 D2(printf("icache_evict\n")); | |
| 193 // If this is an absolute search path from the root, | |
| 194 // remove all cached inodes with i_count of zero (these are only | |
| 195 // held where needed for dotdot filepaths) | |
| 196 while (this) { | |
| 197 next = this->i_cache_next; | |
| 198 if (this != i && this->i_count == 0) { | |
| 199 struct _inode *parent = this->i_parent; | |
| 200 if (this->i_cache_next) | |
| 201 this->i_cache_next->i_cache_prev = this->i_cache_prev; | |
| 202 if (this->i_cache_prev) | |
| 203 this->i_cache_prev->i_cache_next = this->i_cache_next; | |
| 204 jffs2_clear_inode(this); | |
| 205 memset(this, 0x5a, sizeof(*this)); | |
| 206 free(this); | |
| 207 if (parent && parent != this) { | |
| 208 parent->i_count--; | |
| 209 this = root_i; | |
| 210 goto restart; | |
| 211 } | |
| 212 } | |
| 213 this = next; | |
| 214 } | |
| 570 | 215 } |
| 216 | |
| 217 //========================================================================== | |
| 218 // Directory search | |
| 219 | |
| 220 // ------------------------------------------------------------------------- | |
| 221 // init_dirsearch() | |
| 222 // Initialize a dirsearch object to start a search | |
| 223 | |
| 224 static void init_dirsearch(jffs2_dirsearch * ds, | |
| 2042 | 225 struct _inode *dir, const unsigned char *name) |
| 570 | 226 { |
| 1443 | 227 D2(printf("init_dirsearch name = %s\n", name)); |
| 228 D2(printf("init_dirsearch dir = %x\n", dir)); | |
| 229 | |
| 230 dir->i_count++; | |
| 231 ds->dir = dir; | |
| 232 ds->path = name; | |
| 233 ds->node = dir; | |
| 234 ds->name = name; | |
| 235 ds->namelen = 0; | |
| 236 ds->last = false; | |
| 570 | 237 } |
| 238 | |
| 239 // ------------------------------------------------------------------------- | |
| 240 // find_entry() | |
| 241 // Search a single directory for the next name in a path and update the | |
| 242 // dirsearch object appropriately. | |
| 243 | |
| 244 static int find_entry(jffs2_dirsearch * ds) | |
| 245 { | |
| 1443 | 246 struct _inode *dir = ds->dir; |
| 2042 | 247 const unsigned char *name = ds->path; |
| 248 const unsigned char *n = name; | |
| 1443 | 249 char namelen = 0; |
| 250 struct _inode *d; | |
| 570 | 251 |
| 1443 | 252 D2(printf("find_entry\n")); |
| 570 | 253 |
| 1443 | 254 // check that we really have a directory |
| 255 if (!S_ISDIR(dir->i_mode)) | |
| 256 return ENOTDIR; | |
| 570 | 257 |
| 1443 | 258 // Isolate the next element of the path name. |
| 259 while (*n != '\0' && *n != '/') | |
| 260 n++, namelen++; | |
| 570 | 261 |
| 1533 | 262 // Check if this is the last path element. |
| 263 while( *n == '/') n++; | |
| 1443 | 264 if (*n == '\0') |
| 265 ds->last = true; | |
| 570 | 266 |
| 1443 | 267 // update name in dirsearch object |
| 268 ds->name = name; | |
| 269 ds->namelen = namelen; | |
| 570 | 270 |
| 1443 | 271 if (name[0] == '.') |
| 272 switch (namelen) { | |
| 273 default: | |
| 274 break; | |
| 275 case 2: | |
| 276 // Dot followed by not Dot, treat as any other name | |
| 277 if (name[1] != '.') | |
| 278 break; | |
| 279 // Dot Dot | |
| 280 // Move back up the search path | |
| 281 D2(printf("find_entry found ..\n")); | |
| 282 ds->dir = ds->node; | |
| 283 ds->node = ds->dir->i_parent; | |
| 284 ds->node->i_count++; | |
| 285 return ENOERR; | |
| 286 case 1: | |
| 287 // Dot is consumed | |
| 288 D2(printf("find_entry found .\n")); | |
| 289 ds->node = ds->dir; | |
| 290 ds->dir->i_count++; | |
| 291 return ENOERR; | |
| 292 } | |
| 570 | 293 |
| 1443 | 294 // Here we have the name and its length set up. |
| 295 // Search the directory for a matching entry | |
| 570 | 296 |
| 1443 | 297 D2(printf("find_entry for name = %s\n", ds->path)); |
| 298 d = jffs2_lookup(dir, name, namelen); | |
| 299 D2(printf("find_entry got dir = %x\n", d)); | |
| 300 | |
| 301 if (d == NULL) | |
| 302 return ENOENT; | |
|
1812
119d236b530c
* src/fs-ecos.c (find_entry): jffs2_lookup may return error codes.
asl
parents:
1757
diff
changeset
|
303 if (IS_ERR(d)) |
|
119d236b530c
* src/fs-ecos.c (find_entry): jffs2_lookup may return error codes.
asl
parents:
1757
diff
changeset
|
304 return -PTR_ERR(d); |
| 570 | 305 |
| 1443 | 306 // If it's a new directory inode, increase refcount on its parent |
| 307 if (S_ISDIR(d->i_mode) && !d->i_parent) { | |
| 308 d->i_parent = dir; | |
| 309 dir->i_count++; | |
| 310 } | |
| 570 | 311 |
| 1443 | 312 // pass back the node we have found |
| 313 ds->node = d; | |
| 314 return ENOERR; | |
| 570 | 315 |
| 316 } | |
| 317 | |
| 318 // ------------------------------------------------------------------------- | |
| 319 // jffs2_find() | |
| 320 // Main interface to directory search code. This is used in all file | |
| 321 // level operations to locate the object named by the pathname. | |
| 322 | |
| 1443 | 323 // Returns with use count incremented on both the sought object and |
| 324 // the directory it was found in | |
| 570 | 325 static int jffs2_find(jffs2_dirsearch * d) |
| 326 { | |
| 1443 | 327 int err; |
| 328 | |
| 329 D2(printf("jffs2_find for path =%s\n", d->path)); | |
| 570 | 330 |
| 1443 | 331 // Short circuit empty paths |
| 332 if (*(d->path) == '\0') { | |
| 333 d->node->i_count++; | |
| 334 return ENOERR; | |
| 335 } | |
| 570 | 336 |
| 1443 | 337 // iterate down directory tree until we find the object |
| 338 // we want. | |
| 339 for (;;) { | |
| 340 err = find_entry(d); | |
| 570 | 341 |
| 1443 | 342 if (err != ENOERR) |
| 343 return err; | |
| 570 | 344 |
| 1443 | 345 if (d->last) |
| 346 return ENOERR; | |
| 570 | 347 |
| 1443 | 348 /* We're done with it, although it we found a subdir that |
| 349 will have caused the refcount to have been increased */ | |
| 350 jffs2_iput(d->dir); | |
| 570 | 351 |
| 1443 | 352 // Update dirsearch object to search next directory. |
| 353 d->dir = d->node; | |
| 354 d->path += d->namelen; | |
| 1533 | 355 while (*(d->path) == '/') |
| 1443 | 356 d->path++; // skip dirname separators |
| 357 } | |
| 570 | 358 } |
| 359 | |
| 360 //========================================================================== | |
| 361 // Pathconf support | |
| 362 // This function provides support for pathconf() and fpathconf(). | |
| 363 | |
| 1443 | 364 static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info) |
| 570 | 365 { |
| 1443 | 366 int err = ENOERR; |
| 367 D2(printf("jffs2_pathconf\n")); | |
| 570 | 368 |
| 1443 | 369 switch (info->name) { |
| 370 case _PC_LINK_MAX: | |
| 371 info->value = LINK_MAX; | |
| 372 break; | |
| 570 | 373 |
| 1443 | 374 case _PC_MAX_CANON: |
| 375 info->value = -1; // not supported | |
| 376 err = EINVAL; | |
| 377 break; | |
| 570 | 378 |
| 1443 | 379 case _PC_MAX_INPUT: |
| 380 info->value = -1; // not supported | |
| 381 err = EINVAL; | |
| 382 break; | |
| 570 | 383 |
| 1443 | 384 case _PC_NAME_MAX: |
| 385 info->value = NAME_MAX; | |
| 386 break; | |
| 570 | 387 |
| 1443 | 388 case _PC_PATH_MAX: |
| 389 info->value = PATH_MAX; | |
| 390 break; | |
| 570 | 391 |
| 1443 | 392 case _PC_PIPE_BUF: |
| 393 info->value = -1; // not supported | |
| 394 err = EINVAL; | |
| 395 break; | |
| 570 | 396 |
| 1443 | 397 case _PC_ASYNC_IO: |
| 398 info->value = -1; // not supported | |
| 399 err = EINVAL; | |
| 400 break; | |
| 570 | 401 |
| 1443 | 402 case _PC_CHOWN_RESTRICTED: |
| 403 info->value = -1; // not supported | |
| 404 err = EINVAL; | |
| 405 break; | |
| 570 | 406 |
| 1443 | 407 case _PC_NO_TRUNC: |
| 408 info->value = 0; | |
| 409 break; | |
| 570 | 410 |
| 1443 | 411 case _PC_PRIO_IO: |
| 412 info->value = 0; | |
| 413 break; | |
| 570 | 414 |
| 1443 | 415 case _PC_SYNC_IO: |
| 416 info->value = 0; | |
| 417 break; | |
| 570 | 418 |
| 1443 | 419 case _PC_VDISABLE: |
| 420 info->value = -1; // not supported | |
| 421 err = EINVAL; | |
| 422 break; | |
| 570 | 423 |
| 1443 | 424 default: |
| 425 err = EINVAL; | |
| 426 break; | |
| 427 } | |
| 570 | 428 |
| 1443 | 429 return err; |
| 570 | 430 } |
| 431 | |
| 432 //========================================================================== | |
| 433 // Filesystem operations | |
| 434 | |
| 435 // ------------------------------------------------------------------------- | |
| 436 // jffs2_mount() | |
| 437 // Process a mount request. This mainly creates a root for the | |
| 438 // filesystem. | |
| 439 static int jffs2_read_super(struct super_block *sb) | |
| 440 { | |
| 1443 | 441 struct jffs2_sb_info *c; |
| 442 Cyg_ErrNo err; | |
| 443 cyg_uint32 len; | |
| 444 cyg_io_flash_getconfig_devsize_t ds; | |
| 445 cyg_io_flash_getconfig_blocksize_t bs; | |
| 570 | 446 |
| 1443 | 447 D1(printk(KERN_DEBUG "jffs2: read_super\n")); |
| 448 | |
| 449 c = JFFS2_SB_INFO(sb); | |
| 570 | 450 |
| 1443 | 451 len = sizeof (ds); |
| 452 err = cyg_io_get_config(sb->s_dev, | |
| 453 CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len); | |
| 454 if (err != ENOERR) { | |
| 455 D1(printf | |
| 456 ("jffs2: cyg_io_get_config failed to get dev size: %d\n", | |
| 457 err)); | |
| 458 return err; | |
| 459 } | |
| 460 len = sizeof (bs); | |
| 461 bs.offset = 0; | |
| 462 err = cyg_io_get_config(sb->s_dev, | |
| 463 CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len); | |
| 464 if (err != ENOERR) { | |
| 465 D1(printf | |
| 466 ("jffs2: cyg_io_get_config failed to get block size: %d\n", | |
| 467 err)); | |
| 468 return err; | |
| 469 } | |
| 570 | 470 |
| 1443 | 471 c->sector_size = bs.block_size; |
| 472 c->flash_size = ds.dev_size; | |
| 473 c->cleanmarker_size = sizeof(struct jffs2_unknown_node); | |
| 474 | |
| 475 err = jffs2_do_mount_fs(c); | |
| 476 if (err) | |
| 477 return -err; | |
| 570 | 478 |
| 1443 | 479 D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); |
| 480 sb->s_root = jffs2_iget(sb, 1); | |
| 481 if (IS_ERR(sb->s_root)) { | |
| 482 D1(printk(KERN_WARNING "get root inode failed\n")); | |
| 483 err = PTR_ERR(sb->s_root); | |
| 484 sb->s_root = NULL; | |
| 485 goto out_nodes; | |
| 486 } | |
| 570 | 487 |
| 1443 | 488 return 0; |
| 489 | |
| 570 | 490 out_nodes: |
| 1443 | 491 jffs2_free_ino_caches(c); |
| 492 jffs2_free_raw_node_refs(c); | |
| 493 free(c->blocks); | |
| 570 | 494 |
| 1443 | 495 return err; |
| 570 | 496 } |
| 497 | |
| 498 static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte) | |
| 499 { | |
| 1443 | 500 extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end; |
| 501 struct super_block *jffs2_sb = NULL; | |
| 502 struct jffs2_sb_info *c; | |
| 503 cyg_mtab_entry *m; | |
| 504 cyg_io_handle_t t; | |
| 505 Cyg_ErrNo err; | |
| 570 | 506 |
| 1443 | 507 D2(printf("jffs2_mount\n")); |
| 570 | 508 |
| 1443 | 509 err = cyg_io_lookup(mte->devname, &t); |
| 510 if (err != ENOERR) | |
| 511 return -err; | |
| 570 | 512 |
| 1443 | 513 // Iterate through the mount table to see if we're mounted |
| 514 // FIXME: this should be done better - perhaps if the superblock | |
| 515 // can be stored as an inode in the icache. | |
| 516 for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) { | |
| 517 // stop if there are more than the configured maximum | |
| 518 if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) { | |
| 519 m = &cyg_mtab_end; | |
| 520 break; | |
| 521 } | |
| 522 if (m->valid && strcmp(m->fsname, "jffs2") == 0 && | |
| 523 strcmp(m->devname, mte->devname) == 0) { | |
| 524 jffs2_sb = (struct super_block *) m->data; | |
| 525 } | |
| 526 } | |
| 570 | 527 |
| 1443 | 528 if (jffs2_sb == NULL) { |
| 529 jffs2_sb = malloc(sizeof (struct super_block)); | |
| 570 | 530 |
| 1443 | 531 if (jffs2_sb == NULL) |
| 532 return ENOMEM; | |
| 570 | 533 |
| 1443 | 534 c = JFFS2_SB_INFO(jffs2_sb); |
| 535 memset(jffs2_sb, 0, sizeof (struct super_block)); | |
| 536 jffs2_sb->s_dev = t; | |
| 570 | 537 |
| 1443 | 538 c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); |
| 539 if (!c->inocache_list) { | |
| 540 free(jffs2_sb); | |
| 541 return ENOMEM; | |
| 542 } | |
| 543 memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE); | |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
544 if (n_fs_mounted++ == 0) { |
| 1373 | 545 jffs2_create_slab_caches(); // No error check, cannot fail |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
546 jffs2_compressors_init(); |
|
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
547 } |
| 570 | 548 |
| 1443 | 549 err = jffs2_read_super(jffs2_sb); |
| 570 | 550 |
| 1443 | 551 if (err) { |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
552 if (--n_fs_mounted == 0) { |
| 1373 | 553 jffs2_destroy_slab_caches(); |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
554 jffs2_compressors_exit(); |
|
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
555 } |
| 1373 | 556 |
| 1443 | 557 free(jffs2_sb); |
| 558 free(c->inocache_list); | |
| 559 return err; | |
| 560 } | |
| 570 | 561 |
| 1443 | 562 jffs2_sb->s_root->i_parent = jffs2_sb->s_root; // points to itself, no dotdot paths above mountpoint |
| 563 jffs2_sb->s_root->i_cache_prev = NULL; // root inode, so always null | |
| 564 jffs2_sb->s_root->i_cache_next = NULL; | |
| 565 jffs2_sb->s_root->i_count = 1; // Ensures the root inode is always in ram until umount | |
| 570 | 566 |
| 1443 | 567 D2(printf("jffs2_mount erasing pending blocks\n")); |
| 568 #ifdef CYGOPT_FS_JFFS2_WRITE | |
| 569 if (!jffs2_is_readonly(c)) | |
| 570 jffs2_erase_pending_blocks(c,0); | |
| 571 #endif | |
| 572 #ifdef CYGOPT_FS_JFFS2_GCTHREAD | |
| 573 jffs2_start_garbage_collect_thread(c); | |
| 574 #endif | |
| 575 } | |
| 576 mte->data = (CYG_ADDRWORD) jffs2_sb; | |
| 570 | 577 |
| 1443 | 578 jffs2_sb->s_mount_count++; |
| 579 mte->root = (cyg_dir) jffs2_sb->s_root; | |
| 580 D2(printf("jffs2_mounted superblock at %x\n", mte->root)); | |
| 1373 | 581 |
| 1443 | 582 return ENOERR; |
| 570 | 583 } |
| 584 | |
| 1443 | 585 extern cyg_dir cyg_cdir_dir; |
| 586 extern cyg_mtab_entry *cyg_cdir_mtab_entry; | |
| 587 | |
| 570 | 588 // ------------------------------------------------------------------------- |
| 589 // jffs2_umount() | |
| 590 // Unmount the filesystem. | |
| 591 | |
| 592 static int jffs2_umount(cyg_mtab_entry * mte) | |
| 593 { | |
| 1443 | 594 struct _inode *root = (struct _inode *) mte->root; |
| 595 struct super_block *jffs2_sb = root->i_sb; | |
| 596 struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb); | |
| 1547 | 597 struct jffs2_full_dirent *fd, *next; |
| 570 | 598 |
| 1443 | 599 D2(printf("jffs2_umount\n")); |
| 570 | 600 |
| 1443 | 601 // Only really umount if this is the only mount |
| 602 if (jffs2_sb->s_mount_count == 1) { | |
| 603 icache_evict(root, NULL); | |
| 604 if (root->i_cache_next != NULL) { | |
| 605 struct _inode *inode = root; | |
| 606 printf("Refuse to unmount.\n"); | |
| 607 while (inode) { | |
| 608 printf("Ino #%u has use count %d\n", | |
| 609 inode->i_ino, inode->i_count); | |
| 610 inode = inode->i_cache_next; | |
| 611 } | |
| 612 // root icount was set to 1 on mount | |
| 613 return EBUSY; | |
| 614 } | |
| 615 if (root->i_count == 2 && | |
| 616 cyg_cdir_mtab_entry == mte && | |
| 617 cyg_cdir_dir == (cyg_dir)root && | |
| 618 !strcmp(mte->name, "/")) { | |
| 619 /* If we were mounted on root, there's no | |
| 620 way for the cwd to change out and free | |
| 621 the file system for unmounting. So we hack | |
| 622 it -- if cwd is '/' we unset it. Perhaps | |
| 623 we should allow chdir(NULL) to unset | |
| 624 cyg_cdir_dir? */ | |
| 625 cyg_cdir_dir = CYG_DIR_NULL; | |
| 626 jffs2_iput(root); | |
| 627 } | |
| 628 /* Argh. The fileio code sets this; never clears it */ | |
| 629 if (cyg_cdir_mtab_entry == mte) | |
| 630 cyg_cdir_mtab_entry = NULL; | |
| 570 | 631 |
| 1443 | 632 if (root->i_count != 1) { |
| 633 printf("Ino #1 has use count %d\n", | |
| 634 root->i_count); | |
| 635 return EBUSY; | |
| 636 } | |
| 637 #ifdef CYGOPT_FS_JFFS2_GCTHREAD | |
| 638 jffs2_stop_garbage_collect_thread(c); | |
| 639 #endif | |
| 640 jffs2_iput(root); // Time to free the root inode | |
| 1547 | 641 |
| 642 // free directory entries | |
| 643 for (fd = root->jffs2_i.dents; fd; fd = next) { | |
| 644 next=fd->next; | |
|
1816
658319b65ae3
* src/fs-ecos.c (jffs2_open): Call iput on dir node if
asl
parents:
1812
diff
changeset
|
645 jffs2_free_full_dirent(fd); |
| 1547 | 646 } |
| 647 | |
| 1443 | 648 free(root); |
| 649 //Clear root inode | |
| 650 //root_i = NULL; | |
| 651 | |
| 652 // Clean up the super block and root inode | |
| 653 jffs2_free_ino_caches(c); | |
| 654 jffs2_free_raw_node_refs(c); | |
| 655 free(c->blocks); | |
| 656 free(c->inocache_list); | |
| 657 free(jffs2_sb); | |
| 658 // Clear superblock & root pointer | |
| 659 mte->root = CYG_DIR_NULL; | |
| 1271 | 660 mte->data = 0; |
| 1443 | 661 mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount |
| 662 // That's all folks. | |
| 663 D2(printf("jffs2_umount No current mounts\n")); | |
| 664 } else { | |
| 665 jffs2_sb->s_mount_count--; | |
| 1271 | 666 } |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
667 if (--n_fs_mounted == 0) { |
| 1373 | 668 jffs2_destroy_slab_caches(); |
|
1757
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
669 jffs2_compressors_exit(); |
|
c4a8f3019f9c
* cdl/jffs2.cdl: Fixed outdated definitions for compression options.
asl
parents:
1713
diff
changeset
|
670 } |
| 1443 | 671 return ENOERR; |
| 570 | 672 } |
| 673 | |
| 674 // ------------------------------------------------------------------------- | |
| 675 // jffs2_open() | |
| 676 // Open a file for reading or writing. | |
| 677 | |
| 678 static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 679 int mode, cyg_file * file) |
| 570 | 680 { |
| 681 | |
| 1443 | 682 jffs2_dirsearch ds; |
| 683 struct _inode *node = NULL; | |
| 684 int err; | |
| 570 | 685 |
| 1443 | 686 D2(printf("jffs2_open\n")); |
| 570 | 687 |
| 1443 | 688 /* If no chdir has been called and we were the first file system |
| 689 mounted, we get called with dir == NULL. Deal with it */ | |
| 690 if (!dir) | |
| 691 dir = mte->root; | |
| 570 | 692 |
| 1549 | 693 #ifndef CYGOPT_FS_JFFS2_WRITE |
| 1443 | 694 if (mode & (O_CREAT|O_TRUNC|O_WRONLY)) |
| 695 return EROFS; | |
| 696 #endif | |
| 2042 | 697 init_dirsearch(&ds, (struct _inode *) dir, |
| 698 (const unsigned char *) name); | |
| 1443 | 699 |
| 700 err = jffs2_find(&ds); | |
| 570 | 701 |
| 1443 | 702 if (err == ENOENT) { |
| 703 #ifdef CYGOPT_FS_JFFS2_WRITE | |
| 704 if (ds.last && (mode & O_CREAT)) { | |
| 570 | 705 |
| 1443 | 706 // No node there, if the O_CREAT bit is set then we must |
| 707 // create a new one. The dir and name fields of the dirsearch | |
| 708 // object will have been updated so we know where to put it. | |
| 709 | |
| 710 err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node); | |
| 570 | 711 |
| 1443 | 712 if (err != 0) { |
|
1816
658319b65ae3
* src/fs-ecos.c (jffs2_open): Call iput on dir node if
asl
parents:
1812
diff
changeset
|
713 //Possible orphaned inode on the flash - but will be gc'd |
|
658319b65ae3
* src/fs-ecos.c (jffs2_open): Call iput on dir node if
asl
parents:
1812
diff
changeset
|
714 jffs2_iput(ds.dir); |
| 1890 | 715 return -err; |
| 1443 | 716 } |
| 570 | 717 |
| 1443 | 718 err = ENOERR; |
| 719 } | |
| 720 #endif | |
| 721 } else if (err == ENOERR) { | |
| 722 // The node exists. If the O_CREAT and O_EXCL bits are set, we | |
| 723 // must fail the open. | |
| 570 | 724 |
| 1443 | 725 if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { |
| 726 jffs2_iput(ds.node); | |
| 727 err = EEXIST; | |
| 728 } else | |
| 729 node = ds.node; | |
| 730 } | |
| 570 | 731 |
| 1443 | 732 // Finished with the directory now |
| 733 jffs2_iput(ds.dir); | |
| 734 | |
| 735 if (err != ENOERR) | |
| 736 return err; | |
| 570 | 737 |
| 1443 | 738 // Check that we actually have a file here |
| 739 if (S_ISDIR(node->i_mode)) { | |
| 740 jffs2_iput(node); | |
| 741 return EISDIR; | |
| 742 } | |
| 570 | 743 |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
744 // If the O_TRUNC bit is set we must clean out the file data. |
| 1443 | 745 if (mode & O_TRUNC) { |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
746 #ifdef CYGOPT_FS_JFFS2_WRITE |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
747 err = jffs2_truncate_file(node); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
748 if (err) { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
749 jffs2_iput(node); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
750 return err; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
751 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
752 #else |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
753 jffs2_iput(node); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
754 return EROFS; |
| 1443 | 755 #endif |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
756 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
757 |
| 1443 | 758 // Initialise the file object |
| 759 file->f_flag |= mode & CYG_FILE_MODE_MASK; | |
| 760 file->f_type = CYG_FILE_TYPE_FILE; | |
| 761 file->f_ops = &jffs2_fileops; | |
| 762 file->f_offset = (mode & O_APPEND) ? node->i_size : 0; | |
| 763 file->f_data = (CYG_ADDRWORD) node; | |
| 764 file->f_xops = 0; | |
| 570 | 765 |
| 1443 | 766 return ENOERR; |
| 570 | 767 } |
| 768 | |
| 1443 | 769 #ifdef CYGOPT_FS_JFFS2_WRITE |
| 570 | 770 // ------------------------------------------------------------------------- |
| 771 // jffs2_ops_unlink() | |
| 772 // Remove a file link from its directory. | |
| 773 | |
| 774 static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name) | |
| 775 { | |
| 1443 | 776 jffs2_dirsearch ds; |
| 777 int err; | |
| 570 | 778 |
| 1443 | 779 D2(printf("jffs2_ops_unlink\n")); |
| 780 | |
| 2042 | 781 init_dirsearch(&ds, (struct _inode *) dir, |
| 782 (const unsigned char *)name); | |
| 570 | 783 |
| 1443 | 784 err = jffs2_find(&ds); |
| 570 | 785 |
| 1443 | 786 if (err != ENOERR) { |
| 787 jffs2_iput(ds.dir); | |
| 788 return err; | |
| 789 } | |
| 570 | 790 |
| 1443 | 791 // Cannot unlink directories, use rmdir() instead |
| 792 if (S_ISDIR(ds.node->i_mode)) { | |
| 793 jffs2_iput(ds.dir); | |
| 794 jffs2_iput(ds.node); | |
| 795 return EPERM; | |
| 796 } | |
| 570 | 797 |
| 1443 | 798 // Delete it from its directory |
| 570 | 799 |
| 1443 | 800 err = jffs2_unlink(ds.dir, ds.node, ds.name); |
| 801 jffs2_iput(ds.dir); | |
| 802 jffs2_iput(ds.node); | |
| 570 | 803 |
| 1443 | 804 return -err; |
| 570 | 805 } |
| 806 | |
| 807 // ------------------------------------------------------------------------- | |
| 808 // jffs2_ops_mkdir() | |
| 809 // Create a new directory. | |
| 810 | |
| 811 static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) | |
| 812 { | |
| 1443 | 813 jffs2_dirsearch ds; |
| 814 int err; | |
| 570 | 815 |
| 1443 | 816 D2(printf("jffs2_ops_mkdir\n")); |
| 570 | 817 |
| 2042 | 818 init_dirsearch(&ds, (struct _inode *) dir, |
| 819 (const unsigned char *)name); | |
| 570 | 820 |
| 1443 | 821 err = jffs2_find(&ds); |
| 570 | 822 |
| 1443 | 823 if (err == ENOENT) { |
| 824 if (ds.last) { | |
| 825 // The entry does not exist, and it is the last element in | |
| 826 // the pathname, so we can create it here. | |
| 570 | 827 |
| 1443 | 828 err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR); |
| 829 } | |
| 830 // If this was not the last element, then an intermediate | |
| 831 // directory does not exist. | |
| 832 } else { | |
| 833 // If there we no error, something already exists with that | |
| 834 // name, so we cannot create another one. | |
| 1890 | 835 if (err == ENOERR) { |
| 836 jffs2_iput(ds.node); | |
| 837 err = EEXIST; | |
| 838 } | |
| 1443 | 839 } |
| 840 jffs2_iput(ds.dir); | |
| 841 return err; | |
| 570 | 842 } |
| 843 | |
| 844 // ------------------------------------------------------------------------- | |
| 845 // jffs2_ops_rmdir() | |
| 846 // Remove a directory. | |
| 847 | |
| 848 static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name) | |
| 849 { | |
| 1443 | 850 jffs2_dirsearch ds; |
| 851 int err; | |
| 570 | 852 |
| 1443 | 853 D2(printf("jffs2_ops_rmdir\n")); |
| 570 | 854 |
| 2042 | 855 init_dirsearch(&ds, (struct _inode *) dir, |
| 856 (const unsigned char *)name); | |
| 570 | 857 |
| 1443 | 858 err = jffs2_find(&ds); |
| 570 | 859 |
| 1443 | 860 if (err != ENOERR) { |
| 861 jffs2_iput(ds.dir); | |
| 862 return err; | |
| 863 } | |
| 570 | 864 |
| 1443 | 865 // Check that this is actually a directory. |
| 866 if (!S_ISDIR(ds.node->i_mode)) { | |
| 867 jffs2_iput(ds.dir); | |
| 868 jffs2_iput(ds.node); | |
| 869 return EPERM; | |
| 870 } | |
| 570 | 871 |
| 1443 | 872 err = jffs2_rmdir(ds.dir, ds.node, ds.name); |
| 570 | 873 |
| 1443 | 874 jffs2_iput(ds.dir); |
| 875 jffs2_iput(ds.node); | |
| 876 return -err; | |
| 570 | 877 } |
| 878 | |
| 879 // ------------------------------------------------------------------------- | |
| 880 // jffs2_ops_rename() | |
| 881 // Rename a file/dir. | |
| 882 | |
| 883 static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1, | |
| 1443 | 884 const char *name1, cyg_dir dir2, const char *name2) |
| 570 | 885 { |
| 1443 | 886 jffs2_dirsearch ds1, ds2; |
| 887 int err; | |
| 888 | |
| 889 D2(printf("jffs2_ops_rename\n")); | |
| 890 | |
| 2042 | 891 init_dirsearch(&ds1, (struct _inode *) dir1, |
| 892 (const unsigned char *)name1); | |
| 570 | 893 |
| 1443 | 894 err = jffs2_find(&ds1); |
| 570 | 895 |
| 1443 | 896 if (err != ENOERR) { |
| 897 jffs2_iput(ds1.dir); | |
| 898 return err; | |
| 899 } | |
| 570 | 900 |
| 2042 | 901 init_dirsearch(&ds2, (struct _inode *) dir2, |
| 902 (const unsigned char *)name2); | |
| 1443 | 903 |
| 904 err = jffs2_find(&ds2); | |
| 570 | 905 |
| 1443 | 906 // Allow through renames to non-existent objects. |
| 907 if (ds2.last && err == ENOENT) { | |
| 908 ds2.node = NULL; | |
| 909 err = ENOERR; | |
| 910 } | |
| 570 | 911 |
| 1443 | 912 if (err != ENOERR) { |
| 913 jffs2_iput(ds1.dir); | |
| 914 jffs2_iput(ds1.node); | |
| 915 jffs2_iput(ds2.dir); | |
| 916 return err; | |
| 917 } | |
| 570 | 918 |
| 1443 | 919 // Null rename, just return |
| 920 if (ds1.node == ds2.node) { | |
| 921 err = ENOERR; | |
| 922 goto out; | |
| 923 } | |
| 570 | 924 |
| 1443 | 925 // First deal with any entry that is at the destination |
| 926 if (ds2.node) { | |
| 927 // Check that we are renaming like-for-like | |
| 570 | 928 |
| 1443 | 929 if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) { |
| 930 err = EISDIR; | |
| 931 goto out; | |
| 932 } | |
| 570 | 933 |
| 1443 | 934 if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) { |
| 935 err = ENOTDIR; | |
| 936 goto out; | |
| 937 } | |
| 570 | 938 |
| 1443 | 939 // Now delete the destination directory entry |
| 940 /* Er, what happened to atomicity of rename()? */ | |
| 941 err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name); | |
| 570 | 942 |
| 1443 | 943 if (err != 0) |
| 944 goto out; | |
| 945 | |
| 946 } | |
| 947 // Now we know that there is no clashing node at the destination, | |
| 948 // make a new direntry at the destination and delete the old entry | |
| 949 // at the source. | |
| 570 | 950 |
| 1443 | 951 err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name); |
| 570 | 952 |
| 1443 | 953 // Update directory times |
| 954 if (!err) | |
| 955 ds1.dir->i_ctime = | |
| 956 ds1.dir->i_mtime = | |
| 957 ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); | |
| 958 out: | |
| 959 jffs2_iput(ds1.dir); | |
| 960 if (S_ISDIR(ds1.node->i_mode)) { | |
| 961 /* Renamed a directory to elsewhere... so fix up its | |
| 962 i_parent pointer and the i_counts of its old and | |
| 963 new parents. */ | |
| 964 jffs2_iput(ds1.node->i_parent); | |
| 965 ds1.node->i_parent = ds2.dir; | |
| 966 /* We effectively increase its use count by not... */ | |
| 967 } else { | |
| 968 jffs2_iput(ds2.dir); /* ... doing this */ | |
| 969 } | |
| 1890 | 970 jffs2_iput(ds1.node); |
| 1443 | 971 if (ds2.node) |
| 972 jffs2_iput(ds2.node); | |
| 973 | |
| 1890 | 974 return err; |
| 570 | 975 } |
| 976 | |
| 977 // ------------------------------------------------------------------------- | |
| 978 // jffs2_ops_link() | |
| 979 // Make a new directory entry for a file. | |
| 980 | |
| 981 static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1, | |
| 1443 | 982 cyg_dir dir2, const char *name2, int type) |
| 570 | 983 { |
| 1443 | 984 jffs2_dirsearch ds1, ds2; |
| 985 int err; | |
| 570 | 986 |
| 1443 | 987 D2(printf("jffs2_ops_link\n")); |
| 570 | 988 |
| 1443 | 989 // Only do hard links for now in this filesystem |
| 990 if (type != CYG_FSLINK_HARD) | |
| 991 return EINVAL; | |
| 570 | 992 |
| 2042 | 993 init_dirsearch(&ds1, (struct _inode *) dir1, |
| 994 (const unsigned char *) name1); | |
| 570 | 995 |
| 1443 | 996 err = jffs2_find(&ds1); |
| 570 | 997 |
| 1443 | 998 if (err != ENOERR) { |
| 999 jffs2_iput(ds1.dir); | |
| 1000 return err; | |
| 1001 } | |
| 570 | 1002 |
| 2042 | 1003 init_dirsearch(&ds2, (struct _inode *) dir2, |
| 1004 (const unsigned char *) name2); | |
| 1443 | 1005 |
| 1006 err = jffs2_find(&ds2); | |
| 570 | 1007 |
| 1443 | 1008 // Don't allow links to existing objects |
| 1009 if (err == ENOERR) { | |
| 1010 jffs2_iput(ds1.dir); | |
| 1011 jffs2_iput(ds1.node); | |
| 1012 jffs2_iput(ds2.dir); | |
| 1013 jffs2_iput(ds2.node); | |
| 1014 return EEXIST; | |
| 1015 } | |
| 570 | 1016 |
| 1443 | 1017 // Allow through links to non-existing terminal objects |
| 1018 if (ds2.last && err == ENOENT) { | |
| 1019 ds2.node = NULL; | |
| 1020 err = ENOERR; | |
| 1021 } | |
| 570 | 1022 |
| 1443 | 1023 if (err != ENOERR) { |
| 1024 jffs2_iput(ds1.dir); | |
| 1025 jffs2_iput(ds1.node); | |
| 1026 jffs2_iput(ds2.dir); | |
| 1027 return err; | |
| 1028 } | |
| 1029 | |
| 1030 // Now we know that there is no existing node at the destination, | |
| 1031 // make a new direntry at the destination. | |
| 1032 | |
| 1033 err = jffs2_link(ds1.node, ds2.dir, ds2.name); | |
| 570 | 1034 |
| 1443 | 1035 if (err == 0) |
| 1036 ds1.node->i_ctime = | |
| 1037 ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp(); | |
| 570 | 1038 |
| 1443 | 1039 jffs2_iput(ds1.dir); |
| 1040 jffs2_iput(ds1.node); | |
| 1041 jffs2_iput(ds2.dir); | |
| 570 | 1042 |
| 1443 | 1043 return -err; |
| 570 | 1044 } |
| 1443 | 1045 #endif /* CYGOPT_FS_JFFS2_WRITE */ |
| 570 | 1046 // ------------------------------------------------------------------------- |
| 1047 // jffs2_opendir() | |
| 1048 // Open a directory for reading. | |
| 1049 | |
| 1050 static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 1051 cyg_file * file) |
| 570 | 1052 { |
| 1443 | 1053 jffs2_dirsearch ds; |
| 1054 int err; | |
| 570 | 1055 |
| 1443 | 1056 D2(printf("jffs2_opendir\n")); |
| 570 | 1057 |
| 2042 | 1058 init_dirsearch(&ds, (struct _inode *) dir, |
| 1059 (const unsigned char *) name); | |
| 570 | 1060 |
| 1443 | 1061 err = jffs2_find(&ds); |
| 570 | 1062 |
| 1443 | 1063 jffs2_iput(ds.dir); |
| 570 | 1064 |
| 1443 | 1065 if (err != ENOERR) |
| 1066 return err; | |
| 570 | 1067 |
| 1443 | 1068 // check it is really a directory. |
| 1069 if (!S_ISDIR(ds.node->i_mode)) { | |
| 1070 jffs2_iput(ds.node); | |
| 1071 return ENOTDIR; | |
| 1072 } | |
| 570 | 1073 |
| 1443 | 1074 // Initialize the file object, setting the f_ops field to a |
| 1075 // special set of file ops. | |
| 570 | 1076 |
| 1443 | 1077 file->f_type = CYG_FILE_TYPE_FILE; |
| 1078 file->f_ops = &jffs2_dirops; | |
| 1079 file->f_offset = 0; | |
| 1080 file->f_data = (CYG_ADDRWORD) ds.node; | |
| 1081 file->f_xops = 0; | |
| 570 | 1082 |
| 1443 | 1083 return ENOERR; |
| 570 | 1084 |
| 1085 } | |
| 1086 | |
| 1087 // ------------------------------------------------------------------------- | |
| 1088 // jffs2_chdir() | |
| 1089 // Change directory support. | |
| 1090 | |
| 1091 static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 1092 cyg_dir * dir_out) |
| 570 | 1093 { |
| 1443 | 1094 D2(printf("jffs2_chdir\n")); |
| 570 | 1095 |
| 1443 | 1096 if (dir_out != NULL) { |
| 1097 // This is a request to get a new directory pointer in | |
| 1098 // *dir_out. | |
| 570 | 1099 |
| 1443 | 1100 jffs2_dirsearch ds; |
| 1101 int err; | |
| 570 | 1102 |
| 2042 | 1103 init_dirsearch(&ds, (struct _inode *) dir, |
| 1104 (const unsigned char *) name); | |
| 570 | 1105 |
| 1443 | 1106 err = jffs2_find(&ds); |
| 1107 jffs2_iput(ds.dir); | |
| 570 | 1108 |
| 1443 | 1109 if (err != ENOERR) |
| 1110 return err; | |
| 570 | 1111 |
| 1443 | 1112 // check it is a directory |
| 1890 | 1113 if (!S_ISDIR(ds.node->i_mode)) { |
| 1114 jffs2_iput(ds.node); | |
| 1443 | 1115 return ENOTDIR; |
| 1890 | 1116 } |
| 1117 | |
| 1443 | 1118 // Pass it out |
| 1119 *dir_out = (cyg_dir) ds.node; | |
| 1120 } else { | |
| 1121 // If no output dir is required, this means that the mte and | |
| 1122 // dir arguments are the current cdir setting and we should | |
| 1123 // forget this fact. | |
| 570 | 1124 |
| 1443 | 1125 struct _inode *node = (struct _inode *) dir; |
| 570 | 1126 |
| 1443 | 1127 // Just decrement directory reference count. |
| 1128 jffs2_iput(node); | |
| 1129 } | |
| 570 | 1130 |
| 1443 | 1131 return ENOERR; |
| 570 | 1132 } |
| 1133 | |
| 1134 // ------------------------------------------------------------------------- | |
| 1135 // jffs2_stat() | |
| 1136 // Get struct stat info for named object. | |
| 1137 | |
| 1138 static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 1139 struct stat *buf) |
| 570 | 1140 { |
| 1443 | 1141 jffs2_dirsearch ds; |
| 1142 int err; | |
| 570 | 1143 |
| 1443 | 1144 D2(printf("jffs2_stat\n")); |
| 570 | 1145 |
| 2042 | 1146 init_dirsearch(&ds, (struct _inode *) dir, |
| 1147 (const unsigned char *) name); | |
| 570 | 1148 |
| 1443 | 1149 err = jffs2_find(&ds); |
| 1150 jffs2_iput(ds.dir); | |
| 570 | 1151 |
| 1443 | 1152 if (err != ENOERR) |
| 1153 return err; | |
| 570 | 1154 |
| 1443 | 1155 // Fill in the status |
| 1156 buf->st_mode = ds.node->i_mode; | |
| 1157 buf->st_ino = ds.node->i_ino; | |
| 1158 buf->st_dev = 0; | |
| 1159 buf->st_nlink = ds.node->i_nlink; | |
| 1160 buf->st_uid = ds.node->i_uid; | |
| 1161 buf->st_gid = ds.node->i_gid; | |
| 1162 buf->st_size = ds.node->i_size; | |
| 1163 buf->st_atime = ds.node->i_atime; | |
| 1164 buf->st_mtime = ds.node->i_mtime; | |
| 1165 buf->st_ctime = ds.node->i_ctime; | |
| 570 | 1166 |
| 1443 | 1167 jffs2_iput(ds.node); |
| 570 | 1168 |
| 1443 | 1169 return ENOERR; |
| 570 | 1170 } |
| 1171 | |
| 1172 // ------------------------------------------------------------------------- | |
| 1173 // jffs2_getinfo() | |
| 1174 // Getinfo. Currently only support pathconf(). | |
| 1175 | |
| 1176 static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 1177 int key, void *buf, int len) |
| 570 | 1178 { |
| 1443 | 1179 jffs2_dirsearch ds; |
| 1180 int err; | |
| 570 | 1181 |
| 1443 | 1182 D2(printf("jffs2_getinfo\n")); |
| 570 | 1183 |
| 2042 | 1184 init_dirsearch(&ds, (struct _inode *) dir, |
| 1185 (const unsigned char *) name); | |
| 570 | 1186 |
| 1443 | 1187 err = jffs2_find(&ds); |
| 1188 jffs2_iput(ds.dir); | |
| 570 | 1189 |
| 1443 | 1190 if (err != ENOERR) |
| 1191 return err; | |
| 570 | 1192 |
| 1443 | 1193 switch (key) { |
| 1194 case FS_INFO_CONF: | |
| 1195 err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf); | |
| 1196 break; | |
| 570 | 1197 |
| 1443 | 1198 default: |
| 1199 err = EINVAL; | |
| 1200 } | |
| 570 | 1201 |
| 1443 | 1202 jffs2_iput(ds.node); |
| 1203 return err; | |
| 570 | 1204 } |
| 1205 | |
| 1206 // ------------------------------------------------------------------------- | |
| 1207 // jffs2_setinfo() | |
| 1208 // Setinfo. Nothing to support here at present. | |
| 1209 | |
| 1210 static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name, | |
| 1443 | 1211 int key, void *buf, int len) |
| 570 | 1212 { |
| 1443 | 1213 // No setinfo keys supported at present |
| 570 | 1214 |
| 1443 | 1215 D2(printf("jffs2_setinfo\n")); |
| 570 | 1216 |
| 1443 | 1217 return EINVAL; |
| 570 | 1218 } |
| 1219 | |
| 1220 //========================================================================== | |
| 1221 // File operations | |
| 1222 | |
| 1223 // ------------------------------------------------------------------------- | |
| 1224 // jffs2_fo_read() | |
| 1225 // Read data from the file. | |
| 1226 | |
| 1227 static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) | |
| 1228 { | |
| 1443 | 1229 struct _inode *inode = (struct _inode *) fp->f_data; |
| 1230 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | |
| 1231 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | |
| 1232 int i; | |
| 1233 ssize_t resid = uio->uio_resid; | |
| 1234 off_t pos = fp->f_offset; | |
| 570 | 1235 |
| 1443 | 1236 down(&f->sem); |
| 570 | 1237 |
| 1443 | 1238 // Loop over the io vectors until there are none left |
| 1239 for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) { | |
| 1240 int ret; | |
| 1241 cyg_iovec *iov = &uio->uio_iov[i]; | |
| 1242 off_t len = min(iov->iov_len, inode->i_size - pos); | |
| 570 | 1243 |
| 1443 | 1244 D2(printf("jffs2_fo_read inode size %d\n", inode->i_size)); |
| 570 | 1245 |
| 1443 | 1246 ret = |
| 1247 jffs2_read_inode_range(c, f, | |
| 1248 (unsigned char *) iov->iov_base, pos, | |
| 1249 len); | |
| 1250 if (ret) { | |
| 1251 D1(printf | |
| 1252 ("jffs2_fo_read(): read_inode_range failed %d\n", | |
| 1253 ret)); | |
| 1254 uio->uio_resid = resid; | |
| 1255 up(&f->sem); | |
| 1256 return -ret; | |
| 1257 } | |
| 1258 resid -= len; | |
| 1259 pos += len; | |
| 1260 } | |
| 570 | 1261 |
| 1443 | 1262 // We successfully read some data, update the node's access time |
| 1263 // and update the file offset and transfer residue. | |
| 570 | 1264 |
| 1443 | 1265 inode->i_atime = cyg_timestamp(); |
| 570 | 1266 |
| 1443 | 1267 uio->uio_resid = resid; |
| 1268 fp->f_offset = pos; | |
| 570 | 1269 |
| 1443 | 1270 up(&f->sem); |
| 570 | 1271 |
| 1443 | 1272 return ENOERR; |
| 570 | 1273 } |
| 1274 | |
| 1443 | 1275 |
| 1276 #ifdef CYGOPT_FS_JFFS2_WRITE | |
| 570 | 1277 // ------------------------------------------------------------------------- |
| 1278 // jffs2_fo_write() | |
| 1279 // Write data to file. | |
| 1443 | 1280 static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri, |
| 1281 unsigned long offset) | |
| 1282 { | |
| 1283 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | |
| 1284 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | |
| 1285 struct jffs2_full_dnode *fn; | |
| 1286 uint32_t phys_ofs, alloc_len; | |
| 1287 int ret = 0; | |
| 1288 | |
| 1289 /* Make new hole frag from old EOF to new page */ | |
| 1290 D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", | |
| 1291 (unsigned int)inode->i_size, offset)); | |
| 1292 | |
|
1567
9a3dbd0dc33d
* src/fs-ecos.c (jffs2_extend_file): Fix creation of hole inode's
asl
parents:
1563
diff
changeset
|
1293 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); |
| 1443 | 1294 if (ret) |
| 1295 return ret; | |
| 1296 | |
| 1297 down(&f->sem); | |
| 1298 | |
| 1299 ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | |
| 1300 ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | |
|
1567
9a3dbd0dc33d
* src/fs-ecos.c (jffs2_extend_file): Fix creation of hole inode's
asl
parents:
1563
diff
changeset
|
1301 ri->totlen = cpu_to_je32(sizeof(*ri)); |
|
9a3dbd0dc33d
* src/fs-ecos.c (jffs2_extend_file): Fix creation of hole inode's
asl
parents:
1563
diff
changeset
|
1302 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); |
| 1443 | 1303 |
| 1304 ri->version = cpu_to_je32(++f->highest_version); | |
| 1305 ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset)); | |
| 1306 | |
| 1307 ri->offset = cpu_to_je32(inode->i_size); | |
| 1308 ri->dsize = cpu_to_je32(offset - inode->i_size); | |
| 1309 ri->csize = cpu_to_je32(0); | |
| 1310 ri->compr = JFFS2_COMPR_ZERO; | |
|
1567
9a3dbd0dc33d
* src/fs-ecos.c (jffs2_extend_file): Fix creation of hole inode's
asl
parents:
1563
diff
changeset
|
1311 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
| 1443 | 1312 ri->data_crc = cpu_to_je32(0); |
| 1313 | |
| 1314 fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); | |
| 1315 jffs2_complete_reservation(c); | |
| 1316 if (IS_ERR(fn)) { | |
| 1317 ret = PTR_ERR(fn); | |
| 1318 up(&f->sem); | |
| 1319 return ret; | |
| 1320 } | |
| 1321 ret = jffs2_add_full_dnode_to_inode(c, f, fn); | |
| 1322 if (f->metadata) { | |
| 1323 jffs2_mark_node_obsolete(c, f->metadata->raw); | |
| 1324 jffs2_free_full_dnode(f->metadata); | |
| 1325 f->metadata = NULL; | |
| 1326 } | |
| 1327 if (ret) { | |
| 1328 D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); | |
| 1329 jffs2_mark_node_obsolete(c, fn->raw); | |
| 1330 jffs2_free_full_dnode(fn); | |
| 1331 up(&f->sem); | |
| 1332 return ret; | |
| 1333 } | |
| 1334 inode->i_size = offset; | |
| 1335 up(&f->sem); | |
| 1336 return 0; | |
| 1337 } | |
| 570 | 1338 |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1339 // jffs2_fo_open() |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1340 // Truncate a file |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1341 static int jffs2_truncate_file (struct _inode *inode) |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1342 { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1343 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1344 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1345 struct jffs2_full_dnode *new_metadata, * old_metadata; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1346 struct jffs2_raw_inode *ri; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1347 uint32_t phys_ofs, alloclen; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1348 int err; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1349 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1350 ri = jffs2_alloc_raw_inode(); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1351 if (!ri) { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1352 return ENOMEM; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1353 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1354 err = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1355 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1356 if (err) { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1357 jffs2_free_raw_inode(ri); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1358 return err; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1359 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1360 down(&f->sem); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1361 ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1362 ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1363 ri->totlen = cpu_to_je32(sizeof(*ri)); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1364 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1365 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1366 ri->ino = cpu_to_je32(inode->i_ino); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1367 ri->version = cpu_to_je32(++f->highest_version); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1368 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1369 ri->uid = cpu_to_je16(inode->i_uid); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1370 ri->gid = cpu_to_je16(inode->i_gid); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1371 ri->mode = cpu_to_jemode(inode->i_mode); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1372 ri->isize = cpu_to_je32(0); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1373 ri->atime = cpu_to_je32(inode->i_atime); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1374 ri->mtime = cpu_to_je32(cyg_timestamp()); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1375 ri->offset = cpu_to_je32(0); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1376 ri->csize = ri->dsize = cpu_to_je32(0); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1377 ri->compr = JFFS2_COMPR_NONE; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1378 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1379 ri->data_crc = cpu_to_je32(0); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1380 new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1381 phys_ofs, ALLOC_NORMAL); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1382 if (IS_ERR(new_metadata)) { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1383 jffs2_complete_reservation(c); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1384 jffs2_free_raw_inode(ri); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1385 up(&f->sem); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1386 return PTR_ERR(new_metadata); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1387 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1388 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1389 /* It worked. Update the inode */ |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1390 inode->i_mtime = cyg_timestamp(); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1391 inode->i_size = 0; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1392 old_metadata = f->metadata; |
| 2042 | 1393 jffs2_truncate_fragtree (c, &f->fragtree, 0); |
|
1897
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1394 f->metadata = new_metadata; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1395 if (old_metadata) { |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1396 jffs2_mark_node_obsolete(c, old_metadata->raw); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1397 jffs2_free_full_dnode(old_metadata); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1398 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1399 jffs2_free_raw_inode(ri); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1400 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1401 up(&f->sem); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1402 jffs2_complete_reservation(c); |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1403 |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1404 return 0; |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1405 } |
|
45b8b118a6a8
* src/fs-ecos.c (jffs2_truncate_file): Correctly truncate a file
asl
parents:
1890
diff
changeset
|
1406 |
| 570 | 1407 static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) |
| 1408 { | |
| 1443 | 1409 struct _inode *inode = (struct _inode *) fp->f_data; |
| 1410 off_t pos = fp->f_offset; | |
| 1411 ssize_t resid = uio->uio_resid; | |
| 1412 struct jffs2_raw_inode ri; | |
| 1413 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | |
| 1414 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | |
| 1415 int i; | |
| 570 | 1416 |
| 1443 | 1417 // If the APPEND mode bit was supplied, force all writes to |
| 1418 // the end of the file. | |
| 1419 if (fp->f_flag & CYG_FAPPEND) | |
| 1420 pos = fp->f_offset = inode->i_size; | |
| 570 | 1421 |
| 1443 | 1422 if (pos < 0) |
| 1423 return EINVAL; | |
| 570 | 1424 |
| 1443 | 1425 memset(&ri, 0, sizeof(ri)); |
| 1426 | |
| 1427 ri.ino = cpu_to_je32(f->inocache->ino); | |
| 1428 ri.mode = cpu_to_jemode(inode->i_mode); | |
| 1429 ri.uid = cpu_to_je16(inode->i_uid); | |
| 1430 ri.gid = cpu_to_je16(inode->i_gid); | |
| 1431 ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp()); | |
| 570 | 1432 |
| 1443 | 1433 if (pos > inode->i_size) { |
| 1434 int err; | |
| 1435 ri.version = cpu_to_je32(++f->highest_version); | |
| 1436 err = jffs2_extend_file(inode, &ri, pos); | |
| 1437 if (err) | |
| 1438 return -err; | |
| 1439 } | |
| 1562 | 1440 ri.isize = cpu_to_je32(inode->i_size); |
| 570 | 1441 |
| 1443 | 1442 // Now loop over the iovecs until they are all done, or |
| 1443 // we get an error. | |
| 1444 for (i = 0; i < uio->uio_iovcnt; i++) { | |
| 1445 cyg_iovec *iov = &uio->uio_iov[i]; | |
| 2042 | 1446 unsigned char *buf = iov->iov_base; |
| 1443 | 1447 off_t len = iov->iov_len; |
| 570 | 1448 |
| 1443 | 1449 uint32_t writtenlen; |
| 1450 int err; | |
| 570 | 1451 |
| 1443 | 1452 D2(printf("jffs2_fo_write page_start_pos %d\n", pos)); |
| 1890 | 1453 D2(printf("jffs2_fo_write transfer size %d\n", len)); |
| 570 | 1454 |
| 1443 | 1455 err = jffs2_write_inode_range(c, f, &ri, buf, |
| 1456 pos, len, &writtenlen); | |
| 1457 if (err) | |
| 1458 return -err; | |
| 1459 | |
| 1460 if (writtenlen != len) | |
| 1461 return ENOSPC; | |
| 570 | 1462 |
| 1443 | 1463 pos += len; |
| 1464 resid -= len; | |
| 1465 } | |
| 570 | 1466 |
| 1443 | 1467 // We wrote some data successfully, update the modified and access |
| 1468 // times of the inode, increase its size appropriately, and update | |
| 1469 // the file offset and transfer residue. | |
| 1470 inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime); | |
| 1471 if (pos > inode->i_size) | |
| 1472 inode->i_size = pos; | |
| 570 | 1473 |
| 1443 | 1474 uio->uio_resid = resid; |
| 1475 fp->f_offset = pos; | |
| 570 | 1476 |
| 1443 | 1477 return ENOERR; |
| 570 | 1478 } |
| 1443 | 1479 #endif /* CYGOPT_FS_JFFS2_WRITE */ |
| 570 | 1480 |
| 1481 // ------------------------------------------------------------------------- | |
| 1482 // jffs2_fo_lseek() | |
| 1483 // Seek to a new file position. | |
| 1484 | |
| 1485 static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence) | |
| 1486 { | |
| 1443 | 1487 struct _inode *node = (struct _inode *) fp->f_data; |
| 1488 off_t pos = *apos; | |
| 570 | 1489 |
| 1443 | 1490 D2(printf("jffs2_fo_lseek\n")); |
| 570 | 1491 |
| 1443 | 1492 switch (whence) { |
| 1493 case SEEK_SET: | |
| 1494 // Pos is already where we want to be. | |
| 1495 break; | |
| 570 | 1496 |
| 1443 | 1497 case SEEK_CUR: |
| 1498 // Add pos to current offset. | |
| 1499 pos += fp->f_offset; | |
| 1500 break; | |
| 570 | 1501 |
| 1443 | 1502 case SEEK_END: |
| 1503 // Add pos to file size. | |
| 1504 pos += node->i_size; | |
| 1505 break; | |
| 570 | 1506 |
| 1443 | 1507 default: |
| 1508 return EINVAL; | |
| 1509 } | |
| 570 | 1510 |
| 1713 | 1511 if (pos < 0 ) |
| 1601 | 1512 return EINVAL; |
| 1513 | |
| 1443 | 1514 // All OK, set fp offset and return new position. |
| 1515 *apos = fp->f_offset = pos; | |
| 570 | 1516 |
| 1443 | 1517 return ENOERR; |
| 570 | 1518 } |
| 1519 | |
| 1520 // ------------------------------------------------------------------------- | |
| 1521 // jffs2_fo_ioctl() | |
| 1522 // Handle ioctls. Currently none are defined. | |
| 1523 | |
| 1524 static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, | |
| 1443 | 1525 CYG_ADDRWORD data) |
| 570 | 1526 { |
| 1443 | 1527 // No Ioctls currenly defined. |
| 570 | 1528 |
| 1443 | 1529 D2(printf("jffs2_fo_ioctl\n")); |
| 570 | 1530 |
| 1443 | 1531 return EINVAL; |
| 570 | 1532 } |
| 1533 | |
| 1534 // ------------------------------------------------------------------------- | |
| 1535 // jffs2_fo_fsync(). | |
| 1536 // Force the file out to data storage. | |
| 1537 | |
| 1538 static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode) | |
| 1539 { | |
| 1443 | 1540 // Data is always permanently where it belongs, nothing to do |
| 1541 // here. | |
| 570 | 1542 |
| 1443 | 1543 D2(printf("jffs2_fo_fsync\n")); |
| 570 | 1544 |
| 1443 | 1545 return ENOERR; |
| 570 | 1546 } |
| 1547 | |
| 1548 // ------------------------------------------------------------------------- | |
| 1549 // jffs2_fo_close() | |
| 1550 // Close a file. We just decrement the refcnt and let it go away if | |
| 1551 // that is all that is keeping it here. | |
| 1552 | |
| 1553 static int jffs2_fo_close(struct CYG_FILE_TAG *fp) | |
| 1554 { | |
| 1443 | 1555 struct _inode *node = (struct _inode *) fp->f_data; |
| 570 | 1556 |
| 1443 | 1557 D2(printf("jffs2_fo_close\n")); |
| 570 | 1558 |
| 1443 | 1559 jffs2_iput(node); |
| 570 | 1560 |
| 1443 | 1561 fp->f_data = 0; // zero data pointer |
| 570 | 1562 |
| 1443 | 1563 return ENOERR; |
| 570 | 1564 } |
| 1565 | |
| 1566 // ------------------------------------------------------------------------- | |
| 1567 //jffs2_fo_fstat() | |
| 1568 // Get file status. | |
| 1569 | |
| 1570 static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf) | |
| 1571 { | |
| 1443 | 1572 struct _inode *node = (struct _inode *) fp->f_data; |
| 570 | 1573 |
| 1443 | 1574 D2(printf("jffs2_fo_fstat\n")); |
| 570 | 1575 |
| 1443 | 1576 // Fill in the status |
| 1577 buf->st_mode = node->i_mode; | |
| 1578 buf->st_ino = node->i_ino; | |
| 1579 buf->st_dev = 0; | |
| 1580 buf->st_nlink = node->i_nlink; | |
| 1581 buf->st_uid = node->i_uid; | |
| 1582 buf->st_gid = node->i_gid; | |
| 1583 buf->st_size = node->i_size; | |
| 1584 buf->st_atime = node->i_atime; | |
| 1585 buf->st_mtime = node->i_mtime; | |
| 1586 buf->st_ctime = node->i_ctime; | |
| 570 | 1587 |
| 1443 | 1588 return ENOERR; |
| 570 | 1589 } |
| 1590 | |
| 1591 // ------------------------------------------------------------------------- | |
| 1592 // jffs2_fo_getinfo() | |
| 1593 // Get info. Currently only supports fpathconf(). | |
| 1594 | |
| 1595 static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, | |
| 1443 | 1596 int len) |
| 570 | 1597 { |
| 1443 | 1598 struct _inode *node = (struct _inode *) fp->f_data; |
| 1599 int err; | |
| 570 | 1600 |
| 1443 | 1601 D2(printf("jffs2_fo_getinfo\n")); |
| 570 | 1602 |
| 1443 | 1603 switch (key) { |
| 1604 case FS_INFO_CONF: | |
| 1605 err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf); | |
| 1606 break; | |
| 570 | 1607 |
| 1443 | 1608 default: |
| 1609 err = EINVAL; | |
| 1610 } | |
| 1611 return err; | |
| 570 | 1612 |
| 1443 | 1613 return ENOERR; |
| 570 | 1614 } |
| 1615 | |
| 1616 // ------------------------------------------------------------------------- | |
| 1617 // jffs2_fo_setinfo() | |
| 1618 // Set info. Nothing supported here. | |
| 1619 | |
| 1620 static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, | |
| 1443 | 1621 int len) |
| 570 | 1622 { |
| 1443 | 1623 // No setinfo key supported at present |
| 570 | 1624 |
| 1443 | 1625 D2(printf("jffs2_fo_setinfo\n")); |
| 570 | 1626 |
| 1443 | 1627 return ENOERR; |
| 570 | 1628 } |
| 1629 | |
| 1630 //========================================================================== | |
| 1631 // Directory operations | |
| 1632 | |
| 1633 // ------------------------------------------------------------------------- | |
| 1634 // jffs2_fo_dirread() | |
| 1635 // Read a single directory entry from a file. | |
| 1636 | |
| 2042 | 1637 static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen) |
| 570 | 1638 { |
| 1443 | 1639 int len = nlen < namlen ? nlen : namlen; |
| 1640 memcpy(nbuf, name, len); | |
| 1641 nbuf[len] = '\0'; | |
| 570 | 1642 } |
| 1643 | |
| 1644 static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio) | |
| 1645 { | |
| 1443 | 1646 struct _inode *d_inode = (struct _inode *) fp->f_data; |
| 1647 struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base; | |
| 1648 char *nbuf = ent->d_name; | |
|
2475
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1649 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1650 struct _inode *c_ino; |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1651 #endif |
| 1443 | 1652 int nlen = sizeof (ent->d_name) - 1; |
| 1653 off_t len = uio->uio_iov[0].iov_len; | |
| 1654 struct jffs2_inode_info *f; | |
| 1655 struct jffs2_sb_info *c; | |
| 1656 struct _inode *inode = d_inode; | |
| 1657 struct jffs2_full_dirent *fd; | |
| 1658 unsigned long offset, curofs; | |
| 1659 int found = 1; | |
| 570 | 1660 |
| 1443 | 1661 if (len < sizeof (struct dirent)) |
| 1662 return EINVAL; | |
| 570 | 1663 |
| 1443 | 1664 D1(printk |
| 1665 (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino)); | |
| 570 | 1666 |
| 1443 | 1667 f = JFFS2_INODE_INFO(inode); |
| 1668 c = JFFS2_SB_INFO(inode->i_sb); | |
| 570 | 1669 |
| 1443 | 1670 offset = fp->f_offset; |
| 570 | 1671 |
| 1443 | 1672 if (offset == 0) { |
| 1673 D1(printk | |
| 1674 (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino)); | |
| 2042 | 1675 filldir(nbuf, nlen, (const unsigned char *) ".", 1); |
|
2475
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1676 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1677 // Flags here are the same as jffs2_mkdir. Make sure |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1678 // d_type is the same as st_mode of calling stat. |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1679 ent->d_type = |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1680 jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1681 #endif |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1682 goto out; |
| 1443 | 1683 } |
| 1684 if (offset == 1) { | |
| 2042 | 1685 filldir(nbuf, nlen, (const unsigned char *) "..", 2); |
|
2475
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1686 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1687 // Flags here are the same as jffs2_mkdir. Make sure |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1688 // d_type is the same as st_mode of calling stat. |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1689 ent->d_type = |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1690 jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR)); |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1691 #endif |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1692 goto out; |
| 1443 | 1693 } |
| 570 | 1694 |
| 1443 | 1695 curofs = 1; |
| 1696 down(&f->sem); | |
| 1697 for (fd = f->dents; fd; fd = fd->next) { | |
| 570 | 1698 |
| 1443 | 1699 curofs++; |
| 1700 /* First loop: curofs = 2; offset = 2 */ | |
| 1701 if (curofs < offset) { | |
| 1702 D2(printk | |
| 1703 (KERN_DEBUG | |
| 1704 "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", | |
| 1705 fd->name, fd->ino, fd->type, curofs, offset)); | |
| 1706 continue; | |
| 1707 } | |
| 1708 if (!fd->ino) { | |
| 1709 D2(printk | |
| 1710 (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", | |
| 1711 fd->name)); | |
| 1712 offset++; | |
| 1713 continue; | |
| 1714 } | |
| 1715 D2(printk | |
| 1716 (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, | |
| 1717 fd->name, fd->ino, fd->type)); | |
| 2042 | 1718 filldir(nbuf, nlen, fd->name, strlen((char *)fd->name)); |
|
2475
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1719 #ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1720 c_ino = jffs2_iget(inode->i_sb, fd->ino); |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1721 if(IS_ERR(c_ino)) { |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1722 D1(printk(KERN_WARNING "get entry inode failed\n")); |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1723 // fileio already set it to zero, so not needed here |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1724 // ent->d_type = 0; |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1725 } |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1726 else { |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1727 ent->d_type = c_ino->i_mode; |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1728 jffs2_iput(c_ino); |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1729 } |
|
e302e779e69b
* cdl/jffs2.cdl: Use CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE to control
asl
parents:
2199
diff
changeset
|
1730 #endif |
| 1443 | 1731 goto out_sem; |
| 1732 } | |
| 1733 /* Reached the end of the directory */ | |
| 1734 found = 0; | |
| 570 | 1735 out_sem: |
| 1443 | 1736 up(&f->sem); |
| 570 | 1737 out: |
| 1443 | 1738 fp->f_offset = ++offset; |
| 1739 if (found) { | |
| 1740 uio->uio_resid -= sizeof (struct dirent); | |
| 1741 } | |
| 1742 return ENOERR; | |
| 570 | 1743 } |
| 1744 | |
| 1745 // ------------------------------------------------------------------------- | |
| 1746 // jffs2_fo_dirlseek() | |
| 1747 // Seek directory to start. | |
| 1748 | |
| 1749 static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence) | |
| 1750 { | |
| 1443 | 1751 // Only allow SEEK_SET to zero |
| 570 | 1752 |
| 1443 | 1753 D2(printf("jffs2_fo_dirlseek\n")); |
| 570 | 1754 |
| 1443 | 1755 if (whence != SEEK_SET || *pos != 0) |
| 1756 return EINVAL; | |
| 570 | 1757 |
| 1443 | 1758 *pos = fp->f_offset = 0; |
| 570 | 1759 |
| 1443 | 1760 return ENOERR; |
| 570 | 1761 } |
| 1762 | |
| 1763 //========================================================================== | |
| 1764 // | |
| 1765 // Called by JFFS2 | |
| 1766 // =============== | |
| 1767 // | |
| 1768 // | |
| 1769 //========================================================================== | |
| 1770 | |
| 1443 | 1771 unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, |
| 1772 struct jffs2_inode_info *f, | |
| 1773 unsigned long offset, | |
| 1774 unsigned long *priv) | |
| 570 | 1775 { |
| 1443 | 1776 /* FIXME: This works only with one file system mounted at a time */ |
| 1777 int ret; | |
| 570 | 1778 |
| 1834 | 1779 ret = jffs2_read_inode_range(c, f, gc_buffer, |
| 1780 offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE); | |
| 1443 | 1781 if (ret) |
| 1782 return ERR_PTR(ret); | |
| 570 | 1783 |
| 1443 | 1784 return gc_buffer; |
| 570 | 1785 } |
| 1786 | |
| 1443 | 1787 void jffs2_gc_release_page(struct jffs2_sb_info *c, |
| 1788 unsigned char *ptr, | |
| 1789 unsigned long *priv) | |
| 570 | 1790 { |
| 1443 | 1791 /* Do nothing */ |
| 570 | 1792 } |
| 1793 | |
| 1443 | 1794 static struct _inode *new_inode(struct super_block *sb) |
| 570 | 1795 { |
| 1796 | |
| 1443 | 1797 // Only called in write.c jffs2_new_inode |
| 1798 // Always adds itself to inode cache | |
| 570 | 1799 |
| 1443 | 1800 struct _inode *inode; |
| 1801 struct _inode *cached_inode; | |
| 570 | 1802 |
| 1443 | 1803 inode = malloc(sizeof (struct _inode)); |
| 1804 if (inode == NULL) | |
| 1805 return 0; | |
| 570 | 1806 |
| 1443 | 1807 D2(printf |
| 1808 ("malloc new_inode %x ####################################\n", | |
| 1809 inode)); | |
| 570 | 1810 |
| 1443 | 1811 memset(inode, 0, sizeof (struct _inode)); |
| 1812 inode->i_sb = sb; | |
| 1813 inode->i_ino = 1; | |
| 1814 inode->i_count = 1; | |
| 1815 inode->i_nlink = 1; // Let JFFS2 manage the link count | |
| 1816 inode->i_size = 0; | |
| 570 | 1817 |
| 1443 | 1818 inode->i_cache_next = NULL; // Newest inode, about to be cached |
| 570 | 1819 |
| 1443 | 1820 // Add to the icache |
| 1821 for (cached_inode = sb->s_root; cached_inode != NULL; | |
| 1822 cached_inode = cached_inode->i_cache_next) { | |
| 1823 if (cached_inode->i_cache_next == NULL) { | |
| 1824 cached_inode->i_cache_next = inode; // Current last in cache points to newcomer | |
| 1825 inode->i_cache_prev = cached_inode; // Newcomer points back to last | |
| 1826 break; | |
| 1827 } | |
| 1828 } | |
| 1829 return inode; | |
| 570 | 1830 } |
| 1831 | |
| 1443 | 1832 static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino) |
| 570 | 1833 { |
| 1443 | 1834 struct _inode *inode = NULL; |
| 570 | 1835 |
| 1443 | 1836 D2(printf("ilookup\n")); |
| 1837 // Check for this inode in the cache | |
| 1838 for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) { | |
| 1839 if (inode->i_ino == ino) { | |
| 1840 inode->i_count++; | |
| 1841 break; | |
| 1842 } | |
| 1843 } | |
| 1844 return inode; | |
| 570 | 1845 } |
| 1846 | |
| 1443 | 1847 struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino) |
| 570 | 1848 { |
| 1443 | 1849 // Called in super.c jffs2_read_super, dir.c jffs2_lookup, |
| 1850 // and gc.c jffs2_garbage_collect_pass | |
| 1851 | |
| 1852 // Must first check for cached inode | |
| 1853 // If this fails let new_inode create one | |
| 1854 | |
| 1855 struct _inode *inode; | |
| 1856 int err; | |
| 1857 | |
| 1858 D2(printf("jffs2_iget\n")); | |
| 570 | 1859 |
| 1443 | 1860 inode = ilookup(sb, ino); |
| 1861 if (inode) | |
| 1862 return inode; | |
| 1863 | |
| 1864 // Not cached, so malloc it | |
| 1865 inode = new_inode(sb); | |
| 1866 if (inode == NULL) | |
| 1890 | 1867 return ERR_PTR(-ENOMEM); |
| 570 | 1868 |
| 1443 | 1869 inode->i_ino = ino; |
| 570 | 1870 |
| 1443 | 1871 err = jffs2_read_inode(inode); |
| 1872 if (err) { | |
| 1873 printf("jffs2_read_inode() failed\n"); | |
| 1890 | 1874 inode->i_nlink = 0; // free _this_ bad inode right now |
| 1443 | 1875 jffs2_iput(inode); |
| 1876 inode = NULL; | |
| 1877 return ERR_PTR(err); | |
| 1878 } | |
| 1879 return inode; | |
| 570 | 1880 } |
| 1881 | |
| 1882 // ------------------------------------------------------------------------- | |
| 1443 | 1883 // Decrement the reference count on an inode. If this makes the ref count |
| 1884 // zero, then this inode can be freed. | |
| 1885 | |
| 1886 void jffs2_iput(struct _inode *i) | |
| 1887 { | |
| 1888 // Called in jffs2_find | |
| 1889 // (and jffs2_open and jffs2_ops_mkdir?) | |
| 1890 // super.c jffs2_read_super, | |
| 1891 // and gc.c jffs2_garbage_collect_pass | |
| 1892 recurse: | |
| 1893 if (!i) { | |
| 1894 printf("jffs2_iput() called with NULL inode\n"); | |
| 1895 // and let it fault... | |
| 1896 } | |
| 1897 | |
| 1898 i->i_count--; | |
| 1899 | |
| 1900 if (i->i_count < 0) | |
| 1901 BUG(); | |
| 1902 | |
| 1903 if (i->i_count) | |
| 1871 | 1904 return; |
| 1905 | |
| 1443 | 1906 if (!i->i_nlink) { |
| 1907 struct _inode *parent; | |
| 1908 | |
| 1909 // Remove from the icache linked list and free immediately | |
| 1910 if (i->i_cache_prev) | |
| 1911 i->i_cache_prev->i_cache_next = i->i_cache_next; | |
| 1912 if (i->i_cache_next) | |
| 1913 i->i_cache_next->i_cache_prev = i->i_cache_prev; | |
| 1914 | |
| 1915 parent = i->i_parent; | |
| 1916 jffs2_clear_inode(i); | |
| 1917 memset(i, 0x5a, sizeof(*i)); | |
| 1918 free(i); | |
| 1919 | |
| 1920 if (parent && parent != i) { | |
| 1921 i = parent; | |
| 1922 goto recurse; | |
| 1923 } | |
| 1924 | |
| 1925 } else { | |
| 1926 // Evict some _other_ inode with i_count zero, leaving | |
| 1927 // this latest one in the cache for a while | |
| 1928 icache_evict(i->i_sb->s_root, i); | |
| 1929 } | |
| 1930 } | |
| 1931 | |
| 1932 | |
| 1933 // ------------------------------------------------------------------------- | |
| 570 | 1934 // EOF jffs2.c |
| 1443 | 1935 |
| 1936 | |
| 1937 static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |
| 1938 { | |
| 1939 memset(f, 0, sizeof(*f)); | |
| 1940 init_MUTEX_LOCKED(&f->sem); | |
| 1941 } | |
| 1942 | |
| 1943 static void jffs2_clear_inode (struct _inode *inode) | |
| 570 | 1944 { |
| 1945 /* We can forget about this inode for now - drop all | |
| 1946 * the nodelists associated with it, etc. | |
| 1947 */ | |
| 1948 struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | |
| 1949 struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | |
| 1950 | |
| 1951 D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); | |
| 1952 | |
| 1953 jffs2_do_clear_inode(c, f); | |
| 1954 } | |
| 1955 | |
| 1956 | |
| 1957 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, | |
| 1958 fill in the raw_inode while you're at it. */ | |
| 1443 | 1959 struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri) |
| 570 | 1960 { |
| 1443 | 1961 struct _inode *inode; |
| 1962 struct super_block *sb = dir_i->i_sb; | |
| 1963 struct jffs2_sb_info *c; | |
| 1964 struct jffs2_inode_info *f; | |
| 1965 int ret; | |
| 570 | 1966 |
| 1443 | 1967 D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); |
| 1968 | |
| 1969 c = JFFS2_SB_INFO(sb); | |
| 1970 | |
| 1971 inode = new_inode(sb); | |
| 1972 | |
| 1973 if (!inode) | |
| 1974 return ERR_PTR(-ENOMEM); | |
| 570 | 1975 |
| 1443 | 1976 f = JFFS2_INODE_INFO(inode); |
| 1977 jffs2_init_inode_info(f); | |
| 570 | 1978 |
| 1443 | 1979 memset(ri, 0, sizeof(*ri)); |
| 1980 /* Set OS-specific defaults for new inodes */ | |
| 1981 ri->uid = ri->gid = cpu_to_je16(0); | |
| 1982 ri->mode = cpu_to_jemode(mode); | |
| 1983 ret = jffs2_do_new_inode (c, f, mode, ri); | |
| 1984 if (ret) { | |
| 1890 | 1985 // forceful evict: f->sem is locked already, and the |
| 1986 // inode is bad. | |
| 1987 if (inode->i_cache_prev) | |
| 1988 inode->i_cache_prev->i_cache_next = inode->i_cache_next; | |
| 1989 if (inode->i_cache_next) | |
| 1990 inode->i_cache_next->i_cache_prev = inode->i_cache_prev; | |
| 1991 up(&(f->sem)); | |
| 1992 jffs2_clear_inode(inode); | |
| 1993 memset(inode, 0x6a, sizeof(*inode)); | |
| 1994 free(inode); | |
| 1995 return ERR_PTR(ret); | |
| 1443 | 1996 } |
| 1997 inode->i_nlink = 1; | |
| 1998 inode->i_ino = je32_to_cpu(ri->ino); | |
| 1999 inode->i_mode = jemode_to_cpu(ri->mode); | |
| 2000 inode->i_gid = je16_to_cpu(ri->gid); | |
| 2001 inode->i_uid = je16_to_cpu(ri->uid); | |
| 2002 inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp(); | |
| 2003 ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime); | |
| 570 | 2004 |
| 1443 | 2005 inode->i_size = 0; |
| 2006 | |
| 2007 return inode; | |
| 2008 } | |
| 2009 | |
| 2010 | |
| 2011 static int jffs2_read_inode (struct _inode *inode) | |
| 2012 { | |
| 2013 struct jffs2_inode_info *f; | |
| 2014 struct jffs2_sb_info *c; | |
| 2015 struct jffs2_raw_inode latest_node; | |
| 2016 int ret; | |
| 2017 | |
| 2018 D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); | |
| 2019 | |
| 2020 f = JFFS2_INODE_INFO(inode); | |
| 2021 c = JFFS2_SB_INFO(inode->i_sb); | |
| 570 | 2022 |
| 1443 | 2023 jffs2_init_inode_info(f); |
| 2024 | |
| 2025 ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); | |
| 570 | 2026 |
| 1443 | 2027 if (ret) { |
| 2028 up(&f->sem); | |
| 2029 return ret; | |
| 2030 } | |
| 2031 inode->i_mode = jemode_to_cpu(latest_node.mode); | |
| 2032 inode->i_uid = je16_to_cpu(latest_node.uid); | |
| 2033 inode->i_gid = je16_to_cpu(latest_node.gid); | |
| 2034 inode->i_size = je32_to_cpu(latest_node.isize); | |
| 2035 inode->i_atime = je32_to_cpu(latest_node.atime); | |
| 2036 inode->i_mtime = je32_to_cpu(latest_node.mtime); | |
| 2037 inode->i_ctime = je32_to_cpu(latest_node.ctime); | |
| 570 | 2038 |
| 1443 | 2039 inode->i_nlink = f->inocache->nlink; |
| 2040 up(&f->sem); | |
| 2041 | |
| 2042 D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); | |
| 2043 return 0; | |
| 570 | 2044 } |
| 2045 | |
| 2046 | |
| 1443 | 2047 void jffs2_gc_release_inode(struct jffs2_sb_info *c, |
| 2048 struct jffs2_inode_info *f) | |
| 2049 { | |
| 2050 jffs2_iput(OFNI_EDONI_2SFFJ(f)); | |
| 2051 } | |
| 2052 | |
| 2053 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | |
| 2054 int inum, int nlink) | |
| 570 | 2055 { |
| 1443 | 2056 struct _inode *inode; |
| 2057 struct jffs2_inode_cache *ic; | |
| 2058 if (!nlink) { | |
| 2059 /* The inode has zero nlink but its nodes weren't yet marked | |
| 2060 obsolete. This has to be because we're still waiting for | |
| 2061 the final (close() and) jffs2_iput() to happen. | |
| 2062 | |
| 2063 There's a possibility that the final jffs2_iput() could have | |
| 2064 happened while we were contemplating. In order to ensure | |
| 2065 that we don't cause a new read_inode() (which would fail) | |
| 2066 for the inode in question, we use ilookup() in this case | |
| 2067 instead of jffs2_iget(). | |
| 2068 | |
| 2069 The nlink can't _become_ zero at this point because we're | |
| 2070 holding the alloc_sem, and jffs2_do_unlink() would also | |
| 2071 need that while decrementing nlink on any inode. | |
| 2072 */ | |
| 2073 inode = ilookup(OFNI_BS_2SFFJ(c), inum); | |
| 2074 if (!inode) { | |
| 2075 D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n", | |
| 2076 inum)); | |
| 570 | 2077 |
| 1443 | 2078 spin_lock(&c->inocache_lock); |
| 2079 ic = jffs2_get_ino_cache(c, inum); | |
| 2080 if (!ic) { | |
| 2081 D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum)); | |
| 2082 spin_unlock(&c->inocache_lock); | |
| 2083 return NULL; | |
| 2084 } | |
| 2085 if (ic->state != INO_STATE_CHECKEDABSENT) { | |
| 2086 /* Wait for progress. Don't just loop */ | |
| 2087 D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n", | |
| 2088 ic->ino, ic->state)); | |
| 2089 sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | |
| 2090 } else { | |
| 2091 spin_unlock(&c->inocache_lock); | |
| 2092 } | |
| 570 | 2093 |
| 1443 | 2094 return NULL; |
| 2095 } | |
| 2096 } else { | |
| 2097 /* Inode has links to it still; they're not going away because | |
| 2098 jffs2_do_unlink() would need the alloc_sem and we have it. | |
| 2099 Just jffs2_iget() it, and if read_inode() is necessary that's OK. | |
| 2100 */ | |
| 2101 inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); | |
| 2102 if (IS_ERR(inode)) | |
| 2103 return (void *)inode; | |
| 2104 } | |
| 570 | 2105 |
| 1443 | 2106 return JFFS2_INODE_INFO(inode); |
| 2107 } | |
| 2108 | |
| 2109 | |
| 570 | 2110 |
| 1443 | 2111 uint32_t jffs2_from_os_mode(uint32_t osmode) |
| 2112 { | |
| 2113 uint32_t jmode = ((osmode & S_IRUSR)?00400:0) | | |
| 2114 ((osmode & S_IWUSR)?00200:0) | | |
| 2115 ((osmode & S_IXUSR)?00100:0) | | |
| 2116 ((osmode & S_IRGRP)?00040:0) | | |
| 2117 ((osmode & S_IWGRP)?00020:0) | | |
| 2118 ((osmode & S_IXGRP)?00010:0) | | |
| 2119 ((osmode & S_IROTH)?00004:0) | | |
| 2120 ((osmode & S_IWOTH)?00002:0) | | |
| 2121 ((osmode & S_IXOTH)?00001:0); | |
| 2122 | |
| 2123 switch (osmode & S_IFMT) { | |
| 2124 case S_IFSOCK: | |
| 2125 return jmode | 0140000; | |
| 2126 case S_IFLNK: | |
| 2127 return jmode | 0120000; | |
| 2128 case S_IFREG: | |
| 2129 return jmode | 0100000; | |
| 2130 case S_IFBLK: | |
| 2131 return jmode | 0060000; | |
| 2132 case S_IFDIR: | |
| 2133 return jmode | 0040000; | |
| 2134 case S_IFCHR: | |
| 2135 return jmode | 0020000; | |
| 2136 case S_IFIFO: | |
| 2137 return jmode | 0010000; | |
| 2138 case S_ISUID: | |
| 2139 return jmode | 0004000; | |
| 2140 case S_ISGID: | |
| 2141 return jmode | 0002000; | |
| 2142 #ifdef S_ISVTX | |
| 2143 case S_ISVTX: | |
| 2144 return jmode | 0001000; | |
| 2145 #endif | |
| 2146 } | |
| 2147 printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode); | |
| 2148 BUG(); | |
| 2149 return 0; | |
| 2150 } | |
| 570 | 2151 |
| 1443 | 2152 uint32_t jffs2_to_os_mode (uint32_t jmode) |
| 2153 { | |
| 2154 uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) | | |
| 2155 ((jmode & 00200)?S_IWUSR:0) | | |
| 2156 ((jmode & 00100)?S_IXUSR:0) | | |
| 2157 ((jmode & 00040)?S_IRGRP:0) | | |
| 2158 ((jmode & 00020)?S_IWGRP:0) | | |
| 2159 ((jmode & 00010)?S_IXGRP:0) | | |
| 2160 ((jmode & 00004)?S_IROTH:0) | | |
| 2161 ((jmode & 00002)?S_IWOTH:0) | | |
| 2162 ((jmode & 00001)?S_IXOTH:0); | |
| 570 | 2163 |
| 1443 | 2164 switch(jmode & 00170000) { |
| 2165 case 0140000: | |
| 2166 return osmode | S_IFSOCK; | |
| 2167 case 0120000: | |
| 2168 return osmode | S_IFLNK; | |
| 2169 case 0100000: | |
| 2170 return osmode | S_IFREG; | |
| 2171 case 0060000: | |
| 2172 return osmode | S_IFBLK; | |
| 2173 case 0040000: | |
| 2174 return osmode | S_IFDIR; | |
| 2175 case 0020000: | |
| 2176 return osmode | S_IFCHR; | |
| 2177 case 0010000: | |
| 2178 return osmode | S_IFIFO; | |
| 2179 case 0004000: | |
| 2180 return osmode | S_ISUID; | |
| 2181 case 0002000: | |
| 2182 return osmode | S_ISGID; | |
| 2183 #ifdef S_ISVTX | |
| 2184 case 0001000: | |
| 2185 return osmode | S_ISVTX; | |
| 2186 #endif | |
| 2187 } | |
| 2188 printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode); | |
| 2189 BUG(); | |
| 2190 return 0; | |
| 570 | 2191 } |
