Replace previous change by different test
[minix.git] / servers / vfs / open.c
blobfc726955ba73d89d18f22a36764a1c3ddc86c74d
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 upgrade_vnode_lock(vp);
176 truncate_vnode(vp, 0);
178 break;
179 case S_IFDIR:
180 /* Directories may be read but not written. */
181 r = (bits & W_BIT ? EISDIR : OK);
182 break;
183 case S_IFCHR:
184 /* Invoke the driver for special processing. */
185 dev = (dev_t) vp->v_sdev;
186 /* TTY needs to know about the O_NOCTTY flag. */
187 r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY));
188 if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN);
189 else vp = filp->filp_vno; /* Might be updated by
190 * dev_open/clone_opcl */
191 break;
192 case S_IFBLK:
194 lock_bsf();
196 /* Invoke the driver for special processing. */
197 dev = (dev_t) vp->v_sdev;
198 r = bdev_open(dev, bits);
199 if (r != OK) {
200 unlock_bsf();
201 break;
204 major_dev = major(vp->v_sdev);
205 dp = &dmap[major_dev];
206 if (dp->dmap_driver == NONE) {
207 printf("VFS: block driver disappeared!\n");
208 unlock_bsf();
209 r = ENXIO;
210 break;
213 /* Check whether the device is mounted or not. If so,
214 * then that FS is responsible for this device.
215 * Otherwise we default to ROOT_FS.
217 vp->v_bfs_e = ROOT_FS_E; /* By default */
218 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
219 if (vmp->m_dev == vp->v_sdev &&
220 !(vmp->m_flags & VMNT_FORCEROOTBSF)) {
221 vp->v_bfs_e = vmp->m_fs_e;
224 /* Send the driver label to the file system that will
225 * handle the block I/O requests (even when its label
226 * and endpoint are known already), but only when it is
227 * the root file system. Other file systems will
228 * already have it anyway.
230 if (vp->v_bfs_e != ROOT_FS_E) {
231 unlock_bsf();
232 break;
235 if (req_newdriver(vp->v_bfs_e, vp->v_sdev,
236 dp->dmap_label) != OK) {
237 printf("VFS: error sending driver label\n");
238 bdev_close(dev);
239 r = ENXIO;
241 unlock_bsf();
242 break;
244 case S_IFIFO:
245 /* Create a mapped inode on PFS which handles reads
246 and writes to this named pipe. */
247 upgrade_vnode_lock(vp);
248 r = map_vnode(vp, PFS_PROC_NR);
249 if (r == OK) {
250 if (vp->v_ref_count == 1) {
251 if (vp->v_size != 0)
252 r = truncate_vnode(vp, 0);
254 oflags |= O_APPEND; /* force append mode */
255 filp->filp_flags = oflags;
257 if (r == OK) {
258 r = pipe_open(vp, bits, oflags);
260 if (r != ENXIO) {
261 /* See if someone else is doing a rd or wt on
262 * the FIFO. If so, use its filp entry so the
263 * file position will be automatically shared.
265 b = (bits & R_BIT ? R_BIT : W_BIT);
266 filp->filp_count = 0; /* don't find self */
267 if ((filp2 = find_filp(vp, b)) != NULL) {
268 /* Co-reader or writer found. Use it.*/
269 fp->fp_filp[scratch(fp).file.fd_nr] = filp2;
270 filp2->filp_count++;
271 filp2->filp_vno = vp;
272 filp2->filp_flags = oflags;
274 /* v_count was incremented after the vnode
275 * has been found. i_count was incremented
276 * incorrectly in FS, not knowing that we
277 * were going to use an existing filp
278 * entry. Correct this error.
280 unlock_vnode(vp);
281 put_vnode(vp);
282 } else {
283 /* Nobody else found. Restore filp. */
284 filp->filp_count = 1;
287 break;
292 unlock_filp(filp);
294 /* If error, release inode. */
295 if (r != OK) {
296 if (r != SUSPEND) {
297 fp->fp_filp[scratch(fp).file.fd_nr] = NULL;
298 FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
299 filp->filp_count = 0;
300 filp->filp_vno = NULL;
301 filp->filp_state &= ~FS_INVALIDATED; /* Prevent garbage col. */
302 put_vnode(vp);
304 } else {
305 r = scratch(fp).file.fd_nr;
308 return(r);
312 /*===========================================================================*
313 * new_node *
314 *===========================================================================*/
315 static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits)
317 /* Try to create a new inode and return a pointer to it. If the inode already
318 exists, return a pointer to it as well, but set err_code accordingly.
319 NULL is returned if the path cannot be resolved up to the last
320 directory, or when the inode cannot be created due to permissions or
321 otherwise. */
322 struct vnode *dirp, *vp;
323 struct vmnt *dir_vmp, *vp_vmp;
324 int r;
325 struct node_details res;
326 struct lookup findnode;
327 char *path;
329 path = resolve->l_path; /* For easy access */
331 lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp);
332 findnode.l_vmnt_lock = VMNT_WRITE;
333 findnode.l_vnode_lock = VNODE_WRITE; /* dir node */
335 /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
336 * symbolic link. */
337 if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK;
339 /* See if the path can be opened down to the last directory. */
340 if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL);
342 /* The final directory is accessible. Get final component of the path. */
343 lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp);
344 findnode.l_vmnt_lock = VMNT_WRITE;
345 findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL;
346 vp = advance(dirp, &findnode, fp);
347 assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock
348 * on vmp or final component does not exist.
349 * Either way, vp_vmp ought to be not set.
352 /* The combination of a symlink with absolute path followed by a danglink
353 * symlink results in a new path that needs to be re-resolved entirely. */
354 if (path[0] == '/') {
355 unlock_vnode(dirp);
356 unlock_vmnt(dir_vmp);
357 put_vnode(dirp);
358 if (vp != NULL) {
359 unlock_vnode(vp);
360 put_vnode(vp);
362 return new_node(resolve, oflags, bits);
365 if (vp == NULL && err_code == ENOENT) {
366 /* Last path component does not exist. Make a new directory entry. */
367 if ((vp = get_free_vnode()) == NULL) {
368 /* Can't create new entry: out of vnodes. */
369 unlock_vnode(dirp);
370 unlock_vmnt(dir_vmp);
371 put_vnode(dirp);
372 return(NULL);
375 lock_vnode(vp, VNODE_OPCL);
376 upgrade_vmnt_lock(dir_vmp); /* Creating file, need exclusive access */
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.*/
385 /* Downgrade lock to prevent deadlock during symlink resolving*/
386 downgrade_vmnt_lock(dir_vmp);
388 if (r == EEXIST) {
389 struct vnode *slp, *old_wd;
392 /* Resolve path up to symlink */
393 findnode.l_flags = PATH_RET_SYMLINK;
394 findnode.l_vnode_lock = VNODE_READ;
395 findnode.l_vnode = &slp;
396 slp = advance(dirp, &findnode, fp);
397 if (slp != NULL) {
398 if (S_ISLNK(slp->v_mode)) {
399 /* Get contents of link */
401 r = req_rdlink(slp->v_fs_e,
402 slp->v_inode_nr,
403 VFS_PROC_NR,
404 (vir_bytes) path,
405 PATH_MAX - 1, 0);
406 if (r < 0) {
407 /* Failed to read link */
408 unlock_vnode(slp);
409 unlock_vnode(dirp);
410 unlock_vmnt(dir_vmp);
411 put_vnode(slp);
412 put_vnode(dirp);
413 err_code = r;
414 return(NULL);
416 path[r] = '\0'; /* Terminate path */
418 unlock_vnode(slp);
419 put_vnode(slp);
422 /* Try to create the inode the dangling symlink was
423 * pointing to. We have to use dirp as starting point
424 * as there might be multiple successive symlinks
425 * crossing multiple mountpoints.
426 * Unlock vnodes and vmnts as we're going to recurse.
428 unlock_vnode(dirp);
429 unlock_vnode(vp);
430 unlock_vmnt(dir_vmp);
432 old_wd = fp->fp_wd; /* Save orig. working dirp */
433 fp->fp_wd = dirp;
434 vp = new_node(resolve, oflags, bits);
435 fp->fp_wd = old_wd; /* Restore */
437 if (vp != NULL) {
438 put_vnode(dirp);
439 *(resolve->l_vnode) = vp;
440 return(vp);
442 r = err_code;
445 if (r == EEXIST)
446 err_code = EIO; /* Impossible, we have verified that
447 * the last component doesn't exist and
448 * is not a dangling symlink. */
449 else
450 err_code = r;
452 unlock_vmnt(dir_vmp);
453 unlock_vnode(dirp);
454 unlock_vnode(vp);
455 put_vnode(dirp);
456 return(NULL);
459 /* Store results and mark vnode in use */
461 vp->v_fs_e = res.fs_e;
462 vp->v_inode_nr = res.inode_nr;
463 vp->v_mode = res.fmode;
464 vp->v_size = res.fsize;
465 vp->v_uid = res.uid;
466 vp->v_gid = res.gid;
467 vp->v_sdev = res.dev;
468 vp->v_vmnt = dirp->v_vmnt;
469 vp->v_dev = vp->v_vmnt->m_dev;
470 vp->v_fs_count = 1;
471 vp->v_ref_count = 1;
472 } else {
473 /* Either last component exists, or there is some other problem. */
474 if (vp != NULL) {
475 r = EEXIST; /* File exists or a symlink names a file while
476 * O_EXCL is set. */
477 } else
478 r = err_code; /* Other problem. */
481 err_code = r;
482 /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
483 * once. Releasing the lock would cause the resulting vp not be locked and
484 * cause mayhem later on. */
485 if (dirp != vp) {
486 unlock_vnode(dirp);
488 unlock_vmnt(dir_vmp);
489 put_vnode(dirp);
491 *(resolve->l_vnode) = vp;
492 return(vp);
496 /*===========================================================================*
497 * pipe_open *
498 *===========================================================================*/
499 static int pipe_open(struct vnode *vp, mode_t bits, int oflags)
501 /* This function is called from common_open. It checks if
502 * there is at least one reader/writer pair for the pipe, if not
503 * it suspends the caller, otherwise it revives all other blocked
504 * processes hanging on the pipe.
507 if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO);
509 /* Find the reader/writer at the other end of the pipe */
510 if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) {
511 /* Not found */
512 if (oflags & O_NONBLOCK) {
513 if (bits & W_BIT) return(ENXIO);
514 } else {
515 /* Let's wait for the other side to show up */
516 suspend(FP_BLOCKED_ON_POPEN);
517 return(SUSPEND);
519 } else if (susp_count > 0) { /* revive blocked processes */
520 release(vp, OPEN, susp_count);
521 release(vp, CREAT, susp_count);
523 return(OK);
527 /*===========================================================================*
528 * do_mknod *
529 *===========================================================================*/
530 int do_mknod()
532 /* Perform the mknod(name, mode, addr) system call. */
533 register mode_t bits, mode_bits;
534 int r;
535 struct vnode *vp;
536 struct vmnt *vmp;
537 char fullpath[PATH_MAX];
538 struct lookup resolve;
539 vir_bytes vname1;
540 size_t vname1_length;
541 dev_t dev;
543 vname1 = (vir_bytes) job_m_in.name1;
544 vname1_length = (size_t) job_m_in.name1_length;
545 mode_bits = (mode_t) job_m_in.mk_mode; /* mode of the inode */
546 dev = job_m_in.m1_i3;
548 lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
549 resolve.l_vmnt_lock = VMNT_WRITE;
550 resolve.l_vnode_lock = VNODE_WRITE;
552 /* Only the super_user may make nodes other than fifos. */
553 if (!super_user && (!S_ISFIFO(mode_bits) && !S_ISSOCK(mode_bits))) {
554 return(EPERM);
556 bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask);
558 /* Open directory that's going to hold the new node. */
559 if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
560 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
562 /* Make sure that the object is a directory */
563 if (!S_ISDIR(vp->v_mode)) {
564 r = ENOTDIR;
565 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
566 r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
567 fp->fp_effgid, bits, dev);
570 unlock_vnode(vp);
571 unlock_vmnt(vmp);
572 put_vnode(vp);
573 return(r);
576 /*===========================================================================*
577 * do_mkdir *
578 *===========================================================================*/
579 int do_mkdir()
581 /* Perform the mkdir(name, mode) system call. */
582 mode_t bits; /* mode bits for the new inode */
583 int r;
584 struct vnode *vp;
585 struct vmnt *vmp;
586 char fullpath[PATH_MAX];
587 struct lookup resolve;
588 vir_bytes vname1;
589 size_t vname1_length;
590 mode_t dirmode;
592 vname1 = (vir_bytes) job_m_in.name1;
593 vname1_length = (size_t) job_m_in.name1_length;
594 dirmode = (mode_t) job_m_in.mode;
596 lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
597 resolve.l_vmnt_lock = VMNT_WRITE;
598 resolve.l_vnode_lock = VNODE_WRITE;
600 if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
601 bits = I_DIRECTORY | (dirmode & RWX_MODES & fp->fp_umask);
602 if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
604 /* Make sure that the object is a directory */
605 if (!S_ISDIR(vp->v_mode)) {
606 r = ENOTDIR;
607 } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
608 r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
609 fp->fp_effgid, bits);
612 unlock_vnode(vp);
613 unlock_vmnt(vmp);
614 put_vnode(vp);
615 return(r);
618 /*===========================================================================*
619 * do_lseek *
620 *===========================================================================*/
621 int do_lseek()
623 /* Perform the lseek(ls_fd, offset, whence) system call. */
624 register struct filp *rfilp;
625 int r = OK, seekfd, seekwhence;
626 off_t offset;
627 u64_t pos, newpos;
629 seekfd = job_m_in.ls_fd;
630 seekwhence = job_m_in.whence;
631 offset = (off_t) job_m_in.offset_lo;
633 /* Check to see if the file descriptor is valid. */
634 if ( (rfilp = get_filp(seekfd, VNODE_READ)) == NULL) return(err_code);
636 /* No lseek on pipes. */
637 if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
638 unlock_filp(rfilp);
639 return(ESPIPE);
642 /* The value of 'whence' determines the start position to use. */
643 switch(seekwhence) {
644 case SEEK_SET: pos = cvu64(0); break;
645 case SEEK_CUR: pos = rfilp->filp_pos; break;
646 case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break;
647 default: unlock_filp(rfilp); return(EINVAL);
650 if (offset >= 0)
651 newpos = add64ul(pos, offset);
652 else
653 newpos = sub64ul(pos, -offset);
655 /* Check for overflow. */
656 if (ex64hi(newpos) != 0) {
657 r = EOVERFLOW;
658 } else if ((off_t) ex64lo(newpos) < 0) { /* no negative file size */
659 r = EOVERFLOW;
660 } else {
661 /* insert the new position into the output message */
662 m_out.reply_l1 = ex64lo(newpos);
664 if (cmp64(newpos, rfilp->filp_pos) != 0) {
665 rfilp->filp_pos = newpos;
667 /* Inhibit read ahead request */
668 r = req_inhibread(rfilp->filp_vno->v_fs_e,
669 rfilp->filp_vno->v_inode_nr);
673 unlock_filp(rfilp);
674 return(r);
677 /*===========================================================================*
678 * do_llseek *
679 *===========================================================================*/
680 int do_llseek()
682 /* Perform the llseek(ls_fd, offset, whence) system call. */
683 register struct filp *rfilp;
684 u64_t pos, newpos;
685 int r = OK, seekfd, seekwhence;
686 long off_hi, off_lo;
688 seekfd = job_m_in.ls_fd;
689 seekwhence = job_m_in.whence;
690 off_hi = job_m_in.offset_high;
691 off_lo = job_m_in.offset_lo;
693 /* Check to see if the file descriptor is valid. */
694 if ( (rfilp = get_filp(seekfd, VNODE_READ)) == NULL) return(err_code);
696 /* No lseek on pipes. */
697 if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
698 unlock_filp(rfilp);
699 return(ESPIPE);
702 /* The value of 'whence' determines the start position to use. */
703 switch(seekwhence) {
704 case SEEK_SET: pos = cvu64(0); break;
705 case SEEK_CUR: pos = rfilp->filp_pos; break;
706 case SEEK_END: pos = cvul64(rfilp->filp_vno->v_size); break;
707 default: unlock_filp(rfilp); return(EINVAL);
710 newpos = add64(pos, make64(off_lo, off_hi));
712 /* Check for overflow. */
713 if ((off_hi > 0) && cmp64(newpos, pos) < 0)
714 r = EINVAL;
715 else if ((off_hi < 0) && cmp64(newpos, pos) > 0)
716 r = EINVAL;
717 else {
718 /* insert the new position into the output message */
719 m_out.reply_l1 = ex64lo(newpos);
720 m_out.reply_l2 = ex64hi(newpos);
722 if (cmp64(newpos, rfilp->filp_pos) != 0) {
723 rfilp->filp_pos = newpos;
725 /* Inhibit read ahead request */
726 r = req_inhibread(rfilp->filp_vno->v_fs_e,
727 rfilp->filp_vno->v_inode_nr);
731 unlock_filp(rfilp);
732 return(r);
735 /*===========================================================================*
736 * do_close *
737 *===========================================================================*/
738 int do_close()
740 /* Perform the close(fd) system call. */
742 scratch(fp).file.fd_nr = job_m_in.fd;
743 return close_fd(fp, scratch(fp).file.fd_nr);
747 /*===========================================================================*
748 * close_fd *
749 *===========================================================================*/
750 int close_fd(rfp, fd_nr)
751 struct fproc *rfp;
752 int fd_nr;
754 /* Perform the close(fd) system call. */
755 register struct filp *rfilp;
756 register struct vnode *vp;
757 struct file_lock *flp;
758 int lock_count;
760 /* First locate the vnode that belongs to the file descriptor. */
761 if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code);
762 vp = rfilp->filp_vno;
764 close_filp(rfilp);
765 rfp->fp_filp[fd_nr] = NULL;
766 FD_CLR(fd_nr, &rfp->fp_cloexec_set);
767 FD_CLR(fd_nr, &rfp->fp_filp_inuse);
769 /* Check to see if the file is locked. If so, release all locks. */
770 if (nr_locks > 0) {
771 lock_count = nr_locks; /* save count of locks */
772 for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
773 if (flp->lock_type == 0) continue; /* slot not in use */
774 if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) {
775 flp->lock_type = 0;
776 nr_locks--;
779 if (nr_locks < lock_count)
780 lock_revive(); /* one or more locks released */
783 return(OK);
786 /*===========================================================================*
787 * close_reply *
788 *===========================================================================*/
789 void close_reply()
791 /* No need to do anything */