3 * POSIX user space host environment code.
7 * Copyright (c) 2006 Christoph Pfisterer
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
21 * * Neither the name of Christoph Pfisterer nor the names of the
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "fsw_posix.h"
42 /** The file system type name to use. */
47 // function prototypes
49 fsw_status_t
fsw_posix_open_dno(struct fsw_posix_volume
*pvol
, const char *path
, int required_type
,
50 struct fsw_shandle
*shand
);
52 void fsw_posix_change_blocksize(struct fsw_volume
*vol
,
53 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
54 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
);
55 fsw_status_t
fsw_posix_read_block(struct fsw_volume
*vol
, fsw_u32 phys_bno
, void *buffer
);
58 * Dispatch table for our FSW host driver.
61 struct fsw_host_table fsw_posix_host_table
= {
62 FSW_STRING_TYPE_ISO88591
,
64 fsw_posix_change_blocksize
,
68 extern struct fsw_fstype_table
FSW_FSTYPE_TABLE_NAME(FSTYPE
);
75 struct fsw_posix_volume
* fsw_posix_mount(const char *path
, struct fsw_fstype_table
*fstype_table
)
78 struct fsw_posix_volume
*pvol
;
80 // allocate volume structure
81 status
= fsw_alloc_zero(sizeof(struct fsw_posix_volume
), (void **)&pvol
);
86 // open underlying file/device
87 pvol
->fd
= open(path
, O_RDONLY
, 0);
89 fprintf(stderr
, "fsw_posix_mount: %s: %s\n", path
, strerror(errno
));
94 // mount the filesystem
95 if (fstype_table
== NULL
)
96 fstype_table
= &FSW_FSTYPE_TABLE_NAME(FSTYPE
);
97 status
= fsw_mount(pvol
, &fsw_posix_host_table
, fstype_table
, &pvol
->vol
);
99 fprintf(stderr
, "fsw_posix_mount: fsw_mount returned %d\n", status
);
111 int fsw_posix_unmount(struct fsw_posix_volume
*pvol
)
113 if (pvol
->vol
!= NULL
)
114 fsw_unmount(pvol
->vol
);
120 * Open a named regular file.
123 struct fsw_posix_file
* fsw_posix_open(struct fsw_posix_volume
*pvol
, const char *path
, int flags
, mode_t mode
)
126 struct fsw_posix_file
*file
;
128 // TODO: check flags for unwanted values
130 // allocate file structure
131 status
= fsw_alloc(sizeof(struct fsw_posix_file
), &file
);
137 status
= fsw_posix_open_dno(pvol
, path
, FSW_DNODE_TYPE_FILE
, &file
->shand
);
139 fprintf(stderr
, "fsw_posix_open: open_dno returned %d\n", status
);
148 * Read data from a regular file.
151 ssize_t
fsw_posix_read(struct fsw_posix_file
*file
, void *buf
, size_t nbytes
)
156 buffer_size
= nbytes
;
157 status
= fsw_shandle_read(&file
->shand
, &buffer_size
, buf
);
164 * Change position within a regular file.
167 off_t
fsw_posix_lseek(struct fsw_posix_file
*file
, off_t offset
, int whence
)
169 fsw_u64 base_offset
= 0;
173 if (whence
== SEEK_CUR
)
174 base_offset
= file
->shand
.pos
;
175 else if (whence
== SEEK_END
)
176 base_offset
= file
->shand
.dnode
->size
;
178 // calculate new offset, prevent seeks before the start of the file
179 if (offset
< 0 && -offset
> base_offset
)
182 file
->shand
.pos
= base_offset
+ offset
;
184 return file
->shand
.pos
;
188 * Close a regular file.
191 int fsw_posix_close(struct fsw_posix_file
*file
)
193 fsw_shandle_close(&file
->shand
);
199 * Open a directory for iteration.
202 struct fsw_posix_dir
* fsw_posix_opendir(struct fsw_posix_volume
*pvol
, const char *path
)
205 struct fsw_posix_dir
*dir
;
207 // allocate file structure
208 status
= fsw_alloc(sizeof(struct fsw_posix_dir
), &dir
);
213 // open the directory
214 status
= fsw_posix_open_dno(pvol
, path
, FSW_DNODE_TYPE_DIR
, &dir
->shand
);
216 fprintf(stderr
, "fsw_posix_opendir: open_dno returned %d\n", status
);
225 * Read the next entry from a directory.
228 struct dirent
* fsw_posix_readdir(struct fsw_posix_dir
*dir
)
231 struct fsw_dnode
*dno
;
232 static struct dirent dent
;
234 // get next entry from file system
235 status
= fsw_dnode_dir_read(&dir
->shand
, &dno
);
238 fprintf(stderr
, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status
);
241 status
= fsw_dnode_fill(dno
);
243 fprintf(stderr
, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status
);
244 fsw_dnode_release(dno
);
248 // fill dirent structure
249 dent
.d_fileno
= dno
->dnode_id
;
250 dent
.d_reclen
= 8 + dno
->name
.size
+ 1;
252 case FSW_DNODE_TYPE_FILE
:
253 dent
.d_type
= DT_REG
;
255 case FSW_DNODE_TYPE_DIR
:
256 dent
.d_type
= DT_DIR
;
258 case FSW_DNODE_TYPE_SYMLINK
:
259 dent
.d_type
= DT_LNK
;
262 dent
.d_type
= DT_UNKNOWN
;
266 dent
.d_namlen
= dno
->name
.size
;
268 memcpy(dent
.d_name
, dno
->name
.data
, dno
->name
.size
);
269 dent
.d_name
[dno
->name
.size
] = 0;
275 * Rewind a directory to the start.
278 void fsw_posix_rewinddir(struct fsw_posix_dir
*dir
)
287 int fsw_posix_closedir(struct fsw_posix_dir
*dir
)
289 fsw_shandle_close(&dir
->shand
);
295 * Open a shand of a required type by path.
298 fsw_status_t
fsw_posix_open_dno(struct fsw_posix_volume
*pvol
, const char *path
, int required_type
, struct fsw_shandle
*shand
)
301 struct fsw_dnode
*dno
;
302 struct fsw_dnode
*target_dno
;
303 struct fsw_string lookup_path
;
305 lookup_path
.type
= FSW_STRING_TYPE_ISO88591
;
306 lookup_path
.len
= strlen(path
);
307 lookup_path
.size
= lookup_path
.len
;
308 lookup_path
.data
= (void *)path
;
310 // resolve the path (symlinks along the way are automatically resolved)
311 status
= fsw_dnode_lookup_path(pvol
->vol
->root
, &lookup_path
, '/', &dno
);
313 fprintf(stderr
, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status
);
317 // if the final node is a symlink, also resolve it
318 status
= fsw_dnode_resolve(dno
, &target_dno
);
319 fsw_dnode_release(dno
);
321 fprintf(stderr
, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status
);
326 // check that it is a regular file
327 status
= fsw_dnode_fill(dno
);
329 fprintf(stderr
, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status
);
330 fsw_dnode_release(dno
);
333 if (dno
->type
!= required_type
) {
334 fprintf(stderr
, "fsw_posix_open_dno: dnode is not of the requested type\n");
335 fsw_dnode_release(dno
);
336 return FSW_UNSUPPORTED
;
340 status
= fsw_shandle_open(dno
, shand
);
342 fprintf(stderr
, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status
);
344 fsw_dnode_release(dno
);
349 * FSW interface function for block size changes. This function is called by the FSW core
350 * when the file system driver changes the block sizes for the volume.
353 void fsw_posix_change_blocksize(struct fsw_volume
*vol
,
354 fsw_u32 old_phys_blocksize
, fsw_u32 old_log_blocksize
,
355 fsw_u32 new_phys_blocksize
, fsw_u32 new_log_blocksize
)
361 * FSW interface function to read data blocks. This function is called by the FSW core
362 * to read a block of data from the device. The buffer is allocated by the core code.
365 fsw_status_t
fsw_posix_read_block(struct fsw_volume
*vol
, fsw_u32 phys_bno
, void *buffer
)
367 struct fsw_posix_volume
*pvol
= (struct fsw_posix_volume
*)vol
->host_data
;
368 off_t block_offset
, seek_result
;
371 FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno
, vol
->phys_blocksize
));
374 block_offset
= (off_t
)phys_bno
* vol
->phys_blocksize
;
375 seek_result
= lseek(pvol
->fd
, block_offset
, SEEK_SET
);
376 if (seek_result
!= block_offset
)
378 read_result
= read(pvol
->fd
, buffer
, vol
->phys_blocksize
);
379 if (read_result
!= vol
->phys_blocksize
)
387 * Time mapping callback for the fsw_dnode_stat call. This function converts
388 * a Posix style timestamp into an EFI_TIME structure and writes it to the
389 * appropriate member of the EFI_FILE_INFO structure that we're filling.
393 static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
395 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
397 if (which == FSW_DNODE_STAT_CTIME)
398 fsw_posix_decode_time(&FileInfo->CreateTime, posix_time);
399 else if (which == FSW_DNODE_STAT_MTIME)
400 fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
401 else if (which == FSW_DNODE_STAT_ATIME)
402 fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time);
407 * Mode mapping callback for the fsw_dnode_stat call. This function looks at
408 * the Posix mode passed by the file system driver and makes appropriate
409 * adjustments to the EFI_FILE_INFO structure that we're filling.
413 static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
415 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
417 if ((posix_mode & S_IWUSR) == 0)
418 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
423 * Common function to fill an EFI_FILE_INFO with information about a dnode.
427 EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
428 IN struct fsw_dnode *dno,
429 IN OUT UINTN *BufferSize,
433 EFI_FILE_INFO *FileInfo;
435 struct fsw_dnode_stat sb;
437 // make sure the dnode has complete info
438 Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
439 if (EFI_ERROR(Status))
442 // TODO: check/assert that the dno's name is in UTF16
445 RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
446 if (*BufferSize < RequiredSize) {
447 // TODO: wind back the directory in this case
449 *BufferSize = RequiredSize;
450 return EFI_BUFFER_TOO_SMALL;
454 ZeroMem(Buffer, RequiredSize);
455 FileInfo = (EFI_FILE_INFO *)Buffer;
456 FileInfo->Size = RequiredSize;
457 FileInfo->FileSize = dno->size;
458 FileInfo->Attribute = 0;
459 if (dno->type == FSW_DNODE_TYPE_DIR)
460 FileInfo->Attribute |= EFI_FILE_DIRECTORY;
461 fsw_posix_strcpy(FileInfo->FileName, &dno->name);
463 // get the missing info from the fs driver
464 ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
465 sb.store_time_posix = fsw_posix_store_time_posix;
466 sb.store_attr_posix = fsw_posix_store_attr_posix;
467 sb.host_data = FileInfo;
468 Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
469 if (EFI_ERROR(Status))
471 FileInfo->PhysicalSize = sb.used_bytes;
473 // prepare for return
474 *BufferSize = RequiredSize;