vm: fix a null dereference on out-of-memory
[minix.git] / servers / vfs / open.c
blob0a0edf80f7968fe8f83e39d8249c676cd903b762
1 /* This file contains the procedures for creating, opening, closing, and
2 * seeking on files.
4 * The entry points into this file are
5 * do_creat: perform the CREAT system call
6 * do_open: perform the OPEN system call
7 * do_mknod: perform the MKNOD system call
8 * do_mkdir: perform the MKDIR system call
9 * do_close: perform the CLOSE system call
10 * do_lseek: perform the LSEEK system call
11 * do_llseek: perform the LLSEEK system call
14 #include "fs.h"
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <minix/u64.h>
22 #include "file.h"
23 #include "fproc.h"
24 #include "scratchpad.h"
25 #include "dmap.h"
26 #include "lock.h"
27 #include "param.h"
28 #include <dirent.h>
29 #include <assert.h>
30 #include <minix/vfsif.h>
31 #include "vnode.h"
32 #include "vmnt.h"
33 #include "path.h"
35 char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
37 static struct vnode *new_node(struct lookup *resolve, int oflags,
38 mode_t bits);
39 static int pipe_open(struct vnode *vp, mode_t bits, int oflags);
42 /*===========================================================================*
43 * do_creat *
44 *===========================================================================*/
45 int do_creat()
47 /* Perform the creat(name, mode) system call.
48 * syscall might provide 'name' embedded in the message.
51 char fullpath[PATH_MAX];
52 vir_bytes vname;
53 size_t vname_length;
54 mode_t open_mode;
56 vname = (vir_bytes) job_m_in.name;
57 vname_length = (size_t) job_m_in.name_length;
58 open_mode = (mode_t) job_m_in.mode;
60 if (copy_name(vname_length, fullpath) != OK) {
61 /* Direct copy failed, try fetching from user space */
62 if (fetch_name(vname, vname_length, fullpath) != OK)
63 return(err_code);
66 return common_open(fullpath, O_WRONLY | O_CREAT | O_TRUNC, open_mode);
69 /*===========================================================================*
70 * do_open *
71 *===========================================================================*/
72 int do_open()
74 /* Perform the open(name, flags,...) system call.
75 * syscall might provide 'name' embedded in message when not creating file */
77 int create_mode; /* is really mode_t but this gives problems */
78 int open_mode = 0; /* is really mode_t but this gives problems */
79 int r = OK;
80 char fullpath[PATH_MAX];
81 vir_bytes vname;
82 size_t vname_length;
84 open_mode = (mode_t) job_m_in.mode;
85 create_mode = job_m_in.c_mode;
87 /* If O_CREAT is set, open has three parameters, otherwise two. */
88 if (open_mode & O_CREAT) {
89 vname = (vir_bytes) job_m_in.name1;
90 vname_length = (size_t) job_m_in.name1_length;
91 r = fetch_name(vname, vname_length, fullpath);
92 } else {
93 vname = (vir_bytes) job_m_in.name;
94 vname_length = (size_t) job_m_in.name_length;
95 create_mode = 0;
96 if (copy_name(vname_length, fullpath) != OK) {
97 /* Direct copy failed, try fetching from user space */
98 if (fetch_name(vname, vname_length, fullpath) != OK)
99 r = err_code;
103 if (r != OK) return(err_code); /* name was bad */
104 return common_open(fullpath, open_mode, create_mode);
108 /*===========================================================================*
109 * common_open *
110 *===========================================================================*/
111 int common_open(char path[PATH_MAX], int oflags, mode_t omode)
113 /* Common code from do_creat and do_open. */
114 int b, r, exist = TRUE, major_dev;
115 dev_t dev;
116 mode_t bits;
117 struct filp *filp, *filp2;
118 struct vnode *vp;
119 struct vmnt *vmp;
120 struct dmap *dp;
121 struct lookup resolve;
123 /* Remap the bottom two bits of oflags. */
124 bits = (mode_t) mode_map[oflags & O_ACCMODE];
125 if (!bits) return(EINVAL);
127 /* See if file descriptor and filp slots are available. */
128 if ((r = get_fd(0, bits, &(scratch(fp).file.fd_nr), &filp)) != OK) return(r);
130 lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp);
132 /* If O_CREATE is set, try to make the file. */
133 if (oflags & O_CREAT) {
134 omode = I_REGULAR | (omode & ALLPERMS & fp->fp_umask);
135 vp = new_node(&resolve, oflags, omode);
136 r = err_code;
137 if (r == OK) exist = FALSE; /* We just created the file */
138 else if (r != EEXIST) { /* other error */
139 if (vp) unlock_vnode(vp);
140 unlock_filp(filp);
141 return(r);
143 else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL
144 flag is set this is an error */
145 } else {
146 /* Scan path name */
147 resolve.l_vmnt_lock = VMNT_READ;
148 resolve.l_vnode_lock = VNODE_OPCL;
149 if ((vp = eat_path(&resolve, fp)) == NULL) {
150 unlock_filp(filp);
151 return(err_code);
154 if (vmp != NULL) unlock_vmnt(vmp);
157 /* Claim the file descriptor and filp slot and fill them in. */
158 fp->fp_filp[scratch(fp).file.fd_nr] = filp;
159 FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
160 filp->filp_count = 1;
161 filp->filp_vno = vp;
162 filp->filp_flags = oflags;
164 /* Only do the normal open code if we didn't just create the file. */
165 if (exist) {
166 /* Check protections. */
167 if ((r = forbidden(fp, vp, bits)) == OK) {
168 /* Opening reg. files, directories, and special files differ */
169 switch (vp->v_mode & S_IFMT) {
170 case S_IFREG:
171 /* Truncate regular file if O_TRUNC. */
172 if (oflags & O_TRUNC) {
173 if ((r = forbidden(fp, vp, W_BIT)) != OK)
174 break;
175 truncate_vnode(vp, 0);
177 break;
178 case S_IFDIR:
179 /* Directories may be read but not written. */
180 r = (bits & W_BIT ? EISDIR : OK);
181 break;
182 case S_IFCHR:
183 /* Invoke the driver for special processing. */
184 dev = (dev_t) vp->v_sdev;
185 /* TTY needs to know about the O_NOCTTY flag. */
186 r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY));
187 if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN);
188 else vp = filp->filp_vno; /* Might be updated by
189 * dev_open/clone_opcl */
190 break;
191 case S_IFBLK:
193 lock_bsf();
195 /* Invoke the driver for special processing. */
196 dev = (dev_t) vp->v_sdev;
197 r = bdev_open(dev, bits);
198 if (r != OK) {
199 unlock_bsf();
200 break;
203 major_dev = major(vp->v_sdev);
204 dp = &dmap[major_dev];
205 if (dp->dmap_driver == NONE) {
206 printf("VFS: block driver disappeared!\n");
207 unlock_bsf();
208 r = ENXIO;
209 break;
212 /* Check whether the device is mounted or not. If so,
213 * then that FS is responsible for this device.
214 * Otherwise we default to ROOT_FS.
216 vp->v_bfs_e = ROOT_FS_E; /* By default */
217 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
218 if (vmp->m_dev == vp->v_sdev &&
219 !(vmp->m_flags & VMNT_FORCEROOTBSF)) {
220 vp->v_bfs_e = vmp->m_fs_e;
223 /* Send the driver label to the file system that will
224 * handle the block I/O requests (even when its label
225 * and endpoint are known already), but only when it is
226 * the root file system. Other file systems will
227 * already have it anyway.
229 if (vp->v_bfs_e != ROOT_FS_E) {
230 unlock_bsf();
231 break;
234 if (req_newdriver(vp->v_bfs_e, vp->v_sdev,
235 dp->dmap_label) != OK) {
236 printf("VFS: error sending driver label\n");
237 bdev_close(dev);
238 r = ENXIO;
240 unlock_bsf();
241 break;
243 case S_IFIFO:
244 /* Create a mapped inode on PFS which handles reads
245 and writes to this named pipe. */
246 tll_upgrade(&vp->v_lock);
247 r = map_vnode(vp, PFS_PROC_NR);
248 if (r == OK) {
249 if (vp->v_ref_count == 1) {
250 vp->v_pipe_rd_pos = 0;
251 vp->v_pipe_wr_pos = 0;
252 if (vp->v_size != 0)
253 r = truncate_vnode(vp, 0);
255 oflags |= O_APPEND; /* force append mode */
256 filp->filp_flags = oflags;
258 if (r == OK) {
259 r = pipe_open(vp, bits, oflags);
261 if (r != ENXIO) {
262 /* See if someone else is doing a rd or wt on
263 * the FIFO. If so, use its filp entry so the
264 * file position will be automatically shared.
266 b = (bits & R_BIT ? R_BIT : W_BIT);
267 filp->filp_count = 0; /* don't find self */
268 if ((filp2 = find_filp(vp, b)) != NULL) {
269 /* Co-reader or writer found. Use it.*/
270 fp->fp_filp[scratch(fp).file.fd_nr] = filp2;
271 filp2->filp_count++;
272 filp2->filp_vno = vp;
273 filp2->filp_flags = oflags;
275 /* v_count was incremented after the vnode
276 * has been found. i_count was incremented
277 * incorrectly in FS, not knowing that we
278 * were going to use an existing filp
279 * entry. Correct this error.
281 unlock_vnode(vp);
282 put_vnode(vp);
283 } else {
284 /* Nobody else found. Restore filp. */
285 filp->filp_count = 1;
288 break;
293 unlock_filp(filp);
295 /* If error, release inode. */
296 if (r != OK) {
297 if (r != SUSPEND) {
298 fp->fp_filp[scratch(fp).file.fd_nr] = NULL;
299 FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
300 filp->filp_count = 0;
301 filp->filp_vno = NULL;
302 filp->filp_state &= ~FS_INVALIDATED; /* Prevent garbage col. */
303 put_vnode(vp);
305 } else {
306 r = scratch(fp).file.fd_nr;
309 return(r);
313 /*===========================================================================*
314 * new_node *
315 *===========================================================================*/
316 static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits)
318 /* Try to create a new inode and return a pointer to it. If the inode already
319 exists, return a pointer to it as well, but set err_code accordingly.
320 NULL is returned if the path cannot be resolved up to the last
321 directory, or when the inode cannot be created due to permissions or
322 otherwise. */
323 struct vnode *dirp, *vp;
324 struct vmnt *dir_vmp, *vp_vmp;
325 int r;
326 struct node_details res;
327 struct lookup findnode;
328 char *path;
330 path = resolve->l_path; /* For easy access */
332 lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp);
333 findnode.l_vmnt_lock = VMNT_WRITE;
334 findnode.l_vnode_lock = VNODE_WRITE; /* dir node */
336 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
337 * symbolic link. */
338 if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK;
340 /* See if the path can be opened down to the last directory. */
341 if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL);
343 /* The final directory is accessible. Get final component of the path. */
344 lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp);
345 findnode.l_vmnt_lock = VMNT_WRITE;
346 findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL;
347 vp = advance(dirp, &findnode, fp);
348 assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock
349 * on vmp or final component does not exist.
350 * Either way, vp_vmp ought to be not set.
353 /* The combination of a symlink with absolute path followed by a danglink
354 * symlink results in a new path that needs to be re-resolved entirely. */
355 if (path[0] == '/') {
356 unlock_vnode(dirp);
357 unlock_vmnt(dir_vmp);
358 put_vnode(dirp);
359 if (vp != NULL) {
360 unlock_vnode(vp);
361 put_vnode(vp);
363 return new_node(resolve, oflags, bits);
366 if (vp == NULL && err_code == ENOENT) {
367 /* Last path component does not exist. Make a new directory entry. */
368 if ((vp = get_free_vnode()) == NULL) {
369 /* Can't create new entry: out of vnodes. */
370 unlock_vnode(dirp);
371 unlock_vmnt(dir_vmp);
372 put_vnode(dirp);
373 return(NULL);
376 lock_vnode(vp, VNODE_OPCL);
378 if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK ||
379 (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid,
380 fp->fp_effgid, path, &res)) != OK ) {
381 /* Can't create inode either due to permissions or some other
382 * problem. In case r is EEXIST, we might be dealing with a
383 * dangling symlink.*/
384 if (r == EEXIST) {
385 struct vnode *slp, *old_wd;
387 /* Resolve path up to symlink */
388 findnode.l_flags = PATH_RET_SYMLINK;
389 findnode.l_vnode_lock = VNODE_READ;
390 findnode.l_vnode = &slp;
391 slp = advance(dirp, &findnode, fp);
392 if (slp != NULL) {
393 if (S_ISLNK(slp->v_mode)) {
394 /* Get contents of link */
396 r = req_rdlink(slp->v_fs_e,
397 slp->v_inode_nr,
398 VFS_PROC_NR,
399 (vir_bytes) path,
400 PATH_MAX - 1, 0);
401 if (r < 0) {
402 /* Failed to read link */
403 unlock_vnode(slp);
404 unlock_vnode(dirp);
405 unlock_vmnt(dir_vmp);
406 put_vnode(slp);
407 put_vnode(dirp);
408 err_code = r;
409 return(NULL);
411 path[r] = '\0'; /* Terminate path */
413 unlock_vnode(slp);
414 put_vnode(slp);
417 /* Try to create the inode the dangling symlink was
418 * pointing to. We have to use dirp as starting point
419 * as there might be multiple successive symlinks
420 * crossing multiple mountpoints.
421 * Unlock vnodes and vmnts as we're going to recurse.
423 unlock_vnode(dirp);
424 unlock_vnode(vp);
425 unlock_vmnt(dir_vmp);
427 old_wd = fp->fp_wd; /* Save orig. working dirp */
428 fp->fp_wd = dirp;
429 vp = new_node(resolve, oflags, bits);
430 fp->fp_wd = old_wd; /* Restore */
432 if (vp != NULL) {
433 put_vnode(dirp);
434 *(resolve->l_vnode) = vp;
435 return(vp);
437 r = err_code;
440 if (r == EEXIST)
441 err_code = EIO; /* Impossible, we have verified that
442 * the last component doesn't exist and
443 * is not a dangling symlink. */
444 else
445 err_code = r;
447 unlock_vnode(dirp);
448 unlock_vnode(vp);
449 unlock_vmnt(dir_vmp);
450 put_vnode(dirp);
451 return(NULL);
454 /* Store results and mark vnode in use */
456 vp->v_fs_e = res.fs_e;
457 vp->v_inode_nr = res.inode_nr;
458 vp->v_mode = res.fmode;
459 vp->v_size = res.fsize;
460 vp->v_uid = res.uid;
461 vp->v_gid = res.gid;
462 vp->v_sdev = res.dev;
463 vp->v_vmnt = dirp->v_vmnt;
464 vp->v_dev = vp->v_vmnt->m_dev;
465 vp->v_fs_count = 1;
466 vp->v_ref_count = 1;
467 } else {
468 /* Either last component exists, or there is some other problem. */
469 if (vp != NULL) {
470 r = EEXIST; /* File exists or a symlink names a file while
471 * O_EXCL is set. */
472 } else
473 r = err_code; /* Other problem. */
476 err_code = r;
477 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
478 * once. Releasing the lock would cause the resulting vp not be locked and
479 * cause mayhem later on. */
480 if (dirp != vp) {
481 unlock_vnode(dirp);
483 unlock_vmnt(dir_vmp);
484 put_vnode(dirp);
486 *(resolve->l_vnode) = vp;
487 return(vp);
491 /*===========================================================================*
492 * pipe_open *
493 *===========================================================================*/
494 static int pipe_open(struct vnode *vp, mode_t bits, int oflags)
496 /* This function is called from common_open. It checks if
497 * there is at least one reader/writer pair for the pipe, if not
498 * it suspends the caller, otherwise it revives all other blocked
499 * processes hanging on the pipe.
502 if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO);
504 /* Find the reader/writer at the other end of the pipe */
505 if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) {
506 /* Not found */
507 if (oflags & O_NONBLOCK) {
508 if (bits & W_BIT) return(ENXIO);
509 } else {
510 /* Let's wait for the other side to show up */
511 suspend(FP_BLOCKED_ON_POPEN);
512 return(SUSPEND);
514 } else if (susp_count > 0) { /* revive blocked processes */
515 release(vp, OPEN, susp_count);
516 release(vp, CREAT, susp_count);
518 return(OK);
522 /*===========================================================================*
523 * do_mknod *
524 *===========================================================================*/
525 int do_mknod()
527 /* Perform the mknod(name, mode, addr) system call. */
528 register mode_t bits, mode_bits;
529 int r;
530 struct vnode *vp;
531 struct vmnt *vmp;
532 char fullpath[PATH_MAX];
533 struct lookup resolve;
534 vir_bytes vname1;
535 size_t vname1_length;
536 dev_t dev;
538 vname1 = (vir_bytes) job_m_in.name1;
539 vname1_length = (size_t) job_m_in.name1_length;
540 mode_bits = (mode_t) job_m_in.mk_mode; /* mode of the inode */
541 dev = job_m_in.m1_i3;
543 lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
544 resolve.l_vmnt_lock = VMNT_WRITE;
545 resolve.l_vnode_lock = VNODE_READ;
547 /* Only the super_user may make nodes other than fifos. */
548 if (!super_user && (!S_ISFIFO(mode_bits) && !S_ISSOCK(mode_bits))) {
549 return(EPERM);
551 bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask);
553 /* Open directory that's going to hold the new node. */
554 if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
555 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
557 /* Make sure that the object is a directory */
558 if (!S_ISDIR(vp->v_mode)) {
559 r = ENOTDIR;
560 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
561 r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
562 fp->fp_effgid, bits, dev);
565 unlock_vnode(vp);
566 unlock_vmnt(vmp);
567 put_vnode(vp);
568 return(r);
571 /*===========================================================================*
572 * do_mkdir *
573 *===========================================================================*/
574 int do_mkdir()
576 /* Perform the mkdir(name, mode) system call. */
577 mode_t bits; /* mode bits for the new inode */
578 int r;
579 struct vnode *vp;
580 struct vmnt *vmp;
581 char fullpath[PATH_MAX];
582 struct lookup resolve;
583 vir_bytes vname1;
584 size_t vname1_length;
585 mode_t dirmode;
587 vname1 = (vir_bytes) job_m_in.name1;
588 vname1_length = (size_t) job_m_in.name1_length;
589 dirmode = (mode_t) job_m_in.mode;
591 lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
592 resolve.l_vmnt_lock = VMNT_WRITE;
593 resolve.l_vnode_lock = VNODE_READ;
595 if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
596 bits = I_DIRECTORY | (dirmode & RWX_MODES & fp->fp_umask);
597 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
599 /* Make sure that the object is a directory */
600 if (!S_ISDIR(vp->v_mode)) {
601 r = ENOTDIR;
602 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
603 r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
604 fp->fp_effgid, bits);
607 unlock_vnode(vp);
608 unlock_vmnt(vmp);
609 put_vnode(vp);
610 return(r);
613 /*===========================================================================*
614 * do_lseek *
615 *===========================================================================*/
616 int do_lseek()
618 /* Perform the lseek(ls_fd, offset, whence) system call. */
619 register struct filp *rfilp;
620 int r = OK, seekfd, seekwhence;
621 off_t offset;
622 u64_t pos, newpos;
624 seekfd = job_m_in.ls_fd;
625 seekwhence = job_m_in.whence;
626 offset = (off_t) job_m_in.offset_lo;
628 /* Check to see if the file descriptor is valid. */
629 if ( (rfilp = get_filp(seekfd, VNODE_READ)) == NULL) return(err_code);
631 /* No lseek on pipes. */
632 if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
633 unlock_filp(rfilp);
634 return(ESPIPE);
637 /* The value of 'whence' determines the start position to use. */
638 switch(seekwhence) {
639 case SEEK_SET: pos = cvu64(0); break;
640 case SEEK_CUR: pos = rfilp->filp_pos; break;
641 case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break;
642 default: unlock_filp(rfilp); return(EINVAL);
645 if (offset >= 0)
646 newpos = add64ul(pos, offset);
647 else
648 newpos = sub64ul(pos, -offset);
650 /* Check for overflow. */
651 if (ex64hi(newpos) != 0) {
652 r = EOVERFLOW;
653 } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */
654 r = EOVERFLOW;
655 } else {
656 /* insert the new position into the output message */
657 m_out.reply_l1 = ex64lo(newpos);
659 if (cmp64(newpos, rfilp->filp_pos) != 0) {
660 rfilp->filp_pos = newpos;
662 /* Inhibit read ahead request */
663 r = req_inhibread(rfilp->filp_vno->v_fs_e,
664 rfilp->filp_vno->v_inode_nr);
668 unlock_filp(rfilp);
669 return(r);
672 /*===========================================================================*
673 * do_llseek *
674 *===========================================================================*/
675 int do_llseek()
677 /* Perform the llseek(ls_fd, offset, whence) system call. */
678 register struct filp *rfilp;
679 u64_t pos, newpos;
680 int r = OK, seekfd, seekwhence;
681 long off_hi, off_lo;
683 seekfd = job_m_in.ls_fd;
684 seekwhence = job_m_in.whence;
685 off_hi = job_m_in.offset_high;
686 off_lo = job_m_in.offset_lo;
688 /* Check to see if the file descriptor is valid. */
689 if ( (rfilp = get_filp(seekfd, VNODE_READ)) == NULL) return(err_code);
691 /* No lseek on pipes. */
692 if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
693 unlock_filp(rfilp);
694 return(ESPIPE);
697 /* The value of 'whence' determines the start position to use. */
698 switch(seekwhence) {
699 case SEEK_SET: pos = cvu64(0); break;
700 case SEEK_CUR: pos = rfilp->filp_pos; break;
701 case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break;
702 default: unlock_filp(rfilp); return(EINVAL);
705 newpos = add64(pos, make64(off_lo, off_hi));
707 /* Check for overflow. */
708 if ((off_hi > 0) && cmp64(newpos, pos) < 0)
709 r = EINVAL;
710 else if ((off_hi < 0) && cmp64(newpos, pos) > 0)
711 r = EINVAL;
712 else {
713 /* insert the new position into the output message */
714 m_out.reply_l1 = ex64lo(newpos);
715 m_out.reply_l2 = ex64hi(newpos);
717 if (cmp64(newpos, rfilp->filp_pos) != 0) {
718 rfilp->filp_pos = newpos;
720 /* Inhibit read ahead request */
721 r = req_inhibread(rfilp->filp_vno->v_fs_e,
722 rfilp->filp_vno->v_inode_nr);
726 unlock_filp(rfilp);
727 return(r);
730 /*===========================================================================*
731 * do_close *
732 *===========================================================================*/
733 int do_close()
735 /* Perform the close(fd) system call. */
737 scratch(fp).file.fd_nr = job_m_in.fd;
738 return close_fd(fp, scratch(fp).file.fd_nr);
742 /*===========================================================================*
743 * close_fd *
744 *===========================================================================*/
745 int close_fd(rfp, fd_nr)
746 struct fproc *rfp;
747 int fd_nr;
749 /* Perform the close(fd) system call. */
750 register struct filp *rfilp;
751 register struct vnode *vp;
752 struct file_lock *flp;
753 int lock_count;
755 /* First locate the vnode that belongs to the file descriptor. */
756 if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code);
757 vp = rfilp->filp_vno;
759 close_filp(rfilp);
760 rfp->fp_filp[fd_nr] = NULL;
761 FD_CLR(fd_nr, &rfp->fp_cloexec_set);
762 FD_CLR(fd_nr, &rfp->fp_filp_inuse);
764 /* Check to see if the file is locked. If so, release all locks. */
765 if (nr_locks > 0) {
766 lock_count = nr_locks; /* save count of locks */
767 for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
768 if (flp->lock_type == 0) continue; /* slot not in use */
769 if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) {
770 flp->lock_type = 0;
771 nr_locks--;
774 if (nr_locks < lock_count)
775 lock_revive(); /* one or more locks released */
778 return(OK);
781 /*===========================================================================*
782 * close_reply *
783 *===========================================================================*/
784 void close_reply()
786 /* No need to do anything */