Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / fs / ufs.c
blob0619d6e324d682596a9ab8476513c91d93cde216
1 /* ufs.c - Unix File System */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2004,2005,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/err.h>
21 #include <grub/file.h>
22 #include <grub/mm.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
25 #include <grub/dl.h>
26 #include <grub/types.h>
27 #include <grub/i18n.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 #ifdef MODE_UFS2
32 #define GRUB_UFS_MAGIC 0x19540119
33 #else
34 #define GRUB_UFS_MAGIC 0x11954
35 #endif
37 #define GRUB_UFS_INODE 2
38 #define GRUB_UFS_FILETYPE_DIR 4
39 #define GRUB_UFS_FILETYPE_LNK 10
40 #define GRUB_UFS_MAX_SYMLNK_CNT 8
42 #define GRUB_UFS_DIRBLKS 12
43 #define GRUB_UFS_INDIRBLKS 3
45 #define GRUB_UFS_ATTR_TYPE 0160000
46 #define GRUB_UFS_ATTR_FILE 0100000
47 #define GRUB_UFS_ATTR_DIR 0040000
48 #define GRUB_UFS_ATTR_LNK 0120000
50 #define GRUB_UFS_VOLNAME_LEN 32
52 #ifdef MODE_BIGENDIAN
53 #define grub_ufs_to_cpu16 grub_be_to_cpu16
54 #define grub_ufs_to_cpu32 grub_be_to_cpu32
55 #define grub_ufs_to_cpu64 grub_be_to_cpu64
56 #define grub_cpu_to_ufs32_compile_time grub_cpu_to_be32_compile_time
57 #else
58 #define grub_ufs_to_cpu16 grub_le_to_cpu16
59 #define grub_ufs_to_cpu32 grub_le_to_cpu32
60 #define grub_ufs_to_cpu64 grub_le_to_cpu64
61 #define grub_cpu_to_ufs32_compile_time grub_cpu_to_le32_compile_time
62 #endif
64 #ifdef MODE_UFS2
65 typedef grub_uint64_t grub_ufs_blk_t;
66 static inline grub_disk_addr_t
67 grub_ufs_to_cpu_blk (grub_ufs_blk_t blk)
69 return grub_ufs_to_cpu64 (blk);
71 #else
72 typedef grub_uint32_t grub_ufs_blk_t;
73 static inline grub_disk_addr_t
74 grub_ufs_to_cpu_blk (grub_ufs_blk_t blk)
76 return grub_ufs_to_cpu32 (blk);
78 #endif
80 /* Calculate in which group the inode can be found. */
81 #define UFS_BLKSZ(sblock) (grub_ufs_to_cpu32 (sblock->bsize))
82 #define UFS_LOG_BLKSZ(sblock) (data->log2_blksz)
84 #ifdef MODE_UFS2
85 #define INODE_ENDIAN(data,field,bits1,bits2) grub_ufs_to_cpu##bits2 (data->inode.field)
86 #else
87 #define INODE_ENDIAN(data,field,bits1,bits2) grub_ufs_to_cpu##bits1 (data->inode.field)
88 #endif
90 #define INODE_SIZE(data) grub_ufs_to_cpu64 (data->inode.size)
91 #define INODE_MODE(data) grub_ufs_to_cpu16 (data->inode.mode)
92 #ifdef MODE_UFS2
93 #define LOG_INODE_BLKSZ 3
94 #else
95 #define LOG_INODE_BLKSZ 2
96 #endif
97 #ifdef MODE_UFS2
98 #define UFS_INODE_PER_BLOCK 2
99 #else
100 #define UFS_INODE_PER_BLOCK 4
101 #endif
102 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
103 (data,blocks.dir_blocks[blk],32,64)
104 #define INODE_INDIRBLOCKS(data,blk) INODE_ENDIAN \
105 (data,blocks.indir_blocks[blk],32,64)
107 /* The blocks on which the superblock can be found. */
108 static int sblocklist[] = { 128, 16, 0, 512, -1 };
110 struct grub_ufs_sblock
112 grub_uint8_t unused[16];
113 /* The offset of the inodes in the cylinder group. */
114 grub_uint32_t inoblk_offs;
116 grub_uint8_t unused2[4];
118 /* The start of the cylinder group. */
119 grub_uint32_t cylg_offset;
120 grub_uint32_t cylg_mask;
122 grub_uint32_t mtime;
123 grub_uint8_t unused4[12];
125 /* The size of a block in bytes. */
126 grub_int32_t bsize;
127 grub_uint8_t unused5[48];
129 /* The size of filesystem blocks to disk blocks. */
130 grub_uint32_t log2_blksz;
131 grub_uint8_t unused6[40];
132 grub_uint32_t uuidhi;
133 grub_uint32_t uuidlow;
134 grub_uint8_t unused7[32];
136 /* Inodes stored per cylinder group. */
137 grub_uint32_t ino_per_group;
139 /* The frags per cylinder group. */
140 grub_uint32_t frags_per_group;
142 grub_uint8_t unused8[488];
144 /* Volume name for UFS2. */
145 grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
146 grub_uint8_t unused9[360];
148 grub_uint64_t mtime2;
149 grub_uint8_t unused10[292];
151 /* Magic value to check if this is really a UFS filesystem. */
152 grub_uint32_t magic;
155 #ifdef MODE_UFS2
156 /* UFS inode. */
157 struct grub_ufs_inode
159 grub_uint16_t mode;
160 grub_uint16_t nlinks;
161 grub_uint32_t uid;
162 grub_uint32_t gid;
163 grub_uint32_t blocksize;
164 grub_uint64_t size;
165 grub_int64_t nblocks;
166 grub_uint64_t atime;
167 grub_uint64_t mtime;
168 grub_uint64_t ctime;
169 grub_uint64_t create_time;
170 grub_uint32_t atime_usec;
171 grub_uint32_t mtime_usec;
172 grub_uint32_t ctime_usec;
173 grub_uint32_t create_time_sec;
174 grub_uint32_t gen;
175 grub_uint32_t kernel_flags;
176 grub_uint32_t flags;
177 grub_uint32_t extsz;
178 grub_uint64_t ext[2];
179 union
181 struct
183 grub_uint64_t dir_blocks[GRUB_UFS_DIRBLKS];
184 grub_uint64_t indir_blocks[GRUB_UFS_INDIRBLKS];
185 } blocks;
186 grub_uint8_t symlink[(GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS) * 8];
189 grub_uint8_t unused[24];
190 } GRUB_PACKED;
191 #else
192 /* UFS inode. */
193 struct grub_ufs_inode
195 grub_uint16_t mode;
196 grub_uint16_t nlinks;
197 grub_uint16_t uid;
198 grub_uint16_t gid;
199 grub_uint64_t size;
200 grub_uint32_t atime;
201 grub_uint32_t atime_usec;
202 grub_uint32_t mtime;
203 grub_uint32_t mtime_usec;
204 grub_uint32_t ctime;
205 grub_uint32_t ctime_usec;
206 union
208 struct
210 grub_uint32_t dir_blocks[GRUB_UFS_DIRBLKS];
211 grub_uint32_t indir_blocks[GRUB_UFS_INDIRBLKS];
212 } blocks;
213 grub_uint8_t symlink[(GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS) * 4];
215 grub_uint32_t flags;
216 grub_uint32_t nblocks;
217 grub_uint32_t gen;
218 grub_uint32_t unused;
219 grub_uint8_t pad[12];
220 } GRUB_PACKED;
221 #endif
223 /* Directory entry. */
224 struct grub_ufs_dirent
226 grub_uint32_t ino;
227 grub_uint16_t direntlen;
228 union
230 grub_uint16_t namelen;
231 struct
233 grub_uint8_t filetype_bsd;
234 grub_uint8_t namelen_bsd;
237 } GRUB_PACKED;
239 /* Information about a "mounted" ufs filesystem. */
240 struct grub_ufs_data
242 struct grub_ufs_sblock sblock;
243 grub_disk_t disk;
244 struct grub_ufs_inode inode;
245 int ino;
246 int linknest;
247 int log2_blksz;
250 static grub_dl_t my_mod;
252 /* Forward declaration. */
253 static grub_err_t grub_ufs_find_file (struct grub_ufs_data *data,
254 const char *path);
257 static grub_disk_addr_t
258 grub_ufs_get_file_block (struct grub_ufs_data *data, grub_disk_addr_t blk)
260 unsigned long indirsz;
261 int log2_blksz, log_indirsz;
263 /* Direct. */
264 if (blk < GRUB_UFS_DIRBLKS)
265 return INODE_DIRBLOCKS (data, blk);
267 log2_blksz = grub_ufs_to_cpu32 (data->sblock.log2_blksz);
269 blk -= GRUB_UFS_DIRBLKS;
271 log_indirsz = data->log2_blksz - LOG_INODE_BLKSZ;
272 indirsz = 1 << log_indirsz;
274 /* Single indirect block. */
275 if (blk < indirsz)
277 grub_ufs_blk_t indir;
278 grub_disk_read (data->disk,
279 ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 0))
280 << log2_blksz,
281 blk * sizeof (indir), sizeof (indir), &indir);
282 return indir;
284 blk -= indirsz;
286 /* Double indirect block. */
287 if (blk < (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz)
289 grub_ufs_blk_t indir;
291 grub_disk_read (data->disk,
292 ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 1))
293 << log2_blksz,
294 (blk >> log_indirsz) * sizeof (indir),
295 sizeof (indir), &indir);
296 grub_disk_read (data->disk,
297 grub_ufs_to_cpu_blk (indir) << log2_blksz,
298 (blk & ((1 << log_indirsz) - 1)) * sizeof (indir),
299 sizeof (indir), &indir);
301 return indir;
304 blk -= (grub_disk_addr_t) indirsz * (grub_disk_addr_t) indirsz;
306 /* Triple indirect block. */
307 if (!(blk >> (3 * log_indirsz)))
309 grub_ufs_blk_t indir;
311 grub_disk_read (data->disk,
312 ((grub_disk_addr_t) INODE_INDIRBLOCKS (data, 2))
313 << log2_blksz,
314 (blk >> (2 * log_indirsz)) * sizeof (indir),
315 sizeof (indir), &indir);
316 grub_disk_read (data->disk,
317 grub_ufs_to_cpu_blk (indir) << log2_blksz,
318 ((blk >> log_indirsz)
319 & ((1 << log_indirsz) - 1)) * sizeof (indir),
320 sizeof (indir), &indir);
322 grub_disk_read (data->disk,
323 grub_ufs_to_cpu_blk (indir) << log2_blksz,
324 (blk & ((1 << log_indirsz) - 1)) * sizeof (indir),
325 sizeof (indir), &indir);
327 return indir;
330 grub_error (GRUB_ERR_BAD_FS,
331 "ufs does not support quadruple indirect blocks");
332 return 0;
336 /* Read LEN bytes from the file described by DATA starting with byte
337 POS. Return the amount of read bytes in READ. */
338 static grub_ssize_t
339 grub_ufs_read_file (struct grub_ufs_data *data,
340 grub_disk_read_hook_t read_hook, void *read_hook_data,
341 grub_off_t pos, grub_size_t len, char *buf)
343 struct grub_ufs_sblock *sblock = &data->sblock;
344 grub_off_t i;
345 grub_off_t blockcnt;
347 /* Adjust len so it we can't read past the end of the file. */
348 if (len + pos > INODE_SIZE (data))
349 len = INODE_SIZE (data) - pos;
351 blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) >> UFS_LOG_BLKSZ (sblock);
353 for (i = pos >> UFS_LOG_BLKSZ (sblock); i < blockcnt; i++)
355 grub_disk_addr_t blknr;
356 grub_off_t blockoff;
357 grub_off_t blockend = UFS_BLKSZ (sblock);
359 int skipfirst = 0;
361 blockoff = pos & (UFS_BLKSZ (sblock) - 1);
363 blknr = grub_ufs_get_file_block (data, i);
364 if (grub_errno)
365 return -1;
367 /* Last block. */
368 if (i == blockcnt - 1)
370 blockend = (len + pos) & (UFS_BLKSZ (sblock) - 1);
372 if (!blockend)
373 blockend = UFS_BLKSZ (sblock);
376 /* First block. */
377 if (i == (pos >> UFS_LOG_BLKSZ (sblock)))
379 skipfirst = blockoff;
380 blockend -= skipfirst;
383 /* XXX: If the block number is 0 this block is not stored on
384 disk but is zero filled instead. */
385 if (blknr)
387 data->disk->read_hook = read_hook;
388 data->disk->read_hook_data = read_hook_data;
389 grub_disk_read (data->disk,
390 blknr << grub_ufs_to_cpu32 (data->sblock.log2_blksz),
391 skipfirst, blockend, buf);
392 data->disk->read_hook = 0;
393 if (grub_errno)
394 return -1;
396 else
397 grub_memset (buf, UFS_BLKSZ (sblock) - skipfirst, 0);
399 buf += UFS_BLKSZ (sblock) - skipfirst;
402 return len;
405 /* Read inode INO from the mounted filesystem described by DATA. This
406 inode is used by default now. */
407 static grub_err_t
408 grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
410 struct grub_ufs_sblock *sblock = &data->sblock;
412 /* Determine the group the inode is in. */
413 int group = ino / grub_ufs_to_cpu32 (sblock->ino_per_group);
415 /* Determine the inode within the group. */
416 int grpino = ino % grub_ufs_to_cpu32 (sblock->ino_per_group);
418 /* The first block of the group. */
419 int grpblk = group * (grub_ufs_to_cpu32 (sblock->frags_per_group));
421 #ifndef MODE_UFS2
422 grpblk += grub_ufs_to_cpu32 (sblock->cylg_offset)
423 * (group & (~grub_ufs_to_cpu32 (sblock->cylg_mask)));
424 #endif
426 if (!inode)
428 inode = (char *) &data->inode;
429 data->ino = ino;
432 grub_disk_read (data->disk,
433 ((grub_ufs_to_cpu32 (sblock->inoblk_offs) + grpblk)
434 << grub_ufs_to_cpu32 (data->sblock.log2_blksz))
435 + grpino / UFS_INODE_PER_BLOCK,
436 (grpino % UFS_INODE_PER_BLOCK)
437 * sizeof (struct grub_ufs_inode),
438 sizeof (struct grub_ufs_inode),
439 inode);
441 return grub_errno;
445 /* Lookup the symlink the current inode points to. INO is the inode
446 number of the directory the symlink is relative to. */
447 static grub_err_t
448 grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
450 char *symlink;
451 grub_size_t sz = INODE_SIZE (data);
453 if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
454 return grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks"));
456 symlink = grub_malloc (sz + 1);
457 if (!symlink)
458 return grub_errno;
459 /* Normally we should just check that data->inode.nblocks == 0.
460 However old Linux doesn't maintain nblocks correctly and so it's always
461 0. If size is bigger than inline space then the symlink is surely not
462 inline. */
463 /* Check against zero is paylindromic, no need to swap. */
464 if (data->inode.nblocks == 0
465 && INODE_SIZE (data) <= sizeof (data->inode.symlink))
466 grub_strcpy (symlink, (char *) data->inode.symlink);
467 else
469 if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0)
471 grub_free(symlink);
472 return grub_errno;
475 symlink[sz] = '\0';
477 /* The symlink is an absolute path, go back to the root inode. */
478 if (symlink[0] == '/')
479 ino = GRUB_UFS_INODE;
481 /* Now load in the old inode. */
482 if (grub_ufs_read_inode (data, ino, 0))
484 grub_free (symlink);
485 return grub_errno;
488 grub_ufs_find_file (data, symlink);
490 grub_free (symlink);
492 return grub_errno;
496 /* Find the file with the pathname PATH on the filesystem described by
497 DATA. */
498 static grub_err_t
499 grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
501 const char *name;
502 const char *next = path;
503 unsigned int pos = 0;
504 int dirino;
505 char *filename;
507 /* We reject filenames longer than the one we're looking
508 for without reading, so this allocation is enough. */
509 filename = grub_malloc (grub_strlen (path) + 2);
510 if (!filename)
511 return grub_errno;
513 while (1)
515 struct grub_ufs_dirent dirent;
517 name = next;
518 /* Skip the first slash. */
519 while (*name == '/')
520 name++;
521 if (*name == 0)
523 grub_free (filename);
524 return GRUB_ERR_NONE;
527 if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
528 != GRUB_UFS_ATTR_DIR)
530 grub_error (GRUB_ERR_BAD_FILE_TYPE,
531 N_("not a directory"));
532 goto fail;
535 /* Extract the actual part from the pathname. */
536 for (next = name; *next && *next != '/'; next++);
537 for (pos = 0; ; pos += grub_ufs_to_cpu16 (dirent.direntlen))
539 int namelen;
541 if (pos >= INODE_SIZE (data))
543 grub_error (GRUB_ERR_FILE_NOT_FOUND,
544 N_("file `%s' not found"),
545 path);
546 goto fail;
549 if (grub_ufs_read_file (data, 0, 0, pos, sizeof (dirent),
550 (char *) &dirent) < 0)
551 goto fail;
553 #ifdef MODE_UFS2
554 namelen = dirent.namelen_bsd;
555 #else
556 namelen = grub_ufs_to_cpu16 (dirent.namelen);
557 #endif
558 if (namelen < next - name)
559 continue;
561 if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent),
562 next - name + (namelen != next - name),
563 filename) < 0)
564 goto fail;
566 if (grub_strncmp (name, filename, next - name) == 0
567 && (namelen == next - name || filename[next - name] == '\0'))
569 dirino = data->ino;
570 grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0);
572 if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
573 == GRUB_UFS_ATTR_LNK)
575 grub_ufs_lookup_symlink (data, dirino);
576 if (grub_errno)
577 goto fail;
580 break;
584 fail:
585 grub_free (filename);
586 return grub_errno;
590 /* Mount the filesystem on the disk DISK. */
591 static struct grub_ufs_data *
592 grub_ufs_mount (grub_disk_t disk)
594 struct grub_ufs_data *data;
595 int *sblklist = sblocklist;
597 data = grub_malloc (sizeof (struct grub_ufs_data));
598 if (!data)
599 return 0;
601 /* Find a UFS sblock. */
602 while (*sblklist != -1)
604 grub_disk_read (disk, *sblklist, 0, sizeof (struct grub_ufs_sblock),
605 &data->sblock);
606 if (grub_errno)
607 goto fail;
609 /* No need to byteswap bsize in this check. It works the same on both
610 endiannesses. */
611 if (data->sblock.magic == grub_cpu_to_ufs32_compile_time (GRUB_UFS_MAGIC)
612 && data->sblock.bsize != 0
613 && ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0)
614 && data->sblock.ino_per_group != 0)
616 for (data->log2_blksz = 0;
617 (1U << data->log2_blksz) < grub_ufs_to_cpu32 (data->sblock.bsize);
618 data->log2_blksz++);
620 data->disk = disk;
621 data->linknest = 0;
622 return data;
624 sblklist++;
627 fail:
629 if (grub_errno == GRUB_ERR_NONE || grub_errno == GRUB_ERR_OUT_OF_RANGE)
631 #ifdef MODE_UFS2
632 grub_error (GRUB_ERR_BAD_FS, "not an ufs2 filesystem");
633 #else
634 grub_error (GRUB_ERR_BAD_FS, "not an ufs1 filesystem");
635 #endif
638 grub_free (data);
640 return 0;
644 static grub_err_t
645 grub_ufs_dir (grub_device_t device, const char *path,
646 grub_fs_dir_hook_t hook, void *hook_data)
648 struct grub_ufs_data *data;
649 unsigned int pos = 0;
651 data = grub_ufs_mount (device->disk);
652 if (!data)
653 return grub_errno;
655 grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
656 if (grub_errno)
657 return grub_errno;
659 if (!path || path[0] != '/')
661 grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path);
662 return grub_errno;
665 grub_ufs_find_file (data, path);
666 if (grub_errno)
667 goto fail;
669 if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
671 grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
672 goto fail;
675 while (pos < INODE_SIZE (data))
677 struct grub_ufs_dirent dirent;
678 int namelen;
680 if (grub_ufs_read_file (data, 0, 0, pos, sizeof (dirent),
681 (char *) &dirent) < 0)
682 break;
684 if (dirent.direntlen == 0)
685 break;
687 #ifdef MODE_UFS2
688 namelen = dirent.namelen_bsd;
689 #else
690 namelen = grub_ufs_to_cpu16 (dirent.namelen);
691 #endif
693 char *filename = grub_malloc (namelen + 1);
694 if (!filename)
695 goto fail;
696 struct grub_dirhook_info info;
697 struct grub_ufs_inode inode;
699 grub_memset (&info, 0, sizeof (info));
701 if (grub_ufs_read_file (data, 0, 0, pos + sizeof (dirent),
702 namelen, filename) < 0)
704 grub_free (filename);
705 break;
708 filename[namelen] = '\0';
709 grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino),
710 (char *) &inode);
712 info.dir = ((grub_ufs_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
713 == GRUB_UFS_ATTR_DIR);
714 #ifdef MODE_UFS2
715 info.mtime = grub_ufs_to_cpu64 (inode.mtime);
716 #else
717 info.mtime = grub_ufs_to_cpu32 (inode.mtime);
718 #endif
719 info.mtimeset = 1;
721 if (hook (filename, &info, hook_data))
723 grub_free (filename);
724 break;
727 grub_free (filename);
729 pos += grub_ufs_to_cpu16 (dirent.direntlen);
732 fail:
733 grub_free (data);
735 return grub_errno;
739 /* Open a file named NAME and initialize FILE. */
740 static grub_err_t
741 grub_ufs_open (struct grub_file *file, const char *name)
743 struct grub_ufs_data *data;
744 data = grub_ufs_mount (file->device->disk);
745 if (!data)
746 return grub_errno;
748 grub_ufs_read_inode (data, 2, 0);
749 if (grub_errno)
751 grub_free (data);
752 return grub_errno;
755 if (!name || name[0] != '/')
757 grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), name);
758 return grub_errno;
761 grub_ufs_find_file (data, name);
762 if (grub_errno)
764 grub_free (data);
765 return grub_errno;
768 file->data = data;
769 file->size = INODE_SIZE (data);
771 return GRUB_ERR_NONE;
775 static grub_ssize_t
776 grub_ufs_read (grub_file_t file, char *buf, grub_size_t len)
778 struct grub_ufs_data *data =
779 (struct grub_ufs_data *) file->data;
781 return grub_ufs_read_file (data, file->read_hook, file->read_hook_data,
782 file->offset, len, buf);
786 static grub_err_t
787 grub_ufs_close (grub_file_t file)
789 grub_free (file->data);
791 return GRUB_ERR_NONE;
794 static grub_err_t
795 grub_ufs_label (grub_device_t device, char **label)
797 struct grub_ufs_data *data = 0;
799 grub_dl_ref (my_mod);
801 *label = 0;
803 data = grub_ufs_mount (device->disk);
804 if (data)
805 *label = grub_strdup ((char *) data->sblock.volume_name);
807 grub_dl_unref (my_mod);
809 grub_free (data);
811 return grub_errno;
814 static grub_err_t
815 grub_ufs_uuid (grub_device_t device, char **uuid)
817 struct grub_ufs_data *data;
818 grub_disk_t disk = device->disk;
820 grub_dl_ref (my_mod);
822 data = grub_ufs_mount (disk);
823 if (data && (data->sblock.uuidhi != 0 || data->sblock.uuidlow != 0))
824 *uuid = grub_xasprintf ("%08x%08x",
825 (unsigned) grub_ufs_to_cpu32 (data->sblock.uuidhi),
826 (unsigned) grub_ufs_to_cpu32 (data->sblock.uuidlow));
827 else
828 *uuid = NULL;
830 grub_dl_unref (my_mod);
832 grub_free (data);
834 return grub_errno;
838 /* Get mtime. */
839 static grub_err_t
840 grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
842 struct grub_ufs_data *data = 0;
844 grub_dl_ref (my_mod);
846 data = grub_ufs_mount (device->disk);
847 if (!data)
848 *tm = 0;
849 else
851 *tm = grub_ufs_to_cpu32 (data->sblock.mtime);
852 #ifdef MODE_UFS2
853 if (*tm < (grub_int64_t) grub_ufs_to_cpu64 (data->sblock.mtime2))
854 *tm = grub_ufs_to_cpu64 (data->sblock.mtime2);
855 #endif
858 grub_dl_unref (my_mod);
860 grub_free (data);
862 return grub_errno;
867 static struct grub_fs grub_ufs_fs =
869 #ifdef MODE_UFS2
870 .name = "ufs2",
871 #else
872 #ifdef MODE_BIGENDIAN
873 .name = "ufs1_be",
874 #else
875 .name = "ufs1",
876 #endif
877 #endif
878 .dir = grub_ufs_dir,
879 .open = grub_ufs_open,
880 .read = grub_ufs_read,
881 .close = grub_ufs_close,
882 .label = grub_ufs_label,
883 .uuid = grub_ufs_uuid,
884 .mtime = grub_ufs_mtime,
885 /* FIXME: set reserved_first_sector. */
886 #ifdef GRUB_UTIL
887 .blocklist_install = 1,
888 #endif
889 .next = 0
892 #ifdef MODE_UFS2
893 GRUB_MOD_INIT(ufs2)
894 #else
895 #ifdef MODE_BIGENDIAN
896 GRUB_MOD_INIT(ufs1_be)
897 #else
898 GRUB_MOD_INIT(ufs1)
899 #endif
900 #endif
902 grub_fs_register (&grub_ufs_fs);
903 my_mod = mod;
906 #ifdef MODE_UFS2
907 GRUB_MOD_FINI(ufs2)
908 #else
909 #ifdef MODE_BIGENDIAN
910 GRUB_MOD_FINI(ufs1_be)
911 #else
912 GRUB_MOD_FINI(ufs1)
913 #endif
914 #endif
916 grub_fs_unregister (&grub_ufs_fs);