2 #include <inc/string.h>
7 static int file_close(struct Fd
*fd
);
8 static ssize_t
file_read(struct Fd
*fd
, void *buf
, size_t n
, off_t offset
);
9 static ssize_t
file_write(struct Fd
*fd
, const void *buf
, size_t n
, off_t offset
);
10 static int file_stat(struct Fd
*fd
, struct Stat
*stat
);
11 static int file_trunc(struct Fd
*fd
, off_t newsize
);
17 .dev_read
= file_read
,
18 .dev_write
= file_write
,
19 .dev_close
= file_close
,
20 .dev_stat
= file_stat
,
21 .dev_trunc
= file_trunc
24 // Helper functions for file access
25 static int fmap(struct Fd
*fd
, off_t oldsize
, off_t newsize
);
26 static int funmap(struct Fd
*fd
, off_t oldsize
, off_t newsize
, bool dirty
);
28 // Open a file (or directory),
29 // returning the file descriptor index on success, < 0 on failure.
31 open(const char *path
, int mode
)
33 // Find an unused file descriptor page using fd_alloc.
34 // Then send a message to the file server to open a file
35 // using a function in fsipc.c.
36 // (fd_alloc does not allocate a page, it just returns an
37 // unused fd address. Do you need to allocate a page? Look
38 // at fsipc.c if you aren't sure.)
39 // Then map the file data (you may find fmap() helpful).
40 // Return the file descriptor index.
41 // If any step fails, use fd_close to free the file descriptor.
45 if ((r
= fd_alloc(&fd
)) < 0)
47 if ((r
= fsipc_open(path
, mode
, fd
)) < 0) {
51 if ((r
= fmap(fd
, 0, fd
->fd_file
.file
.f_size
)) < 0) {
58 // Clean up a file-server file descriptor.
59 // This function is called by fd_close.
61 file_close(struct Fd
*fd
)
63 // Unmap any data mapped for the file,
64 // then tell the file server that we have closed the file
65 // (to free up its resources).
69 size
= fd
->fd_file
.file
.f_size
;
72 if ((r
= funmap(fd
, size
, size
, 1)) < 0)
79 // Read 'n' bytes from 'fd' at the current seek position into 'buf'.
80 // Since files are memory-mapped, this amounts to a memmove()
81 // surrounded by a little red tape to handle the file size and seek pointer.
83 file_read(struct Fd
*fd
, void *buf
, size_t n
, off_t offset
)
87 // avoid reading past the end of file
88 size
= fd
->fd_file
.file
.f_size
;
91 if (offset
+ n
> size
)
94 // read the data by copying from the file mapping
95 memmove(buf
, fd2data(fd
) + offset
, n
);
99 // Find the page that maps the file block starting at 'offset',
100 // and store its address in '*blk'.
102 read_map(int fdnum
, off_t offset
, void **blk
)
108 if ((r
= fd_lookup(fdnum
, &fd
)) < 0)
110 if (fd
->fd_dev_id
!= devfile
.dev_id
)
112 va
= fd2data(fd
) + offset
;
113 if (offset
>= MAXFILESIZE
)
115 if (!(vpd
[PDX(va
)] & PTE_P
) || !(vpt
[VPN(va
)] & PTE_P
))
121 // Write 'n' bytes from 'buf' to 'fd' at the current seek position.
123 file_write(struct Fd
*fd
, const void *buf
, size_t n
, off_t offset
)
128 // don't write past the maximum file size
130 if (tot
> MAXFILESIZE
)
133 // increase the file's size if necessary
134 if (tot
> fd
->fd_file
.file
.f_size
) {
135 if ((r
= file_trunc(fd
, tot
)) < 0)
140 memmove(fd2data(fd
) + offset
, buf
, n
);
145 file_stat(struct Fd
*fd
, struct Stat
*st
)
147 strcpy(st
->st_name
, fd
->fd_file
.file
.f_name
);
148 st
->st_size
= fd
->fd_file
.file
.f_size
;
149 st
->st_isdir
= (fd
->fd_file
.file
.f_type
== FTYPE_DIR
);
153 // Truncate or extend an open file to 'size' bytes
155 file_trunc(struct Fd
*fd
, off_t newsize
)
161 if (newsize
> MAXFILESIZE
)
164 fileid
= fd
->fd_file
.id
;
165 oldsize
= fd
->fd_file
.file
.f_size
;
166 if ((r
= fsipc_set_size(fileid
, newsize
)) < 0)
168 assert(fd
->fd_file
.file
.f_size
== newsize
);
170 if ((r
= fmap(fd
, oldsize
, newsize
)) < 0)
172 funmap(fd
, oldsize
, newsize
, 0);
177 // Call the file system server to obtain and map file pages
178 // when the size of the file as mapped in our memory increases.
179 // Harmlessly does nothing if oldsize >= newsize.
180 // Returns 0 on success, < 0 on error.
181 // If there is an error, unmaps any newly allocated pages.
183 fmap(struct Fd
* fd
, off_t oldsize
, off_t newsize
)
190 for (i
= ROUNDUP(oldsize
, PGSIZE
); i
< newsize
; i
+= PGSIZE
) {
191 if ((r
= fsipc_map(fd
->fd_file
.id
, i
, va
+ i
)) < 0) {
192 // unmap anything we may have mapped so far
193 funmap(fd
, i
, oldsize
, 0);
200 // Unmap any file pages that no longer represent valid file pages
201 // when the size of the file as mapped in our address space decreases.
202 // Harmlessly does nothing if newsize >= oldsize.
204 funmap(struct Fd
* fd
, off_t oldsize
, off_t newsize
, bool dirty
)
212 // Check vpd to see if anything is mapped.
213 if (!(vpd
[VPD(va
)] & PTE_P
))
217 for (i
= ROUNDUP(newsize
, PGSIZE
); i
< oldsize
; i
+= PGSIZE
)
218 if (vpt
[VPN(va
+ i
)] & PTE_P
) {
220 && (vpt
[VPN(va
+ i
)] & PTE_D
)
221 && (r
= fsipc_dirty(fd
->fd_file
.id
, i
)) < 0)
223 sys_page_unmap(0, va
+ i
);
230 remove(const char *path
)
232 return fsipc_remove(path
);
235 // Synchronize disk with buffer cache