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