Commit 65c4ca1f authored by RAJAGOPALAN GANGADHARAN's avatar RAJAGOPALAN GANGADHARAN Committed by Henrik Brix Andersen
Browse files

fs: open: Add Truncate flag to zfs open



This commit has added new flag FS_O_TRUNC to support truncation
during file open. Modified fs_open to handle truncation based on
provided flags. Included unit tests for flag behavior with common
filesystems.

Signed-off-by: default avatarRAJAGOPALAN GANGADHARAN <g.raju2000@gmail.com>
parent c36d9ec3
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -160,8 +160,11 @@ struct fs_statvfs {
#define FS_O_CREATE     0x10
/** Open/create file for append */
#define FS_O_APPEND     0x20
/** Truncate the file while opening */
#define FS_O_TRUNC      0x40
/** Bitmask for open/create flags */
#define FS_O_FLAGS_MASK 0x30
#define FS_O_FLAGS_MASK 0x70


/** Bitmask for open flags */
#define FS_O_MASK       (FS_O_MODE_MASK | FS_O_FLAGS_MASK)
@@ -268,6 +271,7 @@ static inline void fs_dir_t_init(struct fs_dir_t *zdp)
 *   - @c FS_O_RDWR open for read/write (<tt>FS_O_READ | FS_O_WRITE</tt>)
 *   - @c FS_O_CREATE create file if it does not exist
 *   - @c FS_O_APPEND move to end of file before each write
 *   - @c FS_O_TRUNC truncate the file
 *
 * @warning If @p flags are set to 0 the function will open file, if it exists
 *          and is accessible, but you will have no read/write access to it.
@@ -284,6 +288,7 @@ static inline void fs_dir_t_init(struct fs_dir_t *zdp)
 *	   FS_MOUNT_FLAG_READ_ONLY flag;
 * @retval -ENOENT when the file does not exist at the path;
 * @retval -ENOTSUP when not implemented by underlying file system driver;
 * @retval -EACCES when trying to truncate a file without opening it for write.
 * @retval <0 an other negative errno code, depending on a file system back-end.
 */
int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags);
+24 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
{
	struct fs_mount_t *mp;
	int rc = -EINVAL;
	bool truncate_file = false;

	if ((file_name == NULL) ||
			(strlen(file_name) <= 1) || (file_name[0] != '/')) {
@@ -160,6 +161,19 @@ int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
		return -ENOTSUP;
	}

	if ((flags & FS_O_TRUNC) != 0) {
		if ((flags & FS_O_WRITE) == 0) {
			/** Truncate not allowed when file is not opened for write */
			LOG_ERR("file should be opened for write to truncate!!");
			return -EACCES;
		}
		CHECKIF(mp->fs->truncate == NULL) {
			LOG_ERR("file truncation not supported!!");
			return -ENOTSUP;
		}
		truncate_file = true;
	}

	zfp->mp = mp;
	rc = mp->fs->open(zfp, file_name, flags);
	if (rc < 0) {
@@ -168,6 +182,16 @@ int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
		return rc;
	}

	if (truncate_file) {
		/* Truncate the opened file to 0 length */
		rc = mp->fs->truncate(zfp, 0);
		if (rc < 0) {
			LOG_ERR("file truncation failed (%d)", rc);
			zfp->mp = NULL;
			return rc;
		}
	}

	/* Copy flags to zfp for use with other fs_ API calls */
	zfp->flags = flags;

+91 −0
Original line number Diff line number Diff line
@@ -149,9 +149,13 @@ void test_fs_open_flags(void)
	ZOPEN(&ts, FS_O_READ, -ENOENT);
	ZOPEN(&ts, FS_O_RDWR, -ENOENT);
	ZOPEN(&ts, FS_O_APPEND, -ENOENT);
	ZOPEN(&ts, FS_O_TRUNC, -EACCES);
	ZOPEN(&ts, FS_O_APPEND | FS_O_READ, -ENOENT);
	ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, -ENOENT);
	ZOPEN(&ts, FS_O_APPEND | FS_O_RDWR, -ENOENT);
	ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR, -ENOENT);
	ZOPEN(&ts, FS_O_TRUNC | FS_O_APPEND, -EACCES);
	ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR | FS_O_APPEND, -ENOENT);
	ZEND();


@@ -319,6 +323,73 @@ void test_fs_open_flags(void)
	ZUNLINK(&ts);
	ZEND();

	/** FS_O_TRUNC tests */
	ZBEGIN("Attempt truncate a new file without write access");
	ZOPEN(&ts, FS_O_CREATE | FS_O_TRUNC, -EACCES);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt truncate a new file with write access");
	ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE | FS_O_TRUNC, 0);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt truncate existing with no write access");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_TRUNC, -EACCES);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt truncate existing with write access");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_TRUNC | FS_O_WRITE, 0);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt truncate existing with read access");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_READ | FS_O_TRUNC, -EACCES);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt truncate existing with R/W access");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_RDWR | FS_O_TRUNC, 0);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt read on truncated file but no read access");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_WRITE | FS_O_TRUNC, 0);
	#ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
	ZREAD(&ts, -EACCES);
	#else
	TC_PRINT("Read bypassed\n");
	#endif
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();

	ZBEGIN("Attempt append existing with WRITE access truncated file");
	ZMKEMPTY(&ts);
	ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE | FS_O_TRUNC,  0);
	ZCHKPOS(&ts, 0);
	ZWRITE(&ts, ts.write_size);
	#ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
	ZREAD(&ts, -EACCES);
	#else
	TC_PRINT("Read bypassed\n");
	#endif
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();


	/* This is simple check by file position, not contents. Since writing
	 * same pattern twice, the position of file should be twice the
@@ -355,4 +426,24 @@ void test_fs_open_flags(void)
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();


	ZBEGIN("Check if file is truncated with data");
	/* Prepare file */
	ZUNLINK(&ts);
	ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
	ZWRITE(&ts, ts.write_size);
	ZCLOSE(&ts);

	/* Make sure file has the content */
	ZOPEN(&ts, FS_O_CREATE | FS_O_READ, 0);
	ZREAD(&ts, ts.write_size);
	ZCLOSE(&ts);

	ZOPEN(&ts, FS_O_TRUNC | FS_O_RDWR, 0);
	ZCHKPOS(&ts, 0);
	ZREAD(&ts, 0);
	ZCLOSE(&ts);
	ZUNLINK(&ts);
	ZEND();
}