xref: /minix/minix/fs/ext2/open.c (revision 0a6a1f1d)
1 /* Created (MFS based):
2  *   February 2010 (Evgeniy Ivanov)
3  */
4 
5 #include "fs.h"
6 #include <sys/stat.h>
7 #include <string.h>
8 #include <assert.h>
9 #include "buf.h"
10 #include "inode.h"
11 #include "super.h"
12 
13 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
14 	bits, uid_t uid, gid_t gid, block_t z0);
15 
16 
17 /*===========================================================================*
18  *				fs_create				     *
19  *===========================================================================*/
20 int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
21 	struct fsdriver_node *node)
22 {
23   int r;
24   struct inode *ldirp;
25   struct inode *rip;
26 
27   /* Try to make the file. */
28 
29   /* Get last directory inode (i.e., directory that will hold the new inode) */
30   if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
31 	  return(ENOENT);
32 
33   /* Create a new inode by calling new_node(). */
34   rip = new_node(ldirp, name, mode, uid, gid, NO_BLOCK);
35   r = err_code;
36 
37   /* If an error occurred, release inode. */
38   if (r != OK) {
39 	  put_inode(ldirp);
40 	  put_inode(rip);
41 	  return(r);
42   }
43 
44   /* Reply message */
45   node->fn_ino_nr = rip->i_num;
46   node->fn_mode = rip->i_mode;
47   node->fn_size = rip->i_size;
48   node->fn_uid = rip->i_uid;
49   node->fn_gid = rip->i_gid;
50   node->fn_dev = NO_DEV;
51 
52   /* Drop parent dir */
53   put_inode(ldirp);
54 
55   return(OK);
56 }
57 
58 
59 /*===========================================================================*
60  *				fs_mknod				     *
61  *===========================================================================*/
62 int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
63 	dev_t dev)
64 {
65   struct inode *ip, *ldirp;
66 
67   /* Get last directory inode */
68   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
69 	  return(ENOENT);
70 
71   /* Try to create the new node */
72   ip = new_node(ldirp, name, mode, uid, gid, (block_t) dev);
73 
74   put_inode(ip);
75   put_inode(ldirp);
76   return(err_code);
77 }
78 
79 
80 /*===========================================================================*
81  *				fs_mkdir				     *
82  *===========================================================================*/
83 int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
84 {
85   int r1, r2;			/* status codes */
86   ino_t dot, dotdot;		/* inode numbers for . and .. */
87   struct inode *rip, *ldirp;
88 
89   /* Get last directory inode */
90   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
91       return(ENOENT);
92 
93   /* Next make the inode. If that fails, return error code. */
94   rip = new_node(ldirp, name, mode, uid, gid, (block_t) 0);
95 
96   if(rip == NULL || err_code == EEXIST) {
97 	  put_inode(rip);		/* can't make dir: it already exists */
98 	  put_inode(ldirp);
99 	  return(err_code);
100   }
101 
102   /* Get the inode numbers for . and .. to enter in the directory. */
103   dotdot = ldirp->i_num;	/* parent's inode number */
104   dot = rip->i_num;		/* inode number of the new dir itself */
105 
106   /* Now make dir entries for . and .. unless the disk is completely full. */
107   /* enter . in the new dir*/
108   r1 = search_dir(rip, ".", &dot, ENTER, I_DIRECTORY);
109   /* enter .. in the new dir */
110   r2 = search_dir(rip, "..", &dotdot, ENTER, I_DIRECTORY);
111 
112   /* If both . and .. were successfully entered, increment the link counts. */
113   if (r1 == OK && r2 == OK) {
114 	  /* Normal case.  It was possible to enter . and .. in the new dir. */
115 	  rip->i_links_count++;	/* this accounts for . */
116 	  ldirp->i_links_count++;	/* this accounts for .. */
117 	  ldirp->i_dirt = IN_DIRTY;	/* mark parent's inode as dirty */
118   } else {
119 	  /* It was not possible to enter . or .. probably disk was full -
120 	   * links counts haven't been touched. */
121 	  if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
122 		  panic("Dir disappeared: %d ", (int) rip->i_num);
123 	  rip->i_links_count--;	/* undo the increment done in new_node() */
124   }
125   rip->i_dirt = IN_DIRTY;	/* either way, i_links_count has changed */
126 
127   put_inode(ldirp);		/* return the inode of the parent dir */
128   put_inode(rip);		/* return the inode of the newly made dir */
129   return(err_code);		/* new_node() always sets 'err_code' */
130 }
131 
132 
133 /*===========================================================================*
134  *                             fs_slink 				     *
135  *===========================================================================*/
136 int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
137 	struct fsdriver_data *data, size_t bytes)
138 {
139   struct inode *sip;           /* inode containing symbolic link */
140   struct inode *ldirp;         /* directory containing link */
141   register int r;              /* error code */
142   char* link_target_buf = NULL;       /* either sip->i_block or bp->b_data */
143   struct buf *bp = NULL;    /* disk buffer for link */
144 
145   /* Temporarily open the dir. */
146   if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
147 	  return(EINVAL);
148 
149   /* Create the inode for the symlink. */
150   sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
151 
152   /* If we can then create fast symlink (store it in inode),
153    * Otherwise allocate a disk block for the contents of the symlink and
154    * copy contents of symlink (the name pointed to) into first disk block. */
155   if( (r = err_code) == OK) {
156 	if (bytes + 1 > sip->i_sp->s_block_size) {
157 		r = ENAMETOOLONG;
158 	} else if ((bytes + 1) <= MAX_FAST_SYMLINK_LENGTH) {
159 		r = fsdriver_copyin(data, 0, (char *) sip->i_block, bytes);
160 		sip->i_dirt = IN_DIRTY;
161 		link_target_buf = (char*) sip->i_block;
162         } else {
163 		if ((bp = new_block(sip, (off_t) 0)) != NULL) {
164 			r = fsdriver_copyin(data, 0, b_data(bp), bytes);
165 			lmfs_markdirty(bp);
166 			link_target_buf = b_data(bp);
167 		} else {
168 			r = err_code;
169 		}
170 	}
171 	if (r == OK) {
172 		assert(link_target_buf);
173 		link_target_buf[bytes] = '\0';
174 		sip->i_size = (off_t) strlen(link_target_buf);
175 		if (sip->i_size != bytes) {
176 			  /* This can happen if the user provides a buffer
177 			   * with a \0 in it. This can cause a lot of trouble
178 			   * when the symlink is used later. We could just use
179 			   * the strlen() value, but we want to let the user
180 			   * know he did something wrong. ENAMETOOLONG doesn't
181 			   * exactly describe the error, but there is no
182 			   * ENAMETOOWRONG.
183 			   */
184 			  r = ENAMETOOLONG;
185 		  }
186 	}
187 
188 	put_block(bp); /* put_block() accepts NULL. */
189 
190 	if(r != OK) {
191 		sip->i_links_count = NO_LINK;
192 		if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
193 			panic("Symbolic link vanished");
194 	}
195   }
196 
197   /* put_inode() accepts NULL as a noop, so the below are safe. */
198   put_inode(sip);
199   put_inode(ldirp);
200 
201   return(r);
202 }
203 
204 /*===========================================================================*
205  *				new_node				     *
206  *===========================================================================*/
207 static struct inode *new_node(struct inode *ldirp,
208 	char *string, mode_t bits, uid_t uid, gid_t gid, block_t b0)
209 {
210 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
211  * In all cases it allocates a new inode, makes a directory entry for it in
212  * the ldirp directory with string name, and initializes it.
213  * It returns a pointer to the inode if it can do this;
214  * otherwise it returns NULL.  It always sets 'err_code'
215  * to an appropriate value (OK or an error code).
216  */
217 
218   register struct inode *rip;
219   register int r;
220 
221   if (ldirp->i_links_count == NO_LINK) { /* Dir does not actually exist */
222 	err_code = ENOENT;
223 	return(NULL);
224   }
225 
226   if (S_ISDIR(bits) && (ldirp->i_links_count >= USHRT_MAX ||
227 			ldirp->i_links_count >= LINK_MAX)) {
228         /* New entry is a directory, alas we can't give it a ".." */
229         err_code = EMLINK;
230         return(NULL);
231   }
232 
233   /* Get final component of the path. */
234   rip = advance(ldirp, string);
235 
236   if ( rip == NULL && err_code == ENOENT) {
237 	/* Last path component does not exist.  Make new directory entry. */
238 	if ( (rip = alloc_inode(ldirp, bits, uid, gid)) == NULL) {
239 		/* Can't creat new inode: out of inodes. */
240 		return(NULL);
241 	}
242 
243 	/* Force inode to the disk before making directory entry to make
244 	 * the system more robust in the face of a crash: an inode with
245 	 * no directory entry is much better than the opposite.
246 	 */
247 	rip->i_links_count++;
248 	rip->i_block[0] = b0;		/* major/minor device numbers */
249 	rw_inode(rip, WRITING);		/* force inode to disk now */
250 
251 	/* New inode acquired.  Try to make directory entry. */
252 	if ((r=search_dir(ldirp, string, &rip->i_num, ENTER,
253 			  rip->i_mode & I_TYPE)) != OK) {
254 		rip->i_links_count--;	/* pity, have to free disk inode */
255 		rip->i_dirt = IN_DIRTY;	/* dirty inodes are written out */
256 		put_inode(rip);	/* this call frees the inode */
257 		err_code = r;
258 		return(NULL);
259 	}
260 
261   } else {
262 	/* Either last component exists, or there is some problem. */
263 	if (rip != NULL)
264 		r = EEXIST;
265 	else
266 		r = err_code;
267   }
268 
269   /* The caller has to return the directory inode (*ldirp).  */
270   err_code = r;
271   return(rip);
272 }
273 
274 
275 /*===========================================================================*
276  *				fs_seek					     *
277  *===========================================================================*/
278 void fs_seek(ino_t ino_nr)
279 {
280   struct inode *rip;
281 
282   /* inhibit read ahead */
283   if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
284 	rip->i_seek = ISEEK;
285 }
286