@@ -209,7 +209,6 @@ export class FileHandle implements promises.FileHandle {
209
209
position : number = this . position
210
210
) : Promise < { bytesRead : number ; buffer : TBuffer } > {
211
211
if ( this . closed ) throw UV ( 'EBADF' , 'read' , this . path ) ;
212
-
213
212
if ( this . flag & constants . O_WRONLY ) throw UV ( 'EBADF' , 'read' , this . path ) ;
214
213
215
214
if ( ! ( this . inode . flags ! & InodeFlags . NoAtime ) ) {
@@ -286,7 +285,8 @@ export class FileHandle implements promises.FileHandle {
286
285
if ( flag & constants . O_WRONLY ) throw UV ( 'EBADF' , 'read' , this . path ) ;
287
286
288
287
const { size } = await this . stat ( ) ;
289
- const { buffer : data } = await this . _read ( new Uint8Array ( size ) , 0 , size , 0 ) ;
288
+ const data = new Uint8Array ( size ) ;
289
+ await this . _read ( data , 0 , size , 0 ) ;
290
290
const buffer = Buffer . from ( data ) ;
291
291
return options . encoding ? buffer . toString ( options . encoding ) : buffer ;
292
292
}
@@ -518,9 +518,18 @@ export async function rename(this: V_Context, oldPath: fs.PathLike, newPath: fs.
518
518
519
519
if ( src . fs !== dst . fs ) throw UV ( 'EXDEV' , $ex ) ;
520
520
521
- const stats = await stat . call ( this , dirname ( oldPath ) ) . catch ( rethrow ( $ex ) ) ;
521
+ const parent = ( await stat . call ( this , dirname ( oldPath ) ) . catch ( rethrow ( $ex ) ) ) as Stats ;
522
+ const stats = ( await stat . call ( this , oldPath ) . catch ( rethrow ( $ex ) ) ) as Stats ;
523
+ const newParent = ( await stat . call ( this , dirname ( newPath ) ) . catch ( rethrow ( $ex ) ) ) as Stats ;
524
+ const newStats = ( await stat . call ( this , newPath ) . catch ( ( e : Exception ) => {
525
+ if ( e . code == 'ENOENT' ) return null ;
526
+ throw setUVMessage ( Object . assign ( e , $ex ) ) ;
527
+ } ) ) as Stats ;
528
+
529
+ if ( checkAccess && ( ! parent . hasAccess ( constants . R_OK , this ) || ! newParent . hasAccess ( constants . W_OK , this ) ) ) throw UV ( 'EACCES' , $ex ) ;
522
530
523
- if ( checkAccess && ! stats . hasAccess ( constants . W_OK , this ) ) throw UV ( 'EACCES' , $ex ) ;
531
+ if ( newStats && ! isDirectory ( stats ) && isDirectory ( newStats ) ) throw UV ( 'EISDIR' , $ex ) ;
532
+ if ( newStats && isDirectory ( stats ) && ! isDirectory ( newStats ) ) throw UV ( 'ENOTDIR' , $ex ) ;
524
533
525
534
await src . fs . rename ( src . path , dst . path ) . catch ( rethrow ( $ex ) ) ;
526
535
@@ -618,6 +627,8 @@ async function _open($: V_Context, path: fs.PathLike, opt: OpenOptions): Promise
618
627
619
628
if ( ! isDirectory ( parentStats ) ) throw UV ( 'ENOTDIR' , 'open' , dirname ( path ) ) ;
620
629
630
+ if ( ! opt . allowDirectory && mode & constants . S_IFDIR ) throw UV ( 'EISDIR' , 'open' , path ) ;
631
+
621
632
const { euid : uid , egid : gid } = $ ?. credentials ?? defaultContext . credentials ;
622
633
623
634
const inode = await fs . createFile ( resolved , {
@@ -630,17 +641,12 @@ async function _open($: V_Context, path: fs.PathLike, opt: OpenOptions): Promise
630
641
}
631
642
632
643
if ( checkAccess && ! hasAccess ( $ , stats , flags . toMode ( flag ) ) ) throw UV ( 'EACCES' , $ex ) ;
633
-
634
644
if ( flag & constants . O_EXCL ) throw UV ( 'EEXIST' , $ex ) ;
635
645
636
646
const handle = new FileHandle ( $ , toFD ( new SyncHandle ( $ , path , fs , resolved , flag , stats ) ) ) ;
637
647
638
- /*
639
- In a previous implementation, we deleted the file and
640
- re-created it. However, this created a race condition if another
641
- asynchronous request was trying to read the file, as the file
642
- would not exist for a small period of time.
643
- */
648
+ if ( ! opt . allowDirectory && mode & constants . S_IFDIR ) throw UV ( 'EISDIR' , 'open' , path ) ;
649
+
644
650
if ( flag & constants . O_TRUNC ) await handle . truncate ( 0 ) ;
645
651
646
652
return handle ;
0 commit comments