source: trunk/minix/servers/fs/open.c@ 12

Last change on this file since 12 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 18.4 KB
Line 
1/* This file contains the procedures for creating, opening, closing, and
2 * seeking on files.
3 *
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 */
12
13#include "fs.h"
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <string.h>
17#include <unistd.h>
18#include <minix/callnr.h>
19#include <minix/com.h>
20#include "buf.h"
21#include "file.h"
22#include "fproc.h"
23#include "inode.h"
24#include "lock.h"
25#include "param.h"
26#include "super.h"
27
28#define offset m2_l1
29
30PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
31
32FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode) );
33FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags));
34FORWARD _PROTOTYPE( struct inode *new_node, (struct inode **ldirp,
35 char *path, mode_t bits, zone_t z0, int opaque, char *string));
36
37/*===========================================================================*
38 * do_creat *
39 *===========================================================================*/
40PUBLIC int do_creat()
41{
42/* Perform the creat(name, mode) system call. */
43 int r;
44
45 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
46 r = common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode);
47 return(r);
48}
49
50/*===========================================================================*
51 * do_open *
52 *===========================================================================*/
53PUBLIC int do_open()
54{
55/* Perform the open(name, flags,...) system call. */
56
57 int create_mode = 0; /* is really mode_t but this gives problems */
58 int r;
59
60 /* If O_CREAT is set, open has three parameters, otherwise two. */
61 if (m_in.mode & O_CREAT) {
62 create_mode = m_in.c_mode;
63 r = fetch_name(m_in.c_name, m_in.name1_length, M1);
64 } else {
65 r = fetch_name(m_in.name, m_in.name_length, M3);
66 }
67
68 if (r != OK) return(err_code); /* name was bad */
69 r = common_open(m_in.mode, create_mode);
70 return(r);
71}
72
73/*===========================================================================*
74 * common_open *
75 *===========================================================================*/
76PRIVATE int common_open(register int oflags, mode_t omode)
77{
78/* Common code from do_creat and do_open. */
79
80 struct inode *rip, *ldirp;
81 int r, b, exist = TRUE;
82 dev_t dev;
83 mode_t bits;
84 off_t pos;
85 struct filp *fil_ptr, *filp2;
86
87 /* Remap the bottom two bits of oflags. */
88 bits = (mode_t) mode_map[oflags & O_ACCMODE];
89
90 /* See if file descriptor and filp slots are available. */
91 if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r);
92
93 /* If O_CREATE is set, try to make the file. */
94 if (oflags & O_CREAT) {
95 /* Create a new inode by calling new_node(). */
96 omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
97 rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL);
98 r = err_code;
99 put_inode(ldirp);
100 if (r == OK) exist = FALSE; /* we just created the file */
101 else if (r != EEXIST) return(r); /* other error */
102 else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL
103 flag is set this is an error */
104 } else {
105 /* Scan path name. */
106 if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
107 }
108
109 /* Claim the file descriptor and filp slot and fill them in. */
110 fp->fp_filp[m_in.fd] = fil_ptr;
111 FD_SET(m_in.fd, &fp->fp_filp_inuse);
112 fil_ptr->filp_count = 1;
113 fil_ptr->filp_ino = rip;
114 fil_ptr->filp_flags = oflags;
115
116 /* Only do the normal open code if we didn't just create the file. */
117 if (exist) {
118 /* Check protections. */
119 if ((r = forbidden(rip, bits)) == OK) {
120 /* Opening reg. files directories and special files differ. */
121 switch (rip->i_mode & I_TYPE) {
122 case I_REGULAR:
123 /* Truncate regular file if O_TRUNC. */
124 if (oflags & O_TRUNC) {
125 if ((r = forbidden(rip, W_BIT)) !=OK) break;
126 truncate_inode(rip, 0);
127 wipe_inode(rip);
128 /* Send the inode from the inode cache to the
129 * block cache, so it gets written on the next
130 * cache flush.
131 */
132 rw_inode(rip, WRITING);
133 }
134 break;
135
136 case I_DIRECTORY:
137 /* Directories may be read but not written. */
138 r = (bits & W_BIT ? EISDIR : OK);
139 break;
140
141 case I_CHAR_SPECIAL:
142 case I_BLOCK_SPECIAL:
143 /* Invoke the driver for special processing. */
144 dev = (dev_t) rip->i_zone[0];
145 r = dev_open(dev, who_e, bits | (oflags & ~O_ACCMODE));
146 break;
147
148 case I_NAMED_PIPE:
149 oflags |= O_APPEND; /* force append mode */
150 fil_ptr->filp_flags = oflags;
151 r = pipe_open(rip, bits, oflags);
152 if (r != ENXIO) {
153 /* See if someone else is doing a rd or wt on
154 * the FIFO. If so, use its filp entry so the
155 * file position will be automatically shared.
156 */
157 b = (bits & R_BIT ? R_BIT : W_BIT);
158 fil_ptr->filp_count = 0; /* don't find self */
159 if ((filp2 = find_filp(rip, b)) != NIL_FILP) {
160 /* Co-reader or writer found. Use it.*/
161 fp->fp_filp[m_in.fd] = filp2;
162 filp2->filp_count++;
163 filp2->filp_ino = rip;
164 filp2->filp_flags = oflags;
165
166 /* i_count was incremented incorrectly
167 * by eatpath above, not knowing that
168 * we were going to use an existing
169 * filp entry. Correct this error.
170 */
171 rip->i_count--;
172 } else {
173 /* Nobody else found. Restore filp. */
174 fil_ptr->filp_count = 1;
175 if (b == R_BIT)
176 pos = rip->i_zone[V2_NR_DZONES+0];
177 else
178 pos = rip->i_zone[V2_NR_DZONES+1];
179 fil_ptr->filp_pos = pos;
180 }
181 }
182 break;
183 }
184 }
185 }
186
187 /* If error, release inode. */
188 if (r != OK) {
189 if (r == SUSPEND) return(r); /* Oops, just suspended */
190 fp->fp_filp[m_in.fd] = NIL_FILP;
191 FD_CLR(m_in.fd, &fp->fp_filp_inuse);
192 fil_ptr->filp_count= 0;
193 put_inode(rip);
194 return(r);
195 }
196
197 return(m_in.fd);
198}
199
200/*===========================================================================*
201 * new_node *
202 *===========================================================================*/
203PRIVATE struct inode *new_node(struct inode **ldirp,
204 char *path, mode_t bits, zone_t z0, int opaque, char *parsed)
205{
206/* New_node() is called by common_open(), do_mknod(), and do_mkdir().
207 * In all cases it allocates a new inode, makes a directory entry for it on
208 * the path 'path', and initializes it. It returns a pointer to the inode if
209 * it can do this; otherwise it returns NIL_INODE. It always sets 'err_code'
210 * to an appropriate value (OK or an error code).
211 *
212 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
213 * has to hold at least NAME_MAX bytes.
214 */
215
216 register struct inode *rip;
217 register int r;
218 char string[NAME_MAX];
219
220 *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM);
221 if (*ldirp == NIL_INODE) return(NIL_INODE);
222
223 /* The final directory is accessible. Get final component of the path. */
224 rip = advance(ldirp, string);
225
226 if (S_ISDIR(bits) &&
227 (*ldirp)->i_nlinks >= ((*ldirp)->i_sp->s_version == V1 ?
228 CHAR_MAX : SHRT_MAX)) {
229 /* New entry is a directory, alas we can't give it a ".." */
230 put_inode(rip);
231 err_code = EMLINK;
232 return(NIL_INODE);
233 }
234
235 if ( rip == NIL_INODE && err_code == ENOENT) {
236 /* Last path component does not exist. Make new directory entry. */
237 if ( (rip = alloc_inode((*ldirp)->i_dev, bits)) == NIL_INODE) {
238 /* Can't creat new inode: out of inodes. */
239 return(NIL_INODE);
240 }
241
242 /* Force inode to the disk before making directory entry to make
243 * the system more robust in the face of a crash: an inode with
244 * no directory entry is much better than the opposite.
245 */
246 rip->i_nlinks++;
247 rip->i_zone[0] = z0; /* major/minor device numbers */
248 rw_inode(rip, WRITING); /* force inode to disk now */
249
250 /* New inode acquired. Try to make directory entry. */
251 if ((r = search_dir(*ldirp, string, &rip->i_num,ENTER)) != OK) {
252 rip->i_nlinks--; /* pity, have to free disk inode */
253 rip->i_dirt = DIRTY; /* dirty inodes are written out */
254 put_inode(rip); /* this call frees the inode */
255 err_code = r;
256 return(NIL_INODE);
257 }
258
259 } else {
260 /* Either last component exists, or there is some problem. */
261 if (rip != NIL_INODE)
262 r = EEXIST;
263 else
264 r = err_code;
265 }
266
267 if(parsed) { /* Give the caller the parsed string if requested. */
268 strncpy(parsed, string, NAME_MAX-1);
269 parsed[NAME_MAX-1] = '\0';
270 }
271
272 /* The caller has to return the directory inode (*ldirp). */
273 err_code = r;
274 return(rip);
275}
276
277/*===========================================================================*
278 * pipe_open *
279 *===========================================================================*/
280PRIVATE int pipe_open(register struct inode *rip, register mode_t bits,
281 register int oflags)
282{
283/* This function is called from common_open. It checks if
284 * there is at least one reader/writer pair for the pipe, if not
285 * it suspends the caller, otherwise it revives all other blocked
286 * processes hanging on the pipe.
287 */
288
289 rip->i_pipe = I_PIPE;
290
291 if((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) {
292 printf("pipe opened RW.\n");
293 return ENXIO;
294 }
295
296 if (find_filp(rip, bits & W_BIT ? R_BIT : W_BIT) == NIL_FILP) {
297 if (oflags & O_NONBLOCK) {
298 if (bits & W_BIT) return(ENXIO);
299 } else {
300 suspend(XPOPEN); /* suspend caller */
301 return(SUSPEND);
302 }
303 } else if (susp_count > 0) {/* revive blocked processes */
304 release(rip, OPEN, susp_count);
305 release(rip, CREAT, susp_count);
306 }
307 return(OK);
308}
309
310/*===========================================================================*
311 * do_mknod *
312 *===========================================================================*/
313PUBLIC int do_mknod()
314{
315/* Perform the mknod(name, mode, addr) system call. */
316
317 register mode_t bits, mode_bits;
318 struct inode *ip, *ldirp;
319
320 /* Only the super_user may make nodes other than fifos. */
321 mode_bits = (mode_t) m_in.mk_mode; /* mode of the inode */
322 if (!super_user && ((mode_bits & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
323 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
324 bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask);
325 ip = new_node(&ldirp, user_path, bits, (zone_t) m_in.mk_z0, TRUE, NULL);
326 put_inode(ip);
327 put_inode(ldirp);
328 return(err_code);
329}
330
331/*===========================================================================*
332 * do_mkdir *
333 *===========================================================================*/
334PUBLIC int do_mkdir()
335{
336/* Perform the mkdir(name, mode) system call. */
337
338 int r1, r2; /* status codes */
339 ino_t dot, dotdot; /* inode numbers for . and .. */
340 mode_t bits; /* mode bits for the new inode */
341 char string[NAME_MAX]; /* last component of the new dir's path name */
342 struct inode *rip, *ldirp;
343
344 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
345
346 /* Next make the inode. If that fails, return error code. */
347 bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask);
348 rip = new_node(&ldirp, user_path, bits, (zone_t) 0, TRUE, string);
349 if (rip == NIL_INODE || err_code == EEXIST) {
350 put_inode(rip); /* can't make dir: it already exists */
351 put_inode(ldirp);
352 return(err_code);
353 }
354
355 /* Get the inode numbers for . and .. to enter in the directory. */
356 dotdot = ldirp->i_num; /* parent's inode number */
357 dot = rip->i_num; /* inode number of the new dir itself */
358
359 /* Now make dir entries for . and .. unless the disk is completely full. */
360 /* Use dot1 and dot2, so the mode of the directory isn't important. */
361 rip->i_mode = bits; /* set mode */
362 r1 = search_dir(rip, dot1, &dot, ENTER); /* enter . in the new dir */
363 r2 = search_dir(rip, dot2, &dotdot, ENTER); /* enter .. in the new dir */
364
365 /* If both . and .. were successfully entered, increment the link counts. */
366 if (r1 == OK && r2 == OK) {
367 /* Normal case. It was possible to enter . and .. in the new dir. */
368 rip->i_nlinks++; /* this accounts for . */
369 ldirp->i_nlinks++; /* this accounts for .. */
370 ldirp->i_dirt = DIRTY; /* mark parent's inode as dirty */
371 } else {
372 /* It was not possible to enter . or .. probably disk was full -
373 * links counts haven't been touched.
374 */
375 if(search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK)
376 panic(__FILE__, "Dir disappeared ", rip->i_num);
377 rip->i_nlinks--; /* undo the increment done in new_node() */
378 }
379 rip->i_dirt = DIRTY; /* either way, i_nlinks has changed */
380
381 put_inode(ldirp); /* return the inode of the parent dir */
382 put_inode(rip); /* return the inode of the newly made dir */
383 return(err_code); /* new_node() always sets 'err_code' */
384}
385
386/*===========================================================================*
387 * do_close *
388 *===========================================================================*/
389PUBLIC int do_close()
390{
391/* Perform the close(fd) system call. */
392
393 register struct filp *rfilp;
394 register struct inode *rip;
395 struct file_lock *flp;
396 int rw, mode_word, lock_count;
397 dev_t dev;
398
399 /* First locate the inode that belongs to the file descriptor. */
400 if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
401 rip = rfilp->filp_ino; /* 'rip' points to the inode */
402
403 if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) {
404 /* Check to see if the file is special. */
405 mode_word = rip->i_mode & I_TYPE;
406 if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
407 dev = (dev_t) rip->i_zone[0];
408 if (mode_word == I_BLOCK_SPECIAL) {
409 /* Invalidate cache entries unless special is mounted
410 * or ROOT
411 */
412 if (!mounted(rip)) {
413 (void) do_sync(); /* purge cache */
414 invalidate(dev);
415 }
416 }
417 /* Do any special processing on device close. */
418 dev_close(dev);
419 }
420 }
421
422 /* If the inode being closed is a pipe, release everyone hanging on it. */
423 if (rip->i_pipe == I_PIPE) {
424 rw = (rfilp->filp_mode & R_BIT ? WRITE : READ);
425 release(rip, rw, NR_PROCS);
426 }
427
428 /* If a write has been done, the inode is already marked as DIRTY. */
429 if (--rfilp->filp_count == 0) {
430 if (rip->i_pipe == I_PIPE && rip->i_count > 1) {
431 /* Save the file position in the i-node in case needed later.
432 * The read and write positions are saved separately. The
433 * last 3 zones in the i-node are not used for (named) pipes.
434 */
435 if (rfilp->filp_mode == R_BIT)
436 rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos;
437 else
438 rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos;
439 }
440 put_inode(rip);
441 }
442
443 fp->fp_cloexec &= ~(1L << m_in.fd); /* turn off close-on-exec bit */
444 fp->fp_filp[m_in.fd] = NIL_FILP;
445 FD_CLR(m_in.fd, &fp->fp_filp_inuse);
446
447 /* Check to see if the file is locked. If so, release all locks. */
448 if (nr_locks == 0) return(OK);
449 lock_count = nr_locks; /* save count of locks */
450 for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
451 if (flp->lock_type == 0) continue; /* slot not in use */
452 if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
453 flp->lock_type = 0;
454 nr_locks--;
455 }
456 }
457 if (nr_locks < lock_count) lock_revive(); /* lock released */
458 return(OK);
459}
460
461/*===========================================================================*
462 * do_lseek *
463 *===========================================================================*/
464PUBLIC int do_lseek()
465{
466/* Perform the lseek(ls_fd, offset, whence) system call. */
467
468 register struct filp *rfilp;
469 register off_t pos;
470
471 /* Check to see if the file descriptor is valid. */
472 if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
473
474 /* No lseek on pipes. */
475 if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE);
476
477 /* The value of 'whence' determines the start position to use. */
478 switch(m_in.whence) {
479 case SEEK_SET: pos = 0; break;
480 case SEEK_CUR: pos = rfilp->filp_pos; break;
481 case SEEK_END: pos = rfilp->filp_ino->i_size; break;
482 default: return(EINVAL);
483 }
484
485 /* Check for overflow. */
486 if (((long)m_in.offset > 0) && ((long)(pos + m_in.offset) < (long)pos))
487 return(EINVAL);
488 if (((long)m_in.offset < 0) && ((long)(pos + m_in.offset) > (long)pos))
489 return(EINVAL);
490 pos = pos + m_in.offset;
491
492 if (pos != rfilp->filp_pos)
493 rfilp->filp_ino->i_seek = ISEEK; /* inhibit read ahead */
494 rfilp->filp_pos = pos;
495 m_out.reply_l1 = pos; /* insert the long into the output message */
496 return(OK);
497}
498
499/*===========================================================================*
500 * do_slink *
501 *===========================================================================*/
502PUBLIC int do_slink()
503{
504/* Perform the symlink(name1, name2) system call. */
505
506 register int r; /* error code */
507 char string[NAME_MAX]; /* last component of the new dir's path name */
508 struct inode *sip; /* inode containing symbolic link */
509 struct buf *bp; /* disk buffer for link */
510 struct inode *ldirp; /* directory containing link */
511
512 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK)
513 return(err_code);
514
515 if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE)
516 return(ENAMETOOLONG);
517
518 /* Create the inode for the symlink. */
519 sip = new_node(&ldirp, user_path, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
520 (zone_t) 0, TRUE, string);
521
522 /* Allocate a disk block for the contents of the symlink.
523 * Copy contents of symlink (the name pointed to) into first disk block.
524 */
525 if ((r = err_code) == OK) {
526 r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF
527 ? err_code
528 : sys_vircopy(who_e, D, (vir_bytes) m_in.name1,
529 SELF, D, (vir_bytes) bp->b_data,
530 (vir_bytes) m_in.name1_length-1);
531
532 if(r == OK) {
533 bp->b_data[_MIN_BLOCK_SIZE-1] = '\0';
534 sip->i_size = strlen(bp->b_data);
535 if(sip->i_size != m_in.name1_length-1) {
536 /* This can happen if the user provides a buffer
537 * with a \0 in it. This can cause a lot of trouble
538 * when the symlink is used later. We could just use
539 * the strlen() value, but we want to let the user
540 * know he did something wrong. ENAMETOOLONG doesn't
541 * exactly describe the error, but there is no
542 * ENAMETOOWRONG.
543 */
544 r = ENAMETOOLONG;
545 }
546 }
547
548 put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */
549
550 if (r != OK) {
551 sip->i_nlinks = 0;
552 if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK)
553 panic(__FILE__, "Symbolic link vanished", NO_NUM);
554 }
555 }
556
557 /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */
558 put_inode(sip);
559 put_inode(ldirp);
560
561 return(r);
562}
563
Note: See TracBrowser for help on using the repository browser.