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, DIRECTORY_BLOCK); /* 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