This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ftruncate function for eCos FAT filesystem


Hi,

attached is a patch for a ftruncate function implementation for the eCos FAT filesystem. If it's useful to anybody please feel free to use it.

regards,
   Nelu
Index: packages/fs/fat/current/src/fatfs.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/src/fatfs.c,v
retrieving revision 1.4
diff -u -p -r1.4 fatfs.c
--- packages/fs/fat/current/src/fatfs.c	11 Nov 2004 19:33:30 -0000	1.4
+++ packages/fs/fat/current/src/fatfs.c	5 Sep 2005 12:13:07 -0000
@@ -1290,6 +1290,43 @@ fatfs_fo_write(struct CYG_FILE_TAG *fp, 
 }
 
 // -------------------------------------------------------------------------
+// fatfs_fo_ftruncate()
+// The ftruncate function changes the size of filename to length. If length 
+// is shorter than the previous length, data at the end will be lost.
+
+int 
+fatfs_fo_ftruncate(struct CYG_FILE_TAG *fp, off_t length)
+{
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *) fp->f_data;
+    fatfs_dir_entry_t *file = (fatfs_dir_entry_t *) &fd->node->dentry;
+    int            err;
+
+    if (length == file->size)				// if the requested file size is equal with the current file size
+	    return ENOERR;				// return
+	    
+    if (length < 0)
+	    return EINVAL;
+
+    if (length == 0)
+	    return fatfs_trunc_file(disk, file);	// truncate file to zero length
+
+    if (length < file->size) {
+	    err = fatfs_shorten_file(disk, file, &fd->pos, length);
+    } else {
+	    err = fatfs_extend_file(disk, file, &fd->pos, length);
+    }
+
+    if (ENOERR == err) {
+	    file->size    = length;
+	    file->mtime   =
+	    file->atime   = cyg_timestamp();
+    }
+
+    return err;
+}
+
+// -------------------------------------------------------------------------
 // fatfs_fo_lseek()
 // Seek to a new file position.
 
Index: packages/fs/fat/current/src/fatfs.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/src/fatfs.h,v
retrieving revision 1.3
diff -u -p -r1.3 fatfs.h
--- packages/fs/fat/current/src/fatfs.h	22 Oct 2004 14:10:23 -0000	1.3
+++ packages/fs/fat/current/src/fatfs.h	5 Sep 2005 12:13:07 -0000
@@ -233,6 +233,16 @@ int  fatfs_create_dir(fatfs_disk_t      
 
 int  fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file);
 
