1 /* Created (MFS based):
2 * February 2010 (Evgeniy Ivanov)
13 static struct inode
*new_node(struct inode
*ldirp
, char *string
, mode_t
14 bits
, uid_t uid
, gid_t gid
, block_t z0
);
17 /*===========================================================================*
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
)
27 /* Try to make the file. */
29 /* Get last directory inode (i.e., directory that will hold the new inode) */
30 if ((ldirp
= get_inode(fs_dev
, dir_nr
)) == NULL
)
33 /* Create a new inode by calling new_node(). */
34 rip
= new_node(ldirp
, name
, mode
, uid
, gid
, NO_BLOCK
);
37 /* If an error occurred, release inode. */
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
;
59 /*===========================================================================*
61 *===========================================================================*/
62 int fs_mknod(ino_t dir_nr
, char *name
, mode_t mode
, uid_t uid
, gid_t gid
,
65 struct inode
*ip
, *ldirp
;
67 /* Get last directory inode */
68 if((ldirp
= get_inode(fs_dev
, dir_nr
)) == NULL
)
71 /* Try to create the new node */
72 ip
= new_node(ldirp
, name
, mode
, uid
, gid
, (block_t
) dev
);
80 /*===========================================================================*
82 *===========================================================================*/
83 int fs_mkdir(ino_t dir_nr
, char *name
, mode_t mode
, uid_t uid
, gid_t gid
)
85 int r1
, r2
; /* status codes */
86 ino_t dot
, dotdot
; /* inode numbers for . and .. */
87 struct inode
*rip
, *ldirp
;
89 /* Get last directory inode */
90 if((ldirp
= get_inode(fs_dev
, dir_nr
)) == NULL
)
93 /* Next make the inode. If that fails, return error code. */
94 rip
= new_node(ldirp
, name
, mode
, uid
, gid
, (block_t
) 0);
96 if(rip
== NULL
|| err_code
== EEXIST
) {
97 put_inode(rip
); /* can't make dir: it already exists */
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 */
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
);
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 */
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() */
125 rip
->i_dirt
= IN_DIRTY
; /* either way, i_links_count has changed */
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' */
133 /*===========================================================================*
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
)
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 */
145 /* Temporarily open the dir. */
146 if( (ldirp
= get_inode(fs_dev
, dir_nr
)) == NULL
)
149 /* Create the inode for the symlink. */
150 sip
= new_node(ldirp
, name
, (I_SYMBOLIC_LINK
| RWX_MODES
), uid
, gid
, 0);
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
) {
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
;
163 if ((bp
= new_block(sip
, (off_t
) 0)) != NULL
) {
164 r
= fsdriver_copyin(data
, 0, b_data(bp
), bytes
);
166 link_target_buf
= b_data(bp
);
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
188 put_block(bp
); /* put_block() accepts NULL. */
191 sip
->i_links_count
= NO_LINK
;
192 if (search_dir(ldirp
, name
, NULL
, DELETE
, 0) != OK
)
193 panic("Symbolic link vanished");
197 /* put_inode() accepts NULL as a noop, so the below are safe. */
204 /*===========================================================================*
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
)
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).
218 register struct inode
*rip
;
221 if (ldirp
->i_links_count
== NO_LINK
) { /* Dir does not actually exist */
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 ".." */
233 /* Get final component of the path. */
234 rip
= advance(ldirp
, string
);
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. */
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.
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 */
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 */
262 /* Either last component exists, or there is some problem. */
269 /* The caller has to return the directory inode (*ldirp). */
275 /*===========================================================================*
277 *===========================================================================*/
278 void fs_seek(ino_t ino_nr
)
282 /* inhibit read ahead */
283 if ((rip
= find_inode(fs_dev
, ino_nr
)) != NULL
)