FRESULT f_setlabel()

in fs/fatfs/src/ff.c [4922:5037]


FRESULT f_setlabel (
	const TCHAR* label	/* Pointer to the volume label to set */
)
{
	FRESULT res;
	FATFS_DIR dj;
	FATFS *fs;
	BYTE dirvn[22];
	UINT i, j, slen;
	WCHAR w;
	static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F";


	/* Get logical drive */
	res = find_volume(&label, &fs, FA_WRITE);
	if (res != FR_OK) LEAVE_FF(fs, res);
	dj.obj.fs = fs;

	/* Get length of given volume label */
	for (slen = 0; (UINT)label[slen] >= ' '; slen++) ;	/* Get name length */

#if _FS_EXFAT
	if (fs->fs_type == FS_EXFAT) {	/* On the exFAT volume */
		for (i = j = 0; i < slen; ) {	/* Create volume label in directory form */
			w = label[i++];
#if !_LFN_UNICODE
			if (IsDBCS1(w)) {
				w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;
			}
			w = ff_convert(w, 1);
#endif
			if (w == 0 || chk_chr(badchr, w) || j == 22) {	/* Check validity check validity of the volume label */
				LEAVE_FF(fs, FR_INVALID_NAME);
			}
			st_word(dirvn + j, w); j += 2;
		}
		slen = j;
	} else
#endif
	{	/* On the FAT12/16/32 volume */
		for ( ; slen && label[slen - 1] == ' '; slen--) ;	/* Remove trailing spaces */
		if (slen) {		/* Is there a volume label to be set? */
			dirvn[0] = 0; i = j = 0;	/* Create volume label in directory form */
			do {
#if _LFN_UNICODE
				w = ff_convert(ff_wtoupper(label[i++]), 0);
#else
				w = (BYTE)label[i++];
				if (IsDBCS1(w)) {
					w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;
				}
#if _USE_LFN != 0
				w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0);
#else
				if (IsLower(w)) w -= 0x20;			/* To upper ASCII characters */
#ifdef _EXCVT
				if (w >= 0x80) w = ExCvt[w - 0x80];	/* To upper extended characters (SBCS cfg) */
#else
				if (!_DF1S && w >= 0x80) w = 0;		/* Reject extended characters (ASCII cfg) */
#endif
#endif
#endif
				if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) {	/* Reject invalid characters for volume label */
					LEAVE_FF(fs, FR_INVALID_NAME);
				}
				if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8);
				dirvn[j++] = (BYTE)w;
			} while (i < slen);
			while (j < 11) dirvn[j++] = ' ';	/* Fill remaining name field */
			if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME);	/* Reject illegal name (heading DDEM) */
		}
	}

	/* Set volume label */
	dj.obj.sclust = 0;		/* Open root directory */
	res = dir_sdi(&dj, 0);
	if (res == FR_OK) {
		res = dir_read(&dj, 1);	/* Get volume label entry */
		if (res == FR_OK) {
			if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {
				dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2);	/* Change the volume label */
				mem_cpy(dj.dir + XDIR_Label, dirvn, slen);
			} else {
				if (slen) {
					mem_cpy(dj.dir, dirvn, 11);	/* Change the volume label */
				} else {
					dj.dir[DIR_Name] = DDEM;	/* Remove the volume label */
				}
			}
			fs->wflag = 1;
			res = sync_fs(fs);
		} else {			/* No volume label entry is found or error */
			if (res == FR_NO_FILE) {
				res = FR_OK;
				if (slen) {	/* Create a volume label entry */
					res = dir_alloc(&dj, 1);	/* Allocate an entry */
					if (res == FR_OK) {
						mem_set(dj.dir, 0, SZDIRE);	/* Clear the entry */
						if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {
							dj.dir[XDIR_Type] = 0x83;		/* Create 83 entry */
							dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2);
							mem_cpy(dj.dir + XDIR_Label, dirvn, slen);
						} else {
							dj.dir[DIR_Attr] = AM_VOL;		/* Create volume label entry */
							mem_cpy(dj.dir, dirvn, 11);
						}
						fs->wflag = 1;
						res = sync_fs(fs);
					}
				}
			}
		}
	}

	LEAVE_FF(fs, res);
}