+int  fatfs_shorten_file(fatfs_disk_t  *disk,
+			fatfs_dir_entry_t *file,
+			fatfs_data_pos_t  *pos,
+			off_t length);
+
+int  fatfs_extend_file(fatfs_disk_t  *disk,
+		       fatfs_dir_entry_t *file,
+		       fatfs_data_pos_t  *pos,
+		       off_t length);
+
 int  fatfs_rename_file(fatfs_disk_t      *disk,
                        fatfs_dir_entry_t *dir1,
                        fatfs_dir_entry_t *target,
Index: packages/fs/fat/current/src/fatfs_supp.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/fs/fat/current/src/fatfs_supp.c,v
retrieving revision 1.6
diff -u -p -r1.6 fatfs_supp.c
--- packages/fs/fat/current/src/fatfs_supp.c	3 Aug 2005 20:40:48 -0000	1.6
+++ packages/fs/fat/current/src/fatfs_supp.c	5 Sep 2005 12:13:09 -0000
@@ -2341,6 +2341,154 @@ fatfs_trunc_file(fatfs_disk_t *disk, fat
 }
 
 // -------------------------------------------------------------------------
+// erase_cluster_section()
+// Erases a portion of a cluster with length 'length' 
+// starting from offset 'pos'(fills with 0x00).
+
+static int
+erase_cluster_section(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 pos, cyg_uint32 length)
+{
+    cyg_uint8  data[32];
+    int        len;
+    int        err;
+
+    if ((pos + length) > disk->cluster_size)
+	    return EINVAL;
+
+    memset((void*)data, 0x00, 32);
+
+    while (length > 0) {
+	len = (length < 32) ? length : 32;
+        err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
+        if (err != ENOERR)
+            return err;
+
+        pos += len;
+	length -= len;
+    }
+    
+    return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// fatfs_shorten_file()
+
+int
+fatfs_shorten_file(fatfs_disk_t  *disk,
+		   fatfs_dir_entry_t *file,
+		   fatfs_data_pos_t  *pos,
+		   off_t length)
+{
+	cyg_uint32 next_c, tentry;
+	int        err;
+
+	// if the file is shrinking,
+	// find the last cluster of the new file length (get_position_from_off),
+	// free all clusters from the current one to the end of the file (free_cluster_chain),
+	// and change the size of the coresponding fatfs node.
+	
+	err = get_position_from_off(disk, file->cluster, length, pos, CO_NONE);
+        if (err != ENOERR)
+            return err;
+
+	// get next cluster in chain and free all clusters to the end of file
+	err = read_tentry(disk, pos->cluster, &tentry);
+	if (err != ENOERR)
+		return err;
+
+        switch (get_tentry_type(disk, tentry))
+	{
+		case TENTRY_LAST:
+			// Last cluster in chain no deallocation needed
+			return ENOERR;
+		case TENTRY_REGULAR:
+			// Get next cluster in chain
+			next_c = get_tentry_next_cluster(disk, tentry);
+			break;
+		default:
+			CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x c=%d", 
+				   tentry, pos->cluster);
+			return EIO;
+	}
+
+	err = free_cluster_chain(disk,  next_c);
+        if (err != ENOERR)
+            return err;
+
+        // Set the current cluster tentry to LAST 
+        set_tentry_type(disk, &tentry, TENTRY_LAST);
+        return write_tentry(disk, pos->cluster, &tentry);
+}
+
+// -------------------------------------------------------------------------
+// fatfs_extend_file()
+
+int
+fatfs_extend_file(fatfs_disk_t  *disk,
+		   fatfs_dir_entry_t *file,
+		   fatfs_data_pos_t  *pos,
+		   off_t length)
+{
+	// if the file is extending,
+	// allocate the appropriate number of clusters and link them into the file cluster chain
+	// (find_and_append_cluster).	
+
+	off_t space_last_c = 0;
+	off_t space_needed = 0;
+	int   err;
+	cyg_uint32 last_cluster;
+
+	// compute how much space is needed
+	space_needed = length - file->size;
+
+	// compute how much space there is available in the last file cluster
+	if ((space_last_c = file->size % disk->cluster_size) > 0)
+		space_last_c = disk->cluster_size - space_last_c;
+
+	// find the last cluster in the original file
+	err = get_position_from_off(disk, file->cluster, file->size, pos, CO_NONE);
+	if ((ENOERR != err) && (EEOF != err))
+		return err; 
+	last_cluster = pos->cluster;    
+
+	if (space_needed > space_last_c) {
+		cyg_uint32 new_cluster;
+		off_t new_c = 0;
+		cyg_uint32 cnt;
+
+		// erase the free part of the last cluster
+		if (space_last_c > 0)
+			erase_cluster_section(disk, last_cluster, disk->cluster_size - space_last_c, space_last_c);
+
+		// compute how many new clusters we need
+		new_c = (space_needed - space_last_c) / disk->cluster_size;
+
+		// account for an incomplete cluster at the end of file
+		new_c += ((space_needed - space_last_c) % disk->cluster_size) ? 1:0;
+
+		// extend the chain with new_c clusters		
+		for (cnt=0; new_c > 0; new_c--, cnt++) {
+			err = find_and_append_cluster(disk, last_cluster, &new_cluster, CO_ERASE_NEW);
+			if (err != ENOERR) {
+				// adjust the file size to account for the allocated clusters
+				file->size    += cnt*disk->cluster_size;
+				file->mtime   =
+				file->atime   = cyg_timestamp();
+				return err;
+			}
+
+			last_cluster = new_cluster;
+		}
+	} else {
+		// if we fit in the last cluster
+		// erase the requested part of the last cluster
+		erase_cluster_section(disk, last_cluster, disk->cluster_size - space_last_c, space_needed);		
+	}
+
+	return ENOERR;
+}
+
+// -------------------------------------------------------------------------
 // fatfs_rename_file()
 // Renames a file.
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]