Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/fatfs/fatfs_node.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fat_read_dirent
  2. fat_write_dirent
  3. fat_lookup_dirent
  4. fatfs_lookup_node
  5. fat_get_dirent
  6. fatfs_get_node
  7. fat_add_dirent
  8. fatfs_add_node
  9. fatfs_put_node

   1 /*
   2  * Copyright (c) 2005-2008, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 #include <sys/prex.h>
  31 #include <sys/buf.h>
  32 
  33 #include <ctype.h>
  34 #include <string.h>
  35 #include <unistd.h>
  36 #include <errno.h>
  37 #include <stdlib.h>
  38 
  39 #include "fatfs.h"
  40 
  41 /*
  42  * Read directory entry to buffer, with cache.
  43  */
  44 static int
  45 fat_read_dirent(struct fatfsmount *fmp, u_long sec)
  46 {
  47         struct buf *bp;
  48         int error;
  49 
  50         if ((error = bread(fmp->dev, sec, &bp)) != 0)
  51                 return error;
  52         memcpy(fmp->dir_buf, bp->b_data, SEC_SIZE);
  53         brelse(bp);
  54         return 0;
  55 }
  56 
  57 /*
  58  * Write directory entry from buffer.
  59  */
  60 static int
  61 fat_write_dirent(struct fatfsmount *fmp, u_long sec)
  62 {
  63         struct buf *bp;
  64 
  65         bp = getblk(fmp->dev, sec);
  66         memcpy(bp->b_data, fmp->dir_buf, SEC_SIZE);
  67         return bwrite(bp);
  68 }
  69 
  70 /*
  71  * Find directory entry in specified sector.
  72  * The fat vnode data is filled if success.
  73  *
  74  * @fmp: fatfs mount point
  75  * @sec: sector#
  76  * @name: file name
  77  * @node: pointer to fat node
  78  */
  79 static int
  80 fat_lookup_dirent(struct fatfsmount *fmp, u_long sec, char *name,
  81                   struct fatfs_node *np)
  82 {
  83         struct fat_dirent *de;
  84         int error, i;
  85 
  86         error = fat_read_dirent(fmp, sec);
  87         if (error)
  88                 return error;
  89 
  90         de = (struct fat_dirent *)fmp->dir_buf;
  91 
  92         for (i = 0; i < DIR_PER_SEC; i++) {
  93                 /* Find specific file or directory name */
  94                 if (IS_EMPTY(de))
  95                         return ENOENT;
  96                 if (!IS_VOL(de) &&
  97                     !fat_compare_name((char *)de->name, name)) {
  98                         /* Found. Fill the fat vnode data. */
  99                         *(&np->dirent) = *de;
 100                         np->sector = sec;
 101                         np->offset = sizeof(struct fat_dirent) * i;
 102                         DPRINTF(("fat_lookup_dirent: found sec=%d\n", sec));
 103                         return 0;
 104                 }
 105                 if (!IS_DELETED(de))
 106                         DPRINTF(("fat_lookup_dirent: %s\n", de->name));
 107                 de++;
 108         }
 109         return EAGAIN;
 110 }
 111 
 112 /*
 113  * Find directory entry for specified name in directory.
 114  * The fat vnode data is filled if success.
 115  *
 116  * @dvp: vnode for directory.
 117  * @name: file name
 118  * @np: pointer to fat node
 119  */
 120 int
 121 fatfs_lookup_node(vnode_t dvp, char *name, struct fatfs_node *np)
 122 {
 123         struct fatfsmount *fmp;
 124         char fat_name[12];
 125         u_long cl, sec;
 126         int i, error;
 127 
 128         if (name == NULL)
 129                 return ENOENT;
 130 
 131         DPRINTF(("fat_lookup_denode: cl=%d name=%s\n", dvp->v_blkno, name));
 132 
 133         fat_convert_name(name, fat_name);
 134         *(fat_name + 11) = '\0';
 135 
 136         fmp = (struct fatfsmount *)dvp->v_mount->m_data;
 137         cl = dvp->v_blkno;
 138         if (cl == CL_ROOT) {
 139                 /* Search entry in root directory */
 140                 for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
 141                         error = fat_lookup_dirent(fmp, sec, fat_name, np);
 142                         if (error != EAGAIN)
 143                                 return error;
 144                 }
 145         } else {
 146                 /* Search entry in sub directory */
 147                 while (!IS_EOFCL(fmp, cl)) {
 148                         sec = cl_to_sec(fmp, cl);
 149                         for (i = 0; i < fmp->sec_per_cl; i++) {
 150                                 error = fat_lookup_dirent(fmp, sec, fat_name,
 151                                                    np);
 152                                 if (error != EAGAIN)
 153                                         return error;
 154                                 sec++;
 155                         }
 156                         error = fat_next_cluster(fmp, cl, &cl);
 157                         if (error)
 158                                 return error;
 159                 }
 160         }
 161         return ENOENT;
 162 }
 163 
 164 /*
 165  * Get directory entry for specified index in sector.
 166  * The directory entry is filled if success.
 167  *
 168  * @fmp: fatfs mount point
 169  * @sec: sector#
 170  * @target: target index
 171  * @index: current index
 172  * @np: pointer to fat node
 173  */
 174 static int
 175 fat_get_dirent(struct fatfsmount *fmp, u_long sec, int target, int *index,
 176                struct fatfs_node *np)
 177 {
 178         struct fat_dirent *de;
 179         int error, i;
 180 
 181         error = fat_read_dirent(fmp, sec);
 182         if (error)
 183                 return error;
 184 
 185         de = (struct fat_dirent *)fmp->dir_buf;
 186         for (i = 0; i < DIR_PER_SEC; i++) {
 187                 if (IS_EMPTY(de))
 188                         return ENOENT;
 189                 if (!IS_DELETED(de) && !IS_VOL(de)) {
 190                         /* valid file */
 191                         if (*index == target) {
 192                                 *(&np->dirent) = *de;
 193                                 np->sector = sec;
 194                                 np->offset = sizeof(struct fat_dirent) * i;
 195                                 DPRINTF(("fat_get_dirent: found index=%d\n", *index));
 196                                 return 0;
 197                         }
 198                         (*index)++;
 199                 }
 200                 DPRINTF(("fat_get_dirent: %s\n", de->name));
 201                 de++;
 202         }
 203         return EAGAIN;
 204 }
 205 
 206 /*
 207  * Get directory entry for specified index.
 208  *
 209  * @dvp: vnode for directory.
 210  * @index: index of the entry
 211  * @np: pointer to fat node
 212  */
 213 int
 214 fatfs_get_node(vnode_t dvp, int index, struct fatfs_node *np)
 215 {
 216         struct fatfsmount *fmp;
 217         u_long cl, sec;
 218         int i, cur_index, error;
 219 
 220         fmp = (struct fatfsmount *)dvp->v_mount->m_data;
 221         cl = dvp->v_blkno;
 222         cur_index = 0;
 223 
 224         DPRINTF(("fatfs_get_node: index=%d\n", index));
 225 
 226         if (cl == CL_ROOT) {
 227                 /* Get entry from the root directory */
 228                 for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
 229                         error = fat_get_dirent(fmp, sec, index, &cur_index, np);
 230                         if (error != EAGAIN)
 231                                 return error;
 232                 }
 233         } else {
 234                 /* Get entry from the sub directory */
 235                 while (!IS_EOFCL(fmp, cl)) {
 236                         sec = cl_to_sec(fmp, cl);
 237                         for (i = 0; i < fmp->sec_per_cl; i++) {
 238                                 error = fat_get_dirent(fmp, sec, index,
 239                                                      &cur_index, np);
 240                                 if (error != EAGAIN)
 241                                         return error;
 242                                 sec++;
 243                         }
 244                         error = fat_next_cluster(fmp, cl, &cl);
 245                         if (error)
 246                                 return error;
 247                 }
 248         }
 249         return ENOENT;
 250 }
 251 
 252 /*
 253  * Find empty directory entry and put new entry on it.
 254  *
 255  * @fmp: fatfs mount point
 256  * @sec: sector#
 257  * @np: pointer to fat node
 258  */
 259 static int
 260 fat_add_dirent(struct fatfsmount *fmp, u_long sec, struct fatfs_node *np)
 261 {
 262         struct fat_dirent *de;
 263         int error, i;
 264 
 265         error = fat_read_dirent(fmp, sec);
 266         if (error)
 267                 return error;
 268 
 269         de = (struct fat_dirent *)fmp->dir_buf;
 270         for (i = 0; i < DIR_PER_SEC; i++) {
 271                 if (IS_DELETED(de) || IS_EMPTY(de))
 272                         goto found;
 273                 DPRINTF(("fat_add_dirent: scan %s\n", de->name));
 274                 de++;
 275         }
 276         return ENOENT;
 277 
 278  found:
 279         DPRINTF(("fat_add_dirent: found. sec=%d\n", sec));
 280         memcpy(de, &np->dirent, sizeof(struct fat_dirent));
 281         error = fat_write_dirent(fmp, sec);
 282         return error;
 283 }
 284 
 285 /*
 286  * Find empty directory entry and put new entry on it.
 287  * This search is done only in directory of specified cluster.
 288  * @dvp: vnode for directory.
 289  * @np: pointer to fat node
 290  */
 291 int
 292 fatfs_add_node(vnode_t dvp, struct fatfs_node *np)
 293 {
 294         struct fatfsmount *fmp;
 295         u_long cl, sec;
 296         int i, error;
 297         u_long next;
 298 
 299         fmp = (struct fatfsmount *)dvp->v_mount->m_data;
 300         cl = dvp->v_blkno;
 301 
 302         DPRINTF(("fatfs_add_node: cl=%d\n", cl));
 303 
 304         if (cl == CL_ROOT) {
 305                 /* Add entry in root directory */
 306                 for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
 307                         error = fat_add_dirent(fmp, sec, np);
 308                         if (error != ENOENT)
 309                                 return error;
 310                 }
 311         } else {
 312                 /* Search entry in sub directory */
 313                 while (!IS_EOFCL(fmp, cl)) {
 314                         sec = cl_to_sec(fmp, cl);
 315                         for (i = 0; i < fmp->sec_per_cl; i++) {
 316                                 error = fat_add_dirent(fmp, sec, np);
 317                                 if (error != ENOENT)
 318                                         return error;
 319                                 sec++;
 320                         }
 321                         error = fat_next_cluster(fmp, cl, &next);
 322                         if (error)
 323                                 return error;
 324                         cl = next;
 325                 }
 326                 /* No entry found, add one more free cluster for directory */
 327                 DPRINTF(("fatfs_add_node: expand dir\n"));
 328                 error = fat_expand_dir(fmp, cl, &next);
 329                 if (error)
 330                         return error;
 331 
 332                 /* Initialize free cluster. */
 333                 memset(fmp->dir_buf, 0, SEC_SIZE);
 334                 sec = cl_to_sec(fmp, next);
 335                 for (i = 0; i < fmp->sec_per_cl; i++) {
 336                         error = fat_write_dirent(fmp, sec);
 337                         if (error)
 338                                 return error;
 339                         sec++;
 340                 }
 341                 /* Try again */
 342                 sec = cl_to_sec(fmp, next);
 343                 error = fat_add_dirent(fmp, sec, np);
 344                 return error;
 345         }
 346         return ENOENT;
 347 }
 348 
 349 /*
 350  * Put directory entry.
 351  * @fmp: fat mount data
 352  * @np: pointer to fat node
 353  */
 354 int
 355 fatfs_put_node(struct fatfsmount *fmp, struct fatfs_node *np)
 356 {
 357         int error;
 358 
 359         error = fat_read_dirent(fmp, np->sector);
 360         if (error)
 361                 return error;
 362 
 363         memcpy(fmp->dir_buf + np->offset, &np->dirent,
 364                sizeof(struct fat_dirent));
 365 
 366         error = fat_write_dirent(fmp, np->sector);
 367         return error;
 368 }
 369 

/* [<][>][^][v][top][bottom][index][help] */