xref: /minix3/minix/fs/mfs/open.c (revision 0314acfb2d68447dfa1b0b33aa4c25b1cbfa85d3)
1433d6423SLionel Sambuc #include "fs.h"
2433d6423SLionel Sambuc #include <sys/stat.h>
3433d6423SLionel Sambuc #include <string.h>
4433d6423SLionel Sambuc #include "buf.h"
5433d6423SLionel Sambuc #include "inode.h"
6433d6423SLionel Sambuc #include "super.h"
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc static struct inode *new_node(struct inode *ldirp, char *string, mode_t
9ccaeedb2SDavid van Moolenbroek 	bits, uid_t uid, gid_t gid, zone_t z0);
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc /*===========================================================================*
12433d6423SLionel Sambuc  *				fs_create				     *
13433d6423SLionel Sambuc  *===========================================================================*/
fs_create(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,struct fsdriver_node * node)14ccaeedb2SDavid van Moolenbroek int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
15ccaeedb2SDavid van Moolenbroek 	struct fsdriver_node *node)
16433d6423SLionel Sambuc {
17433d6423SLionel Sambuc   int r;
18433d6423SLionel Sambuc   struct inode *ldirp;
19433d6423SLionel Sambuc   struct inode *rip;
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc   /* Try to make the file. */
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc   /* Get last directory inode (i.e., directory that will hold the new inode) */
24ccaeedb2SDavid van Moolenbroek   if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
25ccaeedb2SDavid van Moolenbroek 	  return(EINVAL);
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc   /* Create a new inode by calling new_node(). */
28ccaeedb2SDavid van Moolenbroek   rip = new_node(ldirp, name, mode, uid, gid, NO_ZONE);
29433d6423SLionel Sambuc   r = err_code;
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc   /* If an error occurred, release inode. */
32433d6423SLionel Sambuc   if (r != OK) {
33433d6423SLionel Sambuc 	  put_inode(ldirp);
34433d6423SLionel Sambuc 	  put_inode(rip);
35433d6423SLionel Sambuc 	  return(r);
36433d6423SLionel Sambuc   }
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc   /* Reply message */
39ccaeedb2SDavid van Moolenbroek   node->fn_ino_nr = rip->i_num;
40ccaeedb2SDavid van Moolenbroek   node->fn_mode = rip->i_mode;
41ccaeedb2SDavid van Moolenbroek   node->fn_size = rip->i_size;
42ccaeedb2SDavid van Moolenbroek   node->fn_uid = rip->i_uid;
43ccaeedb2SDavid van Moolenbroek   node->fn_gid = rip->i_gid;
44ccaeedb2SDavid van Moolenbroek   node->fn_dev = NO_DEV;
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc   /* Drop parent dir */
47433d6423SLionel Sambuc   put_inode(ldirp);
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc   return(OK);
50433d6423SLionel Sambuc }
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc /*===========================================================================*
54433d6423SLionel Sambuc  *				fs_mknod				     *
55433d6423SLionel Sambuc  *===========================================================================*/
fs_mknod(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid,dev_t dev)56ccaeedb2SDavid van Moolenbroek int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
57ccaeedb2SDavid van Moolenbroek 	dev_t dev)
58433d6423SLionel Sambuc {
59433d6423SLionel Sambuc   struct inode *ip, *ldirp;
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc   /* Get last directory inode */
62ccaeedb2SDavid van Moolenbroek   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
63ccaeedb2SDavid van Moolenbroek 	  return(EINVAL);
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc   /* Try to create the new node */
66ccaeedb2SDavid van Moolenbroek   ip = new_node(ldirp, name, mode, uid, gid, (zone_t) dev);
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc   put_inode(ip);
69433d6423SLionel Sambuc   put_inode(ldirp);
70433d6423SLionel Sambuc   return(err_code);
71433d6423SLionel Sambuc }
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc /*===========================================================================*
75433d6423SLionel Sambuc  *				fs_mkdir				     *
76433d6423SLionel Sambuc  *===========================================================================*/
fs_mkdir(ino_t dir_nr,char * name,mode_t mode,uid_t uid,gid_t gid)77ccaeedb2SDavid van Moolenbroek int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc   int r1, r2;			/* status codes */
80433d6423SLionel Sambuc   ino_t dot, dotdot;		/* inode numbers for . and .. */
81433d6423SLionel Sambuc   struct inode *rip, *ldirp;
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc   /* Get last directory inode */
84ccaeedb2SDavid van Moolenbroek   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
85ccaeedb2SDavid van Moolenbroek       return(EINVAL);
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc   /* Next make the inode. If that fails, return error code. */
88ccaeedb2SDavid van Moolenbroek   rip = new_node(ldirp, name, mode, uid, gid, (zone_t) 0);
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc   if(rip == NULL || err_code == EEXIST) {
91433d6423SLionel Sambuc 	  put_inode(rip);		/* can't make dir: it already exists */
92433d6423SLionel Sambuc 	  put_inode(ldirp);
93433d6423SLionel Sambuc 	  return(err_code);
94433d6423SLionel Sambuc   }
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc   /* Get the inode numbers for . and .. to enter in the directory. */
97433d6423SLionel Sambuc   dotdot = ldirp->i_num;	/* parent's inode number */
98433d6423SLionel Sambuc   dot = rip->i_num;		/* inode number of the new dir itself */
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc   /* Now make dir entries for . and .. unless the disk is completely full. */
101ccaeedb2SDavid van Moolenbroek   r1 = search_dir(rip, ".", &dot, ENTER);	/* enter . in the new dir */
102ccaeedb2SDavid van Moolenbroek   r2 = search_dir(rip, "..", &dotdot, ENTER);	/* enter .. in the new dir */
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc   /* If both . and .. were successfully entered, increment the link counts. */
105433d6423SLionel Sambuc   if (r1 == OK && r2 == OK) {
106433d6423SLionel Sambuc 	  /* Normal case.  It was possible to enter . and .. in the new dir. */
107433d6423SLionel Sambuc 	  rip->i_nlinks++;	/* this accounts for . */
108433d6423SLionel Sambuc 	  ldirp->i_nlinks++;	/* this accounts for .. */
109433d6423SLionel Sambuc 	  IN_MARKDIRTY(ldirp);	/* mark parent's inode as dirty */
110433d6423SLionel Sambuc   } else {
111433d6423SLionel Sambuc 	  /* It was not possible to enter . or .. probably disk was full -
112433d6423SLionel Sambuc 	   * links counts haven't been touched. */
113ccaeedb2SDavid van Moolenbroek 	  if(search_dir(ldirp, name, NULL, DELETE) != OK)
114433d6423SLionel Sambuc 		  panic("Dir disappeared: %llu", rip->i_num);
115433d6423SLionel Sambuc 	  rip->i_nlinks--;	/* undo the increment done in new_node() */
116433d6423SLionel Sambuc   }
117433d6423SLionel Sambuc   IN_MARKDIRTY(rip);		/* either way, i_nlinks has changed */
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc   put_inode(ldirp);		/* return the inode of the parent dir */
120433d6423SLionel Sambuc   put_inode(rip);		/* return the inode of the newly made dir */
121433d6423SLionel Sambuc   return(err_code);		/* new_node() always sets 'err_code' */
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc /*===========================================================================*
126433d6423SLionel Sambuc  *                             fs_slink 				     *
127433d6423SLionel Sambuc  *===========================================================================*/
fs_slink(ino_t dir_nr,char * name,uid_t uid,gid_t gid,struct fsdriver_data * data,size_t bytes)128ccaeedb2SDavid van Moolenbroek int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
129ccaeedb2SDavid van Moolenbroek 	struct fsdriver_data *data, size_t bytes)
130433d6423SLionel Sambuc {
131433d6423SLionel Sambuc   struct inode *sip;           /* inode containing symbolic link */
132433d6423SLionel Sambuc   struct inode *ldirp;         /* directory containing link */
133433d6423SLionel Sambuc   register int r;              /* error code */
134433d6423SLionel Sambuc   struct buf *bp;              /* disk buffer for link */
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc   /* Temporarily open the dir. */
137ccaeedb2SDavid van Moolenbroek   if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
138433d6423SLionel Sambuc 	  return(EINVAL);
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc   /* Create the inode for the symlink. */
141ccaeedb2SDavid van Moolenbroek   sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc   /* Allocate a disk block for the contents of the symlink.
144433d6423SLionel Sambuc    * Copy contents of symlink (the name pointed to) into first disk block. */
145433d6423SLionel Sambuc   if( (r = err_code) == OK) {
146433d6423SLionel Sambuc   	bp = new_block(sip, (off_t) 0);
147433d6423SLionel Sambuc   	if (bp == NULL)
148433d6423SLionel Sambuc   		r = err_code;
149433d6423SLionel Sambuc   	else {
150ccaeedb2SDavid van Moolenbroek 		if(get_block_size(sip->i_dev) <= bytes) {
151433d6423SLionel Sambuc 			r = ENAMETOOLONG;
152433d6423SLionel Sambuc 		} else {
153ccaeedb2SDavid van Moolenbroek 			r = fsdriver_copyin(data, 0, b_data(bp), bytes);
154ccaeedb2SDavid van Moolenbroek 			b_data(bp)[bytes] = '\0';
155433d6423SLionel Sambuc 		}
156433d6423SLionel Sambuc 	}
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc 	if(bp != NULL && r == OK) {
159433d6423SLionel Sambuc 		sip->i_size = (off_t) strlen(b_data(bp));
160ccaeedb2SDavid van Moolenbroek 		if(sip->i_size != bytes) {
161433d6423SLionel Sambuc 			/* This can happen if the user provides a buffer
162433d6423SLionel Sambuc 			 * with a \0 in it. This can cause a lot of trouble
163433d6423SLionel Sambuc 			 * when the symlink is used later. We could just use
164433d6423SLionel Sambuc 			 * the strlen() value, but we want to let the user
165433d6423SLionel Sambuc 			 * know he did something wrong. ENAMETOOLONG doesn't
166433d6423SLionel Sambuc 			 * exactly describe the error, but there is no
167433d6423SLionel Sambuc 			 * ENAMETOOWRONG.
168433d6423SLionel Sambuc 			 */
169433d6423SLionel Sambuc 			r = ENAMETOOLONG;
170433d6423SLionel Sambuc 		}
171433d6423SLionel Sambuc 	}
172433d6423SLionel Sambuc 
173*0314acfbSDavid van Moolenbroek 	put_block(bp); /* put_block() accepts NULL. */
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc 	if(r != OK) {
176433d6423SLionel Sambuc 		sip->i_nlinks = NO_LINK;
177ccaeedb2SDavid van Moolenbroek 		if(search_dir(ldirp, name, NULL, DELETE) != OK)
178433d6423SLionel Sambuc 			  panic("Symbolic link vanished");
179433d6423SLionel Sambuc 	}
180433d6423SLionel Sambuc   }
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc   /* put_inode() accepts NULL as a noop, so the below are safe. */
183433d6423SLionel Sambuc   put_inode(sip);
184433d6423SLionel Sambuc   put_inode(ldirp);
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc   return(r);
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc 
189433d6423SLionel Sambuc /*===========================================================================*
190433d6423SLionel Sambuc  *				new_node				     *
191433d6423SLionel Sambuc  *===========================================================================*/
new_node(struct inode * ldirp,char * string,mode_t bits,uid_t uid,gid_t gid,zone_t z0)192433d6423SLionel Sambuc static struct inode *new_node(struct inode *ldirp,
193ccaeedb2SDavid van Moolenbroek 	char *string, mode_t bits, uid_t uid, gid_t gid, zone_t z0)
194433d6423SLionel Sambuc {
195433d6423SLionel Sambuc /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
196433d6423SLionel Sambuc  * In all cases it allocates a new inode, makes a directory entry for it in
197433d6423SLionel Sambuc  * the ldirp directory with string name, and initializes it.
198433d6423SLionel Sambuc  * It returns a pointer to the inode if it can do this;
199433d6423SLionel Sambuc  * otherwise it returns NULL.  It always sets 'err_code'
200433d6423SLionel Sambuc  * to an appropriate value (OK or an error code).
201433d6423SLionel Sambuc  *
202433d6423SLionel Sambuc  * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
203433d6423SLionel Sambuc  * has to hold at least MFS_NAME_MAX bytes.
204433d6423SLionel Sambuc  */
205433d6423SLionel Sambuc   register struct inode *rip;
206433d6423SLionel Sambuc   register int r;
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc   if (ldirp->i_nlinks == NO_LINK) {	/* Dir does not actually exist */
209433d6423SLionel Sambuc   	err_code = ENOENT;
210433d6423SLionel Sambuc   	return(NULL);
211433d6423SLionel Sambuc   }
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc   if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
214433d6423SLionel Sambuc         /* New entry is a directory, alas we can't give it a ".." */
215433d6423SLionel Sambuc         err_code = EMLINK;
216433d6423SLionel Sambuc         return(NULL);
217433d6423SLionel Sambuc   }
218433d6423SLionel Sambuc 
219ccaeedb2SDavid van Moolenbroek   /* Get final component of the path. */
220ccaeedb2SDavid van Moolenbroek   rip = advance(ldirp, string);
221ccaeedb2SDavid van Moolenbroek 
222433d6423SLionel Sambuc   if ( rip == NULL && err_code == ENOENT) {
223433d6423SLionel Sambuc 	/* Last path component does not exist.  Make new directory entry. */
224ccaeedb2SDavid van Moolenbroek 	if ( (rip = alloc_inode((ldirp)->i_dev, bits, uid, gid)) == NULL) {
225433d6423SLionel Sambuc 		/* Can't creat new inode: out of inodes. */
226433d6423SLionel Sambuc 		return(NULL);
227433d6423SLionel Sambuc 	}
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc 	/* Force inode to the disk before making directory entry to make
230433d6423SLionel Sambuc 	 * the system more robust in the face of a crash: an inode with
231433d6423SLionel Sambuc 	 * no directory entry is much better than the opposite.
232433d6423SLionel Sambuc 	 */
233433d6423SLionel Sambuc 	rip->i_nlinks++;
234433d6423SLionel Sambuc 	rip->i_zone[0] = z0;		/* major/minor device numbers */
235433d6423SLionel Sambuc 	rw_inode(rip, WRITING);		/* force inode to disk now */
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 	/* New inode acquired.  Try to make directory entry. */
238ccaeedb2SDavid van Moolenbroek 	if((r=search_dir(ldirp, string, &rip->i_num, ENTER)) != OK) {
239433d6423SLionel Sambuc 		rip->i_nlinks--;	/* pity, have to free disk inode */
240433d6423SLionel Sambuc 		IN_MARKDIRTY(rip);	/* dirty inodes are written out */
241433d6423SLionel Sambuc 		put_inode(rip);	/* this call frees the inode */
242433d6423SLionel Sambuc 		err_code = r;
243433d6423SLionel Sambuc 		return(NULL);
244433d6423SLionel Sambuc 	}
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc   } else {
247433d6423SLionel Sambuc 	/* Either last component exists, or there is some problem. */
248433d6423SLionel Sambuc 	if (rip != NULL)
249433d6423SLionel Sambuc 		r = EEXIST;
250433d6423SLionel Sambuc 	else
251433d6423SLionel Sambuc 		r = err_code;
252433d6423SLionel Sambuc   }
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc   /* The caller has to return the directory inode (*ldirp).  */
255433d6423SLionel Sambuc   err_code = r;
256433d6423SLionel Sambuc   return(rip);
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc /*===========================================================================*
261ccaeedb2SDavid van Moolenbroek  *				fs_seek					     *
262433d6423SLionel Sambuc  *===========================================================================*/
fs_seek(ino_t ino_nr)263ccaeedb2SDavid van Moolenbroek void fs_seek(ino_t ino_nr)
264433d6423SLionel Sambuc {
265433d6423SLionel Sambuc   struct inode *rip;
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc   /* inhibit read ahead */
268ccaeedb2SDavid van Moolenbroek   if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
269433d6423SLionel Sambuc 	  rip->i_seek = ISEEK;
270433d6423SLionel Sambuc }
271