3 // Maximum number of file descriptors a program may hold open concurrently
5 // Bottom of file descriptor area
6 #define FDTABLE 0xD0000000
7 // Bottom of file data area. We reserve one data page for each FD,
8 // which devices can use if they choose.
9 #define FDDATA (FDTABLE + NFD*PGSIZE)
11 static bool fd_isopen(const struct Fd
*fd
);
14 // --------------------------------------------------------------
15 // Low-level file descriptor manipulators
16 // --------------------------------------------------------------
18 // Return the 'struct Fd' for a file descriptor number.
19 // Returns NULL on failure, a pointer on success.
20 // If 'must_exist' is true, then the file descriptor must currently be open
21 // or NULL is returned.
22 // Returns 0 on success, < 0 error code on failure.
25 fd_lookup(int fdnum
, struct Fd
**fd_store
, bool must_exist
)
27 struct Fd
*fd
= (struct Fd
*) (FDTABLE
+ fdnum
* PGSIZE
);
29 if (fdnum
< 0 || fdnum
>= NFD
|| (must_exist
&& !fd_isopen(fd
))) {
38 // Return true iff 'fd' is a valid file descriptor pointer.
41 fd_valid(const struct Fd
*fd
)
43 return PGOFF(fd
) == 0 && fd
>= (const struct Fd
*) FDTABLE
44 && fd
< (const struct Fd
*) (FDTABLE
+ NFD
* PGSIZE
);
47 // Return true iff 'fd' is currently open.
50 fd_isopen(const struct Fd
*fd
)
53 return (vpd
[PDX(fd
)] & PTE_P
) && (vpt
[PGNUM(fd
)] & PTE_P
);
56 // Return the file descriptor number for a 'struct Fd'.
62 return ((uintptr_t) fd
- FDTABLE
) / PGSIZE
;
65 // Return the file descriptor data pointer for a 'struct Fd'.
68 fd2data(struct Fd
*fd
)
71 return (char *) (FDDATA
+ num
* PGSIZE
);
75 // Finds the smallest index from 0 to NFD-1 that doesn't have
76 // its fd page mapped.
77 // Sets *fd_store to the corresponding fd page virtual address.
79 // Does NOT actually allocate an fd page.
80 // It is up to the caller to allocate the page somehow.
81 // This means that if someone calls fd_find_unused twice in a row
82 // without allocating the first page we return, we'll return the same
83 // page the second time.
85 // Returns 0 on success, < 0 on error. Errors are:
86 // -E_MAX_FD: no more file descriptors
87 // On error, *fd_store is set to 0.
89 fd_find_unused(struct Fd
**fd_store
)
94 for (i
= 0; i
< NFD
; i
++) {
95 (void) fd_lookup(i
, &fd
, false);
105 // Frees file descriptor 'fd' by closing the corresponding file
106 // and unmapping the file descriptor page.
107 // If 'must_exist' is 0, then fd can be a closed or nonexistent file
108 // descriptor; the function will return 0 and have no other effect.
109 // If 'must_exist' is 1, then fd_close returns -E_INVAL when passed a
110 // closed or nonexistent file descriptor.
111 // Returns 0 on success, < 0 on error.
113 fd_close(struct Fd
*fd
, bool must_exist
)
118 if ((r
= fd_lookup(fd2num(fd
), &fd2
, must_exist
)) < 0
120 return (must_exist
? -E_INVAL
: 0);
121 if ((r
= dev_lookup(fd
->fd_dev_id
, &dev
)) >= 0) {
123 r
= (*dev
->dev_close
)(fd
);
127 // Make sure fd is unmapped. Might be a no-op if
128 // (*dev->dev_close)(fd) already unmapped it.
129 (void) sys_page_unmap(0, fd
);
133 static struct Dev
*devtab
[] =
142 dev_lookup(int dev_id
, struct Dev
**dev
)
145 for (i
= 0; devtab
[i
]; i
++)
146 if (devtab
[i
]->dev_id
== dev_id
) {
150 cprintf("[%08x] unknown device type %d\n", thisenv
->env_id
, dev_id
);
156 // --------------------------------------------------------------
157 // File descriptor interface functions
158 // --------------------------------------------------------------
165 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0)
168 return fd_close(fd
, true);
175 for (i
= 0; i
< NFD
; i
++)
179 // Make file descriptor 'newfdnum' a duplicate of file descriptor 'oldfdnum'.
180 // For instance, writing onto either file descriptor will affect the
181 // file and the file offset of the other.
182 // Closes any previously open file descriptor at 'newfdnum'.
183 // This is implemented using virtual memory tricks (of course!).
185 dup(int oldfdnum
, int newfdnum
)
190 struct Fd
*oldfd
, *newfd
;
192 if ((r
= fd_lookup(oldfdnum
, &oldfd
, true)) < 0
193 || (r
= fd_lookup(newfdnum
, &newfd
, false)) < 0)
197 ova
= fd2data(oldfd
);
198 nva
= fd2data(newfd
);
200 if ((vpd
[PDX(ova
)] & PTE_P
) && (vpt
[PGNUM(ova
)] & PTE_P
))
201 if ((r
= sys_page_map(0, ova
, 0, nva
, vpt
[PGNUM(ova
)] & PTE_USER
)) < 0)
203 if ((r
= sys_page_map(0, oldfd
, 0, newfd
, vpt
[PGNUM(oldfd
)] & PTE_USER
)) < 0)
209 sys_page_unmap(0, newfd
);
210 sys_page_unmap(0, nva
);
215 read(int fdnum
, void *buf
, size_t n
)
221 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0
222 || (r
= dev_lookup(fd
->fd_dev_id
, &dev
)) < 0)
224 if ((fd
->fd_omode
& O_ACCMODE
) == O_WRONLY
) {
225 cprintf("[%08x] read %d -- bad mode\n", thisenv
->env_id
, fdnum
);
230 return (*dev
->dev_read
)(fd
, buf
, n
);
234 readn(int fdnum
, void *buf
, size_t n
)
239 for (tot
= 0; tot
< n
; tot
+= m
) {
240 m
= read(fdnum
, (char*)buf
+ tot
, n
- tot
);
250 write(int fdnum
, const void *buf
, size_t n
)
256 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0
257 || (r
= dev_lookup(fd
->fd_dev_id
, &dev
)) < 0)
259 if ((fd
->fd_omode
& O_ACCMODE
) == O_RDONLY
)
263 return (*dev
->dev_write
)(fd
, buf
, n
);
267 seek(int fdnum
, off_t offset
)
272 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0)
274 fd
->fd_offset
= offset
;
279 ftruncate(int fdnum
, off_t newsize
)
285 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0
286 || (r
= dev_lookup(fd
->fd_dev_id
, &dev
)) < 0)
288 if ((fd
->fd_omode
& O_ACCMODE
) == O_RDONLY
) {
289 cprintf("[%08x] ftruncate %d -- bad mode\n", thisenv
->env_id
, fdnum
);
294 return (*dev
->dev_trunc
)(fd
, newsize
);
298 fstat(int fdnum
, struct Stat
*stat
)
304 if ((r
= fd_lookup(fdnum
, &fd
, true)) < 0
305 || (r
= dev_lookup(fd
->fd_dev_id
, &dev
)) < 0)
309 stat
->st_name
[0] = 0;
313 return (*dev
->dev_stat
)(fd
, stat
);
317 stat(const char *path
, struct Stat
*stat
)
321 if ((fd
= open(path
, O_RDONLY
)) < 0)